[Lldb-commits] [lldb] r270658 - Add support for arm64 compact unwind tables, used on darwin arm64

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Tue May 24 21:20:28 PDT 2016


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 -- ");




More information about the lldb-commits mailing list