od-macho: dump compact unwind info.
authorTristan Gingold <tristan.gingold@adacore.com>
Mon, 17 Mar 2014 08:46:36 +0000 (09:46 +0100)
committerTristan Gingold <tristan.gingold@adacore.com>
Mon, 17 Mar 2014 09:29:07 +0000 (10:29 +0100)
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
binutils/od-macho.c
include/mach-o/ChangeLog
include/mach-o/unwind.h [new file with mode: 0644]

index 7f212dd3d27ff997a09af0443ae023e4ba512154..2a65f47db40401f38e921f44e5b5311c2307fa49 100644 (file)
@@ -1,3 +1,16 @@
+2014-03-17  Tristan Gingold  <gingold@adacore.com>
+
+       * 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  <gingold@adacore.com>
 
        * od-macho.c (dump_load_command): Handle lazy load dylib.
index 45a0beb7ac45195f2a1a56fd4372b1c5092275be..7754f364032198bd0ef04122ee880d29334a0333 100644 (file)
@@ -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.  */
index 5be7170f4fb12d4c01da9462764bb8340765e688..c4a4a2c300f0ef8076c58bca1fdecca12b91b46d 100644 (file)
@@ -1,3 +1,7 @@
+2014-03-17  Tristan Gingold  <gingold@adacore.com>
+
+       * unwind.h: New file.
+
 2014-03-05  Alan Modra  <amodra@gmail.com>
 
        Update copyright years.
diff --git a/include/mach-o/unwind.h b/include/mach-o/unwind.h
new file mode 100644 (file)
index 0000000..f67c75b
--- /dev/null
@@ -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 */