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) 43struct EHABIIndexEntry { 44 uint32_t functionOffset; 45 uint32_t data; 46}; 47#endif 48 49#if defined(_AIX) 50namespace libunwind { 51char *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 94extern char __eh_frame_start; 95extern char __eh_frame_end; 96 97#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) 98extern char __eh_frame_hdr_start; 99extern 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. 106extern char __exidx_start; 107extern 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 121namespace libunwind { 122 123/// Used by findUnwindSections() to return info about needed sections. 124struct 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 152class UnwindInfoSectionsCache { 153public: 154 155 struct CacheItem { 156 CacheItem(UnwindInfoSections &uis, uintptr_t pc) 157 : m_uis(uis), m_pc(pc) { 158 } 159 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 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 175 UnwindInfoSectionsCache() { 176 m_head = RB_INITIALIZER(&head); 177 } 178 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 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 203private: 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. 212class _LIBUNWIND_HIDDEN LocalAddressSpace { 213public: 214 typedef uintptr_t pint_t; 215 typedef intptr_t sint_t; 216 uint8_t get8(pint_t addr) { 217 uint8_t val; 218 memcpy(&val, (void *)addr, sizeof(val)); 219 return val; 220 } 221 uint16_t get16(pint_t addr) { 222 uint16_t val; 223 memcpy(&val, (void *)addr, sizeof(val)); 224 return val; 225 } 226 uint32_t get32(pint_t addr) { 227 uint32_t val; 228 memcpy(&val, (void *)addr, sizeof(val)); 229 return val; 230 } 231 uint64_t get64(pint_t addr) { 232 uint64_t val; 233 memcpy(&val, (void *)addr, sizeof(val)); 234 return val; 235 } 236 double getDouble(pint_t addr) { 237 double val; 238 memcpy(&val, (void *)addr, sizeof(val)); 239 return val; 240 } 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 261inline 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 269inline 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. 278inline 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. 303inline 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 323inline LocalAddressSpace::pint_t 324LocalAddressSpace::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 437struct _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. 448static FrameHeaderCache TheFrameHeaderCache; 449#endif 450 451static 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 465static 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 497static 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 547inline 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 701inline 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 708inline 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