Author: jmolenda Date: Tue May 24 23:20:28 2016 New Revision: 270658 URL: http://llvm.org/viewvc/llvm-project?rev=270658&view=rev Log: Add support for arm64 compact unwind tables, used on darwin arm64 systems (ios, tvos, watchos). It's a simple format to use now that I have i386/x86_64 supported already.
The unwind instructions are only valid at call sites -- that is, when lldb is unwinding a frame in the middle of the stack. It cannot be used for the currently executing frame; it has no information about prologues/epilogues/etc. <rdar://problem/12062336> Modified: lldb/trunk/include/lldb/Symbol/CompactUnwindInfo.h lldb/trunk/source/Symbol/CompactUnwindInfo.cpp lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c Modified: lldb/trunk/include/lldb/Symbol/CompactUnwindInfo.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/CompactUnwindInfo.h?rev=270658&r1=270657&r2=270658&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/CompactUnwindInfo.h (original) +++ lldb/trunk/include/lldb/Symbol/CompactUnwindInfo.h Tue May 24 23:20:28 2016 @@ -133,6 +133,9 @@ private: bool CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start); + bool + CreateUnwindPlan_arm64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start); + ObjectFile &m_objfile; lldb::SectionSP m_section_sp; lldb::DataBufferSP m_section_contents_if_encrypted; // if the binary is encrypted, read the sect contents Modified: lldb/trunk/source/Symbol/CompactUnwindInfo.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/CompactUnwindInfo.cpp?rev=270658&r1=270657&r2=270658&view=diff ============================================================================== --- lldb/trunk/source/Symbol/CompactUnwindInfo.cpp (original) +++ lldb/trunk/source/Symbol/CompactUnwindInfo.cpp Tue May 24 23:20:28 2016 @@ -101,6 +101,27 @@ namespace lldb_private { UNWIND_X86_64_REG_R15 = 5, UNWIND_X86_64_REG_RBP = 6, }; + + FLAGS_ANONYMOUS_ENUM() + { + UNWIND_ARM64_MODE_MASK = 0x0F000000, + UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, + UNWIND_ARM64_MODE_DWARF = 0x03000000, + UNWIND_ARM64_MODE_FRAME = 0x04000000, + + UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, + UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, + UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, + UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, + UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, + UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, + UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, + UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, + UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, + + UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, + UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, + }; } @@ -195,6 +216,10 @@ CompactUnwindInfo::GetUnwindPlan (Target { return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr); } + if (arch.GetTriple().getArch() == llvm::Triple::aarch64) + { + return CreateUnwindPlan_arm64 (target, function_info, unwind_plan, addr); + } if (arch.GetTriple().getArch() == llvm::Triple::x86) { return CreateUnwindPlan_i386 (target, function_info, unwind_plan, addr); @@ -1229,3 +1254,166 @@ CompactUnwindInfo::CreateUnwindPlan_i386 } return false; } + + + +// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)" doc by ARM + +enum arm64_eh_regnum { + x19 = 19, + x20 = 20, + x21 = 21, + x22 = 22, + x23 = 23, + x24 = 24, + x25 = 25, + x26 = 26, + x27 = 27, + x28 = 28, + + fp = 29, + ra = 30, + sp = 31, + pc = 32, + + // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s for the 64-bit + // fp regs. Normally in DWARF it's context sensitive - so it knows it is fetching a + // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder is operating + // at a lower level and we'd try to fetch 128 bits if we were told that v8 were stored on + // the stack... + v8 = 72, + v9 = 73, + v10 = 74, + v11 = 75, + v12 = 76, + v13 = 77, + v14 = 78, + v15 = 79, +}; + +bool +CompactUnwindInfo::CreateUnwindPlan_arm64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) +{ + unwind_plan.SetSourceName ("compact unwind info"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + unwind_plan.SetRegisterKind (eRegisterKindEHFrame); + + unwind_plan.SetLSDAAddress (function_info.lsda_address); + unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); + + UnwindPlan::RowSP row (new UnwindPlan::Row); + + const int wordsize = 8; + int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK; + + if (mode == UNWIND_ARM64_MODE_DWARF) + return false; + + if (mode == UNWIND_ARM64_MODE_FRAMELESS) + { + row->SetOffset (0); + + uint32_t stack_size = (EXTRACT_BITS (function_info.encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) * 16; + + // Our previous Call Frame Address is the stack pointer plus the stack size + row->GetCFAValue().SetIsRegisterPlusOffset (arm64_eh_regnum::sp, stack_size); + + // Our previous PC is in the LR + row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra, true); + + unwind_plan.AppendRow (row); + return true; + } + + // Should not be possible + if (mode != UNWIND_ARM64_MODE_FRAME) + return false; + + + // mode == UNWIND_ARM64_MODE_FRAME + + row->GetCFAValue().SetIsRegisterPlusOffset (arm64_eh_regnum::fp , 2 * wordsize); + row->SetOffset (0); + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::fp, wordsize * -2, true); + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::pc, wordsize * -1, true); + row->SetRegisterLocationToIsCFAPlusOffset (arm64_eh_regnum::sp, 0, true); + + int reg_pairs_saved_count = 1; + + uint32_t saved_register_bits = function_info.encoding & 0xfff; + + if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x19, cfa_offset, true); + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x20, cfa_offset, true); + reg_pairs_saved_count++; + } + + if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x21, cfa_offset, true); + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x22, cfa_offset, true); + reg_pairs_saved_count++; + } + + if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x23, cfa_offset, true); + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x24, cfa_offset, true); + reg_pairs_saved_count++; + } + + if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x25, cfa_offset, true); + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x26, cfa_offset, true); + reg_pairs_saved_count++; + } + + if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x27, cfa_offset, true); + cfa_offset -= wordsize; + row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x28, cfa_offset, true); + reg_pairs_saved_count++; + } + + // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits off the stack; + // not sure if we have a good way to represent the 64-bitness of these saves. + + if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) + { + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) + { + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) + { + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) + { + reg_pairs_saved_count++; + } + + unwind_plan.AppendRow (row); + return true; +} + Modified: lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c?rev=270658&r1=270657&r2=270658&view=diff ============================================================================== --- lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c (original) +++ lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c Tue May 24 23:20:28 2016 @@ -14,6 +14,28 @@ #include <stdio.h> #include <mach-o/nlist.h> + +enum { + UNWIND_ARM64_MODE_MASK = 0x0F000000, + UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, + UNWIND_ARM64_MODE_DWARF = 0x03000000, + UNWIND_ARM64_MODE_FRAME = 0x04000000, + + UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, + UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, + UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, + UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, + UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, + UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, + UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, + UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, + UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, + + UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, + UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; + + #define EXTRACT_BITS(value, mask) \ ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) ) @@ -901,6 +923,129 @@ print_encoding_i386 (struct baton baton, } } +void +print_encoding_arm64 (struct baton baton, uint8_t *function_start, uint32_t encoding) +{ + const int wordsize = 8; + int mode = encoding & UNWIND_ARM64_MODE_MASK; + switch (mode) + { + case UNWIND_ARM64_MODE_FRAME: + { + printf ("frame func: CFA is fp+%d ", 16); + printf (" pc=[CFA-8] fp=[CFA-16]"); + int reg_pairs_saved_count = 1; + uint32_t saved_register_bits = encoding & 0xfff; + if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" x19=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" x20=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" x21=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" x22=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" x23=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" x24=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" x25=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" x26=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" x27=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" x28=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" d8=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" d9=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" d10=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" d11=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" d12=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" d13=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) + { + int cfa_offset = reg_pairs_saved_count * -2 * wordsize; + cfa_offset -= wordsize; + printf (" d14=[CFA%d]", cfa_offset); + cfa_offset -= wordsize; + printf (" d15=[CFA%d]", cfa_offset); + reg_pairs_saved_count++; + } + + } + break; + + case UNWIND_ARM64_MODE_FRAMELESS: + { + uint32_t stack_size = encoding & UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK; + printf ("frameless function: stack size %d ", stack_size * 16); + + } + break; + + case UNWIND_ARM64_MODE_DWARF: + { + uint32_t dwarf_offset = encoding & UNWIND_ARM64_DWARF_SECTION_OFFSET; + printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")", + dwarf_offset, dwarf_offset + baton.eh_section_file_address); + } + break; + + case 0: + { + printf (" no unwind information"); + } + break; + } +} + + void print_encoding (struct baton baton, uint8_t *function_start, uint32_t encoding) { @@ -913,6 +1058,10 @@ void print_encoding (struct baton baton, { print_encoding_i386 (baton, function_start, encoding); } + else if (baton.cputype == CPU_TYPE_ARM64) + { + print_encoding_arm64 (baton, function_start, encoding); + } else { printf (" -- unsupported encoding arch -- "); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits