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