/* od-macho.c -- dump information about an Mach-O object file.
- Copyright (C) 2011-2014 Free Software Foundation, Inc.
+ Copyright (C) 2011-2019 Free Software Foundation, Inc.
Written by Tristan Gingold, Adacore.
This file is part of GNU Binutils.
#include "bfd.h"
#include "objdump.h"
#include "bucomm.h"
+#include "dwarf.h"
#include "bfdlink.h"
-#include "libbfd.h"
#include "mach-o.h"
#include "mach-o/external.h"
#include "mach-o/codesign.h"
#define OPT_FUNCTION_STARTS 8
#define OPT_DATA_IN_CODE 9
#define OPT_TWOLEVEL_HINTS 10
+#define OPT_DYLD_INFO 11
/* List of actions. */
static struct objdump_private_option options[] =
{ "function_starts", 0 },
{ "data_in_code", 0 },
{ "twolevel_hints", 0 },
+ { "dyld_info", 0 },
{ NULL, 0 }
};
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\
+ dyld_info Display dyld information\n\
"));
}
{ "arm", BFD_MACH_O_CPU_TYPE_ARM },
{ "mc88000", BFD_MACH_O_CPU_TYPE_MC88000 },
{ "sparc", BFD_MACH_O_CPU_TYPE_SPARC },
- { "i860", BFD_MACH_O_CPU_TYPE_I860 },
{ "alpha", BFD_MACH_O_CPU_TYPE_ALPHA },
{ "powerpc", BFD_MACH_O_CPU_TYPE_POWERPC },
{ "powerpc_64", BFD_MACH_O_CPU_TYPE_POWERPC_64 },
{ "setuid_safe", BFD_MACH_O_MH_SETUID_SAFE },
{ "no_reexported_dylibs", BFD_MACH_O_MH_NO_REEXPORTED_DYLIBS },
{ "pie", BFD_MACH_O_MH_PIE },
+ { "dead_strippable_dylib", BFD_MACH_O_MH_DEAD_STRIPPABLE_DYLIB },
+ { "has_tlv", BFD_MACH_O_MH_HAS_TLV_DESCRIPTORS },
+ { "no_heap_execution", BFD_MACH_O_MH_NO_HEAP_EXECUTION },
+ { "app_extension_safe", BFD_MACH_O_MH_APP_EXTENSION_SAFE },
{ NULL, 0}
};
{ "data_in_code", BFD_MACH_O_LC_DATA_IN_CODE},
{ "source_version", BFD_MACH_O_LC_SOURCE_VERSION},
{ "dylib_code_sign_drs", BFD_MACH_O_LC_DYLIB_CODE_SIGN_DRS},
+ { "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},
+ { "note", BFD_MACH_O_LC_NOTE},
+ { "build_version", BFD_MACH_O_LC_BUILD_VERSION},
{ NULL, 0}
};
{ "state_none", BFD_MACH_O_x86_THREAD_STATE_NONE},
{ NULL, 0 }
};
-\f
+
+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)
printf ("-");
}
+/* Print a bfd_uint64_t, using a platform independent style. */
+
+static void
+printf_uint64 (bfd_uint64_t v)
+{
+ printf ("0x%08lx%08lx",
+ (unsigned long)((v >> 16) >> 16), (unsigned long)(v & 0xffffffffUL));
+}
+
static const char *
bfd_mach_o_get_name_or_null (const bfd_mach_o_xlat_name *table,
unsigned long val)
h->filetype,
bfd_mach_o_get_name (bfd_mach_o_filetype_name, h->filetype));
printf (_(" ncmds : %08lx (%lu)\n"), h->ncmds, h->ncmds);
- printf (_(" sizeofcmds: %08lx\n"), h->sizeofcmds);
+ printf (_(" sizeofcmds: %08lx (%lu)\n"), h->sizeofcmds, h->sizeofcmds);
printf (_(" flags : %08lx ("), h->flags);
bfd_mach_o_print_flags (bfd_mach_o_header_flags_name, h->flags);
fputs (_(")\n"), stdout);
dump_section_map (bfd *abfd)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
- unsigned int i;
+ bfd_mach_o_load_command *cmd;
unsigned int sec_nbr = 0;
fputs (_("Segments and Sections:\n"), stdout);
fputs (_(" #: Segment name Section name Address\n"), stdout);
- for (i = 0; i < mdata->header.ncmds; i++)
+ for (cmd = mdata->first_command; cmd != NULL; cmd = cmd->next)
{
bfd_mach_o_segment_command *seg;
bfd_mach_o_section *sec;
- if (mdata->commands[i].type != BFD_MACH_O_LC_SEGMENT
- && mdata->commands[i].type != BFD_MACH_O_LC_SEGMENT_64)
+ if (cmd->type != BFD_MACH_O_LC_SEGMENT
+ && cmd->type != BFD_MACH_O_LC_SEGMENT_64)
continue;
- seg = &mdata->commands[i].command.segment;
+ seg = &cmd->command.segment;
printf ("[Segment %-16s ", seg->segname);
printf_vma (seg->vmaddr);
bfd_mach_o_segment_command *seg = &cmd->command.segment;
bfd_mach_o_section *sec;
- printf (" name: %s\n", *seg->segname ? seg->segname : "*none*");
- printf (" vmaddr: ");
+ printf (" name: %16s", *seg->segname ? seg->segname : "*none*");
+ 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");
+ printf (" vmaddr: ");
printf_vma (seg->vmaddr);
printf (" vmsize: ");
printf_vma (seg->vmsize);
printf ("\n");
- printf (" fileoff: ");
+ printf (" fileoff: ");
printf_vma (seg->fileoff);
printf (" filesize: ");
printf_vma ((bfd_vma)seg->filesize);
printf (" endoff: ");
printf_vma ((bfd_vma)(seg->fileoff + seg->filesize));
printf ("\n");
- 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);
}
}
+static bfd_boolean
+load_and_dump (bfd *abfd, ufile_ptr off, unsigned int len,
+ void (*dump)(bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off))
+{
+ unsigned char *buf;
+
+ if (len == 0)
+ return TRUE;
+
+ buf = xmalloc (len);
+
+ if (bfd_seek (abfd, off, SEEK_SET) == 0
+ && bfd_bread (buf, len, abfd) == len)
+ dump (abfd, buf, len, off);
+ else
+ return FALSE;
+
+ free (buf);
+ return TRUE;
+}
+
+static const bfd_mach_o_xlat_name bfd_mach_o_dyld_rebase_type_name[] =
+{
+ { "pointer", BFD_MACH_O_REBASE_TYPE_POINTER },
+ { "text_abs32", BFD_MACH_O_REBASE_TYPE_TEXT_ABSOLUTE32 },
+ { "text_pcrel32", BFD_MACH_O_REBASE_TYPE_TEXT_PCREL32 },
+ { NULL, 0 }
+};
+
+static void
+dump_dyld_info_rebase (bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off ATTRIBUTE_UNUSED)
+{
+ unsigned int i;
+ bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+ unsigned int ptrsize = mdata->header.version == 2 ? 8 : 4;
+
+ for (i = 0; i < len; )
+ {
+ unsigned char b = buf[i++];
+ unsigned char imm = b & BFD_MACH_O_REBASE_IMMEDIATE_MASK;
+ bfd_vma leb;
+ unsigned int leblen;
+
+ printf (" [0x%04x] 0x%02x: ", i, b);
+ switch (b & BFD_MACH_O_REBASE_OPCODE_MASK)
+ {
+ case BFD_MACH_O_REBASE_OPCODE_DONE:
+ printf ("done\n");
+ return;
+ case BFD_MACH_O_REBASE_OPCODE_SET_TYPE_IMM:
+ printf ("set_type %s\n",
+ bfd_mach_o_get_name (bfd_mach_o_dyld_rebase_type_name, imm));
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("set segment: %u and offset: 0x%08x\n",
+ imm, (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("add addr uleb: 0x%08x\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ printf ("add addr imm scaled: %u\n", imm * ptrsize);
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ printf ("rebase imm times: %u\n", imm);
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("rebase uleb times: %u\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("rebase add addr uleb: %u\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("rebase uleb times (%u)", (unsigned) leb);
+ i += leblen;
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf (" skipping uleb (%u)\n", (unsigned) leb);
+ i += leblen;
+ break;
+ default:
+ printf ("unknown\n");
+ return;
+ }
+ }
+ printf (" rebase commands without end!\n");
+}
+
+static void
+dump_dyld_info_bind (bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off ATTRIBUTE_UNUSED)
+{
+ unsigned int i;
+ bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+ unsigned int ptrsize = mdata->header.version == 2 ? 8 : 4;
+
+ for (i = 0; i < len; )
+ {
+ unsigned char b = buf[i++];
+ unsigned char imm = b & BFD_MACH_O_BIND_IMMEDIATE_MASK;
+ bfd_vma leb;
+ unsigned int leblen;
+
+ printf (" [0x%04x] 0x%02x: ", i, b);
+ switch (b & BFD_MACH_O_BIND_OPCODE_MASK)
+ {
+ case BFD_MACH_O_BIND_OPCODE_DONE:
+ printf ("done\n");
+ return;
+ case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ printf ("set dylib ordinal imm: %u\n", imm);
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("set dylib ordinal uleb: %u\n", imm);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ imm = (imm != 0) ? imm | BFD_MACH_O_BIND_OPCODE_MASK : imm;
+ printf ("set dylib special imm: %d\n", imm);
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ printf ("set symbol trailing flags imm: 0x%02x, ", imm);
+ for (; i < len && buf[i] != 0; i++)
+ putchar (buf[i] >= ' ' && buf[i] < 0x7f ? buf[i] : '?');
+ putchar ('\n');
+ i++;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_TYPE_IMM:
+ /* Kludge: use the same table as rebase type. */
+ printf ("set_type %s\n",
+ bfd_mach_o_get_name (bfd_mach_o_dyld_rebase_type_name, imm));
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_ADDEND_SLEB:
+ {
+ bfd_signed_vma svma;
+ svma = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("set addend sleb: 0x%08x\n", (unsigned) svma);
+ i += leblen;
+ }
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("set segment: %u and offset: 0x%08x\n",
+ imm, (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("add addr uleb: 0x%08x\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND:
+ printf ("do bind\n");
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("do bind add addr uleb: 0x%08x\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ printf ("do bind add addr imm scaled: %u\n", imm * ptrsize);
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf ("do bind uleb times (%u)", (unsigned) leb);
+ i += leblen;
+ leb = read_leb128 (buf + i, &leblen, 0, buf + len);
+ printf (" skipping uleb (%u)\n", (unsigned) leb);
+ i += leblen;
+ break;
+ default:
+ printf ("unknown\n");
+ return;
+ }
+ }
+ printf (" bind commands without end!\n");
+}
+
+struct export_info_data
+{
+ const unsigned char *name;
+ struct export_info_data *next;
+};
+
+static void
+dump_dyld_info_export_1 (bfd *abfd, unsigned char *buf, unsigned int len,
+ unsigned int off, struct export_info_data *parent,
+ struct export_info_data *base)
+{
+ bfd_vma size;
+ unsigned int leblen;
+ unsigned int child_count;
+ unsigned int i;
+
+ size = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+
+ if (size != 0)
+ {
+ bfd_vma flags;
+ struct export_info_data *d;
+
+ flags = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+
+ fputs (" ", stdout);
+ switch (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_MASK)
+ {
+ case BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
+ putchar ('-');
+ break;
+ case BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
+ putchar ('T');
+ break;
+ default:
+ putchar ('?');
+ break;
+ }
+ putchar ((flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION) ?
+ 'W' : '-');
+
+ if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_REEXPORT)
+ {
+ bfd_vma lib;
+
+ lib = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+
+ fputs (" [reexport] ", stdout);
+ for (d = base; d != NULL; d = d->next)
+ printf ("%s", d->name);
+
+ fputs (" (", stdout);
+ if (buf[off] != 0)
+ {
+ fputs ((const char *)buf + off, stdout);
+ putchar (' ');
+ off += strlen ((const char *)buf + off);
+ }
+ printf ("from dylib %u)\n", (unsigned) lib);
+ off++;
+ }
+ else
+ {
+ bfd_vma offset;
+ bfd_vma resolv = 0;
+
+ offset = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+
+ if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+ {
+ resolv = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+ }
+
+ printf (" 0x%08x ", (unsigned) offset);
+ for (d = base; d != NULL; d = d->next)
+ printf ("%s", d->name);
+ if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+ printf (" [resolv: 0x%08x]", (unsigned) resolv);
+ printf ("\n");
+ }
+ }
+
+ child_count = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+
+ for (i = 0; i < child_count; i++)
+ {
+ struct export_info_data sub_data;
+ bfd_vma sub_off;
+
+ sub_data.name = buf + off;
+ sub_data.next = NULL;
+ parent->next = &sub_data;
+
+ off += strlen ((const char *)buf + off) + 1;
+
+ sub_off = read_leb128 (buf + off, &leblen, 0, buf + len);
+ off += leblen;
+
+ dump_dyld_info_export_1 (abfd, buf, len, sub_off, &sub_data, base);
+ }
+}
+
+static void
+dump_dyld_info_export (bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off ATTRIBUTE_UNUSED)
+{
+ struct export_info_data data;
+
+ data.name = (const unsigned char *) "";
+ data.next = NULL;
+
+ printf (" fl offset sym (Flags: Tls Weak)\n");
+ dump_dyld_info_export_1 (abfd, buf, len, 0, &data, &data);
+}
+
static void
-dump_dyld_info (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_load_command *cmd)
+dump_dyld_info (bfd *abfd, bfd_mach_o_load_command *cmd,
+ bfd_boolean verbose)
{
- bfd_mach_o_dyld_info_command *info = &cmd->command.dyld_info;
-
- printf (" rebase: off: 0x%08x size: %-8u\n",
- info->rebase_off, info->rebase_size);
- printf (" bind: off: 0x%08x size: %-8u\n",
- info->bind_off, info->bind_size);
- printf (" weak bind: off: 0x%08x size: %-8u\n",
- info->weak_bind_off, info->weak_bind_size);
- printf (" lazy bind: off: 0x%08x size: %-8u\n",
- info->lazy_bind_off, info->lazy_bind_size);
- printf (" export: off: 0x%08x size: %-8u\n",
- info->export_off, info->export_size);
+ bfd_mach_o_dyld_info_command *dinfo = &cmd->command.dyld_info;
+
+ printf (" rebase: off: 0x%08x size: %-8u (endoff: 0x%08x)\n",
+ dinfo->rebase_off, dinfo->rebase_size,
+ dinfo->rebase_off + dinfo->rebase_size);
+ printf (" bind: off: 0x%08x size: %-8u (endoff: 0x%08x)\n",
+ dinfo->bind_off, dinfo->bind_size,
+ dinfo->bind_off + dinfo->bind_size);
+ printf (" weak bind: off: 0x%08x size: %-8u (endoff: 0x%08x)\n",
+ dinfo->weak_bind_off, dinfo->weak_bind_size,
+ dinfo->weak_bind_off + dinfo->weak_bind_size);
+ printf (" lazy bind: off: 0x%08x size: %-8u (endoff: 0x%08x)\n",
+ dinfo->lazy_bind_off, dinfo->lazy_bind_size,
+ dinfo->lazy_bind_off + dinfo->lazy_bind_size);
+ printf (" export: off: 0x%08x size: %-8u (endoff: 0x%08x)\n",
+ dinfo->export_off, dinfo->export_size,
+ dinfo->export_off + dinfo->export_size);
+
+ if (!verbose)
+ return;
+
+ printf (" rebase:\n");
+ if (!load_and_dump (abfd, dinfo->rebase_off, dinfo->rebase_size,
+ dump_dyld_info_rebase))
+ non_fatal (_("cannot read rebase dyld info"));
+
+ printf (" bind:\n");
+ if (!load_and_dump (abfd, dinfo->bind_off, dinfo->bind_size,
+ dump_dyld_info_bind))
+ non_fatal (_("cannot read bind dyld info"));
+
+ printf (" weak bind:\n");
+ if (!load_and_dump (abfd, dinfo->weak_bind_off, dinfo->weak_bind_size,
+ dump_dyld_info_bind))
+ non_fatal (_("cannot read weak bind dyld info"));
+
+ printf (" lazy bind:\n");
+ if (!load_and_dump (abfd, dinfo->lazy_bind_off, dinfo->lazy_bind_size,
+ dump_dyld_info_bind))
+ non_fatal (_("cannot read lazy bind dyld info"));
+
+ printf (" exported symbols:\n");
+ if (!load_and_dump (abfd, dinfo->export_off, dinfo->export_size,
+ dump_dyld_info_export))
+ non_fatal (_("cannot read export symbols dyld info"));
}
static void
return;
}
count = bfd_getb32 (buf + 8);
- printf (_(" %u index entries:\n"), count);
+ printf (ngettext (" %u index entry:\n",
+ " %u index entries:\n",
+ count),
+ count);
if (len < 12 + 8 * count)
{
printf (_(" [bad block length]\n"));
}
for (p = buf + 1; *p != 0; p += len)
{
- addr += read_unsigned_leb128 (abfd, p, &len);
+ addr += read_leb128 (p, &len, 0, buf + cmd->datasize);
fputs (" ", stdout);
bfd_printf_vma (abfd, addr);
putchar ('\n');
}
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_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,
- bfd_boolean verbose)
+ unsigned int idx, bfd_boolean verbose)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
const char *cmd_name;
cmd_name = bfd_mach_o_get_name_or_null
(bfd_mach_o_load_command_name, cmd->type);
- printf ("Load command ");
+ printf ("Load command #%-2u (size: %3u, offset: %4u): ",
+ idx, cmd->len, cmd->offset);
if (cmd_name == NULL)
- printf ("0x%02x:", cmd->type);
+ printf ("0x%02x\n", cmd->type);
else
- printf ("%s:", cmd_name);
+ printf ("%s\n", cmd_name);
switch (cmd->type)
{
bfd_mach_o_uuid_command *uuid = &cmd->command.uuid;
unsigned int j;
+ printf (" ");
for (j = 0; j < sizeof (uuid->uuid); j ++)
printf (" %02x", uuid->uuid[j]);
putchar ('\n');
case BFD_MACH_O_LC_LOAD_UPWARD_DYLIB:
{
bfd_mach_o_dylib_command *dylib = &cmd->command.dylib;
- printf (" %s\n", dylib->name_str);
+ printf (" name: %s\n", dylib->name_str);
printf (" time stamp: 0x%08lx\n",
dylib->timestamp);
printf (" current version: 0x%08lx\n",
break;
case BFD_MACH_O_LC_LOAD_DYLINKER:
case BFD_MACH_O_LC_ID_DYLINKER:
- printf (" %s\n", cmd->command.dylinker.name_str);
+ 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);
+ printf (" %s\n", cmd->command.dylinker.name_str);
break;
case BFD_MACH_O_LC_SYMTAB:
{
bfd_mach_o_symtab_command *symtab = &cmd->command.symtab;
- printf ("\n"
- " symoff: 0x%08x nsyms: %8u (endoff: 0x%08x)\n",
+ printf (" symoff: 0x%08x nsyms: %8u (endoff: 0x%08x)\n",
symtab->symoff, symtab->nsyms,
symtab->symoff + symtab->nsyms
* (mdata->header.version == 2
break;
}
case BFD_MACH_O_LC_DYSYMTAB:
- putchar ('\n');
dump_dysymtab (abfd, cmd, verbose);
break;
case BFD_MACH_O_LC_LOADFVMLIB:
case BFD_MACH_O_LC_IDFVMLIB:
{
bfd_mach_o_fvmlib_command *fvmlib = &cmd->command.fvmlib;
- printf (" %s\n", fvmlib->name_str);
+ printf (" fvmlib: %s\n", fvmlib->name_str);
printf (" minor version: 0x%08x\n", fvmlib->minor_version);
printf (" header address: 0x%08x\n", fvmlib->header_addr);
}
{
bfd_mach_o_linkedit_command *linkedit = &cmd->command.linkedit;
printf
- ("\n"
- " dataoff: 0x%08lx datasize: 0x%08lx (endoff: 0x%08lx)\n",
+ (" dataoff: 0x%08lx datasize: 0x%08lx (endoff: 0x%08lx)\n",
linkedit->dataoff, linkedit->datasize,
linkedit->dataoff + linkedit->datasize);
case BFD_MACH_O_LC_SUB_CLIENT:
case BFD_MACH_O_LC_RPATH:
{
- bfd_mach_o_str_command *str = &cmd->command.str;
- printf (" %s\n", str->str);
+ bfd_mach_o_str_command *strc = &cmd->command.str;
+ printf (" %s\n", strc->str);
break;
}
case BFD_MACH_O_LC_THREAD:
{
bfd_mach_o_encryption_info_command *cryp =
&cmd->command.encryption_info;
- printf
- ("\n"
- " cryptoff: 0x%08x cryptsize: 0x%08x (endoff 0x%08x)"
- " cryptid: %u\n",
- cryp->cryptoff, cryp->cryptsize,
- cryp->cryptoff + cryp->cryptsize,
- cryp->cryptid);
+ printf (" cryptoff: 0x%08x cryptsize: 0x%08x (endoff 0x%08x)"
+ " cryptid: %u\n",
+ cryp->cryptoff, cryp->cryptsize,
+ cryp->cryptoff + cryp->cryptsize,
+ cryp->cryptid);
}
break;
case BFD_MACH_O_LC_DYLD_INFO:
- putchar ('\n');
- dump_dyld_info (abfd, cmd);
+ dump_dyld_info (abfd, cmd, verbose);
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:
+ case BFD_MACH_O_LC_VERSION_MIN_TVOS:
{
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 sdk: ");
+ printf_version (ver->sdk);
+ printf ("\n");
}
break;
case BFD_MACH_O_LC_SOURCE_VERSION:
{
bfd_mach_o_source_version_command *version =
&cmd->command.source_version;
- printf ("\n"
- " version a.b.c.d.e: %u.%u.%u.%u.%u\n",
+ printf (" version a.b.c.d.e: %u.%u.%u.%u.%u\n",
version->a, version->b, version->c, version->d, version->e);
break;
}
unsigned int j;
unsigned int last;
- printf (" %s\n", pbdy->name_str);
+ printf (" dylib: %s\n", pbdy->name_str);
printf (" nmodules: %u\n", pbdy->nmodules);
printf (" linked modules (at %u): ",
pbdy->linked_modules_offset - cmd->offset);
case BFD_MACH_O_LC_PREBIND_CKSUM:
{
bfd_mach_o_prebind_cksum_command *cksum = &cmd->command.prebind_cksum;
- printf (" 0x%08x\n", cksum->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",
+ printf (" table offset: 0x%08x nbr hints: %u\n",
hints->offset, hints->nhints);
if (verbose)
dump_twolevel_hints (abfd, hints);
case BFD_MACH_O_LC_MAIN:
{
bfd_mach_o_main_command *entry = &cmd->command.main;
- printf ("\n"
- " entry offset: ");
- printf_vma (entry->entryoff);
+ printf (" entry offset: ");
+ printf_uint64 (entry->entryoff);
printf ("\n"
" stack size: ");
- printf_vma (entry->stacksize);
+ printf_uint64 (entry->stacksize);
+ 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;
}
+ case BFD_MACH_O_LC_BUILD_VERSION:
+ dump_build_version (abfd, cmd);
+ break;
default:
- putchar ('\n');
- printf (" offset: 0x%08lx\n", (unsigned long)cmd->offset);
- printf (" size: 0x%08lx\n", (unsigned long)cmd->len);
break;
}
putchar ('\n');
dump_load_commands (bfd *abfd, unsigned int cmd32, unsigned int cmd64)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+ bfd_mach_o_load_command *cmd;
unsigned int i;
- for (i = 0; i < mdata->header.ncmds; i++)
+ for (cmd = mdata->first_command, i = 0; cmd != NULL; cmd = cmd->next, i++)
{
- bfd_mach_o_load_command *cmd = &mdata->commands[i];
-
if (cmd32 == 0)
- dump_load_command (abfd, cmd, FALSE);
+ dump_load_command (abfd, cmd, i, FALSE);
else if (cmd->type == cmd32 || cmd->type == cmd64)
- dump_load_command (abfd, cmd, TRUE);
+ dump_load_command (abfd, cmd, i, TRUE);
}
}
unsigned int regs;
char pfx = sz == 8 ? 'R' : 'E';
- regs = encoding & MACH_O_UNWIND_X86_64_RBP_FRAME_REGSITERS;
+ regs = encoding & MACH_O_UNWIND_X86_64_RBP_FRAME_REGISTERS;
printf (" %cSP frame", pfx);
if (regs != 0)
{
}
}
+/* Dump arm64 compact unwind entries. */
+
+static void
+dump_unwind_encoding_arm64 (unsigned int encoding)
+{
+ switch (encoding & MACH_O_UNWIND_ARM64_MODE_MASK)
+ {
+ case MACH_O_UNWIND_ARM64_MODE_FRAMELESS:
+ printf (" frameless");
+ break;
+ case MACH_O_UNWIND_ARM64_MODE_DWARF:
+ printf (" Dwarf offset: 0x%06x",
+ encoding & MACH_O_UNWIND_ARM64_DWARF_SECTION_OFFSET);
+ return;
+ case MACH_O_UNWIND_ARM64_MODE_FRAME:
+ printf (" frame");
+ break;
+ default:
+ printf (" [unhandled mode]");
+ return;
+ }
+ switch (encoding & MACH_O_UNWIND_ARM64_MODE_MASK)
+ {
+ case MACH_O_UNWIND_ARM64_MODE_FRAMELESS:
+ case MACH_O_UNWIND_ARM64_MODE_FRAME:
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_X19_X20_PAIR)
+ printf (" x19-x20");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_X21_X22_PAIR)
+ printf (" x21-x22");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_X23_X24_PAIR)
+ printf (" x23-x24");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_X25_X26_PAIR)
+ printf (" x25-x26");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_X27_X28_PAIR)
+ printf (" x27-x28");
+ break;
+ }
+ switch (encoding & MACH_O_UNWIND_ARM64_MODE_MASK)
+ {
+ case MACH_O_UNWIND_ARM64_MODE_FRAME:
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_D8_D9_PAIR)
+ printf (" d8-d9");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_D10_D11_PAIR)
+ printf (" d10-d11");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_D12_D13_PAIR)
+ printf (" d12-d13");
+ if (encoding & MACH_O_UNWIND_ARM64_FRAME_D14_D15_PAIR)
+ printf (" d14-d15");
+ break;
+ case MACH_O_UNWIND_ARM64_MODE_FRAMELESS:
+ printf (" size: %u",
+ (encoding & MACH_O_UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK) >> 8);
+ break;
+ }
+}
+
static void
dump_unwind_encoding (bfd_mach_o_data_struct *mdata, unsigned int encoding)
{
case BFD_MACH_O_CPU_TYPE_I386:
dump_unwind_encoding_x86 (encoding, 4, unwind_x86_regs);
break;
+ case BFD_MACH_O_CPU_TYPE_ARM64:
+ dump_unwind_encoding_arm64 (encoding);
+ break;
default:
printf (" [unhandled cpu]");
break;
e = (struct mach_o_compact_unwind_64 *) p;
putchar (' ');
- fprintf_vma (stdout, bfd_get_64 (abfd, e->start));
+ printf_uint64 (bfd_get_64 (abfd, e->start));
printf (" %08lx", bfd_get_32 (abfd, e->length));
putchar (' ');
- fprintf_vma (stdout, bfd_get_64 (abfd, e->personnality));
+ printf_uint64 (bfd_get_64 (abfd, e->personality));
putchar (' ');
- fprintf_vma (stdout, bfd_get_64 (abfd, e->lsda));
+ printf_uint64 (bfd_get_64 (abfd, e->lsda));
putchar ('\n');
printf (" encoding: ");
printf (" %u encodings, %u personalities, %u level-1 indexes:\n",
encodings_count, personality_count, index_count);
+ /* Personality. */
+ if (personality_count > 0)
+ {
+ const unsigned char *pers = content + personality_offset;
+
+ printf (" personalities\n");
+ for (i = 0; i < personality_count; i++)
+ printf (" %u: 0x%08x\n", i,
+ (unsigned) bfd_get_32 (abfd, pers + 4 * i));
+ }
+
/* Level-1 index. */
printf (" idx function level2 off lsda off\n");
+ 4 * (enc_idx - encodings_count);
encoding = bfd_get_32 (abfd, enc_addr);
- printf (" %-4u 0x%08x [%3u] ", j,
+ printf (" %4u 0x%08x [%3u] ", j,
func_offset + en_func, enc_idx);
dump_unwind_encoding (mdata, encoding);
putchar ('\n');
void (*dump)(bfd*, const unsigned char*, bfd_size_type))
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
- unsigned int i;
+ bfd_mach_o_load_command *cmd;
- for (i = 0; i < mdata->header.ncmds; i++)
+ for (cmd = mdata->first_command; cmd != NULL; cmd = cmd->next)
{
- 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)
{
dump_section_content (abfd, "__TEXT", "__unwind_info",
dump_exe_compact_unwind);
}
+ if (options[OPT_DYLD_INFO].selected)
+ dump_load_commands (abfd, BFD_MACH_O_LC_DYLD_INFO, 0);
}
/* Vector for Mach-O. */
const struct objdump_private_desc objdump_private_desc_mach_o =
- {
- mach_o_help,
- mach_o_filter,
- mach_o_dump,
- options
- };
+{
+ mach_o_help,
+ mach_o_filter,
+ mach_o_dump,
+ options
+};