From a72672224093ca600154b934ba662b677ae10ba8 Mon Sep 17 00:00:00 2001 From: Mark Harmstone Date: Mon, 31 Oct 2022 00:15:53 +0000 Subject: ld: Add section header stream to PDB files --- ld/pdb.c | 69 +++++++++++++++++++++++-- ld/testsuite/ld-pe/pdb.exp | 123 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 3 deletions(-) diff --git a/ld/pdb.c b/ld/pdb.c index 80ed31e..1190dcf 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -385,7 +385,8 @@ get_arch_number (bfd *abfd) /* Stream 4 is the debug information (DBI) stream. */ static bool -populate_dbi_stream (bfd *stream, bfd *abfd) +populate_dbi_stream (bfd *stream, bfd *abfd, + uint16_t section_header_stream_num) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; @@ -419,7 +420,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd) bfd_putl16 (0xffff, &opt.fixup_stream); bfd_putl16 (0xffff, &opt.omap_to_src_stream); bfd_putl16 (0xffff, &opt.omap_from_src_stream); - bfd_putl16 (0xffff, &opt.section_header_stream); + bfd_putl16 (section_header_stream_num, &opt.section_header_stream); bfd_putl16 (0xffff, &opt.token_map_stream); bfd_putl16 (0xffff, &opt.xdata_stream); bfd_putl16 (0xffff, &opt.pdata_stream); @@ -432,6 +433,60 @@ populate_dbi_stream (bfd *stream, bfd *abfd) return true; } +/* The section header stream contains a copy of the section headers + from the PE file, in the same format. */ +static bool +create_section_header_stream (bfd *pdb, bfd *abfd, uint16_t *num) +{ + bfd *stream; + unsigned int section_count; + file_ptr scn_base; + size_t len; + char *buf; + + stream = add_stream (pdb, NULL, num); + if (!stream) + return false; + + section_count = abfd->section_count; + + /* Empty sections aren't output. */ + for (asection *sect = abfd->sections; sect; sect = sect->next) + { + if (sect->size == 0) + section_count--; + } + + if (section_count == 0) + return true; + + /* Copy section table from output - it's already been written at this + point. */ + + scn_base = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); + + bfd_seek (abfd, scn_base, SEEK_SET); + + len = section_count * sizeof (struct external_scnhdr); + buf = xmalloc (len); + + if (bfd_bread (buf, len, abfd) != len) + { + free (buf); + return false; + } + + if (bfd_bwrite (buf, len, stream) != len) + { + free (buf); + return false; + } + + free (buf); + + return true; +} + /* Create a PDB debugging file for the PE image file abfd with the build ID guid, stored at pdb_name. */ bool @@ -440,6 +495,7 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) bfd *pdb; bool ret = false; bfd *info_stream, *dbi_stream, *names_stream; + uint16_t section_header_stream_num; pdb = bfd_openw (pdb_name, "pdb"); if (!pdb) @@ -498,7 +554,14 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) goto end; } - if (!populate_dbi_stream (dbi_stream, abfd)) + if (!create_section_header_stream (pdb, abfd, §ion_header_stream_num)) + { + einfo (_("%P: warning: cannot create section header stream " + "in PDB file: %E\n")); + goto end; + } + + if (!populate_dbi_stream (dbi_stream, abfd, section_header_stream_num)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index b62ce6d..cee0721 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -278,6 +278,123 @@ proc check_dbi_stream { pdb } { return 1 } +proc get_section_stream_index { pdb } { + global ar + + set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0003"] + + if ![string match "" $exec_output] { + return -1 + } + + set fi [open tmpdir/0003] + fconfigure $fi -translation binary + + # skip fields + seek $fi 24 + + # read substream sizes + + set data [read $fi 4] + binary scan $data i mod_info_size + + set data [read $fi 4] + binary scan $data i section_contribution_size + + set data [read $fi 4] + binary scan $data i section_map_size + + set data [read $fi 4] + binary scan $data i source_info_size + + set data [read $fi 4] + binary scan $data i type_server_map_size + + # skip type server index + seek $fi 4 current + + set data [read $fi 4] + binary scan $data i optional_dbg_header_size + + if { $optional_dbg_header_size < 12 } { + close $fi + return -1 + } + + # skip data + seek $fi [expr 12 + $mod_info_size + $section_contribution_size + $section_map_size + $source_info_size + $type_server_map_size + 10] current + + set data [read $fi 2] + binary scan $data s section_stream_index + + close $fi + + return $section_stream_index +} + +proc check_section_stream { img pdb } { + global ar + + # read sections stream + + set index [get_section_stream_index $pdb] + + if { $index == -1 } { + return 0 + } + + set index_str [format "%04x" $index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"] + + if ![string match "" $exec_output] { + return 0 + } + + set stream_length [file size tmpdir/$index_str] + + set fi [open tmpdir/$index_str] + fconfigure $fi -translation binary + + set stream_data [read $fi $stream_length] + + close $fi + + # read sections from PE file + + set fi [open $img] + fconfigure $fi -translation binary + + # read PE offset + read $fi 0x3c + set data [read $fi 4] + binary scan $data i pe_offset + + # read number of sections + seek $fi [expr $pe_offset + 6] + set data [read $fi 2] + binary scan $data s num_sections + + # read size of optional header + seek $fi 12 current + set data [read $fi 2] + binary scan $data s opt_header_size + + # read section headers + seek $fi [expr $opt_header_size + 2] current + set section_data [read $fi [expr $num_sections * 40]] + + close $fi + + # compare + + if { $stream_data ne $section_data} { + return 0 + } + + return 1 +} + if ![ld_assemble $as $srcdir/$subdir/pdb1.s tmpdir/pdb1.o] { unsupported "Build pdb1.o" return @@ -318,3 +435,9 @@ if [check_dbi_stream tmpdir/pdb1.pdb] { } else { fail "Invalid DBI stream" } + +if [check_section_stream tmpdir/pdb1.exe tmpdir/pdb1.pdb] { + pass "Valid section stream" +} else { + fail "Invalid section stream" +} -- cgit v1.1