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