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