[PATCH v2 0/6] Fixes for new mach-o load commands

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH v2 0/6] Fixes for new mach-o load commands

Roman Bolshakov
Hello dear maintainers,

Apple has added a set of new load commands that weren't handled by bfd.
Some of them are rarely processed by binutils, like binaries with
LC_VERSION_MIN_TVOS.

But inability to handle LC_BUILD_VERSION resulted in a few bug reports,
and rendered binutils/gdb to be unusable with Mojave binaries:
  binutils/23728, gdb/23742, binutils/23746

The patch series implements processing of the new commands in bfd and
dump routines in objectdump.

I'm leaving the original cover message as is because couple hours after
v1 patchset, another commit came into master brach that fixes the
aforementioned errors on macOS Mojave by skipping LC_BUILD_VERSION
command.

The patchset should still be helpful as it does parse LC_BUILD_VERSION
and a few other load commands.

--
Best regards,
Roman

Changes in v2:
  * Reformatted printf_version to follow GNU style
  * Rebased to master

Roman Bolshakov (6):
  mach-o: Don't split version into a few fields
  mach-o: Print sdk field in LC_VERSION_MIN_*
  mach-o: Print LC_VERSION_MIN_WATCHOS
  mach-o: Handle LC_VERSION_MIN_TVOS
  mach-o: Handle LC_NOTE
  mach-o: Handle LC_BUILD_VERSION command

 bfd/ChangeLog             |  19 +++++++
 bfd/mach-o.c              |  49 +++++++++++++++---
 bfd/mach-o.h              |  44 ++++++++++++++--
 binutils/ChangeLog        |  11 ++++
 binutils/od-macho.c       | 104 +++++++++++++++++++++++++++++++++++++-
 include/ChangeLog         |  10 ++++
 include/mach-o/external.h |  17 ++++++-
 include/mach-o/loader.h   |   2 +
 8 files changed, 242 insertions(+), 14 deletions(-)

--
2.19.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 1/6] mach-o: Don't split version into a few fields

Roman Bolshakov
X.Y.Z tuple is used for minos version and sdk version fields in a number of
load commands:
  LC_VERSION_MIN_MACOSX
  LC_VERSION_MIN_IOS
  LC_VERSION_MIN_WATCHOS
  LC_VERSION_MIN_TVOS
  LC_BUILD_VERSION

We could use a macro to avoid code duplication for reading and setting
the X/Y/Z fields in all the load commands. But since there're no users
of the fields except od, we can just add a function that properly prints
all version components out of 4-byte unsigned integer and remove the
version subfields until they're really needed.

This also fixes incorrect length of the first version subfield as it
should be two bytes long instead of one:
  X.Y.Z is encoded in nibbles xxxx.yy.zz

Signed-off-by: Roman Bolshakov <[hidden email]>
Reviewed-by: Tristan Gingold <[hidden email]>
---
 bfd/ChangeLog       |  7 +++++++
 bfd/mach-o.c        |  6 +-----
 bfd/mach-o.h        |  6 ++----
 binutils/ChangeLog  |  5 +++++
 binutils/od-macho.c | 14 +++++++++++++-
 5 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 155251d3d4..d90e4576f1 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2018-11-06  Roman Bolshakov <[hidden email]>
