1 //===------------------------- AddressSpace.hpp ---------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 // 9 // Abstracts accessing local vs remote address spaces. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef __ADDRESSSPACE_HPP__ 14 #define __ADDRESSSPACE_HPP__ 15 16 #include <stdint.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 21 #ifndef _LIBUNWIND_IS_BAREMETAL 22 #include <dlfcn.h> 23 #endif 24 25 #ifdef __APPLE__ 26 #include <mach-o/getsect.h> 27 namespace libunwind { 28 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); 29 } 30 #endif 31 32 #include "libunwind.h" 33 #include "config.h" 34 #include "dwarf2.h" 35 #include "Registers.hpp" 36 37 #if _LIBUNWIND_ARM_EHABI 38 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 39 40 typedef void *_Unwind_Ptr; 41 42 #elif defined(__linux__) 43 44 typedef long unsigned int *_Unwind_Ptr; 45 extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len); 46 47 // Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system. 48 #define dl_unwind_find_exidx __gnu_Unwind_Find_exidx 49 50 #elif !defined(_LIBUNWIND_IS_BAREMETAL) 51 #include <link.h> 52 #else // !defined(_LIBUNWIND_IS_BAREMETAL) 53 // When statically linked on bare-metal, the symbols for the EH table are looked 54 // up without going through the dynamic loader. 55 struct EHTEntry { 56 uint32_t functionOffset; 57 uint32_t unwindOpcodes; 58 }; 59 extern EHTEntry __exidx_start; 60 extern EHTEntry __exidx_end; 61 #endif // !defined(_LIBUNWIND_IS_BAREMETAL) 62 #endif // _LIBUNWIND_ARM_EHABI 63 64 #if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \ 65 defined(__linux__) || defined(__NetBSD__) 66 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX 67 #include <link.h> 68 // Macro for machine-independent access to the ELF program headers. This 69 // macro is not available on some systems (e.g., FreeBSD). On these 70 // systems the data structures are just called Elf_XXX. Define ElfW() 71 // locally. 72 #if !defined(ElfW) 73 #define ElfW(type) Elf_##type 74 #endif 75 #include "EHHeaderParser.hpp" 76 #endif 77 #endif 78 79 namespace libunwind { 80 81 /// Used by findUnwindSections() to return info about needed sections. 82 struct UnwindInfoSections { 83 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \ 84 _LIBUNWIND_SUPPORT_COMPACT_UNWIND 85 // No dso_base for ARM EHABI. 86 uintptr_t dso_base; 87 #endif 88 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND 89 uintptr_t dwarf_section; 90 uintptr_t dwarf_section_length; 91 #endif 92 #if _LIBUNWIND_SUPPORT_DWARF_INDEX 93 uintptr_t dwarf_index_section; 94 uintptr_t dwarf_index_section_length; 95 #endif 96 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND 97 uintptr_t compact_unwind_section; 98 uintptr_t compact_unwind_section_length; 99 #endif 100 #if _LIBUNWIND_ARM_EHABI 101 uintptr_t arm_section; 102 uintptr_t arm_section_length; 103 #endif 104 }; 105 106 107 /// LocalAddressSpace is used as a template parameter to UnwindCursor when 108 /// unwinding a thread in the same process. The wrappers compile away, 109 /// making local unwinds fast. 110 class __attribute__((visibility("hidden"))) LocalAddressSpace { 111 public: 112 #ifdef __LP64__ 113 typedef uint64_t pint_t; 114 typedef int64_t sint_t; 115 #else 116 typedef uint32_t pint_t; 117 typedef int32_t sint_t; 118 #endif 119 uint8_t get8(pint_t addr) { 120 uint8_t val; 121 memcpy(&val, (void *)addr, sizeof(val)); 122 return val; 123 } 124 uint16_t get16(pint_t addr) { 125 uint16_t val; 126 memcpy(&val, (void *)addr, sizeof(val)); 127 return val; 128 } 129 uint32_t get32(pint_t addr) { 130 uint32_t val; 131 memcpy(&val, (void *)addr, sizeof(val)); 132 return val; 133 } 134 uint64_t get64(pint_t addr) { 135 uint64_t val; 136 memcpy(&val, (void *)addr, sizeof(val)); 137 return val; 138 } 139 double getDouble(pint_t addr) { 140 double val; 141 memcpy(&val, (void *)addr, sizeof(val)); 142 return val; 143 } 144 v128 getVector(pint_t addr) { 145 v128 val; 146 memcpy(&val, (void *)addr, sizeof(val)); 147 return val; 148 } 149 uintptr_t getP(pint_t addr); 150 static uint64_t getULEB128(pint_t &addr, pint_t end); 151 static int64_t getSLEB128(pint_t &addr, pint_t end); 152 153 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 154 pint_t datarelBase = 0); 155 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, 156 unw_word_t *offset); 157 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); 158 bool findOtherFDE(pint_t targetAddr, pint_t &fde); 159 160 static LocalAddressSpace sThisAddressSpace; 161 }; 162 163 inline uintptr_t LocalAddressSpace::getP(pint_t addr) { 164 #ifdef __LP64__ 165 return get64(addr); 166 #else 167 return get32(addr); 168 #endif 169 } 170 171 /// Read a ULEB128 into a 64-bit word. 172 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { 173 const uint8_t *p = (uint8_t *)addr; 174 const uint8_t *pend = (uint8_t *)end; 175 uint64_t result = 0; 176 int bit = 0; 177 do { 178 uint64_t b; 179 180 if (p == pend) 181 _LIBUNWIND_ABORT("truncated uleb128 expression"); 182 183 b = *p & 0x7f; 184 185 if (bit >= 64 || b << bit >> bit != b) { 186 _LIBUNWIND_ABORT("malformed uleb128 expression"); 187 } else { 188 result |= b << bit; 189 bit += 7; 190 } 191 } while (*p++ >= 0x80); 192 addr = (pint_t) p; 193 return result; 194 } 195 196 /// Read a SLEB128 into a 64-bit word. 197 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { 198 const uint8_t *p = (uint8_t *)addr; 199 const uint8_t *pend = (uint8_t *)end; 200 int64_t result = 0; 201 int bit = 0; 202 uint8_t byte; 203 do { 204 if (p == pend) 205 _LIBUNWIND_ABORT("truncated sleb128 expression"); 206 byte = *p++; 207 result |= ((byte & 0x7f) << bit); 208 bit += 7; 209 } while (byte & 0x80); 210 // sign extend negative numbers 211 if ((byte & 0x40) != 0) 212 result |= (-1LL) << bit; 213 addr = (pint_t) p; 214 return result; 215 } 216 217 inline LocalAddressSpace::pint_t 218 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 219 pint_t datarelBase) { 220 pint_t startAddr = addr; 221 const uint8_t *p = (uint8_t *)addr; 222 pint_t result; 223 224 // first get value 225 switch (encoding & 0x0F) { 226 case DW_EH_PE_ptr: 227 result = getP(addr); 228 p += sizeof(pint_t); 229 addr = (pint_t) p; 230 break; 231 case DW_EH_PE_uleb128: 232 result = (pint_t)getULEB128(addr, end); 233 break; 234 case DW_EH_PE_udata2: 235 result = get16(addr); 236 p += 2; 237 addr = (pint_t) p; 238 break; 239 case DW_EH_PE_udata4: 240 result = get32(addr); 241 p += 4; 242 addr = (pint_t) p; 243 break; 244 case DW_EH_PE_udata8: 245 result = (pint_t)get64(addr); 246 p += 8; 247 addr = (pint_t) p; 248 break; 249 case DW_EH_PE_sleb128: 250 result = (pint_t)getSLEB128(addr, end); 251 break; 252 case DW_EH_PE_sdata2: 253 // Sign extend from signed 16-bit value. 254 result = (pint_t)(int16_t)get16(addr); 255 p += 2; 256 addr = (pint_t) p; 257 break; 258 case DW_EH_PE_sdata4: 259 // Sign extend from signed 32-bit value. 260 result = (pint_t)(int32_t)get32(addr); 261 p += 4; 262 addr = (pint_t) p; 263 break; 264 case DW_EH_PE_sdata8: 265 result = (pint_t)get64(addr); 266 p += 8; 267 addr = (pint_t) p; 268 break; 269 default: 270 _LIBUNWIND_ABORT("unknown pointer encoding"); 271 } 272 273 // then add relative offset 274 switch (encoding & 0x70) { 275 case DW_EH_PE_absptr: 276 // do nothing 277 break; 278 case DW_EH_PE_pcrel: 279 result += startAddr; 280 break; 281 case DW_EH_PE_textrel: 282 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); 283 break; 284 case DW_EH_PE_datarel: 285 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a 286 // default value of 0, and we abort in the event that someone calls this 287 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding. 288 if (datarelBase == 0) 289 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0"); 290 result += datarelBase; 291 break; 292 case DW_EH_PE_funcrel: 293 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); 294 break; 295 case DW_EH_PE_aligned: 296 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); 297 break; 298 default: 299 _LIBUNWIND_ABORT("unknown pointer encoding"); 300 break; 301 } 302 303 if (encoding & DW_EH_PE_indirect) 304 result = getP(result); 305 306 return result; 307 } 308 309 #ifdef __APPLE__ 310 struct dyld_unwind_sections 311 { 312 const struct mach_header* mh; 313 const void* dwarf_section; 314 uintptr_t dwarf_section_length; 315 const void* compact_unwind_section; 316 uintptr_t compact_unwind_section_length; 317 }; 318 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ 319 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \ 320 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 321 // In 10.7.0 or later, libSystem.dylib implements this function. 322 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); 323 #else 324 // In 10.6.x and earlier, we need to implement this functionality. Note 325 // that this requires a newer version of libmacho (from cctools) than is 326 // present in libSystem on 10.6.x (for getsectiondata). 327 static inline bool _dyld_find_unwind_sections(void* addr, 328 dyld_unwind_sections* info) { 329 // Find mach-o image containing address. 330 Dl_info dlinfo; 331 if (!dladdr(addr, &dlinfo)) 332 return false; 333 #if __LP64__ 334 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase; 335 #else 336 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase; 337 #endif 338 339 // Initialize the return struct 340 info->mh = (const struct mach_header *)mh; 341 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length); 342 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length); 343 344 if (!info->dwarf_section) { 345 info->dwarf_section_length = 0; 346 } 347 348 if (!info->compact_unwind_section) { 349 info->compact_unwind_section_length = 0; 350 } 351 352 return true; 353 } 354 #endif 355 #endif 356 357 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, 358 UnwindInfoSections &info) { 359 #ifdef __APPLE__ 360 dyld_unwind_sections dyldInfo; 361 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { 362 info.dso_base = (uintptr_t)dyldInfo.mh; 363 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND 364 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; 365 info.dwarf_section_length = dyldInfo.dwarf_section_length; 366 #endif 367 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; 368 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; 369 return true; 370 } 371 #elif _LIBUNWIND_ARM_EHABI 372 #ifdef _LIBUNWIND_IS_BAREMETAL 373 // Bare metal is statically linked, so no need to ask the dynamic loader 374 info.arm_section = (uintptr_t)(&__exidx_start); 375 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); 376 #else 377 int length = 0; 378 info.arm_section = (uintptr_t) dl_unwind_find_exidx( 379 (_Unwind_Ptr) targetAddr, &length); 380 info.arm_section_length = (uintptr_t)length; 381 #endif 382 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x", 383 info.arm_section, info.arm_section_length); 384 if (info.arm_section && info.arm_section_length) 385 return true; 386 #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND 387 #if _LIBUNWIND_SUPPORT_DWARF_INDEX 388 struct dl_iterate_cb_data { 389 LocalAddressSpace *addressSpace; 390 UnwindInfoSections *sects; 391 uintptr_t targetAddr; 392 }; 393 394 dl_iterate_cb_data cb_data = {this, &info, targetAddr}; 395 int found = dl_iterate_phdr( 396 [](struct dl_phdr_info *pinfo, size_t, void *data) -> int { 397 auto cbdata = static_cast<dl_iterate_cb_data *>(data); 398 size_t object_length; 399 bool found_obj = false; 400 bool found_hdr = false; 401 402 assert(cbdata); 403 assert(cbdata->sects); 404 405 if (cbdata->targetAddr < pinfo->dlpi_addr) { 406 return false; 407 } 408 409 #if !defined(Elf_Half) 410 typedef ElfW(Half) Elf_Half; 411 #endif 412 #if !defined(Elf_Phdr) 413 typedef ElfW(Phdr) Elf_Phdr; 414 #endif 415 416 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { 417 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; 418 if (phdr->p_type == PT_LOAD) { 419 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr; 420 uintptr_t end = begin + phdr->p_memsz; 421 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) { 422 cbdata->sects->dso_base = begin; 423 object_length = phdr->p_memsz; 424 found_obj = true; 425 } 426 } else if (phdr->p_type == PT_GNU_EH_FRAME) { 427 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; 428 uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; 429 cbdata->sects->dwarf_index_section = eh_frame_hdr_start; 430 cbdata->sects->dwarf_index_section_length = phdr->p_memsz; 431 EHHeaderParser<LocalAddressSpace>::decodeEHHdr( 432 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, 433 hdrInfo); 434 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; 435 found_hdr = true; 436 } 437 } 438 439 if (found_obj && found_hdr) { 440 cbdata->sects->dwarf_section_length = object_length; 441 return true; 442 } else { 443 return false; 444 } 445 }, 446 &cb_data); 447 return static_cast<bool>(found); 448 #else 449 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." 450 #endif 451 #endif 452 453 return false; 454 } 455 456 457 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { 458 #ifdef __APPLE__ 459 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); 460 #else 461 // TO DO: if OS has way to dynamically register FDEs, check that. 462 (void)targetAddr; 463 (void)fde; 464 return false; 465 #endif 466 } 467 468 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, 469 size_t bufLen, 470 unw_word_t *offset) { 471 #ifndef _LIBUNWIND_IS_BAREMETAL 472 Dl_info dyldInfo; 473 if (dladdr((void *)addr, &dyldInfo)) { 474 if (dyldInfo.dli_sname != NULL) { 475 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); 476 *offset = (addr - (pint_t) dyldInfo.dli_saddr); 477 return true; 478 } 479 } 480 #endif 481 return false; 482 } 483 484 485 486 #ifdef UNW_REMOTE 487 488 /// OtherAddressSpace is used as a template parameter to UnwindCursor when 489 /// unwinding a thread in the another process. The other process can be a 490 /// different endianness and a different pointer size which is handled by 491 /// the P template parameter. 492 template <typename P> 493 class OtherAddressSpace { 494 public: 495 OtherAddressSpace(task_t task) : fTask(task) {} 496 497 typedef typename P::uint_t pint_t; 498 499 uint8_t get8(pint_t addr); 500 uint16_t get16(pint_t addr); 501 uint32_t get32(pint_t addr); 502 uint64_t get64(pint_t addr); 503 pint_t getP(pint_t addr); 504 uint64_t getULEB128(pint_t &addr, pint_t end); 505 int64_t getSLEB128(pint_t &addr, pint_t end); 506 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 507 pint_t datarelBase = 0); 508 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, 509 unw_word_t *offset); 510 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); 511 bool findOtherFDE(pint_t targetAddr, pint_t &fde); 512 private: 513 void *localCopy(pint_t addr); 514 515 task_t fTask; 516 }; 517 518 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) { 519 return *((uint8_t *)localCopy(addr)); 520 } 521 522 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) { 523 return P::E::get16(*(uint16_t *)localCopy(addr)); 524 } 525 526 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) { 527 return P::E::get32(*(uint32_t *)localCopy(addr)); 528 } 529 530 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) { 531 return P::E::get64(*(uint64_t *)localCopy(addr)); 532 } 533 534 template <typename P> 535 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) { 536 return P::getP(*(uint64_t *)localCopy(addr)); 537 } 538 539 template <typename P> 540 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) { 541 uintptr_t size = (end - addr); 542 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); 543 LocalAddressSpace::pint_t sladdr = laddr; 544 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); 545 addr += (laddr - sladdr); 546 return result; 547 } 548 549 template <typename P> 550 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) { 551 uintptr_t size = (end - addr); 552 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); 553 LocalAddressSpace::pint_t sladdr = laddr; 554 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); 555 addr += (laddr - sladdr); 556 return result; 557 } 558 559 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) { 560 // FIX ME 561 } 562 563 template <typename P> 564 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf, 565 size_t bufLen, unw_word_t *offset) { 566 // FIX ME 567 } 568 569 /// unw_addr_space is the base class that abstract unw_addr_space_t type in 570 /// libunwind.h points to. 571 struct unw_addr_space { 572 cpu_type_t cpuType; 573 task_t taskPort; 574 }; 575 576 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points 577 /// to when examining 578 /// a 32-bit intel process. 579 struct unw_addr_space_i386 : public unw_addr_space { 580 unw_addr_space_i386(task_t task) : oas(task) {} 581 OtherAddressSpace<Pointer32<LittleEndian> > oas; 582 }; 583 584 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t 585 /// points to when examining 586 /// a 64-bit intel process. 587 struct unw_addr_space_x86_64 : public unw_addr_space { 588 unw_addr_space_x86_64(task_t task) : oas(task) {} 589 OtherAddressSpace<Pointer64<LittleEndian> > oas; 590 }; 591 592 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points 593 /// to when examining 594 /// a 32-bit PowerPC process. 595 struct unw_addr_space_ppc : public unw_addr_space { 596 unw_addr_space_ppc(task_t task) : oas(task) {} 597 OtherAddressSpace<Pointer32<BigEndian> > oas; 598 }; 599 600 #endif // UNW_REMOTE 601 602 } // namespace libunwind 603 604 #endif // __ADDRESSSPACE_HPP__ 605