[Lldb-commits] [lldb] r222910 - Add support for UNWIND_X86_64_MODE_STACK_IND entries.

Jason Molenda jmolenda at apple.com
Thu Nov 27 19:54:13 PST 2014


Author: jmolenda
Date: Thu Nov 27 21:54:13 2014
New Revision: 222910

URL: http://llvm.org/viewvc/llvm-project?rev=222910&view=rev
Log:
Add support for UNWIND_X86_64_MODE_STACK_IND entries.
Correct the function offset computations in UNWIND_SECOND_LEVEL_REGULAR
tables.  A few other small fixes.


Modified:
    lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c

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=222910&r1=222909&r2=222910&view=diff
==============================================================================
--- lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c (original)
+++ lldb/trunk/tools/compact-unwind/compact-unwind-dumper.c Thu Nov 27 21:54:13 2014
@@ -13,6 +13,9 @@
 #include <inttypes.h>
 #include <stdio.h>
 
+#define EXTRACT_BITS(value, mask) \
+        ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
+
 
 // A quick sketch of a program which can parse the compact unwind info
 // used on Darwin systems for exception handling.  The output of
@@ -30,7 +33,12 @@ struct baton
     int addr_size;                   // 4 or 8 bytes, the size of addresses in this file
 
     uint64_t text_segment_vmaddr;    // __TEXT segment vmaddr
+    uint64_t text_segment_file_offset;
+
     uint64_t text_section_vmaddr;    // __TEXT,__text section vmaddr
+    uint64_t text_section_file_offset;
+
+    uint8_t *text_section_start;     // pointer into this program's address space
 
     uint64_t eh_section_file_address; // the file address of the __TEXT,__eh_frame section
 
