From 3cc27770cfa2080f70d44659de9d62adc80489fc Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Tue, 25 Mar 2014 15:51:54 +0100 Subject: [PATCH] Mach-O: add objdump -P function_starts to display function starts. bfd/ * mach-o.h (bfd_mach_o_get_base_address): New prototype. * mach-o.c (bfd_mach_o_write_symtab) (bfd_mach_o_write_contents) (bfd_mach_o_set_section_flags_from_bfd) (bfd_mach_o_build_seg_command): Fix indentation. (bfd_mach_o_get_base_address): New function. binutils/ * od-macho.c (OPT_FUNCTION_STARTS): New macro. (options): Add entry for function_starts. (mach_o_help): Ditto. (disp_segment_prot): New function. (dump_section_map): Call disp_segment_prot. (dump_function_starts): New function. (dump_obj_compact_unwind): Fix ouput indentation. (dump_exe_compact_unwind): Fix ouput indentation. (mach_o_dump): Handle function_starts. --- bfd/ChangeLog | 9 +++++ bfd/mach-o.c | 42 ++++++++++++++++++++--- bfd/mach-o.h | 2 ++ binutils/ChangeLog | 12 +++++++ binutils/od-macho.c | 97 ++++++++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 142 insertions(+), 20 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f2b5f9c..54b7834 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2014-03-27 Tristan Gingold + + * mach-o.h (bfd_mach_o_get_base_address): New prototype. + * mach-o.c (bfd_mach_o_write_symtab) + (bfd_mach_o_write_contents) + (bfd_mach_o_set_section_flags_from_bfd) + (bfd_mach_o_build_seg_command): Fix indentation. + (bfd_mach_o_get_base_address): New function. + 2014-03-26 Nick Clifton * cofflink.c (_bfd_coff_generic_relocate_section): Skip diff --git a/bfd/mach-o.c b/bfd/mach-o.c index 6237602..8e8842b 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -1478,7 +1478,7 @@ bfd_mach_o_write_symtab (bfd *abfd, bfd_mach_o_load_command *command) BFD_ASSERT (command->type == BFD_MACH_O_LC_SYMTAB); /* Write the symbols first. */ - mdata->filelen = FILE_ALIGN(mdata->filelen, wide ? 3 : 2); + mdata->filelen = FILE_ALIGN (mdata->filelen, wide ? 3 : 2); sym->symoff = mdata->filelen; if (bfd_seek (abfd, sym->symoff, SEEK_SET) != 0) return FALSE; @@ -2018,8 +2018,9 @@ bfd_mach_o_write_contents (bfd *abfd) case BFD_MACH_O_LC_SUB_FRAMEWORK: break; default: - (*_bfd_error_handler) (_("unable to write unknown load command 0x%lx"), - (unsigned long) cur->type); + (*_bfd_error_handler) + (_("unable to write unknown load command 0x%lx"), + (unsigned long) cur->type); return FALSE; } } @@ -2042,7 +2043,8 @@ bfd_mach_o_append_section_to_segment (bfd_mach_o_segment_command *seg, /* Create section Mach-O flags from BFD flags. */ static void -bfd_mach_o_set_section_flags_from_bfd (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) +bfd_mach_o_set_section_flags_from_bfd (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec) { flagword bfd_flags; bfd_mach_o_section *s = bfd_mach_o_get_mach_o_section (sec); @@ -2173,7 +2175,8 @@ bfd_mach_o_build_seg_command (const char *segment, mdata->filelen += s->size; } - /* Now pass through again, for zerofill, only now we just update the vmsize. */ + /* Now pass through again, for zerofill, only now we just update the + vmsize. */ for (i = 0; i < mdata->nsects; ++i) { bfd_mach_o_section *s = mdata->sections[i]; @@ -4274,6 +4277,35 @@ bfd_mach_o_gen_core_p (bfd *abfd) return bfd_mach_o_header_p (abfd, BFD_MACH_O_MH_CORE, 0); } +/* Return the base address of ABFD, ie the address at which the image is + mapped. The possible initial pagezero is ignored. */ + +bfd_vma +bfd_mach_o_get_base_address (bfd *abfd) +{ + bfd_mach_o_data_struct *mdata; + unsigned int i; + + /* Check for Mach-O. */ + if (!bfd_mach_o_valid (abfd)) + return 0; + mdata = bfd_mach_o_get_data (abfd); + + for (i = 0; i < mdata->header.ncmds; i++) + { + 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)) + { + struct bfd_mach_o_segment_command *segcmd = &cmd->command.segment; + + if (segcmd->initprot != 0) + return segcmd->vmaddr; + } + } + return 0; +} + typedef struct mach_o_fat_archentry { unsigned long cputype; diff --git a/bfd/mach-o.h b/bfd/mach-o.h index 6f695c5..4418b92 100644 --- a/bfd/mach-o.h +++ b/bfd/mach-o.h @@ -656,6 +656,8 @@ unsigned int bfd_mach_o_section_get_entry_size (bfd *, bfd_mach_o_section *); bfd_boolean bfd_mach_o_read_symtab_symbols (bfd *); bfd_boolean bfd_mach_o_read_symtab_strtab (bfd *abfd); +bfd_vma bfd_mach_o_get_base_address (bfd *); + /* A placeholder in case we need to suppress emitting the dysymtab for some reason (e.g. compatibility with older system versions). */ #define bfd_mach_o_should_emit_dysymtab(x) TRUE diff --git a/binutils/ChangeLog b/binutils/ChangeLog index b9fa77d..975979d 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,15 @@ +2014-03-27 Tristan Gingold + + * od-macho.c (OPT_FUNCTION_STARTS): New macro. + (options): Add entry for function_starts. + (mach_o_help): Ditto. + (disp_segment_prot): New function. + (dump_section_map): Call disp_segment_prot. + (dump_function_starts): New function. + (dump_obj_compact_unwind): Fix ouput indentation. + (dump_exe_compact_unwind): Fix ouput indentation. + (mach_o_dump): Handle function_starts. + 2014-03-26 Tristan Gingold * od-macho.c (bfd_mach_o_cpu_name): Add BFD_MACH_O_CPU_TYPE_ARM64. diff --git a/binutils/od-macho.c b/binutils/od-macho.c index 6f88112..4733e87 100644 --- a/binutils/od-macho.c +++ b/binutils/od-macho.c @@ -42,6 +42,7 @@ #define OPT_CODESIGN 5 #define OPT_SEG_SPLIT_INFO 6 #define OPT_COMPACT_UNWIND 7 +#define OPT_FUNCTION_STARTS 8 /* List of actions. */ static struct objdump_private_option options[] = @@ -54,6 +55,7 @@ static struct objdump_private_option options[] = { "codesign", 0 }, { "seg_split_info", 0 }, { "compact_unwind", 0 }, + { "function_starts", 0 }, { NULL, 0 } }; @@ -64,14 +66,15 @@ mach_o_help (FILE *stream) { 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\ ")); } @@ -284,6 +287,14 @@ dump_header (bfd *abfd) } 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 dump_section_map (bfd *abfd) { bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd); @@ -309,9 +320,7 @@ dump_section_map (bfd *abfd) 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) @@ -393,8 +402,13 @@ dump_segment (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_load_command *cmd) 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); } @@ -912,6 +926,55 @@ dump_segment_split_info (bfd *abfd, bfd_mach_o_linkedit_command *cmd) } 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 void dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd, bfd_boolean verbose) { @@ -1005,6 +1068,8 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd, dump_code_signature (abfd, linkedit); else if (verbose && cmd->type == BFD_MACH_O_LC_SEGMENT_SPLIT_INFO) dump_segment_split_info (abfd, linkedit); + else if (verbose && cmd->type == BFD_MACH_O_LC_FUNCTION_STARTS) + dump_function_starts (abfd, linkedit); break; } case BFD_MACH_O_LC_SUB_FRAMEWORK: @@ -1260,7 +1325,7 @@ dump_obj_compact_unwind (bfd *abfd, 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) @@ -1309,7 +1374,7 @@ dump_exe_compact_unwind (bfd *abfd, 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)) @@ -1544,6 +1609,8 @@ mach_o_dump (bfd *abfd) 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_COMPACT_UNWIND].selected) { dump_section_content (abfd, "__LD", "__compact_unwind", -- 2.7.4