1 # Expect script for creating PDB files when linking.
2 # Copyright (C) 2022-2025 Free Software Foundation, Inc.
4 # This file is part of the GNU Binutils.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 if {![istarget i*86-*-mingw*]
22 && ![istarget i*86-*-cygwin*]
23 && ![istarget i*86-*-winnt]
24 && ![istarget i*86-*-pe]
25 && ![istarget x86_64-*-mingw*]
26 && ![istarget x86_64-*-pe*]
27 && ![istarget x86_64-*-cygwin]
28 && ![istarget aarch64-*-mingw*]
29 && ![istarget aarch64-*-pe*]} {
33 proc get_pdb_name { pe } {
36 set exec_output [run_host_cmd "$OBJDUMP" "-p $pe"]
38 if ![regexp -line "^\\(format RSDS signature (\[0-9a-fA-F\]{32}) age 1 pdb (.*)\\)$" $exec_output full sig pdb] {
45 proc get_pdb_guid { pe } {
48 set exec_output [run_host_cmd "$OBJDUMP" "-p $pe"]
50 if ![regexp -line "^\\(format RSDS signature (\[0-9a-fA-F\]{32}) age 1 pdb (.*)\\)$" $exec_output full sig pdb] {
57 proc check_pdb_info_stream { pdb guid } {
60 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0001"]
62 if ![string match "" $exec_output] {
66 set fi [open tmpdir/0001]
67 fconfigure $fi -translation binary
72 binary scan $data i version
74 if { $version != 20000404 } {
79 # skip signature (timestamp)
85 binary scan $data i age
94 set data [read $fi 16]
95 binary scan $data H2H2H2H2H2H2H2H2H* guid1 guid2 guid3 guid4 guid5 guid6 guid7 guid8 guid9
97 set data "$guid4$guid3$guid2$guid1$guid6$guid5$guid8$guid7$guid9"
99 if { $data ne $guid } {
106 set data [read $fi 4]
107 binary scan $data i names_length
108 read $fi $names_length
110 # read number of names entries
112 set data [read $fi 4]
113 binary scan $data i num_entries
115 # skip number of buckets
118 # skip present bitmap
120 set data [read $fi 4]
121 binary scan $data i bitmap_length
122 read $fi [expr $bitmap_length * 4]
124 # skip deleted bitmap
126 set data [read $fi 4]
127 binary scan $data i bitmap_length
128 read $fi [expr $bitmap_length * 4]
131 read $fi [expr $num_entries * 8]
136 # read second version
138 set data [read $fi 4]
139 binary scan $data i version2
141 if { $version2 != 20140508 } {
151 proc check_type_stream { pdb stream } {
154 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $stream"]
156 if ![string match "" $exec_output] {
160 set fi [open tmpdir/$stream]
161 fconfigure $fi -translation binary
165 set data [read $fi 4]
166 binary scan $data i version
168 if { $version != 20040203 } {
175 set data [read $fi 4]
176 binary scan $data i header_size
178 if { $header_size != 0x38 } {
183 # skip type_index_begin and type_index_end
186 # read type_record_bytes
188 set data [read $fi 4]
189 binary scan $data i type_record_bytes
193 # check stream length
195 set stream_length [file size tmpdir/$stream]
197 if { $stream_length != [ expr $header_size + $type_record_bytes ] } {
204 proc check_dbi_stream { pdb } {
207 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0003"]
209 if ![string match "" $exec_output] {
213 set fi [open tmpdir/0003]
214 fconfigure $fi -translation binary
218 set data [read $fi 4]
219 binary scan $data i signature
221 if { $signature != -1 } {
228 set data [read $fi 4]
229 binary scan $data i version
231 if { $version != 19990903 } {
238 set data [read $fi 4]
239 binary scan $data i age
249 # read substream sizes
251 set data [read $fi 4]
252 binary scan $data i mod_info_size
254 set data [read $fi 4]
255 binary scan $data i section_contribution_size
257 set data [read $fi 4]
258 binary scan $data i section_map_size
260 set data [read $fi 4]
261 binary scan $data i source_info_size
263 set data [read $fi 4]
264 binary scan $data i type_server_map_size
266 # skip MFC type server index
269 set data [read $fi 4]
270 binary scan $data i optional_dbg_header_size
272 set data [read $fi 4]
273 binary scan $data i ec_substream_size
277 # check stream length
279 set stream_length [file size tmpdir/0003]
281 if { $stream_length != [expr 0x40 + $mod_info_size + $section_contribution_size + $section_map_size + $source_info_size + $type_server_map_size + $optional_dbg_header_size + $ec_substream_size] } {
288 proc get_section_stream_index { pdb } {
291 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0003"]
293 if ![string match "" $exec_output] {
297 set fi [open tmpdir/0003]
298 fconfigure $fi -translation binary
303 # read substream sizes
305 set data [read $fi 4]
306 binary scan $data i mod_info_size
308 set data [read $fi 4]
309 binary scan $data i section_contribution_size
311 set data [read $fi 4]
312 binary scan $data i section_map_size
314 set data [read $fi 4]
315 binary scan $data i source_info_size
317 set data [read $fi 4]
318 binary scan $data i type_server_map_size
320 # skip type server index
323 set data [read $fi 4]
324 binary scan $data i optional_dbg_header_size
326 if { $optional_dbg_header_size < 12 } {
332 seek $fi [expr 12 + $mod_info_size + $section_contribution_size + $section_map_size + $source_info_size + $type_server_map_size + 10] current
334 set data [read $fi 2]
335 binary scan $data s section_stream_index
339 return $section_stream_index
342 proc check_section_stream { img pdb } {
345 # read sections stream
347 set index [get_section_stream_index $pdb]
349 if { $index == -1 } {
353 set index_str [format "%04x" $index]
355 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"]
357 if ![string match "" $exec_output] {
361 set stream_length [file size tmpdir/$index_str]
363 set fi [open tmpdir/$index_str]
364 fconfigure $fi -translation binary
366 set stream_data [read $fi $stream_length]
370 # read sections from PE file
373 fconfigure $fi -translation binary
377 set data [read $fi 4]
378 binary scan $data i pe_offset
380 # read number of sections
381 seek $fi [expr $pe_offset + 6]
382 set data [read $fi 2]
383 binary scan $data s num_sections
385 # read size of optional header
387 set data [read $fi 2]
388 binary scan $data s opt_header_size
390 # read section headers
391 seek $fi [expr $opt_header_size + 2] current
392 set section_data [read $fi [expr $num_sections * 40]]
398 if { $stream_data ne $section_data} {
405 proc get_publics_stream_index { pdb } {
408 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0003"]
410 if ![string match "" $exec_output] {
414 set fi [open tmpdir/0003]
415 fconfigure $fi -translation binary
420 # read substream sizes
422 set data [read $fi 2]
423 binary scan $data s index
430 proc get_sym_record_stream_index { pdb } {
433 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0003"]
435 if ![string match "" $exec_output] {
439 set fi [open tmpdir/0003]
440 fconfigure $fi -translation binary
445 # read substream sizes
447 set data [read $fi 2]
448 binary scan $data s index
455 proc check_publics_stream { pdb } {
461 set publics_index [get_publics_stream_index $pdb]
463 if { $publics_index == -1 } {
467 set index_str [format "%04x" $publics_index]
469 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"]
471 if ![string match "" $exec_output] {
475 set exp [file_contents "$srcdir/$subdir/pdb1-publics.d"]
476 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
477 if ![string match $exp $got] {
481 set sym_record_index [get_sym_record_stream_index $pdb]
483 if { $sym_record_index == -1 } {
487 set index_str [format "%04x" $sym_record_index]
489 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"]
491 if ![string match "" $exec_output] {
495 set exp [file_contents "$srcdir/$subdir/pdb1-sym-record.d"]
496 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
497 if ![string match $exp $got] {
510 if ![ld_assemble $as $srcdir/$subdir/pdb1.s tmpdir/pdb1.o] {
511 unsupported "Build pdb1.o"
515 if ![ld_link $ld "tmpdir/pdb1.exe" "--pdb=tmpdir/pdb1.pdb --gc-sections -e foo tmpdir/pdb1.o"] {
516 fail "Could not create a PE image with a PDB file"
520 if ![string equal [get_pdb_name "tmpdir/pdb1.exe"] "pdb1.pdb"] {
521 fail "PDB filename not found in CodeView debug info"
525 pass "PDB filename present in CodeView debug info"
527 if [check_pdb_info_stream tmpdir/pdb1.pdb [get_pdb_guid "tmpdir/pdb1.exe"]] {
528 pass "Valid PDB info stream"
530 fail "Invalid PDB info stream"
533 if [check_type_stream tmpdir/pdb1.pdb "0002"] {
534 pass "Valid TPI stream"
536 fail "Invalid TPI stream"
539 if [check_type_stream tmpdir/pdb1.pdb "0004"] {
540 pass "Valid IPI stream"
542 fail "Invalid IPI stream"
545 if [check_dbi_stream tmpdir/pdb1.pdb] {
546 pass "Valid DBI stream"
548 fail "Invalid DBI stream"
551 if [check_section_stream tmpdir/pdb1.exe tmpdir/pdb1.pdb] {
552 pass "Valid section stream"
554 fail "Invalid section stream"
557 if [check_publics_stream tmpdir/pdb1.pdb] {
558 pass "Valid publics stream"
560 fail "Invalid publics stream"
564 proc test_mod_info { mod_info } {
565 # check filenames in mod_info
569 set obj1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
570 incr off [expr [string length $obj1] + 1]
572 set ar1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
573 incr off [expr [string length $ar1] + 1]
575 if [string match "*pdb2a.o" $obj1] {
576 pass "Correct name for first object file"
578 fail "Incorrect name for first object file"
581 if [string equal $obj1 $ar1] {
582 pass "Correct archive name for first object file"
584 fail "Incorrect archive name for first object file"
587 if { [expr $off % 4] != 0 } {
588 set off [expr $off + 4 - ($off % 4)]
593 set obj2 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
594 incr off [expr [string length $obj2] + 1]
596 set ar2 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
597 incr off [expr [string length $ar2] + 1]
599 if [string match "*pdb2b.o" $obj2] {
600 pass "Correct name for second object file"
602 fail "Incorrect name for second object file"
605 if [string match "*pdb2b.a" $ar2] {
606 pass "Correct archive name for second object file"
608 fail "Incorrect archive name for second object file"
611 if { [expr $off % 4] != 0 } {
612 set off [expr $off + 4 - ($off % 4)]
616 proc test_section_contrib { section_contrib } {
621 set fi [open tmpdir/pdb2-sc w]
622 fconfigure $fi -translation binary
623 puts -nonewline $fi $section_contrib
626 set exp [file_contents "$srcdir/$subdir/pdb2-section-contrib.d"]
627 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb2-sc"]
629 if [string equal $exp $got] {
630 pass "Correct section contribution substream"
632 fail "Incorrect section contribution substream"
643 if ![ld_assemble $as $srcdir/$subdir/pdb2a.s tmpdir/pdb2a.o] {
644 unsupported "Build pdb2a.o"
648 if ![ld_assemble $as $srcdir/$subdir/pdb2b.s tmpdir/pdb2b.o] {
649 unsupported "Build pdb2b.o"
653 set exec_output [run_host_cmd "$ar" "cr tmpdir/pdb2b.a tmpdir/pdb2b.o"]
655 if ![string match "" $exec_output] {
656 unsupported "Create pdb2b.a"
660 if ![ld_link $ld "tmpdir/pdb2.exe" "--pdb=tmpdir/pdb2.pdb --gc-sections --disable-reloc-section -e foo tmpdir/pdb2a.o tmpdir/pdb2b.a"] {
661 unsupported "Create PE image with PDB file"
665 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb2.pdb 0003"]
667 if ![string match "" $exec_output] {
671 set fi [open tmpdir/0003]
672 fconfigure $fi -translation binary
676 set data [read $fi 4]
677 binary scan $data i mod_info_size
679 set data [read $fi 4]
680 binary scan $data i section_contrib_size
684 set mod_info [read $fi $mod_info_size]
685 set section_contrib [read $fi $section_contrib_size]
689 test_mod_info $mod_info
690 test_section_contrib $section_contrib
693 proc find_named_stream { pdb name } {
696 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0001"]
698 if ![string match "" $exec_output] {
702 set fi [open tmpdir/0001]
703 fconfigure $fi -translation binary
707 set data [read $fi 4]
708 binary scan $data i string_len
710 set strings [read $fi $string_len]
714 while {[string first \000 $strings $string_off] != -1 } {
715 set str [string range $strings $string_off [expr [string first \000 $strings $string_off] - 1]]
717 if { $str eq $name } {
721 incr string_off [expr [string length $str] + 1]
724 if { [string length $strings] == $string_off } { # string not found
729 set data [read $fi 4]
730 binary scan $data i num_entries
734 set data [read $fi 4]
735 binary scan $data i present_bitmap_len
737 seek $fi [expr $present_bitmap_len * 4] current
739 set data [read $fi 4]
740 binary scan $data i deleted_bitmap_len
742 seek $fi [expr $deleted_bitmap_len * 4] current
744 for {set i 0} {$i < $num_entries} {incr i} {
745 set data [read $fi 4]
746 binary scan $data i offset
748 if { $offset == $string_off } {
749 set data [read $fi 4]
750 binary scan $data i value
772 if ![ld_assemble $as $srcdir/$subdir/pdb-strings1.s tmpdir/pdb-strings1.o] {
773 unsupported "Build pdb-strings1.o"
777 if ![ld_assemble $as $srcdir/$subdir/pdb-strings2.s tmpdir/pdb-strings2.o] {
778 unsupported "Build pdb-strings2.o"
782 if ![ld_link $ld "tmpdir/pdb-strings.exe" "--pdb=tmpdir/pdb-strings.pdb tmpdir/pdb-strings1.o tmpdir/pdb-strings2.o"] {
783 unsupported "Create PE image with PDB file"
787 set index [find_named_stream "tmpdir/pdb-strings.pdb" "/names"]
790 fail "Could not find /names stream"
793 pass "Found /names stream"
796 set index_str [format "%04x" $index]
798 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-strings.pdb $index_str"]
800 if ![string match "" $exec_output] {
804 set exp [file_contents "$srcdir/$subdir/pdb-strings.d"]
805 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
807 if ![string match $exp $got] {
808 fail "Strings table was not as expected"
810 pass "Strings table was as expected"
814 proc extract_c13_info { pdb mod_info } {
817 binary scan [string range $mod_info 34 35] s module_sym_stream
818 binary scan [string range $mod_info 36 39] i sym_byte_size
819 binary scan [string range $mod_info 40 43] i c11_byte_size
820 binary scan [string range $mod_info 44 47] i c13_byte_size
822 set index_str [format "%04x" $module_sym_stream]
824 set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"]
826 if ![string match "" $exec_output] {
830 set fi [open tmpdir/$index_str]
831 fconfigure $fi -translation binary
833 seek $fi [expr $sym_byte_size + $c11_byte_size]
835 set data [read $fi $c13_byte_size]
850 if ![ld_assemble $as $srcdir/$subdir/pdb3a.s tmpdir/pdb3a.o] {
851 unsupported "Build pdb3a.o"
855 if ![ld_assemble $as $srcdir/$subdir/pdb3b.s tmpdir/pdb3b.o] {
856 unsupported "Build pdb3b.o"
860 if ![ld_link $ld "tmpdir/pdb3.exe" "--pdb=tmpdir/pdb3.pdb --gc-sections -e main tmpdir/pdb3a.o tmpdir/pdb3b.o"] {
861 unsupported "Create PE image with PDB file"
865 # read relevant bits from DBI stream
867 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb3.pdb 0003"]
869 if ![string match "" $exec_output] {
870 fail "Could not extract DBI stream"
873 pass "Extracted DBI stream"
876 set fi [open tmpdir/0003]
877 fconfigure $fi -translation binary
881 # read substream sizes
883 set data [read $fi 4]
884 binary scan $data i mod_info_size
886 set data [read $fi 4]
887 binary scan $data i section_contribution_size
889 set data [read $fi 4]
890 binary scan $data i section_map_size
892 set data [read $fi 4]
893 binary scan $data i source_info_size
897 set mod_info [read $fi $mod_info_size]
899 seek $fi [expr $section_contribution_size + $section_map_size] current
901 set source_info [read $fi $source_info_size]
905 # check source info substream
907 set fi [open tmpdir/pdb3-source-info w]
908 fconfigure $fi -translation binary
909 puts -nonewline $fi $source_info
912 set exp [file_contents "$srcdir/$subdir/pdb3-source-info.d"]
913 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-source-info"]
915 if [string match $exp $got] {
916 pass "Correct source info substream"
918 fail "Incorrect source info substream"
921 # check C13 info in first module
923 set c13_info [extract_c13_info "tmpdir/pdb3.pdb" [string range $mod_info 0 63]]
925 set fi [open tmpdir/pdb3-c13-info1 w]
926 fconfigure $fi -translation binary
927 puts -nonewline $fi $c13_info
930 set exp [file_contents "$srcdir/$subdir/pdb3-c13-info1.d"]
931 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-c13-info1"]
933 if [string match $exp $got] {
934 pass "Correct C13 info for first module"
936 fail "Incorrect C13 info for first module"
939 # check C13 info in second module
941 set fn1_end [string first \000 $mod_info 64]
942 set fn2_end [string first \000 $mod_info [expr $fn1_end + 1]]
944 set off [expr $fn2_end + 1]
946 if { [expr $off % 4] != 0 } {
947 set off [expr $off + 4 - ($off % 4)]
950 set c13_info [extract_c13_info "tmpdir/pdb3.pdb" [string range $mod_info $off [expr $off + 63]]]
952 set fi [open tmpdir/pdb3-c13-info2 w]
953 fconfigure $fi -translation binary
954 puts -nonewline $fi $c13_info
957 set exp [file_contents "$srcdir/$subdir/pdb3-c13-info2.d"]
958 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-c13-info2"]
960 if [string match $exp $got] {
961 pass "Correct C13 info for second module"
963 fail "Incorrect C13 info for second module"
975 if ![ld_assemble $as $srcdir/$subdir/pdb-types1a.s tmpdir/pdb-types1a.o] {
976 unsupported "Build pdb-types1a.o"
980 if ![ld_assemble $as $srcdir/$subdir/pdb-types1b.s tmpdir/pdb-types1b.o] {
981 unsupported "Build pdb-types1b.o"
985 if ![ld_link $ld "tmpdir/pdb-types1.exe" "--pdb=tmpdir/pdb-types1.pdb tmpdir/pdb-types1a.o tmpdir/pdb-types1b.o"] {
986 unsupported "Create PE image with PDB file"
990 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types1.pdb 0002"]
992 if ![string match "" $exec_output] {
993 fail "Could not extract TPI stream"
996 pass "Extracted TPI stream"
999 # check values in TPI header, and save anything interesting
1001 set fi [open tmpdir/0002]
1002 fconfigure $fi -translation binary
1006 set data [read $fi 4]
1007 binary scan $data i first_type
1009 if { $first_type != 0x1000 } {
1010 fail "Incorrect first type value in TPI stream."
1012 pass "Correct first type value in TPI stream."
1015 set data [read $fi 4]
1016 binary scan $data i end_type
1018 # end_type is one greater than the last type in the stream
1019 if { $end_type != 0x1030 } {
1020 fail "Incorrect end type value in TPI stream."
1022 pass "Correct end type value in TPI stream."
1025 set data [read $fi 4]
1026 binary scan $data i type_list_size
1028 set data [read $fi 2]
1029 binary scan $data s hash_stream_index
1033 set data [read $fi 4]
1034 binary scan $data i hash_size
1036 if { $hash_size != 4 } {
1037 fail "Incorrect hash size in TPI stream."
1039 pass "Correct hash size in TPI stream."
1042 set data [read $fi 4]
1043 binary scan $data i num_buckets
1045 if { $num_buckets != 0x3ffff } {
1046 fail "Incorrect number of buckets in TPI stream."
1048 pass "Correct number of buckets in TPI stream."
1051 set data [read $fi 4]
1052 binary scan $data i hash_list_offset
1054 set data [read $fi 4]
1055 binary scan $data i hash_list_size
1057 set data [read $fi 4]
1058 binary scan $data i skip_list_offset
1060 set data [read $fi 4]
1061 binary scan $data i skip_list_size
1065 set type_list [read $fi $type_list_size]
1069 set fi [open tmpdir/pdb-types1-typelist w]
1070 fconfigure $fi -translation binary
1071 puts -nonewline $fi $type_list
1076 set exp [file_contents "$srcdir/$subdir/pdb-types1-typelist.d"]
1077 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types1-typelist"]
1078 if ![string match $exp $got] {
1079 fail "Incorrect type list in TPI stream."
1081 pass "Correct type list in TPI stream."
1084 # extract hash list and skip list
1086 set index_str [format "%04x" $hash_stream_index]
1088 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types1.pdb $index_str"]
1090 if ![string match "" $exec_output] {
1091 fail "Could not extract TPI hash stream."
1093 pass "Extracted TPI hash stream."
1096 set fi [open tmpdir/$index_str]
1097 fconfigure $fi -translation binary
1099 seek $fi $hash_list_offset
1100 set hash_list [read $fi $hash_list_size]
1102 seek $fi $skip_list_offset
1103 set skip_list [read $fi $skip_list_size]
1109 set fi [open tmpdir/pdb-types1-hashlist w]
1110 fconfigure $fi -translation binary
1111 puts -nonewline $fi $hash_list
1114 set exp [file_contents "$srcdir/$subdir/pdb-types1-hashlist.d"]
1115 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types1-hashlist"]
1116 if ![string match $exp $got] {
1117 fail "Incorrect hash list in TPI stream."
1119 pass "Correct hash list in TPI stream."
1124 set fi [open tmpdir/pdb-types1-skiplist w]
1125 fconfigure $fi -translation binary
1126 puts -nonewline $fi $skip_list
1129 set exp [file_contents "$srcdir/$subdir/pdb-types1-skiplist.d"]
1130 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types1-skiplist"]
1131 if ![string match $exp $got] {
1132 fail "Incorrect skip list in TPI stream."
1134 pass "Correct skip list in TPI stream."
1146 if ![ld_assemble $as $srcdir/$subdir/pdb-types2a.s tmpdir/pdb-types2a.o] {
1147 unsupported "Build pdb-types2a.o"
1151 if ![ld_assemble $as $srcdir/$subdir/pdb-types2b.s tmpdir/pdb-types2b.o] {
1152 unsupported "Build pdb-types2b.o"
1156 if ![ld_link $ld "tmpdir/pdb-types2.exe" "--pdb=tmpdir/pdb-types2.pdb tmpdir/pdb-types2a.o tmpdir/pdb-types2b.o"] {
1157 unsupported "Create PE image with PDB file"
1161 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb 0004"]
1163 if ![string match "" $exec_output] {
1164 fail "Could not extract IPI stream"
1167 pass "Extracted IPI stream"
1170 # check values in IPI header, and save anything interesting
1172 set fi [open tmpdir/0004]
1173 fconfigure $fi -translation binary
1177 set data [read $fi 4]
1178 binary scan $data i first_type
1180 if { $first_type != 0x1000 } {
1181 fail "Incorrect first type value in IPI stream."
1183 pass "Correct first type value in IPI stream."
1186 set data [read $fi 4]
1187 binary scan $data i end_type
1189 # end_type is one greater than the last type in the stream
1190 if { $end_type != 0x100f } {
1191 fail "Incorrect end type value in IPI stream."
1193 pass "Correct end type value in IPI stream."
1196 set data [read $fi 4]
1197 binary scan $data i type_list_size
1199 set data [read $fi 2]
1200 binary scan $data s hash_stream_index
1204 set data [read $fi 4]
1205 binary scan $data i hash_size
1207 if { $hash_size != 4 } {
1208 fail "Incorrect hash size in IPI stream."
1210 pass "Correct hash size in IPI stream."
1213 set data [read $fi 4]
1214 binary scan $data i num_buckets
1216 if { $num_buckets != 0x3ffff } {
1217 fail "Incorrect number of buckets in IPI stream."
1219 pass "Correct number of buckets in IPI stream."
1222 set data [read $fi 4]
1223 binary scan $data i hash_list_offset
1225 set data [read $fi 4]
1226 binary scan $data i hash_list_size
1228 set data [read $fi 4]
1229 binary scan $data i skip_list_offset
1231 set data [read $fi 4]
1232 binary scan $data i skip_list_size
1236 set type_list [read $fi $type_list_size]
1240 set fi [open tmpdir/pdb-types2-typelist w]
1241 fconfigure $fi -translation binary
1242 puts -nonewline $fi $type_list
1247 set exp [file_contents "$srcdir/$subdir/pdb-types2-typelist.d"]
1248 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-typelist"]
1249 if ![string match $exp $got] {
1250 fail "Incorrect type list in IPI stream."
1252 pass "Correct type list in IPI stream."
1255 # extract hash list and skip list
1257 set index_str [format "%04x" $hash_stream_index]
1259 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb $index_str"]
1261 if ![string match "" $exec_output] {
1262 fail "Could not extract IPI hash stream."
1264 pass "Extracted IPI hash stream."
1267 set fi [open tmpdir/$index_str]
1268 fconfigure $fi -translation binary
1270 seek $fi $hash_list_offset
1271 set hash_list [read $fi $hash_list_size]
1273 seek $fi $skip_list_offset
1274 set skip_list [read $fi $skip_list_size]
1280 set fi [open tmpdir/pdb-types2-hashlist w]
1281 fconfigure $fi -translation binary
1282 puts -nonewline $fi $hash_list
1285 set exp [file_contents "$srcdir/$subdir/pdb-types2-hashlist.d"]
1286 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-hashlist"]
1287 if ![string match $exp $got] {
1288 fail "Incorrect hash list in IPI stream."
1290 pass "Correct hash list in IPI stream."
1295 set fi [open tmpdir/pdb-types2-skiplist w]
1296 fconfigure $fi -translation binary
1297 puts -nonewline $fi $skip_list
1300 set exp [file_contents "$srcdir/$subdir/pdb-types2-skiplist.d"]
1301 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-skiplist"]
1302 if ![string match $exp $got] {
1303 fail "Incorrect skip list in IPI stream."
1305 pass "Correct skip list in IPI stream."
1317 if ![ld_assemble $as $srcdir/$subdir/pdb-types3a.s tmpdir/pdb-types3a.o] {
1318 unsupported "Build pdb-types3a.o"
1322 if ![ld_assemble $as $srcdir/$subdir/pdb-types3b.s tmpdir/pdb-types3b.o] {
1323 unsupported "Build pdb-types3b.o"
1327 if ![ld_link $ld "tmpdir/pdb-types3.exe" "--pdb=tmpdir/pdb-types3.pdb tmpdir/pdb-types3a.o tmpdir/pdb-types3b.o"] {
1328 unsupported "Create PE image with PDB file"
1332 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types3.pdb 0004"]
1334 if ![string match "" $exec_output] {
1335 fail "Could not extract IPI stream"
1338 pass "Extracted IPI stream"
1341 set fi [open tmpdir/0004]
1342 fconfigure $fi -translation binary
1346 set data [read $fi 4]
1347 binary scan $data i type_list_size
1349 set data [read $fi 2]
1350 binary scan $data s hash_stream_index
1354 set data [read $fi 4]
1355 binary scan $data i hash_list_offset
1357 set data [read $fi 4]
1358 binary scan $data i hash_list_size
1360 set data [read $fi 4]
1361 binary scan $data i skip_list_offset
1363 set data [read $fi 4]
1364 binary scan $data i skip_list_size
1368 set type_list [read $fi $type_list_size]
1372 set fi [open tmpdir/pdb-types3-typelist w]
1373 fconfigure $fi -translation binary
1374 puts -nonewline $fi $type_list
1379 set exp [file_contents "$srcdir/$subdir/pdb-types3-typelist.d"]
1380 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types3-typelist"]
1381 if ![string match $exp $got] {
1382 fail "Incorrect type list in IPI stream."
1384 pass "Correct type list in IPI stream."
1387 # extract hash list and skip list
1389 set index_str [format "%04x" $hash_stream_index]
1391 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types3.pdb $index_str"]
1393 if ![string match "" $exec_output] {
1394 fail "Could not extract IPI hash stream."
1396 pass "Extracted IPI hash stream."
1399 set fi [open tmpdir/$index_str]
1400 fconfigure $fi -translation binary
1402 seek $fi $hash_list_offset
1403 set hash_list [read $fi $hash_list_size]
1405 seek $fi $skip_list_offset
1406 set skip_list [read $fi $skip_list_size]
1412 set fi [open tmpdir/pdb-types3-hashlist w]
1413 fconfigure $fi -translation binary
1414 puts -nonewline $fi $hash_list
1417 set exp [file_contents "$srcdir/$subdir/pdb-types3-hashlist.d"]
1418 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types3-hashlist"]
1419 if ![string match $exp $got] {
1420 fail "Incorrect hash list in IPI stream."
1422 pass "Correct hash list in IPI stream."
1427 set fi [open tmpdir/pdb-types3-skiplist w]
1428 fconfigure $fi -translation binary
1429 puts -nonewline $fi $skip_list
1432 set exp [file_contents "$srcdir/$subdir/pdb-types3-skiplist.d"]
1433 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types3-skiplist"]
1434 if ![string match $exp $got] {
1435 fail "Incorrect skip list in IPI stream."
1437 pass "Correct skip list in IPI stream."
1449 if ![ld_assemble $as $srcdir/$subdir/pdb-syms1a.s tmpdir/pdb-syms1a.o] {
1450 unsupported "Build pdb-syms1a.o"
1454 if ![ld_assemble $as $srcdir/$subdir/pdb-syms1b.s tmpdir/pdb-syms1b.o] {
1455 unsupported "Build pdb-syms1b.o"
1459 if ![ld_link $ld "tmpdir/pdb-syms1.exe" "--pdb=tmpdir/pdb-syms1.pdb tmpdir/pdb-syms1a.o tmpdir/pdb-syms1b.o"] {
1460 unsupported "Create PE image with PDB file"
1464 # get index of globals stream and records stream
1466 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb 0003"]
1468 if ![string match "" $exec_output] {
1469 fail "Could not extract DBI stream"
1472 pass "Extracted DBI stream"
1475 set fi [open tmpdir/0003]
1476 fconfigure $fi -translation binary
1479 set data [read $fi 2]
1480 binary scan $data s globals_index
1483 set data [read $fi 2]
1484 binary scan $data s records_index
1487 set data [read $fi 4]
1488 binary scan $data i mod_info_size
1491 set mod_info [read $fi $mod_info_size]
1495 # get index of first and second module streams
1497 binary scan [string range $mod_info 34 35] s mod1_index
1501 set obj1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
1502 incr off [expr [string length $obj1] + 1]
1504 set ar1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
1505 incr off [expr [string length $ar1] + 1]
1507 if { [expr $off % 4] != 0 } {
1508 set off [expr $off + 4 - ($off % 4)]
1513 binary scan [string range $mod_info $off [expr $off + 1]] s mod2_index
1515 # check globals stream
1517 set index_str [format "%04x" $globals_index]
1519 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"]
1521 if ![string match "" $exec_output] {
1522 fail "Could not extract globals stream"
1525 pass "Extracted globals stream"
1528 set exp [file_contents "$srcdir/$subdir/pdb-syms1-globals.d"]
1529 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
1531 if [string match $exp $got] {
1532 pass "Correct globals stream"
1534 fail "Incorrect globals stream"
1537 # check records stream
1539 set index_str [format "%04x" $records_index]
1541 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"]
1543 if ![string match "" $exec_output] {
1544 fail "Could not extract records stream"
1547 pass "Extracted records stream"
1550 set exp [file_contents "$srcdir/$subdir/pdb-syms1-records.d"]
1551 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
1553 if [string match $exp $got] {
1554 pass "Correct records stream"
1556 fail "Incorrect records stream"
1559 # check symbols in first module
1561 set index_str [format "%04x" $mod1_index]
1563 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"]
1565 if ![string match "" $exec_output] {
1566 fail "Could not extract first module's symbols"
1569 pass "Extracted first module's symbols"
1572 set exp [file_contents "$srcdir/$subdir/pdb-syms1-symbols1.d"]
1573 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
1575 if [string match $exp $got] {
1576 pass "Correct symbols in first module's stream"
1578 fail "Incorrect symbols in first module's stream"
1581 # check symbols in second module
1583 set index_str [format "%04x" $mod2_index]
1585 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"]
1587 if ![string match "" $exec_output] {
1588 fail "Could not extract second module's symbols"
1591 pass "Extracted second module's symbols"
1594 set exp [file_contents "$srcdir/$subdir/pdb-syms1-symbols2.d"]
1595 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
1597 if [string match $exp $got] {
1598 pass "Correct symbols in second module's stream"
1600 fail "Incorrect symbols in second module's stream"
1612 if ![ld_assemble $as $srcdir/$subdir/pdb-syms2.s tmpdir/pdb-syms2.o] {
1613 unsupported "Build pdb-syms2.o"
1617 if ![ld_link $ld "tmpdir/pdb-syms2.exe" "--pdb=tmpdir/pdb-syms2.pdb tmpdir/pdb-syms2.o"] {
1618 unsupported "Create PE image with PDB file"
1622 # get index of module stream
1624 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb 0003"]
1626 if ![string match "" $exec_output] {
1627 fail "Could not extract DBI stream"
1630 pass "Extracted DBI stream"
1633 set fi [open tmpdir/0003]
1634 fconfigure $fi -translation binary
1637 set data [read $fi 4]
1638 binary scan $data i mod_info_size
1641 set mod_info [read $fi $mod_info_size]
1645 binary scan [string range $mod_info 34 35] s module_index
1647 # check module records
1649 set index_str [format "%04x" $module_index]
1651 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb $index_str"]
1653 if ![string match "" $exec_output] {
1654 fail "Could not extract module symbols"
1657 pass "Extracted module symbols"
1660 set exp [file_contents "$srcdir/$subdir/pdb-syms2-symbols1.d"]
1661 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
1663 if [string match $exp $got] {
1664 pass "Correct symbols in module stream"
1666 fail "Incorrect symbols in module stream"
1669 # check linker symbols
1673 set obj1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
1674 incr off [expr [string length $obj1] + 1]
1676 set ar1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]]
1677 incr off [expr [string length $ar1] + 1]
1679 if { [expr $off % 4] != 0 } {
1680 set off [expr $off + 4 - ($off % 4)]
1685 binary scan [string range $mod_info $off [expr $off + 1]] s linker_syms_index
1687 set index_str [format "%04x" $linker_syms_index]
1689 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb $index_str"]
1691 if ![string match "" $exec_output] {
1692 fail "Could not extract linker symbols"
1695 pass "Extracted linker symbols"
1698 set syms [file_contents "tmpdir/$index_str"]
1703 binary scan [string range $syms $off [expr $off + 1]] s sym_len
1704 binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type
1706 if { $sym_type != 0x1101 } {
1707 fail "First linker symbol was not S_OBJNAME"
1709 pass "First linker symbol was S_OBJNAME"
1711 set linker_fn [string range $syms [expr $off + 8] [expr [string first \000 $syms [expr $off + 8]] - 1]]
1713 if ![string equal $linker_fn "* Linker *"] {
1714 fail "Incorrect linker object name"
1716 pass "Correct linker object name"
1720 incr off [expr $sym_len + 2]
1724 binary scan [string range $syms $off [expr $off + 1]] s sym_len
1725 binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type
1727 if { $sym_type != 0x113c } {
1728 fail "Second linker symbol was not S_COMPILE3"
1730 pass "Second linker symbol was S_COMPILE3"
1733 incr off [expr $sym_len + 2]
1737 binary scan [string range $syms $off [expr $off + 1]] s sym_len
1738 binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type
1740 if { $sym_type != 0x113d } {
1741 fail "Third linker symbol was not S_ENVBLOCK"
1743 pass "Third linker symbol was S_ENVBLOCK"
1755 if ![ld_assemble $as $srcdir/$subdir/pdb-inlineelines1a.s tmpdir/pdb-inlineelines1a.o] {
1756 unsupported "Build pdb-inlineelines1a.o"
1760 if ![ld_assemble $as $srcdir/$subdir/pdb-inlineelines1b.s tmpdir/pdb-inlineelines1b.o] {
1761 unsupported "Build pdb-inlineelines1a.o"
1765 if ![ld_link $ld "tmpdir/pdb-inlineelines1.exe" "--pdb=tmpdir/pdb-inlineelines1.pdb tmpdir/pdb-inlineelines1a.o tmpdir/pdb-inlineelines1b.o"] {
1766 unsupported "Create PE image with PDB file"
1770 # read relevant bits from DBI stream
1772 set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-inlineelines1.pdb 0003"]
1774 if ![string match "" $exec_output] {
1775 fail "Could not extract DBI stream"
1778 pass "Extracted DBI stream"
1781 set fi [open tmpdir/0003]
1782 fconfigure $fi -translation binary
1786 # read substream sizes
1788 set data [read $fi 4]
1789 binary scan $data i mod_info_size
1793 set mod_info [read $fi $mod_info_size]
1797 # check C13 info in second module
1799 # We're interested here that the inlinee function IDs get rewritten:
1800 # 1003 -> 1002, 1004 -> 1003. The numbers are lower because linking splits
1801 # the types into two separate streams, numbered individually.
1803 # This is what cvdump.exe -inll pdb-inlineelines1.pdb should look like:
1807 # InlineeId FileId StaringLine
1811 # For some reason it numbers file IDs in bytes for object files but as an
1812 # index for PDBs, but they're stored on disk the same way.
1814 set fn1_end [string first \000 $mod_info 64]
1815 set fn2_end [string first \000 $mod_info [expr $fn1_end + 1]]
1817 set off [expr $fn2_end + 1]
1819 if { [expr $off % 4] != 0 } {
1820 set off [expr $off + 4 - ($off % 4)]
1823 set c13_info [extract_c13_info "tmpdir/pdb-inlineelines1.pdb" [string range $mod_info $off [expr $off + 63]]]
1825 set fi [open tmpdir/pdb-inlineelines1-c13-info2 w]
1826 fconfigure $fi -translation binary
1827 puts -nonewline $fi $c13_info
1830 set exp [file_contents "$srcdir/$subdir/pdb-inlineelines1-c13-info2.d"]
1831 set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-inlineelines1-c13-info2"]
1833 if [string match $exp $got] {
1834 pass "Correct C13 info for second module"
1836 fail "Incorrect C13 info for second module"