+
+ * mach-o.h (bfd_mach_o_version_min_command): Don't split version into
+ a few fields.
+ * mach-o.c (bfd_mach_o_read_version_min): Don't split version into a
+ few fields.
+
 2018-11-06  Romain Margheriti  <[hidden email]>
 
  PR 23742
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 1d0ade3a02..e3d5dbe0d5 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -4598,15 +4598,11 @@ bfd_mach_o_read_version_min (bfd *abfd, bfd_mach_o_load_command *command)
 {
   bfd_mach_o_version_min_command *cmd = &command->command.version_min;
   struct mach_o_version_min_command_external raw;
-  unsigned int ver;
 
   if (bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
     return FALSE;
 
-  ver = bfd_get_32 (abfd, raw.version);
-  cmd->rel = ver >> 16;
-  cmd->maj = ver >> 8;
-  cmd->min = ver;
+  cmd->version = bfd_get_32 (abfd, raw.version);
   cmd->reserved = bfd_get_32 (abfd, raw.reserved);
   return TRUE;
 }
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index d80d43991e..4fd229f352 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -519,10 +519,8 @@ bfd_mach_o_dyld_info_command;
 
 typedef struct bfd_mach_o_version_min_command
 {
-  unsigned char rel;
-  unsigned char maj;
-  unsigned char min;
-  unsigned int reserved;
+  uint32_t version;
+  uint32_t reserved;
 }
 bfd_mach_o_version_min_command;
 
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index f484f92294..089d7a61b6 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,8 @@
+2018-11-06  Roman Bolshakov  <[hidden email]>
+
+ * od-macho.c (printf_version): New.
+ (dump_load_command): Use it to print version.
+
 2018-11-06  H.J. Lu  <[hidden email]>
 
  * doc/binutils.texi: Document --enable-x86-feature and
diff --git a/binutils/od-macho.c b/binutils/od-macho.c
index 8153adae92..9b10f2d654 100644
--- a/binutils/od-macho.c
+++ b/binutils/od-macho.c
@@ -1438,6 +1438,16 @@ dump_twolevel_hints (bfd *abfd, bfd_mach_o_twolevel_hints_command *cmd)
   free (buf);
 }
 
+static void
+printf_version (uint32_t version)
+{
+  uint32_t maj, min, upd;
+  maj = (version >> 16) & 0xffff;
+  min = (version >> 8) & 0xff;
+  upd = version & 0xff;
+  printf ("%u.%u.%u", maj, min, upd);
+}
+
 static void
 dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
                    unsigned int idx, bfd_boolean verbose)
@@ -1585,7 +1595,9 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
       {
         bfd_mach_o_version_min_command *ver = &cmd->command.version_min;
 
-        printf ("    %u.%u.%u\n", ver->rel, ver->maj, ver->min);
+        printf ("   os: ");
+        printf_version (ver->version);
+        printf ("\n");
       }
       break;
     case BFD_MACH_O_LC_SOURCE_VERSION:
--
2.19.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 2/6] mach-o: Print sdk field in LC_VERSION_MIN_*

Roman Bolshakov
In reply to this post by Roman Bolshakov
sdk field was read by bfd but never printed.
Rename it to sdk and dump it in od.

Signed-off-by: Roman Bolshakov <[hidden email]>
Signed-off-by: Saagar Jha  <[hidden email]>
Reviewed-by: Tristan Gingold <[hidden email]>
---
 bfd/ChangeLog             | 5 +++--
 bfd/mach-o.c              | 2 +-
 bfd/mach-o.h              | 2 +-
 binutils/ChangeLog        | 3 ++-
 binutils/od-macho.c       | 2 ++
 include/ChangeLog         | 6 ++++++
 include/mach-o/external.h | 2 +-
 7 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d90e4576f1..5ec55af648 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,9 +1,10 @@
 2018-11-06  Roman Bolshakov <[hidden email]>
+    Saagar Jha  <[hidden email]>
 
  * mach-o.h (bfd_mach_o_version_min_command): Don't split version into
- a few fields.
+ a few fields. Rename reserved to sdk.
  * mach-o.c (bfd_mach_o_read_version_min): Don't split version into a
- few fields.
+ few fields. Rename reserved to sdk.
 
 2018-11-06  Romain Margheriti  <[hidden email]>
 
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index e3d5dbe0d5..78de9f4637 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -4603,7 +4603,7 @@ bfd_mach_o_read_version_min (bfd *abfd, bfd_mach_o_load_command *command)
     return FALSE;
 
   cmd->version = bfd_get_32 (abfd, raw.version);
-  cmd->reserved = bfd_get_32 (abfd, raw.reserved);
+  cmd->sdk = bfd_get_32 (abfd, raw.sdk);
   return TRUE;
 }
 
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index 4fd229f352..28ccb09c69 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -520,7 +520,7 @@ bfd_mach_o_dyld_info_command;
 typedef struct bfd_mach_o_version_min_command
 {
   uint32_t version;
-  uint32_t reserved;
+  uint32_t sdk;
 }
 bfd_mach_o_version_min_command;
 
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 089d7a61b6..270ee4d693 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,7 +1,8 @@
 2018-11-06  Roman Bolshakov  <[hidden email]>
+    Saagar Jha  <[hidden email]>
 
  * od-macho.c (printf_version): New.
- (dump_load_command): Use it to print version.
+ (dump_load_command): Use it to print version. Print sdk version.
 
 2018-11-06  H.J. Lu  <[hidden email]>
 
diff --git a/binutils/od-macho.c b/binutils/od-macho.c
index 9b10f2d654..d394c75774 100644
--- a/binutils/od-macho.c
+++ b/binutils/od-macho.c
@@ -1597,6 +1597,8 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
 
         printf ("   os: ");
         printf_version (ver->version);
+        printf ("\n   sdk: ");
+        printf_version (ver->sdk);
         printf ("\n");
       }
       break;
diff --git a/include/ChangeLog b/include/ChangeLog
index 3bcf18047b..d9548a4747 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,9 @@
+2018-11-06  Roman Bolshakov <[hidden email]>
+    Saagar Jha  <[hidden email]>
+
+ * mach-o/external.h (mach_o_version_min_command_external): Rename
+ reserved to sdk.
+
 2018-11-06  Romain Margheriti  <[hidden email]>
 
  PR 23742
diff --git a/include/mach-o/external.h b/include/mach-o/external.h
index 2609bad982..aa7260a58a 100644
--- a/include/mach-o/external.h
+++ b/include/mach-o/external.h
@@ -308,7 +308,7 @@ struct mach_o_twolevel_hints_command_external
 struct mach_o_version_min_command_external
 {
   unsigned char version[4];
-  unsigned char reserved[4];
+  unsigned char sdk[4];
 };
 
 struct mach_o_encryption_info_command_external
--
2.19.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 3/6] mach-o: Print LC_VERSION_MIN_WATCHOS

Roman Bolshakov
In reply to this post by Roman Bolshakov
Content of LC_VERSION_MIN_WATCHOS gets parsed by bfd but objdump doesn't
print it.

Signed-off-by: Roman Bolshakov <[hidden email]>
Reviewed-by: Tristan Gingold <[hidden email]>
---
 binutils/ChangeLog  | 3 ++-
 binutils/od-macho.c | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 270ee4d693..ce07ba8d58 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -2,7 +2,8 @@
     Saagar Jha  <[hidden email]>
 
  * od-macho.c (printf_version): New.
- (dump_load_command): Use it to print version. Print sdk version.
+ (dump_load_command): Use it to print version. Print sdk version. Print
+ version info for watchOS.
 
 2018-11-06  H.J. Lu  <[hidden email]>
 
diff --git a/binutils/od-macho.c b/binutils/od-macho.c
index d394c75774..dc64342c65 100644
--- a/binutils/od-macho.c
+++ b/binutils/od-macho.c
@@ -209,6 +209,7 @@ static const bfd_mach_o_xlat_name bfd_mach_o_load_command_name[] =
   { "encryption_info_64", BFD_MACH_O_LC_ENCRYPTION_INFO_64},
   { "linker_options", BFD_MACH_O_LC_LINKER_OPTIONS},
   { "linker_optimization_hint", BFD_MACH_O_LC_LINKER_OPTIMIZATION_HINT},
+  { "version_min_watchos", BFD_MACH_O_LC_VERSION_MIN_WATCHOS},
   { NULL, 0}
 };
 
@@ -1592,6 +1593,7 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
       break;
     case BFD_MACH_O_LC_VERSION_MIN_MACOSX:
     case BFD_MACH_O_LC_VERSION_MIN_IPHONEOS:
+    case BFD_MACH_O_LC_VERSION_MIN_WATCHOS:
       {
         bfd_mach_o_version_min_command *ver = &cmd->command.version_min;
 
--
2.19.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 4/6] mach-o: Handle LC_VERSION_MIN_TVOS

