Mach-O: add objdump -P function_starts to display function starts.
authorTristan Gingold <tristan.gingold@adacore.com>
Tue, 25 Mar 2014 14:51:54 +0000 (15:51 +0100)
committerTristan Gingold <tristan.gingold@adacore.com>
Thu, 27 Mar 2014 09:23:22 +0000 (10:23 +0100)
bfd/
* mach-o.h (bfd_mach_o_get_base_address): New prototype.
* mach-o.c (bfd_mach_o_write_symtab)
(bfd_mach_o_write_contents)
(bfd_mach_o_set_section_flags_from_bfd)
(bfd_mach_o_build_seg_command): Fix indentation.
(bfd_mach_o_get_base_address): New function.

binutils/
* od-macho.c (OPT_FUNCTION_STARTS): New macro.
(options): Add entry for function_starts.
(mach_o_help): Ditto.
(disp_segment_prot): New function.
(dump_section_map): Call disp_segment_prot.
(dump_function_starts): New function.
(dump_obj_compact_unwind): Fix ouput indentation.
(dump_exe_compact_unwind): Fix ouput indentation.
(mach_o_dump): Handle function_starts.

bfd/ChangeLog
bfd/mach-o.c
bfd/mach-o.h
binutils/ChangeLog
binutils/od-macho.c

index f2b5f9c4aca13901e1296d504094a37f0c64c167..54b783417e5dd134b63efc20b5eee17f92b1097d 100644 (file)
@@ -1,3 +1,12 @@
+2014-03-27  Tristan Gingold  <gingold@adacore.com>
+
+       * mach-o.h (bfd_mach_o_get_base_address): New prototype.
+       * mach-o.c (bfd_mach_o_write_symtab)
+       (bfd_mach_o_write_contents)
+       (bfd_mach_o_set_section_flags_from_bfd)
+       (bfd_mach_o_build_seg_command): Fix indentation.
+       (bfd_mach_o_get_base_address): New function.
+
 2014-03-26  Nick Clifton  <nickc@redhat.com>
 
        * cofflink.c (_bfd_coff_generic_relocate_section): Skip
index 62376020215bb41b873df5c38f8bc66c583ba8f0..8e8842bdb24109ea1ab97bb150ac70c7278a0520 100644 (file)
@@ -1478,7 +1478,7 @@ bfd_mach_o_write_symtab (bfd *abfd, bfd_mach_o_load_command *command)
   BFD_ASSERT (command->type == BFD_MACH_O_LC_SYMTAB);
 
   /* Write the symbols first.  */
-  mdata->filelen = FILE_ALIGN(mdata->filelen, wide ? 3 : 2);
+  mdata->filelen = FILE_ALIGN (mdata->filelen, wide ? 3 : 2);
   sym->symoff = mdata->filelen;
   if (bfd_seek (abfd, sym->symoff, SEEK_SET) != 0)
     return FALSE;
@@ -2018,8 +2018,9 @@ bfd_mach_o_write_contents (bfd *abfd)
        case BFD_MACH_O_LC_SUB_FRAMEWORK:
          break;
        default:
-         (*_bfd_error_handler) (_("unable to write unknown load command 0x%lx"),
-                                (unsigned long) cur->type);
+         (*_bfd_error_handler)
+           (_("unable to write unknown load command 0x%lx"),
+            (unsigned long) cur->type);
          return FALSE;
        }
     }
