[PATCH v2 6/6] mach-o: Handle LC_BUILD_VERSION command

Roman Bolshakov r.bolshakov@yadro.com
Tue Nov 6 21:16:00 GMT 2018


All new binaries compiled for macOS Mojave (10.14) and a few other new
platforms have started to use the new load command that essentially
replaced LC_*_VERSION_MIN commands.

Inability to handle the command prevented the whole set of binutils,
including gdb from processing new macOS binaries.

Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
Signed-off-by: Saagar Jha  <saagar@saagarjha.com>
Reviewed-by: Tristan Gingold <tgingold@free.fr>
Cc: Tom Tromey <tom@tromey.com>
Cc: Nick Clifton <nickc@redhat.com>
---
 bfd/ChangeLog             | 14 ++++++--
 bfd/mach-o.c              | 21 +++++++++++-
 bfd/mach-o.h              | 29 ++++++++++++++++
 binutils/ChangeLog        |  6 +++-
 binutils/od-macho.c       | 71 ++++++++++++++++++++++++++++++++++++++-
 include/ChangeLog         |  1 +
 include/mach-o/external.h |  8 +++++
 7 files changed, 144 insertions(+), 6 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 0e3d3457ee..4c81d3838c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,13 +1,21 @@
 2018-11-06  Roman Bolshakov <r.bolshakov@yadro.com>
 	    Saagar Jha  <saagar@saagarjha.com>
 
-	* mach-o.h (bfd_mach_o_version_min_command): Don't split version into
-	a few fields. Rename reserved to sdk.
+	* mach-o.h: Add new enums for BFD_MACH_O_PLATFORM_MACOS,
+	BFD_MACH_O_PLATFORM_IOS, BFD_MACH_O_PLATFORM_TVOS,
+	BFD_MACH_O_PLATFORM_WATCHOS, BFD_MACH_O_PLATFORM_BRIDGEOS,
+	BFD_MACH_O_TOOL_CLANG, BFD_MACH_O_TOOL_SWIFT, BFD_MACH_O_TOOL_LD.
 	(struct bfd_mach_o_note_command): New.
+	(struct bfd_mach_o_build_version_tool): New
+	(struct bfd_mach_o_build_version_command): New
+	(bfd_mach_o_read_version_min): Don't split version into
+	a few fields. Rename reserved to sdk.
 	* mach-o.c (bfd_mach_o_read_version_min): Don't split version into a
 	few fields. Rename reserved to sdk.
-	(bfd_mach_o_read_command): Handle LC_VERSION_MIN_TVOS, LC_NOTE.
+	(bfd_mach_o_read_command): Handle LC_VERSION_MIN_TVOS, LC_NOTE,
+	LC_BUILD_VERSION.
 	(bfd_mach_o_read_note): New.
+	(bfd_mach_o_read_build_version): New.
 
 2018-11-06  Romain Margheriti  <lilrom13@gmail.com>
 
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 9d01566240..024f29ed6c 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -4692,6 +4692,22 @@ bfd_mach_o_read_note (bfd *abfd, bfd_mach_o_load_command *command)
   return TRUE;
 }
 
