OLD | NEW |
(Empty) | |
| 1 //===------------------------- UnwindCursor.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 // C++ interface to lower levels of libuwind |
| 10 //===----------------------------------------------------------------------===// |
| 11 |
| 12 #ifndef __UNWINDCURSOR_HPP__ |
| 13 #define __UNWINDCURSOR_HPP__ |
| 14 |
| 15 #include <stdint.h> |
| 16 #include <stdio.h> |
| 17 #include <stdlib.h> |
| 18 #include <pthread.h> |
| 19 |
| 20 #if __APPLE__ |
| 21 #include <mach-o/dyld.h> |
| 22 #endif |
| 23 |
| 24 #include "libunwind.h" |
| 25 |
| 26 #include "AddressSpace.hpp" |
| 27 #include "Registers.hpp" |
| 28 #include "DwarfInstructions.hpp" |
| 29 #include "CompactUnwinder.hpp" |
| 30 #include "config.h" |
| 31 |
| 32 namespace libunwind { |
| 33 |
| 34 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 35 /// Cache of recently found FDEs. |
| 36 template <typename A> |
| 37 class _LIBUNWIND_HIDDEN DwarfFDECache { |
| 38 typedef typename A::pint_t pint_t; |
| 39 public: |
| 40 static pint_t findFDE(pint_t mh, pint_t pc); |
| 41 static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); |
| 42 static void removeAllIn(pint_t mh); |
| 43 static void iterateCacheEntries(void (*func)(unw_word_t ip_start, |
| 44 unw_word_t ip_end, |
| 45 unw_word_t fde, unw_word_t mh)); |
| 46 |
| 47 private: |
| 48 |
| 49 struct entry { |
| 50 pint_t mh; |
| 51 pint_t ip_start; |
| 52 pint_t ip_end; |
| 53 pint_t fde; |
| 54 }; |
| 55 |
| 56 // These fields are all static to avoid needing an initializer. |
| 57 // There is only one instance of this class per process. |
| 58 static pthread_rwlock_t _lock; |
| 59 #if __APPLE__ |
| 60 static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); |
| 61 static bool _registeredForDyldUnloads; |
| 62 #endif |
| 63 // Can't use std::vector<> here because this code is below libc++. |
| 64 static entry *_buffer; |
| 65 static entry *_bufferUsed; |
| 66 static entry *_bufferEnd; |
| 67 static entry _initialBuffer[64]; |
| 68 }; |
| 69 |
| 70 template <typename A> |
| 71 typename DwarfFDECache<A>::entry * |
| 72 DwarfFDECache<A>::_buffer = _initialBuffer; |
| 73 |
| 74 template <typename A> |
| 75 typename DwarfFDECache<A>::entry * |
| 76 DwarfFDECache<A>::_bufferUsed = _initialBuffer; |
| 77 |
| 78 template <typename A> |
| 79 typename DwarfFDECache<A>::entry * |
| 80 DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64]; |
| 81 |
| 82 template <typename A> |
| 83 typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64]; |
| 84 |
| 85 template <typename A> |
| 86 pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER; |
| 87 |
| 88 #if __APPLE__ |
| 89 template <typename A> |
| 90 bool DwarfFDECache<A>::_registeredForDyldUnloads = false; |
| 91 #endif |
| 92 |
| 93 template <typename A> |
| 94 typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) { |
| 95 pint_t result = 0; |
| 96 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock)); |
| 97 for (entry *p = _buffer; p < _bufferUsed; ++p) { |
| 98 if ((mh == p->mh) || (mh == 0)) { |
| 99 if ((p->ip_start <= pc) && (pc < p->ip_end)) { |
| 100 result = p->fde; |
| 101 break; |
| 102 } |
| 103 } |
| 104 } |
| 105 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); |
| 106 return result; |
| 107 } |
| 108 |
| 109 template <typename A> |
| 110 void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, |
| 111 pint_t fde) { |
| 112 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); |
| 113 if (_bufferUsed >= _bufferEnd) { |
| 114 size_t oldSize = (size_t)(_bufferEnd - _buffer); |
| 115 size_t newSize = oldSize * 4; |
| 116 // Can't use operator new (we are below it). |
| 117 entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); |
| 118 memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); |
| 119 if (_buffer != _initialBuffer) |
| 120 free(_buffer); |
| 121 _buffer = newBuffer; |
| 122 _bufferUsed = &newBuffer[oldSize]; |
| 123 _bufferEnd = &newBuffer[newSize]; |
| 124 } |
| 125 _bufferUsed->mh = mh; |
| 126 _bufferUsed->ip_start = ip_start; |
| 127 _bufferUsed->ip_end = ip_end; |
| 128 _bufferUsed->fde = fde; |
| 129 ++_bufferUsed; |
| 130 #if __APPLE__ |
| 131 if (!_registeredForDyldUnloads) { |
| 132 _dyld_register_func_for_remove_image(&dyldUnloadHook); |
| 133 _registeredForDyldUnloads = true; |
| 134 } |
| 135 #endif |
| 136 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); |
| 137 } |
| 138 |
| 139 template <typename A> |
| 140 void DwarfFDECache<A>::removeAllIn(pint_t mh) { |
| 141 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); |
| 142 entry *d = _buffer; |
| 143 for (const entry *s = _buffer; s < _bufferUsed; ++s) { |
| 144 if (s->mh != mh) { |
| 145 if (d != s) |
| 146 *d = *s; |
| 147 ++d; |
| 148 } |
| 149 } |
| 150 _bufferUsed = d; |
| 151 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); |
| 152 } |
| 153 |
| 154 template <typename A> |
| 155 void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { |
| 156 removeAllIn((pint_t) mh); |
| 157 } |
| 158 |
| 159 template <typename A> |
| 160 void DwarfFDECache<A>::iterateCacheEntries(void (*func)( |
| 161 unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { |
| 162 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); |
| 163 for (entry *p = _buffer; p < _bufferUsed; ++p) { |
| 164 (*func)(p->ip_start, p->ip_end, p->fde, p->mh); |
| 165 } |
| 166 _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); |
| 167 } |
| 168 #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 169 |
| 170 |
| 171 #define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) |
| 172 |
| 173 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 174 template <typename A> class UnwindSectionHeader { |
| 175 public: |
| 176 UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) |
| 177 : _addressSpace(addressSpace), _addr(addr) {} |
| 178 |
| 179 uint32_t version() const { |
| 180 return _addressSpace.get32(_addr + |
| 181 offsetof(unwind_info_section_header, version)); |
| 182 } |
| 183 uint32_t commonEncodingsArraySectionOffset() const { |
| 184 return _addressSpace.get32(_addr + |
| 185 offsetof(unwind_info_section_header, |
| 186 commonEncodingsArraySectionOffset)); |
| 187 } |
| 188 uint32_t commonEncodingsArrayCount() const { |
| 189 return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, |
| 190 commonEncodingsArrayCount)); |
| 191 } |
| 192 uint32_t personalityArraySectionOffset() const { |
| 193 return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, |
| 194 personalityArraySectionOffset)); |
| 195 } |
| 196 uint32_t personalityArrayCount() const { |
| 197 return _addressSpace.get32( |
| 198 _addr + offsetof(unwind_info_section_header, personalityArrayCount)); |
| 199 } |
| 200 uint32_t indexSectionOffset() const { |
| 201 return _addressSpace.get32( |
| 202 _addr + offsetof(unwind_info_section_header, indexSectionOffset)); |
| 203 } |
| 204 uint32_t indexCount() const { |
| 205 return _addressSpace.get32( |
| 206 _addr + offsetof(unwind_info_section_header, indexCount)); |
| 207 } |
| 208 |
| 209 private: |
| 210 A &_addressSpace; |
| 211 typename A::pint_t _addr; |
| 212 }; |
| 213 |
| 214 template <typename A> class UnwindSectionIndexArray { |
| 215 public: |
| 216 UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) |
| 217 : _addressSpace(addressSpace), _addr(addr) {} |
| 218 |
| 219 uint32_t functionOffset(uint32_t index) const { |
| 220 return _addressSpace.get32( |
| 221 _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, |
| 222 functionOffset)); |
| 223 } |
| 224 uint32_t secondLevelPagesSectionOffset(uint32_t index) const { |
| 225 return _addressSpace.get32( |
| 226 _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, |
| 227 secondLevelPagesSectionOffset)); |
| 228 } |
| 229 uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { |
| 230 return _addressSpace.get32( |
| 231 _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, |
| 232 lsdaIndexArraySectionOffset)); |
| 233 } |
| 234 |
| 235 private: |
| 236 A &_addressSpace; |
| 237 typename A::pint_t _addr; |
| 238 }; |
| 239 |
| 240 template <typename A> class UnwindSectionRegularPageHeader { |
| 241 public: |
| 242 UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) |
| 243 : _addressSpace(addressSpace), _addr(addr) {} |
| 244 |
| 245 uint32_t kind() const { |
| 246 return _addressSpace.get32( |
| 247 _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); |
| 248 } |
| 249 uint16_t entryPageOffset() const { |
| 250 return _addressSpace.get16( |
| 251 _addr + offsetof(unwind_info_regular_second_level_page_header, |
| 252 entryPageOffset)); |
| 253 } |
| 254 uint16_t entryCount() const { |
| 255 return _addressSpace.get16( |
| 256 _addr + |
| 257 offsetof(unwind_info_regular_second_level_page_header, entryCount)); |
| 258 } |
| 259 |
| 260 private: |
| 261 A &_addressSpace; |
| 262 typename A::pint_t _addr; |
| 263 }; |
| 264 |
| 265 template <typename A> class UnwindSectionRegularArray { |
| 266 public: |
| 267 UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) |
| 268 : _addressSpace(addressSpace), _addr(addr) {} |
| 269 |
| 270 uint32_t functionOffset(uint32_t index) const { |
| 271 return _addressSpace.get32( |
| 272 _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, |
| 273 functionOffset)); |
| 274 } |
| 275 uint32_t encoding(uint32_t index) const { |
| 276 return _addressSpace.get32( |
| 277 _addr + |
| 278 arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); |
| 279 } |
| 280 |
| 281 private: |
| 282 A &_addressSpace; |
| 283 typename A::pint_t _addr; |
| 284 }; |
| 285 |
| 286 template <typename A> class UnwindSectionCompressedPageHeader { |
| 287 public: |
| 288 UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) |
| 289 : _addressSpace(addressSpace), _addr(addr) {} |
| 290 |
| 291 uint32_t kind() const { |
| 292 return _addressSpace.get32( |
| 293 _addr + |
| 294 offsetof(unwind_info_compressed_second_level_page_header, kind)); |
| 295 } |
| 296 uint16_t entryPageOffset() const { |
| 297 return _addressSpace.get16( |
| 298 _addr + offsetof(unwind_info_compressed_second_level_page_header, |
| 299 entryPageOffset)); |
| 300 } |
| 301 uint16_t entryCount() const { |
| 302 return _addressSpace.get16( |
| 303 _addr + |
| 304 offsetof(unwind_info_compressed_second_level_page_header, entryCount)); |
| 305 } |
| 306 uint16_t encodingsPageOffset() const { |
| 307 return _addressSpace.get16( |
| 308 _addr + offsetof(unwind_info_compressed_second_level_page_header, |
| 309 encodingsPageOffset)); |
| 310 } |
| 311 uint16_t encodingsCount() const { |
| 312 return _addressSpace.get16( |
| 313 _addr + offsetof(unwind_info_compressed_second_level_page_header, |
| 314 encodingsCount)); |
| 315 } |
| 316 |
| 317 private: |
| 318 A &_addressSpace; |
| 319 typename A::pint_t _addr; |
| 320 }; |
| 321 |
| 322 template <typename A> class UnwindSectionCompressedArray { |
| 323 public: |
| 324 UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) |
| 325 : _addressSpace(addressSpace), _addr(addr) {} |
| 326 |
| 327 uint32_t functionOffset(uint32_t index) const { |
| 328 return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( |
| 329 _addressSpace.get32(_addr + index * sizeof(uint32_t))); |
| 330 } |
| 331 uint16_t encodingIndex(uint32_t index) const { |
| 332 return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( |
| 333 _addressSpace.get32(_addr + index * sizeof(uint32_t))); |
| 334 } |
| 335 |
| 336 private: |
| 337 A &_addressSpace; |
| 338 typename A::pint_t _addr; |
| 339 }; |
| 340 |
| 341 template <typename A> class UnwindSectionLsdaArray { |
| 342 public: |
| 343 UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) |
| 344 : _addressSpace(addressSpace), _addr(addr) {} |
| 345 |
| 346 uint32_t functionOffset(uint32_t index) const { |
| 347 return _addressSpace.get32( |
| 348 _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, |
| 349 index, functionOffset)); |
| 350 } |
| 351 uint32_t lsdaOffset(uint32_t index) const { |
| 352 return _addressSpace.get32( |
| 353 _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, |
| 354 index, lsdaOffset)); |
| 355 } |
| 356 |
| 357 private: |
| 358 A &_addressSpace; |
| 359 typename A::pint_t _addr; |
| 360 }; |
| 361 #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 362 |
| 363 |
| 364 class _LIBUNWIND_HIDDEN AbstractUnwindCursor { |
| 365 public: |
| 366 virtual bool validReg(int) = 0; |
| 367 virtual unw_word_t getReg(int) = 0; |
| 368 virtual void setReg(int, unw_word_t) = 0; |
| 369 virtual bool validFloatReg(int) = 0; |
| 370 virtual double getFloatReg(int) = 0; |
| 371 virtual void setFloatReg(int, double) = 0; |
| 372 virtual int step() = 0; |
| 373 virtual void getInfo(unw_proc_info_t *) = 0; |
| 374 virtual void jumpto() = 0; |
| 375 virtual bool isSignalFrame() = 0; |
| 376 virtual bool getFunctionName(char *bf, size_t ln, unw_word_t *off) = 0; |
| 377 virtual void setInfoBasedOnIPRegister(bool isReturnAddr = false) = 0; |
| 378 virtual const char *getRegisterName(int num) = 0; |
| 379 }; |
| 380 |
| 381 |
| 382 /// UnwindCursor contains all state (including all register values) during |
| 383 /// an unwind. This is normally stack allocated inside a unw_cursor_t. |
| 384 template <typename A, typename R> |
| 385 class UnwindCursor : public AbstractUnwindCursor{ |
| 386 typedef typename A::pint_t pint_t; |
| 387 public: |
| 388 UnwindCursor(unw_context_t *context, A &as); |
| 389 UnwindCursor(A &as, void *threadArg); |
| 390 virtual ~UnwindCursor() {} |
| 391 virtual bool validReg(int); |
| 392 virtual unw_word_t getReg(int); |
| 393 virtual void setReg(int, unw_word_t); |
| 394 virtual bool validFloatReg(int); |
| 395 virtual double getFloatReg(int); |
| 396 virtual void setFloatReg(int, double); |
| 397 virtual int step(); |
| 398 virtual void getInfo(unw_proc_info_t *); |
| 399 virtual void jumpto(); |
| 400 virtual bool isSignalFrame(); |
| 401 virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); |
| 402 virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); |
| 403 virtual const char *getRegisterName(int num); |
| 404 |
| 405 void operator delete(void *, size_t) {} |
| 406 |
| 407 private: |
| 408 |
| 409 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 410 bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, |
| 411 uint32_t fdeSectionOffsetHint=0); |
| 412 int stepWithDwarfFDE() { |
| 413 return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace, |
| 414 (pint_t)this->getReg(UNW_REG_IP), |
| 415 (pint_t)_info.unwind_info, |
| 416 _registers); |
| 417 } |
| 418 #endif |
| 419 |
| 420 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 421 bool getInfoFromCompactEncodingSection(pint_t pc, |
| 422 const UnwindInfoSections §s); |
| 423 int stepWithCompactEncoding() { |
| 424 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 425 if ( compactSaysUseDwarf() ) |
| 426 return stepWithDwarfFDE(); |
| 427 #endif |
| 428 R dummy; |
| 429 return stepWithCompactEncoding(dummy); |
| 430 } |
| 431 |
| 432 int stepWithCompactEncoding(Registers_x86_64 &) { |
| 433 return CompactUnwinder_x86_64<A>::stepWithCompactEncoding( |
| 434 _info.format, _info.start_ip, _addressSpace, _registers); |
| 435 } |
| 436 |
| 437 int stepWithCompactEncoding(Registers_x86 &) { |
| 438 return CompactUnwinder_x86<A>::stepWithCompactEncoding( |
| 439 _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); |
| 440 } |
| 441 |
| 442 int stepWithCompactEncoding(Registers_ppc &) { |
| 443 return UNW_EINVAL; |
| 444 } |
| 445 |
| 446 int stepWithCompactEncoding(Registers_arm64 &) { |
| 447 return CompactUnwinder_arm64<A>::stepWithCompactEncoding( |
| 448 _info.format, _info.start_ip, _addressSpace, _registers); |
| 449 } |
| 450 |
| 451 bool compactSaysUseDwarf(uint32_t *offset=NULL) const { |
| 452 R dummy; |
| 453 return compactSaysUseDwarf(dummy, offset); |
| 454 } |
| 455 |
| 456 bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { |
| 457 if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { |
| 458 if (offset) |
| 459 *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); |
| 460 return true; |
| 461 } |
| 462 return false; |
| 463 } |
| 464 |
| 465 bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { |
| 466 if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { |
| 467 if (offset) |
| 468 *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); |
| 469 return true; |
| 470 } |
| 471 return false; |
| 472 } |
| 473 |
| 474 bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { |
| 475 return true; |
| 476 } |
| 477 |
| 478 bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { |
| 479 if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { |
| 480 if (offset) |
| 481 *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); |
| 482 return true; |
| 483 } |
| 484 return false; |
| 485 } |
| 486 |
| 487 compact_unwind_encoding_t dwarfEncoding() const { |
| 488 R dummy; |
| 489 return dwarfEncoding(dummy); |
| 490 } |
| 491 |
| 492 compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { |
| 493 return UNWIND_X86_64_MODE_DWARF; |
| 494 } |
| 495 |
| 496 compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { |
| 497 return UNWIND_X86_MODE_DWARF; |
| 498 } |
| 499 |
| 500 compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { |
| 501 return 0; |
| 502 } |
| 503 |
| 504 compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { |
| 505 return UNWIND_ARM64_MODE_DWARF; |
| 506 } |
| 507 #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 508 |
| 509 |
| 510 A &_addressSpace; |
| 511 R _registers; |
| 512 unw_proc_info_t _info; |
| 513 bool _unwindInfoMissing; |
| 514 bool _isSignalFrame; |
| 515 }; |
| 516 |
| 517 |
| 518 template <typename A, typename R> |
| 519 UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) |
| 520 : _addressSpace(as), _registers(context), _unwindInfoMissing(false), |
| 521 _isSignalFrame(false) { |
| 522 static_assert(sizeof(UnwindCursor<A, R>) < sizeof(unw_cursor_t), |
| 523 "UnwindCursor<> does not fit in unw_cursor_t"); |
| 524 |
| 525 bzero(&_info, sizeof(_info)); |
| 526 } |
| 527 |
| 528 template <typename A, typename R> |
| 529 UnwindCursor<A, R>::UnwindCursor(A &as, void *) |
| 530 : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { |
| 531 bzero(&_info, sizeof(_info)); |
| 532 // FIXME |
| 533 // fill in _registers from thread arg |
| 534 } |
| 535 |
| 536 |
| 537 template <typename A, typename R> |
| 538 bool UnwindCursor<A, R>::validReg(int regNum) { |
| 539 return _registers.validRegister(regNum); |
| 540 } |
| 541 |
| 542 template <typename A, typename R> |
| 543 unw_word_t UnwindCursor<A, R>::getReg(int regNum) { |
| 544 return _registers.getRegister(regNum); |
| 545 } |
| 546 |
| 547 template <typename A, typename R> |
| 548 void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) { |
| 549 _registers.setRegister(regNum, (typename A::pint_t)value); |
| 550 } |
| 551 |
| 552 template <typename A, typename R> |
| 553 bool UnwindCursor<A, R>::validFloatReg(int regNum) { |
| 554 return _registers.validFloatRegister(regNum); |
| 555 } |
| 556 |
| 557 template <typename A, typename R> |
| 558 double UnwindCursor<A, R>::getFloatReg(int regNum) { |
| 559 return _registers.getFloatRegister(regNum); |
| 560 } |
| 561 |
| 562 template <typename A, typename R> |
| 563 void UnwindCursor<A, R>::setFloatReg(int regNum, double value) { |
| 564 _registers.setFloatRegister(regNum, value); |
| 565 } |
| 566 |
| 567 template <typename A, typename R> void UnwindCursor<A, R>::jumpto() { |
| 568 _registers.jumpto(); |
| 569 } |
| 570 |
| 571 template <typename A, typename R> |
| 572 const char *UnwindCursor<A, R>::getRegisterName(int regNum) { |
| 573 return _registers.getRegisterName(regNum); |
| 574 } |
| 575 |
| 576 template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() { |
| 577 return _isSignalFrame; |
| 578 } |
| 579 |
| 580 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 581 template <typename A, typename R> |
| 582 bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, |
| 583 const UnwindInfoSections §s, |
| 584 uint32_t fdeSectionOffsetHint) { |
| 585 typename CFI_Parser<A>::FDE_Info fdeInfo; |
| 586 typename CFI_Parser<A>::CIE_Info cieInfo; |
| 587 bool foundFDE = false; |
| 588 bool foundInCache = false; |
| 589 // If compact encoding table gave offset into dwarf section, go directly there |
| 590 if (fdeSectionOffsetHint != 0) { |
| 591 foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, |
| 592 (uint32_t)sects.dwarf_section_length, |
| 593 sects.dwarf_section + fdeSectionOffsetHint, |
| 594 &fdeInfo, &cieInfo); |
| 595 } |
| 596 #if _LIBUNWIND_SUPPORT_DWARF_INDEX |
| 597 if (!foundFDE && (sects.dwarf_index_section != 0)) { |
| 598 // Have eh_frame_hdr section which is index into dwarf section. |
| 599 // TO DO: implement index search |
| 600 } |
| 601 #endif |
| 602 if (!foundFDE) { |
| 603 // otherwise, search cache of previously found FDEs. |
| 604 pint_t cachedFDE = DwarfFDECache<A>::findFDE(sects.dso_base, pc); |
| 605 if (cachedFDE != 0) { |
| 606 foundFDE = |
| 607 CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, |
| 608 (uint32_t)sects.dwarf_section_length, |
| 609 cachedFDE, &fdeInfo, &cieInfo); |
| 610 foundInCache = foundFDE; |
| 611 } |
| 612 } |
| 613 if (!foundFDE) { |
| 614 // Still not found, do full scan of __eh_frame section. |
| 615 foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section, |
| 616 (uint32_t)sects.dwarf_section_length, 0, |
| 617 &fdeInfo, &cieInfo); |
| 618 } |
| 619 if (foundFDE) { |
| 620 typename CFI_Parser<A>::PrologInfo prolog; |
| 621 if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, |
| 622 &prolog)) { |
| 623 // Save off parsed FDE info |
| 624 _info.start_ip = fdeInfo.pcStart; |
| 625 _info.end_ip = fdeInfo.pcEnd; |
| 626 _info.lsda = fdeInfo.lsda; |
| 627 _info.handler = cieInfo.personality; |
| 628 _info.gp = prolog.spExtraArgSize; |
| 629 _info.flags = 0; |
| 630 _info.format = dwarfEncoding(); |
| 631 _info.unwind_info = fdeInfo.fdeStart; |
| 632 _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; |
| 633 _info.extra = (unw_word_t) sects.dso_base; |
| 634 |
| 635 // Add to cache (to make next lookup faster) if we had no hint |
| 636 // and there was no index. |
| 637 if (!foundInCache && (fdeSectionOffsetHint == 0)) { |
| 638 #if _LIBUNWIND_SUPPORT_DWARF_INDEX |
| 639 if (sects.dwarf_index_section == 0) |
| 640 #endif |
| 641 DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, |
| 642 fdeInfo.fdeStart); |
| 643 } |
| 644 return true; |
| 645 } |
| 646 } |
| 647 //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); |
| 648 return false; |
| 649 } |
| 650 #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 651 |
| 652 |
| 653 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 654 template <typename A, typename R> |
| 655 bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc, |
| 656 const UnwindInfoSections §s) { |
| 657 const bool log = false; |
| 658 if (log) |
| 659 fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", |
| 660 (uint64_t)pc, (uint64_t)sects.dso_base); |
| 661 |
| 662 const UnwindSectionHeader<A> sectionHeader(_addressSpace, |
| 663 sects.compact_unwind_section); |
| 664 if (sectionHeader.version() != UNWIND_SECTION_VERSION) |
| 665 return false; |
| 666 |
| 667 // do a binary search of top level index to find page with unwind info |
| 668 pint_t targetFunctionOffset = pc - sects.dso_base; |
| 669 const UnwindSectionIndexArray<A> topIndex(_addressSpace, |
| 670 sects.compact_unwind_section |
| 671 + sectionHeader.indexSectionOffset()); |
| 672 uint32_t low = 0; |
| 673 uint32_t high = sectionHeader.indexCount(); |
| 674 uint32_t last = high - 1; |
| 675 while (low < high) { |
| 676 uint32_t mid = (low + high) / 2; |
| 677 //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", |
| 678 //mid, low, high, topIndex.functionOffset(mid)); |
| 679 if (topIndex.functionOffset(mid) <= targetFunctionOffset) { |
| 680 if ((mid == last) || |
| 681 (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { |
| 682 low = mid; |
| 683 break; |
| 684 } else { |
| 685 low = mid + 1; |
| 686 } |
| 687 } else { |
| 688 high = mid; |
| 689 } |
| 690 } |
| 691 const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); |
| 692 const uint32_t firstLevelNextPageFunctionOffset = |
| 693 topIndex.functionOffset(low + 1); |
| 694 const pint_t secondLevelAddr = |
| 695 sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low)
; |
| 696 const pint_t lsdaArrayStartAddr = |
| 697 sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); |
| 698 const pint_t lsdaArrayEndAddr = |
| 699 sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1)
; |
| 700 if (log) |
| 701 fprintf(stderr, "\tfirst level search for result index=%d " |
| 702 "to secondLevelAddr=0x%llX\n", |
| 703 low, (uint64_t) secondLevelAddr); |
| 704 // do a binary search of second level page index |
| 705 uint32_t encoding = 0; |
| 706 pint_t funcStart = 0; |
| 707 pint_t funcEnd = 0; |
| 708 pint_t lsda = 0; |
| 709 pint_t personality = 0; |
| 710 uint32_t pageKind = _addressSpace.get32(secondLevelAddr); |
| 711 if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { |
| 712 // regular page |
| 713 UnwindSectionRegularPageHeader<A> pageHeader(_addressSpace, |
| 714 secondLevelAddr); |
| 715 UnwindSectionRegularArray<A> pageIndex( |
| 716 _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); |
| 717 // binary search looks for entry with e where index[e].offset <= pc < |
| 718 // index[e+1].offset |
| 719 if (log) |
| 720 fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " |
| 721 "regular page starting at secondLevelAddr=0x%llX\n", |
| 722 (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); |
| 723 low = 0; |
| 724 high = pageHeader.entryCount(); |
| 725 while (low < high) { |
| 726 uint32_t mid = (low + high) / 2; |
| 727 if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { |
| 728 if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { |
| 729 // at end of table |
| 730 low = mid; |
| 731 funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; |
| 732 break; |
| 733 } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { |
| 734 // next is too big, so we found it |
| 735 low = mid; |
| 736 funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; |
| 737 break; |
| 738 } else { |
| 739 low = mid + 1; |
| 740 } |
| 741 } else { |
| 742 high = mid; |
| 743 } |
| 744 } |
| 745 encoding = pageIndex.encoding(low); |
| 746 funcStart = pageIndex.functionOffset(low) + sects.dso_base; |
| 747 if (pc < funcStart) { |
| 748 if (log) |
| 749 fprintf( |
| 750 stderr, |
| 751 "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", |
| 752 (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); |
| 753 return false; |
| 754 } |
| 755 if (pc > funcEnd) { |
| 756 if (log) |
| 757 fprintf( |
| 758 stderr, |
| 759 "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", |
| 760 (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); |
| 761 return false; |
| 762 } |
| 763 } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { |
| 764 // compressed page |
| 765 UnwindSectionCompressedPageHeader<A> pageHeader(_addressSpace, |
| 766 secondLevelAddr); |
| 767 UnwindSectionCompressedArray<A> pageIndex( |
| 768 _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); |
| 769 const uint32_t targetFunctionPageOffset = |
| 770 (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); |
| 771 // binary search looks for entry with e where index[e].offset <= pc < |
| 772 // index[e+1].offset |
| 773 if (log) |
| 774 fprintf(stderr, "\tbinary search of compressed page starting at " |
| 775 "secondLevelAddr=0x%llX\n", |
| 776 (uint64_t) secondLevelAddr); |
| 777 low = 0; |
| 778 last = pageHeader.entryCount() - 1; |
| 779 high = pageHeader.entryCount(); |
| 780 while (low < high) { |
| 781 uint32_t mid = (low + high) / 2; |
| 782 if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { |
| 783 if ((mid == last) || |
| 784 (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { |
| 785 low = mid; |
| 786 break; |
| 787 } else { |
| 788 low = mid + 1; |
| 789 } |
| 790 } else { |
| 791 high = mid; |
| 792 } |
| 793 } |
| 794 funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset |
| 795 + sects.dso_base; |
| 796 if (low < last) |
| 797 funcEnd = |
| 798 pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset |
| 799 + sects.dso_base; |
| 800 else |
| 801 funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; |
| 802 if (pc < funcStart) { |
| 803 _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " |
| 804 "level compressed unwind table. funcStart=0x%llX\n", |
| 805 (uint64_t) pc, (uint64_t) funcStart); |
| 806 return false; |
| 807 } |
| 808 if (pc > funcEnd) { |
| 809 _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " |
| 810 "level compressed unwind table. funcEnd=0x%llX\n", |
| 811 (uint64_t) pc, (uint64_t) funcEnd); |
| 812 return false; |
| 813 } |
| 814 uint16_t encodingIndex = pageIndex.encodingIndex(low); |
| 815 if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { |
| 816 // encoding is in common table in section header |
| 817 encoding = _addressSpace.get32( |
| 818 sects.compact_unwind_section + |
| 819 sectionHeader.commonEncodingsArraySectionOffset() + |
| 820 encodingIndex * sizeof(uint32_t)); |
| 821 } else { |
| 822 // encoding is in page specific table |
| 823 uint16_t pageEncodingIndex = |
| 824 encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); |
| 825 encoding = _addressSpace.get32(secondLevelAddr + |
| 826 pageHeader.encodingsPageOffset() + |
| 827 pageEncodingIndex * sizeof(uint32_t)); |
| 828 } |
| 829 } else { |
| 830 _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " |
| 831 "level page\n", |
| 832 (uint64_t) sects.compact_unwind_section); |
| 833 return false; |
| 834 } |
| 835 |
| 836 // look up LSDA, if encoding says function has one |
| 837 if (encoding & UNWIND_HAS_LSDA) { |
| 838 UnwindSectionLsdaArray<A> lsdaIndex(_addressSpace, lsdaArrayStartAddr); |
| 839 uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); |
| 840 low = 0; |
| 841 high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / |
| 842 sizeof(unwind_info_section_header_lsda_index_entry); |
| 843 // binary search looks for entry with exact match for functionOffset |
| 844 if (log) |
| 845 fprintf(stderr, |
| 846 "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", |
| 847 funcStartOffset); |
| 848 while (low < high) { |
| 849 uint32_t mid = (low + high) / 2; |
| 850 if (lsdaIndex.functionOffset(mid) == funcStartOffset) { |
| 851 lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; |
| 852 break; |
| 853 } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { |
| 854 low = mid + 1; |
| 855 } else { |
| 856 high = mid; |
| 857 } |
| 858 } |
| 859 if (lsda == 0) { |
| 860 _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " |
| 861 "pc=0x%0llX, but lsda table has no entry\n", |
| 862 encoding, (uint64_t) pc); |
| 863 return false; |
| 864 } |
| 865 } |
| 866 |
| 867 // extact personality routine, if encoding says function has one |
| 868 uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> |
| 869 (__builtin_ctz(UNWIND_PERSONALITY_MASK)); |
| 870 if (personalityIndex != 0) { |
| 871 --personalityIndex; // change 1-based to zero-based index |
| 872 if (personalityIndex > sectionHeader.personalityArrayCount()) { |
| 873 _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " |
| 874 "but personality table has only %d entires\n", |
| 875 encoding, personalityIndex, |
| 876 sectionHeader.personalityArrayCount()); |
| 877 return false; |
| 878 } |
| 879 uint32_t personalityDelta = _addressSpace.get32( |
| 880 sects.compact_unwind_section + sectionHeader.personalityArraySectionOffs
et() + |
| 881 personalityIndex * sizeof(uint32_t)); |
| 882 pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; |
| 883 personality = _addressSpace.getP(personalityPointer); |
| 884 if (log) |
| 885 fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " |
| 886 "personalityDelta=0x%08X, personality=0x%08llX\n", |
| 887 (uint64_t) pc, personalityDelta, (uint64_t) personality); |
| 888 } |
| 889 |
| 890 if (log) |
| 891 fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " |
| 892 "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", |
| 893 (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); |
| 894 _info.start_ip = funcStart; |
| 895 _info.end_ip = funcEnd; |
| 896 _info.lsda = lsda; |
| 897 _info.handler = personality; |
| 898 _info.gp = 0; |
| 899 _info.flags = 0; |
| 900 _info.format = encoding; |
| 901 _info.unwind_info = 0; |
| 902 _info.unwind_info_size = 0; |
| 903 _info.extra = sects.dso_base; |
| 904 return true; |
| 905 } |
| 906 #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 907 |
| 908 |
| 909 template <typename A, typename R> |
| 910 void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) { |
| 911 pint_t pc = (pint_t)this->getReg(UNW_REG_IP); |
| 912 |
| 913 // If the last line of a function is a "throw" the compiler sometimes |
| 914 // emits no instructions after the call to __cxa_throw. This means |
| 915 // the return address is actually the start of the next function. |
| 916 // To disambiguate this, back up the pc when we know it is a return |
| 917 // address. |
| 918 if (isReturnAddress) |
| 919 --pc; |
| 920 |
| 921 // Ask address space object to find unwind sections for this pc. |
| 922 UnwindInfoSections sects; |
| 923 if (_addressSpace.findUnwindSections(pc, sects)) { |
| 924 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 925 // If there is a compact unwind encoding table, look there first. |
| 926 if (sects.compact_unwind_section != 0) { |
| 927 if (this->getInfoFromCompactEncodingSection(pc, sects)) { |
| 928 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 929 // Found info in table, done unless encoding says to use dwarf. |
| 930 uint32_t dwarfOffset; |
| 931 if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { |
| 932 if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { |
| 933 // found info in dwarf, done |
| 934 return; |
| 935 } |
| 936 } |
| 937 #endif |
| 938 // If unwind table has entry, but entry says there is no unwind info, |
| 939 // record that we have no unwind info. |
| 940 if (_info.format == 0) |
| 941 _unwindInfoMissing = true; |
| 942 return; |
| 943 } |
| 944 } |
| 945 #endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 946 |
| 947 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 948 // If there is dwarf unwind info, look there next. |
| 949 if (sects.dwarf_section != 0) { |
| 950 if (this->getInfoFromDwarfSection(pc, sects)) { |
| 951 // found info in dwarf, done |
| 952 return; |
| 953 } |
| 954 } |
| 955 #endif |
| 956 } |
| 957 |
| 958 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 959 // There is no static unwind info for this pc. Look to see if an FDE was |
| 960 // dynamically registered for it. |
| 961 pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc); |
| 962 if (cachedFDE != 0) { |
| 963 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; |
| 964 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; |
| 965 const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace, |
| 966 cachedFDE, &fdeInfo, &cieInfo); |
| 967 if (msg == NULL) { |
| 968 typename CFI_Parser<A>::PrologInfo prolog; |
| 969 if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, |
| 970 pc, &prolog)) { |
| 971 // save off parsed FDE info |
| 972 _info.start_ip = fdeInfo.pcStart; |
| 973 _info.end_ip = fdeInfo.pcEnd; |
| 974 _info.lsda = fdeInfo.lsda; |
| 975 _info.handler = cieInfo.personality; |
| 976 _info.gp = prolog.spExtraArgSize; |
| 977 // Some frameless functions need SP |
| 978 // altered when resuming in function. |
| 979 _info.flags = 0; |
| 980 _info.format = dwarfEncoding(); |
| 981 _info.unwind_info = fdeInfo.fdeStart; |
| 982 _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; |
| 983 _info.extra = 0; |
| 984 return; |
| 985 } |
| 986 } |
| 987 } |
| 988 |
| 989 // Lastly, ask AddressSpace object about platform specific ways to locate |
| 990 // other FDEs. |
| 991 pint_t fde; |
| 992 if (_addressSpace.findOtherFDE(pc, fde)) { |
| 993 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; |
| 994 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; |
| 995 if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { |
| 996 // Double check this FDE is for a function that includes the pc. |
| 997 if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { |
| 998 typename CFI_Parser<A>::PrologInfo prolog; |
| 999 if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, |
| 1000 cieInfo, pc, &prolog)) { |
| 1001 // save off parsed FDE info |
| 1002 _info.start_ip = fdeInfo.pcStart; |
| 1003 _info.end_ip = fdeInfo.pcEnd; |
| 1004 _info.lsda = fdeInfo.lsda; |
| 1005 _info.handler = cieInfo.personality; |
| 1006 _info.gp = prolog.spExtraArgSize; |
| 1007 _info.flags = 0; |
| 1008 _info.format = dwarfEncoding(); |
| 1009 _info.unwind_info = fdeInfo.fdeStart; |
| 1010 _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; |
| 1011 _info.extra = 0; |
| 1012 return; |
| 1013 } |
| 1014 } |
| 1015 } |
| 1016 } |
| 1017 #endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 1018 |
| 1019 // no unwind info, flag that we can't reliably unwind |
| 1020 _unwindInfoMissing = true; |
| 1021 } |
| 1022 |
| 1023 template <typename A, typename R> |
| 1024 int UnwindCursor<A, R>::step() { |
| 1025 // Bottom of stack is defined is when no unwind info cannot be found. |
| 1026 if (_unwindInfoMissing) |
| 1027 return UNW_STEP_END; |
| 1028 |
| 1029 // Use unwinding info to modify register set as if function returned. |
| 1030 int result; |
| 1031 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND |
| 1032 result = this->stepWithCompactEncoding(); |
| 1033 #elif _LIBUNWIND_SUPPORT_DWARF_UNWIND |
| 1034 result = this->stepWithDwarfFDE(); |
| 1035 #else |
| 1036 #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or _LIBUNWIND_SUPPORT_DWARF_UNWI
ND |
| 1037 #endif |
| 1038 |
| 1039 // update info based on new PC |
| 1040 if (result == UNW_STEP_SUCCESS) { |
| 1041 this->setInfoBasedOnIPRegister(true); |
| 1042 if (_unwindInfoMissing) |
| 1043 return UNW_STEP_END; |
| 1044 } |
| 1045 |
| 1046 return result; |
| 1047 } |
| 1048 |
| 1049 template <typename A, typename R> |
| 1050 void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) { |
| 1051 *info = _info; |
| 1052 } |
| 1053 |
| 1054 template <typename A, typename R> |
| 1055 bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen, |
| 1056 unw_word_t *offset) { |
| 1057 return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), |
| 1058 buf, bufLen, offset); |
| 1059 } |
| 1060 |
| 1061 }; // namespace libunwind |
| 1062 |
| 1063 #endif // __UNWINDCURSOR_HPP__ |
OLD | NEW |