OLD | NEW |
(Empty) | |
| 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 <dlfcn.h> |
| 20 |
| 21 #if __APPLE__ |
| 22 #include <mach-o/dyld_priv.h> |
| 23 namespace libunwind { |
| 24 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); |
| 25 } |
| 26 #endif |
| 27 |
| 28 #include "libunwind.h" |
| 29 #include "config.h" |
| 30 #include "dwarf2.h" |
| 31 #include "Registers.hpp" |
| 32 |
| 33 namespace libunwind { |
| 34 |
| 35 /// Used by findUnwindSections() to return info about needed sections. |
| 36 struct UnwindInfoSections { |
| 37 uintptr_t dso_base; |
| 38 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 39 uintptr_t dwarf_section; |
| 40 uintptr_t dwarf_section_length; |
| 41 #endif |
| 42 #if _LIBUNWIND_SUPPORT_DWARF_INDEX |
| 43 uintptr_t dwarf_index_section; |
| 44 uintptr_t dwarf_index_section_length; |
| 45 #endif |
| 46 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 47 uintptr_t compact_unwind_section; |
| 48 uintptr_t compact_unwind_section_length; |
| 49 #endif |
| 50 }; |
| 51 |
| 52 |
| 53 /// LocalAddressSpace is used as a template parameter to UnwindCursor when |
| 54 /// unwinding a thread in the same process. The wrappers compile away, |
| 55 /// making local unwinds fast. |
| 56 class __attribute__((visibility("hidden"))) LocalAddressSpace { |
| 57 public: |
| 58 #if __LP64__ |
| 59 typedef uint64_t pint_t; |
| 60 typedef int64_t sint_t; |
| 61 #else |
| 62 typedef uint32_t pint_t; |
| 63 typedef int32_t sint_t; |
| 64 #endif |
| 65 uint8_t get8(pint_t addr) { return *((uint8_t *)addr); } |
| 66 uint16_t get16(pint_t addr) { return *((uint16_t *)addr); } |
| 67 uint32_t get32(pint_t addr) { return *((uint32_t *)addr); } |
| 68 uint64_t get64(pint_t addr) { return *((uint64_t *)addr); } |
| 69 double getDouble(pint_t addr) { return *((double *)addr); } |
| 70 v128 getVector(pint_t addr) { return *((v128 *)addr); } |
| 71 uintptr_t getP(pint_t addr); |
| 72 static uint64_t getULEB128(pint_t &addr, pint_t end); |
| 73 static int64_t getSLEB128(pint_t &addr, pint_t end); |
| 74 |
| 75 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding); |
| 76 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, |
| 77 unw_word_t *offset); |
| 78 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); |
| 79 bool findOtherFDE(pint_t targetAddr, pint_t &fde); |
| 80 |
| 81 static LocalAddressSpace sThisAddressSpace; |
| 82 }; |
| 83 |
| 84 |
| 85 inline uintptr_t LocalAddressSpace::getP(pint_t addr) { |
| 86 #if __LP64__ |
| 87 return get64(addr); |
| 88 #else |
| 89 return get32(addr); |
| 90 #endif |
| 91 } |
| 92 |
| 93 /// Read a ULEB128 into a 64-bit word. |
| 94 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { |
| 95 const uint8_t *p = (uint8_t *)addr; |
| 96 const uint8_t *pend = (uint8_t *)end; |
| 97 uint64_t result = 0; |
| 98 int bit = 0; |
| 99 do { |
| 100 uint64_t b; |
| 101 |
| 102 if (p == pend) |
| 103 _LIBUNWIND_ABORT("truncated uleb128 expression"); |
| 104 |
| 105 b = *p & 0x7f; |
| 106 |
| 107 if (bit >= 64 || b << bit >> bit != b) { |
| 108 _LIBUNWIND_ABORT("malformed uleb128 expression"); |
| 109 } else { |
| 110 result |= b << bit; |
| 111 bit += 7; |
| 112 } |
| 113 } while (*p++ >= 0x80); |
| 114 addr = (pint_t) p; |
| 115 return result; |
| 116 } |
| 117 |
| 118 /// Read a SLEB128 into a 64-bit word. |
| 119 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { |
| 120 const uint8_t *p = (uint8_t *)addr; |
| 121 const uint8_t *pend = (uint8_t *)end; |
| 122 int64_t result = 0; |
| 123 int bit = 0; |
| 124 uint8_t byte; |
| 125 do { |
| 126 if (p == pend) |
| 127 _LIBUNWIND_ABORT("truncated sleb128 expression"); |
| 128 byte = *p++; |
| 129 result |= ((byte & 0x7f) << bit); |
| 130 bit += 7; |
| 131 } while (byte & 0x80); |
| 132 // sign extend negative numbers |
| 133 if ((byte & 0x40) != 0) |
| 134 result |= (-1LL) << bit; |
| 135 addr = (pint_t) p; |
| 136 return result; |
| 137 } |
| 138 |
| 139 inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr, |
| 140 pint_t end, |
| 141 uint8_t encoding) { |
| 142 pint_t startAddr = addr; |
| 143 const uint8_t *p = (uint8_t *)addr; |
| 144 pint_t result; |
| 145 |
| 146 // first get value |
| 147 switch (encoding & 0x0F) { |
| 148 case DW_EH_PE_ptr: |
| 149 result = getP(addr); |
| 150 p += sizeof(pint_t); |
| 151 addr = (pint_t) p; |
| 152 break; |
| 153 case DW_EH_PE_uleb128: |
| 154 result = (pint_t)getULEB128(addr, end); |
| 155 break; |
| 156 case DW_EH_PE_udata2: |
| 157 result = get16(addr); |
| 158 p += 2; |
| 159 addr = (pint_t) p; |
| 160 break; |
| 161 case DW_EH_PE_udata4: |
| 162 result = get32(addr); |
| 163 p += 4; |
| 164 addr = (pint_t) p; |
| 165 break; |
| 166 case DW_EH_PE_udata8: |
| 167 result = (pint_t)get64(addr); |
| 168 p += 8; |
| 169 addr = (pint_t) p; |
| 170 break; |
| 171 case DW_EH_PE_sleb128: |
| 172 result = (pint_t)getSLEB128(addr, end); |
| 173 break; |
| 174 case DW_EH_PE_sdata2: |
| 175 result = (uint16_t)get16(addr); |
| 176 p += 2; |
| 177 addr = (pint_t) p; |
| 178 break; |
| 179 case DW_EH_PE_sdata4: |
| 180 result = (uint32_t)get32(addr); |
| 181 p += 4; |
| 182 addr = (pint_t) p; |
| 183 break; |
| 184 case DW_EH_PE_sdata8: |
| 185 result = (pint_t)get64(addr); |
| 186 p += 8; |
| 187 addr = (pint_t) p; |
| 188 break; |
| 189 default: |
| 190 _LIBUNWIND_ABORT("unknown pointer encoding"); |
| 191 } |
| 192 |
| 193 // then add relative offset |
| 194 switch (encoding & 0x70) { |
| 195 case DW_EH_PE_absptr: |
| 196 // do nothing |
| 197 break; |
| 198 case DW_EH_PE_pcrel: |
| 199 result += startAddr; |
| 200 break; |
| 201 case DW_EH_PE_textrel: |
| 202 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); |
| 203 break; |
| 204 case DW_EH_PE_datarel: |
| 205 _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported"); |
| 206 break; |
| 207 case DW_EH_PE_funcrel: |
| 208 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); |
| 209 break; |
| 210 case DW_EH_PE_aligned: |
| 211 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); |
| 212 break; |
| 213 default: |
| 214 _LIBUNWIND_ABORT("unknown pointer encoding"); |
| 215 break; |
| 216 } |
| 217 |
| 218 if (encoding & DW_EH_PE_indirect) |
| 219 result = getP(result); |
| 220 |
| 221 return result; |
| 222 } |
| 223 |
| 224 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, |
| 225 UnwindInfoSections &info) { |
| 226 #if __APPLE__ |
| 227 dyld_unwind_sections dyldInfo; |
| 228 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { |
| 229 info.dso_base = (uintptr_t)dyldInfo.mh; |
| 230 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 231 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; |
| 232 info.dwarf_section_length = dyldInfo.dwarf_section_length; |
| 233 #endif |
| 234 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_sect
ion; |
| 235 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; |
| 236 return true; |
| 237 } |
| 238 #else |
| 239 // TO DO |
| 240 |
| 241 #endif |
| 242 |
| 243 return false; |
| 244 } |
| 245 |
| 246 |
| 247 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { |
| 248 #if __APPLE__ |
| 249 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); |
| 250 #else |
| 251 // TO DO: if OS has way to dynamically register FDEs, check that. |
| 252 return false; |
| 253 #endif |
| 254 } |
| 255 |
| 256 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, |
| 257 size_t bufLen, |
| 258 unw_word_t *offset) { |
| 259 dl_info dyldInfo; |
| 260 if (dladdr((void *)addr, &dyldInfo)) { |
| 261 if (dyldInfo.dli_sname != NULL) { |
| 262 strlcpy(buf, dyldInfo.dli_sname, bufLen); |
| 263 *offset = (addr - (pint_t) dyldInfo.dli_saddr); |
| 264 return true; |
| 265 } |
| 266 } |
| 267 return false; |
| 268 } |
| 269 |
| 270 |
| 271 |
| 272 #if UNW_REMOTE |
| 273 |
| 274 /// OtherAddressSpace is used as a template parameter to UnwindCursor when |
| 275 /// unwinding a thread in the another process. The other process can be a |
| 276 /// different endianness and a different pointer size which is handled by |
| 277 /// the P template parameter. |
| 278 template <typename P> |
| 279 class OtherAddressSpace { |
| 280 public: |
| 281 OtherAddressSpace(task_t task) : fTask(task) {} |
| 282 |
| 283 typedef typename P::uint_t pint_t; |
| 284 |
| 285 uint8_t get8(pint_t addr); |
| 286 uint16_t get16(pint_t addr); |
| 287 uint32_t get32(pint_t addr); |
| 288 uint64_t get64(pint_t addr); |
| 289 pint_t getP(pint_t addr); |
| 290 uint64_t getULEB128(pint_t &addr, pint_t end); |
| 291 int64_t getSLEB128(pint_t &addr, pint_t end); |
| 292 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding); |
| 293 bool findFunctionName(pint_t addr, char *buf, size_t bufLen, |
| 294 unw_word_t *offset); |
| 295 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); |
| 296 bool findOtherFDE(pint_t targetAddr, pint_t &fde); |
| 297 private: |
| 298 void *localCopy(pint_t addr); |
| 299 |
| 300 task_t fTask; |
| 301 }; |
| 302 |
| 303 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) { |
| 304 return *((uint8_t *)localCopy(addr)); |
| 305 } |
| 306 |
| 307 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) { |
| 308 return P::E::get16(*(uint16_t *)localCopy(addr)); |
| 309 } |
| 310 |
| 311 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) { |
| 312 return P::E::get32(*(uint32_t *)localCopy(addr)); |
| 313 } |
| 314 |
| 315 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) { |
| 316 return P::E::get64(*(uint64_t *)localCopy(addr)); |
| 317 } |
| 318 |
| 319 template <typename P> |
| 320 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) { |
| 321 return P::getP(*(uint64_t *)localCopy(addr)); |
| 322 } |
| 323 |
| 324 template <typename P> |
| 325 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) { |
| 326 uintptr_t size = (end - addr); |
| 327 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); |
| 328 LocalAddressSpace::pint_t sladdr = laddr; |
| 329 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); |
| 330 addr += (laddr - sladdr); |
| 331 return result; |
| 332 } |
| 333 |
| 334 template <typename P> |
| 335 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) { |
| 336 uintptr_t size = (end - addr); |
| 337 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); |
| 338 LocalAddressSpace::pint_t sladdr = laddr; |
| 339 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); |
| 340 addr += (laddr - sladdr); |
| 341 return result; |
| 342 } |
| 343 |
| 344 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) { |
| 345 // FIX ME |
| 346 } |
| 347 |
| 348 template <typename P> |
| 349 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf, |
| 350 size_t bufLen, unw_word_t *offset) { |
| 351 // FIX ME |
| 352 } |
| 353 |
| 354 /// unw_addr_space is the base class that abstract unw_addr_space_t type in |
| 355 /// libunwind.h points to. |
| 356 struct unw_addr_space { |
| 357 cpu_type_t cpuType; |
| 358 task_t taskPort; |
| 359 }; |
| 360 |
| 361 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points |
| 362 /// to when examining |
| 363 /// a 32-bit intel process. |
| 364 struct unw_addr_space_i386 : public unw_addr_space { |
| 365 unw_addr_space_i386(task_t task) : oas(task) {} |
| 366 OtherAddressSpace<Pointer32<LittleEndian> > oas; |
| 367 }; |
| 368 |
| 369 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t |
| 370 /// points to when examining |
| 371 /// a 64-bit intel process. |
| 372 struct unw_addr_space_x86_64 : public unw_addr_space { |
| 373 unw_addr_space_x86_64(task_t task) : oas(task) {} |
| 374 OtherAddressSpace<Pointer64<LittleEndian> > oas; |
| 375 }; |
| 376 |
| 377 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points |
| 378 /// to when examining |
| 379 /// a 32-bit PowerPC process. |
| 380 struct unw_addr_space_ppc : public unw_addr_space { |
| 381 unw_addr_space_ppc(task_t task) : oas(task) {} |
| 382 OtherAddressSpace<Pointer32<BigEndian> > oas; |
| 383 }; |
| 384 |
| 385 #endif // UNW_REMOTE |
| 386 |
| 387 } // namespace libunwind |
| 388 |
| 389 #endif // __ADDRESSSPACE_HPP__ |
OLD | NEW |