• 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 index = 0;
46   if ((maps_init (&mi, pid)) < 0)
47     return NULL;
48   int buf_sz = 1024;
49   buf = (struct map_info*)mmap(NULL, buf_sz * sizeof(struct map_info), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
50   if (buf == NULL) {
51     return NULL;
52   }
53 
54   while (maps_next (&mi, &start, &end, &offset, &flags))
55     {
56       if (index >= buf_sz) {
57         struct map_info *newBuf = (struct map_info *)mmap(NULL, 2 * buf_sz * sizeof(struct map_info), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
58         if (buf != NULL && newBuf != NULL) {
59           memcpy(newBuf, buf, buf_sz * sizeof(struct map_info));
60           munmap(buf, buf_sz * sizeof(struct map_info));
61           buf_sz *= 2;
62           buf = newBuf;
63         } else {
64           Dprintf("Lost Map:%p-%p %s\n", (void*)start, (void*)end, mi.path);
65           continue;
66         }
67       }
68       char *match = strstr(mi.path, "/dev");
69       if (match != NULL && match - mi.path == 0) {
70         continue;
71       }
72       cur_map = &buf[index];
73       cur_map->start = start;
74       cur_map->end = end;
75       cur_map->offset = offset;
76       cur_map->flags = flags;
77       cur_map->path = "";
78       if (mi.path != NULL) {
79         cur_map->path = strdup(mi.path);
80       }
81       cur_map->ei.size = 0;
82       cur_map->ei.image = NULL;
83       cur_map->ei.has_dyn_info = 0;
84       cur_map->ei.load_bias = -1;
85       cur_map->ei.strtab = NULL;
86       cur_map->ei.lib_name_offset = 0;
87       cur_map->sz = buf_sz;
88       cur_map->buf = buf;
89       cur_map->buf_sz = buf_sz;
90       index = index + 1;
91     }
92   if (&buf[0] != NULL) {
93     map_list = &buf[0];
94     map_list->sz = index;
95     map_list->buf = buf;
96     map_list->buf_sz = buf_sz;
97   } else {
98       munmap(buf, buf_sz * sizeof(struct map_info));
99   }
100   maps_close (&mi);
101   Debug(12, "Finish create map list, sz:%d, index%d.\n", sz, index);
102   return map_list;
103 }
104 
105 HIDDEN void
maps_destroy_list(struct map_info * map_info)106 maps_destroy_list(struct map_info *map_info)
107 {
108   struct map_info *map;
109   int buf_sz  = map_info->buf_sz;
110   void* buf = map_info->buf;
111   int sz = map_info->sz;
112   for (int i = 0; i < sz; i++)
113     {
114       map = &map_info[i];
115       if (map->ei.image != MAP_FAILED && map->ei.image != NULL) {
116         munmap(map->ei.image, map->ei.size);
117         map->ei.image = NULL;
118       }
119 
120       if (map->mdi.image != MAP_FAILED && map->mdi.image != NULL) {
121         munmap(map->mdi.image, map->mdi.size);
122         map->mdi.image = NULL;
123       }
124 
125       if (map->path) {
126         free(map->path);
127         map->path = NULL;
128       }
129       map = NULL;
130     }
131   if (buf != NULL) {
132     munmap(buf, buf_sz * sizeof(struct map_info));
133     buf = NULL;
134   }
135 }
136 
137 HIDDEN struct map_info *
get_map(struct map_info * map_list,unw_word_t addr)138 get_map(struct map_info *map_list, unw_word_t addr)
139 {
140   if (map_list == NULL) {
141     return NULL;
142   }
143 
144   struct map_info* buf = map_list->buf;
145   if (buf == NULL) {
146     return NULL;
147   }
148 
149   int begin = 0;
150   int end = map_list->sz - 1;
151   while (begin <= end) {
152     int mid = begin + ((end - begin) / 2);
153     if (addr < buf[mid].start) {
154       end = mid - 1;
155     } else if (addr <= buf[mid].end) {
156       return &buf[mid];
157     } else {
158       begin = mid + 1;
159     }
160   }
161 
162   if ((begin < map_list->sz) && (addr >= buf[begin].start) && (addr <= buf[begin].end)) {
163     return &buf[begin];
164   }
165 
166   Dprintf("Could not find map for addr:%p\n", (void*)addr);
167   return NULL;
168 }
169 
170 HIDDEN int
maps_is_readable(struct map_info * map_list,unw_word_t addr)171 maps_is_readable(struct map_info *map_list, unw_word_t addr)
172 {
173 #ifndef UNW_LOCAL_ONLY
174   if (map_list == NULL)
175     return 1;
176 #endif
177   struct map_info *map = get_map(map_list, addr);
178   if (map != NULL)
179     return map->flags & PROT_READ;
180   return 0;
181 }
182 
183 #ifdef PARSE_ELF_IN_HAP
map_elf_in_hap(struct map_info * map)184 static int map_elf_in_hap(struct map_info *map)
185 {
186   // elf header is in the first mmap area
187   // c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header
188   // c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region
189   // c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap
190   // c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap
191   if (map - 1 == NULL) {
192     Dprintf("no prev map exist.\n");
193     return -1;
194   }
195 
196   struct map_info* prev = map - 1;
197   struct stat stat;
198   int fd;
199   fd = UNW_TEMP_FAILURE_RETRY (open (map->path, O_RDONLY));
200   if (fd < 0) {
201     Dprintf("failed to open hap file.(%d)\n", errno);
202     return -1;
203   }
204 
205   if (fstat (fd, &stat) < 0) {
206     Dprintf("failed to stat hap file sz.(%d)\n", errno);
207     close (fd);
208     return -1;
209   }
210 
211   size_t size = prev->end - prev->start;
212   void* elf = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, prev->offset);
213   if (elf == MAP_FAILED) {
214     Dprintf("failed to map program header in hap.(%d)\n", errno);
215     close (fd);
216     return -1;
217   }
218 
219   map->ei.size = calc_elf_file_size(elf, size);
220   // maybe we should get it from phdr.
221   map->offset = map->offset - prev->offset;
222   munmap(elf, size);
223   if (map->ei.size <= 0 || map->ei.size > (size_t)(stat.st_size - prev->offset))
224   {
225     Dprintf("invalid elf size? sz:%d, hap sz:%d", (int)map->ei.size, (int)stat.st_size);
226     close (fd);
227     return -1;
228   }
229 
230   map->ei.image = mmap (NULL, map->ei.size, PROT_READ, MAP_PRIVATE, fd, prev->offset);
231   close (fd);
232   if (map->ei.image == MAP_FAILED) {
233     Dprintf("failed to map so in hap.\n");
234     return -1;
235   }
236 
237   return 0;
238 }
239 #endif
240 
241 HIDDEN int
maps_is_writable(struct map_info * map_list,unw_word_t addr)242 maps_is_writable(struct map_info *map_list, unw_word_t addr)
243 {
244 #ifndef UNW_LOCAL_ONLY
245   if (map_list == NULL)
246     return 1;
247 #endif
248   struct map_info *map = get_map(map_list, addr);
249   if (map != NULL)
250     return map->flags & PROT_WRITE;
251   return 0;
252 }
253 
254 HIDDEN struct map_info*
tdep_get_elf_image(unw_addr_space_t as,pid_t pid,unw_word_t ip)255 tdep_get_elf_image(unw_addr_space_t as, pid_t pid, unw_word_t ip)
256 {
257   struct map_info *map;
258   struct cursor* cursor = get_cursor_from_as(as);
259   int find_cached_map = ((cursor != NULL) && (cursor->dwarf.ip == ip));
260   if (find_cached_map  &&
261     (cursor->dwarf.ip == cursor->dwarf.cached_ip) && cursor->dwarf.cached_map != NULL) {
262     return cursor->dwarf.cached_map;
263   }
264 
265   if (as->map_list == NULL && pid > 0) {
266     as->map_list = maps_create_list(pid);
267     if (as->map_list == NULL) {
268       Dprintf("Failed to maps_create_list for pid:%d\n", pid);
269       return NULL;
270     }
271   }
272 
273   map = get_map(as->map_list, ip); // ip must located in executable map region
274   if (!map)
275     return NULL;
276 
277   if (map->ei.image == NULL)
278     {
279       if (strstr(map->path, ".hap") != NULL) {
280 #ifdef PARSE_ELF_IN_HAP
281         if (map_elf_in_hap(map) < 0) {
282           Dprintf("invalid map_elf_in_hap?\n");
283           return NULL;
284         }
285 #else
286         Dprintf("Unsupport map_elf_in_hap\n");
287         return NULL;
288 #endif
289       } else {
290         if (elf_map_image(&map->ei, map->path) < 0) {
291             map->ei.image = NULL;
292             map->ei.has_try_load = 1;
293             Dprintf("Failed to elf_map_image for ip:%p\n", (void*)ip);
294             return NULL;
295           }
296       }
297       map->ei.mdi = &(map->mdi);
298     }
299 
300   if (find_cached_map) {
301     cursor->dwarf.cached_map = map;
302     cursor->dwarf.cached_ip = ip;
303   }
304   return map;
305 }
306 
get_previous_instr_sz(unw_cursor_t * cursor)307 unw_word_t get_previous_instr_sz(unw_cursor_t *cursor)
308 {
309   struct cursor *c = (struct cursor *) cursor;
310   unw_addr_space_t as = c->dwarf.as;
311   unw_accessors_t *a = unw_get_accessors (as);
312   unw_word_t ip = c->dwarf.ip;
313   int sz = 4;
314 #if defined(UNW_TARGET_ARM)
315   if (ip)
316     {
317       if (ip & 1)
318         {
319           void *arg;
320           unw_word_t value;
321           arg = c->dwarf.as_arg;
322           // 0xe000f000 ---> machine code of blx Instr (blx label)
323           if (ip < 5 || (*a->access_mem) (as, ip - 5, &value, 0, arg) < 0 ||
324               (value & 0xe000f000) != 0xe000f000)
325             sz = 2;
326         }
327     }
328 #elif defined(UNW_TARGET_ARM64)
329   sz = 4;
330 #elif defined(UNW_TARGET_X86)
331   sz = 1;
332 #elif defined(UNW_TARGET_x86_64)
333   sz = 1;
334 #else
335 // other arch need to be add here.
336 #endif
337   return sz;
338 }
339 
340 
341 #ifndef UNW_REMOTE_ONLY
342 
343 void
tdep_get_exe_image_path(char * path)344 tdep_get_exe_image_path (char *path)
345 {
346   strcpy(path, "/proc/self/exe");
347 }
348 
349 #endif /* !UNW_REMOTE_ONLY */
350