@@ -123,6 +131,7 @@ scan_macho_load_commands (struct baton *
              && nsects != 0 && segment_name[0] != '\0' && strcmp (segment_name, "__TEXT") == 0)
         {
             baton->text_segment_vmaddr = segment_vmaddr;
+            baton->text_segment_file_offset = segment_offset;
 
             uint32_t current_sect = 0;
             while (current_sect < nsects && (offset - start_of_this_load_cmd) < *lc_cmdsize)
@@ -167,6 +176,7 @@ scan_macho_load_commands (struct baton *
                         struct section_64 sect;
                         memcpy (&sect, offset, sizeof (struct section_64));
                         baton->text_section_vmaddr = sect.addr;
+                        baton->text_section_file_offset = sect.offset;
                     }
                     else
                     {
@@ -195,7 +205,7 @@ scan_macho_load_commands (struct baton *
 }
 
 void
-print_encoding_x86_64 (struct baton baton, uint32_t encoding)
+print_encoding_x86_64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
 {
     int mode = encoding & UNWIND_X86_64_MODE_MASK;
     switch (mode)
@@ -204,9 +214,9 @@ print_encoding_x86_64 (struct baton bato
         {
             printf (" - frame func: CFA is rbp+%d ", 16);
             printf (" rip=[CFA-8] rbp=[CFA-16]");
-            uint32_t saved_registers_offset = (encoding & UNWIND_X86_64_RBP_FRAME_OFFSET) >> (__builtin_ctz (UNWIND_X86_64_RBP_FRAME_OFFSET));
+            uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
 
-            uint32_t saved_registers_locations = (encoding & UNWIND_X86_64_RBP_FRAME_REGISTERS) >> (__builtin_ctz (UNWIND_X86_64_RBP_FRAME_REGISTERS));
+            uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
 
 
             saved_registers_offset += 2;
@@ -240,26 +250,25 @@ print_encoding_x86_64 (struct baton bato
         break;
 
         case UNWIND_X86_64_MODE_STACK_IND:
-        {
-            printf (" UNWIND_X86_64_MODE_STACK_IND not yet supported\n");
-            break;
-        }
         case UNWIND_X86_64_MODE_STACK_IMMD:
         {
-            uint32_t stack_size = (encoding & UNWIND_X86_64_FRAMELESS_STACK_SIZE) >> (__builtin_ctz (UNWIND_X86_64_FRAMELESS_STACK_SIZE));
-            uint32_t stack_adjust = (encoding & UNWIND_X86_64_FRAMELESS_STACK_ADJUST) >> (__builtin_ctz (UNWIND_X86_64_FRAMELESS_STACK_ADJUST));
-            uint32_t register_count = (encoding & UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT) >> (__builtin_ctz (UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT));
-            uint32_t permutation = (encoding & UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION) >> (__builtin_ctz (UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION));
-            
-            printf (" frameless function: stack size %d, stack adjust %d, register count %d ", stack_size * 8, stack_adjust * 8, register_count);
-            if ((encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND)
+            uint32_t stack_size = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+            uint32_t register_count = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+            uint32_t permutation = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+
+            if (mode == UNWIND_X86_64_MODE_STACK_IND && function_start)
             {
-                printf (" UNWIND_X86_64_MODE_STACK_IND not handled ");
-                // stack size is too large to store in UNWIND_X86_64_FRAMELESS_STACK_SIZE; instead 
-                // stack_size is an offset into the function's instruction stream to the 32-bit literal
-                // value in a "sub $xxx, %rsp" instruction.
-                return;
+                uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+
+                // offset into the function instructions; 0 == beginning of first instruction
+                uint32_t offset_to_subl_insn = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+
+                stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
+
+                stack_size += stack_adjust * 8;
             }
+            
+            printf (" frameless function: stack size %d, register count %d ", stack_size * 8, register_count);
 
             if (register_count == 0)
             {
@@ -267,23 +276,31 @@ print_encoding_x86_64 (struct baton bato
             }
             else
             {
+
+                // We need to include (up to) 6 registers in 10 bits.
+                // That would be 18 bits if we just used 3 bits per reg to indicate
+                // the order they're saved on the stack. 
+                //
+                // This is done with Lehmer code permutation, e.g. see
+                // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
                 int permunreg[6];
 
-                // Decode the variable base number that's used to encode
-                // the Lehmer code for this permutation.
-                // v. http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
+                // This decodes the variable-base number in the 10 bits
+                // and gives us the Lehmer code sequence which can then
+                // be decoded.
+
                 switch (register_count) 
                 {
                     case 6:
-                        permunreg[0] = permutation/120;
+                        permunreg[0] = permutation/120;    // 120 == 5!
                         permutation -= (permunreg[0]*120);
-                        permunreg[1] = permutation/24;
+                        permunreg[1] = permutation/24;     // 24 == 4!
                         permutation -= (permunreg[1]*24);
-                        permunreg[2] = permutation/6;
+                        permunreg[2] = permutation/6;      // 6 == 3!
                         permutation -= (permunreg[2]*6);
-                        permunreg[3] = permutation/2;
+                        permunreg[3] = permutation/2;      // 2 == 2!
                         permutation -= (permunreg[3]*2);
-                        permunreg[4] = permutation;
+                        permunreg[4] = permutation;        // 1 == 1!
                         permunreg[5] = 0;
                         break;
                     case 5:
@@ -402,12 +419,12 @@ print_encoding_x86_64 (struct baton bato
     }
 }
 
-void print_encoding (struct baton baton, uint32_t encoding)
+void print_encoding (struct baton baton, uint8_t *function_start, uint32_t encoding)
 {
 
     if (baton.cputype == CPU_TYPE_X86_64)
     {
-        print_encoding_x86_64 (baton, encoding);
+        print_encoding_x86_64 (baton, function_start, encoding);
     }
     else
     {
@@ -430,14 +447,11 @@ print_function_encoding (struct baton ba
     }
     printf ("    func [%d] offset %d (file addr 0x%" PRIx64 ")%s - 0x%x", 
             idx, entry_func_offset, 
-            entry_func_offset + baton.text_segment_vmaddr,  // FIXME
-#if 0
-            entry_func_offset + baton.first_level_index_entry.functionOffset + baton.text_segment_vmaddr,  // FIXME
-#endif
+            baton.first_level_index_entry.functionOffset + entry_func_offset + baton.text_segment_vmaddr,  // FIXME
             entry_encoding_index_str, 
             encoding);
 
-    print_encoding (baton, encoding);
+    print_encoding (baton, baton.mach_header_start + baton.first_level_index_entry.functionOffset + baton.text_section_file_offset + entry_func_offset, encoding);
 
     bool has_lsda = encoding & UNWIND_HAS_LSDA;
 
@@ -475,7 +489,7 @@ print_function_encoding (struct baton ba
         printf (", LSDA offset %d", lsda_offset);
     }
 
-    uint32_t pers_idx = (encoding & UNWIND_PERSONALITY_MASK) >> (__builtin_ctz(UNWIND_PERSONALITY_MASK));
+    uint32_t pers_idx = EXTRACT_BITS (encoding, UNWIND_PERSONALITY_MASK);
     if (pers_idx != 0)
     {
         pers_idx--;  // Change 1-based to 0-based index
@@ -503,7 +517,14 @@ print_second_level_index_regular (struct
     {
         uint32_t func_offset = *((uint32_t *) (offset));
         uint32_t encoding = *((uint32_t *) (offset + 4)); 
-        print_function_encoding (baton, idx, encoding, (uint32_t) -1, func_offset);
+
+        // UNWIND_SECOND_LEVEL_REGULAR entries have a funcOffset which includes the 
+        // functionOffset from the containing index table already.  UNWIND_SECOND_LEVEL_COMPRESSED
+        // entries only have the offset from the containing index table functionOffset.
+        // So strip off the contianing index table functionOffset value here so they can
+        // be treated the same at the lower layers.
+
+        print_function_encoding (baton, idx, encoding, (uint32_t) -1, func_offset - baton.first_level_index_entry.functionOffset);
         idx++;
         offset += 8;
     }
@@ -667,7 +688,7 @@ int main (int argc, char **argv)
     {
         uint32_t encoding = *((uint32_t*) common_encodings);
         printf ("    Common Encoding [%d]: 0x%x", encoding_idx, encoding);
-        print_encoding (baton, encoding);
+        print_encoding (baton, NULL, encoding);
         printf ("\n");
         common_encodings += sizeof (uint32_t);
         encoding_idx++;





More information about the lldb-commits mailing list