#define OPT_CODESIGN 5
#define OPT_SEG_SPLIT_INFO 6
#define OPT_COMPACT_UNWIND 7
+#define OPT_FUNCTION_STARTS 8
+#define OPT_DATA_IN_CODE 9
/* List of actions. */
static struct objdump_private_option options[] =
{ "codesign", 0 },
{ "seg_split_info", 0 },
{ "compact_unwind", 0 },
+ { "function_starts", 0 },
+ { "data_in_code", 0 },
{ NULL, 0 }
};
{
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\
+ data_in_code Display data in code entries\n\
"));
}
{ "powerpc", BFD_MACH_O_CPU_TYPE_POWERPC },
{ "powerpc_64", BFD_MACH_O_CPU_TYPE_POWERPC_64 },
{ "x86_64", BFD_MACH_O_CPU_TYPE_X86_64 },
+ { "arm64", BFD_MACH_O_CPU_TYPE_ARM64 },
{ NULL, 0}
};
bfd_mach_o_print_flags (bfd_mach_o_header_flags_name, h->flags);
fputs (_(")\n"), stdout);
printf (_(" reserved : %08x\n"), h->reserved);
+ putchar ('\n');
+}
+
+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
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)
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);
}
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 const bfd_mach_o_xlat_name data_in_code_kind_name[] =
+{
+ { "data", BFD_MACH_O_DICE_KIND_DATA },
+ { "1 byte jump table", BFD_MACH_O_DICE_JUMP_TABLES8 },
+ { "2 bytes jump table", BFD_MACH_O_DICE_JUMP_TABLES16 },
+ { "4 bytes jump table", BFD_MACH_O_DICE_JUMP_TABLES32 },
+ { "4 bytes abs jump table", BFD_MACH_O_DICE_ABS_JUMP_TABLES32 },
+ { NULL, 0 }
+};
+
+static void
+dump_data_in_code (bfd *abfd, bfd_mach_o_linkedit_command *cmd)
+{
+ unsigned char *buf;
+ unsigned char *p;
+
+ if (cmd->datasize == 0)
+ {
+ printf (" no data_in_code entries\n");
+ return;
+ }
+
+ buf = xmalloc (cmd->datasize);
+ 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;
+ }
+
+ printf (" offset length kind\n");
+ for (p = buf; p < buf + cmd->datasize; )
+ {
+ struct mach_o_data_in_code_entry_external *dice;
+ unsigned int offset;
+ unsigned int length;
+ unsigned int kind;
+
+ dice = (struct mach_o_data_in_code_entry_external *) p;
+
+ offset = bfd_get_32 (abfd, dice->offset);
+ length = bfd_get_16 (abfd, dice->length);
+ kind = bfd_get_16 (abfd, dice->kind);
+
+ printf (" 0x%08x 0x%04x 0x%04x %s\n", offset, length, kind,
+ bfd_mach_o_get_name (data_in_code_kind_name, kind));
+
+ p += sizeof (*dice);
+ }
+ free (buf);
+}
+
static void
dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
bfd_boolean verbose)
case BFD_MACH_O_LC_ID_DYLINKER:
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);
+ break;
case BFD_MACH_O_LC_SYMTAB:
{
bfd_mach_o_symtab_command *symtab = &cmd->command.symtab;
case BFD_MACH_O_LC_CODE_SIGNATURE:
case BFD_MACH_O_LC_SEGMENT_SPLIT_INFO:
case BFD_MACH_O_LC_FUNCTION_STARTS:
+ case BFD_MACH_O_LC_DATA_IN_CODE:
+ case BFD_MACH_O_LC_DYLIB_CODE_SIGN_DRS:
{
bfd_mach_o_linkedit_command *linkedit = &cmd->command.linkedit;
printf
linkedit->dataoff, linkedit->datasize,
linkedit->dataoff + linkedit->datasize);
- if (verbose && cmd->type == BFD_MACH_O_LC_CODE_SIGNATURE)
- dump_code_signature (abfd, linkedit);
- else if (verbose && cmd->type == BFD_MACH_O_LC_SEGMENT_SPLIT_INFO)
- dump_segment_split_info (abfd, linkedit);
- break;
+ if (verbose)
+ switch (cmd->type)
+ {
+ case BFD_MACH_O_LC_CODE_SIGNATURE:
+ dump_code_signature (abfd, linkedit);
+ break;
+ case BFD_MACH_O_LC_SEGMENT_SPLIT_INFO:
+ dump_segment_split_info (abfd, linkedit);
+ break;
+ case BFD_MACH_O_LC_FUNCTION_STARTS:
+ dump_function_starts (abfd, linkedit);
+ break;
+ case BFD_MACH_O_LC_DATA_IN_CODE:
+ dump_data_in_code (abfd, linkedit);
+ break;
+ default:
+ break;
+ }
}
+ break;
case BFD_MACH_O_LC_SUB_FRAMEWORK:
case BFD_MACH_O_LC_SUB_UMBRELLA:
case BFD_MACH_O_LC_SUB_LIBRARY:
stack_adj =
(encoding & MACH_O_UNWIND_X86_64_FRAMELESS_STACK_ADJUST) >> 13;
- printf (" size at 0x%03x + 0x%02x", stack_size, stack_adj);
+ printf (" size at 0x%03x + 0x%02x", stack_size, stack_adj * sz);
}
/* Registers are coded using arithmetic compression: the register
is indexed in range 0-6, the second in range 0-5, the third in
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)
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))
const unsigned char *level2;
unsigned int kind;
- if (i == index_count - 1)
- break;
-
func_offset = bfd_get_32 (abfd, index_entry->function_offset);
level2_offset = bfd_get_32 (abfd, index_entry->second_level_offset);
+ /* No level-2 for this index (should be the last index). */
+ if (level2_offset == 0)
+ continue;
+
level2 = content + level2_offset;
kind = bfd_get_32 (abfd, level2);
switch (kind)
nbr_lsda = (next_lsda_offset - lsda_offset) / sizeof (*lsda);
for (j = 0; j < nbr_lsda; j++)
{
- printf (" lsda %-3u: function 0x%08x lsda 0x%08x\n",
+ printf (" lsda %3u: function 0x%08x lsda 0x%08x\n",
j, (unsigned int) bfd_get_32 (abfd, lsda->function_offset),
(unsigned int) bfd_get_32 (abfd, lsda->lsda_offset));
lsda++;
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_DATA_IN_CODE].selected)
+ dump_load_commands (abfd, BFD_MACH_O_LC_DATA_IN_CODE, 0);
if (options[OPT_COMPACT_UNWIND].selected)
{
dump_section_content (abfd, "__LD", "__compact_unwind",