]>
Commit | Line | Data |
---|---|---|
eff02e4f ILT |
1 | /* elf.c -- Get debug data from an ELF file for backtraces. |
2 | Copyright (C) 2012 Free Software Foundation, Inc. | |
3 | Written by Ian Lance Taylor, Google. | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions are | |
7 | met: | |
8 | ||
9 | (1) Redistributions of source code must retain the above copyright | |
10 | notice, this list of conditions and the following disclaimer. | |
11 | ||
12 | (2) Redistributions in binary form must reproduce the above copyright | |
13 | notice, this list of conditions and the following disclaimer in | |
14 | the documentation and/or other materials provided with the | |
15 | distribution. | |
16 | ||
17 | (3) The name of the author may not be used to | |
18 | endorse or promote products derived from this software without | |
19 | specific prior written permission. | |
20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
30 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | POSSIBILITY OF SUCH DAMAGE. */ | |
32 | ||
33 | #include "config.h" | |
34 | ||
35 | #include <stdlib.h> | |
36 | #include <string.h> | |
37 | #include <sys/types.h> | |
38 | ||
39 | #include "backtrace.h" | |
40 | #include "internal.h" | |
41 | ||
42 | /* The configure script must tell us whether we are 32-bit or 64-bit | |
43 | ELF. We could make this code test and support either possibility, | |
44 | but there is no point. This code only works for the currently | |
45 | running executable, which means that we know the ELF mode at | |
46 | configure mode. */ | |
47 | ||
48 | #if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 | |
49 | #error "Unknown BACKTRACE_ELF_SIZE" | |
50 | #endif | |
51 | ||
52 | /* Basic types. */ | |
53 | ||
54 | typedef uint16_t Elf_Half; | |
55 | typedef uint32_t Elf_Word; | |
56 | typedef int32_t Elf_Sword; | |
57 | ||
58 | #if BACKTRACE_ELF_SIZE == 32 | |
59 | ||
60 | typedef uint32_t Elf_Addr; | |
61 | typedef uint32_t Elf_Off; | |
62 | ||
63 | typedef uint32_t Elf_WXword; | |
64 | ||
65 | #else | |
66 | ||
67 | typedef uint64_t Elf_Addr; | |
68 | typedef uint64_t Elf_Off; | |
69 | typedef uint64_t Elf_Xword; | |
70 | typedef int64_t Elf_Sxword; | |
71 | ||
72 | typedef uint64_t Elf_WXword; | |
73 | ||
74 | #endif | |
75 | ||
76 | /* Data structures and associated constants. */ | |
77 | ||
78 | #define EI_NIDENT 16 | |
79 | ||
80 | typedef struct { | |
81 | unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ | |
82 | Elf_Half e_type; /* Identifies object file type */ | |
83 | Elf_Half e_machine; /* Specifies required architecture */ | |
84 | Elf_Word e_version; /* Identifies object file version */ | |
85 | Elf_Addr e_entry; /* Entry point virtual address */ | |
86 | Elf_Off e_phoff; /* Program header table file offset */ | |
87 | Elf_Off e_shoff; /* Section header table file offset */ | |
88 | Elf_Word e_flags; /* Processor-specific flags */ | |
89 | Elf_Half e_ehsize; /* ELF header size in bytes */ | |
90 | Elf_Half e_phentsize; /* Program header table entry size */ | |
91 | Elf_Half e_phnum; /* Program header table entry count */ | |
92 | Elf_Half e_shentsize; /* Section header table entry size */ | |
93 | Elf_Half e_shnum; /* Section header table entry count */ | |
94 | Elf_Half e_shstrndx; /* Section header string table index */ | |
95 | } Elf_Ehdr; | |
96 | ||
97 | #define EI_MAG0 0 | |
98 | #define EI_MAG1 1 | |
99 | #define EI_MAG2 2 | |
100 | #define EI_MAG3 3 | |
101 | #define EI_CLASS 4 | |
102 | #define EI_DATA 5 | |
103 | #define EI_VERSION 6 | |
104 | ||
105 | #define ELFMAG0 0x7f | |
106 | #define ELFMAG1 'E' | |
107 | #define ELFMAG2 'L' | |
108 | #define ELFMAG3 'F' | |
109 | ||
110 | #define ELFCLASS32 1 | |
111 | #define ELFCLASS64 2 | |
112 | ||
113 | #define ELFDATA2LSB 1 | |
114 | #define ELFDATA2MSB 2 | |
115 | ||
116 | #define EV_CURRENT 1 | |
117 | ||
118 | typedef struct { | |
119 | Elf_Word sh_name; /* Section name, index in string tbl */ | |
120 | Elf_Word sh_type; /* Type of section */ | |
121 | Elf_WXword sh_flags; /* Miscellaneous section attributes */ | |
122 | Elf_Addr sh_addr; /* Section virtual addr at execution */ | |
123 | Elf_Off sh_offset; /* Section file offset */ | |
124 | Elf_WXword sh_size; /* Size of section in bytes */ | |
125 | Elf_Word sh_link; /* Index of another section */ | |
126 | Elf_Word sh_info; /* Additional section information */ | |
127 | Elf_WXword sh_addralign; /* Section alignment */ | |
128 | Elf_WXword sh_entsize; /* Entry size if section holds table */ | |
129 | } Elf_Shdr; | |
130 | ||
131 | #define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ | |
132 | #define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ | |
133 | ||
134 | #define SHT_SYMTAB 2 | |
135 | #define SHT_STRTAB 3 | |
136 | #define SHT_DYNSYM 11 | |
137 | ||
138 | #if BACKTRACE_ELF_SIZE == 32 | |
139 | ||
140 | typedef struct | |
141 | { | |
142 | Elf_Word st_name; /* Symbol name, index in string tbl */ | |
143 | Elf_Addr st_value; /* Symbol value */ | |
144 | Elf_Word st_size; /* Symbol size */ | |
145 | unsigned char st_info; /* Symbol binding and type */ | |
146 | unsigned char st_other; /* Visibility and other data */ | |
147 | Elf_Half st_shndx; /* Symbol section index */ | |
148 | } Elf_Sym; | |
149 | ||
150 | #else /* BACKTRACE_ELF_SIZE != 32 */ | |
151 | ||
152 | typedef struct | |
153 | { | |
154 | Elf_Word st_name; /* Symbol name, index in string tbl */ | |
155 | unsigned char st_info; /* Symbol binding and type */ | |
156 | unsigned char st_other; /* Visibility and other data */ | |
157 | Elf_Half st_shndx; /* Symbol section index */ | |
158 | Elf_Addr st_value; /* Symbol value */ | |
159 | Elf_Xword st_size; /* Symbol size */ | |
160 | } Elf_Sym; | |
161 | ||
162 | #endif /* BACKTRACE_ELF_SIZE != 32 */ | |
163 | ||
164 | #define STT_FUNC 2 | |
165 | ||
166 | /* An index of ELF sections we care about. */ | |
167 | ||
168 | enum debug_section | |
169 | { | |
170 | DEBUG_INFO, | |
171 | DEBUG_LINE, | |
172 | DEBUG_ABBREV, | |
173 | DEBUG_RANGES, | |
174 | DEBUG_STR, | |
175 | DEBUG_MAX | |
176 | }; | |
177 | ||
178 | /* Names of sections, indexed by enum elf_section. */ | |
179 | ||
180 | static const char * const debug_section_names[DEBUG_MAX] = | |
181 | { | |
182 | ".debug_info", | |
183 | ".debug_line", | |
184 | ".debug_abbrev", | |
185 | ".debug_ranges", | |
186 | ".debug_str" | |
187 | }; | |
188 | ||
189 | /* Information we gather for the sections we care about. */ | |
190 | ||
191 | struct debug_section_info | |
192 | { | |
193 | /* Section file offset. */ | |
194 | off_t offset; | |
195 | /* Section size. */ | |
196 | size_t size; | |
197 | /* Section contents, after read from file. */ | |
198 | const unsigned char *data; | |
199 | }; | |
200 | ||
201 | /* Information we keep for an ELF symbol. */ | |
202 | ||
203 | struct elf_symbol | |
204 | { | |
205 | /* The name of the symbol. */ | |
206 | const char *name; | |
207 | /* The address of the symbol. */ | |
208 | uintptr_t address; | |
209 | /* The size of the symbol. */ | |
210 | size_t size; | |
211 | }; | |
212 | ||
213 | /* Information to pass to elf_syminfo. */ | |
214 | ||
215 | struct elf_syminfo_data | |
216 | { | |
217 | /* The ELF symbols, sorted by address. */ | |
218 | struct elf_symbol *symbols; | |
219 | /* The number of symbols. */ | |
220 | size_t count; | |
221 | }; | |
222 | ||
223 | /* A dummy callback function used when we can't find any debug info. */ | |
224 | ||
225 | static int | |
226 | elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, | |
227 | uintptr_t pc ATTRIBUTE_UNUSED, | |
228 | backtrace_full_callback callback ATTRIBUTE_UNUSED, | |
229 | backtrace_error_callback error_callback, void *data) | |
230 | { | |
231 | error_callback (data, "no debug info in ELF executable", -1); | |
232 | return 0; | |
233 | } | |
234 | ||
235 | /* A dummy callback function used when we can't find a symbol | |
236 | table. */ | |
237 | ||
238 | static void | |
239 | elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, | |
240 | uintptr_t pc ATTRIBUTE_UNUSED, | |
241 | backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, | |
242 | backtrace_error_callback error_callback, void *data) | |
243 | { | |
244 | error_callback (data, "no symbol table in ELF executable", -1); | |
245 | } | |
246 | ||
247 | /* Compare struct elf_symbol for qsort. */ | |
248 | ||
249 | static int | |
250 | elf_symbol_compare (const void *v1, const void *v2) | |
251 | { | |
252 | const struct elf_symbol *e1 = (const struct elf_symbol *) v1; | |
253 | const struct elf_symbol *e2 = (const struct elf_symbol *) v2; | |
254 | ||
255 | if (e1->address < e2->address) | |
256 | return -1; | |
257 | else if (e1->address > e2->address) | |
258 | return 1; | |
259 | else | |
260 | return 0; | |
261 | } | |
262 | ||
263 | /* Compare a PC against an elf_symbol for bsearch. We allocate one | |
264 | extra entry in the array so that this can look safely at the next | |
265 | entry. */ | |
266 | ||
267 | static int | |
268 | elf_symbol_search (const void *vkey, const void *ventry) | |
269 | { | |
270 | const uintptr_t *key = (const uintptr_t *) vkey; | |
271 | const struct elf_symbol *entry = (const struct elf_symbol *) ventry; | |
272 | uintptr_t pc; | |
273 | ||
274 | pc = *key; | |
275 | if (pc < entry->address) | |
276 | return -1; | |
277 | else if (pc >= entry->address + entry->size) | |
278 | return 1; | |
279 | else | |
280 | return 0; | |
281 | } | |
282 | ||
283 | /* Initialize the symbol table info for elf_syminfo. */ | |
284 | ||
285 | static int | |
286 | elf_initialize_syminfo (struct backtrace_state *state, | |
287 | const unsigned char *symtab_data, size_t symtab_size, | |
288 | const unsigned char *strtab, size_t strtab_size, | |
289 | backtrace_error_callback error_callback, | |
290 | void *data, struct elf_syminfo_data *sdata) | |
291 | { | |
292 | size_t sym_count; | |
293 | const Elf_Sym *sym; | |
294 | size_t elf_symbol_count; | |
295 | size_t elf_symbol_size; | |
296 | struct elf_symbol *elf_symbols; | |
297 | size_t i; | |
298 | unsigned int j; | |
299 | ||
300 | sym_count = symtab_size / sizeof (Elf_Sym); | |
301 | ||
302 | /* We only care about function symbols. Count them. */ | |
303 | sym = (const Elf_Sym *) symtab_data; | |
304 | elf_symbol_count = 0; | |
305 | for (i = 0; i < sym_count; ++i, ++sym) | |
306 | { | |
307 | if ((sym->st_info & 0xf) == STT_FUNC) | |
308 | ++elf_symbol_count; | |
309 | } | |
310 | ||
311 | elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol); | |
312 | elf_symbols = ((struct elf_symbol *) | |
313 | backtrace_alloc (state, elf_symbol_size, error_callback, | |
314 | data)); | |
315 | if (elf_symbols == NULL) | |
316 | return 0; | |
317 | ||
318 | sym = (const Elf_Sym *) symtab_data; | |
319 | j = 0; | |
320 | for (i = 0; i < sym_count; ++i, ++sym) | |
321 | { | |
322 | if ((sym->st_info & 0xf) != STT_FUNC) | |
323 | continue; | |
324 | if (sym->st_name >= strtab_size) | |
325 | { | |
326 | error_callback (data, "symbol string index out of range", 0); | |
327 | backtrace_free (state, elf_symbols, elf_symbol_size, error_callback, | |
328 | data); | |
329 | return 0; | |
330 | } | |
331 | elf_symbols[j].name = (const char *) strtab + sym->st_name; | |
332 | elf_symbols[j].address = sym->st_value; | |
333 | elf_symbols[j].size = sym->st_size; | |
334 | ++j; | |
335 | } | |
336 | ||
337 | qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), | |
338 | elf_symbol_compare); | |
339 | ||
340 | sdata->symbols = elf_symbols; | |
341 | sdata->count = elf_symbol_count; | |
342 | ||
343 | return 1; | |
344 | } | |
345 | ||
346 | /* Return the symbol name and value for a PC. */ | |
347 | ||
348 | static void | |
349 | elf_syminfo (struct backtrace_state *state, uintptr_t pc, | |
350 | backtrace_syminfo_callback callback, | |
351 | backtrace_error_callback error_callback ATTRIBUTE_UNUSED, | |
352 | void *data) | |
353 | { | |
354 | struct elf_syminfo_data *edata; | |
355 | struct elf_symbol *sym; | |
356 | ||
357 | edata = (struct elf_syminfo_data *) state->syminfo_data; | |
358 | sym = ((struct elf_symbol *) | |
359 | bsearch (&pc, edata->symbols, edata->count, | |
360 | sizeof (struct elf_symbol), elf_symbol_search)); | |
361 | if (sym == NULL) | |
362 | callback (data, pc, NULL, 0); | |
363 | else | |
364 | callback (data, pc, sym->name, sym->address); | |
365 | } | |
366 | ||
367 | /* Initialize the backtrace data we need from an ELF executable. At | |
368 | the ELF level, all we need to do is find the debug info | |
369 | sections. */ | |
370 | ||
371 | int | |
372 | backtrace_initialize (struct backtrace_state *state, int descriptor, | |
373 | backtrace_error_callback error_callback, | |
374 | void *data, fileline *fileline_fn) | |
375 | { | |
376 | struct backtrace_view ehdr_view; | |
377 | Elf_Ehdr ehdr; | |
378 | off_t shoff; | |
379 | unsigned int shnum; | |
380 | unsigned int shstrndx; | |
381 | struct backtrace_view shdrs_view; | |
382 | int shdrs_view_valid; | |
383 | const Elf_Shdr *shdrs; | |
384 | const Elf_Shdr *shstrhdr; | |
385 | size_t shstr_size; | |
386 | off_t shstr_off; | |
387 | struct backtrace_view names_view; | |
388 | int names_view_valid; | |
389 | const char *names; | |
390 | unsigned int symtab_shndx; | |
391 | unsigned int dynsym_shndx; | |
392 | unsigned int i; | |
393 | struct debug_section_info sections[DEBUG_MAX]; | |
394 | struct backtrace_view symtab_view; | |
395 | int symtab_view_valid; | |
396 | struct backtrace_view strtab_view; | |
397 | int strtab_view_valid; | |
398 | off_t min_offset; | |
399 | off_t max_offset; | |
400 | struct backtrace_view debug_view; | |
401 | int debug_view_valid; | |
402 | ||
403 | shdrs_view_valid = 0; | |
404 | names_view_valid = 0; | |
405 | symtab_view_valid = 0; | |
406 | strtab_view_valid = 0; | |
407 | debug_view_valid = 0; | |
408 | ||
409 | if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, | |
410 | data, &ehdr_view)) | |
411 | goto fail; | |
412 | ||
413 | memcpy (&ehdr, ehdr_view.data, sizeof ehdr); | |
414 | ||
415 | backtrace_release_view (state, &ehdr_view, error_callback, data); | |
416 | ||
417 | if (ehdr.e_ident[EI_MAG0] != ELFMAG0 | |
418 | || ehdr.e_ident[EI_MAG1] != ELFMAG1 | |
419 | || ehdr.e_ident[EI_MAG2] != ELFMAG2 | |
420 | || ehdr.e_ident[EI_MAG3] != ELFMAG3) | |
421 | { | |
422 | error_callback (data, "executable file is not ELF", 0); | |
423 | goto fail; | |
424 | } | |
425 | if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) | |
426 | { | |
427 | error_callback (data, "executable file is unrecognized ELF version", 0); | |
428 | goto fail; | |
429 | } | |
430 | ||
431 | #if BACKTRACE_ELF_SIZE == 32 | |
432 | #define BACKTRACE_ELFCLASS ELFCLASS32 | |
433 | #else | |
434 | #define BACKTRACE_ELFCLASS ELFCLASS64 | |
435 | #endif | |
436 | ||
437 | if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) | |
438 | { | |
439 | error_callback (data, "executable file is unexpected ELF class", 0); | |
440 | goto fail; | |
441 | } | |
442 | ||
443 | if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB | |
444 | && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) | |
445 | { | |
446 | error_callback (data, "executable file has unknown endianness", 0); | |
447 | goto fail; | |
448 | } | |
449 | ||
450 | shoff = ehdr.e_shoff; | |
451 | shnum = ehdr.e_shnum; | |
452 | shstrndx = ehdr.e_shstrndx; | |
453 | ||
454 | if ((shnum == 0 || shstrndx == SHN_XINDEX) | |
455 | && shoff != 0) | |
456 | { | |
457 | struct backtrace_view shdr_view; | |
458 | const Elf_Shdr *shdr; | |
459 | ||
460 | if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, | |
461 | error_callback, data, &shdr_view)) | |
462 | goto fail; | |
463 | ||
464 | shdr = (const Elf_Shdr *) shdr_view.data; | |
465 | ||
466 | if (shnum == 0) | |
467 | shnum = shdr->sh_size; | |
468 | ||
469 | if (shstrndx == SHN_XINDEX) | |
470 | { | |
471 | shstrndx = shdr->sh_link; | |
472 | ||
473 | /* Versions of the GNU binutils between 2.12 and 2.18 did | |
474 | not handle objects with more than SHN_LORESERVE sections | |
475 | correctly. All large section indexes were offset by | |
476 | 0x100. There is more information at | |
477 | http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . | |
478 | Fortunately these object files are easy to detect, as the | |
479 | GNU binutils always put the section header string table | |
480 | near the end of the list of sections. Thus if the | |
481 | section header string table index is larger than the | |
482 | number of sections, then we know we have to subtract | |
483 | 0x100 to get the real section index. */ | |
484 | if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) | |
485 | shstrndx -= 0x100; | |
486 | } | |
487 | ||
488 | backtrace_release_view (state, &shdr_view, error_callback, data); | |
489 | } | |
490 | ||
491 | /* To translate PC to file/line when using DWARF, we need to find | |
492 | the .debug_info and .debug_line sections. */ | |
493 | ||
494 | /* Read the section headers, skipping the first one. */ | |
495 | ||
496 | if (!backtrace_get_view (state, descriptor, shoff + sizeof (Elf_Shdr), | |
497 | (shnum - 1) * sizeof (Elf_Shdr), | |
498 | error_callback, data, &shdrs_view)) | |
499 | goto fail; | |
500 | shdrs_view_valid = 1; | |
501 | shdrs = (const Elf_Shdr *) shdrs_view.data; | |
502 | ||
503 | /* Read the section names. */ | |
504 | ||
505 | shstrhdr = &shdrs[shstrndx - 1]; | |
506 | shstr_size = shstrhdr->sh_size; | |
507 | shstr_off = shstrhdr->sh_offset; | |
508 | ||
509 | if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size, | |
510 | error_callback, data, &names_view)) | |
511 | goto fail; | |
512 | names_view_valid = 1; | |
513 | names = (const char *) names_view.data; | |
514 | ||
515 | symtab_shndx = 0; | |
516 | dynsym_shndx = 0; | |
517 | ||
518 | memset (sections, 0, sizeof sections); | |
519 | for (i = 1; i < shnum; ++i) | |
520 | { | |
521 | const Elf_Shdr *shdr; | |
522 | unsigned int sh_name; | |
523 | const char *name; | |
524 | int j; | |
525 | ||
526 | shdr = &shdrs[i - 1]; | |
527 | ||
528 | if (shdr->sh_type == SHT_SYMTAB) | |
529 | symtab_shndx = i; | |
530 | else if (shdr->sh_type == SHT_DYNSYM) | |
531 | dynsym_shndx = i; | |
532 | ||
533 | sh_name = shdr->sh_name; | |
534 | if (sh_name >= shstr_size) | |
535 | { | |
536 | error_callback (data, "ELF section name out of range", 0); | |
537 | goto fail; | |
538 | } | |
539 | ||
540 | name = names + sh_name; | |
541 | ||
542 | for (j = 0; j < (int) DEBUG_MAX; ++j) | |
543 | { | |
544 | if (strcmp (name, debug_section_names[j]) == 0) | |
545 | { | |
546 | sections[j].offset = shdr->sh_offset; | |
547 | sections[j].size = shdr->sh_size; | |
548 | break; | |
549 | } | |
550 | } | |
551 | } | |
552 | ||
553 | if (symtab_shndx == 0) | |
554 | symtab_shndx = dynsym_shndx; | |
555 | if (symtab_shndx == 0) | |
556 | { | |
557 | state->syminfo_fn = elf_nosyms; | |
558 | state->syminfo_data = NULL; | |
559 | } | |
560 | else | |
561 | { | |
562 | const Elf_Shdr *symtab_shdr; | |
563 | unsigned int strtab_shndx; | |
564 | const Elf_Shdr *strtab_shdr; | |
565 | struct elf_syminfo_data *sdata; | |
566 | ||
567 | symtab_shdr = &shdrs[symtab_shndx - 1]; | |
568 | strtab_shndx = symtab_shdr->sh_link; | |
569 | if (strtab_shndx >= shnum) | |
570 | { | |
571 | error_callback (data, | |
572 | "ELF symbol table strtab link out of range", 0); | |
573 | goto fail; | |
574 | } | |
575 | strtab_shdr = &shdrs[strtab_shndx - 1]; | |
576 | ||
577 | if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, | |
578 | symtab_shdr->sh_size, error_callback, data, | |
579 | &symtab_view)) | |
580 | goto fail; | |
581 | symtab_view_valid = 1; | |
582 | ||
583 | if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, | |
584 | strtab_shdr->sh_size, error_callback, data, | |
585 | &strtab_view)) | |
586 | goto fail; | |
587 | strtab_view_valid = 1; | |
588 | ||
589 | sdata = ((struct elf_syminfo_data *) | |
590 | backtrace_alloc (state, sizeof *sdata, error_callback, data)); | |
591 | if (sdata == NULL) | |
592 | goto fail; | |
593 | ||
594 | if (!elf_initialize_syminfo (state, | |
595 | symtab_view.data, symtab_shdr->sh_size, | |
596 | strtab_view.data, strtab_shdr->sh_size, | |
597 | error_callback, data, sdata)) | |
598 | { | |
599 | backtrace_free (state, sdata, sizeof *sdata, error_callback, data); | |
600 | goto fail; | |
601 | } | |
602 | ||
603 | /* We no longer need the symbol table, but we hold on to the | |
604 | string table permanently. */ | |
605 | backtrace_release_view (state, &symtab_view, error_callback, data); | |
606 | ||
607 | state->syminfo_fn = elf_syminfo; | |
608 | state->syminfo_data = sdata; | |
609 | } | |
610 | ||
611 | /* FIXME: Need to handle compressed debug sections. */ | |
612 | ||
613 | backtrace_release_view (state, &shdrs_view, error_callback, data); | |
614 | shdrs_view_valid = 0; | |
615 | backtrace_release_view (state, &names_view, error_callback, data); | |
616 | names_view_valid = 0; | |
617 | ||
618 | /* Read all the debug sections in a single view, since they are | |
619 | probably adjacent in the file. We never release this view. */ | |
620 | ||
621 | min_offset = 0; | |
622 | max_offset = 0; | |
623 | for (i = 0; i < (int) DEBUG_MAX; ++i) | |
624 | { | |
625 | off_t end; | |
626 | ||
627 | if (min_offset == 0 || sections[i].offset < min_offset) | |
628 | min_offset = sections[i].offset; | |
629 | end = sections[i].offset + sections[i].size; | |
630 | if (end > max_offset) | |
631 | max_offset = end; | |
632 | } | |
633 | if (min_offset == 0 || max_offset == 0) | |
634 | { | |
635 | if (!backtrace_close (descriptor, error_callback, data)) | |
636 | goto fail; | |
637 | state->fileline_fn = elf_nodebug; | |
638 | state->fileline_data = NULL; | |
639 | return 1; | |
640 | } | |
641 | ||
642 | if (!backtrace_get_view (state, descriptor, min_offset, | |
643 | max_offset - min_offset, | |
644 | error_callback, data, &debug_view)) | |
645 | goto fail; | |
646 | debug_view_valid = 1; | |
647 | ||
648 | /* We've read all we need from the executable. */ | |
649 | if (!backtrace_close (descriptor, error_callback, data)) | |
650 | goto fail; | |
651 | descriptor = -1; | |
652 | ||
653 | for (i = 0; i < (int) DEBUG_MAX; ++i) | |
654 | sections[i].data = ((const unsigned char *) debug_view.data | |
655 | + (sections[i].offset - min_offset)); | |
656 | ||
657 | if (!backtrace_dwarf_initialize (state, | |
658 | sections[DEBUG_INFO].data, | |
659 | sections[DEBUG_INFO].size, | |
660 | sections[DEBUG_LINE].data, | |
661 | sections[DEBUG_LINE].size, | |
662 | sections[DEBUG_ABBREV].data, | |
663 | sections[DEBUG_ABBREV].size, | |
664 | sections[DEBUG_RANGES].data, | |
665 | sections[DEBUG_RANGES].size, | |
666 | sections[DEBUG_STR].data, | |
667 | sections[DEBUG_STR].size, | |
668 | ehdr.e_ident[EI_DATA] == ELFDATA2MSB, | |
669 | error_callback, data, fileline_fn)) | |
670 | goto fail; | |
671 | ||
672 | return 1; | |
673 | ||
674 | fail: | |
675 | if (shdrs_view_valid) | |
676 | backtrace_release_view (state, &shdrs_view, error_callback, data); | |
677 | if (names_view_valid) | |
678 | backtrace_release_view (state, &names_view, error_callback, data); | |
679 | if (symtab_view_valid) | |
680 | backtrace_release_view (state, &symtab_view, error_callback, data); | |
681 | if (strtab_view_valid) | |
682 | backtrace_release_view (state, &strtab_view, error_callback, data); | |
683 | if (debug_view_valid) | |
684 | backtrace_release_view (state, &debug_view, error_callback, data); | |
685 | if (descriptor != -1) | |
686 | backtrace_close (descriptor, error_callback, data); | |
687 | return 0; | |
688 | } |