1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //
8 // Abstracts accessing local vs remote address spaces.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef __ADDRESSSPACE_HPP__
13 #define __ADDRESSSPACE_HPP__
14
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/tree.h>
20
21 #include "libunwind.h"
22 #include "config.h"
23 #include "dwarf2.h"
24 #include "EHHeaderParser.hpp"
25 #include "Registers.hpp"
26
27 #ifndef _LIBUNWIND_USE_DLADDR
28 #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
29 #define _LIBUNWIND_USE_DLADDR 1
30 #else
31 #define _LIBUNWIND_USE_DLADDR 0
32 #endif
33 #endif
34
35 #if _LIBUNWIND_USE_DLADDR
36 #include <dlfcn.h>
37 #if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
38 #pragma comment(lib, "dl")
39 #endif
40 #endif
41
42 #if defined(_LIBUNWIND_ARM_EHABI)
43 struct EHABIIndexEntry {
44 uint32_t functionOffset;
45 uint32_t data;
46 };
47 #endif
48
49 #if defined(_AIX)
50 namespace libunwind {
51 char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen,
52 unw_word_t *offset);
53 }
54 #endif
55
56 #ifdef __APPLE__
57
58 struct dyld_unwind_sections
59 {
60 const struct mach_header* mh;
61 const void* dwarf_section;
62 uintptr_t dwarf_section_length;
63 const void* compact_unwind_section;
64 uintptr_t compact_unwind_section_length;
65 };
66
67 // In 10.7.0 or later, libSystem.dylib implements this function.
68 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
69
70 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
71
72 // When statically linked on bare-metal, the symbols for the EH table are looked
73 // up without going through the dynamic loader.
74
75 // The following linker script may be used to produce the necessary sections and symbols.
76 // Unless the --eh-frame-hdr linker option is provided, the section is not generated
77 // and does not take space in the output file.
78 //
79 // .eh_frame :
80 // {
81 // __eh_frame_start = .;
82 // KEEP(*(.eh_frame))
83 // __eh_frame_end = .;
84 // }
85 //
86 // .eh_frame_hdr :
87 // {
88 // KEEP(*(.eh_frame_hdr))
89 // }
90 //
91 // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
92 // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
93
94 extern char __eh_frame_start;
95 extern char __eh_frame_end;
96
97 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
98 extern char __eh_frame_hdr_start;
99 extern char __eh_frame_hdr_end;
100 #endif
101
102 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
103
104 // When statically linked on bare-metal, the symbols for the EH table are looked
105 // up without going through the dynamic loader.
106 extern char __exidx_start;
107 extern char __exidx_end;
108
109 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
110
111 #include <windows.h>
112 #include <psapi.h>
113
114 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
115 defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
116
117 #include <link.h>
118
119 #endif
120
121 namespace libunwind {
122
123 /// Used by findUnwindSections() to return info about needed sections.
124 struct UnwindInfoSections {
125 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
126 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
127 defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
128 // No dso_base for SEH.
129 uintptr_t dso_base;
130 #endif
131 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
132 size_t text_segment_length;
133 #endif
134 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
135 uintptr_t dwarf_section;
136 size_t dwarf_section_length;
137 #endif
138 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
139 uintptr_t dwarf_index_section;
140 size_t dwarf_index_section_length;
141 #endif
142 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
143 uintptr_t compact_unwind_section;
144 size_t compact_unwind_section_length;
145 #endif
146 #if defined(_LIBUNWIND_ARM_EHABI)
147 uintptr_t arm_section;
148 size_t arm_section_length;
149 #endif
150 };
151
152 class UnwindInfoSectionsCache {
153 public:
154
155 struct CacheItem {
CacheItemlibunwind::UnwindInfoSectionsCache::CacheItem156 CacheItem(UnwindInfoSections &uis, uintptr_t pc)
157 : m_uis(uis), m_pc(pc) {
158 }
CacheItemlibunwind::UnwindInfoSectionsCache::CacheItem159 CacheItem(uintptr_t pc)
160 : m_pc(pc) {
161 }
162
163 UnwindInfoSections m_uis;
164 uintptr_t m_pc;
165
166 RB_ENTRY(CacheItem) entry;
167 };
168
169 typedef uintptr_t CacheItemKey;
170
CacheCmp(struct CacheItem * c1,struct CacheItem * c2)171 int CacheCmp(struct CacheItem *c1, struct CacheItem *c2) {
172 return (c1->m_pc < c2->m_pc ? -1 : c1->m_pc > c2->m_pc);
173 }
174
UnwindInfoSectionsCache()175 UnwindInfoSectionsCache() {
176 m_head = RB_INITIALIZER(&head);
177 }
178
getUnwindInfoSectionsForPC(CacheItemKey key,UnwindInfoSections & uis)179 bool getUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) {
180 UnwindInfoSections *result = nullptr;
181 if (m_prev_req_item && m_prev_req_item->m_pc == key)
182 result = &m_prev_req_item->m_uis;
183 else {
184 struct CacheItem find(key), *res;
185 res = RB_FIND(CacheTree, &m_head, &find);
186 if (res) {
187 m_prev_req_item = res;
188 result = &res->m_uis;
189 }
190 }
191 if (result) {
192 uis = *result;
193 return true;
194 }
195 return false;
196 }
197
setUnwindInfoSectionsForPC(CacheItemKey key,UnwindInfoSections & uis)198 void setUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) {
199 CacheItem *p_item(new CacheItem(uis, key));
200 RB_INSERT(CacheTree, &m_head, p_item);
201 }
202
203 private:
204 CacheItem *m_prev_req_item = nullptr;
205 RB_HEAD(CacheTree, CacheItem) m_head;
206 RB_GENERATE(CacheTree, CacheItem, entry, CacheCmp);
207 };
208
209 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
210 /// unwinding a thread in the same process. The wrappers compile away,
211 /// making local unwinds fast.
212 class _LIBUNWIND_HIDDEN LocalAddressSpace {
213 public:
214 typedef uintptr_t pint_t;
215 typedef intptr_t sint_t;
get8(pint_t addr)216 uint8_t get8(pint_t addr) {
217 uint8_t val;
218 memcpy(&val, (void *)addr, sizeof(val));
219 return val;
220 }
get16(pint_t addr)221 uint16_t get16(pint_t addr) {
222 uint16_t val;
223 memcpy(&val, (void *)addr, sizeof(val));
224 return val;
225 }
get32(pint_t addr)226 uint32_t get32(pint_t addr) {
227 uint32_t val;
228 memcpy(&val, (void *)addr, sizeof(val));
229 return val;
230 }
get64(pint_t addr)231 uint64_t get64(pint_t addr) {
232 uint64_t val;
233 memcpy(&val, (void *)addr, sizeof(val));
234 return val;
235 }
getDouble(pint_t addr)236 double getDouble(pint_t addr) {
237 double val;
238 memcpy(&val, (void *)addr, sizeof(val));
239 return val;
240 }
getVector(pint_t addr)241 v128 getVector(pint_t addr) {
242 v128 val;
243 memcpy(&val, (void *)addr, sizeof(val));
244 return val;
245 }
246 uintptr_t getP(pint_t addr);
247 uint64_t getRegister(pint_t addr);
248 static uint64_t getULEB128(pint_t &addr, pint_t end);
249 static int64_t getSLEB128(pint_t &addr, pint_t end);
250
251 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
252 pint_t datarelBase = 0);
253 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
254 unw_word_t *offset);
255 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
256 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
257
258 static LocalAddressSpace sThisAddressSpace;
259 };
260
getP(pint_t addr)261 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
262 #if __SIZEOF_POINTER__ == 8
263 return get64(addr);
264 #else
265 return get32(addr);
266 #endif
267 }
268
getRegister(pint_t addr)269 inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
270 #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
271 return get64(addr);
272 #else
273 return get32(addr);
274 #endif
275 }
276
277 /// Read a ULEB128 into a 64-bit word.
getULEB128(pint_t & addr,pint_t end)278 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
279 const uint8_t *p = (uint8_t *)addr;
280 const uint8_t *pend = (uint8_t *)end;
281 uint64_t result = 0;
282 int bit = 0;
283 do {
284 uint64_t b;
285
286 if (p == pend)
287 _LIBUNWIND_ABORT("truncated uleb128 expression");
288
289 b = *p & 0x7f;
290
291 if (bit >= 64 || b << bit >> bit != b) {
292 _LIBUNWIND_ABORT("malformed uleb128 expression");
293 } else {
294 result |= b << bit;
295 bit += 7;
296 }
297 } while (*p++ >= 0x80);
298 addr = (pint_t) p;
299 return result;
300 }
301
302 /// Read a SLEB128 into a 64-bit word.
getSLEB128(pint_t & addr,pint_t end)303 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
304 const uint8_t *p = (uint8_t *)addr;
305 const uint8_t *pend = (uint8_t *)end;
306 uint64_t result = 0;
307 int bit = 0;
308 uint8_t byte;
309 do {
310 if (p == pend)
311 _LIBUNWIND_ABORT("truncated sleb128 expression");
312 byte = *p++;
313 result |= (uint64_t)(byte & 0x7f) << bit;
314 bit += 7;
315 } while (byte & 0x80);
316 // sign extend negative numbers
317 if ((byte & 0x40) != 0 && bit < 64)
318 result |= (-1ULL) << bit;
319 addr = (pint_t) p;
320 return (int64_t)result;
321 }
322
323 inline LocalAddressSpace::pint_t
getEncodedP(pint_t & addr,pint_t end,uint8_t encoding,pint_t datarelBase)324 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
325 pint_t datarelBase) {
326 pint_t startAddr = addr;
327 const uint8_t *p = (uint8_t *)addr;
328 pint_t result;
329
330 if (encoding == DW_EH_PE_omit) {
331 return (pint_t)NULL;
332 }
333
334 // first get value
335 switch (encoding & 0x0F) {
336 case DW_EH_PE_ptr:
337 result = getP(addr);
338 p += sizeof(pint_t);
339 addr = (pint_t) p;
340 break;
341 case DW_EH_PE_uleb128:
342 result = (pint_t)getULEB128(addr, end);
343 break;
344 case DW_EH_PE_udata2:
345 result = get16(addr);
346 p += 2;
347 addr = (pint_t) p;
348 break;
349 case DW_EH_PE_udata4:
350 result = get32(addr);
351 p += 4;
352 addr = (pint_t) p;
353 break;
354 case DW_EH_PE_udata8:
355 result = (pint_t)get64(addr);
356 p += 8;
357 addr = (pint_t) p;
358 break;
359 case DW_EH_PE_sleb128:
360 result = (pint_t)getSLEB128(addr, end);
361 break;
362 case DW_EH_PE_sdata2:
363 // Sign extend from signed 16-bit value.
364 result = (pint_t)(int16_t)get16(addr);
365 p += 2;
366 addr = (pint_t) p;
367 break;
368 case DW_EH_PE_sdata4:
369 // Sign extend from signed 32-bit value.
370 result = (pint_t)(int32_t)get32(addr);
371 p += 4;
372 addr = (pint_t) p;
373 break;
374 case DW_EH_PE_sdata8:
375 result = (pint_t)get64(addr);
376 p += 8;
377 addr = (pint_t) p;
378 break;
379 default:
380 _LIBUNWIND_ABORT("unknown pointer encoding");
381 }
382
383 // then add relative offset
384 switch (encoding & 0x70) {
385 case DW_EH_PE_absptr:
386 // do nothing
387 break;
388 case DW_EH_PE_pcrel:
389 result += startAddr;
390 break;
391 case DW_EH_PE_textrel:
392 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
393 break;
394 case DW_EH_PE_datarel:
395 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
396 // default value of 0, and we abort in the event that someone calls this
397 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
398 if (datarelBase == 0)
399 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
400 result += datarelBase;
401 break;
402 case DW_EH_PE_funcrel:
403 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
404 break;
405 case DW_EH_PE_aligned:
406 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
407 break;
408 default:
409 _LIBUNWIND_ABORT("unknown pointer encoding");
410 break;
411 }
412
413 if (encoding & DW_EH_PE_indirect)
414 result = getP(result);
415
416 return result;
417 }
418
419 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
420
421 // The ElfW() macro for pointer-size independent ELF header traversal is not
422 // provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
423 // data structures are just called Elf_XXX. Define ElfW() locally.
424 #if !defined(ElfW)
425 #define ElfW(type) Elf_##type
426 #endif
427 #if !defined(Elf_Half)
428 typedef ElfW(Half) Elf_Half;
429 #endif
430 #if !defined(Elf_Phdr)
431 typedef ElfW(Phdr) Elf_Phdr;
432 #endif
433 #if !defined(Elf_Addr)
434 typedef ElfW(Addr) Elf_Addr;
435 #endif
436
437 struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
438 LocalAddressSpace *addressSpace;
439 UnwindInfoSections *sects;
440 uintptr_t targetAddr;
441 };
442
443 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
444 #include "FrameHeaderCache.hpp"
445
446 // Typically there is one cache per process, but when libunwind is built as a
447 // hermetic static library, then each shared object may have its own cache.
448 static FrameHeaderCache TheFrameHeaderCache;
449 #endif
450
checkAddrInSegment(const Elf_Phdr * phdr,size_t image_base,dl_iterate_cb_data * cbdata)451 static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
452 dl_iterate_cb_data *cbdata) {
453 if (phdr->p_type == PT_LOAD) {
454 uintptr_t begin = image_base + phdr->p_vaddr;
455 uintptr_t end = begin + phdr->p_memsz;
456 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
457 cbdata->sects->dso_base = begin;
458 cbdata->sects->text_segment_length = phdr->p_memsz;
459 return true;
460 }
461 }
462 return false;
463 }
464
checkForUnwindInfoSegment(const Elf_Phdr * phdr,size_t image_base,dl_iterate_cb_data * cbdata)465 static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
466 dl_iterate_cb_data *cbdata) {
467 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
468 if (phdr->p_type == PT_GNU_EH_FRAME) {
469 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
470 uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
471 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
472 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
473 if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
474 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
475 hdrInfo)) {
476 // .eh_frame_hdr records the start of .eh_frame, but not its size.
477 // Rely on a zero terminator to find the end of the section.
478 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
479 cbdata->sects->dwarf_section_length = SIZE_MAX;
480 return true;
481 }
482 }
483 return false;
484 #elif defined(_LIBUNWIND_ARM_EHABI)
485 if (phdr->p_type == PT_ARM_EXIDX) {
486 uintptr_t exidx_start = image_base + phdr->p_vaddr;
487 cbdata->sects->arm_section = exidx_start;
488 cbdata->sects->arm_section_length = phdr->p_memsz;
489 return true;
490 }
491 return false;
492 #else
493 #error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
494 #endif
495 }
496
findUnwindSectionsByPhdr(struct dl_phdr_info * pinfo,size_t pinfo_size,void * data)497 static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
498 size_t pinfo_size, void *data) {
499 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
500 if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
501 return 0;
502 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
503 if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
504 return 1;
505 #else
506 // Avoid warning about unused variable.
507 (void)pinfo_size;
508 #endif
509
510 Elf_Addr image_base = pinfo->dlpi_addr;
511
512 // Most shared objects seen in this callback function likely don't contain the
513 // target address, so optimize for that. Scan for a matching PT_LOAD segment
514 // first and bail when it isn't found.
515 bool found_text = false;
516 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
517 if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
518 found_text = true;
519 break;
520 }
521 }
522 if (!found_text)
523 return 0;
524
525 // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
526 // backward.
527 bool found_unwind = false;
528 for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
529 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
530 if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
531 found_unwind = true;
532 break;
533 }
534 }
535 if (!found_unwind)
536 return 0;
537
538 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
539 TheFrameHeaderCache.add(cbdata->sects);
540 #endif
541 return 1;
542 }
543
544 #endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
545
546
findUnwindSections(pint_t targetAddr,UnwindInfoSections & info)547 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
548 UnwindInfoSections &info) {
549 #ifdef __APPLE__
550 dyld_unwind_sections dyldInfo;
551 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
552 info.dso_base = (uintptr_t)dyldInfo.mh;
553 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
554 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
555 info.dwarf_section_length = (size_t)dyldInfo.dwarf_section_length;
556 #endif
557 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
558 info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
559 return true;
560 }
561 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
562 info.dso_base = 0;
563 // Bare metal is statically linked, so no need to ask the dynamic loader
564 info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
565 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
566 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
567 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
568 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
569 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
570 info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
571 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
572 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
573 #endif
574 if (info.dwarf_section_length)
575 return true;
576 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
577 // Bare metal is statically linked, so no need to ask the dynamic loader
578 info.arm_section = (uintptr_t)(&__exidx_start);
579 info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
580 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
581 (void *)info.arm_section, (void *)info.arm_section_length);
582 if (info.arm_section && info.arm_section_length)
583 return true;
584 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
585 HMODULE mods[1024];
586 HANDLE process = GetCurrentProcess();
587 DWORD needed;
588
589 if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
590 DWORD err = GetLastError();
591 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
592 "returned error %d", (int)err);
593 (void)err;
594 return false;
595 }
596
597 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
598 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
599 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
600 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
601 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
602 bool found_obj = false;
603 bool found_hdr = false;
604
605 info.dso_base = (uintptr_t)mods[i];
606 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
607 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
608 uintptr_t end = begin + pish->Misc.VirtualSize;
609 if (!strncmp((const char *)pish->Name, ".text",
610 IMAGE_SIZEOF_SHORT_NAME)) {
611 if (targetAddr >= begin && targetAddr < end)
612 found_obj = true;
613 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
614 IMAGE_SIZEOF_SHORT_NAME)) {
615 info.dwarf_section = begin;
616 info.dwarf_section_length = pish->Misc.VirtualSize;
617 found_hdr = true;
618 }
619 if (found_obj && found_hdr)
620 return true;
621 }
622 }
623 return false;
624 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
625 // Don't even bother, since Windows has functions that do all this stuff
626 // for us.
627 (void)targetAddr;
628 (void)info;
629 return true;
630 #elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
631 // The traceback table is used for unwinding.
632 (void)targetAddr;
633 (void)info;
634 return true;
635 #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
636 int length = 0;
637 info.arm_section =
638 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
639 info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
640 if (info.arm_section && info.arm_section_length)
641 return true;
642 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
643 // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
644 // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
645 // support for _dl_find_object on other unwind formats is not implemented,
646 // yet.
647 #if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
648 // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
649 #if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
650 #error _dl_find_object retrieves an unexpected section type
651 #endif
652 // We look-up `dl_find_object` dynamically at runtime to ensure backwards
653 // compatibility with earlier version of glibc not yet providing it. On older
654 // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
655 // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
656 static decltype(_dl_find_object) *dlFindObject;
657 static bool dlFindObjectChecked = false;
658 if (!dlFindObjectChecked) {
659 dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
660 dlsym(RTLD_DEFAULT, "_dl_find_object"));
661 dlFindObjectChecked = true;
662 }
663 // Try to find the unwind info using `dl_find_object`
664 dl_find_object findResult;
665 if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
666 if (findResult.dlfo_eh_frame == nullptr) {
667 // Found an entry for `targetAddr`, but there is no unwind info.
668 return false;
669 }
670 info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
671 info.text_segment_length = static_cast<size_t>(
672 (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
673
674 // Record the start of PT_GNU_EH_FRAME.
675 info.dwarf_index_section =
676 reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
677 // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
678 // Setting length to `SIZE_MAX` effectively disables all range checks.
679 info.dwarf_index_section_length = SIZE_MAX;
680 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
681 if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
682 *this, info.dwarf_index_section, info.dwarf_index_section_length,
683 hdrInfo)) {
684 return false;
685 }
686 // Record the start of the FDE and use SIZE_MAX to indicate that we do
687 // not know the end address.
688 info.dwarf_section = hdrInfo.eh_frame_ptr;
689 info.dwarf_section_length = SIZE_MAX;
690 return true;
691 }
692 #endif
693 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
694 int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
695 return static_cast<bool>(found);
696 #endif
697
698 return false;
699 }
700
findOtherFDE(pint_t targetAddr,pint_t & fde)701 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
702 // TO DO: if OS has way to dynamically register FDEs, check that.
703 (void)targetAddr;
704 (void)fde;
705 return false;
706 }
707
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)708 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
709 size_t bufLen,
710 unw_word_t *offset) {
711 #if _LIBUNWIND_USE_DLADDR
712 Dl_info dyldInfo;
713 if (dladdr((void *)addr, &dyldInfo)) {
714 if (dyldInfo.dli_sname != NULL) {
715 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
716 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
717 return true;
718 }
719 }
720 #elif defined(_AIX)
721 uint16_t nameLen;
722 char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
723 if (funcName != NULL) {
724 snprintf(buf, bufLen, "%.*s", nameLen, funcName);
725 return true;
726 }
727 #else
728 (void)addr;
729 (void)buf;
730 (void)bufLen;
731 (void)offset;
732 #endif
733 return false;
734 }
735
736 } // namespace libunwind
737
738 #endif // __ADDRESSSPACE_HPP__
739