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