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__) 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(__linux__) || \ 65 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. 325 static inline bool _dyld_find_unwind_sections(void* addr, 326 dyld_unwind_sections* info) { 327 // Find mach-o image containing address. 328 Dl_info dlinfo; 329 if (!dladdr(addr, &dlinfo)) 330 return false; 331 const mach_header *mh = (const mach_header *)dlinfo.dli_saddr; 332 333 // Find dwarf unwind section in that image. 334 unsigned long size; 335 const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size); 336 if (!p) 337 return false; 338 339 // Fill in return struct. 340 info->mh = mh; 341 info->dwarf_section = p; 342 info->dwarf_section_length = size; 343 info->compact_unwind_section = 0; 344 info->compact_unwind_section_length = 0; 345 346 return true; 347 } 348 #endif 349 #endif 350 351 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, 352 UnwindInfoSections &info) { 353 #ifdef __APPLE__ 354 dyld_unwind_sections dyldInfo; 355 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { 356 info.dso_base = (uintptr_t)dyldInfo.mh; 357 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND 358 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; 359 info.dwarf_section_length = dyldInfo.dwarf_section_length; 360 #endif 361 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; 362 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; 363 return true; 364 } 365 #elif _LIBUNWIND_ARM_EHABI 366 #ifdef _LIBUNWIND_IS_BAREMETAL 367 // Bare metal is statically linked, so no need to ask the dynamic loader 368 info.arm_section = (uintptr_t)(&__exidx_start); 369 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start); 370 #else 371 int length = 0; 372 info.arm_section = (uintptr_t) dl_unwind_find_exidx( 373 (_Unwind_Ptr) targetAddr, &length); 374 info.arm_section_length = (uintptr_t)length; 375 #endif 376 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n", 377 info.arm_section, info.arm_section_length); 378 if (info.arm_section && info.arm_section_length) 379 return true; 380 #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND 381 #if _LIBUNWIND_SUPPORT_DWARF_INDEX 382 struct dl_iterate_cb_data { 383 LocalAddressSpace *addressSpace; 384 UnwindInfoSections *sects; 385 uintptr_t targetAddr; 386 }; 387 388 dl_iterate_cb_data cb_data = {this, &info, targetAddr}; 389 int found = dl_iterate_phdr( 390 [](struct dl_phdr_info *pinfo, size_t, void *data) -> int { 391 auto cbdata = static_cast<dl_iterate_cb_data *>(data); 392 size_t object_length; 393 bool found_obj = false; 394 bool found_hdr = false; 395 396 assert(cbdata); 397 assert(cbdata->sects); 398 399 if (cbdata->targetAddr < pinfo->dlpi_addr) { 400 return false; 401 } 402 403 #if !defined(Elf_Half) 404 typedef ElfW(Half) Elf_Half; 405 #endif 406 #if !defined(Elf_Phdr) 407 typedef ElfW(Phdr) Elf_Phdr; 408 #endif 409 410 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) { 411 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i]; 412 if (phdr->p_type == PT_LOAD) { 413 uintptr_t begin = pinfo->dlpi_addr + 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 object_length = phdr->p_memsz; 418 found_obj = true; 419 } 420 } else if (phdr->p_type == PT_GNU_EH_FRAME) { 421 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo; 422 uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr; 423 cbdata->sects->dwarf_index_section = eh_frame_hdr_start; 424 cbdata->sects->dwarf_index_section_length = phdr->p_memsz; 425 EHHeaderParser<LocalAddressSpace>::decodeEHHdr( 426 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz, 427 hdrInfo); 428 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr; 429 found_hdr = true; 430 } 431 } 432 433 if (found_obj && found_hdr) { 434 cbdata->sects->dwarf_section_length = object_length; 435 return true; 436 } else { 437 return false; 438 } 439 }, 440 &cb_data); 441 return static_cast<bool>(found); 442 #else 443 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform." 444 #endif 445 #endif 446 447 return false; 448 } 449 450 451 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { 452 #ifdef __APPLE__ 453 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); 454 #else 455 // TO DO: if OS has way to dynamically register FDEs, check that. 456 (void)targetAddr; 457 (void)fde; 458 return false; 459 #endif 460 } 461 462 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, 463 size_t bufLen, 464 unw_word_t *offset) { 465 #ifndef _LIBUNWIND_IS_BAREMETAL 466 Dl_info dyldInfo; 467 if (dladdr((void *)addr, &dyldInfo)) { 468 if (dyldInfo.dli_sname != NULL) { 469 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname); 470 *offset = (addr - (pint_t) dyldInfo.dli_saddr); 471 return true; 472 } 473 } 474 #endif 475 return false; 476 } 477 478 479 480 #ifdef UNW_REMOTE 481 482 /// OtherAddressSpace is used as a template parameter to UnwindCursor when 483 /// unwinding a thread in the another process. The other process can be a 484 /// different endianness and a different pointer size which is handled by 485 /// the P template parameter. 486 template <typename P> 487 class OtherAddressSpace { 488 public: 489 OtherAddressSpace(task_t task) : fTask(task) {} 490 491 typedef typename P::uint_t pint_t; 492 493 uint8_t get8(pint_t addr); 494 uint16_t get16(pint_t addr); 495 uint32_t get32(pint_t addr); 496 uint64_t get64(pint_t addr); 497 pint_t getP(pint_t addr); 498 uint64_t getULEB128(pint_t &addr, pint_t end); 499 int64_t getSLEB128(pint_t &addr, pint_t end); 500 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding, 501 pint_t datarelBase = 0); 502 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, 503 unw_word_t *offset); 504 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); 505 bool findOtherFDE(pint_t targetAddr, pint_t &fde); 506 private: 507 void *localCopy(pint_t addr); 508 509 task_t fTask; 510 }; 511 512 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) { 513 return *((uint8_t *)localCopy(addr)); 514 } 515 516 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) { 517 return P::E::get16(*(uint16_t *)localCopy(addr)); 518 } 519 520 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) { 521 return P::E::get32(*(uint32_t *)localCopy(addr)); 522 } 523 524 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) { 525 return P::E::get64(*(uint64_t *)localCopy(addr)); 526 } 527 528 template <typename P> 529 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) { 530 return P::getP(*(uint64_t *)localCopy(addr)); 531 } 532 533 template <typename P> 534 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) { 535 uintptr_t size = (end - addr); 536 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); 537 LocalAddressSpace::pint_t sladdr = laddr; 538 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); 539 addr += (laddr - sladdr); 540 return result; 541 } 542 543 template <typename P> 544 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) { 545 uintptr_t size = (end - addr); 546 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); 547 LocalAddressSpace::pint_t sladdr = laddr; 548 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); 549 addr += (laddr - sladdr); 550 return result; 551 } 552 553 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) { 554 // FIX ME 555 } 556 557 template <typename P> 558 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf, 559 size_t bufLen, unw_word_t *offset) { 560 // FIX ME 561 } 562 563 /// unw_addr_space is the base class that abstract unw_addr_space_t type in 564 /// libunwind.h points to. 565 struct unw_addr_space { 566 cpu_type_t cpuType; 567 task_t taskPort; 568 }; 569 570 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points 571 /// to when examining 572 /// a 32-bit intel process. 573 struct unw_addr_space_i386 : public unw_addr_space { 574 unw_addr_space_i386(task_t task) : oas(task) {} 575 OtherAddressSpace<Pointer32<LittleEndian> > oas; 576 }; 577 578 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t 579 /// points to when examining 580 /// a 64-bit intel process. 581 struct unw_addr_space_x86_64 : public unw_addr_space { 582 unw_addr_space_x86_64(task_t task) : oas(task) {} 583 OtherAddressSpace<Pointer64<LittleEndian> > oas; 584 }; 585 586 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points 587 /// to when examining 588 /// a 32-bit PowerPC process. 589 struct unw_addr_space_ppc : public unw_addr_space { 590 unw_addr_space_ppc(task_t task) : oas(task) {} 591 OtherAddressSpace<Pointer32<BigEndian> > oas; 592 }; 593 594 #endif // UNW_REMOTE 595 596 } // namespace libunwind 597 598 #endif // __ADDRESSSPACE_HPP__ 599