Roman Bolshakov
In reply to this post by Roman Bolshakov
The load command was introduced shortly after LC_VERSION_MIN_WATCHOS. It
has exactly the same format as the other load commands from the same
family.

Signed-off-by: Roman Bolshakov <[hidden email]>
Reviewed-by: Tristan Gingold <[hidden email]>
---
 bfd/ChangeLog           | 1 +
 bfd/mach-o.c            | 1 +
 binutils/ChangeLog      | 2 +-
 binutils/od-macho.c     | 2 ++
 include/ChangeLog       | 1 +
 include/mach-o/loader.h | 1 +
 6 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 5ec55af648..87047fb0eb 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -5,6 +5,7 @@
  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.
 
 2018-11-06  Romain Margheriti  <[hidden email]>
 
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 78de9f4637..d6de267397 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -4873,6 +4873,7 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command)
     case BFD_MACH_O_LC_VERSION_MIN_MACOSX:
     case BFD_MACH_O_LC_VERSION_MIN_IPHONEOS:
     case BFD_MACH_O_LC_VERSION_MIN_WATCHOS:
+    case BFD_MACH_O_LC_VERSION_MIN_TVOS:
       if (!bfd_mach_o_read_version_min (abfd, command))
  return FALSE;
       break;
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index ce07ba8d58..6b05f37eae 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -3,7 +3,7 @@
 
  * od-macho.c (printf_version): New.
  (dump_load_command): Use it to print version. Print sdk version. Print
- version info for watchOS.
+ version info for watchOS and tvOS.
 
 2018-11-06  H.J. Lu  <[hidden email]>
 
diff --git a/binutils/od-macho.c b/binutils/od-macho.c
index dc64342c65..9f2d51a2da 100644
--- a/binutils/od-macho.c
+++ b/binutils/od-macho.c
@@ -209,6 +209,7 @@ static const bfd_mach_o_xlat_name bfd_mach_o_load_command_name[] =
   { "encryption_info_64", BFD_MACH_O_LC_ENCRYPTION_INFO_64},
   { "linker_options", BFD_MACH_O_LC_LINKER_OPTIONS},
   { "linker_optimization_hint", BFD_MACH_O_LC_LINKER_OPTIMIZATION_HINT},
+  { "version_min_tvos", BFD_MACH_O_LC_VERSION_MIN_TVOS},
   { "version_min_watchos", BFD_MACH_O_LC_VERSION_MIN_WATCHOS},
   { NULL, 0}
 };
@@ -1594,6 +1595,7 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
     case BFD_MACH_O_LC_VERSION_MIN_MACOSX:
     case BFD_MACH_O_LC_VERSION_MIN_IPHONEOS:
     case BFD_MACH_O_LC_VERSION_MIN_WATCHOS:
+    case BFD_MACH_O_LC_VERSION_MIN_TVOS:
       {
         bfd_mach_o_version_min_command *ver = &cmd->command.version_min;
 
diff --git a/include/ChangeLog b/include/ChangeLog
index d9548a4747..a55fab8f00 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -3,6 +3,7 @@
 
  * mach-o/external.h (mach_o_version_min_command_external): Rename
  reserved to sdk.
+ * mach-o/loader.h (BFD_MACH_O_LC_VERSION_MIN_TVOS): Define
 
 2018-11-06  Romain Margheriti  <[hidden email]>
 
diff --git a/include/mach-o/loader.h b/include/mach-o/loader.h
index 9abc51c35d..acc31f0499 100644
--- a/include/mach-o/loader.h
+++ b/include/mach-o/loader.h
@@ -185,6 +185,7 @@ typedef enum bfd_mach_o_load_command_type
   BFD_MACH_O_LC_ENCRYPTION_INFO_64 = 0x2c, /* Encrypted 64 bit seg info.  */
   BFD_MACH_O_LC_LINKER_OPTIONS = 0x2d, /* Linker options.  */
   BFD_MACH_O_LC_LINKER_OPTIMIZATION_HINT = 0x2e, /* Optimization hints.  */
+  BFD_MACH_O_LC_VERSION_MIN_TVOS = 0x2f, /* Minimal tvOS version.  */
   BFD_MACH_O_LC_VERSION_MIN_WATCHOS = 0x30, /* Minimal WatchOS version.  */
   BFD_MACH_O_LC_BUILD_VERSION = 0x32     /* Records linker, SDK, OS, and tools version used.  */
 }
--
2.19.1

Reply | Threaded
Open this post in threaded view
|

[PATCH v2 5/6] mach-o: Handle LC_NOTE

Roman Bolshakov
In reply to this post by Roman Bolshakov
This is a new command to describe a region of any data. Initially, it's
used in in MH_CORE files.

Signed-off-by: Roman Bolshakov <[hidden email]>
Signed-off-by: Saagar Jha <[hidden email]>
Reviewed-by: Tristan Gingold <[hidden email]>
---
 bfd/ChangeLog             |  4 +++-
 bfd/mach-o.c              | 19 +++++++++++++++++++
 bfd/mach-o.h              |  9 +++++++++
 binutils/ChangeLog        |  2 +-
 binutils/od-macho.c       | 13 +++++++++++++
 include/ChangeLog         |  4 +++-
 include/mach-o/external.h |  7 +++++++
 include/mach-o/loader.h   |  1 +
 8 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 87047fb0eb..0e3d3457ee 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -3,9 +3,11 @@
 
  * mach-o.h (bfd_mach_o_version_min_command): Don't split version into
  a few fields. Rename reserved to sdk.
+ (struct bfd_mach_o_note_command): New.
  * 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.
+ (bfd_mach_o_read_command): Handle LC_VERSION_MIN_TVOS, LC_NOTE.
+ (bfd_mach_o_read_note): New.
 
 2018-11-06  Romain Margheriti  <[hidden email]>
 
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index d6de267397..9d01566240 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -4677,6 +4677,21 @@ bfd_mach_o_read_source_version (bfd *abfd, bfd_mach_o_load_command *command)
   return TRUE;
 }
 
+static bfd_boolean
+bfd_mach_o_read_note (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  bfd_mach_o_note_command *cmd = &command->command.note;
+  struct mach_o_note_command_external raw;
+
+  if (bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
+    return FALSE;
+
+  memcpy (cmd->data_owner, raw.data_owner, 16);
+  cmd->offset = bfd_get_64 (abfd, raw.offset);
+  cmd->size = bfd_get_64 (abfd, raw.size);
+  return TRUE;
+}
+
 static bfd_boolean
 bfd_mach_o_read_segment (bfd *abfd,
  bfd_mach_o_load_command *command,
@@ -4885,6 +4900,10 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command)
       if (!bfd_mach_o_read_source_version (abfd, command))
  return FALSE;
       break;
+    case BFD_MACH_O_LC_NOTE:
+      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:
       break;
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index 28ccb09c69..805c30e4e2 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -549,6 +549,14 @@ typedef struct bfd_mach_o_source_version_command
 }
 bfd_mach_o_source_version_command;
 
+typedef struct bfd_mach_o_note_command
+{
+  char data_owner[16];
+  bfd_uint64_t offset;
+  bfd_uint64_t size;
+}
+bfd_mach_o_note_command;
+
 typedef struct bfd_mach_o_load_command
 {
   /* Next command in the single linked list.  */
@@ -582,6 +590,7 @@ typedef struct bfd_mach_o_load_command
     bfd_mach_o_fvmlib_command fvmlib;
     bfd_mach_o_main_command main;
     bfd_mach_o_source_version_command source_version;
+    bfd_mach_o_note_command note;
   } command;
 }
 bfd_mach_o_load_command;
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 6b05f37eae..3b17ec76db 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -3,7 +3,7 @@
 
  * od-macho.c (printf_version): New.
  (dump_load_command): Use it to print version. Print sdk version. Print
- version info for watchOS and tvOS.
+ version info for watchOS and tvOS. Print LC_NOTE.
 
 2018-11-06  H.J. Lu  <[hidden email]>
 
