mach-o: display data_in_code.
[deliverable/binutils-gdb.git] / binutils / od-macho.c
index 7754f364032198bd0ef04122ee880d29334a0333..31cce9dab3f77f264a0acb11401e20871972272e 100644 (file)
@@ -42,6 +42,8 @@
 #define OPT_CODESIGN 5
 #define OPT_SEG_SPLIT_INFO 6
 #define OPT_COMPACT_UNWIND 7
+#define OPT_FUNCTION_STARTS 8
+#define OPT_DATA_IN_CODE 9
 
 /* List of actions.  */
 static struct objdump_private_option options[] =
@@ -54,6 +56,8 @@ static struct objdump_private_option options[] =
     { "codesign", 0 },
     { "seg_split_info", 0 },
     { "compact_unwind", 0 },
+    { "function_starts", 0 },
+    { "data_in_code", 0 },
     { NULL, 0 }
   };
 
@@ -64,14 +68,16 @@ mach_o_help (FILE *stream)
 {
   fprintf (stream, _("\
 For Mach-O files:\n\
-  header         Display the file header\n\
-  section        Display the segments and sections commands\n\
-  map            Display the section map\n\
-  load           Display the load commands\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\
+  header           Display the file header\n\
+  section          Display the segments and sections commands\n\
+  map              Display the section map\n\
+  load             Display the load commands\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\
+  function_starts  Display start address of functions\n\
+  data_in_code     Display data in code entries\n\
 "));
 }
 
@@ -99,6 +105,7 @@ static const bfd_mach_o_xlat_name bfd_mach_o_cpu_name[] =
   { "powerpc", BFD_MACH_O_CPU_TYPE_POWERPC },
   { "powerpc_64", BFD_MACH_O_CPU_TYPE_POWERPC_64 },
   { "x86_64", BFD_MACH_O_CPU_TYPE_X86_64 },
+  { "arm64", BFD_MACH_O_CPU_TYPE_ARM64 },
   { NULL, 0}
 };
 
@@ -280,6 +287,15 @@ dump_header (bfd *abfd)
   bfd_mach_o_print_flags (bfd_mach_o_header_flags_name, h->flags);
   fputs (_(")\n"), stdout);
   printf (_(" reserved  : %08x\n"), h->reserved);
+  putchar ('\n');
+}
+
+static void
+disp_segment_prot (unsigned int prot)
+{
+  putchar (prot & BFD_MACH_O_PROT_READ ? 'r' : '-');
+  putchar (prot & BFD_MACH_O_PROT_WRITE ? 'w' : '-');
+  putchar (prot & BFD_MACH_O_PROT_EXECUTE ? 'x' : '-');
 }
 
 static void
@@ -308,9 +324,7 @@ dump_section_map (bfd *abfd)
       putchar ('-');
       printf_vma  (seg->vmaddr + seg->vmsize - 1);
       putchar (' ');
-      putchar (seg->initprot & BFD_MACH_O_PROT_READ ? 'r' : '-');
-      putchar (seg->initprot & BFD_MACH_O_PROT_WRITE ? 'w' : '-');
-      putchar (seg->initprot & BFD_MACH_O_PROT_EXECUTE ? 'x' : '-');
+      disp_segment_prot (seg->initprot);
       printf ("]\n");
 
       for (sec = seg->sect_head; sec != NULL; sec = sec->next)
@@ -392,8 +406,13 @@ dump_segment (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_load_command *cmd)
   printf (" endoff: ");
   printf_vma ((bfd_vma)(seg->fileoff + seg->filesize));
   printf ("\n");
-  printf ("   nsects: %lu  ", seg->nsects);
-  printf (" flags: %lx\n", seg->flags);
+  printf ("   nsects: %lu", seg->nsects);
+  printf ("   flags: %lx", seg->flags);
+  printf ("   initprot: ");
+  disp_segment_prot (seg->initprot);
+  printf ("   maxprot: ");
+  disp_segment_prot (seg->maxprot);
+  printf ("\n");
   for (sec = seg->sect_head; sec != NULL; sec = sec->next)
     dump_section_header (abfd, sec);
 }
