/src/libunwind/src/os-linux.c
Line | Count | Source |
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/stat.h> |
29 | | #include <string.h> |
30 | | #include <stdlib.h> |
31 | | #include <assert.h> |
32 | | |
33 | | #include "libunwind_i.h" |
34 | | #include "os-linux.h" |
35 | | |
36 | | #ifndef MAX_VDSO_SIZE |
37 | | /*Dont know what is the Max Size in my system it was 8192 or twice the page size*/ |
38 | 0 | # define MAX_VDSO_SIZE ((size_t) 2 * sysconf (_SC_PAGESIZE)) |
39 | | #endif |
40 | | |
41 | | #ifndef MAP_32BIT |
42 | | # define MAP_32BIT 0 |
43 | | #endif |
44 | | |
45 | | |
46 | | int |
47 | | tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei, pid_t pid, unw_word_t ip, |
48 | | unsigned long *segbase, unsigned long *mapoff, |
49 | | char *path, size_t pathlen, |
50 | | void *arg) |
51 | 29.5k | { |
52 | 29.5k | struct map_iterator mi; |
53 | 29.5k | int found = 0, rc = UNW_ESUCCESS; |
54 | 29.5k | unsigned long hi; |
55 | 29.5k | char root[sizeof ("/proc/0123456789/root")], *cp; |
56 | 29.5k | char *full_path; |
57 | 29.5k | struct stat st; |
58 | 29.5k | unw_accessors_t *a; |
59 | 29.5k | unw_word_t magic; |
60 | | |
61 | | |
62 | 29.5k | if (maps_init (&mi, pid) < 0) |
63 | 0 | return -1; |
64 | | |
65 | 103k | while (maps_next (&mi, segbase, &hi, mapoff, NULL)) |
66 | 103k | if (ip >= *segbase && ip < hi) |
67 | 29.5k | { |
68 | 29.5k | found = 1; |
69 | 29.5k | break; |
70 | 29.5k | } |
71 | | |
72 | 29.5k | if (!found) |
73 | 0 | { |
74 | 0 | maps_close (&mi); |
75 | 0 | return -1; |
76 | 0 | } |
77 | | |
78 | | // get path only, no need to map elf image |
79 | 29.5k | if (!ei && path) |
80 | 0 | { |
81 | 0 | strncpy(path, mi.path, pathlen); |
82 | 0 | path[pathlen - 1] = '\0'; |
83 | 0 | if (strlen(mi.path) >= pathlen) |
84 | 0 | rc = -UNW_ENOMEM; |
85 | |
|
86 | 0 | maps_close (&mi); |
87 | 0 | return rc; |
88 | 0 | } |
89 | | |
90 | 29.5k | full_path = mi.path; |
91 | | |
92 | | /* Get process root */ |
93 | 29.5k | memcpy (root, "/proc/", 6); |
94 | 29.5k | cp = unw_ltoa (root + 6, pid); |
95 | 29.5k | assert (cp + 6 < root + sizeof (root)); |
96 | 29.5k | memcpy (cp, "/root", 6); |
97 | | |
98 | 29.5k | size_t _len = strlen (mi.path) + 1; |
99 | 29.5k | if (!stat(root, &st) && S_ISDIR(st.st_mode)) |
100 | 29.5k | _len += strlen (root); |
101 | 0 | else |
102 | 0 | root[0] = '\0'; |
103 | | |
104 | 29.5k | full_path = path; |
105 | 29.5k | if(!path) |
106 | 0 | full_path = (char*) malloc (_len); |
107 | 29.5k | else if(_len >= pathlen) // passed buffer is too small, fail |
108 | 0 | { |
109 | 0 | maps_close (&mi); |
110 | 0 | return -1; |
111 | 0 | } |
112 | | |
113 | 29.5k | strcpy (full_path, root); |
114 | 29.5k | strcat (full_path, mi.path); |
115 | | |
116 | 29.5k | if (stat(full_path, &st) || !S_ISREG(st.st_mode)) |
117 | 0 | strcpy(full_path, mi.path); |
118 | | |
119 | 29.5k | rc = elf_map_image (ei, full_path); |
120 | | |
121 | | /*Follwing code is adapted from |
122 | | https://sourceware.org/pipermail/frysk-cvs/2008q1/007245.html, |
123 | | For VDSO there is no file in the file system, so read the ELF , |
124 | | and create mmaped file for the content of the VDSO |
125 | | */ |
126 | 29.5k | if (rc != -1) |
127 | 29.5k | { |
128 | 29.5k | maps_close (&mi); |
129 | 29.5k | goto err_exit; |
130 | 29.5k | } |
131 | | |
132 | | /* If the above failed, try to bring in page-sized segments directly |
133 | | from process memory. This enables us to locate VDSO unwind |
134 | | tables. */ |
135 | 0 | ei->size = hi - *segbase; |
136 | 0 | if (ei->size > MAX_VDSO_SIZE) |
137 | 0 | { |
138 | 0 | maps_close (&mi); |
139 | 0 | goto err_exit; |
140 | 0 | } |
141 | | |
142 | 0 | a = unw_get_accessors (as); |
143 | 0 | if (! a->access_mem) |
144 | 0 | { |
145 | 0 | maps_close (&mi); |
146 | 0 | goto err_exit; |
147 | 0 | } |
148 | | |
149 | | /* Try to decide whether it's an ELF image before bringing it all |
150 | | in. */ |
151 | 0 | if (ei->size <= EI_CLASS || ei->size <= sizeof (magic)) |
152 | 0 | { |
153 | 0 | maps_close (&mi); |
154 | 0 | goto err_exit; |
155 | 0 | } |
156 | | |
157 | 0 | if (sizeof (magic) >= SELFMAG) |
158 | 0 | { |
159 | 0 | int ret = (*a->access_mem) (as, *segbase, &magic, 0, arg); |
160 | 0 | if (ret < 0) |
161 | 0 | { |
162 | 0 | rc = ret; |
163 | 0 | maps_close (&mi); |
164 | 0 | goto err_exit; |
165 | 0 | } |
166 | | |
167 | 0 | if (memcmp (&magic, ELFMAG, SELFMAG) != 0) |
168 | 0 | { |
169 | 0 | maps_close (&mi); |
170 | 0 | goto err_exit; |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | 0 | ei->image = mmap (0, ei->size, PROT_READ | PROT_WRITE, |
175 | 0 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); |
176 | 0 | if (ei->image == MAP_FAILED) |
177 | 0 | { |
178 | 0 | maps_close (&mi); |
179 | 0 | goto err_exit; |
180 | 0 | } |
181 | | |
182 | 0 | if (sizeof (magic) >= SELFMAG) |
183 | 0 | { |
184 | 0 | *(unw_word_t *)ei->image = magic; |
185 | 0 | hi = sizeof (magic); |
186 | 0 | } |
187 | 0 | else |
188 | 0 | hi = 0; |
189 | |
|
190 | 0 | for (; hi < ei->size; hi += sizeof (unw_word_t)) |
191 | 0 | { |
192 | 0 | rc = (*a->access_mem) (as, *segbase + hi, ei->image + hi, |
193 | 0 | 0, arg); |
194 | 0 | if (rc < 0) |
195 | 0 | { |
196 | 0 | munmap (ei->image, ei->size); |
197 | 0 | maps_close (&mi); |
198 | 0 | goto err_exit; |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | 0 | if (*segbase == *mapoff |
203 | 0 | && (*path == 0 || strcmp (path, "[vdso]") == 0)) |
204 | 0 | *mapoff = 0; |
205 | |
|
206 | 29.5k | err_exit: |
207 | | |
208 | 29.5k | if (!path) |
209 | 0 | free (full_path); |
210 | | |
211 | 29.5k | maps_close (&mi); |
212 | 29.5k | return rc; |
213 | 0 | } |
214 | | |
215 | | #ifndef UNW_REMOTE_ONLY |
216 | | |
217 | | void |
218 | | tdep_get_exe_image_path (char *path) |
219 | 0 | { |
220 | 0 | strcpy(path, "/proc/self/exe"); |
221 | 0 | } |
222 | | |
223 | | #endif /* !UNW_REMOTE_ONLY */ |