diff --git a/binutils/od-macho.c b/binutils/od-macho.c
index 9f2d51a2da..f56c32ff67 100644
--- a/binutils/od-macho.c
+++ b/binutils/od-macho.c
@@ -211,6 +211,7 @@ static const bfd_mach_o_xlat_name bfd_mach_o_load_command_name[] =
   { "linker_optimization_hint", BFD_MACH_O_LC_LINKER_OPTIMIZATION_HINT},
   { "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},
   { NULL, 0}
 };
 
@@ -1661,6 +1662,18 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
  printf ("\n");
         break;
       }
+    case BFD_MACH_O_LC_NOTE:
+      {
+        bfd_mach_o_note_command *note = &cmd->command.note;
+        printf ("   data owner: %.16s\n", note->data_owner);
+        printf ("   offset:     ");
+ printf_uint64 (note->offset);
+        printf ("\n"
+                "   size:       ");
+ printf_uint64 (note->size);
+ printf ("\n");
+        break;
+      }
     default:
       break;
     }
diff --git a/include/ChangeLog b/include/ChangeLog
index a55fab8f00..210451fb80 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,9 +1,11 @@
 2018-11-06  Roman Bolshakov <[hidden email]>
     Saagar Jha  <[hidden email]>
 
- * mach-o/external.h (mach_o_version_min_command_external): Rename
+ * mach-o/external.h (mach_o_nversion_min_command_external): Rename
  reserved to sdk.
+ (mach_o_note_command_external): New
  * mach-o/loader.h (BFD_MACH_O_LC_VERSION_MIN_TVOS): Define
+ (BFD_MACH_O_LC_NOTE): Define
 
 2018-11-06  Romain Margheriti  <[hidden email]>
 
diff --git a/include/mach-o/external.h b/include/mach-o/external.h
index aa7260a58a..7889b57794 100644
--- a/include/mach-o/external.h
+++ b/include/mach-o/external.h
@@ -345,6 +345,13 @@ struct mach_o_source_version_command_external
    and 24 bits for A.  */
 };
 
+struct mach_o_note_command_external
+{
+  unsigned char data_owner[16]; /* Owner name for this note. */
+  unsigned char offset[8];      /* File offset of the note. */
+  unsigned char size[8];        /* Length of the note. */
+};
+
 /* The LD_DATA_IN_CODE command use a linkedit_data_command that points to
    a table of entries.  */
 
diff --git a/include/mach-o/loader.h b/include/mach-o/loader.h
index acc31f0499..5cbc411b36 100644
--- a/include/mach-o/loader.h
+++ b/include/mach-o/loader.h
@@ -187,6 +187,7 @@ typedef enum bfd_mach_o_load_command_type
   BFD_MACH_O_LC_LINKER_OPTIMIZATION_HINT = 0x2e, /* Optimization hints.  */
   BFD_MACH_O_LC_VERSION_MIN_TVOS = 0x2f, /* Minimal tvOS version.  */
   BFD_MACH_O_LC_VERSION_MIN_WATCHOS = 0x30, /* Minimal WatchOS version.  */
+  BFD_MACH_O_LC_NOTE = 0x31, /* Region of arbitrary data. */
   BFD_MACH_O_LC_BUILD_VERSION = 0x32     /* Records linker, SDK, OS, and tools version used.  */
 }
 bfd_mach_o_load_command_type;
--
2.19.1

Reply | Threaded
Open this post in threaded view
|

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

Roman Bolshakov
In reply to this post by Roman Bolshakov
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 <[hidden email]>
Signed-off-by: Saagar Jha  <[hidden email]>
Reviewed-by: Tristan Gingold <[hidden email]>
Cc: Tom Tromey <[hidden email]>
Cc: Nick Clifton <[hidden email]>
---
 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 <[hidden email]>
     Saagar Jha  <[hidden email]>
 
- * 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  <[hidden email]>
 
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  <[hidden email]>
     Saagar Jha  <[hidden email]>
 
+ 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  <[hidden email]>
 
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