1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2007-2009 Apple Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25// 26// C++ interface to lower levels of libuwind 27// 28 29#ifndef __UNWINDCURSOR_HPP__ 30#define __UNWINDCURSOR_HPP__ 31 32#include <stdint.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <pthread.h> 36#include <Availability.h> 37 38#include "libunwind.h" 39 40#include "AddressSpace.hpp" 41#include "Registers.hpp" 42#include "DwarfInstructions.hpp" 43#include "CompactUnwinder.hpp" 44#include "InternalMacros.h" 45 46#if __MAC_OS_X_VERSION_MIN_REQUIRED 47 #define KEYMGR_SUPPPORT 1 48#else 49 #define KEYMGR_SUPPPORT 0 50#endif 51 52 53#if KEYMGR_SUPPPORT 54// private keymgr stuff 55#define KEYMGR_GCC3_DW2_OBJ_LIST 302 56extern "C" { 57 extern void _keymgr_set_and_unlock_processwide_ptr(int key, void* ptr); 58 extern void* _keymgr_get_and_lock_processwide_ptr(int key); 59}; 60 61// undocumented libgcc "struct object" 62struct libgcc_object 63{ 64 void* start; 65 void* unused1; 66 void* unused2; 67 void* fde; 68 unsigned long encoding; 69 void* fde_end; 70 libgcc_object* next; 71}; 72 73// undocumented libgcc "struct km_object_info" referenced by KEYMGR_GCC3_DW2_OBJ_LIST 74struct libgcc_object_info { 75 struct libgcc_object* seen_objects; 76 struct libgcc_object* unseen_objects; 77 unsigned spare[2]; 78}; 79#endif // KEYMGR_SUPPPORT 80 81 82 83namespace libunwind { 84 85#if !FOR_DYLD 86template <typename A> 87class DwarfFDECache 88{ 89public: 90 typedef typename A::pint_t pint_t; 91 static pint_t findFDE(pint_t mh, pint_t pc); 92 static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); 93 static void removeAllIn(pint_t mh); 94 static void iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)); 95private: 96 static void dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide); 97 98 struct entry { pint_t mh; pint_t ip_start; pint_t ip_end; pint_t fde; }; 99 100 // these fields are all static to avoid needing an initializer 101 // there is only one instance of this class per process 102 static pthread_rwlock_t fgLock; 103 static bool fgRegisteredForDyldUnloads; 104 // can't use std::vector<> here because this code must live in libSystem.dylib (which is below libstdc++.dylib) 105 static entry* fgBuffer; 106 static entry* fgBufferUsed; 107 static entry* fgBufferEnd; 108 static entry fgInitialBuffer[64]; 109}; 110 111template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBuffer = fgInitialBuffer; 112template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferUsed = fgInitialBuffer; 113template <typename A> typename DwarfFDECache<A>::entry* DwarfFDECache<A>::fgBufferEnd = &fgInitialBuffer[64]; 114template <typename A> typename DwarfFDECache<A>::entry DwarfFDECache<A>::fgInitialBuffer[64]; 115 116template <typename A> 117pthread_rwlock_t DwarfFDECache<A>::fgLock = PTHREAD_RWLOCK_INITIALIZER; 118 119template <typename A> 120bool DwarfFDECache<A>::fgRegisteredForDyldUnloads = false; 121 122 123template <typename A> 124typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) 125{ 126 pint_t result = NULL; 127 DEBUG_LOG_NON_ZERO(::pthread_rwlock_rdlock(&fgLock)); 128 for(entry* p=fgBuffer; p < fgBufferUsed; ++p) { 129 if ( (mh == p->mh) || (mh == 0) ) { 130 if ( (p->ip_start <= pc) && (pc < p->ip_end) ) { 131 result = p->fde; 132 break; 133 } 134 } 135 } 136 DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); 137 //fprintf(stderr, "DwarfFDECache::findFDE(mh=0x%llX, pc=0x%llX) => 0x%llX\n", (uint64_t)mh, (uint64_t)pc, (uint64_t)result); 138 return result; 139} 140 141template <typename A> 142void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde) 143{ 144 //fprintf(stderr, "DwarfFDECache::add(mh=0x%llX, ip_start=0x%llX, ip_end=0x%llX, fde=0x%llX) pthread=%p\n", 145 // (uint64_t)mh, (uint64_t)ip_start, (uint64_t)ip_end, (uint64_t)fde, pthread_self()); 146 DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock)); 147 if ( fgBufferUsed >= fgBufferEnd ) { 148 int oldSize = fgBufferEnd - fgBuffer; 149 int newSize = oldSize*4; 150 entry* newBuffer = (entry*)malloc(newSize*sizeof(entry)); // can't use operator new in libSystem.dylib 151 memcpy(newBuffer, fgBuffer, oldSize*sizeof(entry)); 152 //fprintf(stderr, "DwarfFDECache::add() growing buffer to %d\n", newSize); 153 if ( fgBuffer != fgInitialBuffer ) 154 free(fgBuffer); 155 fgBuffer = newBuffer; 156 fgBufferUsed = &newBuffer[oldSize]; 157 fgBufferEnd = &newBuffer[newSize]; 158 } 159 fgBufferUsed->mh = mh; 160 fgBufferUsed->ip_start = ip_start; 161 fgBufferUsed->ip_end = ip_end; 162 fgBufferUsed->fde = fde; 163 ++fgBufferUsed; 164 if ( !fgRegisteredForDyldUnloads ) { 165 _dyld_register_func_for_remove_image(&dyldUnloadHook); 166 fgRegisteredForDyldUnloads = true; 167 } 168 DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); 169} 170 171 172 173template <typename A> 174void DwarfFDECache<A>::removeAllIn(pint_t mh) 175{ 176 DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock)); 177 entry* d=fgBuffer; 178 for(const entry* s=fgBuffer; s < fgBufferUsed; ++s) { 179 if ( s->mh != mh ) { 180 if ( d != s ) 181 *d = *s; 182 ++d; 183 } 184 } 185 fgBufferUsed = d; 186 DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); 187} 188 189 190template <typename A> 191void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header* mh, intptr_t vmaddr_slide) 192{ 193 removeAllIn((pint_t)mh); 194} 195 196template <typename A> 197void DwarfFDECache<A>::iterateCacheEntries(void (*func)(unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) 198{ 199 DEBUG_LOG_NON_ZERO(::pthread_rwlock_wrlock(&fgLock)); 200 for(entry* p=fgBuffer; p < fgBufferUsed; ++p) { 201 (*func)(p->ip_start, p->ip_end, p->fde, p->mh); 202 } 203 DEBUG_LOG_NON_ZERO(::pthread_rwlock_unlock(&fgLock)); 204} 205#endif // !FOR_DYLD 206 207 208 209 210#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) 211 212template <typename A> 213class UnwindSectionHeader { 214public: 215 UnwindSectionHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 216 217 uint32_t version() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, version)); } 218 uint32_t commonEncodingsArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArraySectionOffset)); } 219 uint32_t commonEncodingsArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, commonEncodingsArrayCount)); } 220 uint32_t personalityArraySectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArraySectionOffset)); } 221 uint32_t personalityArrayCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, personalityArrayCount)); } 222 uint32_t indexSectionOffset() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexSectionOffset)); } 223 uint32_t indexCount() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_section_header, indexCount)); } 224private: 225 A& fAddressSpace; 226 typename A::pint_t fAddr; 227}; 228 229template <typename A> 230class UnwindSectionIndexArray { 231public: 232 UnwindSectionIndexArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 233 234 uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, functionOffset)); } 235 uint32_t secondLevelPagesSectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, secondLevelPagesSectionOffset)); } 236 uint32_t lsdaIndexArraySectionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_index_entry, index, lsdaIndexArraySectionOffset)); } 237private: 238 A& fAddressSpace; 239 typename A::pint_t fAddr; 240}; 241 242 243template <typename A> 244class UnwindSectionRegularPageHeader { 245public: 246 UnwindSectionRegularPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 247 248 uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_regular_second_level_page_header, kind)); } 249 uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryPageOffset)); } 250 uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_regular_second_level_page_header, entryCount)); } 251private: 252 A& fAddressSpace; 253 typename A::pint_t fAddr; 254}; 255 256 257template <typename A> 258class UnwindSectionRegularArray { 259public: 260 UnwindSectionRegularArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 261 262 uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, functionOffset)); } 263 uint32_t encoding(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); } 264private: 265 A& fAddressSpace; 266 typename A::pint_t fAddr; 267}; 268 269 270template <typename A> 271class UnwindSectionCompressedPageHeader { 272public: 273 UnwindSectionCompressedPageHeader(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 274 275 uint32_t kind() const INLINE { return fAddressSpace.get32(fAddr + offsetof(unwind_info_compressed_second_level_page_header, kind)); } 276 uint16_t entryPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryPageOffset)); } 277 uint16_t entryCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); } 278 uint16_t encodingsPageOffset() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsPageOffset)); } 279 uint16_t encodingsCount() const INLINE { return fAddressSpace.get16(fAddr + offsetof(unwind_info_compressed_second_level_page_header, encodingsCount)); } 280private: 281 A& fAddressSpace; 282 typename A::pint_t fAddr; 283}; 284 285 286template <typename A> 287class UnwindSectionCompressedArray { 288public: 289 UnwindSectionCompressedArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 290 291 uint32_t functionOffset(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); } 292 uint16_t encodingIndex(int index) const INLINE { return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( fAddressSpace.get32(fAddr + index*sizeof(uint32_t)) ); } 293private: 294 A& fAddressSpace; 295 typename A::pint_t fAddr; 296}; 297 298 299template <typename A> 300class UnwindSectionLsdaArray { 301public: 302 UnwindSectionLsdaArray(A& addressSpace, typename A::pint_t addr) : fAddressSpace(addressSpace), fAddr(addr) {} 303 304 uint32_t functionOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, functionOffset)); } 305 int32_t lsdaOffset(int index) const INLINE { return fAddressSpace.get32(fAddr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, index, lsdaOffset)); } 306private: 307 A& fAddressSpace; 308 typename A::pint_t fAddr; 309}; 310 311 312template <typename A, typename R> 313class UnwindCursor 314{ 315public: 316 UnwindCursor(unw_context_t* context, A& as); 317 UnwindCursor(A& as, thread_t thread); 318 virtual ~UnwindCursor() {} 319 virtual bool validReg(int); 320 virtual uint64_t getReg(int); 321 virtual void setReg(int, uint64_t); 322 virtual bool validFloatReg(int); 323 virtual double getFloatReg(int); 324 virtual void setFloatReg(int, double); 325 virtual int step(); 326 virtual void getInfo(unw_proc_info_t*); 327 virtual void jumpto(); 328 virtual const char* getRegisterName(int num); 329 virtual bool isSignalFrame(); 330 virtual bool getFunctionName(char* buf, size_t bufLen, unw_word_t* offset); 331 virtual void setInfoBasedOnIPRegister(bool isReturnAddress=false); 332 333 void operator delete(void* p, size_t size) {} 334 335private: 336 typedef typename A::pint_t pint_t; 337 typedef uint32_t EncodedUnwindInfo; 338 339 bool getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart); 340 bool getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE); 341 342 int stepWithDwarfFDE() 343 { return DwarfInstructions<A,R>::stepWithDwarf(fAddressSpace, this->getReg(UNW_REG_IP), fInfo.unwind_info, fRegisters); } 344 345 int stepWithCompactEncoding() { R dummy; return stepWithCompactEncoding(dummy); } 346 int stepWithCompactEncoding(Registers_x86_64&) 347 { return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); } 348 int stepWithCompactEncoding(Registers_x86&) 349 { return CompactUnwinder_x86<A>::stepWithCompactEncoding(fInfo.format, fInfo.start_ip, fAddressSpace, fRegisters); } 350 int stepWithCompactEncoding(Registers_ppc&) 351 { return UNW_EINVAL; } 352 353#if FOR_DYLD 354 #if __ppc__ 355 bool mustUseDwarf() const { return true; } 356 #else 357 bool mustUseDwarf() const { return false; } 358 #endif 359#else 360 bool mustUseDwarf() const { R dummy; uint32_t offset; return dwarfWithOffset(dummy, offset); } 361#endif 362 363 bool dwarfWithOffset(uint32_t& offset) const { R dummy; return dwarfWithOffset(dummy, offset); } 364 bool dwarfWithOffset(Registers_x86_64&, uint32_t& offset) const { 365 if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF ) { 366 offset = (fInfo.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); 367 return true; 368 } 369#if SUPPORT_OLD_BINARIES 370 if ( (fInfo.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_COMPATIBILITY ) { 371 if ( (fInfo.format & UNWIND_X86_64_CASE_MASK) == UNWIND_X86_64_UNWIND_REQUIRES_DWARF ) { 372 offset = 0; 373 return true; 374 } 375 } 376#endif 377 return false; 378 } 379 bool dwarfWithOffset(Registers_x86&, uint32_t& offset) const { 380 if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF ) { 381 offset = (fInfo.format & UNWIND_X86_DWARF_SECTION_OFFSET); 382 return true; 383 } 384#if SUPPORT_OLD_BINARIES 385 if ( (fInfo.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_COMPATIBILITY ) { 386 if ( (fInfo.format & UNWIND_X86_CASE_MASK) == UNWIND_X86_UNWIND_REQUIRES_DWARF ) { 387 offset = 0; 388 return true; 389 } 390 } 391#endif 392 return false; 393 } 394 bool dwarfWithOffset(Registers_ppc&, uint32_t& offset) const { return true; } 395 396 397 compact_unwind_encoding_t dwarfEncoding() const { R dummy; return dwarfEncoding(dummy); } 398 compact_unwind_encoding_t dwarfEncoding(Registers_x86_64&) const { return UNWIND_X86_64_MODE_DWARF; } 399 compact_unwind_encoding_t dwarfEncoding(Registers_x86&) const { return UNWIND_X86_MODE_DWARF; } 400 compact_unwind_encoding_t dwarfEncoding(Registers_ppc&) const { return 0; } 401 402 unw_proc_info_t fInfo; 403 R fRegisters; 404 A& fAddressSpace; 405 bool fUnwindInfoMissing; 406 bool fIsSignalFrame; 407}; 408 409typedef UnwindCursor<LocalAddressSpace,Registers_x86> AbstractUnwindCursor; 410 411template <typename A, typename R> 412UnwindCursor<A,R>::UnwindCursor(unw_context_t* context, A& as) 413 : fRegisters(context), fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false) 414{ 415 COMPILE_TIME_ASSERT( sizeof(UnwindCursor<A,R>) < sizeof(unw_cursor_t) ); 416 417 bzero(&fInfo, sizeof(fInfo)); 418} 419 420template <typename A, typename R> 421UnwindCursor<A,R>::UnwindCursor(A& as, thread_t thread) 422 : fAddressSpace(as), fUnwindInfoMissing(false), fIsSignalFrame(false) 423{ 424 bzero(&fInfo, sizeof(fInfo)); 425 // FIXME 426 // fill in fRegisters from thread 427} 428 429template <typename A, typename R> 430bool UnwindCursor<A,R>::validReg(int regNum) 431{ 432 return fRegisters.validRegister(regNum); 433} 434 435template <typename A, typename R> 436uint64_t UnwindCursor<A,R>::getReg(int regNum) 437{ 438 return fRegisters.getRegister(regNum); 439} 440 441template <typename A, typename R> 442void UnwindCursor<A,R>::setReg(int regNum, uint64_t value) 443{ 444 fRegisters.setRegister(regNum, value); 445} 446 447template <typename A, typename R> 448bool UnwindCursor<A,R>::validFloatReg(int regNum) 449{ 450 return fRegisters.validFloatRegister(regNum); 451} 452 453template <typename A, typename R> 454double UnwindCursor<A,R>::getFloatReg(int regNum) 455{ 456 return fRegisters.getFloatRegister(regNum); 457} 458 459template <typename A, typename R> 460void UnwindCursor<A,R>::setFloatReg(int regNum, double value) 461{ 462 fRegisters.setFloatRegister(regNum, value); 463} 464 465template <typename A, typename R> 466void UnwindCursor<A,R>::jumpto() 467{ 468 fRegisters.jumpto(); 469} 470 471template <typename A, typename R> 472const char* UnwindCursor<A,R>::getRegisterName(int regNum) 473{ 474 return fRegisters.getRegisterName(regNum); 475} 476 477template <typename A, typename R> 478bool UnwindCursor<A,R>::isSignalFrame() 479{ 480 return fIsSignalFrame; 481} 482 483 484template <typename A, typename R> 485bool UnwindCursor<A,R>::getInfoFromDwarfSection(pint_t pc, pint_t mh, pint_t ehSectionStart, uint32_t sectionLength, uint32_t sectionOffsetOfFDE) 486{ 487 typename CFI_Parser<A>::FDE_Info fdeInfo; 488 typename CFI_Parser<A>::CIE_Info cieInfo; 489 bool foundFDE = false; 490 bool foundInCache = false; 491 // if compact encoding table gave offset into dwarf section, go directly there 492 if ( sectionOffsetOfFDE != 0 ) { 493 foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, ehSectionStart+sectionOffsetOfFDE, &fdeInfo, &cieInfo); 494 } 495#if !FOR_DYLD 496 if ( !foundFDE ) { 497 // otherwise, search cache of previously found FDEs 498 pint_t cachedFDE = DwarfFDECache<A>::findFDE(mh, pc); 499 //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%llX) cachedFDE=0x%llX\n", (uint64_t)pc, (uint64_t)cachedFDE); 500 if ( cachedFDE != 0 ) { 501 foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, cachedFDE, &fdeInfo, &cieInfo); 502 foundInCache = foundFDE; 503 //fprintf(stderr, "cachedFDE=0x%llX, foundInCache=%d\n", (uint64_t)cachedFDE, foundInCache); 504 } 505 } 506#endif 507 if ( !foundFDE ) { 508 // still not found, do full scan of __eh_frame section 509 foundFDE = CFI_Parser<A>::findFDE(fAddressSpace, pc, ehSectionStart, sectionLength, 0, &fdeInfo, &cieInfo); 510 } 511 if ( foundFDE ) { 512 typename CFI_Parser<A>::PrologInfo prolog; 513 if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) { 514 // save off parsed FDE info 515 fInfo.start_ip = fdeInfo.pcStart; 516 fInfo.end_ip = fdeInfo.pcEnd; 517 fInfo.lsda = fdeInfo.lsda; 518 fInfo.handler = cieInfo.personality; 519 fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function 520 fInfo.flags = 0; 521 fInfo.format = dwarfEncoding(); 522 fInfo.unwind_info = fdeInfo.fdeStart; 523 fInfo.unwind_info_size = fdeInfo.fdeLength; 524 fInfo.extra = (unw_word_t)mh; 525 if ( !foundInCache && (sectionOffsetOfFDE == 0) ) { 526 // don't add to cache entries the compact encoding table can find quickly 527 //fprintf(stderr, "getInfoFromDwarfSection(pc=0x%0llX), mh=0x%llX, start_ip=0x%0llX, fde=0x%0llX, personality=0x%0llX\n", 528 // (uint64_t)pc, (uint64_t)mh, fInfo.start_ip, fInfo.unwind_info, fInfo.handler); 529#if !FOR_DYLD 530 DwarfFDECache<A>::add(mh, fdeInfo.pcStart, fdeInfo.pcEnd, fdeInfo.fdeStart); 531#endif 532 } 533 return true; 534 } 535 } 536 //DEBUG_MESSAGE("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); 537 return false; 538} 539 540 541template <typename A, typename R> 542bool UnwindCursor<A,R>::getInfoFromCompactEncodingSection(pint_t pc, pint_t mh, pint_t unwindSectionStart) 543{ 544 const bool log = false; 545 if ( log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", (uint64_t)pc, (uint64_t)mh); 546 547 const UnwindSectionHeader<A> sectionHeader(fAddressSpace, unwindSectionStart); 548 if ( sectionHeader.version() != UNWIND_SECTION_VERSION ) 549 return false; 550 551 // do a binary search of top level index to find page with unwind info 552 uint32_t targetFunctionOffset = pc - mh; 553 const UnwindSectionIndexArray<A> topIndex(fAddressSpace, unwindSectionStart + sectionHeader.indexSectionOffset()); 554 uint32_t low = 0; 555 uint32_t high = sectionHeader.indexCount(); 556 const uint32_t last = high - 1; 557 while ( low < high ) { 558 uint32_t mid = (low + high)/2; 559 //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", mid, low, high, topIndex.functionOffset(mid)); 560 if ( topIndex.functionOffset(mid) <= targetFunctionOffset ) { 561 if ( (mid == last) || (topIndex.functionOffset(mid+1) > targetFunctionOffset) ) { 562 low = mid; 563 break; 564 } 565 else { 566 low = mid+1; 567 } 568 } 569 else { 570 high = mid; 571 } 572 } 573 const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); 574 const uint32_t firstLevelNextPageFunctionOffset = topIndex.functionOffset(low+1); 575 const pint_t secondLevelAddr = unwindSectionStart+topIndex.secondLevelPagesSectionOffset(low); 576 const pint_t lsdaArrayStartAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low); 577 const pint_t lsdaArrayEndAddr = unwindSectionStart+topIndex.lsdaIndexArraySectionOffset(low+1); 578 if ( log ) fprintf(stderr, "\tfirst level search for result index=%d to secondLevelAddr=0x%llX\n", 579 low, (uint64_t)secondLevelAddr); 580 // do a binary search of second level page index 581 uint32_t encoding = 0; 582 pint_t funcStart = 0; 583 pint_t funcEnd = 0; 584 pint_t lsda = 0; 585 pint_t personality = 0; 586 uint32_t pageKind = fAddressSpace.get32(secondLevelAddr); 587 if ( pageKind == UNWIND_SECOND_LEVEL_REGULAR ) { 588 // regular page 589 UnwindSectionRegularPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr); 590 UnwindSectionRegularArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset()); 591 // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset 592 if ( log ) fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in regular page starting at secondLevelAddr=0x%llX\n", 593 (uint64_t)targetFunctionOffset, (uint64_t)secondLevelAddr); 594 uint32_t low = 0; 595 uint32_t high = pageHeader.entryCount(); 596 while ( low < high ) { 597 uint32_t mid = (low + high)/2; 598 if ( pageIndex.functionOffset(mid) <= targetFunctionOffset ) { 599 if ( mid == (uint32_t)(pageHeader.entryCount()-1) ) { 600 // at end of table 601 low = mid; 602 funcEnd = firstLevelNextPageFunctionOffset + mh; 603 break; 604 } 605 else if ( pageIndex.functionOffset(mid+1) > targetFunctionOffset ) { 606 // next is too big, so we found it 607 low = mid; 608 funcEnd = pageIndex.functionOffset(low+1) + mh; 609 break; 610 } 611 else { 612 low = mid+1; 613 } 614 } 615 else { 616 high = mid; 617 } 618 } 619 encoding = pageIndex.encoding(low); 620 funcStart = pageIndex.functionOffset(low) + mh; 621 if ( pc < funcStart ) { 622 if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd); 623 return false; 624 } 625 if ( pc > funcEnd ) { 626 if ( log ) fprintf(stderr, "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart, (uint64_t)funcEnd); 627 return false; 628 } 629 } 630 else if ( pageKind == UNWIND_SECOND_LEVEL_COMPRESSED ) { 631 // compressed page 632 UnwindSectionCompressedPageHeader<A> pageHeader(fAddressSpace, secondLevelAddr); 633 UnwindSectionCompressedArray<A> pageIndex(fAddressSpace, secondLevelAddr + pageHeader.entryPageOffset()); 634 const uint32_t targetFunctionPageOffset = targetFunctionOffset - firstLevelFunctionOffset; 635 // binary search looks for entry with e where index[e].offset <= pc < index[e+1].offset 636 if ( log ) fprintf(stderr, "\tbinary search of compressed page starting at secondLevelAddr=0x%llX\n", (uint64_t)secondLevelAddr); 637 uint32_t low = 0; 638 const uint32_t last = pageHeader.entryCount() - 1; 639 uint32_t high = pageHeader.entryCount(); 640 while ( low < high ) { 641 uint32_t mid = (low + high)/2; 642 if ( pageIndex.functionOffset(mid) <= targetFunctionPageOffset ) { 643 if ( (mid == last) || (pageIndex.functionOffset(mid+1) > targetFunctionPageOffset) ) { 644 low = mid; 645 break; 646 } 647 else { 648 low = mid+1; 649 } 650 } 651 else { 652 high = mid; 653 } 654 } 655 funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + mh; 656 if ( low < last ) 657 funcEnd = pageIndex.functionOffset(low+1) + firstLevelFunctionOffset + mh; 658 else 659 funcEnd = firstLevelNextPageFunctionOffset + mh; 660 if ( pc < funcStart ) { 661 DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcStart=0x%llX\n", (uint64_t)pc, (uint64_t)funcStart); 662 return false; 663 } 664 if ( pc > funcEnd ) { 665 DEBUG_MESSAGE("malformed __unwind_info, pc=0x%llX not in second level compressed unwind table. funcEnd=0x%llX\n", (uint64_t)pc, (uint64_t)funcEnd); 666 return false; 667 } 668 uint16_t encodingIndex = pageIndex.encodingIndex(low); 669 if ( encodingIndex < sectionHeader.commonEncodingsArrayCount() ) { 670 // encoding is in common table in section header 671 encoding = fAddressSpace.get32(unwindSectionStart+sectionHeader.commonEncodingsArraySectionOffset()+encodingIndex*sizeof(uint32_t)); 672 } 673 else { 674 // encoding is in page specific table 675 uint16_t pageEncodingIndex = encodingIndex-sectionHeader.commonEncodingsArrayCount(); 676 encoding = fAddressSpace.get32(secondLevelAddr+pageHeader.encodingsPageOffset()+pageEncodingIndex*sizeof(uint32_t)); 677 } 678 } 679 else { 680 DEBUG_MESSAGE("malformed __unwind_info at 0x%0llX bad second level page\n", (uint64_t)unwindSectionStart); 681 return false; 682 } 683 684 // look up LSDA, if encoding says function has one 685 if ( encoding & UNWIND_HAS_LSDA ) { 686 UnwindSectionLsdaArray<A> lsdaIndex(fAddressSpace, lsdaArrayStartAddr); 687 uint32_t funcStartOffset = funcStart - mh; 688 uint32_t low = 0; 689 uint32_t high = (lsdaArrayEndAddr-lsdaArrayStartAddr)/sizeof(unwind_info_section_header_lsda_index_entry); 690 // binary search looks for entry with exact match for functionOffset 691 if ( log ) fprintf(stderr, "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", funcStartOffset); 692 while ( low < high ) { 693 uint32_t mid = (low + high)/2; 694 if ( lsdaIndex.functionOffset(mid) == funcStartOffset ) { 695 lsda = lsdaIndex.lsdaOffset(mid) + mh; 696 break; 697 } 698 else if ( lsdaIndex.functionOffset(mid) < funcStartOffset ) { 699 low = mid+1; 700 } 701 else { 702 high = mid; 703 } 704 } 705 if ( lsda == 0 ) { 706 DEBUG_MESSAGE("found encoding 0x%08X with HAS_LSDA bit set for pc=0x%0llX, but lsda table has no entry\n", encoding, (uint64_t)pc); 707 return false; 708 } 709 } 710 711 // extact personality routine, if encoding says function has one 712 uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK)); 713 if ( personalityIndex != 0 ) { 714 --personalityIndex; // change 1-based to zero-based index 715 if ( personalityIndex > sectionHeader.personalityArrayCount() ) { 716 DEBUG_MESSAGE("found encoding 0x%08X with personality index %d, but personality table has only %d entires\n", 717 encoding, personalityIndex, sectionHeader.personalityArrayCount()); 718 return false; 719 } 720 int32_t personalityDelta = fAddressSpace.get32(unwindSectionStart+sectionHeader.personalityArraySectionOffset()+personalityIndex*sizeof(uint32_t)); 721 pint_t personalityPointer = personalityDelta + mh; 722 personality = fAddressSpace.getP(personalityPointer); 723 if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), personalityDelta=0x%08X, personality=0x%08llX\n", 724 (uint64_t)pc, personalityDelta, (uint64_t)personality); 725 } 726 727 if (log ) fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", 728 (uint64_t)pc, encoding, (uint64_t)lsda, (uint64_t)funcStart); 729 fInfo.start_ip = funcStart; 730 fInfo.end_ip = funcEnd; 731 fInfo.lsda = lsda; 732 fInfo.handler = personality; 733 fInfo.gp = 0; 734 fInfo.flags = 0; 735 fInfo.format = encoding; 736 fInfo.unwind_info = 0; 737 fInfo.unwind_info_size = 0; 738 fInfo.extra = mh; 739 return true; 740} 741 742 743 744template <typename A, typename R> 745void UnwindCursor<A,R>::setInfoBasedOnIPRegister(bool isReturnAddress) 746{ 747 pint_t pc = this->getReg(UNW_REG_IP); 748 749 // if the last line of a function is a "throw" the compile sometimes 750 // emits no instructions after the call to __cxa_throw. This means 751 // the return address is actually the start of the next function. 752 // To disambiguate this, back up the pc when we know it is a return 753 // address. 754 if ( isReturnAddress ) 755 --pc; 756 757 // ask address space object to find unwind sections for this pc 758 pint_t mh; 759 pint_t dwarfStart; 760 pint_t dwarfLength; 761 pint_t compactStart; 762 if ( fAddressSpace.findUnwindSections(pc, mh, dwarfStart, dwarfLength, compactStart) ) { 763 // if there is a compact unwind encoding table, look there first 764 if ( compactStart != 0 ) { 765 if ( this->getInfoFromCompactEncodingSection(pc, mh, compactStart) ) { 766#if !FOR_DYLD 767 // found info in table, done unless encoding says to use dwarf 768 uint32_t offsetInDwarfSection; 769 if ( (dwarfStart != 0) && dwarfWithOffset(offsetInDwarfSection) ) { 770 if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, offsetInDwarfSection) ) { 771 // found info in dwarf, done 772 return; 773 } 774 } 775#endif 776 // if unwind table has entry, but entry says there is no unwind info, note that 777 if ( fInfo.format == 0 ) 778 fUnwindInfoMissing = true; 779 780 // old compact encoding 781 if ( !mustUseDwarf() ) { 782 return; 783 } 784 } 785 } 786#if !FOR_DYLD || __ppc__ 787 // if there is dwarf unwind info, look there next 788 if ( dwarfStart != 0 ) { 789 if ( this->getInfoFromDwarfSection(pc, mh, dwarfStart, dwarfLength, 0) ) { 790 // found info in dwarf, done 791 return; 792 } 793 } 794#endif 795 } 796 797#if !FOR_DYLD 798 // the PC is not in code loaded by dyld, look through __register_frame() registered FDEs 799 pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc); 800 if ( cachedFDE != 0 ) { 801 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; 802 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; 803 const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, cachedFDE, &fdeInfo, &cieInfo); 804 if ( msg == NULL ) { 805 typename CFI_Parser<A>::PrologInfo prolog; 806 if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) { 807 // save off parsed FDE info 808 fInfo.start_ip = fdeInfo.pcStart; 809 fInfo.end_ip = fdeInfo.pcEnd; 810 fInfo.lsda = fdeInfo.lsda; 811 fInfo.handler = cieInfo.personality; 812 fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function 813 fInfo.flags = 0; 814 fInfo.format = dwarfEncoding(); 815 fInfo.unwind_info = fdeInfo.fdeStart; 816 fInfo.unwind_info_size = fdeInfo.fdeLength; 817 fInfo.extra = 0; 818 return; 819 } 820 } 821 } 822 823#if KEYMGR_SUPPPORT 824 // lastly check for old style keymgr registration of dynamically generated FDEs 825 // acquire exclusive access to libgcc_object_info 826 libgcc_object_info* head = (libgcc_object_info*)_keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); 827 if ( head != NULL ) { 828 // look at each FDE in keymgr 829 for (libgcc_object* ob = head->unseen_objects; ob != NULL; ob = ob->next) { 830 CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; 831 CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; 832 const char* msg = CFI_Parser<A>::decodeFDE(fAddressSpace, (pint_t)ob->fde, &fdeInfo, &cieInfo); 833 if ( msg == NULL ) { 834 // see if this FDE is for a function that includes the pc we are looking for 835 if ( (fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd) ) { 836 typename CFI_Parser<A>::PrologInfo prolog; 837 if ( CFI_Parser<A>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo, pc, &prolog) ) { 838 // save off parsed FDE info 839 fInfo.start_ip = fdeInfo.pcStart; 840 fInfo.end_ip = fdeInfo.pcEnd; 841 fInfo.lsda = fdeInfo.lsda; 842 fInfo.handler = cieInfo.personality; 843 fInfo.gp = prolog.spExtraArgSize; // some frameless functions need SP altered when resuming in function 844 fInfo.flags = 0; 845 fInfo.format = dwarfEncoding(); 846 fInfo.unwind_info = fdeInfo.fdeStart; 847 fInfo.unwind_info_size = fdeInfo.fdeLength; 848 fInfo.extra = 0; 849 _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); 850 return; 851 } 852 } 853 } 854 } 855 } 856 // release libgcc_object_info 857 _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); 858#endif // KEYMGR_SUPPPORT 859 860#endif 861 862 // no unwind info, flag that we can't reliable unwind 863 fUnwindInfoMissing = true; 864} 865 866 867template <typename A, typename R> 868int UnwindCursor<A,R>::step() 869{ 870 // bottom of stack is defined as when no more unwind info 871 if ( fUnwindInfoMissing ) 872 return UNW_STEP_END; 873 874 // apply unwinding to register set 875 int result; 876 if ( this->mustUseDwarf() ) 877 result = this->stepWithDwarfFDE(); 878 else 879 result = this->stepWithCompactEncoding(); 880 881 // update info based on new PC 882 if ( result == UNW_STEP_SUCCESS ) { 883 this->setInfoBasedOnIPRegister(true); 884 if ( fUnwindInfoMissing ) 885 return UNW_STEP_END; 886 } 887 888 return result; 889} 890 891 892template <typename A, typename R> 893void UnwindCursor<A,R>::getInfo(unw_proc_info_t* info) 894{ 895 *info = fInfo; 896} 897 898 899template <typename A, typename R> 900bool UnwindCursor<A,R>::getFunctionName(char* buf, size_t bufLen, unw_word_t* offset) 901{ 902 return fAddressSpace.findFunctionName(this->getReg(UNW_REG_IP), buf, bufLen, offset); 903} 904 905}; // namespace libunwind 906 907 908#endif // __UNWINDCURSOR_HPP__ 909 910 911 912 913