@@ -910,6 +929,108 @@ dump_segment_split_info (bfd *abfd, bfd_mach_o_linkedit_command *cmd)
   free (buf);
 }
 
+static void
+dump_function_starts (bfd *abfd, bfd_mach_o_linkedit_command *cmd)
+{
+  unsigned char *buf = xmalloc (cmd->datasize);
+  unsigned char *end_buf = buf + cmd->datasize;
+  unsigned char *p;
+  bfd_vma addr;
+
+  if (bfd_seek (abfd, cmd->dataoff, SEEK_SET) != 0
+      || bfd_bread (buf, cmd->datasize, abfd) != cmd->datasize)
+    {
+      non_fatal (_("cannot read function starts"));
+      free (buf);
+      return;
+    }
+
+  /* Function starts are delta encoded, starting from the base address.  */
+  addr = bfd_mach_o_get_base_address (abfd);
+
+  for (p = buf; ;)
+    {
+      bfd_vma delta = 0;
+      unsigned int shift = 0;
+
+      if (*p == 0 || p == end_buf)
+       break;
+      while (1)
+       {
+         unsigned char b = *p++;
+
+         delta |= (b & 0x7f) << shift;
+         if ((b & 0x80) == 0)
+           break;
+         if (p == end_buf)
+           {
+             fputs ("   [truncated]\n", stdout);
+             break;
+           }
+         shift += 7;
+       }
+
+      addr += delta;
+      fputs ("    ", stdout);
+      bfd_printf_vma (abfd, addr);
+      putchar ('\n');
+    }
+  free (buf);
+}
+
+static const bfd_mach_o_xlat_name data_in_code_kind_name[] =
+{
+  { "data", BFD_MACH_O_DICE_KIND_DATA },
+  { "1 byte jump table", BFD_MACH_O_DICE_JUMP_TABLES8 },
+  { "2 bytes jump table", BFD_MACH_O_DICE_JUMP_TABLES16 },
+  { "4 bytes jump table", BFD_MACH_O_DICE_JUMP_TABLES32 },
+  { "4 bytes abs jump table", BFD_MACH_O_DICE_ABS_JUMP_TABLES32 },
+  { NULL, 0 }
+};
+
+static void
+dump_data_in_code (bfd *abfd, bfd_mach_o_linkedit_command *cmd)
+{
+  unsigned char *buf;
+  unsigned char *p;
+
+  if (cmd->datasize == 0)
+    {
+      printf ("   no data_in_code entries\n");
+      return;
+    }
+
+  buf = xmalloc (cmd->datasize);
+  if (bfd_seek (abfd, cmd->dataoff, SEEK_SET) != 0
+      || bfd_bread (buf, cmd->datasize, abfd) != cmd->datasize)
+    {
+      non_fatal (_("cannot read function starts"));
+      free (buf);
+      return;
+    }
+
+  printf ("   offset     length kind\n");
+  for (p = buf; p < buf + cmd->datasize; )
+    {
+      struct mach_o_data_in_code_entry_external *dice;
+      unsigned int offset;
+      unsigned int length;
+      unsigned int kind;
+
+      dice = (struct mach_o_data_in_code_entry_external *) p;
+
+      offset = bfd_get_32 (abfd, dice->offset);
+      length = bfd_get_16 (abfd, dice->length);
+      kind = bfd_get_16 (abfd, dice->kind);
+
+      printf ("   0x%08x 0x%04x 0x%04x %s\n", offset, length, kind,
+             bfd_mach_o_get_name (data_in_code_kind_name, kind));
+
+      p += sizeof (*dice);
+    }
+  free (buf);
+}
+
 static void
 dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
                    bfd_boolean verbose)
@@ -962,6 +1083,10 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
     case BFD_MACH_O_LC_ID_DYLINKER:
       printf (" %s\n", cmd->command.dylinker.name_str);
       break;
