• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2003-2005 Hewlett-Packard Co
3         Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4 
5 This file is part of libunwind.
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25 
26 #include <limits.h>
27 #include <stdio.h>
28 #include <sys/mman.h>
29 #include <sys/stat.h>
30 
31 #include "compiler.h"
32 #include "elfxx.h"
33 #include "libunwind_i.h"
34 #include "map_info.h"
35 #include "os-linux.h"
36 
37 HIDDEN struct map_info *
maps_create_list(pid_t pid)38 maps_create_list(pid_t pid)
39 {
40   struct map_iterator mi;
41   unsigned long start, end, offset, flags;
42   struct map_info *map_list = NULL;
43   struct map_info *cur_map;
44   struct map_info *buf;
45   int sz;
46   int index = 0;
47   if ((sz = maps_init (&mi, pid)) < 0)
48     return NULL;
49 
50   if (sz < 0 || sz > 65536) {
51     return NULL;
52   }
53 
54   int buf_sz = sz + 256;
55   buf = (struct map_info*)mmap(NULL, buf_sz * sizeof(struct map_info), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
56   if (buf == NULL) {
57     return NULL;
58   }
59 
60   while (maps_next (&mi, &start, &end, &offset, &flags))
61     {
62       if (index >= buf_sz) {
63         Dprintf("Lost Map:%p-%p %s\n", (void*)start, (void*)end, mi.path);
64         continue;
65       }
66 
67       cur_map = &buf[index];
68       cur_map->next = map_list;
69       cur_map->start = start;
70       cur_map->end = end;
71       cur_map->offset = offset;
72       cur_map->flags = flags;
73       cur_map->path = strdup(mi.path);
74       cur_map->ei.size = 0;
75       cur_map->ei.image = NULL;
76       cur_map->ei.has_dyn_info = 0;
77       cur_map->ei.load_bias = -1;
78       cur_map->ei.strtab = NULL;
79       cur_map->ei.lib_name_offset = 0;
80       cur_map->sz = sz;
81       cur_map->buf = buf;
82       cur_map->buf_sz = buf_sz;
83       map_list = cur_map;
84       index = index + 1;
85     }
86   if (map_list != NULL) {
87       map_list->sz = index;
88   } else {
89       munmap(buf, buf_sz * sizeof(struct map_info));
90   }
91   maps_close (&mi);
92   Debug(12, "Finish create map list, sz:%d, index%d.\n", sz, index);
93   return map_list;
94 }
95 
96 HIDDEN void
maps_destroy_list(struct map_info * map_info)97 maps_destroy_list(struct map_info *map_info)
98 {
99   struct map_info *map;
100   int buf_sz  = map_info->buf_sz;
101   void* buf = map_info->buf;
102   while (map_info)
103     {
104       map = map_info;
105       map_info = map->next;
106       if (map->ei.image != MAP_FAILED && map->ei.image != NULL) {
107         munmap(map->ei.image, map->ei.size);
108         map->ei.image = NULL;
109       }
110 
111       if (map->mdi.image != MAP_FAILED && map->mdi.image != NULL) {
112         munmap(map->mdi.image, map->mdi.size);
113         map->mdi.image = NULL;
114       }
115 
116       if (map->path) {
117         free(map->path);
118         map->path = NULL;
119       }
120       map = NULL;
121     }
122   if (buf != NULL) {
123     munmap(buf, buf_sz * sizeof(struct map_info));
124     buf = NULL;
125   }
126 }
127 
128 HIDDEN struct map_info *
get_map(struct map_info * map_list,unw_word_t addr)129 get_map(struct map_info *map_list, unw_word_t addr)
130 {
131   if (map_list == NULL) {
132     return NULL;
133   }
134 
135   struct map_info* buf = map_list->buf;
136   if (buf == NULL) {
137     return NULL;
138   }
139 
140   int begin = 0;
141   int end = map_list->sz - 1;
142   while (begin <= end) {
143     int mid = begin + ((end - begin) / 2);
144     if (addr < buf[mid].start) {
145       end = mid - 1;
146     } else if (addr <= buf[mid].end) {
147       return &buf[mid];
148     } else {
149       begin = mid + 1;
150     }
151   }
152 
153   if ((addr >= buf[begin].start) && (addr <= buf[begin].end)) {
154     return &buf[begin];
155   }
156 
157   Dprintf("Could not find map for addr:%p\n", (void*)addr);
158   return NULL;
159 }
160 
161 HIDDEN int
maps_is_readable(struct map_info * map_list,unw_word_t addr)162 maps_is_readable(struct map_info *map_list, unw_word_t addr)
163 {
164 #ifndef UNW_LOCAL_ONLY
165   if (map_list == NULL)
166     return 1;
167 #endif
168   struct map_info *map = get_map(map_list, addr);
169   if (map != NULL)
170     return map->flags & PROT_READ;
171   return 0;
172 }
173 
174 #ifdef PARSE_ELF_IN_HAP
map_elf_in_hap(struct map_info * map)175 static int map_elf_in_hap(struct map_info *map)
176 {
177   // elf header is in the first mmap area
178   // c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header
179   // c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region
180   // c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap
181   // c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap
182   if (map->next == NULL) {
183     Dprintf("no prev map exist.\n");
184     return -1;
185   }
186 
187   struct map_info* prev = map->next;
188   struct stat stat;
189   int fd;
190   fd = UNW_TEMP_FAILURE_RETRY (open (map->path, O_RDONLY));
191   if (fd < 0) {
192     Dprintf("failed to open hap file.(%d)\n", errno);
193     return -1;
194   }
195 
196   if (fstat (fd, &stat) < 0) {
197     Dprintf("failed to stat hap file sz.(%d)\n", errno);
198     close (fd);
199     return -1;
200   }
201 
202   size_t size = prev->end - prev->start;
203   void* elf = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, prev->offset);
204   if (elf == MAP_FAILED) {
205     Dprintf("failed to map program header in hap.(%d)\n", errno);
206     close (fd);
207     return -1;
208   }
209 
210   map->ei.size = calc_elf_file_size(elf, size);
211   // maybe we should get it from phdr.
212   map->offset = map->offset - prev->offset;
213   munmap(elf, size);
214   if (map->ei.size <= 0 || map->ei.size > (size_t)(stat.st_size - prev->offset))
215   {
216     Dprintf("invalid elf size? sz:%d, hap sz:%d", (int)map->ei.size, (int)stat.st_size);
217     close (fd);
218     return -1;
219   }
220 
221   map->ei.image = mmap (NULL, map->ei.size, PROT_READ, MAP_PRIVATE, fd, prev->offset);
222   close (fd);
223   if (map->ei.image == MAP_FAILED) {
224     Dprintf("failed to map so in hap.\n");
225     return -1;
226   }
227 
228   return 0;
229 }
230 #endif
231 
232 HIDDEN int
maps_is_writable(struct map_info * map_list,unw_word_t addr)233 maps_is_writable(struct map_info *map_list, unw_word_t addr)
234 {
235 #ifndef UNW_LOCAL_ONLY
236   if (map_list == NULL)
237     return 1;
238 #endif
239   struct map_info *map = get_map(map_list, addr);
240   if (map != NULL)
241     return map->flags & PROT_WRITE;
242   return 0;
243 }
244 
245 HIDDEN struct map_info*
tdep_get_elf_image(unw_addr_space_t as,pid_t pid,unw_word_t ip)246 tdep_get_elf_image(unw_addr_space_t as, pid_t pid, unw_word_t ip)
247 {
248   struct map_info *map;
249   struct cursor* cursor = get_cursor_from_as(as);
250   int find_cached_map = ((cursor != NULL) && (cursor->dwarf.ip == ip));
251   if (find_cached_map  &&
252     (cursor->dwarf.ip == cursor->dwarf.cached_ip) && cursor->dwarf.cached_map != NULL) {
253     return cursor->dwarf.cached_map;
254   }
255 
256   if (as->map_list == NULL && pid > 0) {
257     as->map_list = maps_create_list(pid);
258     if (as->map_list == NULL) {
259       Dprintf("Failed to maps_create_list for pid:%d\n", pid);
260       return NULL;
261     }
262   }
263 
264   map = get_map(as->map_list, ip); // ip must located in executable map region
265   if (!map)
266     return NULL;
267 
268   if (map->ei.image == NULL)
269     {
270       if (strstr(map->path, ".hap") != NULL) {
271 #ifdef PARSE_ELF_IN_HAP
272         if (map_elf_in_hap(map) < 0) {
273           Dprintf("invalid map_elf_in_hap?\n");
274           return NULL;
275         }
276 #else
277         Dprintf("Unsupport map_elf_in_hap\n");
278         return NULL;
279 #endif
280       } else {
281         if (elf_map_image(&map->ei, map->path) < 0) {
282             map->ei.image = NULL;
283             map->ei.has_try_load = 1;
284             Dprintf("Failed to elf_map_image for ip:%p\n", (void*)ip);
285             return NULL;
286           }
287       }
288       map->ei.mdi = &(map->mdi);
289     }
290 
291   if (find_cached_map) {
292     cursor->dwarf.cached_map = map;
293     cursor->dwarf.cached_ip = ip;
294   }
295   return map;
296 }
297 
get_previous_instr_sz(unw_cursor_t * cursor)298 unw_word_t get_previous_instr_sz(unw_cursor_t *cursor)
299 {
300   struct cursor *c = (struct cursor *) cursor;
301   unw_addr_space_t as = c->dwarf.as;
302   unw_accessors_t *a = unw_get_accessors (as);
303   unw_word_t ip = c->dwarf.ip;
304   int sz = 4;
305 #if defined(UNW_TARGET_ARM)
306   if (ip)
307     {
308       if (ip & 1)
309         {
310           void *arg;
311           unw_word_t value;
312           arg = c->dwarf.as_arg;
313           // 0xe000f000 ---> machine code of blx Instr (blx label)
314           if (ip < 5 || (*a->access_mem) (as, ip - 5, &value, 0, arg) < 0 ||
315               (value & 0xe000f000) != 0xe000f000)
316             sz = 2;
317         }
318     }
319 #elif defined(UNW_TARGET_ARM64)
320   sz = 4;
321 #elif defined(UNW_TARGET_X86)
322   sz = 1;
323 #elif defined(UNW_TARGET_x86_64)
324   sz = 1;
325 #else
326 // other arch need to be add here.
327 #endif
328   return sz;
329 }
330 
331 
332 #ifndef UNW_REMOTE_ONLY
333 
334 void
tdep_get_exe_image_path(char * path)335 tdep_get_exe_image_path (char *path)
336 {
337   strcpy(path, "/proc/self/exe");
338 }
339 
340 #endif /* !UNW_REMOTE_ONLY */
341