From 7a79c51466c30188d49d03d3e3593c87e5a3345e Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Wed, 26 Mar 2014 15:01:53 +0100 Subject: [PATCH] mach-o: read and dump: prebound_dylib, prebind_cksum, twolevel_hints. include/mach-o: * external.h (mach_o_prebound_dylib_command_external) (mach_o_prebind_cksum_command_external) (mach_o_twolevel_hints_command_external): New types. bfd/ * mach-o.h (bfd_mach_o_twolevel_hints_command) (bfd_mach_o_prebind_cksum_command): New types. (bfd_mach_o_prebound_dylib_command): Rewrite. (bfd_mach_o_load_command): Add prebind_cksum and twolevel_hints fields. * mach-o.c (bfd_mach_o_read_prebound_dylib): Read and decode the command. (bfd_mach_o_read_prebind_cksum): New function. (bfd_mach_o_read_twolevel_hints): Ditto. (bfd_mach_o_read_command): Handle prebind cksum and twolevel hints commands. binutils/ * od-macho.c (OPT_TWOLEVEL_HINTS): New macro. (options): Add entry for twolevel_hints. (dump_data_in_code): Fix error message. (dump_twolevel_hints): New function. (dump_load_command): Handle prebound dylib, prebind cksum and twolevel hints. (mach_o_dump): Handle twolevel hints. --- bfd/ChangeLog | 14 +++++++ bfd/mach-o.c | 72 ++++++++++++++++++++++++++++++--- bfd/mach-o.h | 32 +++++++++++++-- binutils/ChangeLog | 10 +++++ binutils/od-macho.c | 83 ++++++++++++++++++++++++++++++++++++++- include/mach-o/ChangeLog | 6 +++ include/mach-o/external.h | 18 +++++++++ 7 files changed, 226 insertions(+), 9 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5c7b2b301e..d2fb972f59 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2014-04-02 Tristan Gingold + + * mach-o.h (bfd_mach_o_twolevel_hints_command) + (bfd_mach_o_prebind_cksum_command): New types. + (bfd_mach_o_prebound_dylib_command): Rewrite. + (bfd_mach_o_load_command): Add prebind_cksum and twolevel_hints + fields. + * mach-o.c (bfd_mach_o_read_prebound_dylib): Read and decode the + command. + (bfd_mach_o_read_prebind_cksum): New function. + (bfd_mach_o_read_twolevel_hints): Ditto. + (bfd_mach_o_read_command): Handle prebind cksum and twolevel hints + commands. + 2014-04-02 Alan Modra * elfcode.h (bfd_from_remote_memory): Add "size" parameter. diff --git a/bfd/mach-o.c b/bfd/mach-o.c index e33c01f1e4..525607e8c0 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -3207,12 +3207,69 @@ bfd_mach_o_read_dylib (bfd *abfd, bfd_mach_o_load_command *command) } static int -bfd_mach_o_read_prebound_dylib (bfd *abfd ATTRIBUTE_UNUSED, - bfd_mach_o_load_command *command ATTRIBUTE_UNUSED) +bfd_mach_o_read_prebound_dylib (bfd *abfd, + bfd_mach_o_load_command *command) { - /* bfd_mach_o_prebound_dylib_command *cmd = &command->command.prebound_dylib; */ + bfd_mach_o_prebound_dylib_command *cmd = &command->command.prebound_dylib; + struct mach_o_prebound_dylib_command_external raw; + unsigned int nameoff; + unsigned int modoff; + unsigned int str_len; + unsigned char *str; + + if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0 + || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw)) + return -1; + + nameoff = bfd_h_get_32 (abfd, raw.name); + modoff = bfd_h_get_32 (abfd, raw.linked_modules); + if (nameoff > command->len || modoff > command->len) + return -1; + + str_len = command->len - sizeof (raw); + str = bfd_alloc (abfd, str_len); + if (str == NULL) + return -1; + if (bfd_bread (str, str_len, abfd) != str_len) + return -1; + + cmd->name_offset = command->offset + nameoff; + cmd->nmodules = bfd_h_get_32 (abfd, raw.nmodules); + cmd->linked_modules_offset = command->offset + modoff; + + cmd->name_str = (char *)str + nameoff - (sizeof (raw) + BFD_MACH_O_LC_SIZE); + cmd->linked_modules = str + modoff - (sizeof (raw) + BFD_MACH_O_LC_SIZE); + return 0; +} + +static int +bfd_mach_o_read_prebind_cksum (bfd *abfd, + bfd_mach_o_load_command *command) +{ + bfd_mach_o_prebind_cksum_command *cmd = &command->command.prebind_cksum; + struct mach_o_prebind_cksum_command_external raw; - BFD_ASSERT (command->type == BFD_MACH_O_LC_PREBOUND_DYLIB); + if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0 + || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw)) + return -1; + + cmd->cksum = bfd_get_32 (abfd, raw.cksum); + return 0; +} + +static int +bfd_mach_o_read_twolevel_hints (bfd *abfd, + bfd_mach_o_load_command *command) +{ + bfd_mach_o_twolevel_hints_command *cmd = &command->command.twolevel_hints; + struct mach_o_twolevel_hints_command_external raw; + + if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0 + || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw)) + return -1; + + cmd->offset = bfd_get_32 (abfd, raw.offset); + cmd->nhints = bfd_get_32 (abfd, raw.nhints); return 0; } @@ -3881,8 +3938,13 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command) if (bfd_mach_o_read_dysymtab (abfd, command) != 0) return -1; break; - case BFD_MACH_O_LC_TWOLEVEL_HINTS: case BFD_MACH_O_LC_PREBIND_CKSUM: + if (bfd_mach_o_read_prebind_cksum (abfd, command) != 0) + return -1; + break; + case BFD_MACH_O_LC_TWOLEVEL_HINTS: + if (bfd_mach_o_read_twolevel_hints (abfd, command) != 0) + return -1; break; case BFD_MACH_O_LC_UUID: if (bfd_mach_o_read_uuid (abfd, command) != 0) diff --git a/bfd/mach-o.h b/bfd/mach-o.h index 4418b9287b..629459bc3e 100644 --- a/bfd/mach-o.h +++ b/bfd/mach-o.h @@ -375,6 +375,27 @@ bfd_mach_o_dysymtab_command; #define BFD_MACH_O_INDIRECT_SYMBOL_ABS 0x40000000 #define BFD_MACH_O_INDIRECT_SYMBOL_SIZE 4 +/* For LC_TWOLEVEL_HINTS. */ + +typedef struct bfd_mach_o_twolevel_hints_command +{ + /* Offset to the hint table. */ + unsigned int offset; + + /* Number of entries in the table. */ + unsigned int nhints; +} +bfd_mach_o_twolevel_hints_command; + +/* For LC_PREBIND_CKSUM. */ + +typedef struct bfd_mach_o_prebind_cksum_command +{ + /* Checksum or zero. */ + unsigned int cksum; +} +bfd_mach_o_prebind_cksum_command; + /* For LC_THREAD or LC_UNIXTHREAD. */ typedef struct bfd_mach_o_thread_flavour @@ -421,9 +442,12 @@ bfd_mach_o_dylib_command; typedef struct bfd_mach_o_prebound_dylib_command { - unsigned long name; /* Library's path name. */ - unsigned long nmodules; /* Number of modules in library. */ - unsigned long linked_modules; /* Bit vector of linked modules. */ + unsigned int name_offset; /* Library's path name. */ + unsigned int nmodules; /* Number of modules in library. */ + unsigned int linked_modules_offset; /* Bit vector of linked modules. */ + + char *name_str; + unsigned char *linked_modules; } bfd_mach_o_prebound_dylib_command; @@ -535,6 +559,8 @@ typedef struct bfd_mach_o_load_command bfd_mach_o_dylib_command dylib; bfd_mach_o_dylinker_command dylinker; bfd_mach_o_prebound_dylib_command prebound_dylib; + bfd_mach_o_prebind_cksum_command prebind_cksum; + bfd_mach_o_twolevel_hints_command twolevel_hints; bfd_mach_o_uuid_command uuid; bfd_mach_o_linkedit_command linkedit; bfd_mach_o_str_command str; diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 60f50c37d9..56ea960026 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,13 @@ +2014-04-02 Tristan Gingold + + * od-macho.c (OPT_TWOLEVEL_HINTS): New macro. + (options): Add entry for twolevel_hints. + (dump_data_in_code): Fix error message. + (dump_twolevel_hints): New function. + (dump_load_command): Handle prebound dylib, prebind cksum + and twolevel hints. + (mach_o_dump): Handle twolevel hints. + 2014-04-01 Tristan Gingold * od-macho.c (OPT_DATA_IN_CODE): New macro. diff --git a/binutils/od-macho.c b/binutils/od-macho.c index 31cce9dab3..d606a2beb0 100644 --- a/binutils/od-macho.c +++ b/binutils/od-macho.c @@ -44,6 +44,7 @@ #define OPT_COMPACT_UNWIND 7 #define OPT_FUNCTION_STARTS 8 #define OPT_DATA_IN_CODE 9 +#define OPT_TWOLEVEL_HINTS 10 /* List of actions. */ static struct objdump_private_option options[] = @@ -58,6 +59,7 @@ static struct objdump_private_option options[] = { "compact_unwind", 0 }, { "function_starts", 0 }, { "data_in_code", 0 }, + { "twolevel_hints", 0 }, { NULL, 0 } }; @@ -78,6 +80,7 @@ For Mach-O files:\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\ + twolevel_hints Display the two-level namespace lookup hints table\n\ ")); } @@ -1004,7 +1007,7 @@ dump_data_in_code (bfd *abfd, bfd_mach_o_linkedit_command *cmd) if (bfd_seek (abfd, cmd->dataoff, SEEK_SET) != 0 || bfd_bread (buf, cmd->datasize, abfd) != cmd->datasize) { - non_fatal (_("cannot read function starts")); + non_fatal (_("cannot read data_in_code")); free (buf); return; } @@ -1031,6 +1034,45 @@ dump_data_in_code (bfd *abfd, bfd_mach_o_linkedit_command *cmd) free (buf); } +static void +dump_twolevel_hints (bfd *abfd, bfd_mach_o_twolevel_hints_command *cmd) +{ + size_t sz = 4 * cmd->nhints; + unsigned char *buf; + unsigned char *p; + + buf = xmalloc (sz); + if (bfd_seek (abfd, cmd->offset, SEEK_SET) != 0 + || bfd_bread (buf, sz, abfd) != sz) + { + non_fatal (_("cannot read twolevel hints")); + free (buf); + return; + } + + for (p = buf; p < buf + sz; p += 4) + { + unsigned int v; + unsigned int isub_image; + unsigned int itoc; + + v = bfd_get_32 (abfd, p); + if (bfd_big_endian (abfd)) + { + isub_image = (v >> 24) & 0xff; + itoc = v & 0xffffff; + } + else + { + isub_image = v & 0xff; + itoc = (v >> 8) & 0xffffff; + } + + printf (" %3u %8u\n", isub_image, itoc); + } + free (buf); +} + static void dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd, bfd_boolean verbose) @@ -1195,6 +1237,43 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd, version->a, version->b, version->c, version->d, version->e); break; } + case BFD_MACH_O_LC_PREBOUND_DYLIB: + { + bfd_mach_o_prebound_dylib_command *pbdy = &cmd->command.prebound_dylib; + unsigned char *lm = pbdy->linked_modules; + unsigned int j; + unsigned int last; + + printf (" %s\n", pbdy->name_str); + printf (" nmodules: %u\n", pbdy->nmodules); + printf (" linked modules (at %u): ", + pbdy->linked_modules_offset - cmd->offset); + last = pbdy->nmodules > 32 ? 32 : pbdy->nmodules; + for (j = 0; j < last; j++) + printf ("%u", (lm[j >> 3] >> (j & 7)) & 1); + if (last < pbdy->nmodules) + printf ("..."); + putchar ('\n'); + break; + } + case BFD_MACH_O_LC_PREBIND_CKSUM: + { + bfd_mach_o_prebind_cksum_command *cksum = &cmd->command.prebind_cksum; + printf (" 0x%08x\n", cksum->cksum); + break; + } + case BFD_MACH_O_LC_TWOLEVEL_HINTS: + { + bfd_mach_o_twolevel_hints_command *hints = + &cmd->command.twolevel_hints; + + printf ("\n" + " table offset: 0x%08x nbr hints: %u\n", + hints->offset, hints->nhints); + if (verbose) + dump_twolevel_hints (abfd, hints); + break; + } case BFD_MACH_O_LC_MAIN: { bfd_mach_o_main_command *entry = &cmd->command.main; @@ -1688,6 +1767,8 @@ mach_o_dump (bfd *abfd) 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_TWOLEVEL_HINTS].selected) + dump_load_commands (abfd, BFD_MACH_O_LC_TWOLEVEL_HINTS, 0); if (options[OPT_COMPACT_UNWIND].selected) { dump_section_content (abfd, "__LD", "__compact_unwind", diff --git a/include/mach-o/ChangeLog b/include/mach-o/ChangeLog index 3624f8ac33..b3dc669a0c 100644 --- a/include/mach-o/ChangeLog +++ b/include/mach-o/ChangeLog @@ -1,3 +1,9 @@ +2014-04-02 Tristan Gingold + + * external.h (mach_o_prebound_dylib_command_external) + (mach_o_prebind_cksum_command_external) + (mach_o_twolevel_hints_command_external): New types. + 2014-03-26 Tristan Gingold * loader.h (bfd_mach_o_cpu_type): Add BFD_MACH_O_CPU_TYPE_ARM64. diff --git a/include/mach-o/external.h b/include/mach-o/external.h index d92c10ef8d..4fb950b203 100644 --- a/include/mach-o/external.h +++ b/include/mach-o/external.h @@ -287,6 +287,24 @@ struct mach_o_dyld_info_command_external unsigned char export_size[4]; }; +struct mach_o_prebound_dylib_command_external +{ + unsigned char name[4]; + unsigned char nmodules[4]; + unsigned char linked_modules[4]; +}; + +struct mach_o_prebind_cksum_command_external +{ + unsigned char cksum[4]; +}; + +struct mach_o_twolevel_hints_command_external +{ + unsigned char offset[4]; + unsigned char nhints[4]; +}; + struct mach_o_version_min_command_external { unsigned char version[4]; -- 2.34.1