summaryrefslogtreecommitdiffstats
path: root/lldb/tools/compact-unwind/compact-unwind-dumper.c
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/tools/compact-unwind/compact-unwind-dumper.c')
-rw-r--r--lldb/tools/compact-unwind/compact-unwind-dumper.c2814
1 files changed, 1364 insertions, 1450 deletions
diff --git a/lldb/tools/compact-unwind/compact-unwind-dumper.c b/lldb/tools/compact-unwind/compact-unwind-dumper.c
index f70f602326b..570c42981a2 100644
--- a/lldb/tools/compact-unwind/compact-unwind-dumper.c
+++ b/lldb/tools/compact-unwind/compact-unwind-dumper.c
@@ -1,66 +1,64 @@
-#include <stdint.h>
-#include <mach-o/loader.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <mach-o/compact_unwind_encoding.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
#include <mach/machine.h>
-#include <stdlib.h>
#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
#include <sys/errno.h>
+#include <sys/mman.h>
#include <sys/stat.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <mach-o/nlist.h>
-
+#include <sys/types.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,
+ 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,
};
enum {
- UNWIND_ARM_MODE_MASK = 0x0F000000,
- UNWIND_ARM_MODE_FRAME = 0x01000000,
- UNWIND_ARM_MODE_FRAME_D = 0x02000000,
- UNWIND_ARM_MODE_DWARF = 0x04000000,
+ UNWIND_ARM_MODE_MASK = 0x0F000000,
+ UNWIND_ARM_MODE_FRAME = 0x01000000,
+ UNWIND_ARM_MODE_FRAME_D = 0x02000000,
+ UNWIND_ARM_MODE_DWARF = 0x04000000,
- UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
+ UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
- UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
- UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
- UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
+ UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
+ UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
+ UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
- UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
- UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
- UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
- UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
- UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
+ UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
+ UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
+ UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
+ UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
+ UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
- UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
+ UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
- UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+ UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
};
-#define EXTRACT_BITS(value, mask) \
- ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) )
-
+#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
@@ -68,1534 +66,1450 @@ enum {
// can dump at least the UNWIND_X86_64_MODE_RBP_FRAME format entries
// correctly.
-struct symbol
-{
- uint64_t file_address;
- const char *name;
+struct symbol {
+ uint64_t file_address;
+ const char *name;
};
-int
-symbol_compare (const void *a, const void *b)
-{
- return (int) ((struct symbol *)a)->file_address - ((struct symbol *)b)->file_address;
+int symbol_compare(const void *a, const void *b) {
+ return (int)((struct symbol *)a)->file_address -
+ ((struct symbol *)b)->file_address;
}
-struct baton
-{
- cpu_type_t cputype;
+struct baton {
+ cpu_type_t cputype;
- uint8_t *mach_header_start; // pointer into this program's address space
- uint8_t *compact_unwind_start; // pointer into this program's address space
+ uint8_t *mach_header_start; // pointer into this program's address space
+ uint8_t *compact_unwind_start; // pointer into this program's address space
- int addr_size; // 4 or 8 bytes, the size of addresses in this file
+ 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_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;
+ uint64_t text_section_vmaddr; // __TEXT,__text section vmaddr
+ uint64_t text_section_file_offset;
- uint64_t eh_section_file_address; // the file address of the __TEXT,__eh_frame section
+ uint64_t eh_section_file_address; // the file address of the __TEXT,__eh_frame
+ // section
- uint8_t *lsda_array_start; // for the currently-being-processed first-level index
- uint8_t *lsda_array_end; // the lsda_array_start for the NEXT first-level index
+ uint8_t
+ *lsda_array_start; // for the currently-being-processed first-level index
+ uint8_t
+ *lsda_array_end; // the lsda_array_start for the NEXT first-level index
- struct symbol *symbols;
- int symbols_count;
+ struct symbol *symbols;
+ int symbols_count;
- uint64_t *function_start_addresses;
- int function_start_addresses_count;
+ uint64_t *function_start_addresses;
+ int function_start_addresses_count;
- int current_index_table_number;
+ int current_index_table_number;
- struct unwind_info_section_header unwind_header;
- struct unwind_info_section_header_index_entry first_level_index_entry;
- struct unwind_info_compressed_second_level_page_header compressed_second_level_page_header;
- struct unwind_info_regular_second_level_page_header regular_second_level_page_header;
+ struct unwind_info_section_header unwind_header;
+ struct unwind_info_section_header_index_entry first_level_index_entry;
+ struct unwind_info_compressed_second_level_page_header
+ compressed_second_level_page_header;
+ struct unwind_info_regular_second_level_page_header
+ regular_second_level_page_header;
};
-
-uint64_t
-read_leb128 (uint8_t **offset)
-{
- uint64_t result = 0;
- int shift = 0;
- while (1)
- {
- uint8_t byte = **offset;
- *offset = *offset + 1;
- result |= (byte & 0x7f) << shift;
- if ((byte & 0x80) == 0)
- break;
- shift += 7;
- }
-
- return result;
+uint64_t read_leb128(uint8_t **offset) {
+ uint64_t result = 0;
+ int shift = 0;
+ while (1) {
+ uint8_t byte = **offset;
+ *offset = *offset + 1;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+
+ return result;
}
// step through the load commands in a thin mach-o binary,
// find the cputype and the start of the __TEXT,__unwind_info
// section, return a pointer to that section or NULL if not found.
-static void
-scan_macho_load_commands (struct baton *baton)
-{
- struct symtab_command symtab_cmd;
- uint64_t linkedit_segment_vmaddr;
- uint64_t linkedit_segment_file_offset;
-
- baton->compact_unwind_start = 0;
-
- uint32_t *magic = (uint32_t *) baton->mach_header_start;
-
- if (*magic != MH_MAGIC && *magic != MH_MAGIC_64)
- {
- printf ("Unexpected magic number 0x%x in header, exiting.", *magic);
- exit (1);
- }
-
- bool is_64bit = false;
- if (*magic == MH_MAGIC_64)
- is_64bit = true;
-
- uint8_t *offset = baton->mach_header_start;
-
- struct mach_header mh;
- memcpy (&mh, offset, sizeof (struct mach_header));
- if (is_64bit)
- offset += sizeof (struct mach_header_64);
- else
- offset += sizeof (struct mach_header);
-
- if (is_64bit)
- baton->addr_size = 8;
- else
- baton->addr_size = 4;
-
- baton->cputype = mh.cputype;
-
- uint8_t *start_of_load_commands = offset;
-
- uint32_t cur_cmd = 0;
- while (cur_cmd < mh.ncmds && (offset - start_of_load_commands) < mh.sizeofcmds)
- {
- struct load_command lc;
- uint32_t *lc_cmd = (uint32_t *) offset;
- uint32_t *lc_cmdsize = (uint32_t *) offset + 1;
- uint8_t *start_of_this_load_cmd = offset;
-
- if (*lc_cmd == LC_SEGMENT || *lc_cmd == LC_SEGMENT_64)
- {
- char segment_name[17];
- segment_name[0] = '\0';
- uint32_t nsects = 0;
- uint64_t segment_offset = 0;
- uint64_t segment_vmaddr = 0;
-
- if (*lc_cmd == LC_SEGMENT_64)
- {
- struct segment_command_64 seg;
- memcpy (&seg, offset, sizeof (struct segment_command_64));
- memcpy (&segment_name, &seg.segname, 16);
- segment_name[16] = '\0';
- nsects = seg.nsects;
- segment_offset = seg.fileoff;
- segment_vmaddr = seg.vmaddr;
- offset += sizeof (struct segment_command_64);
- if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1)
- {
- printf ("Segment '%s' is encrypted.\n", segment_name);
- }
+static void scan_macho_load_commands(struct baton *baton) {
+ struct symtab_command symtab_cmd;
+ uint64_t linkedit_segment_vmaddr;
+ uint64_t linkedit_segment_file_offset;
+
+ baton->compact_unwind_start = 0;
+
+ uint32_t *magic = (uint32_t *)baton->mach_header_start;
+
+ if (*magic != MH_MAGIC && *magic != MH_MAGIC_64) {
+ printf("Unexpected magic number 0x%x in header, exiting.", *magic);
+ exit(1);
+ }
+
+ bool is_64bit = false;
+ if (*magic == MH_MAGIC_64)
+ is_64bit = true;
+
+ uint8_t *offset = baton->mach_header_start;
+
+ struct mach_header mh;
+ memcpy(&mh, offset, sizeof(struct mach_header));
+ if (is_64bit)
+ offset += sizeof(struct mach_header_64);
+ else
+ offset += sizeof(struct mach_header);
+
+ if (is_64bit)
+ baton->addr_size = 8;
+ else
+ baton->addr_size = 4;
+
+ baton->cputype = mh.cputype;
+
+ uint8_t *start_of_load_commands = offset;
+
+ uint32_t cur_cmd = 0;
+ while (cur_cmd < mh.ncmds &&
+ (offset - start_of_load_commands) < mh.sizeofcmds) {
+ struct load_command lc;
+ uint32_t *lc_cmd = (uint32_t *)offset;
+ uint32_t *lc_cmdsize = (uint32_t *)offset + 1;
+ uint8_t *start_of_this_load_cmd = offset;
+
+ if (*lc_cmd == LC_SEGMENT || *lc_cmd == LC_SEGMENT_64) {
+ char segment_name[17];
+ segment_name[0] = '\0';
+ uint32_t nsects = 0;
+ uint64_t segment_offset = 0;
+ uint64_t segment_vmaddr = 0;
+
+ if (*lc_cmd == LC_SEGMENT_64) {
+ struct segment_command_64 seg;
+ memcpy(&seg, offset, sizeof(struct segment_command_64));
+ memcpy(&segment_name, &seg.segname, 16);
+ segment_name[16] = '\0';
+ nsects = seg.nsects;
+ segment_offset = seg.fileoff;
+ segment_vmaddr = seg.vmaddr;
+ offset += sizeof(struct segment_command_64);
+ if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1) {
+ printf("Segment '%s' is encrypted.\n", segment_name);
+ }
+ }
+
+ if (*lc_cmd == LC_SEGMENT) {
+ struct segment_command seg;
+ memcpy(&seg, offset, sizeof(struct segment_command));
+ memcpy(&segment_name, &seg.segname, 16);
+ segment_name[16] = '\0';
+ nsects = seg.nsects;
+ segment_offset = seg.fileoff;
+ segment_vmaddr = seg.vmaddr;
+ offset += sizeof(struct segment_command);
+ if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1) {
+ printf("Segment '%s' is encrypted.\n", segment_name);
+ }
+ }
+
+ if (nsects != 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) {
+ char sect_name[17];
+ memcpy(&sect_name, offset, 16);
+ sect_name[16] = '\0';
+ if (strcmp(sect_name, "__unwind_info") == 0) {
+ if (is_64bit) {
+ struct section_64 sect;
+ memset(&sect, 0, sizeof(struct section_64));
+ memcpy(&sect, offset, sizeof(struct section_64));
+ baton->compact_unwind_start =
+ baton->mach_header_start + sect.offset;
+ } else {
+ struct section sect;
+ memset(&sect, 0, sizeof(struct section));
+ memcpy(&sect, offset, sizeof(struct section));
+ baton->compact_unwind_start =
+ baton->mach_header_start + sect.offset;
}
-
- if (*lc_cmd == LC_SEGMENT)
- {
- struct segment_command seg;
- memcpy (&seg, offset, sizeof (struct segment_command));
- memcpy (&segment_name, &seg.segname, 16);
- segment_name[16] = '\0';
- nsects = seg.nsects;
- segment_offset = seg.fileoff;
- segment_vmaddr = seg.vmaddr;
- offset += sizeof (struct segment_command);
- if ((seg.flags & SG_PROTECTED_VERSION_1) == SG_PROTECTED_VERSION_1)
- {
- printf ("Segment '%s' is encrypted.\n", segment_name);
- }
+ }
+ if (strcmp(sect_name, "__eh_frame") == 0) {
+ if (is_64bit) {
+ struct section_64 sect;
+ memset(&sect, 0, sizeof(struct section_64));
+ memcpy(&sect, offset, sizeof(struct section_64));
+ baton->eh_section_file_address = sect.addr;
+ } else {
+ struct section sect;
+ memset(&sect, 0, sizeof(struct section));
+ memcpy(&sect, offset, sizeof(struct section));
+ baton->eh_section_file_address = sect.addr;
}
-
- if (nsects != 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)
- {
- char sect_name[17];
- memcpy (&sect_name, offset, 16);
- sect_name[16] = '\0';
- if (strcmp (sect_name, "__unwind_info") == 0)
- {
- if (is_64bit)
- {
- struct section_64 sect;
- memset (&sect, 0, sizeof (struct section_64));
- memcpy (&sect, offset, sizeof (struct section_64));
- baton->compact_unwind_start = baton->mach_header_start + sect.offset;
- }
- else
- {
- struct section sect;
- memset (&sect, 0, sizeof (struct section));
- memcpy (&sect, offset, sizeof (struct section));
- baton->compact_unwind_start = baton->mach_header_start + sect.offset;
- }
- }
- if (strcmp (sect_name, "__eh_frame") == 0)
- {
- if (is_64bit)
- {
- struct section_64 sect;
- memset (&sect, 0, sizeof (struct section_64));
- memcpy (&sect, offset, sizeof (struct section_64));
- baton->eh_section_file_address = sect.addr;
- }
- else
- {
- struct section sect;
- memset (&sect, 0, sizeof (struct section));
- memcpy (&sect, offset, sizeof (struct section));
- baton->eh_section_file_address = sect.addr;
- }
- }
- if (strcmp (sect_name, "__text") == 0)
- {
- if (is_64bit)
- {
- struct section_64 sect;
- memset (&sect, 0, sizeof (struct section_64));
- memcpy (&sect, offset, sizeof (struct section_64));
- baton->text_section_vmaddr = sect.addr;
- baton->text_section_file_offset = sect.offset;
- }
- else
- {
- struct section sect;
- memset (&sect, 0, sizeof (struct section));
- memcpy (&sect, offset, sizeof (struct section));
- baton->text_section_vmaddr = sect.addr;
- }
- }
- if (is_64bit)
- {
- offset += sizeof (struct section_64);
- }
- else
- {
- offset += sizeof (struct section);
- }
- }
+ }
+ if (strcmp(sect_name, "__text") == 0) {
+ if (is_64bit) {
+ struct section_64 sect;
+ memset(&sect, 0, sizeof(struct section_64));
+ memcpy(&sect, offset, sizeof(struct section_64));
+ baton->text_section_vmaddr = sect.addr;
+ baton->text_section_file_offset = sect.offset;
+ } else {
+ struct section sect;
+ memset(&sect, 0, sizeof(struct section));
+ memcpy(&sect, offset, sizeof(struct section));
+ baton->text_section_vmaddr = sect.addr;
}
-
- if (strcmp (segment_name, "__LINKEDIT") == 0)
- {
- linkedit_segment_vmaddr = segment_vmaddr;
- linkedit_segment_file_offset = segment_offset;
- }
- }
-
- if (*lc_cmd == LC_SYMTAB)
- {
- memcpy (&symtab_cmd, offset, sizeof (struct symtab_command));
+ }
+ if (is_64bit) {
+ offset += sizeof(struct section_64);
+ } else {
+ offset += sizeof(struct section);
+ }
}
+ }
- if (*lc_cmd == LC_DYSYMTAB)
- {
- struct dysymtab_command dysymtab_cmd;
- memcpy (&dysymtab_cmd, offset, sizeof (struct dysymtab_command));
-
- int nlist_size = 12;
- if (is_64bit)
- nlist_size = 16;
-
- char *string_table = (char *) (baton->mach_header_start + symtab_cmd.stroff);
- uint8_t *local_syms = baton->mach_header_start + symtab_cmd.symoff + (dysymtab_cmd.ilocalsym * nlist_size);
- int local_syms_count = dysymtab_cmd.nlocalsym;
- uint8_t *exported_syms = baton->mach_header_start + symtab_cmd.symoff + (dysymtab_cmd.iextdefsym * nlist_size);
- int exported_syms_count = dysymtab_cmd.nextdefsym;
-
- // We're only going to create records for a small number of these symbols but to
- // simplify the memory management I'll allocate enough space to store all of them.
- baton->symbols = (struct symbol *) malloc (sizeof (struct symbol) * (local_syms_count + exported_syms_count));
- baton->symbols_count = 0;
-
- for (int i = 0; i < local_syms_count; i++)
- {
- struct nlist_64 nlist;
- memset (&nlist, 0, sizeof (struct nlist_64));
- if (is_64bit)
- {
- memcpy (&nlist, local_syms + (i * nlist_size), sizeof (struct nlist_64));
- }
- else
- {
- struct nlist nlist_32;
- memset (&nlist_32, 0, sizeof (struct nlist));
- memcpy (&nlist_32, local_syms + (i * nlist_size), sizeof (struct nlist));
- nlist.n_un.n_strx = nlist_32.n_un.n_strx;
- nlist.n_type = nlist_32.n_type;
- nlist.n_sect = nlist_32.n_sect;
- nlist.n_desc = nlist_32.n_desc;
- nlist.n_value = nlist_32.n_value;
- }
- if ((nlist.n_type & N_STAB) == 0
- && ((nlist.n_type & N_EXT) == 1 ||
- ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT))
- && nlist.n_value != 0
- && nlist.n_value != baton->text_segment_vmaddr)
- {
- baton->symbols[baton->symbols_count].file_address = nlist.n_value;
- if (baton->cputype == CPU_TYPE_ARM)
- baton->symbols[baton->symbols_count].file_address = baton->symbols[baton->symbols_count].file_address & ~1;
- baton->symbols[baton->symbols_count].name = string_table + nlist.n_un.n_strx;
- baton->symbols_count++;
- }
- }
+ if (strcmp(segment_name, "__LINKEDIT") == 0) {
+ linkedit_segment_vmaddr = segment_vmaddr;
+ linkedit_segment_file_offset = segment_offset;
+ }
+ }
- for (int i = 0; i < exported_syms_count; i++)
- {
- struct nlist_64 nlist;
- memset (&nlist, 0, sizeof (struct nlist_64));
- if (is_64bit)
- {
- memcpy (&nlist, exported_syms + (i * nlist_size), sizeof (struct nlist_64));
- }
- else
- {
- struct nlist nlist_32;
- memcpy (&nlist_32, exported_syms + (i * nlist_size), sizeof (struct nlist));
- nlist.n_un.n_strx = nlist_32.n_un.n_strx;
- nlist.n_type = nlist_32.n_type;
- nlist.n_sect = nlist_32.n_sect;
- nlist.n_desc = nlist_32.n_desc;
- nlist.n_value = nlist_32.n_value;
- }
- if ((nlist.n_type & N_STAB) == 0
- && ((nlist.n_type & N_EXT) == 1 ||
- ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT))
- && nlist.n_value != 0
- && nlist.n_value != baton->text_segment_vmaddr)
- {
- baton->symbols[baton->symbols_count].file_address = nlist.n_value;
- if (baton->cputype == CPU_TYPE_ARM)
- baton->symbols[baton->symbols_count].file_address = baton->symbols[baton->symbols_count].file_address & ~1;
- baton->symbols[baton->symbols_count].name = string_table + nlist.n_un.n_strx;
- baton->symbols_count++;
- }
- }
+ if (*lc_cmd == LC_SYMTAB) {
+ memcpy(&symtab_cmd, offset, sizeof(struct symtab_command));
+ }
- qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
+ if (*lc_cmd == LC_DYSYMTAB) {
+ struct dysymtab_command dysymtab_cmd;
+ memcpy(&dysymtab_cmd, offset, sizeof(struct dysymtab_command));
+
+ int nlist_size = 12;
+ if (is_64bit)
+ nlist_size = 16;
+
+ char *string_table =
+ (char *)(baton->mach_header_start + symtab_cmd.stroff);
+ uint8_t *local_syms = baton->mach_header_start + symtab_cmd.symoff +
+ (dysymtab_cmd.ilocalsym * nlist_size);
+ int local_syms_count = dysymtab_cmd.nlocalsym;
+ uint8_t *exported_syms = baton->mach_header_start + symtab_cmd.symoff +
+ (dysymtab_cmd.iextdefsym * nlist_size);
+ int exported_syms_count = dysymtab_cmd.nextdefsym;
+
+ // We're only going to create records for a small number of these symbols
+ // but to
+ // simplify the memory management I'll allocate enough space to store all
+ // of them.
+ baton->symbols = (struct symbol *)malloc(
+ sizeof(struct symbol) * (local_syms_count + exported_syms_count));
+ baton->symbols_count = 0;
+
+ for (int i = 0; i < local_syms_count; i++) {
+ struct nlist_64 nlist;
+ memset(&nlist, 0, sizeof(struct nlist_64));
+ if (is_64bit) {
+ memcpy(&nlist, local_syms + (i * nlist_size),
+ sizeof(struct nlist_64));
+ } else {
+ struct nlist nlist_32;
+ memset(&nlist_32, 0, sizeof(struct nlist));
+ memcpy(&nlist_32, local_syms + (i * nlist_size),
+ sizeof(struct nlist));
+ nlist.n_un.n_strx = nlist_32.n_un.n_strx;
+ nlist.n_type = nlist_32.n_type;
+ nlist.n_sect = nlist_32.n_sect;
+ nlist.n_desc = nlist_32.n_desc;
+ nlist.n_value = nlist_32.n_value;
}
-
- if (*lc_cmd == LC_FUNCTION_STARTS)
- {
- struct linkedit_data_command function_starts_cmd;
- memcpy (&function_starts_cmd, offset, sizeof (struct linkedit_data_command));
-
- uint8_t *funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
- uint8_t *function_end = funcstarts_offset + function_starts_cmd.datasize;
- int count = 0;
-
- while (funcstarts_offset < function_end)
- {
- if (read_leb128 (&funcstarts_offset) != 0)
- {
- count++;
- }
- }
-
- baton->function_start_addresses = (uint64_t *) malloc (sizeof (uint64_t) * count);
- baton->function_start_addresses_count = count;
-
- funcstarts_offset = baton->mach_header_start + function_starts_cmd.dataoff;
- uint64_t current_pc = baton->text_segment_vmaddr;
- int i = 0;
- while (funcstarts_offset < function_end)
- {
- uint64_t func_start = read_leb128 (&funcstarts_offset);
- if (func_start != 0)
- {
- current_pc += func_start;
- baton->function_start_addresses[i++] = current_pc;
- }
- }
+ if ((nlist.n_type & N_STAB) == 0 &&
+ ((nlist.n_type & N_EXT) == 1 ||
+ ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT)) &&
+ nlist.n_value != 0 && nlist.n_value != baton->text_segment_vmaddr) {
+ baton->symbols[baton->symbols_count].file_address = nlist.n_value;
+ if (baton->cputype == CPU_TYPE_ARM)
+ baton->symbols[baton->symbols_count].file_address =
+ baton->symbols[baton->symbols_count].file_address & ~1;
+ baton->symbols[baton->symbols_count].name =
+ string_table + nlist.n_un.n_strx;
+ baton->symbols_count++;
+ }
+ }
+
+ for (int i = 0; i < exported_syms_count; i++) {
+ struct nlist_64 nlist;
+ memset(&nlist, 0, sizeof(struct nlist_64));
+ if (is_64bit) {
+ memcpy(&nlist, exported_syms + (i * nlist_size),
+ sizeof(struct nlist_64));
+ } else {
+ struct nlist nlist_32;
+ memcpy(&nlist_32, exported_syms + (i * nlist_size),
+ sizeof(struct nlist));
+ nlist.n_un.n_strx = nlist_32.n_un.n_strx;
+ nlist.n_type = nlist_32.n_type;
+ nlist.n_sect = nlist_32.n_sect;
+ nlist.n_desc = nlist_32.n_desc;
+ nlist.n_value = nlist_32.n_value;
+ }
+ if ((nlist.n_type & N_STAB) == 0 &&
+ ((nlist.n_type & N_EXT) == 1 ||
+ ((nlist.n_type & N_TYPE) == N_TYPE && nlist.n_sect != NO_SECT)) &&
+ nlist.n_value != 0 && nlist.n_value != baton->text_segment_vmaddr) {
+ baton->symbols[baton->symbols_count].file_address = nlist.n_value;
+ if (baton->cputype == CPU_TYPE_ARM)
+ baton->symbols[baton->symbols_count].file_address =
+ baton->symbols[baton->symbols_count].file_address & ~1;
+ baton->symbols[baton->symbols_count].name =
+ string_table + nlist.n_un.n_strx;
+ baton->symbols_count++;
}
+ }
- offset = start_of_this_load_cmd + *lc_cmdsize;
- cur_cmd++;
+ qsort(baton->symbols, baton->symbols_count, sizeof(struct symbol),
+ symbol_compare);
}
+ if (*lc_cmd == LC_FUNCTION_STARTS) {
+ struct linkedit_data_command function_starts_cmd;
+ memcpy(&function_starts_cmd, offset,
+ sizeof(struct linkedit_data_command));
- // Augment the symbol table with the function starts table -- adding symbol entries
- // for functions that were stripped.
+ uint8_t *funcstarts_offset =
+ baton->mach_header_start + function_starts_cmd.dataoff;
+ uint8_t *function_end = funcstarts_offset + function_starts_cmd.datasize;
+ int count = 0;
- int unnamed_functions_to_add = 0;
- for (int i = 0; i < baton->function_start_addresses_count; i++)
- {
- struct symbol search_key;
- search_key.file_address = baton->function_start_addresses[i];
- if (baton->cputype == CPU_TYPE_ARM)
- search_key.file_address = search_key.file_address & ~1;
- struct symbol *sym = bsearch (&search_key, baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
- if (sym == NULL)
- unnamed_functions_to_add++;
- }
-
- baton->symbols = (struct symbol *) realloc (baton->symbols, sizeof (struct symbol) * (baton->symbols_count + unnamed_functions_to_add));
-
- int current_unnamed_symbol = 1;
- int number_symbols_added = 0;
- for (int i = 0; i < baton->function_start_addresses_count; i++)
- {
- struct symbol search_key;
- search_key.file_address = baton->function_start_addresses[i];
- if (baton->cputype == CPU_TYPE_ARM)
- search_key.file_address = search_key.file_address & ~1;
- struct symbol *sym = bsearch (&search_key, baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
- if (sym == NULL)
- {
- char *name;
- asprintf (&name, "unnamed function #%d", current_unnamed_symbol++);
- baton->symbols[baton->symbols_count + number_symbols_added].file_address = baton->function_start_addresses[i];
- baton->symbols[baton->symbols_count + number_symbols_added].name = name;
- number_symbols_added++;
+ while (funcstarts_offset < function_end) {
+ if (read_leb128(&funcstarts_offset) != 0) {
+ count++;
+ }
+ }
+
+ baton->function_start_addresses =
+ (uint64_t *)malloc(sizeof(uint64_t) * count);
+ baton->function_start_addresses_count = count;
+
+ funcstarts_offset =
+ baton->mach_header_start + function_starts_cmd.dataoff;
+ uint64_t current_pc = baton->text_segment_vmaddr;
+ int i = 0;
+ while (funcstarts_offset < function_end) {
+ uint64_t func_start = read_leb128(&funcstarts_offset);
+ if (func_start != 0) {
+ current_pc += func_start;
+ baton->function_start_addresses[i++] = current_pc;
}
+ }
}
- baton->symbols_count += number_symbols_added;
- qsort (baton->symbols, baton->symbols_count, sizeof (struct symbol), symbol_compare);
+ offset = start_of_this_load_cmd + *lc_cmdsize;
+ cur_cmd++;
+ }
+
+ // Augment the symbol table with the function starts table -- adding symbol
+ // entries
+ // for functions that were stripped.
+
+ int unnamed_functions_to_add = 0;
+ for (int i = 0; i < baton->function_start_addresses_count; i++) {
+ struct symbol search_key;
+ search_key.file_address = baton->function_start_addresses[i];
+ if (baton->cputype == CPU_TYPE_ARM)
+ search_key.file_address = search_key.file_address & ~1;
+ struct symbol *sym =
+ bsearch(&search_key, baton->symbols, baton->symbols_count,
+ sizeof(struct symbol), symbol_compare);
+ if (sym == NULL)
+ unnamed_functions_to_add++;
+ }
+
+ baton->symbols = (struct symbol *)realloc(
+ baton->symbols, sizeof(struct symbol) *
+ (baton->symbols_count + unnamed_functions_to_add));
+
+ int current_unnamed_symbol = 1;
+ int number_symbols_added = 0;
+ for (int i = 0; i < baton->function_start_addresses_count; i++) {
+ struct symbol search_key;
+ search_key.file_address = baton->function_start_addresses[i];
+ if (baton->cputype == CPU_TYPE_ARM)
+ search_key.file_address = search_key.file_address & ~1;
+ struct symbol *sym =
+ bsearch(&search_key, baton->symbols, baton->symbols_count,
+ sizeof(struct symbol), symbol_compare);
+ if (sym == NULL) {
+ char *name;
+ asprintf(&name, "unnamed function #%d", current_unnamed_symbol++);
+ baton->symbols[baton->symbols_count + number_symbols_added].file_address =
+ baton->function_start_addresses[i];
+ baton->symbols[baton->symbols_count + number_symbols_added].name = name;
+ number_symbols_added++;
+ }
+ }
+ baton->symbols_count += number_symbols_added;
+ qsort(baton->symbols, baton->symbols_count, sizeof(struct symbol),
+ symbol_compare);
+
+ // printf ("function start addresses\n");
+ // for (int i = 0; i < baton->function_start_addresses_count; i++)
+ // {
+ // printf ("0x%012llx\n", baton->function_start_addresses[i]);
+ // }
+
+ // printf ("symbol table names & addresses\n");
+ // for (int i = 0; i < baton->symbols_count; i++)
+ // {
+ // printf ("0x%012llx %s\n", baton->symbols[i].file_address,
+ // baton->symbols[i].name);
+ // }
+}
-// printf ("function start addresses\n");
-// for (int i = 0; i < baton->function_start_addresses_count; i++)
-// {
-// printf ("0x%012llx\n", baton->function_start_addresses[i]);
-// }
+void print_encoding_x86_64(struct baton baton, uint8_t *function_start,
+ uint32_t encoding) {
+ int mode = encoding & UNWIND_X86_64_MODE_MASK;
+ switch (mode) {
+ case UNWIND_X86_64_MODE_RBP_FRAME: {
+ printf("frame func: CFA is rbp+%d ", 16);
+ printf(" rip=[CFA-8] rbp=[CFA-16]");
+ uint32_t saved_registers_offset =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
-// printf ("symbol table names & addresses\n");
-// for (int i = 0; i < baton->symbols_count; i++)
-// {
-// printf ("0x%012llx %s\n", baton->symbols[i].file_address, baton->symbols[i].name);
-// }
+ uint32_t saved_registers_locations =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
-}
+ saved_registers_offset += 2;
-void
-print_encoding_x86_64 (struct baton baton, uint8_t *function_start, uint32_t encoding)
-{
- int mode = encoding & UNWIND_X86_64_MODE_MASK;
- switch (mode)
- {
- case UNWIND_X86_64_MODE_RBP_FRAME:
- {
- printf ("frame func: CFA is rbp+%d ", 16);
- printf (" rip=[CFA-8] rbp=[CFA-16]");
- uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
-
- uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
-
-
- saved_registers_offset += 2;
-
- for (int i = 0; i < 5; i++)
- {
- switch (saved_registers_locations & 0x7)
- {
- case UNWIND_X86_64_REG_NONE:
- break;
- case UNWIND_X86_64_REG_RBX:
- printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
- break;
- case UNWIND_X86_64_REG_R12:
- printf (" r12=[CFA-%d]", saved_registers_offset * 8);
- break;
- case UNWIND_X86_64_REG_R13:
- printf (" r13=[CFA-%d]", saved_registers_offset * 8);
- break;
- case UNWIND_X86_64_REG_R14:
- printf (" r14=[CFA-%d]", saved_registers_offset * 8);
- break;
- case UNWIND_X86_64_REG_R15:
- printf (" r15=[CFA-%d]", saved_registers_offset * 8);
- break;
- }
- saved_registers_offset--;
- saved_registers_locations >>= 3;
- }
- }
+ for (int i = 0; i < 5; i++) {
+ switch (saved_registers_locations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
break;
+ case UNWIND_X86_64_REG_RBX:
+ printf(" rbx=[CFA-%d]", saved_registers_offset * 8);
+ break;
+ case UNWIND_X86_64_REG_R12:
+ printf(" r12=[CFA-%d]", saved_registers_offset * 8);
+ break;
+ case UNWIND_X86_64_REG_R13:
+ printf(" r13=[CFA-%d]", saved_registers_offset * 8);
+ break;
+ case UNWIND_X86_64_REG_R14:
+ printf(" r14=[CFA-%d]", saved_registers_offset * 8);
+ break;
+ case UNWIND_X86_64_REG_R15:
+ printf(" r15=[CFA-%d]", saved_registers_offset * 8);
+ break;
+ }
+ saved_registers_offset--;
+ saved_registers_locations >>= 3;
+ }
+ } break;
- case UNWIND_X86_64_MODE_STACK_IND:
- case UNWIND_X86_64_MODE_STACK_IMMD:
- {
- 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)
- {
- uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ case UNWIND_X86_64_MODE_STACK_IND:
+ case UNWIND_X86_64_MODE_STACK_IMMD: {
+ 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);
- // 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);
+ if (mode == UNWIND_X86_64_MODE_STACK_IND && function_start) {
+ uint32_t stack_adjust =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
- stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
+ // 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 += stack_adjust * 8;
+ stack_size = *((uint32_t *)(function_start + offset_to_subl_insn));
- printf ("large stack ");
- }
-
- if (mode == UNWIND_X86_64_MODE_STACK_IND)
- {
- printf ("frameless function: stack size %d, register count %d ", stack_size * 8, register_count);
- }
- else
- {
- printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
- }
+ stack_size += stack_adjust * 8;
- if (register_count == 0)
- {
- printf (" no registers saved");
- }
- 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];
-
- // 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; // 120 == 5!
- permutation -= (permunreg[0]*120);
- permunreg[1] = permutation/24; // 24 == 4!
- permutation -= (permunreg[1]*24);
- permunreg[2] = permutation/6; // 6 == 3!
- permutation -= (permunreg[2]*6);
- permunreg[3] = permutation/2; // 2 == 2!
- permutation -= (permunreg[3]*2);
- permunreg[4] = permutation; // 1 == 1!
- 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;
- }
-
- // Decode the Lehmer code for this permutation of
- // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
-
- int registers[6];
- bool used[7] = { false, false, false, false, false, false, false };
- for (int i = 0; i < register_count; i++)
- {
- int renum = 0;
- for (int j = 1; j < 7; j++)
- {
- if (used[j] == false)
- {
- if (renum == permunreg[i])
- {
- registers[i] = j;
- used[j] = true;
- break;
- }
- renum++;
- }
- }
- }
-
-
- if (mode == UNWIND_X86_64_MODE_STACK_IND)
- {
- printf (" CFA is rsp+%d ", stack_size);
- }
- else
- {
- printf (" CFA is rsp+%d ", stack_size * 8);
- }
-
- uint32_t saved_registers_offset = 1;
- printf (" rip=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
-
- for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
- {
- switch (registers[i])
- {
- case UNWIND_X86_64_REG_NONE:
- break;
- case UNWIND_X86_64_REG_RBX:
- printf (" rbx=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
- break;
- case UNWIND_X86_64_REG_R12:
- printf (" r12=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
- break;
- case UNWIND_X86_64_REG_R13:
- printf (" r13=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
- break;
- case UNWIND_X86_64_REG_R14:
- printf (" r14=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
- break;
- case UNWIND_X86_64_REG_R15:
- printf (" r15=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
- break;
- case UNWIND_X86_64_REG_RBP:
- printf (" rbp=[CFA-%d]", saved_registers_offset * 8);
- saved_registers_offset++;
- break;
- }
- }
+ printf("large stack ");
+ }
- }
+ if (mode == UNWIND_X86_64_MODE_STACK_IND) {
+ printf("frameless function: stack size %d, register count %d ",
+ stack_size * 8, register_count);
+ } else {
+ printf("frameless function: stack size %d, register count %d ",
+ stack_size, register_count);
+ }
- }
+ if (register_count == 0) {
+ printf(" no registers saved");
+ } 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];
+
+ // 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; // 120 == 5!
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24; // 24 == 4!
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6; // 6 == 3!
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2; // 2 == 2!
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation; // 1 == 1!
+ permunreg[5] = 0;
break;
-
- case UNWIND_X86_64_MODE_DWARF:
- {
- uint32_t dwarf_offset = encoding & UNWIND_X86_DWARF_SECTION_OFFSET;
- printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
- dwarf_offset, dwarf_offset + baton.eh_section_file_address);
- }
+ 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 0:
- {
- printf (" no unwind information");
- }
+ 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;
- }
-}
-
-void
-print_encoding_i386 (struct baton baton, uint8_t *function_start, uint32_t encoding)
-{
- int mode = encoding & UNWIND_X86_MODE_MASK;
- switch (mode)
- {
- case UNWIND_X86_MODE_EBP_FRAME:
- {
- printf ("frame func: CFA is ebp+%d ", 8);
- printf (" eip=[CFA-4] ebp=[CFA-8]");
- uint32_t saved_registers_offset = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_OFFSET);
-
- uint32_t saved_registers_locations = EXTRACT_BITS (encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
-
-
- saved_registers_offset += 2;
-
- for (int i = 0; i < 5; i++)
- {
- switch (saved_registers_locations & 0x7)
- {
- case UNWIND_X86_REG_NONE:
- break;
- case UNWIND_X86_REG_EBX:
- printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
- break;
- case UNWIND_X86_REG_ECX:
- printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
- break;
- case UNWIND_X86_REG_EDX:
- printf (" edx=[CFA-%d]", saved_registers_offset * 4);
- break;
- case UNWIND_X86_REG_EDI:
- printf (" edi=[CFA-%d]", saved_registers_offset * 4);
- break;
- case UNWIND_X86_REG_ESI:
- printf (" esi=[CFA-%d]", saved_registers_offset * 4);
- break;
- }
- saved_registers_offset--;
- saved_registers_locations >>= 3;
+ 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;
+ }
+
+ // Decode the Lehmer code for this permutation of
+ // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
+
+ int registers[6];
+ bool used[7] = {false, false, false, false, false, false, false};
+ for (int i = 0; i < register_count; i++) {
+ int renum = 0;
+ for (int j = 1; j < 7; j++) {
+ if (used[j] == false) {
+ if (renum == permunreg[i]) {
+ registers[i] = j;
+ used[j] = true;
+ break;
}
+ renum++;
+ }
}
- break;
+ }
+
+ if (mode == UNWIND_X86_64_MODE_STACK_IND) {
+ printf(" CFA is rsp+%d ", stack_size);
+ } else {
+ printf(" CFA is rsp+%d ", stack_size * 8);
+ }
+
+ uint32_t saved_registers_offset = 1;
+ printf(" rip=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+
+ for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
+ switch (registers[i]) {
+ case UNWIND_X86_64_REG_NONE:
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ printf(" rbx=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_64_REG_R12:
+ printf(" r12=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_64_REG_R13:
+ printf(" r13=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_64_REG_R14:
+ printf(" r14=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_64_REG_R15:
+ printf(" r15=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ printf(" rbp=[CFA-%d]", saved_registers_offset * 8);
+ saved_registers_offset++;
+ break;
+ }
+ }
+ }
- case UNWIND_X86_MODE_STACK_IND:
- case UNWIND_X86_MODE_STACK_IMMD:
- {
- uint32_t stack_size = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
- uint32_t register_count = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
- uint32_t permutation = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ } break;
- if (mode == UNWIND_X86_MODE_STACK_IND && function_start)
- {
- uint32_t stack_adjust = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ case UNWIND_X86_64_MODE_DWARF: {
+ uint32_t dwarf_offset = encoding & UNWIND_X86_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;
- // offset into the function instructions; 0 == beginning of first instruction
- uint32_t offset_to_subl_insn = EXTRACT_BITS (encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ case 0: {
+ printf(" no unwind information");
+ } break;
+ }
+}
- stack_size = *((uint32_t*) (function_start + offset_to_subl_insn));
+void print_encoding_i386(struct baton baton, uint8_t *function_start,
+ uint32_t encoding) {
+ int mode = encoding & UNWIND_X86_MODE_MASK;
+ switch (mode) {
+ case UNWIND_X86_MODE_EBP_FRAME: {
+ printf("frame func: CFA is ebp+%d ", 8);
+ printf(" eip=[CFA-4] ebp=[CFA-8]");
+ uint32_t saved_registers_offset =
+ EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_OFFSET);
- stack_size += stack_adjust * 4;
+ uint32_t saved_registers_locations =
+ EXTRACT_BITS(encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
- printf ("large stack ");
- }
-
- if (mode == UNWIND_X86_MODE_STACK_IND)
- {
- printf ("frameless function: stack size %d, register count %d ", stack_size, register_count);
- }
- else
- {
- printf ("frameless function: stack size %d, register count %d ", stack_size * 4, register_count);
- }
-
- if (register_count == 0)
- {
- printf (" no registers saved");
- }
- 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];
-
- // 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; // 120 == 5!
- permutation -= (permunreg[0]*120);
- permunreg[1] = permutation/24; // 24 == 4!
- permutation -= (permunreg[1]*24);
- permunreg[2] = permutation/6; // 6 == 3!
- permutation -= (permunreg[2]*6);
- permunreg[3] = permutation/2; // 2 == 2!
- permutation -= (permunreg[3]*2);
- permunreg[4] = permutation; // 1 == 1!
- 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;
- }
-
- // Decode the Lehmer code for this permutation of
- // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
-
- int registers[6];
- bool used[7] = { false, false, false, false, false, false, false };
- for (int i = 0; i < register_count; i++)
- {
- int renum = 0;
- for (int j = 1; j < 7; j++)
- {
- if (used[j] == false)
- {
- if (renum == permunreg[i])
- {
- registers[i] = j;
- used[j] = true;
- break;
- }
- renum++;
- }
- }
- }
-
-
- if (mode == UNWIND_X86_MODE_STACK_IND)
- {
- printf (" CFA is esp+%d ", stack_size);
- }
- else
- {
- printf (" CFA is esp+%d ", stack_size * 4);
- }
-
- uint32_t saved_registers_offset = 1;
- printf (" eip=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
-
- for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--)
- {
- switch (registers[i])
- {
- case UNWIND_X86_REG_NONE:
- break;
- case UNWIND_X86_REG_EBX:
- printf (" ebx=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
- break;
- case UNWIND_X86_REG_ECX:
- printf (" ecx=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
- break;
- case UNWIND_X86_REG_EDX:
- printf (" edx=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
- break;
- case UNWIND_X86_REG_EDI:
- printf (" edi=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
- break;
- case UNWIND_X86_REG_ESI:
- printf (" esi=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
- break;
- case UNWIND_X86_REG_EBP:
- printf (" ebp=[CFA-%d]", saved_registers_offset * 4);
- saved_registers_offset++;
- break;
- }
- }
+ saved_registers_offset += 2;
- }
-
- }
+ for (int i = 0; i < 5; i++) {
+ switch (saved_registers_locations & 0x7) {
+ case UNWIND_X86_REG_NONE:
break;
-
- case UNWIND_X86_MODE_DWARF:
- {
- uint32_t dwarf_offset = encoding & UNWIND_X86_DWARF_SECTION_OFFSET;
- printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
- dwarf_offset, dwarf_offset + baton.eh_section_file_address);
- }
+ case UNWIND_X86_REG_EBX:
+ printf(" ebx=[CFA-%d]", saved_registers_offset * 4);
break;
-
- case 0:
- {
- printf (" no unwind information");
- }
+ case UNWIND_X86_REG_ECX:
+ printf(" ecx=[CFA-%d]", saved_registers_offset * 4);
+ break;
+ case UNWIND_X86_REG_EDX:
+ printf(" edx=[CFA-%d]", saved_registers_offset * 4);
+ break;
+ case UNWIND_X86_REG_EDI:
+ printf(" edi=[CFA-%d]", saved_registers_offset * 4);
+ break;
+ case UNWIND_X86_REG_ESI:
+ printf(" esi=[CFA-%d]", saved_registers_offset * 4);
break;
+ }
+ saved_registers_offset--;
+ saved_registers_locations >>= 3;
}
-}
+ } break;
-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++;
- }
+ case UNWIND_X86_MODE_STACK_IND:
+ case UNWIND_X86_MODE_STACK_IMMD: {
+ uint32_t stack_size =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t register_count =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
- }
- break;
+ if (mode == UNWIND_X86_MODE_STACK_IND && function_start) {
+ uint32_t stack_adjust =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
- 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);
+ // offset into the function instructions; 0 == beginning of first
+ // instruction
+ uint32_t offset_to_subl_insn =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
- }
- break;
+ stack_size = *((uint32_t *)(function_start + offset_to_subl_insn));
- 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;
+ stack_size += stack_adjust * 4;
- case 0:
- {
- printf (" no unwind information");
- }
- break;
+ printf("large stack ");
}
-}
-void
-print_encoding_armv7 (struct baton baton, uint8_t *function_start, uint32_t encoding)
-{
- const int wordsize = 4;
- int mode = encoding & UNWIND_ARM_MODE_MASK;
- switch (mode)
- {
- case UNWIND_ARM_MODE_FRAME_D:
- case UNWIND_ARM_MODE_FRAME:
- {
- int stack_adjust = EXTRACT_BITS (encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK) * wordsize;
-
- printf ("frame func: CFA is fp+%d ", (2 * wordsize) + stack_adjust);
- int cfa_offset = -stack_adjust;
-
- cfa_offset -= wordsize;
- printf (" pc=[CFA%d]", cfa_offset);
- cfa_offset -= wordsize;
- printf (" fp=[CFA%d]", cfa_offset);
-
- uint32_t saved_register_bits = encoding & 0xff;
- if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6)
- {
- cfa_offset -= wordsize;
- printf (" r6=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5)
- {
- cfa_offset -= wordsize;
- printf (" r5=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4)
- {
- cfa_offset -= wordsize;
- printf (" r4=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12)
- {
- cfa_offset -= wordsize;
- printf (" r12=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11)
- {
- cfa_offset -= wordsize;
- printf (" r11=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10)
- {
- cfa_offset -= wordsize;
- printf (" r10=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9)
- {
- cfa_offset -= wordsize;
- printf (" r9=[CFA%d]", cfa_offset);
- }
- if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8)
- {
- cfa_offset -= wordsize;
- printf (" r8=[CFA%d]", cfa_offset);
- }
+ if (mode == UNWIND_X86_MODE_STACK_IND) {
+ printf("frameless function: stack size %d, register count %d ",
+ stack_size, register_count);
+ } else {
+ printf("frameless function: stack size %d, register count %d ",
+ stack_size * 4, register_count);
+ }
- if (mode == UNWIND_ARM_MODE_FRAME_D)
- {
- uint32_t d_reg_bits = EXTRACT_BITS (encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
- switch (d_reg_bits)
- {
- case 0:
- // vpush {d8}
- cfa_offset -= 8;
- printf (" d8=[CFA%d]", cfa_offset);
- break;
- case 1:
- // vpush {d10}
- // vpush {d8}
- cfa_offset -= 8;
- printf (" d10=[CFA%d]", cfa_offset);
- cfa_offset -= 8;
- printf (" d8=[CFA%d]", cfa_offset);
- break;
- case 2:
- // vpush {d12}
- // vpush {d10}
- // vpush {d8}
- cfa_offset -= 8;
- printf (" d12=[CFA%d]", cfa_offset);
- cfa_offset -= 8;
- printf (" d10=[CFA%d]", cfa_offset);
- cfa_offset -= 8;
- printf (" d8=[CFA%d]", cfa_offset);
- break;
- case 3:
- // vpush {d14}
- // vpush {d12}
- // vpush {d10}
- // vpush {d8}
- cfa_offset -= 8;
- printf (" d14=[CFA%d]", cfa_offset);
- cfa_offset -= 8;
- printf (" d12=[CFA%d]", cfa_offset);
- cfa_offset -= 8;
- printf (" d10=[CFA%d]", cfa_offset);
- cfa_offset -= 8;
- printf (" d8=[CFA%d]", cfa_offset);
- break;
- case 4:
- // vpush {d14}
- // vpush {d12}
- // sp = (sp - 24) & (-16);
- // vst {d8, d9, d10}
- printf (" d14, d12, d10, d9, d8");
- break;
- case 5:
- // vpush {d14}
- // sp = (sp - 40) & (-16);
- // vst {d8, d9, d10, d11}
- // vst {d12}
- printf (" d14, d11, d10, d9, d8, d12");
- break;
- case 6:
- // sp = (sp - 56) & (-16);
- // vst {d8, d9, d10, d11}
- // vst {d12, d13, d14}
- printf (" d11, d10, d9, d8, d14, d13, d12");
- break;
- case 7:
- // sp = (sp - 64) & (-16);
- // vst {d8, d9, d10, d11}
- // vst {d12, d13, d14, d15}
- printf (" d11, d10, d9, d8, d15, d14, d13, d12");
- break;
- }
- }
- }
+ if (register_count == 0) {
+ printf(" no registers saved");
+ } 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];
+
+ // 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; // 120 == 5!
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24; // 24 == 4!
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6; // 6 == 3!
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2; // 2 == 2!
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation; // 1 == 1!
+ permunreg[5] = 0;
break;
-
- case UNWIND_ARM_MODE_DWARF:
- {
- uint32_t dwarf_offset = encoding & UNWIND_ARM_DWARF_SECTION_OFFSET;
- printf ("DWARF unwind instructions: FDE at offset %d (file address 0x%" PRIx64 ")",
- dwarf_offset, dwarf_offset + baton.eh_section_file_address);
- }
+ 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 0:
- {
- printf (" no unwind information");
- }
+ 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;
+ }
+
+ // Decode the Lehmer code for this permutation of
+ // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
+
+ int registers[6];
+ bool used[7] = {false, false, false, false, false, false, false};
+ for (int i = 0; i < register_count; i++) {
+ int renum = 0;
+ for (int j = 1; j < 7; j++) {
+ if (used[j] == false) {
+ if (renum == permunreg[i]) {
+ registers[i] = j;
+ used[j] = true;
+ break;
+ }
+ renum++;
+ }
+ }
+ }
+
+ if (mode == UNWIND_X86_MODE_STACK_IND) {
+ printf(" CFA is esp+%d ", stack_size);
+ } else {
+ printf(" CFA is esp+%d ", stack_size * 4);
+ }
+
+ uint32_t saved_registers_offset = 1;
+ printf(" eip=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+
+ for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
+ switch (registers[i]) {
+ case UNWIND_X86_REG_NONE:
+ break;
+ case UNWIND_X86_REG_EBX:
+ printf(" ebx=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_REG_ECX:
+ printf(" ecx=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_REG_EDX:
+ printf(" edx=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_REG_EDI:
+ printf(" edi=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_REG_ESI:
+ printf(" esi=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+ break;
+ case UNWIND_X86_REG_EBP:
+ printf(" ebp=[CFA-%d]", saved_registers_offset * 4);
+ saved_registers_offset++;
+ break;
+ }
+ }
}
-}
-
+ } break;
+ case UNWIND_X86_MODE_DWARF: {
+ uint32_t dwarf_offset = encoding & UNWIND_X86_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;
-void print_encoding (struct baton baton, uint8_t *function_start, uint32_t encoding)
-{
+ case 0: {
+ printf(" no unwind information");
+ } break;
+ }
+}
- if (baton.cputype == CPU_TYPE_X86_64)
- {
- print_encoding_x86_64 (baton, function_start, encoding);
+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++;
}
- else if (baton.cputype == CPU_TYPE_I386)
- {
- print_encoding_i386 (baton, function_start, encoding);
+ 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++;
}
- else if (baton.cputype == CPU_TYPE_ARM64)
- {
- print_encoding_arm64 (baton, function_start, encoding);
+ 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++;
}
- else if (baton.cputype == CPU_TYPE_ARM)
- {
- print_encoding_armv7 (baton, function_start, encoding);
+ 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++;
}
- else
- {
- printf (" -- unsupported encoding arch -- ");
+ 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++;
}
-}
-
-void
-print_function_encoding (struct baton baton, uint32_t idx, uint32_t encoding, uint32_t entry_encoding_index, uint32_t entry_func_offset)
-{
-
- char *entry_encoding_index_str = "";
- if (entry_encoding_index != (uint32_t) -1)
- {
- asprintf (&entry_encoding_index_str, ", encoding #%d", entry_encoding_index);
+ 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++;
}
- else
- {
- asprintf (&entry_encoding_index_str, "");
+ 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++;
}
-
- uint64_t file_address = baton.first_level_index_entry.functionOffset + entry_func_offset + baton.text_segment_vmaddr;
-
- if (baton.cputype == CPU_TYPE_ARM)
- file_address = file_address & ~1;
-
- printf (" func [%d] offset %d (file addr 0x%" PRIx64 ")%s, encoding is 0x%x",
- idx, entry_func_offset,
- file_address,
- entry_encoding_index_str,
- encoding);
-
- struct symbol *symbol = NULL;
- for (int i = 0; i < baton.symbols_count; i++)
- {
- if (i == baton.symbols_count - 1 && baton.symbols[i].file_address <= file_address)
- {
- symbol = &(baton.symbols[i]);
- break;
- }
- else
- {
- if (baton.symbols[i].file_address <= file_address && baton.symbols[i + 1].file_address > file_address)
- {
- symbol = &(baton.symbols[i]);
- break;
- }
- }
+ 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++;
}
-
- printf ("\n ");
- if (symbol)
- {
- int offset = file_address - symbol->file_address;
-
- // FIXME this is a poor heuristic - if we're greater than 16 bytes past the
- // start of the function, this is the unwind info for a stripped function.
- // In reality the compact unwind entry may not line up exactly with the
- // function bounds.
- if (offset >= 0)
- {
- printf ("name: %s", symbol->name);
- if (offset > 0)
- {
- printf (" + %d", offset);
- }
- }
- printf ("\n ");
+ 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++;
}
- 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;
-
- if (has_lsda)
- {
- uint32_t func_offset = entry_func_offset + baton.first_level_index_entry.functionOffset;
+ } break;
- int lsda_entry_number = -1;
+ 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);
- uint32_t low = 0;
- uint32_t high = (baton.lsda_array_end - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
+ } break;
- while (low < high)
- {
- uint32_t mid = (low + high) / 2;
+ 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;
- uint8_t *mid_lsda_entry_addr = (baton.lsda_array_start + (mid * sizeof (struct unwind_info_section_header_lsda_index_entry)));
- struct unwind_info_section_header_lsda_index_entry mid_lsda_entry;
- memcpy (&mid_lsda_entry, mid_lsda_entry_addr, sizeof (struct unwind_info_section_header_lsda_index_entry));
- if (mid_lsda_entry.functionOffset == func_offset)
- {
- lsda_entry_number = (mid_lsda_entry_addr - baton.lsda_array_start) / sizeof (struct unwind_info_section_header_lsda_index_entry);
- break;
- }
- else if (mid_lsda_entry.functionOffset < func_offset)
- {
- low = mid + 1;
- }
- else
- {
- high = mid;
- }
- }
+ case 0: {
+ printf(" no unwind information");
+ } break;
+ }
+}
- if (lsda_entry_number != -1)
- {
- printf (", LSDA entry #%d", lsda_entry_number);
- }
- else
- {
- printf (", LSDA entry not found");
- }
+void print_encoding_armv7(struct baton baton, uint8_t *function_start,
+ uint32_t encoding) {
+ const int wordsize = 4;
+ int mode = encoding & UNWIND_ARM_MODE_MASK;
+ switch (mode) {
+ case UNWIND_ARM_MODE_FRAME_D:
+ case UNWIND_ARM_MODE_FRAME: {
+ int stack_adjust =
+ EXTRACT_BITS(encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK) * wordsize;
+
+ printf("frame func: CFA is fp+%d ", (2 * wordsize) + stack_adjust);
+ int cfa_offset = -stack_adjust;
+
+ cfa_offset -= wordsize;
+ printf(" pc=[CFA%d]", cfa_offset);
+ cfa_offset -= wordsize;
+ printf(" fp=[CFA%d]", cfa_offset);
+
+ uint32_t saved_register_bits = encoding & 0xff;
+ if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
+ cfa_offset -= wordsize;
+ printf(" r6=[CFA%d]", cfa_offset);
}
-
- uint32_t pers_idx = EXTRACT_BITS (encoding, UNWIND_PERSONALITY_MASK);
- if (pers_idx != 0)
- {
- pers_idx--; // Change 1-based to 0-based index
- printf (", personality entry #%d", pers_idx);
+ if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
+ cfa_offset -= wordsize;
+ printf(" r5=[CFA%d]", cfa_offset);
}
-
- printf ("\n");
-}
-
-void
-print_second_level_index_regular (struct baton baton)
-{
- uint8_t *page_entries = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset + baton.regular_second_level_page_header.entryPageOffset;
- uint32_t entries_count = baton.regular_second_level_page_header.entryCount;
-
- uint8_t *offset = page_entries;
-
- uint32_t idx = 0;
- while (idx < entries_count)
- {
- uint32_t func_offset = *((uint32_t *) (offset));
- uint32_t encoding = *((uint32_t *) (offset + 4));
-
- // 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 containing 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;
+ if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
+ cfa_offset -= wordsize;
+ printf(" r4=[CFA%d]", cfa_offset);
}
-}
-
-void
-print_second_level_index_compressed (struct baton baton)
-{
- uint8_t *this_index = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
- uint8_t *start_of_entries = this_index + baton.compressed_second_level_page_header.entryPageOffset;
- uint8_t *offset = start_of_entries;
- for (uint16_t idx = 0; idx < baton.compressed_second_level_page_header.entryCount; idx++)
- {
- uint32_t entry = *((uint32_t*) offset);
- offset += 4;
- uint32_t encoding;
-
- uint32_t entry_encoding_index = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
- uint32_t entry_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry);
-
- if (entry_encoding_index < baton.unwind_header.commonEncodingsArrayCount)
- {
- // encoding is in common table in section header
- encoding = *((uint32_t*) (baton.compact_unwind_start + baton.unwind_header.commonEncodingsArraySectionOffset + (entry_encoding_index * sizeof (uint32_t))));
- }
- else
- {
- // encoding is in page specific table
- uint32_t page_encoding_index = entry_encoding_index - baton.unwind_header.commonEncodingsArrayCount;
- encoding = *((uint32_t*) (this_index + baton.compressed_second_level_page_header.encodingsPageOffset + (page_encoding_index * sizeof (uint32_t))));
- }
-
-
- print_function_encoding (baton, idx, encoding, entry_encoding_index, entry_func_offset);
+ if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
+ cfa_offset -= wordsize;
+ printf(" r12=[CFA%d]", cfa_offset);
}
-}
-
-void
-print_second_level_index (struct baton baton)
-{
- uint8_t *index_start = baton.compact_unwind_start + baton.first_level_index_entry.secondLevelPagesSectionOffset;
-
- if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_REGULAR)
- {
- struct unwind_info_regular_second_level_page_header header;
- memcpy (&header, index_start, sizeof (struct unwind_info_regular_second_level_page_header));
- printf (" UNWIND_SECOND_LEVEL_REGULAR #%d entryPageOffset %d, entryCount %d\n", baton.current_index_table_number, header.entryPageOffset, header.entryCount);
- baton.regular_second_level_page_header = header;
- print_second_level_index_regular (baton);
+ if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
+ cfa_offset -= wordsize;
+ printf(" r11=[CFA%d]", cfa_offset);
+ }
+ if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
+ cfa_offset -= wordsize;
+ printf(" r10=[CFA%d]", cfa_offset);
+ }
+ if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
+ cfa_offset -= wordsize;
+ printf(" r9=[CFA%d]", cfa_offset);
+ }
+ if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
+ cfa_offset -= wordsize;
+ printf(" r8=[CFA%d]", cfa_offset);
}
- if ((*(uint32_t*) index_start) == UNWIND_SECOND_LEVEL_COMPRESSED)
- {
- struct unwind_info_compressed_second_level_page_header header;
- memcpy (&header, index_start, sizeof (struct unwind_info_compressed_second_level_page_header));
- printf (" UNWIND_SECOND_LEVEL_COMPRESSED #%d entryPageOffset %d, entryCount %d, encodingsPageOffset %d, encodingsCount %d\n", baton.current_index_table_number, header.entryPageOffset, header.entryCount, header.encodingsPageOffset, header.encodingsCount);
- baton.compressed_second_level_page_header = header;
- print_second_level_index_compressed (baton);
+ if (mode == UNWIND_ARM_MODE_FRAME_D) {
+ uint32_t d_reg_bits =
+ EXTRACT_BITS(encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
+ switch (d_reg_bits) {
+ case 0:
+ // vpush {d8}
+ cfa_offset -= 8;
+ printf(" d8=[CFA%d]", cfa_offset);
+ break;
+ case 1:
+ // vpush {d10}
+ // vpush {d8}
+ cfa_offset -= 8;
+ printf(" d10=[CFA%d]", cfa_offset);
+ cfa_offset -= 8;
+ printf(" d8=[CFA%d]", cfa_offset);
+ break;
+ case 2:
+ // vpush {d12}
+ // vpush {d10}
+ // vpush {d8}
+ cfa_offset -= 8;
+ printf(" d12=[CFA%d]", cfa_offset);
+ cfa_offset -= 8;
+ printf(" d10=[CFA%d]", cfa_offset);
+ cfa_offset -= 8;
+ printf(" d8=[CFA%d]", cfa_offset);
+ break;
+ case 3:
+ // vpush {d14}
+ // vpush {d12}
+ // vpush {d10}
+ // vpush {d8}
+ cfa_offset -= 8;
+ printf(" d14=[CFA%d]", cfa_offset);
+ cfa_offset -= 8;
+ printf(" d12=[CFA%d]", cfa_offset);
+ cfa_offset -= 8;
+ printf(" d10=[CFA%d]", cfa_offset);
+ cfa_offset -= 8;
+ printf(" d8=[CFA%d]", cfa_offset);
+ break;
+ case 4:
+ // vpush {d14}
+ // vpush {d12}
+ // sp = (sp - 24) & (-16);
+ // vst {d8, d9, d10}
+ printf(" d14, d12, d10, d9, d8");
+ break;
+ case 5:
+ // vpush {d14}
+ // sp = (sp - 40) & (-16);
+ // vst {d8, d9, d10, d11}
+ // vst {d12}
+ printf(" d14, d11, d10, d9, d8, d12");
+ break;
+ case 6:
+ // sp = (sp - 56) & (-16);
+ // vst {d8, d9, d10, d11}
+ // vst {d12, d13, d14}
+ printf(" d11, d10, d9, d8, d14, d13, d12");
+ break;
+ case 7:
+ // sp = (sp - 64) & (-16);
+ // vst {d8, d9, d10, d11}
+ // vst {d12, d13, d14, d15}
+ printf(" d11, d10, d9, d8, d15, d14, d13, d12");
+ break;
+ }
}
+ } break;
+
+ case UNWIND_ARM_MODE_DWARF: {
+ uint32_t dwarf_offset = encoding & UNWIND_ARM_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_index_sections (struct baton baton)
-{
- uint8_t *index_section_offset = baton.compact_unwind_start + baton.unwind_header.indexSectionOffset;
- uint32_t index_count = baton.unwind_header.indexCount;
-
- uint32_t cur_idx = 0;
-
- uint8_t *offset = index_section_offset;
- while (cur_idx < index_count)
- {
- baton.current_index_table_number = cur_idx;
- struct unwind_info_section_header_index_entry index_entry;
- memcpy (&index_entry, offset, sizeof (struct unwind_info_section_header_index_entry));
- printf ("index section #%d: functionOffset %d, secondLevelPagesSectionOffset %d, lsdaIndexArraySectionOffset %d\n", cur_idx, index_entry.functionOffset, index_entry.secondLevelPagesSectionOffset, index_entry.lsdaIndexArraySectionOffset);
-
- // secondLevelPagesSectionOffset == 0 means this is a sentinel entry
- if (index_entry.secondLevelPagesSectionOffset != 0)
- {
- struct unwind_info_section_header_index_entry next_index_entry;
- memcpy (&next_index_entry, offset + sizeof (struct unwind_info_section_header_index_entry), sizeof (struct unwind_info_section_header_index_entry));
-
- baton.lsda_array_start = baton.compact_unwind_start + index_entry.lsdaIndexArraySectionOffset;
- baton.lsda_array_end = baton.compact_unwind_start + next_index_entry.lsdaIndexArraySectionOffset;
-
- uint8_t *lsda_entry_offset = baton.lsda_array_start;
- uint32_t lsda_count = 0;
- while (lsda_entry_offset < baton.lsda_array_end)
- {
- struct unwind_info_section_header_lsda_index_entry lsda_entry;
- memcpy (&lsda_entry, lsda_entry_offset, sizeof (struct unwind_info_section_header_lsda_index_entry));
- uint64_t function_file_address = baton.first_level_index_entry.functionOffset + lsda_entry.functionOffset + baton.text_segment_vmaddr;
- uint64_t lsda_file_address = lsda_entry.lsdaOffset + baton.text_segment_vmaddr;
- printf (" LSDA [%d] functionOffset %d (%d) (file address 0x%" PRIx64 "), lsdaOffset %d (file address 0x%" PRIx64 ")\n",
- lsda_count, lsda_entry.functionOffset,
- lsda_entry.functionOffset - index_entry.functionOffset,
- function_file_address,
- lsda_entry.lsdaOffset, lsda_file_address);
- lsda_count++;
- lsda_entry_offset += sizeof (struct unwind_info_section_header_lsda_index_entry);
- }
-
- printf ("\n");
-
- baton.first_level_index_entry = index_entry;
- print_second_level_index (baton);
- }
-
- printf ("\n");
-
- cur_idx++;
- offset += sizeof (struct unwind_info_section_header_index_entry);
- }
+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, function_start, encoding);
+ } else if (baton.cputype == CPU_TYPE_I386) {
+ print_encoding_i386(baton, function_start, encoding);
+ } else if (baton.cputype == CPU_TYPE_ARM64) {
+ print_encoding_arm64(baton, function_start, encoding);
+ } else if (baton.cputype == CPU_TYPE_ARM) {
+ print_encoding_armv7(baton, function_start, encoding);
+ } else {
+ printf(" -- unsupported encoding arch -- ");
+ }
}
-int main (int argc, char **argv)
-{
- struct stat st;
- char *file = argv[0];
- if (argc > 1)
- file = argv[1];
- int fd = open (file, O_RDONLY);
- if (fd == -1)
- {
- printf ("Failed to open '%s'\n", file);
- exit (1);
+void print_function_encoding(struct baton baton, uint32_t idx,
+ uint32_t encoding, uint32_t entry_encoding_index,
+ uint32_t entry_func_offset) {
+
+ char *entry_encoding_index_str = "";
+ if (entry_encoding_index != (uint32_t)-1) {
+ asprintf(&entry_encoding_index_str, ", encoding #%d", entry_encoding_index);
+ } else {
+ asprintf(&entry_encoding_index_str, "");
+ }
+
+ uint64_t file_address = baton.first_level_index_entry.functionOffset +
+ entry_func_offset + baton.text_segment_vmaddr;
+
+ if (baton.cputype == CPU_TYPE_ARM)
+ file_address = file_address & ~1;
+
+ printf(
+ " func [%d] offset %d (file addr 0x%" PRIx64 ")%s, encoding is 0x%x",
+ idx, entry_func_offset, file_address, entry_encoding_index_str, encoding);
+
+ struct symbol *symbol = NULL;
+ for (int i = 0; i < baton.symbols_count; i++) {
+ if (i == baton.symbols_count - 1 &&
+ baton.symbols[i].file_address <= file_address) {
+ symbol = &(baton.symbols[i]);
+ break;
+ } else {
+ if (baton.symbols[i].file_address <= file_address &&
+ baton.symbols[i + 1].file_address > file_address) {
+ symbol = &(baton.symbols[i]);
+ break;
+ }
}
- fstat (fd, &st);
- uint8_t *file_mem = (uint8_t*) mmap (0, st.st_size, PROT_READ, MAP_PRIVATE | MAP_FILE, fd, 0);
- if (file_mem == MAP_FAILED)
- {
- printf ("Failed to mmap() '%s'\n", file);
+ }
+
+ printf("\n ");
+ if (symbol) {
+ int offset = file_address - symbol->file_address;
+
+ // FIXME this is a poor heuristic - if we're greater than 16 bytes past the
+ // start of the function, this is the unwind info for a stripped function.
+ // In reality the compact unwind entry may not line up exactly with the
+ // function bounds.
+ if (offset >= 0) {
+ printf("name: %s", symbol->name);
+ if (offset > 0) {
+ printf(" + %d", offset);
+ }
+ }
+ printf("\n ");
+ }
+
+ 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;
+
+ if (has_lsda) {
+ uint32_t func_offset =
+ entry_func_offset + baton.first_level_index_entry.functionOffset;
+
+ int lsda_entry_number = -1;
+
+ uint32_t low = 0;
+ uint32_t high = (baton.lsda_array_end - baton.lsda_array_start) /
+ sizeof(struct unwind_info_section_header_lsda_index_entry);
+
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+
+ uint8_t *mid_lsda_entry_addr =
+ (baton.lsda_array_start +
+ (mid * sizeof(struct unwind_info_section_header_lsda_index_entry)));
+ struct unwind_info_section_header_lsda_index_entry mid_lsda_entry;
+ memcpy(&mid_lsda_entry, mid_lsda_entry_addr,
+ sizeof(struct unwind_info_section_header_lsda_index_entry));
+ if (mid_lsda_entry.functionOffset == func_offset) {
+ lsda_entry_number =
+ (mid_lsda_entry_addr - baton.lsda_array_start) /
+ sizeof(struct unwind_info_section_header_lsda_index_entry);
+ break;
+ } else if (mid_lsda_entry.functionOffset < func_offset) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
}
- FILE *f = fopen ("a.out", "r");
-
- struct baton baton;
- baton.mach_header_start = file_mem;
- baton.symbols = NULL;
- baton.symbols_count = 0;
- baton.function_start_addresses = NULL;
- baton.function_start_addresses_count = 0;
+ if (lsda_entry_number != -1) {
+ printf(", LSDA entry #%d", lsda_entry_number);
+ } else {
+ printf(", LSDA entry not found");
+ }
+ }
- scan_macho_load_commands (&baton);
+ uint32_t pers_idx = EXTRACT_BITS(encoding, UNWIND_PERSONALITY_MASK);
+ if (pers_idx != 0) {
+ pers_idx--; // Change 1-based to 0-based index
+ printf(", personality entry #%d", pers_idx);
+ }
- if (baton.compact_unwind_start == NULL)
- {
- printf ("could not find __TEXT,__unwind_info section\n");
- exit (1);
- }
+ printf("\n");
+}
+void print_second_level_index_regular(struct baton baton) {
+ uint8_t *page_entries =
+ baton.compact_unwind_start +
+ baton.first_level_index_entry.secondLevelPagesSectionOffset +
+ baton.regular_second_level_page_header.entryPageOffset;
+ uint32_t entries_count = baton.regular_second_level_page_header.entryCount;
+
+ uint8_t *offset = page_entries;
+
+ uint32_t idx = 0;
+ while (idx < entries_count) {
+ uint32_t func_offset = *((uint32_t *)(offset));
+ uint32_t encoding = *((uint32_t *)(offset + 4));
+
+ // 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 containing 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;
+ }
+}
- struct unwind_info_section_header header;
- memcpy (&header, baton.compact_unwind_start, sizeof (struct unwind_info_section_header));
- printf ("Header:\n");
- printf (" version %u\n", header.version);
- printf (" commonEncodingsArraySectionOffset is %d\n", header.commonEncodingsArraySectionOffset);
- printf (" commonEncodingsArrayCount is %d\n", header.commonEncodingsArrayCount);
- printf (" personalityArraySectionOffset is %d\n", header.personalityArraySectionOffset);
- printf (" personalityArrayCount is %d\n", header.personalityArrayCount);
- printf (" indexSectionOffset is %d\n", header.indexSectionOffset);
- printf (" indexCount is %d\n", header.indexCount);
-
- uint8_t *common_encodings = baton.compact_unwind_start + header.commonEncodingsArraySectionOffset;
- uint32_t encoding_idx = 0;
- while (encoding_idx < header.commonEncodingsArrayCount)
- {
- uint32_t encoding = *((uint32_t*) common_encodings);
- printf (" Common Encoding [%d]: 0x%x ", encoding_idx, encoding);
- print_encoding (baton, NULL, encoding);
- printf ("\n");
- common_encodings += sizeof (uint32_t);
- encoding_idx++;
+void print_second_level_index_compressed(struct baton baton) {
+ uint8_t *this_index =
+ baton.compact_unwind_start +
+ baton.first_level_index_entry.secondLevelPagesSectionOffset;
+ uint8_t *start_of_entries =
+ this_index + baton.compressed_second_level_page_header.entryPageOffset;
+ uint8_t *offset = start_of_entries;
+ for (uint16_t idx = 0;
+ idx < baton.compressed_second_level_page_header.entryCount; idx++) {
+ uint32_t entry = *((uint32_t *)offset);
+ offset += 4;
+ uint32_t encoding;
+
+ uint32_t entry_encoding_index =
+ UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
+ uint32_t entry_func_offset =
+ UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
+
+ if (entry_encoding_index < baton.unwind_header.commonEncodingsArrayCount) {
+ // encoding is in common table in section header
+ encoding =
+ *((uint32_t *)(baton.compact_unwind_start +
+ baton.unwind_header.commonEncodingsArraySectionOffset +
+ (entry_encoding_index * sizeof(uint32_t))));
+ } else {
+ // encoding is in page specific table
+ uint32_t page_encoding_index =
+ entry_encoding_index - baton.unwind_header.commonEncodingsArrayCount;
+ encoding = *((uint32_t *)(this_index +
+ baton.compressed_second_level_page_header
+ .encodingsPageOffset +
+ (page_encoding_index * sizeof(uint32_t))));
}
- uint8_t *pers_arr = baton.compact_unwind_start + header.personalityArraySectionOffset;
- uint32_t pers_idx = 0;
- while (pers_idx < header.personalityArrayCount)
- {
- int32_t pers_delta = *((int32_t*) (baton.compact_unwind_start + header.personalityArraySectionOffset + (pers_idx * sizeof (uint32_t))));
- printf (" Personality [%d]: personality function ptr @ offset %d (file address 0x%" PRIx64 ")\n", pers_idx, pers_delta, baton.text_segment_vmaddr + pers_delta);
- pers_idx++;
- pers_arr += sizeof (uint32_t);
- }
+ print_function_encoding(baton, idx, encoding, entry_encoding_index,
+ entry_func_offset);
+ }
+}
- printf ("\n");
+void print_second_level_index(struct baton baton) {
+ uint8_t *index_start =
+ baton.compact_unwind_start +
+ baton.first_level_index_entry.secondLevelPagesSectionOffset;
+
+ if ((*(uint32_t *)index_start) == UNWIND_SECOND_LEVEL_REGULAR) {
+ struct unwind_info_regular_second_level_page_header header;
+ memcpy(&header, index_start,
+ sizeof(struct unwind_info_regular_second_level_page_header));
+ printf(
+ " UNWIND_SECOND_LEVEL_REGULAR #%d entryPageOffset %d, entryCount %d\n",
+ baton.current_index_table_number, header.entryPageOffset,
+ header.entryCount);
+ baton.regular_second_level_page_header = header;
+ print_second_level_index_regular(baton);
+ }
+
+ if ((*(uint32_t *)index_start) == UNWIND_SECOND_LEVEL_COMPRESSED) {
+ struct unwind_info_compressed_second_level_page_header header;
+ memcpy(&header, index_start,
+ sizeof(struct unwind_info_compressed_second_level_page_header));
+ printf(" UNWIND_SECOND_LEVEL_COMPRESSED #%d entryPageOffset %d, "
+ "entryCount %d, encodingsPageOffset %d, encodingsCount %d\n",
+ baton.current_index_table_number, header.entryPageOffset,
+ header.entryCount, header.encodingsPageOffset,
+ header.encodingsCount);
+ baton.compressed_second_level_page_header = header;
+ print_second_level_index_compressed(baton);
+ }
+}
- baton.unwind_header = header;
+void print_index_sections(struct baton baton) {
+ uint8_t *index_section_offset =
+ baton.compact_unwind_start + baton.unwind_header.indexSectionOffset;
+ uint32_t index_count = baton.unwind_header.indexCount;
+
+ uint32_t cur_idx = 0;
+
+ uint8_t *offset = index_section_offset;
+ while (cur_idx < index_count) {
+ baton.current_index_table_number = cur_idx;
+ struct unwind_info_section_header_index_entry index_entry;
+ memcpy(&index_entry, offset,
+ sizeof(struct unwind_info_section_header_index_entry));
+ printf("index section #%d: functionOffset %d, "
+ "secondLevelPagesSectionOffset %d, lsdaIndexArraySectionOffset %d\n",
+ cur_idx, index_entry.functionOffset,
+ index_entry.secondLevelPagesSectionOffset,
+ index_entry.lsdaIndexArraySectionOffset);
+
+ // secondLevelPagesSectionOffset == 0 means this is a sentinel entry
+ if (index_entry.secondLevelPagesSectionOffset != 0) {
+ struct unwind_info_section_header_index_entry next_index_entry;
+ memcpy(&next_index_entry,
+ offset + sizeof(struct unwind_info_section_header_index_entry),
+ sizeof(struct unwind_info_section_header_index_entry));
+
+ baton.lsda_array_start =
+ baton.compact_unwind_start + index_entry.lsdaIndexArraySectionOffset;
+ baton.lsda_array_end = baton.compact_unwind_start +
+ next_index_entry.lsdaIndexArraySectionOffset;
+
+ uint8_t *lsda_entry_offset = baton.lsda_array_start;
+ uint32_t lsda_count = 0;
+ while (lsda_entry_offset < baton.lsda_array_end) {
+ struct unwind_info_section_header_lsda_index_entry lsda_entry;
+ memcpy(&lsda_entry, lsda_entry_offset,
+ sizeof(struct unwind_info_section_header_lsda_index_entry));
+ uint64_t function_file_address =
+ baton.first_level_index_entry.functionOffset +
+ lsda_entry.functionOffset + baton.text_segment_vmaddr;
+ uint64_t lsda_file_address =
+ lsda_entry.lsdaOffset + baton.text_segment_vmaddr;
+ printf(" LSDA [%d] functionOffset %d (%d) (file address 0x%" PRIx64
+ "), lsdaOffset %d (file address 0x%" PRIx64 ")\n",
+ lsda_count, lsda_entry.functionOffset,
+ lsda_entry.functionOffset - index_entry.functionOffset,
+ function_file_address, lsda_entry.lsdaOffset, lsda_file_address);
+ lsda_count++;
+ lsda_entry_offset +=
+ sizeof(struct unwind_info_section_header_lsda_index_entry);
+ }
+
+ printf("\n");
+
+ baton.first_level_index_entry = index_entry;
+ print_second_level_index(baton);
+ }
- print_index_sections (baton);
+ printf("\n");
+ cur_idx++;
+ offset += sizeof(struct unwind_info_section_header_index_entry);
+ }
+}
- return 0;
+int main(int argc, char **argv) {
+ struct stat st;
+ char *file = argv[0];
+ if (argc > 1)
+ file = argv[1];
+ int fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ printf("Failed to open '%s'\n", file);
+ exit(1);
+ }
+ fstat(fd, &st);
+ uint8_t *file_mem =
+ (uint8_t *)mmap(0, st.st_size, PROT_READ, MAP_PRIVATE | MAP_FILE, fd, 0);
+ if (file_mem == MAP_FAILED) {
+ printf("Failed to mmap() '%s'\n", file);
+ }
+
+ FILE *f = fopen("a.out", "r");
+
+ struct baton baton;
+ baton.mach_header_start = file_mem;
+ baton.symbols = NULL;
+ baton.symbols_count = 0;
+ baton.function_start_addresses = NULL;
+ baton.function_start_addresses_count = 0;
+
+ scan_macho_load_commands(&baton);
+
+ if (baton.compact_unwind_start == NULL) {
+ printf("could not find __TEXT,__unwind_info section\n");
+ exit(1);
+ }
+
+ struct unwind_info_section_header header;
+ memcpy(&header, baton.compact_unwind_start,
+ sizeof(struct unwind_info_section_header));
+ printf("Header:\n");
+ printf(" version %u\n", header.version);
+ printf(" commonEncodingsArraySectionOffset is %d\n",
+ header.commonEncodingsArraySectionOffset);
+ printf(" commonEncodingsArrayCount is %d\n",
+ header.commonEncodingsArrayCount);
+ printf(" personalityArraySectionOffset is %d\n",
+ header.personalityArraySectionOffset);
+ printf(" personalityArrayCount is %d\n", header.personalityArrayCount);
+ printf(" indexSectionOffset is %d\n", header.indexSectionOffset);
+ printf(" indexCount is %d\n", header.indexCount);
+
+ uint8_t *common_encodings =
+ baton.compact_unwind_start + header.commonEncodingsArraySectionOffset;
+ uint32_t encoding_idx = 0;
+ while (encoding_idx < header.commonEncodingsArrayCount) {
+ uint32_t encoding = *((uint32_t *)common_encodings);
+ printf(" Common Encoding [%d]: 0x%x ", encoding_idx, encoding);
+ print_encoding(baton, NULL, encoding);
+ printf("\n");
+ common_encodings += sizeof(uint32_t);
+ encoding_idx++;
+ }
+
+ uint8_t *pers_arr =
+ baton.compact_unwind_start + header.personalityArraySectionOffset;
+ uint32_t pers_idx = 0;
+ while (pers_idx < header.personalityArrayCount) {
+ int32_t pers_delta = *((int32_t *)(baton.compact_unwind_start +
+ header.personalityArraySectionOffset +
+ (pers_idx * sizeof(uint32_t))));
+ printf(" Personality [%d]: personality function ptr @ offset %d (file "
+ "address 0x%" PRIx64 ")\n",
+ pers_idx, pers_delta, baton.text_segment_vmaddr + pers_delta);
+ pers_idx++;
+ pers_arr += sizeof(uint32_t);
+ }
+
+ printf("\n");
+
+ baton.unwind_header = header;
+
+ print_index_sections(baton);
+
+ return 0;
}
OpenPOWER on IntegriCloud