2014-10-01 Pierre Muller Add support for pdata output for pe coff objects. * pe-x86_64.c (pex64_bfd_print_pdata): Add external declaration. (bfd_pe_print_data): Set macro to pex64_bfd_print_data. * pei-x86_64.c (pex64_bfd_print_pdata): Changed to global function. Now handles multiple .pdata sections. (pex_bfd_print_pdata_section): New static helper function, using most of old pex_bfd_print_pdata function code, but adding support for coff pe objects, which might have some fields starting at zero offset. (pex64_print_all_pdata_sections) : New static helper function, used in call to bfd_map_over_sections inside new pex66_bfd_print_pdata function. (bfd_boolean pdata_count): New static variable, used to return bfd_boolean value for pex64_bfd_print_pdata function. diff --git a/bfd/pe-x86_64.c b/bfd/pe-x86_64.c index 673a544..6fe519f 100644 --- a/bfd/pe-x86_64.c +++ b/bfd/pe-x86_64.c @@ -58,6 +58,12 @@ { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } +/* The function pex64_bfd_print_pdata is implemented in pei-x86_64.c + source, but has be extended to also handle pe objects. */ +extern bfd_boolean pex64_bfd_print_pdata (bfd * abfd, void * vfile); + +#define bfd_pe_print_pdata pex64_bfd_print_pdata + #include "coff-x86_64.c" /* Entry for big object files. */ diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c index 48554d3..37268e3 100644 --- a/bfd/pei-x86_64.c +++ b/bfd/pei-x86_64.c @@ -439,23 +439,24 @@ sort_xdata_arr (const void *l, const void *r) /* Display unwind tables for x86-64. */ static bfd_boolean -pex64_bfd_print_pdata (bfd *abfd, void *vfile) +pex64_bfd_print_pdata_section (bfd *abfd, void *vfile, asection *pdata_section) { FILE *file = (FILE *) vfile; bfd_byte *pdata = NULL; bfd_byte *xdata = NULL; - asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata"); - asection *xdata_section; + asection *xdata_section = NULL; bfd_vma xdata_base; bfd_size_type i; + bfd_size_type datasize; bfd_size_type stop; - bfd_vma prev_beginaddress = 0; - bfd_vma prev_unwinddata_rva = 0; + bfd_vma prev_beginaddress = (bfd_vma) -1; + bfd_vma prev_unwinddata_rva = (bfd_vma) -1; bfd_vma imagebase; int onaline = PDATA_ROW_SIZE; int seen_error = 0; bfd_vma *xdata_arr = NULL; int xdata_arr_cnt; + int virt_size_is_zero = 0; /* Sanity checks. */ if (pdata_section == NULL @@ -466,12 +467,37 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) stop = pei_section_data (abfd, pdata_section)->virt_size; if ((stop % onaline) != 0) fprintf (file, - _("warning: .pdata section size (%ld) is not a multiple of %d\n"), - (long) stop, onaline); + _("warning: %s section size (%ld) is not a multiple of %d\n"), + pdata_section->name, (long) stop, onaline); + + datasize = pdata_section->size; + if (datasize == 0) + { + if (stop) + fprintf (file, _("Warning, %s section size is zero sized\n"), + pdata_section->name); + return TRUE; + } + + /* virt_size might be zero for objects. */ + if (stop == 0 && strcmp (abfd->xvec->name, "pe-x86-64") == 0) + { + stop = (datasize / onaline) * onaline; + virt_size_is_zero = 1; + } + else if (datasize < stop) + { + fprintf (file, + _("Warning, %s section size is smaller than virtual size\n"), + pdata_section->name); + /* Be sure not to read passed datasize. */ + stop = datasize / onaline; + } /* Display functions table. */ fprintf (file, - _("\nThe Function Table (interpreted .pdata section contents)\n")); + _("\nThe Function Table (interpreted %s section contents)\n"), + pdata_section->name); fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t UnwindData\n")); @@ -482,7 +508,10 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1)); xdata_arr_cnt = 0; - imagebase = pe_data (abfd)->pe_opthdr.ImageBase; + if (strcmp (abfd->xvec->name, "pei-x86-64") == 0) + imagebase = pe_data (abfd)->pe_opthdr.ImageBase; + else + imagebase = 0; for (i = 0; i < stop; i += onaline) { @@ -528,8 +557,8 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) seen_error = 1; fprintf (file, " has negative unwind address\n"); } - if (rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf)) - xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData; + else if (rf.rva_UnwindData != 0 || virt_size_is_zero) + xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData; } if (seen_error) @@ -545,20 +574,42 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) /* Find the section containing the unwind data (.xdata). */ xdata_base = xdata_arr[0]; - xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata"); - if (!xdata_section) - xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data"); + /* For sections with long names, first look for the same section name, + replacing .pdata by .xdata prefix. */ + if (strcmp (pdata_section->name, ".pdata") != 0) + { + char *xdata_name = alloca (strlen (pdata_section->name + 1)); + + xdata_name = strcpy (xdata_name, pdata_section->name); + // transform .pdata prefix into .xdata prefix + if (strlen (xdata_name) > 1) + xdata_name [1] = 'x'; + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, + xdata_name); + } + /* Second, try the .xdata section itself. */ if (!xdata_section) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".xdata"); - if (!xdata_section) + /* Otherwise, if xdata_base is non zero, search also inside + other standard sections. */ + if (!xdata_section && xdata_base) + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata"); + if (!xdata_section && xdata_base) + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data"); + if (!xdata_section && xdata_base) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata"); - if (!xdata_section) + if (!xdata_section && xdata_base) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text"); + /* Transfer xdata section into xdata array. */ if (!xdata_section || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata)) goto done; + /* Avoid "also used "... ouput for single unwind info + in object file. */ + prev_unwinddata_rva = (bfd_vma) -1; + /* Do dump of pdata related xdata. */ for (i = 0; i < stop; i += onaline) { @@ -573,7 +624,7 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) /* We are probably into the padding of the section now. */ break; if (i == 0) - fprintf (file, "\nDump of .xdata\n"); + fprintf (file, "\nDump of %s\n", xdata_section->name); fputc (' ', file); fprintf_vma (file, rf.rva_UnwindData + imagebase); @@ -596,7 +647,7 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) fprintf_vma (file, rf.rva_EndAddress + imagebase); fputc ('\n', file); - if (rf.rva_UnwindData != 0) + if (rf.rva_UnwindData != 0 || virt_size_is_zero) { if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf)) { @@ -651,6 +702,41 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile) return TRUE; } + +/* Static counter of number of found pdata sections. */ +static bfd_boolean pdata_count; + +/* Functionn prototype. */ +bfd_boolean pex64_bfd_print_pdata (bfd *abfd, void *vfile); + +/* Helper function for bfd_map_over_section. */ +static void +pex64_print_all_pdata_sections (bfd *abfd, asection *pdata, void *obj) +{ + if (strncmp (pdata->name, ".pdata", + strlen (".pdata")) == 0) + { + if (pex64_bfd_print_pdata_section (abfd, obj, pdata)) + pdata_count++; + } +} + +bfd_boolean +pex64_bfd_print_pdata (bfd *abfd, void *vfile) +{ + asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata"); + + if (pdata_section) + return pex64_bfd_print_pdata_section (abfd, vfile, pdata_section); + else + { + pdata_count = 0; + bfd_map_over_sections (abfd, pex64_print_all_pdata_sections, vfile); + return (pdata_count > 0); + } +} + #define bfd_pe_print_pdata pex64_bfd_print_pdata +#define bfd_coff_std_swap_table bfd_coff_pei_swap_table #include "coff-x86_64.c"