@@ -2042,7 +2043,8 @@ bfd_mach_o_append_section_to_segment (bfd_mach_o_segment_command *seg,
 /* Create section Mach-O flags from BFD flags.  */
 
 static void
-bfd_mach_o_set_section_flags_from_bfd (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+bfd_mach_o_set_section_flags_from_bfd (bfd *abfd ATTRIBUTE_UNUSED,
+                                      asection *sec)
 {
   flagword bfd_flags;
   bfd_mach_o_section *s = bfd_mach_o_get_mach_o_section (sec);
@@ -2173,7 +2175,8 @@ bfd_mach_o_build_seg_command (const char *segment,
       mdata->filelen += s->size;
     }
 
-  /* Now pass through again, for zerofill, only now we just update the vmsize.  */
+  /* Now pass through again, for zerofill, only now we just update the
+     vmsize.  */
   for (i = 0; i < mdata->nsects; ++i)
     {
       bfd_mach_o_section *s = mdata->sections[i];
@@ -4274,6 +4277,35 @@ bfd_mach_o_gen_core_p (bfd *abfd)
   return bfd_mach_o_header_p (abfd, BFD_MACH_O_MH_CORE, 0);
 }
 
+/* Return the base address of ABFD, ie the address at which the image is
+   mapped.  The possible initial pagezero is ignored.  */
+
+bfd_vma
+bfd_mach_o_get_base_address (bfd *abfd)
+{
+  bfd_mach_o_data_struct *mdata;
+  unsigned int i;
+
+  /* Check for Mach-O.  */
+  if (!bfd_mach_o_valid (abfd))
+    return 0;
+  mdata = bfd_mach_o_get_data (abfd);
+
+  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))
+       {
+         struct bfd_mach_o_segment_command *segcmd = &cmd->command.segment;
+
+         if (segcmd->initprot != 0)
+           return segcmd->vmaddr;
+       }
+    }
+  return 0;
+}
+
 typedef struct mach_o_fat_archentry
 {
   unsigned long cputype;
index 6f695c578940489e64a8a55e490f8b6f8d467bee..4418b9287b66ec33ee369b94f9772e7c6dc54089 100644 (file)
@@ -656,6 +656,8 @@ unsigned int bfd_mach_o_section_get_entry_size (bfd *, bfd_mach_o_section *);
 bfd_boolean bfd_mach_o_read_symtab_symbols (bfd *);
 bfd_boolean bfd_mach_o_read_symtab_strtab (bfd *abfd);
 
+bfd_vma bfd_mach_o_get_base_address (bfd *);
+
 /* A placeholder in case we need to suppress emitting the dysymtab for some
    reason (e.g. compatibility with older system versions).  */
 #define bfd_mach_o_should_emit_dysymtab(x) TRUE
index b9fa77d371e65c1fdb01223d4ca1da7d08083485..975979dcb2b833fa5a1a8703092d8586fd6f4e31 100644 (file)
@@ -1,3 +1,15 @@
+2014-03-27  Tristan Gingold  <gingold@adacore.com>
+
+       * od-macho.c (OPT_FUNCTION_STARTS): New macro.
+       (options): Add entry for function_starts.
+       (mach_o_help): Ditto.
+       (disp_segment_prot): New function.
+       (dump_section_map): Call disp_segment_prot.
+       (dump_function_starts): New function.
+       (dump_obj_compact_unwind): Fix ouput indentation.
+       (dump_exe_compact_unwind): Fix ouput indentation.
+       (mach_o_dump): Handle function_starts.
+
 2014-03-26  Tristan Gingold  <gingold@adacore.com>
 
        * od-macho.c (bfd_mach_o_cpu_name): Add BFD_MACH_O_CPU_TYPE_ARM64.
index 6f881129b6ed22c5f25c2a1961b42b2cb0890286..4733e873a64ea1792d195084434424138dbb5486 100644 (file)
@@ -42,6 +42,7 @@
 #define OPT_CODESIGN 5
 #define OPT_SEG_SPLIT_INFO 6
 #define OPT_COMPACT_UNWIND 7
+#define OPT_FUNCTION_STARTS 8
 
 /* List of actions.  */
 static struct objdump_private_option options[] =
@@ -54,6 +55,7 @@ static struct objdump_private_option options[] =
     { "codesign", 0 },
     { "seg_split_info", 0 },
     { "compact_unwind", 0 },
+    { "function_starts", 0 },
     { NULL, 0 }
   };
 
@@ -64,14 +66,15 @@ 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\
 "));
 }
 
@@ -283,6 +286,14 @@ dump_header (bfd *abfd)
   printf (_(" reserved  : %08x\n"), h->reserved);
 }
 
+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
 dump_section_map (bfd *abfd)
 {
@@ -309,9 +320,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)
@@ -393,8 +402,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);
 }
@@ -911,6 +925,55 @@ 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 void
 dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
                    bfd_boolean verbose)
@@ -1005,6 +1068,8 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
           dump_code_signature (abfd, linkedit);
         else if (verbose && cmd->type == BFD_MACH_O_LC_SEGMENT_SPLIT_INFO)
           dump_segment_split_info (abfd, linkedit);
+        else if (verbose && cmd->type == BFD_MACH_O_LC_FUNCTION_STARTS)
+          dump_function_starts (abfd, linkedit);
         break;
       }
     case BFD_MACH_O_LC_SUB_FRAMEWORK:
@@ -1260,7 +1325,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)
@@ -1309,7 +1374,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))
@@ -1544,6 +1609,8 @@ 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_COMPACT_UNWIND].selected)
     {
       dump_section_content (abfd, "__LD", "__compact_unwind",