+    case BFD_MACH_O_LC_DYLD_ENVIRONMENT:
+      putchar ('\n');
+      printf ("  %s\n", cmd->command.dylinker.name_str);
+      break;
     case BFD_MACH_O_LC_SYMTAB:
       {
         bfd_mach_o_symtab_command *symtab = &cmd->command.symtab;
@@ -992,6 +1117,8 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
     case BFD_MACH_O_LC_CODE_SIGNATURE:
     case BFD_MACH_O_LC_SEGMENT_SPLIT_INFO:
     case BFD_MACH_O_LC_FUNCTION_STARTS:
+    case BFD_MACH_O_LC_DATA_IN_CODE:
+    case BFD_MACH_O_LC_DYLIB_CODE_SIGN_DRS:
       {
         bfd_mach_o_linkedit_command *linkedit = &cmd->command.linkedit;
         printf
@@ -1000,12 +1127,26 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
            linkedit->dataoff, linkedit->datasize,
            linkedit->dataoff + linkedit->datasize);
 
-        if (verbose && cmd->type == BFD_MACH_O_LC_CODE_SIGNATURE)
-          dump_code_signature (abfd, linkedit);
-        else if (verbose && cmd->type == BFD_MACH_O_LC_SEGMENT_SPLIT_INFO)
-          dump_segment_split_info (abfd, linkedit);
-        break;
+       if (verbose)
+         switch (cmd->type)
+           {
+           case BFD_MACH_O_LC_CODE_SIGNATURE:
+             dump_code_signature (abfd, linkedit);
+             break;
+           case BFD_MACH_O_LC_SEGMENT_SPLIT_INFO:
+             dump_segment_split_info (abfd, linkedit);
+             break;
+           case BFD_MACH_O_LC_FUNCTION_STARTS:
+             dump_function_starts (abfd, linkedit);
+             break;
+           case BFD_MACH_O_LC_DATA_IN_CODE:
+             dump_data_in_code (abfd, linkedit);
+             break;
+           default:
+             break;
+           }
       }
+      break;
     case BFD_MACH_O_LC_SUB_FRAMEWORK:
     case BFD_MACH_O_LC_SUB_UMBRELLA:
     case BFD_MACH_O_LC_SUB_LIBRARY:
@@ -1157,7 +1298,7 @@ dump_unwind_encoding_x86 (unsigned int encoding, unsigned int sz,
 
            stack_adj =
              (encoding & MACH_O_UNWIND_X86_64_FRAMELESS_STACK_ADJUST) >> 13;
-           printf (" size at 0x%03x + 0x%02x", stack_size, stack_adj);
+           printf (" size at 0x%03x + 0x%02x", stack_size, stack_adj * sz);
          }
        /* Registers are coded using arithmetic compression: the register
           is indexed in range 0-6, the second in range 0-5, the third in
@@ -1259,7 +1400,7 @@ dump_obj_compact_unwind (bfd *abfd,
   int is_64 = mdata->header.version == 2;
   const unsigned char *p;
 
-  printf (" compact unwind info:\n");
+  printf ("Compact unwind info:\n");
   printf (" start            length   personality      lsda\n");
 
   if (is_64)
@@ -1308,7 +1449,7 @@ dump_exe_compact_unwind (bfd *abfd,
   unsigned int i;
 
   /* The header.  */
-  printf (" compact unwind info:\n");
+  printf ("Compact unwind info:\n");
 
   hdr = (struct mach_o_unwind_info_header *) content;
   if (size < sizeof (*hdr))
@@ -1359,12 +1500,13 @@ dump_exe_compact_unwind (bfd *abfd,
       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);
 
+      /* No level-2 for this index (should be the last index).  */
+      if (level2_offset == 0)
+       continue;
+
       level2 = content + level2_offset;
       kind = bfd_get_32 (abfd, level2);
       switch (kind)
@@ -1477,7 +1619,7 @@ dump_exe_compact_unwind (bfd *abfd,
        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",
+           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++;
@@ -1542,6 +1684,10 @@ 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_FUNCTION_STARTS].selected)
+    dump_load_commands (abfd, BFD_MACH_O_LC_FUNCTION_STARTS, 0);
+  if (options[OPT_DATA_IN_CODE].selected)
+    dump_load_commands (abfd, BFD_MACH_O_LC_DATA_IN_CODE, 0);
   if (options[OPT_COMPACT_UNWIND].selected)
     {
       dump_section_content (abfd, "__LD", "__compact_unwind",
This page took 0.026423 seconds and 4 git commands to generate.