+static bfd_boolean
+bfd_mach_o_read_build_version (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  bfd_mach_o_build_version_command *cmd = &command->command.build_version;
+  struct mach_o_build_version_command_external raw;
+
+  if (bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
+    return FALSE;
+
+  cmd->platform = bfd_get_32 (abfd, raw.platform);
+  cmd->minos = bfd_get_32 (abfd, raw.minos);
+  cmd->sdk = bfd_get_32 (abfd, raw.sdk);
+  cmd->ntools = bfd_get_32 (abfd, raw.ntools);
+  return TRUE;
+}
+
 static bfd_boolean
 bfd_mach_o_read_segment (bfd *abfd,
 			 bfd_mach_o_load_command *command,
@@ -4904,8 +4920,11 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command)
       if (!bfd_mach_o_read_note (abfd, command))
         return FALSE;
       break;
-    case BFD_MACH_O_LC_LINKER_OPTIONS:
     case BFD_MACH_O_LC_BUILD_VERSION:
+      if (!bfd_mach_o_read_build_version (abfd, command))
+        return FALSE;
+      break;
+    case BFD_MACH_O_LC_LINKER_OPTIONS:
       break;
     default:
       command->len = 0;
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index 805c30e4e2..e4951ec31b 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -113,6 +113,18 @@ bfd_mach_o_segment_command;
 #define BFD_MACH_O_PROT_WRITE   0x02
 #define BFD_MACH_O_PROT_EXECUTE 0x04
 
+/* Target platforms. */
+#define BFD_MACH_O_PLATFORM_MACOS    1
+#define BFD_MACH_O_PLATFORM_IOS      2
+#define BFD_MACH_O_PLATFORM_TVOS     3
+#define BFD_MACH_O_PLATFORM_WATCHOS  4
+#define BFD_MACH_O_PLATFORM_BRIDGEOS 5
+
+/* Build tools. */
+#define BFD_MACH_O_TOOL_CLANG 1
+#define BFD_MACH_O_TOOL_SWIFT 2
+#define BFD_MACH_O_TOOL_LD    3
+
 /* Expanded internal representation of a relocation entry.  */
 typedef struct bfd_mach_o_reloc_info
 {
@@ -557,6 +569,22 @@ typedef struct bfd_mach_o_note_command
 }
 bfd_mach_o_note_command;
 
+typedef struct bfd_mach_o_build_version_tool
+{
+  uint32_t tool;
+  uint32_t version;
+}
+bfd_mach_o_build_version_tool;
+
+typedef struct bfd_mach_o_build_version_command
+{
+  uint32_t platform;
+  uint32_t minos;
+  uint32_t sdk;
+  uint32_t ntools;
+}
+bfd_mach_o_build_version_command;
+
 typedef struct bfd_mach_o_load_command
 {
   /* Next command in the single linked list.  */
@@ -591,6 +619,7 @@ typedef struct bfd_mach_o_load_command
     bfd_mach_o_main_command main;
     bfd_mach_o_source_version_command source_version;
     bfd_mach_o_note_command note;
+    bfd_mach_o_build_version_command build_version;
   } command;
 }
 bfd_mach_o_load_command;
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 3b17ec76db..afa9fc6015 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,9 +1,13 @@
 2018-11-06  Roman Bolshakov  <r.bolshakov@yadro.com>
 	    Saagar Jha  <saagar@saagarjha.com>
 
+	PR 23728
 	* od-macho.c (printf_version): New.
 	(dump_load_command): Use it to print version. Print sdk version. Print
-	version info for watchOS and tvOS. Print LC_NOTE.
+	version info for watchOS and tvOS. Print LC_NOTE, LC_BUILD_VERSION.
+	(dump_buld_version): New.
+	(bfd_mach_o_platform_name): New
+	(bfd_mach_o_tool_name): New
 
 2018-11-06  H.J. Lu  <hongjiu.lu@intel.com>
 
diff --git a/binutils/od-macho.c b/binutils/od-macho.c
index f56c32ff67..33488b4eca 100644
--- a/binutils/od-macho.c
+++ b/binutils/od-macho.c
@@ -212,6 +212,7 @@ static const bfd_mach_o_xlat_name bfd_mach_o_load_command_name[] =
   { "version_min_tvos", BFD_MACH_O_LC_VERSION_MIN_TVOS},
   { "version_min_watchos", BFD_MACH_O_LC_VERSION_MIN_WATCHOS},
   { "note", BFD_MACH_O_LC_NOTE},
+  { "build_version", BFD_MACH_O_LC_BUILD_VERSION},
   { NULL, 0}
 };
 
@@ -232,7 +233,25 @@ static const bfd_mach_o_xlat_name bfd_mach_o_thread_x86_name[] =
   { "state_none", BFD_MACH_O_x86_THREAD_STATE_NONE},
   { NULL, 0 }
 };
