• 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 "libunwind_i.h"
32 #include "map_info.h"
33 #include "os-linux.h"
34 
35 struct map_info *
maps_create_list(pid_t pid)36 maps_create_list(pid_t pid)
37 {
38   struct map_iterator mi;
39   unsigned long start, end, offset, flags;
40   struct map_info *map_list = NULL;
41   struct map_info *cur_map;
42   struct map_info *buf;
43   int sz;
44   int index = 0;
45   if ((sz = maps_init (&mi, pid)) < 0)
46     return NULL;
47 
48   if (sz < 0 || sz > 65536) {
49     return NULL;
50   }
51 
52   int buf_sz = sz + 256;
53   buf = (struct map_info*)mmap(NULL, buf_sz * sizeof(struct map_info), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
54   if (buf == NULL) {
55     return NULL;
56   }
57 
58   while (maps_next (&mi, &start, &end, &offset, &flags))
59     {
60       if (index >= buf_sz) {
61         Dprintf("Lost Map:%p-%p %s\n", (void*)start, (void*)end, mi.path);
62         continue;
63       }
64 
65       cur_map = &buf[index];
66       cur_map->next = map_list;
67       cur_map->start = start;
68       cur_map->end = end;
69       cur_map->offset = offset;
70       cur_map->flags = flags;
71       cur_map->path = strdup(mi.path);
72       cur_map->ei.size = 0;
73       cur_map->ei.image = NULL;
74       cur_map->ei.has_dyn_info = 0;
75       cur_map->ei.load_bias = -1;
76       cur_map->ei.strtab = NULL;
77       cur_map->sz = sz;
78       cur_map->buf = buf;
79       cur_map->buf_sz = buf_sz;
80       map_list = cur_map;
81       index = index + 1;
82     }
83   if (map_list != NULL) {
84       map_list->sz = index;
85   } else {
86       munmap(buf, buf_sz * sizeof(struct map_info));
87   }
88   maps_close (&mi);
89   Debug(12, "Finish create map list, sz:%d, index%d.\n", sz, index);
90   return map_list;
91 }
92 
93 void
maps_destroy_list(struct map_info * map_info)94 maps_destroy_list(struct map_info *map_info)
95 {
96   struct map_info *map;
97   int buf_sz  = map_info->buf_sz;
98   void* buf = map_info->buf;
99   while (map_info)
100     {
101       map = map_info;
102       map_info = map->next;
103       if (map->ei.image != MAP_FAILED && map->ei.image != NULL) {
104         munmap(map->ei.image, map->ei.size);
105         map->ei.image = NULL;
106       }
107 
108       if (map->mdi.image != MAP_FAILED && map->mdi.image != NULL) {
109         munmap(map->mdi.image, map->mdi.size);
110         map->mdi.image = NULL;
111       }
112 
113       if (map->path) {
114         free(map->path);
115         map->path = NULL;
116       }
117       map = NULL;
118     }
119   if (buf != NULL) {
120     munmap(buf, buf_sz * sizeof(struct map_info));
121     buf = NULL;
122   }
123 }
124 
125 struct map_info *
get_map(struct map_info * map_list,unw_word_t addr)126 get_map(struct map_info *map_list, unw_word_t addr)
127 {
128   if (map_list == NULL) {
129     return NULL;
130   }
131 
132   struct map_info* buf = map_list->buf;
133   if (buf == NULL) {
134     return NULL;
135   }
136 
137   int begin = 0;
138   int end = map_list->sz - 1;
139   while (begin <= end) {
140     int mid = begin + ((end - begin) / 2);
141     if (addr < buf[mid].start) {
142       end = mid - 1;
143     } else if (addr <= buf[mid].end) {
144       return &buf[mid];
145     } else {
146       begin = mid + 1;
147     }
148   }
149 
150   if ((addr >= buf[begin].start) && (addr <= buf[begin].end)) {
151     return &buf[begin];
152   }
153 
154   Dprintf("Could not find map for addr:%p\n", (void*)addr);
155   return NULL;
156 }
157 
maps_is_readable(struct map_info * map_list,unw_word_t addr)158 int maps_is_readable(struct map_info *map_list, unw_word_t addr)
159 {
160   /* If there is no map, assume everything is okay. */
161   if (map_list == NULL)
162     return 1;
163   struct map_info *map = get_map(map_list, addr);
164   if (map != NULL)
165     return ((map->flags & PROT_READ) && (addr <= (map->end - sizeof(unw_word_t))));
166   return 0;
167 }
168 
maps_is_writable(struct map_info * map_list,unw_word_t addr)169 int maps_is_writable(struct map_info *map_list, unw_word_t addr)
170 {
171   /* If there is no map, assume everything is okay. */
172   if (map_list == NULL)
173     return 1;
174   struct map_info *map = get_map(map_list, addr);
175   if (map != NULL)
176     return ((map->flags & PROT_WRITE) && (addr <= (map->end - sizeof(unw_word_t))));
177   return 0;
178 }
179 
180 struct map_info*
tdep_get_elf_image(unw_addr_space_t as,pid_t pid,unw_word_t ip)181 tdep_get_elf_image(unw_addr_space_t as, pid_t pid, unw_word_t ip)
182 {
183   struct map_info *map;
184   struct cursor* cursor = get_cursor_from_as(as);
185   int find_cached_map = ((cursor != NULL) && (cursor->dwarf.ip == ip));
186   if (find_cached_map  &&
187     (cursor->dwarf.ip == cursor->dwarf.cached_ip) && cursor->dwarf.cached_map != NULL) {
188     return cursor->dwarf.cached_map;
189   }
190 
191   if (as->map_list == NULL && pid > 0) {
192     as->map_list = maps_create_list(pid);
193     if (as->map_list == NULL) {
194       Dprintf("Failed to maps_create_list for pid:%d\n", pid);
195       return NULL;
196     }
197   }
198 
199 
200   map = get_map(as->map_list, ip);
201   if (!map)
202     return NULL;
203 
204   if (map->ei.image == NULL)
205     {
206       int ret = elf_map_image(&map->ei, map->path);
207       if (ret < 0)
208         {
209           map->ei.image = NULL;
210           map->ei.has_try_load = 1;
211           Dprintf("Failed to elf_map_image for ip:%p\n", (void*)ip);
212           return NULL;
213         }
214       map->ei.mdi = &(map->mdi);
215     }
216 
217   if (find_cached_map) {
218     cursor->dwarf.cached_map = map;
219     cursor->dwarf.cached_ip = ip;
220   }
221   return map;
222 }
223 
get_previous_instr_sz(unw_cursor_t * cursor)224 unw_word_t get_previous_instr_sz(unw_cursor_t *cursor)
225 {
226   struct cursor *c = (struct cursor *) cursor;
227   unw_addr_space_t as = c->dwarf.as;
228   unw_accessors_t *a = unw_get_accessors (as);
229   unw_word_t ip = c->dwarf.ip;
230   int sz = 4;
231 #if defined(UNW_TARGET_ARM)
232   if (ip)
233     {
234       if (ip & 1)
235         {
236           void *arg;
237           unw_word_t value;
238           arg = c->dwarf.as_arg;
239           // 0xe000f000 ---> machine code of blx Instr (blx label)
240           if (ip < 5 || (*a->access_mem) (as, ip - 5, &value, 0, arg) < 0 ||
241               (value & 0xe000f000) != 0xe000f000)
242             sz = 2;
243         }
244     }
245 #elif defined(UNW_TARGET_ARM64)
246   sz = 4;
247 #elif defined(UNW_TARGET_X86)
248   sz = 1;
249 #elif defined(UNW_TARGET_x86_64)
250   sz = 1;
251 #else
252 // other arch need to be add here.
253 #endif
254   return sz;
255 }
256 
257 
258 #ifndef UNW_REMOTE_ONLY
259 
260 void
tdep_get_exe_image_path(char * path)261 tdep_get_exe_image_path (char *path)
262 {
263   strcpy(path, "/proc/self/exe");
264 }
265 
266 #endif /* !UNW_REMOTE_ONLY */
267