• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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