[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 (§, 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