-
+
+static const bfd_mach_o_xlat_name bfd_mach_o_platform_name[] =
+{
+  { "macos", BFD_MACH_O_PLATFORM_MACOS},
+  { "ios", BFD_MACH_O_PLATFORM_IOS},
+  { "tvos", BFD_MACH_O_PLATFORM_TVOS},
+  { "watchos", BFD_MACH_O_PLATFORM_WATCHOS},
+  { "bridgeos", BFD_MACH_O_PLATFORM_BRIDGEOS},
+  { NULL, 0 }
+};
+
+static const bfd_mach_o_xlat_name bfd_mach_o_tool_name[] =
+{
+  { "clang", BFD_MACH_O_TOOL_CLANG},
+  { "swift", BFD_MACH_O_TOOL_SWIFT},
+  { "ld", BFD_MACH_O_TOOL_LD},
+  { NULL, 0 }
+};
+
 static void
 bfd_mach_o_print_flags (const bfd_mach_o_xlat_name *table,
                         unsigned long val)
@@ -1451,6 +1470,53 @@ printf_version (uint32_t version)
   printf ("%u.%u.%u", maj, min, upd);
 }
 
+static void
+dump_build_version (bfd *abfd, bfd_mach_o_load_command *cmd)
+{
+  const char *platform_name;
+  size_t tools_len, tools_offset;
+  bfd_mach_o_build_version_tool *tools, *tool;
+  bfd_mach_o_build_version_command *ver = &cmd->command.build_version;
+  uint32_t i;
+
+  platform_name = bfd_mach_o_get_name_or_null
+    (bfd_mach_o_platform_name, ver->platform);
+  if (platform_name == NULL)
+    printf ("   platform: 0x%08x\n", ver->platform);
+  else
+    printf ("   platform: %s\n", platform_name);
+  printf ("   os:       ");
+  printf_version (ver->minos);
+  printf ("\n   sdk:      ");
+  printf_version (ver->sdk);
+  printf ("\n   ntools:   %u\n", ver->ntools);
+
+  tools_len = sizeof (bfd_mach_o_build_version_tool) * ver->ntools;
+  tools_offset = cmd->offset + cmd->len - tools_len;
+
+  tools = xmalloc (tools_len);
+  if (bfd_seek (abfd, tools_offset, SEEK_SET) != 0
+      || bfd_bread (tools, tools_len, abfd) != tools_len) {
+    non_fatal (_("cannot read build tools"));
+    free (tools);
+    return;
+  }
+  for (i = 0, tool = tools; i < ver->ntools; i++, tool++)
+  {
+    const char * tool_name;
+    tool_name = bfd_mach_o_get_name_or_null
+      (bfd_mach_o_tool_name, tool->tool);
+    if (tool_name == NULL)
+      printf ("   tool:     0x%08x\n", tool->tool);
+    else
+      printf ("   tool:     %s\n", tool_name);
+    printf ("   version:  ");
+    printf_version (tool->version);
+    printf ("\n");
+  }
+  free (tools);
+}
+
 static void
 dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
                    unsigned int idx, bfd_boolean verbose)
@@ -1674,6 +1740,9 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
 	printf ("\n");
         break;
       }
+    case BFD_MACH_O_LC_BUILD_VERSION:
+      dump_build_version (abfd, cmd);
+      break;
     default:
       break;
     }
diff --git a/include/ChangeLog b/include/ChangeLog
index 210451fb80..b0878c6c67 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -4,6 +4,7 @@
 	* mach-o/external.h (mach_o_nversion_min_command_external): Rename
 	reserved to sdk.
 	(mach_o_note_command_external): New
+	(mach_o_build_version_command_external): New
 	* mach-o/loader.h (BFD_MACH_O_LC_VERSION_MIN_TVOS): Define
 	(BFD_MACH_O_LC_NOTE): Define
 
diff --git a/include/mach-o/external.h b/include/mach-o/external.h
index 7889b57794..22891e5be2 100644
--- a/include/mach-o/external.h
+++ b/include/mach-o/external.h
@@ -352,6 +352,14 @@ struct mach_o_note_command_external
   unsigned char size[8];        /* Length of the note. */
 };
 
+struct mach_o_build_version_command_external
+{
+  unsigned char platform[4];    /* Target platform. */
+  unsigned char minos[4];       /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+  unsigned char sdk[4];         /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+  unsigned char ntools[4];      /* Number of tool entries following this. */
+};
+
 /* The LD_DATA_IN_CODE command use a linkedit_data_command that points to
    a table of entries.  */
 
-- 
2.19.1



More information about the Binutils mailing list