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