summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Harmstone <mark@harmstone.com>2022-10-31 00:15:53 +0000
committerAlan Modra <amodra@gmail.com>2022-10-31 12:57:26 +1030
commita72672224093ca600154b934ba662b677ae10ba8 (patch)
treed49f11d0d38e0bdcd980a406f8524d4e81de581c
parent3c5e7c6dfcfa19904b4edc66b3e9f4eb41b28643 (diff)
ld: Add section header stream to PDB files
-rw-r--r--ld/pdb.c69
-rw-r--r--ld/testsuite/ld-pe/pdb.exp123
2 files changed, 189 insertions, 3 deletions
diff --git a/ld/pdb.c b/ld/pdb.c
index 80ed31e257a..1190dcf6cdf 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, &section_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 b62ce6da6f8..cee072187de 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"
+}