+#define EXTRACT_BITS(value, mask) \
+ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
+
+template <>
+void UnwindPrinter<x86_64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ *str = '\0';
+ switch ( encoding & UNWIND_X86_64_MODE_MASK ) {
+ case UNWIND_X86_64_MODE_RBP_FRAME:
+ {
+ uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+ if ( savedRegistersLocations == 0 ) {
+ strcpy(str, "rbp frame, no saved registers");
+ }
+ else {
+ sprintf(str, "rbp frame, at -%d:", savedRegistersOffset*8);
+ bool needComma = false;
+ for (int i=0; i < 5; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
+ strcat(str, "-");
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ strcat(str, "rbx");
+ break;
+ case UNWIND_X86_64_REG_R12:
+ strcat(str, "r12");
+ break;
+ case UNWIND_X86_64_REG_R13:
+ strcat(str, "r13");
+ break;
+ case UNWIND_X86_64_REG_R14:
+ strcat(str, "r14");
+ break;
+ case UNWIND_X86_64_REG_R15:
+ strcat(str, "r15");
+ break;
+ default:
+ strcat(str, "r?");
+ }
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ if ( savedRegistersLocations == 0 )
+ break;
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ case UNWIND_X86_64_MODE_STACK_IND:
+ {
+ uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+ if ( (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = x86_64::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
+ sprintf(str, "stack size=0x%08X, ", subl + 8*stackAdjust);
+ }
+ else {
+ sprintf(str, "stack size=%d, ", stackSize*8);
+ }
+ if ( regCount == 0 ) {
+ strcat(str, "no registers saved");
+ }
+ else {
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // renumber registers back to standard numbers
+ int registers[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (int i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registers[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ bool needComma = false;
+ for (int i=0; i < regCount; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch ( registers[i] ) {
+ case UNWIND_X86_64_REG_RBX:
+ strcat(str, "rbx");
+ break;
+ case UNWIND_X86_64_REG_R12:
+ strcat(str, "r12");
+ break;
+ case UNWIND_X86_64_REG_R13:
+ strcat(str, "r13");
+ break;
+ case UNWIND_X86_64_REG_R14:
+ strcat(str, "r14");
+ break;
+ case UNWIND_X86_64_REG_R15:
+ strcat(str, "r15");
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ strcat(str, "rbp");
+ break;
+ default:
+ strcat(str, "r??");
+ }
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_64_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ break;
+ default:
+ if ( encoding == 0 )
+ strcat(str, "no unwind information");
+ else
+ strcat(str, "tbd ");
+ }
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ strcat(str, " LSDA");
+ }
+
+}
+
+template <>
+void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ *str = '\0';
+ switch ( encoding & UNWIND_X86_MODE_MASK ) {
+ case UNWIND_X86_MODE_EBP_FRAME:
+ {
+ uint32_t savedRegistersOffset = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations = EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+ if ( savedRegistersLocations == 0 ) {
+ strcpy(str, "ebp frame, no saved registers");
+ }
+ else {
+ sprintf(str, "ebp frame, at -%d:", savedRegistersOffset*4);
+ bool needComma = false;
+ for (int i=0; i < 5; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_REG_NONE:
+ strcat(str, "-");
+ break;
+ case UNWIND_X86_REG_EBX:
+ strcat(str, "ebx");
+ break;
+ case UNWIND_X86_REG_ECX:
+ strcat(str, "ecx");
+ break;
+ case UNWIND_X86_REG_EDX:
+ strcat(str, "edx");
+ break;
+ case UNWIND_X86_REG_EDI:
+ strcat(str, "edi");
+ break;
+ case UNWIND_X86_REG_ESI:
+ strcat(str, "esi");
+ break;
+ default:
+ strcat(str, "e??");
+ }
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ if ( savedRegistersLocations == 0 )
+ break;
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_MODE_STACK_IMMD:
+ case UNWIND_X86_MODE_STACK_IND:
+ {
+ uint32_t stackSize = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation = EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ if ( (encoding & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_STACK_IND ) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = x86::P::E::get32(*((uint32_t*)(funcStart+stackSize)));
+ sprintf(str, "stack size=0x%08X, ", subl+4*stackAdjust);
+ }
+ else {
+ sprintf(str, "stack size=%d, ", stackSize*4);
+ }
+ if ( regCount == 0 ) {
+ strcat(str, "no saved regs");
+ }
+ else {
+ int permunreg[6];
+ switch ( regCount ) {
+ case 6:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation/120;
+ permutation -= (permunreg[0]*120);
+ permunreg[1] = permutation/24;
+ permutation -= (permunreg[1]*24);
+ permunreg[2] = permutation/6;
+ permutation -= (permunreg[2]*6);
+ permunreg[3] = permutation/2;
+ permutation -= (permunreg[3]*2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation/60;
+ permutation -= (permunreg[0]*60);
+ permunreg[1] = permutation/12;
+ permutation -= (permunreg[1]*12);
+ permunreg[2] = permutation/3;
+ permutation -= (permunreg[2]*3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation/20;
+ permutation -= (permunreg[0]*20);
+ permunreg[1] = permutation/4;
+ permutation -= (permunreg[1]*4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation/5;
+ permutation -= (permunreg[0]*5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // renumber registers back to standard numbers
+ int registers[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (int i=0; i < regCount; ++i) {
+ int renum = 0;
+ for (int u=1; u < 7; ++u) {
+ if ( !used[u] ) {
+ if ( renum == permunreg[i] ) {
+ registers[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ bool needComma = false;
+ for (int i=0; i < regCount; ++i) {
+ if ( needComma )
+ strcat(str, ",");
+ else
+ needComma = true;
+ switch ( registers[i] ) {
+ case UNWIND_X86_REG_EBX:
+ strcat(str, "ebx");
+ break;
+ case UNWIND_X86_REG_ECX:
+ strcat(str, "ecx");
+ break;
+ case UNWIND_X86_REG_EDX:
+ strcat(str, "edx");
+ break;
+ case UNWIND_X86_REG_EDI:
+ strcat(str, "edi");
+ break;
+ case UNWIND_X86_REG_ESI:
+ strcat(str, "esi");
+ break;
+ case UNWIND_X86_REG_EBP:
+ strcat(str, "ebp");
+ break;
+ default:
+ strcat(str, "e??");
+ }
+ }
+ }
+ }
+ break;
+ case UNWIND_X86_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_DWARF_SECTION_OFFSET);
+ break;
+ default:
+ if ( encoding == 0 )
+ strcat(str, "no unwind information");
+ else
+ strcat(str, "tbd ");
+ }
+ if ( encoding & UNWIND_HAS_LSDA ) {
+ strcat(str, " LSDA");
+ }
+
+}
+
+#if SUPPORT_ARCH_arm64
+template <>
+void UnwindPrinter<arm64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ uint32_t stackSize;
+ switch ( encoding & UNWIND_ARM64_MODE_MASK ) {
+ case UNWIND_ARM64_MODE_FRAMELESS:
+ stackSize = EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+ if ( stackSize == 0 )
+ strcpy(str, "no frame, no saved registers ");
+ else
+ sprintf(str, "stack size=%d: ", 16 * stackSize);
+ if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+ strcat(str, "x19/20 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+ strcat(str, "x21/22 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+ strcat(str, "x23/24 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+ strcat(str, "x25/26 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+ strcat(str, "x27/28 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+ strcat(str, "d8/9 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+ strcat(str, "d10/11 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+ strcat(str, "d12/13 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+ strcat(str, "d14/15 ");
+ break;
+ break;
+ case UNWIND_ARM64_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ break;
+ case UNWIND_ARM64_MODE_FRAME:
+ strcpy(str, "std frame: ");
+ if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+ strcat(str, "x19/20 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+ strcat(str, "x21/22 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+ strcat(str, "x23/24 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+ strcat(str, "x25/26 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+ strcat(str, "x27/28 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+ strcat(str, "d8/9 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+ strcat(str, "d10/11 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+ strcat(str, "d12/13 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+ strcat(str, "d14/15 ");
+ break;
+ case UNWIND_ARM64_MODE_FRAME_OLD:
+ strcpy(str, "old frame: ");
+ if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD )
+ strcat(str, "x21/22 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD )
+ strcat(str, "x23/24 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD )
+ strcat(str, "x25/26 ");
+ if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD )
+ strcat(str, "x27/28 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD )
+ strcat(str, "d8/9 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD )
+ strcat(str, "d10/11 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD )
+ strcat(str, "d12/13 ");
+ if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD )
+ strcat(str, "d14/15 ");
+ break;
+ }
+}
+#endif
+
+template <>
+void UnwindPrinter<arm>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+ *str = '\0';
+ switch ( encoding & UNWIND_ARM_MODE_MASK ) {
+ case UNWIND_ARM_MODE_DWARF:
+ sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_ARM_DWARF_SECTION_OFFSET);
+ break;
+ case UNWIND_ARM_MODE_FRAME:
+ case UNWIND_ARM_MODE_FRAME_D:
+ switch ( encoding & UNWIND_ARM_FRAME_STACK_ADJUST_MASK ) {
+ case 0x00000000:
+ strcpy(str, "std frame: ");
+ break;
+ case 0x00400000:
+ strcat(str, "std frame(sp adj 4): ");
+ break;
+ case 0x00800000:
+ strcat(str, "std frame(sp adj 8): ");
+ break;
+ case 0x00C00000:
+ strcat(str, "std frame(sp adj 12): ");
+ break;
+ }
+ if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R4 )
+ strcat(str, "r4 ");
+ if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R5 )
+ strcat(str, "r5 ");
+ if ( encoding & UNWIND_ARM_FRAME_FIRST_PUSH_R6 )
+ strcat(str, "r6 ");
+
+ if ( encoding & 0x000000F8)
+ strcat(str, " / ");
+ if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R8 )
+ strcat(str, "r8 ");
+ if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R9 )
+ strcat(str, "r9 ");
+ if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R10 )
+ strcat(str, "r10 ");
+ if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R11 )
+ strcat(str, "r11 ");
+ if ( encoding & UNWIND_ARM_FRAME_SECOND_PUSH_R12 )
+ strcat(str, "r12 ");
+
+ if ( (encoding & UNWIND_ARM_MODE_MASK) == UNWIND_ARM_MODE_FRAME_D ) {
+ switch ( encoding & UNWIND_ARM_FRAME_D_REG_COUNT_MASK ) {
+ case 0x00000000:
+ strcat(str, " / d8 ");
+ break;
+ case 0x00000100:
+ strcat(str, " / d8,d10 ");
+ break;
+ case 0x00000200:
+ strcat(str, " / d8,d10,d12 ");
+ break;
+ case 0x00000300:
+ strcat(str, " / d8,d10,d12,d14 ");
+ break;
+ case 0x00000400:
+ strcat(str, " / d12,d14 / d8,d9,d10 ");
+ break;
+ case 0x00000500:
+ strcat(str, " / d14 / d8,d9,d10,d11,d12");
+ break;
+ case 0x00000600:
+ strcat(str, " / d8,d9,d10,d11,d12,d13,d14 ");
+ break;
+ case 0x00000700:
+ strcat(str, " / d8,d9,d10,d11,d12,d13,d14 ");
+ break;
+ default:
+ strcat(str, " / unknown D register usage ");
+ break;
+ }
+ }
+
+ break;
+ default:
+ if ( encoding == 0 )
+ strcpy(str, "no unwind information");
+ else
+ strcpy(str, "unsupported compact unwind");
+ break;
+ }
+}
+
+
+template <>
+const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+
+template <>
+const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+
+#if SUPPORT_ARCH_arm64
+template <>
+const char* UnwindPrinter<arm64>::personalityName(const macho_relocation_info<arm64::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+#endif
+
+template <>
+const char* UnwindPrinter<arm>::personalityName(const macho_relocation_info<arm::P>* reloc)
+{
+ //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+ //assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+ const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+ return &fStrings[sym.n_strx()];
+}
+
+template <typename A>
+bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
+{
+ const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)((uint8_t*)fHeader + fUnwindSection->reloff());
+ const macho_relocation_info<P>* relocsEnd = &relocs[fUnwindSection->nreloc()];
+ for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+ if ( reloc->r_extern() && (reloc->r_address() == sectionOffset) ) {
+ *personalityStr = this->personalityName(reloc);
+ if ( addr != NULL )
+ *addr = fSymbols[reloc->r_symbolnum()].n_value();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+template <typename A>
+void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
+{
+ printf("Arch: %s, Section: __LD,__compact_unwind (size=0x%08llX, => %lld entries)\n",
+ archName(), fUnwindSection->size(), fUnwindSection->size() / sizeof(macho_compact_unwind_entry<P>));
+
+ const macho_compact_unwind_entry<P>* const entriesStart = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset());
+ const macho_compact_unwind_entry<P>* const entriesEnd = (macho_compact_unwind_entry<P>*)((uint8_t*)fHeader + fUnwindSection->offset() + fUnwindSection->size());
+ for (const macho_compact_unwind_entry<P>* entry=entriesStart; entry < entriesEnd; ++entry) {
+ uint64_t entryAddress = ((char*)entry - (char*)entriesStart) + fUnwindSection->addr();
+ printf("0x%08llX:\n", entryAddress);
+ const char* functionNameStr;
+ pint_t funcAddress;
+ uint32_t offsetInFunction;
+ if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::codeStartFieldOffset(), &functionNameStr, &funcAddress) ) {
+ offsetInFunction = entry->codeStart();
+ }
+ else {
+ functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
+ funcAddress = entry->codeStart();
+ }
+ if ( offsetInFunction == 0 )
+ printf(" start: 0x%08llX %s\n", (uint64_t)funcAddress, functionNameStr);
+ else
+ printf(" start: 0x%08llX %s+0x%X\n", (uint64_t)funcAddress+offsetInFunction, functionNameStr, offsetInFunction);
+
+ printf(" end: 0x%08llX (len=0x%08X)\n", (uint64_t)(funcAddress+offsetInFunction+entry->codeLen()), entry->codeLen());
+
+ char encodingString[200];
+ this->decode(entry->compactUnwindInfo(), ((const uint8_t*)fHeader), encodingString);
+ printf(" unwind info: 0x%08X %s\n", entry->compactUnwindInfo(), encodingString);
+
+ const char* personalityNameStr;
+ if ( hasExernReloc(((char*)entry-(char*)entriesStart)+macho_compact_unwind_entry<P>::personalityFieldOffset(), &personalityNameStr) ) {
+ printf(" personality: %s\n", personalityNameStr);
+ }
+ else {
+ printf(" personality:\n");
+ }
+ if ( entry->lsda() == 0 ) {
+ printf(" lsda:\n");
+ }
+ else {
+ uint32_t lsdaOffset;
+ const char* lsdaName = this->functionName(entry->lsda(), &lsdaOffset);
+ if ( lsdaOffset == 0 )
+ printf(" lsda: 0x%08llX %s\n", (uint64_t)entry->lsda(), lsdaName);
+ else
+ printf(" lsda: 0x%08llX %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
+ }
+ }
+}