From 167e1c1f1fde89cb29a9dae05a9c6cac5d27fdb2 Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Mon, 17 Mar 2014 09:46:36 +0100 Subject: [PATCH] od-macho: dump compact unwind info. binutils/ * od-macho.c (dump_section_header): Renames of dump_section. (dump_segment): Adjust after renaming. (OPT_COMPACT_UNWIND): Define. (options): Add compact unwind. (mach_o_help): Document compact_unwind. (unwind_x86_64_regs, unwind_x86_regs): New arrays. (dump_unwind_encoding_x86, dump_unwind_encoding) (dump_obj_compact_unwind, dump_exe_compact_unwind) (dump_section_content): New functions. (mach_o_dump): Handle compact unwind. include/mach-o/ * unwind.h: New file. --- binutils/ChangeLog | 13 ++ binutils/od-macho.c | 446 ++++++++++++++++++++++++++++++++++++++- include/mach-o/ChangeLog | 4 + include/mach-o/unwind.h | 199 +++++++++++++++++ 4 files changed, 660 insertions(+), 2 deletions(-) create mode 100644 include/mach-o/unwind.h diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 7f212dd3d27..2a65f47db40 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,16 @@ +2014-03-17 Tristan Gingold + + * od-macho.c (dump_section_header): Renames of dump_section. + (dump_segment): Adjust after renaming. + (OPT_COMPACT_UNWIND): Define. + (options): Add compact unwind. + (mach_o_help): Document compact_unwind. + (unwind_x86_64_regs, unwind_x86_regs): New arrays. + (dump_unwind_encoding_x86, dump_unwind_encoding) + (dump_obj_compact_unwind, dump_exe_compact_unwind) + (dump_section_content): New functions. + (mach_o_dump): Handle compact unwind. + 2014-03-17 Tristan Gingold * od-macho.c (dump_load_command): Handle lazy load dylib. diff --git a/binutils/od-macho.c b/binutils/od-macho.c index 45a0beb7ac4..7754f364032 100644 --- a/binutils/od-macho.c +++ b/binutils/od-macho.c @@ -31,6 +31,7 @@ #include "mach-o.h" #include "mach-o/external.h" #include "mach-o/codesign.h" +#include "mach-o/unwind.h" /* Index of the options in the options[] array. */ #define OPT_HEADER 0 @@ -40,6 +41,7 @@ #define OPT_DYSYMTAB 4 #define OPT_CODESIGN 5 #define OPT_SEG_SPLIT_INFO 6 +#define OPT_COMPACT_UNWIND 7 /* List of actions. */ static struct objdump_private_option options[] = @@ -51,6 +53,7 @@ static struct objdump_private_option options[] = { "dysymtab", 0 }, { "codesign", 0 }, { "seg_split_info", 0 }, + { "compact_unwind", 0 }, { NULL, 0 } }; @@ -68,6 +71,7 @@ For Mach-O files:\n\ dysymtab Display the dynamic symbol table\n\ codesign Display code signature\n\ seg_split_info Display segment split info\n\ + compact_unwind Display compact unwinding info\n\ ")); } @@ -322,7 +326,7 @@ dump_section_map (bfd *abfd) } static void -dump_section (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_section *sec) +dump_section_header (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_section *sec) { printf (" Section: %-16s %-16s (bfdname: %s)\n", sec->sectname, sec->segname, sec->bfdsection->name); @@ -391,7 +395,7 @@ dump_segment (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_load_command *cmd) printf (" nsects: %lu ", seg->nsects); printf (" flags: %lx\n", seg->flags); for (sec = seg->sect_head; sec != NULL; sec = sec->next) - dump_section (abfd, sec); + dump_section_header (abfd, sec); } static void @@ -1088,6 +1092,437 @@ dump_load_commands (bfd *abfd, unsigned int cmd32, unsigned int cmd64) } } +static const char * const unwind_x86_64_regs[] = + {"", "rbx", "r12", "r13", "r14", "r15", "rbp", "???" }; + +static const char * const unwind_x86_regs[] = + {"", "ebx", "ecx", "edx", "edi", "edi", "ebp", "???" }; + +/* Dump x86 or x86-64 compact unwind encoding. Works for both architecture, + as the encoding is the same (but not register names). */ + +static void +dump_unwind_encoding_x86 (unsigned int encoding, unsigned int sz, + const char * const regs_name[]) +{ + unsigned int mode; + + mode = encoding & MACH_O_UNWIND_X86_64_MODE_MASK; + switch (mode) + { + case MACH_O_UNWIND_X86_64_MODE_RBP_FRAME: + { + unsigned int regs; + char pfx = sz == 8 ? 'R' : 'E'; + + regs = encoding & MACH_O_UNWIND_X86_64_RBP_FRAME_REGSITERS; + printf (" %cSP frame", pfx); + if (regs != 0) + { + unsigned int offset; + int i; + + offset = (encoding & MACH_O_UNWIND_X86_64_RBP_FRAME_OFFSET) >> 16; + printf (" at %cBP-%u:", pfx, offset * sz); + for (i = 0; i < 5; i++) + { + unsigned int reg = (regs >> (i * 3)) & 0x7; + if (reg != MACH_O_UNWIND_X86_64_REG_NONE) + printf (" %s", regs_name[reg]); + } + } + } + break; + case MACH_O_UNWIND_X86_64_MODE_STACK_IMMD: + case MACH_O_UNWIND_X86_64_MODE_STACK_IND: + { + unsigned int stack_size; + unsigned int reg_count; + unsigned int reg_perm; + unsigned int regs[6]; + int i, j; + + printf (" frameless"); + stack_size = + (encoding & MACH_O_UNWIND_X86_64_FRAMELESS_STACK_SIZE) >> 16; + reg_count = + (encoding & MACH_O_UNWIND_X86_64_FRAMELESS_REG_COUNT) >> 10; + reg_perm = encoding & MACH_O_UNWIND_X86_64_FRAMELESS_REG_PERMUTATION; + + if (mode == MACH_O_UNWIND_X86_64_MODE_STACK_IMMD) + printf (" size: 0x%03x", stack_size * sz); + else + { + unsigned int stack_adj; + + stack_adj = + (encoding & MACH_O_UNWIND_X86_64_FRAMELESS_STACK_ADJUST) >> 13; + printf (" size at 0x%03x + 0x%02x", stack_size, stack_adj); + } + /* Registers are coded using arithmetic compression: the register + is indexed in range 0-6, the second in range 0-5, the third in + range 0-4, etc. Already used registers are removed in next + ranges. */ +#define DO_PERM(R, NUM) R = reg_perm / NUM; reg_perm -= R * NUM + switch (reg_count) + { + case 6: + case 5: + DO_PERM (regs[0], 120); + DO_PERM (regs[1], 24); + DO_PERM (regs[2], 6); + DO_PERM (regs[3], 2); + DO_PERM (regs[4], 1); + regs[5] = 0; /* Not used if reg_count = 5. */ + break; + case 4: + DO_PERM (regs[0], 60); + DO_PERM (regs[1], 12); + DO_PERM (regs[2], 3); + DO_PERM (regs[3], 1); + break; + case 3: + DO_PERM (regs[0], 20); + DO_PERM (regs[1], 4); + DO_PERM (regs[2], 1); + break; + case 2: + DO_PERM (regs[0], 5); + DO_PERM (regs[1], 1); + break; + case 1: + DO_PERM (regs[0], 1); + break; + case 0: + break; + default: + printf (" [bad reg count]"); + return; + } +#undef DO_PERM + /* Renumber. */ + for (i = reg_count - 1; i >= 0; i--) + { + unsigned int inc = 1; + for (j = 0; j < i; j++) + if (regs[i] >= regs[j]) + inc++; + regs[i] += inc; + } + /* Display. */ + for (i = 0; i < (int) reg_count; i++) + printf (" %s", regs_name[regs[i]]); + } + break; + case MACH_O_UNWIND_X86_64_MODE_DWARF: + printf (" Dwarf offset: 0x%06x", + encoding & MACH_O_UNWIND_X86_64_DWARF_SECTION_OFFSET); + break; + default: + printf (" [unhandled mode]"); + break; + } +} + +static void +dump_unwind_encoding (bfd_mach_o_data_struct *mdata, unsigned int encoding) +{ + printf ("0x%08x", encoding); + if (encoding == 0) + return; + + switch (mdata->header.cputype) + { + case BFD_MACH_O_CPU_TYPE_X86_64: + dump_unwind_encoding_x86 (encoding, 8, unwind_x86_64_regs); + break; + case BFD_MACH_O_CPU_TYPE_I386: + dump_unwind_encoding_x86 (encoding, 4, unwind_x86_regs); + break; + default: + printf (" [unhandled cpu]"); + break; + } + if (encoding & MACH_O_UNWIND_HAS_LSDA) + printf (" LSDA"); + if (encoding & MACH_O_UNWIND_PERSONALITY_MASK) + printf (" PERS(%u)", + ((encoding & MACH_O_UNWIND_PERSONALITY_MASK) + >> MACH_O_UNWIND_PERSONALITY_SHIFT)); +} + +static void +dump_obj_compact_unwind (bfd *abfd, + const unsigned char *content, bfd_size_type size) +{ + bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd); + int is_64 = mdata->header.version == 2; + const unsigned char *p; + + printf (" compact unwind info:\n"); + printf (" start length personality lsda\n"); + + if (is_64) + { + struct mach_o_compact_unwind_64 *e = + (struct mach_o_compact_unwind_64 *) content; + + for (p = content; p < content + size; p += sizeof (*e)) + { + e = (struct mach_o_compact_unwind_64 *) p; + + putchar (' '); + fprintf_vma (stdout, bfd_get_64 (abfd, e->start)); + printf (" %08lx", bfd_get_32 (abfd, e->length)); + putchar (' '); + fprintf_vma (stdout, bfd_get_64 (abfd, e->personnality)); + putchar (' '); + fprintf_vma (stdout, bfd_get_64 (abfd, e->lsda)); + putchar ('\n'); + + printf (" encoding: "); + dump_unwind_encoding (mdata, bfd_get_32 (abfd, e->encoding)); + putchar ('\n'); + } + } + else + { + printf ("unhandled\n"); + } +} + +static void +dump_exe_compact_unwind (bfd *abfd, + const unsigned char *content, bfd_size_type size) +{ + bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd); + struct mach_o_unwind_info_header *hdr; + unsigned int version; + unsigned int encodings_offset; + unsigned int encodings_count; + unsigned int personality_offset; + unsigned int personality_count; + unsigned int index_offset; + unsigned int index_count; + struct mach_o_unwind_index_entry *index_entry; + unsigned int i; + + /* The header. */ + printf (" compact unwind info:\n"); + + hdr = (struct mach_o_unwind_info_header *) content; + if (size < sizeof (*hdr)) + { + printf (" truncated!\n"); + return; + } + + version = bfd_get_32 (abfd, hdr->version); + if (version != MACH_O_UNWIND_SECTION_VERSION) + { + printf (" unknown version: %u\n", version); + return; + } + encodings_offset = bfd_get_32 (abfd, hdr->encodings_array_offset); + encodings_count = bfd_get_32 (abfd, hdr->encodings_array_count); + personality_offset = bfd_get_32 (abfd, hdr->personality_array_offset); + personality_count = bfd_get_32 (abfd, hdr->personality_array_count); + index_offset = bfd_get_32 (abfd, hdr->index_offset); + index_count = bfd_get_32 (abfd, hdr->index_count); + printf (" %u encodings, %u personalities, %u level-1 indexes:\n", + encodings_count, personality_count, index_count); + + /* Level-1 index. */ + printf (" idx function level2 off lsda off\n"); + + index_entry = (struct mach_o_unwind_index_entry *) (content + index_offset); + for (i = 0; i < index_count; i++) + { + unsigned int func_offset; + unsigned int level2_offset; + unsigned int lsda_offset; + + func_offset = bfd_get_32 (abfd, index_entry->function_offset); + level2_offset = bfd_get_32 (abfd, index_entry->second_level_offset); + lsda_offset = bfd_get_32 (abfd, index_entry->lsda_index_offset); + printf (" %3u 0x%08x 0x%08x 0x%08x\n", + i, func_offset, level2_offset, lsda_offset); + index_entry++; + } + + /* Level-1 index. */ + index_entry = (struct mach_o_unwind_index_entry *) (content + index_offset); + for (i = 0; i < index_count; i++) + { + unsigned int func_offset; + unsigned int level2_offset; + const unsigned char *level2; + unsigned int kind; + + if (i == index_count - 1) + break; + + func_offset = bfd_get_32 (abfd, index_entry->function_offset); + level2_offset = bfd_get_32 (abfd, index_entry->second_level_offset); + + level2 = content + level2_offset; + kind = bfd_get_32 (abfd, level2); + switch (kind) + { + case MACH_O_UNWIND_SECOND_LEVEL_COMPRESSED: + { + struct mach_o_unwind_compressed_second_level_page_header *l2; + unsigned int entry_offset; + unsigned int entry_count; + unsigned int l2_encodings_offset; + unsigned int l2_encodings_count; + const unsigned char *en; + unsigned int j; + + l2 = (struct mach_o_unwind_compressed_second_level_page_header *) + level2; + entry_offset = bfd_get_16 (abfd, l2->entry_page_offset); + entry_count = bfd_get_16 (abfd, l2->entry_count); + l2_encodings_offset = bfd_get_16 (abfd, l2->encodings_offset); + l2_encodings_count = bfd_get_16 (abfd, l2->encodings_count); + + printf (" index %2u: compressed second level: " + "%u entries, %u encodings (at 0x%08x)\n", + i, entry_count, l2_encodings_count, l2_encodings_offset); + printf (" # function eidx encoding\n"); + + en = level2 + entry_offset; + for (j = 0; j < entry_count; j++) + { + unsigned int entry; + unsigned int en_func; + unsigned int enc_idx; + unsigned int encoding; + const unsigned char *enc_addr; + + entry = bfd_get_32 (abfd, en); + en_func = + MACH_O_UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry); + enc_idx = + MACH_O_UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry); + if (enc_idx < encodings_count) + enc_addr = content + encodings_offset + + 4 * enc_idx; + else + enc_addr = level2 + l2_encodings_offset + + 4 * (enc_idx - encodings_count); + encoding = bfd_get_32 (abfd, enc_addr); + + printf (" %-4u 0x%08x [%3u] ", j, + func_offset + en_func, enc_idx); + dump_unwind_encoding (mdata, encoding); + putchar ('\n'); + + en += 4; + } + } + break; + + case MACH_O_UNWIND_SECOND_LEVEL_REGULAR: + { + struct mach_o_unwind_regular_second_level_page_header *l2; + struct mach_o_unwind_regular_second_level_entry *en; + unsigned int entry_offset; + unsigned int entry_count; + unsigned int j; + + l2 = (struct mach_o_unwind_regular_second_level_page_header *) + level2; + + entry_offset = bfd_get_16 (abfd, l2->entry_page_offset); + entry_count = bfd_get_16 (abfd, l2->entry_count); + printf (" index %2u: regular level 2 at 0x%04x, %u entries\n", + i, entry_offset, entry_count); + printf (" # function encoding\n"); + + en = (struct mach_o_unwind_regular_second_level_entry *) + (level2 + entry_offset); + for (j = 0; j < entry_count; j++) + { + unsigned int en_func; + unsigned int encoding; + + en_func = bfd_get_32 (abfd, en->function_offset); + encoding = bfd_get_32 (abfd, en->encoding); + printf (" %-4u 0x%08x ", j, en_func); + dump_unwind_encoding (mdata, encoding); + putchar ('\n'); + en++; + } + } + break; + + default: + printf (" index %2u: unhandled second level format (%u)\n", + i, kind); + break; + } + + { + struct mach_o_unwind_lsda_index_entry *lsda; + unsigned int lsda_offset; + unsigned int next_lsda_offset; + unsigned int nbr_lsda; + unsigned int j; + + lsda_offset = bfd_get_32 (abfd, index_entry->lsda_index_offset); + next_lsda_offset = bfd_get_32 (abfd, index_entry[1].lsda_index_offset); + lsda = (struct mach_o_unwind_lsda_index_entry *) + (content + lsda_offset); + nbr_lsda = (next_lsda_offset - lsda_offset) / sizeof (*lsda); + for (j = 0; j < nbr_lsda; j++) + { + printf (" lsda %-3u: function 0x%08x lsda 0x%08x\n", + j, (unsigned int) bfd_get_32 (abfd, lsda->function_offset), + (unsigned int) bfd_get_32 (abfd, lsda->lsda_offset)); + lsda++; + } + } + index_entry++; + } +} + +static void +dump_section_content (bfd *abfd, + const char *segname, const char *sectname, + void (*dump)(bfd*, const unsigned char*, bfd_size_type)) +{ + bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd); + unsigned int i; + + for (i = 0; i < mdata->header.ncmds; i++) + { + bfd_mach_o_load_command *cmd = &mdata->commands[i]; + if (cmd->type == BFD_MACH_O_LC_SEGMENT + || cmd->type == BFD_MACH_O_LC_SEGMENT_64) + { + bfd_mach_o_segment_command *seg = &cmd->command.segment; + bfd_mach_o_section *sec; + for (sec = seg->sect_head; sec != NULL; sec = sec->next) + if (strcmp (sec->segname, segname) == 0 + && strcmp (sec->sectname, sectname) == 0) + { + bfd_size_type size; + asection *bfdsec = sec->bfdsection; + unsigned char *content; + + size = bfd_get_section_size (bfdsec); + content = (unsigned char *) xmalloc (size); + bfd_get_section_contents (abfd, bfdsec, content, 0, size); + + (*dump)(abfd, content, size); + + free (content); + } + } + } +} + /* Dump ABFD (according to the options[] array). */ static void @@ -1107,6 +1542,13 @@ mach_o_dump (bfd *abfd) dump_load_commands (abfd, BFD_MACH_O_LC_CODE_SIGNATURE, 0); if (options[OPT_SEG_SPLIT_INFO].selected) dump_load_commands (abfd, BFD_MACH_O_LC_SEGMENT_SPLIT_INFO, 0); + if (options[OPT_COMPACT_UNWIND].selected) + { + dump_section_content (abfd, "__LD", "__compact_unwind", + dump_obj_compact_unwind); + dump_section_content (abfd, "__TEXT", "__unwind_info", + dump_exe_compact_unwind); + } } /* Vector for Mach-O. */ diff --git a/include/mach-o/ChangeLog b/include/mach-o/ChangeLog index 5be7170f4fb..c4a4a2c300f 100644 --- a/include/mach-o/ChangeLog +++ b/include/mach-o/ChangeLog @@ -1,3 +1,7 @@ +2014-03-17 Tristan Gingold + + * unwind.h: New file. + 2014-03-05 Alan Modra Update copyright years. diff --git a/include/mach-o/unwind.h b/include/mach-o/unwind.h new file mode 100644 index 00000000000..f67c75b1f75 --- /dev/null +++ b/include/mach-o/unwind.h @@ -0,0 +1,199 @@ +/* Mach-O compact unwind encoding. + Copyright (C) 2014 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef _MACH_O_UNWIND_H +#define _MACH_O_UNWIND_H + +/* Encodings bits for all cpus. */ +#define MACH_O_UNWIND_IS_NOT_FUNCTION_START 0x80000000 +#define MACH_O_UNWIND_HAS_LSDA 0x40000000 +#define MACH_O_UNWIND_PERSONALITY_MASK 0x30000000 +#define MACH_O_UNWIND_PERSONALITY_SHIFT 28 + +/* Encodings for x86-64. */ + +/* Kind of encoding (4 bits). */ +#define MACH_O_UNWIND_X86_64_MODE_MASK 0x0f000000 + +/* Frame is RBP based, using the standard sequence: push %rbp; mov %rsp, %rbp. + Non-volatile registers must be saved in the stack starting at %rbp-8 to + %rbp-2040 (offset is encoded in offset bits * 8). Registers saved are + encoded in registers bits, 3 bits per register. */ +#define MACH_O_UNWIND_X86_64_MODE_RBP_FRAME 0x01000000 +#define MACH_O_UNWIND_X86_64_RBP_FRAME_REGSITERS 0x00007FFF +#define MACH_O_UNWIND_X86_64_RBP_FRAME_OFFSET 0x00FF0000 + +/* Frameless function, with a small stack size. */ +#define MACH_O_UNWIND_X86_64_MODE_STACK_IMMD 0x02000000 +#define MACH_O_UNWIND_X86_64_FRAMELESS_STACK_SIZE 0x00FF0000 +#define MACH_O_UNWIND_X86_64_FRAMELESS_REG_COUNT 0x00001C00 +#define MACH_O_UNWIND_X86_64_FRAMELESS_REG_PERMUTATION 0x000003FF + +/* Frameless function, with a larger stack size. The stack size is the sum + of the X in subq $X,%rsp (address of X is at function + stack size bits) + and stack adjust. */ +#define MACH_O_UNWIND_X86_64_MODE_STACK_IND 0x03000000 +#define MACH_O_UNWIND_X86_64_FRAMELESS_STACK_ADJUST 0x0000E000 + +/* Use dwarf. */ +#define MACH_O_UNWIND_X86_64_MODE_DWARF 0x04000000 +#define MACH_O_UNWIND_X86_64_DWARF_SECTION_OFFSET 0x00ffffff + +/* Registers. */ +#define MACH_O_UNWIND_X86_64_REG_NONE 0 +#define MACH_O_UNWIND_X86_64_REG_RBX 1 +#define MACH_O_UNWIND_X86_64_REG_R12 2 +#define MACH_O_UNWIND_X86_64_REG_R13 3 +#define MACH_O_UNWIND_X86_64_REG_R14 4 +#define MACH_O_UNWIND_X86_64_REG_R15 5 +#define MACH_O_UNWIND_X86_64_REG_RBP 6 + +/* Encodings for x86 (almot the same as x86-64). */ + +/* Kind of encoding (4 bits). */ +#define MACH_O_UNWIND_X86_MODE_MASK 0x0f000000 + +/* Frame is EBP based, using the standard sequence: push %ebp; mov %esp, %ebp. + Non-volatile registers must be saved in the stack starting at %ebp-4 to + %ebp-240 (offset is encoded in offset bits * 4). Registers saved are + encoded in registers bits, 3 bits per register. */ +#define MACH_O_UNWIND_X86_MODE_EBP_FRAME 0x01000000 +#define MACH_O_UNWIND_X86_EBP_FRAME_REGSITERS 0x00007FFF +#define MACH_O_UNWIND_X86_EBP_FRAME_OFFSET 0x00FF0000 + +/* Frameless function, with a small stack size. */ +#define MACH_O_UNWIND_X86_MODE_STACK_IMMD 0x02000000 +#define MACH_O_UNWIND_X86_FRAMELESS_STACK_SIZE 0x00FF0000 +#define MACH_O_UNWIND_X86_FRAMELESS_REG_COUNT 0x00001C00 +#define MACH_O_UNWIND_X86_FRAMELESS_REG_PERMUTATION 0x000003FF + +/* Frameless function, with a larger stack size. The stack size is the sum + of the X in subq $X,%esp (address of X is at function + stack size bits) + and stack adjust. */ +#define MACH_O_UNWIND_X86_MODE_STACK_IND 0x03000000 +#define MACH_O_UNWIND_X86_FRAMELESS_STACK_ADJUST 0x0000E000 + +/* Use dwarf. */ +#define MACH_O_UNWIND_X86_MODE_DWARF 0x04000000 +#define MACH_O_UNWIND_X86_DWARF_SECTION_OFFSET 0x00ffffff + +/* Registers. */ +#define MACH_O_UNWIND_X86_REG_NONE 0 +#define MACH_O_UNWIND_X86_REG_EBX 1 +#define MACH_O_UNWIND_X86_REG_ECX 2 +#define MACH_O_UNWIND_X86_REG_EDX 3 +#define MACH_O_UNWIND_X86_REG_EDI 4 +#define MACH_O_UNWIND_X86_REG_ESI 5 +#define MACH_O_UNWIND_X86_REG_EBP 6 + +/* Entry in object file (in __LD,__compact_unwind section). */ + +struct mach_o_compact_unwind_32 +{ + unsigned char start[4]; + unsigned char length[4]; + unsigned char encoding[4]; + unsigned char personality[4]; + unsigned char lsda[4]; +}; + +struct mach_o_compact_unwind_64 +{ + unsigned char start[8]; + unsigned char length[4]; + unsigned char encoding[4]; + unsigned char personnality[8]; + unsigned char lsda[8]; +}; + +/* Header in images (in __TEXT,__unwind_info). */ + +#define MACH_O_UNWIND_SECTION_VERSION 1 /* Current verion in header. */ +struct mach_o_unwind_info_header +{ + unsigned char version[4]; /* Currently MACH_O_UNWIND_SECTION_VERSION. */ + unsigned char encodings_array_offset[4]; + unsigned char encodings_array_count[4]; + unsigned char personality_array_offset[4]; + unsigned char personality_array_count[4]; + unsigned char index_offset[4]; + unsigned char index_count[4]; + /* Followed by: + - encodings array + These are the encodings shared, for index < encoding_array_count + - personality array + count given by personality_array_count + - index entries + count given by index_count + - lsda index entries + last offset given by lsda offset of last index_entry. + */ +}; + +struct mach_o_unwind_index_entry +{ + unsigned char function_offset[4]; + unsigned char second_level_offset[4]; + unsigned char lsda_index_offset[4]; +}; + +struct mach_o_unwind_lsda_index_entry +{ + unsigned char function_offset[4]; + unsigned char lsda_offset[4]; +}; + +/* Second level index pages. */ + +#define MACH_O_UNWIND_SECOND_LEVEL_REGULAR 2 +struct mach_o_unwind_regular_second_level_page_header +{ + unsigned char kind[4]; + unsigned char entry_page_offset[2]; + unsigned char entry_count[2]; + /* Array of entries. */ +}; + +struct mach_o_unwind_regular_second_level_entry +{ + unsigned char function_offset[4]; + unsigned char encoding[4]; +}; + +#define MACH_O_UNWIND_SECOND_LEVEL_COMPRESSED 3 +struct mach_o_unwind_compressed_second_level_page_header +{ + unsigned char kind[4]; + unsigned char entry_page_offset[2]; + unsigned char entry_count[2]; + unsigned char encodings_offset[2]; + unsigned char encodings_count[2]; + /* Followed by entries array (one word, see below). */ + /* Followed by (non-common) encodings array. */ +}; + +/* Compressed entries are one word, containing function offset and encoding + index. */ +#define MACH_O_UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(en) \ + ((en) & 0x00FFFFFF) +#define MACH_O_UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(en) \ + (((en) >> 24) & 0xFF) + +#endif /* _MACH_O_UNWIND_H */ -- 2.30.2