4242#define OPT_CODESIGN 5
4343#define OPT_SEG_SPLIT_INFO 6
4444#define OPT_COMPACT_UNWIND 7
45+ #define OPT_FUNCTION_STARTS 8
4546
4647/* List of actions. */
4748static struct objdump_private_option options [] =
@@ -54,6 +55,7 @@ static struct objdump_private_option options[] =
5455 { "codesign" , 0 },
5556 { "seg_split_info" , 0 },
5657 { "compact_unwind" , 0 },
58+ { "function_starts" , 0 },
5759 { NULL , 0 }
5860 };
5961
@@ -64,14 +66,15 @@ mach_o_help (FILE *stream)
6466{
6567 fprintf (stream , _ ("\
6668For Mach-O files:\n\
67- header Display the file header\n\
68- section Display the segments and sections commands\n\
69- map Display the section map\n\
70- load Display the load commands\n\
71- dysymtab Display the dynamic symbol table\n\
72- codesign Display code signature\n\
73- seg_split_info Display segment split info\n\
74- compact_unwind Display compact unwinding info\n\
69+ header Display the file header\n\
70+ section Display the segments and sections commands\n\
71+ map Display the section map\n\
72+ load Display the load commands\n\
73+ dysymtab Display the dynamic symbol table\n\
74+ codesign Display code signature\n\
75+ seg_split_info Display segment split info\n\
76+ compact_unwind Display compact unwinding info\n\
77+ function_starts Display start address of functions\n\
7578" ));
7679}
7780
@@ -283,6 +286,14 @@ dump_header (bfd *abfd)
283286 printf (_ (" reserved : %08x\n" ), h -> reserved );
284287}
285288
289+ static void
290+ disp_segment_prot (unsigned int prot )
291+ {
292+ putchar (prot & BFD_MACH_O_PROT_READ ? 'r' : '-' );
293+ putchar (prot & BFD_MACH_O_PROT_WRITE ? 'w' : '-' );
294+ putchar (prot & BFD_MACH_O_PROT_EXECUTE ? 'x' : '-' );
295+ }
296+
286297static void
287298dump_section_map (bfd * abfd )
288299{
@@ -309,9 +320,7 @@ dump_section_map (bfd *abfd)
309320 putchar ('-' );
310321 printf_vma (seg -> vmaddr + seg -> vmsize - 1 );
311322 putchar (' ' );
312- putchar (seg -> initprot & BFD_MACH_O_PROT_READ ? 'r' : '-' );
313- putchar (seg -> initprot & BFD_MACH_O_PROT_WRITE ? 'w' : '-' );
314- putchar (seg -> initprot & BFD_MACH_O_PROT_EXECUTE ? 'x' : '-' );
323+ disp_segment_prot (seg -> initprot );
315324 printf ("]\n" );
316325
317326 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)
393402 printf (" endoff: " );
394403 printf_vma ((bfd_vma )(seg -> fileoff + seg -> filesize ));
395404 printf ("\n" );
396- printf (" nsects: %lu " , seg -> nsects );
397- printf (" flags: %lx\n" , seg -> flags );
405+ printf (" nsects: %lu" , seg -> nsects );
406+ printf (" flags: %lx" , seg -> flags );
407+ printf (" initprot: " );
408+ disp_segment_prot (seg -> initprot );
409+ printf (" maxprot: " );
410+ disp_segment_prot (seg -> maxprot );
411+ printf ("\n" );
398412 for (sec = seg -> sect_head ; sec != NULL ; sec = sec -> next )
399413 dump_section_header (abfd , sec );
400414}
@@ -911,6 +925,55 @@ dump_segment_split_info (bfd *abfd, bfd_mach_o_linkedit_command *cmd)
911925 free (buf );
912926}
913927
928+ static void
929+ dump_function_starts (bfd * abfd , bfd_mach_o_linkedit_command * cmd )
930+ {
931+ unsigned char * buf = xmalloc (cmd -> datasize );
932+ unsigned char * end_buf = buf + cmd -> datasize ;
933+ unsigned char * p ;
934+ bfd_vma addr ;
935+
936+ if (bfd_seek (abfd , cmd -> dataoff , SEEK_SET ) != 0
937+ || bfd_bread (buf , cmd -> datasize , abfd ) != cmd -> datasize )
938+ {
939+ non_fatal (_ ("cannot read function starts" ));
940+ free (buf );
941+ return ;
942+ }
943+
944+ /* Function starts are delta encoded, starting from the base address. */
945+ addr = bfd_mach_o_get_base_address (abfd );
946+
947+ for (p = buf ; ;)
948+ {
949+ bfd_vma delta = 0 ;
950+ unsigned int shift = 0 ;
951+
952+ if (* p == 0 || p == end_buf )
953+ break ;
954+ while (1 )
955+ {
956+ unsigned char b = * p ++ ;
957+
958+ delta |= (b & 0x7f ) << shift ;
959+ if ((b & 0x80 ) == 0 )
960+ break ;
961+ if (p == end_buf )
962+ {
963+ fputs (" [truncated]\n" , stdout );
964+ break ;
965+ }
966+ shift += 7 ;
967+ }
968+
969+ addr += delta ;
970+ fputs (" " , stdout );
971+ bfd_printf_vma (abfd , addr );
972+ putchar ('\n' );
973+ }
974+ free (buf );
975+ }
976+
914977static void
915978dump_load_command (bfd * abfd , bfd_mach_o_load_command * cmd ,
916979 bfd_boolean verbose )
@@ -1005,6 +1068,8 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
10051068 dump_code_signature (abfd , linkedit );
10061069 else if (verbose && cmd -> type == BFD_MACH_O_LC_SEGMENT_SPLIT_INFO )
10071070 dump_segment_split_info (abfd , linkedit );
1071+ else if (verbose && cmd -> type == BFD_MACH_O_LC_FUNCTION_STARTS )
1072+ dump_function_starts (abfd , linkedit );
10081073 break ;
10091074 }
10101075 case BFD_MACH_O_LC_SUB_FRAMEWORK :
@@ -1260,7 +1325,7 @@ dump_obj_compact_unwind (bfd *abfd,
12601325 int is_64 = mdata -> header .version == 2 ;
12611326 const unsigned char * p ;
12621327
1263- printf (" compact unwind info:\n" );
1328+ printf ("Compact unwind info:\n" );
12641329 printf (" start length personality lsda\n" );
12651330
12661331 if (is_64 )
@@ -1309,7 +1374,7 @@ dump_exe_compact_unwind (bfd *abfd,
13091374 unsigned int i ;
13101375
13111376 /* The header. */
1312- printf (" compact unwind info:\n" );
1377+ printf ("Compact unwind info:\n" );
13131378
13141379 hdr = (struct mach_o_unwind_info_header * ) content ;
13151380 if (size < sizeof (* hdr ))
@@ -1544,6 +1609,8 @@ mach_o_dump (bfd *abfd)
15441609 dump_load_commands (abfd , BFD_MACH_O_LC_CODE_SIGNATURE , 0 );
15451610 if (options [OPT_SEG_SPLIT_INFO ].selected )
15461611 dump_load_commands (abfd , BFD_MACH_O_LC_SEGMENT_SPLIT_INFO , 0 );
1612+ if (options [OPT_FUNCTION_STARTS ].selected )
1613+ dump_load_commands (abfd , BFD_MACH_O_LC_FUNCTION_STARTS , 0 );
15471614 if (options [OPT_COMPACT_UNWIND ].selected )
15481615 {
15491616 dump_section_content (abfd , "__LD" , "__compact_unwind" ,
0 commit comments