1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "os-ohos.h"
17
18 #include <dlfcn.h>
19 #include <unistd.h>
20 #include <pthread.h>
21 #include <stdbool.h>
22
23 #include "elfxx.h"
24 #include "libunwind_i.h"
25
26 #define unw_init_local_addr_space UNW_OBJ(init_local_addr_space)
27
28 extern unw_word_t get_previous_instr_sz(unw_cursor_t *cursor);
29 extern void unw_init_local_addr_space (unw_addr_space_t as);
30 extern struct map_info *get_map(struct map_info *map_list, unw_word_t addr);
31
32 void
unw_set_target_pid(unw_addr_space_t as,int pid)33 unw_set_target_pid(unw_addr_space_t as, int pid)
34 {
35 as->pid = pid;
36 }
37
38 unw_word_t
unw_get_rel_pc(unw_cursor_t * cursor)39 unw_get_rel_pc (unw_cursor_t *cursor)
40 {
41 struct cursor *c = (struct cursor *) cursor;
42 if (c->dwarf.rel_pc != 0 && c->dwarf.cached_ip == c->dwarf.ip) {
43 return c->dwarf.rel_pc;
44 }
45
46 c->dwarf.cached_map = tdep_get_elf_image (c->dwarf.as, c->dwarf.as->pid, c->dwarf.ip);
47 if (c->dwarf.cached_map == NULL) {
48 c->dwarf.cached_ip = 0;
49 return 0;
50 }
51
52 if (c->dwarf.cached_map->ei.load_bias == -1) {
53 struct elf_dyn_info edi;
54 invalidate_edi(&edi);
55 if (tdep_find_unwind_table (&edi, &(c->dwarf.cached_map->ei),
56 c->dwarf.as, c->dwarf.cached_map->path,
57 c->dwarf.cached_map->start, c->dwarf.cached_map->offset,
58 c->dwarf.ip) < 0) {
59 return 0;
60 }
61 }
62
63 c->dwarf.rel_pc = c->dwarf.ip -
64 c->dwarf.cached_map->start +
65 c->dwarf.cached_map->offset +
66 c->dwarf.cached_map->ei.load_bias;
67 return c->dwarf.rel_pc;
68 }
69
unw_get_previous_instr_sz(unw_cursor_t * cursor)70 unw_word_t unw_get_previous_instr_sz(unw_cursor_t *cursor)
71 {
72 return get_previous_instr_sz(cursor);
73 }
74
75 struct map_info*
unw_get_map(unw_cursor_t * cursor)76 unw_get_map (unw_cursor_t *cursor)
77 {
78 struct cursor *c = (struct cursor *) cursor;
79 return get_map(c->dwarf.as->map_list, c->dwarf.ip);
80 }
81
82 struct map_info*
unw_get_maps(unw_cursor_t * cursor)83 unw_get_maps (unw_cursor_t *cursor)
84 {
85 struct cursor *c = (struct cursor *) cursor;
86 return c->dwarf.as->map_list;
87 }
88
89 /*
90 0 success
91 -1 failed, not found
92 */
93 int
unw_get_symbol_info(struct unw_cursor * cursor,uint64_t pc,int buf_sz,char * buf,uint64_t * sym_start,uint64_t * sym_end)94 unw_get_symbol_info(struct unw_cursor *cursor, uint64_t pc, int buf_sz, char *buf, uint64_t *sym_start, uint64_t *sym_end)
95 {
96 struct map_info* map = unw_get_map(cursor);
97 if (map == NULL) {
98 return -1;
99 }
100
101 return elf_w (get_symbol_info_in_image)(&(map->ei), map->start, map->offset, pc, buf_sz, buf, sym_start, sym_end);
102 }
103
104 int
unw_get_symbol_info_by_pc(unw_addr_space_t as,uint64_t pc,int buf_sz,char * buf,uint64_t * sym_start,uint64_t * sym_end)105 unw_get_symbol_info_by_pc(unw_addr_space_t as, uint64_t pc, int buf_sz, char *buf, uint64_t *sym_start, uint64_t *sym_end)
106 {
107 #ifdef UNW_REMOTE_ONLY
108 return -1;
109 #else
110 if (as->map_list == NULL) {
111 return -1;
112 }
113
114 struct map_info* map = tdep_get_elf_image(as, as->pid, pc);
115 if (map == NULL) {
116 return -1;
117 }
118
119 return elf_w (get_symbol_info_in_image)(&(map->ei), map->start, map->offset, pc, buf_sz, buf, sym_start, sym_end);
120 #endif
121 }
122
123 void
unw_init_local_address_space(unw_addr_space_t * as)124 unw_init_local_address_space(unw_addr_space_t* as)
125 {
126 #ifdef UNW_REMOTE_ONLY
127 return;
128 #else
129 if (as == NULL) {
130 return;
131 }
132
133 if (*as != NULL) {
134 return;
135 }
136
137 (*as)= (unw_addr_space_t)calloc(1, sizeof(struct unw_addr_space));
138 unw_init_local_addr_space(*as);
139 int pid = -1;
140 (*as)->pid = pid;
141 (*as)->map_list = maps_create_list(pid);
142 #endif
143 }
144
145 void
unw_destroy_local_address_space(unw_addr_space_t as)146 unw_destroy_local_address_space(unw_addr_space_t as)
147 {
148 #ifdef UNW_REMOTE_ONLY
149 return;
150 #else
151 if (as == NULL) {
152 return;
153 }
154
155 if (as->map_list != NULL) {
156 maps_destroy_list(as->map_list);
157 as->map_list = NULL;
158 }
159
160 free(as);
161 #endif
162 }
163
164 void
unw_set_context(unw_cursor_t * cursor,uintptr_t regs[],int reg_sz)165 unw_set_context(unw_cursor_t * cursor, uintptr_t regs[], int reg_sz)
166 {
167 struct cursor *c = (struct cursor *) cursor;
168 int min_sz = reg_sz < DWARF_NUM_PRESERVED_REGS ? reg_sz : DWARF_NUM_PRESERVED_REGS;
169 c->dwarf.reg_sz = min_sz;
170 for (int i = 0; i < min_sz; i++) {
171 c->dwarf.ctx[i] = regs[i];
172 }
173
174 #if defined(__arm__)
175 c->dwarf.ip = regs[UNW_ARM_R15];
176 c->dwarf.cfa = regs[UNW_REG_SP];
177 #elif defined(__aarch64__)
178 c->dwarf.ip = regs[UNW_AARCH64_PC];
179 c->dwarf.cfa = regs[UNW_REG_SP];
180 #elif defined(__x86_64__)
181 c->dwarf.ip = regs[UNW_REG_IP];
182 c->dwarf.cfa = regs[UNW_REG_SP];
183 #endif
184 return;
185 }
186
187 void
unw_set_adjust_pc(struct unw_cursor * cursor,uint64_t pc)188 unw_set_adjust_pc(struct unw_cursor *cursor, uint64_t pc)
189 {
190 struct cursor *c = (struct cursor *) cursor;
191 c->dwarf.ip = pc;
192 }
193
194 bool
unw_is_ark_managed_frame(struct cursor * c)195 unw_is_ark_managed_frame(struct cursor* c)
196 {
197 if (c->dwarf.cached_map != NULL) {
198 Dprintf("cached map with elf image, not ark frame.\n");
199 return false;
200 }
201
202 struct map_info* map = get_map(c->dwarf.as->map_list, c->dwarf.ip);
203 if (map == NULL) {
204 Dprintf("Not mapped ip.\n");
205 return false;
206 }
207
208 if ((strstr(map->path, "[anon:ArkTS Code]") == NULL) &&
209 (strstr(map->path, "/dev/zero") == NULL)) {
210 Dprintf("Not ark map:%s.\n", map->path);
211 return false;
212 }
213
214 if ((map->flags & PROT_EXEC) == 0) {
215 Dprintf("Target map is not executable.\n");
216 return false;
217 }
218
219 return true;
220 }
221
222 #define ARK_LIB_NAME "libark_jsruntime.so"
223 int (*step_ark_managed_native_frame_fn)(int, uintptr_t*, uintptr_t*, uintptr_t*, char*, size_t);
224 int (*get_ark_js_heap_crash_info_fn)(int, uintptr_t *, uintptr_t *, int, char *, size_t);
225 void* handle = NULL; // this handle will never be unloaded
226 pthread_mutex_t lock;
227
228 int
unw_step_ark_managed_native_frame(int pid,uintptr_t * pc,uintptr_t * fp,uintptr_t * sp,char * buf,size_t buf_sz)229 unw_step_ark_managed_native_frame(int pid, uintptr_t* pc, uintptr_t* fp, uintptr_t* sp, char* buf, size_t buf_sz)
230 {
231 if (step_ark_managed_native_frame_fn != NULL) {
232 return step_ark_managed_native_frame_fn(pid, pc, fp, sp, buf, buf_sz);
233 }
234
235 pthread_mutex_lock(&lock);
236 if (step_ark_managed_native_frame_fn != NULL) {
237 pthread_mutex_unlock(&lock);
238 return step_ark_managed_native_frame_fn(pid, pc, fp, sp, buf, buf_sz);
239 }
240
241 if (handle == NULL) {
242 handle = dlopen(ARK_LIB_NAME, RTLD_LAZY);
243 if (handle == NULL) {
244 Dprintf("Failed to load library(%s).\n", dlerror());
245 pthread_mutex_unlock(&lock);
246 return -1;
247 }
248 }
249
250 *(void**)(&step_ark_managed_native_frame_fn) = dlsym(handle, "step_ark_managed_native_frame");
251 if (!step_ark_managed_native_frame_fn) {
252 Dprintf("Failed to find symbol(%s).\n", dlerror());
253 handle = NULL;
254 pthread_mutex_unlock(&lock);
255 return -1;
256 }
257
258 pthread_mutex_unlock(&lock);
259 return step_ark_managed_native_frame_fn(pid, pc, fp, sp, buf, buf_sz);
260 }
261
262 int
unw_get_ark_js_heap_crash_info(int pid,uintptr_t * x20,uintptr_t * fp,int out_js_info,char * buf,size_t buf_sz)263 unw_get_ark_js_heap_crash_info(int pid, uintptr_t* x20, uintptr_t* fp, int out_js_info, char* buf, size_t buf_sz)
264 {
265 if (get_ark_js_heap_crash_info_fn != NULL) {
266 return get_ark_js_heap_crash_info_fn(pid, x20, fp, out_js_info, buf, buf_sz);
267 }
268
269 pthread_mutex_lock(&lock);
270 if (get_ark_js_heap_crash_info_fn != NULL) {
271 pthread_mutex_unlock(&lock);
272 return get_ark_js_heap_crash_info_fn(pid, x20, fp, out_js_info, buf, buf_sz);
273 }
274
275 if (handle == NULL) {
276 handle = dlopen(ARK_LIB_NAME, RTLD_LAZY);
277 if (handle == NULL) {
278 Dprintf("Failed to load library(%s).\n", dlerror());
279 pthread_mutex_unlock(&lock);
280 return -1;
281 }
282 }
283
284 *(void**)(&get_ark_js_heap_crash_info_fn) = dlsym(handle, "get_ark_js_heap_crash_info");
285 if (!get_ark_js_heap_crash_info_fn) {
286 Dprintf("Failed to find symbol(%s).\n", dlerror());
287 handle = NULL;
288 pthread_mutex_unlock(&lock);
289 return -1;
290 }
291
292 pthread_mutex_unlock(&lock);
293 return get_ark_js_heap_crash_info_fn(pid, x20, fp, out_js_info, buf, buf_sz);
294 }
295
296 bool
unw_get_build_id(struct map_info * map,uint8_t ** build_id_ptr,size_t * length)297 unw_get_build_id (struct map_info* map, uint8_t** build_id_ptr, size_t* length)
298 {
299 #ifdef PARSE_BUILD_ID
300 if (map == NULL) {
301 return false;
302 }
303
304 if (map->ei.build_id_note == NULL) {
305 return false;
306 }
307
308 *build_id_ptr = map->ei.build_id_note->build_id;
309 *length = map->ei.build_id_note->nhdr.n_descsz;
310 return true;
311 #else
312 return false;
313 #endif
314 }
315
316 int
unw_get_library_name_by_map(struct map_info * map,char * buf,int buf_sz)317 unw_get_library_name_by_map(struct map_info* map, char *buf, int buf_sz)
318 {
319 if (map == NULL || buf == NULL) {
320 Dprintf("Invaild map_info or buffer.\n");
321 return -1;
322 }
323
324 if (map->ei.image == NULL || map->ei.lib_name_offset == 0) {
325 Dprintf("Invaild elf_image or lib_name_offset.\n");
326 return -1;
327 }
328
329 if (map->ei.strtab == NULL) {
330 Dprintf("Invaild str_tab.\n");
331 return -1;
332 }
333
334 if (strlen(map->ei.strtab + map->ei.lib_name_offset) > 1024) {
335 Dprintf("Invaild library name.\n");
336 return -1;
337 }
338
339 strncpy (buf, map->ei.strtab + map->ei.lib_name_offset, buf_sz);
340 return 0;
341 }
342