mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 01:53:38 +08:00
ld/pdb: Handle DEBUG_S_INLINEELINES data
The DEBUG_S_INLINEELINES block in the .debug$S section records the line numbers in a source file covered by inlined functions. It's similar to the DEBUG_S_LINES block, but as it references LF_FUNC_ID types we also need to parse it to remap the type numbers.
This commit is contained in:
parent
05ff7a4dfe
commit
909fcd9bc8
84
ld/pdb.c
84
ld/pdb.c
@ -161,6 +161,9 @@ static const uint32_t crc_table[] =
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
static bool remap_type (void *data, struct type_entry **map,
|
||||
uint32_t type_num, uint32_t num_types);
|
||||
|
||||
/* Add a new stream to the PDB archive, and return its BFD. */
|
||||
static bfd *
|
||||
add_stream (bfd *pdb, const char *name, uint16_t *stream_num)
|
||||
@ -1836,6 +1839,76 @@ calculate_symbols_size (uint8_t *data, uint32_t size, uint32_t *sym_size)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Parse the DEBUG_S_INLINEELINES data, which records the line numbers that
|
||||
correspond to inlined functions. This is similar to DEBUG_S_LINES (see
|
||||
handle_debugs_section), but rather than just copying we also need to remap
|
||||
the numbers of the referenced LF_FUNC_ID types. */
|
||||
|
||||
static bool
|
||||
parse_inlinee_lines (uint8_t *data, uint32_t size, uint8_t **bufptr,
|
||||
struct type_entry **map, uint32_t num_types)
|
||||
{
|
||||
uint32_t version;
|
||||
uint8_t *ptr;
|
||||
unsigned int num_entries;
|
||||
|
||||
bfd_putl32 (DEBUG_S_INLINEELINES, *bufptr);
|
||||
*bufptr += sizeof (uint32_t);
|
||||
|
||||
bfd_putl32 (size, *bufptr);
|
||||
*bufptr += sizeof (uint32_t);
|
||||
|
||||
/* The inlinee lines data consists of a version uint32_t (0), followed by an
|
||||
array of struct inlinee_source_line:
|
||||
|
||||
struct inlinee_source_line
|
||||
{
|
||||
uint32_t function_id;
|
||||
uint32_t file_id;
|
||||
uint32_t line_no;
|
||||
};
|
||||
|
||||
(see InlineeSourceLine in cvinfo.h)
|
||||
|
||||
We're only interested here in the function_id, as we need to remap its
|
||||
type number.
|
||||
*/
|
||||
|
||||
if (size < sizeof (uint32_t))
|
||||
{
|
||||
einfo (_("%P: warning: truncated DEBUG_S_INLINEELINES data\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
version = bfd_getl32 (data + sizeof (uint32_t) + sizeof (uint32_t));
|
||||
if (version != CV_INLINEE_SOURCE_LINE_SIGNATURE)
|
||||
{
|
||||
einfo (_("%P: warning: unexpected DEBUG_S_INLINEELINES version %u\n"),
|
||||
version);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy (*bufptr, data, size);
|
||||
ptr = *bufptr + sizeof (uint32_t);
|
||||
*bufptr += size;
|
||||
|
||||
num_entries = (size - sizeof (uint32_t)) / (3 * sizeof (uint32_t));
|
||||
|
||||
for (unsigned int i = 0; i < num_entries; i++)
|
||||
{
|
||||
uint32_t func_id;
|
||||
|
||||
func_id = bfd_getl32 (ptr);
|
||||
|
||||
if (!remap_type (ptr, map, func_id, num_types))
|
||||
return false;
|
||||
|
||||
ptr += 3 * sizeof (uint32_t);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Parse the .debug$S section within an object file. */
|
||||
static bool
|
||||
handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
|
||||
@ -1951,6 +2024,7 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
|
||||
switch (type)
|
||||
{
|
||||
case DEBUG_S_FILECHKSMS:
|
||||
case DEBUG_S_INLINEELINES:
|
||||
c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size;
|
||||
|
||||
if (c13_size % sizeof (uint32_t))
|
||||
@ -2088,6 +2162,16 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DEBUG_S_INLINEELINES:
|
||||
if (!parse_inlinee_lines (data + off, size, &bufptr, map, num_types))
|
||||
{
|
||||
free (data);
|
||||
free (symbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
off += size;
|
||||
|
3
ld/pdb.h
3
ld/pdb.h
@ -241,10 +241,13 @@ struct optional_dbg_header
|
||||
#define DEBUG_S_LINES 0xf2
|
||||
#define DEBUG_S_STRINGTABLE 0xf3
|
||||
#define DEBUG_S_FILECHKSMS 0xf4
|
||||
#define DEBUG_S_INLINEELINES 0xf6
|
||||
|
||||
#define STRING_TABLE_SIGNATURE 0xeffeeffe
|
||||
#define STRING_TABLE_VERSION 1
|
||||
|
||||
#define CV_INLINEE_SOURCE_LINE_SIGNATURE 0
|
||||
|
||||
/* VHdr in nmt.h */
|
||||
struct string_table_header
|
||||
{
|
||||
|
10
ld/testsuite/ld-pe/pdb-inlineelines1-c13-info2.d
Normal file
10
ld/testsuite/ld-pe/pdb-inlineelines1-c13-info2.d
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
tmpdir/pdb-inlineelines1-c13-info2: file format binary
|
||||
|
||||
Contents of section .data:
|
||||
0000 f4000000 30000000 02000000 10016745 ....0.........gE
|
||||
0010 2301efcd ab8998ba dcfe1023 45670000 #..........#Eg..
|
||||
0020 08000000 100198ba dcfe1023 45676745 ...........#EggE
|
||||
0030 2301efcd ab890000 f6000000 1c000000 #...............
|
||||
0040 00000000 02100000 00000000 2a000000 ............*...
|
||||
0050 03100000 18000000 1c000000 ............
|
20
ld/testsuite/ld-pe/pdb-inlineelines1a.s
Normal file
20
ld/testsuite/ld-pe/pdb-inlineelines1a.s
Normal file
@ -0,0 +1,20 @@
|
||||
.equ CV_SIGNATURE_C13, 4
|
||||
|
||||
.equ LF_STRING_ID, 0x1605
|
||||
|
||||
.equ CV_INLINEE_SOURCE_LINE_SIGNATURE, 0
|
||||
|
||||
.section ".debug$T", "rn"
|
||||
|
||||
.long CV_SIGNATURE_C13
|
||||
|
||||
/* Type 1000, string "hello" */
|
||||
.string1:
|
||||
.short .types_end - .string1 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 /* sub-string */
|
||||
.asciz "hello"
|
||||
.byte 0xf2 /* padding */
|
||||
.byte 0xf1 /* padding */
|
||||
|
||||
.types_end:
|
160
ld/testsuite/ld-pe/pdb-inlineelines1b.s
Normal file
160
ld/testsuite/ld-pe/pdb-inlineelines1b.s
Normal file
@ -0,0 +1,160 @@
|
||||
.equ CV_SIGNATURE_C13, 4
|
||||
|
||||
.equ DEBUG_S_STRINGTABLE, 0xf3
|
||||
.equ DEBUG_S_FILECHKSMS, 0xf4
|
||||
.equ DEBUG_S_INLINEELINES, 0xf6
|
||||
.equ CHKSUM_TYPE_MD5, 1
|
||||
|
||||
.equ NUM_MD5_BYTES, 16
|
||||
|
||||
.equ T_VOID, 0x0003
|
||||
.equ T_UINT4, 0x0075
|
||||
|
||||
.equ LF_ARGLIST, 0x1201
|
||||
.equ LF_PROCEDURE, 0x1008
|
||||
.equ LF_FUNC_ID, 0x1601
|
||||
.equ LF_STRING_ID, 0x1605
|
||||
|
||||
.equ CV_INLINEE_SOURCE_LINE_SIGNATURE, 0
|
||||
|
||||
.section ".debug$T", "rn"
|
||||
|
||||
.long CV_SIGNATURE_C13
|
||||
|
||||
/* Type 1000, string "world" */
|
||||
.string1:
|
||||
.short .arglist1 - .string1 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 /* sub-string */
|
||||
.asciz "world"
|
||||
.byte 0xf2 /* padding */
|
||||
.byte 0xf1 /* padding */
|
||||
|
||||
/* Type 1001, arglist (uint32_t) */
|
||||
.arglist1:
|
||||
.short .proctype1 - .arglist1 - 2
|
||||
.short LF_ARGLIST
|
||||
.long 1 /* no. entries */
|
||||
.long T_UINT4
|
||||
|
||||
/* Type 1002, procedure (return type T_VOID, arglist 1001) */
|
||||
.proctype1:
|
||||
.short .funcid1 - .proctype1 - 2
|
||||
.short LF_PROCEDURE
|
||||
.long T_VOID
|
||||
.byte 0 /* calling convention */
|
||||
.byte 0 /* attributes */
|
||||
.short 1 /* no. parameters */
|
||||
.long 0x1001
|
||||
|
||||
/* Type 1003, func ID for proc1 */
|
||||
.funcid1:
|
||||
.short .funcid2 - .funcid1 - 2
|
||||
.short LF_FUNC_ID
|
||||
.long 0 /* parent scope */
|
||||
.long 0x1002 /* type */
|
||||
.asciz "proc1"
|
||||
.byte 0xf2 /* padding */
|
||||
.byte 0xf1 /* padding */
|
||||
|
||||
/* Type 1004, func ID for proc2 */
|
||||
.funcid2:
|
||||
.short .types_end - .funcid2 - 2
|
||||
.short LF_FUNC_ID
|
||||
.long 0 /* parent scope */
|
||||
.long 0x1002 /* type */
|
||||
.asciz "proc2"
|
||||
.byte 0xf2 /* padding */
|
||||
.byte 0xf1 /* padding */
|
||||
|
||||
.types_end:
|
||||
|
||||
.section ".debug$S", "rn"
|
||||
.long CV_SIGNATURE_C13
|
||||
|
||||
/*
|
||||
*** STRINGTABLE
|
||||
|
||||
00000000
|
||||
00000001 foo.c
|
||||
00000007 bar.c
|
||||
*/
|
||||
|
||||
.long DEBUG_S_STRINGTABLE
|
||||
.long .strings_end - .strings_start
|
||||
|
||||
.strings_start:
|
||||
|
||||
.asciz ""
|
||||
|
||||
.src1:
|
||||
.asciz "foo.c"
|
||||
|
||||
.src2:
|
||||
.asciz "bar.c"
|
||||
|
||||
.strings_end:
|
||||
|
||||
.balign 4
|
||||
|
||||
/*
|
||||
*** FILECHKSUMS
|
||||
|
||||
FileId St.Offset Cb Type ChksumBytes
|
||||
0 00000001 10 MD5 67452301EFCDAB8998BADCFE10234567
|
||||
18 00000007 10 MD5 98BADCFE1023456767452301EFCDAB89
|
||||
*/
|
||||
|
||||
.long DEBUG_S_FILECHKSMS
|
||||
.long .chksms_end - .chksms_start
|
||||
|
||||
.chksms_start:
|
||||
|
||||
.file1:
|
||||
.long .src1 - .strings_start
|
||||
.byte NUM_MD5_BYTES
|
||||
.byte CHKSUM_TYPE_MD5
|
||||
.long 0x01234567
|
||||
.long 0x89abcdef
|
||||
.long 0xfedcba98
|
||||
.long 0x67452310
|
||||
.short 0 /* padding */
|
||||
|
||||
.file2:
|
||||
.long .src2 - .strings_start
|
||||
.byte NUM_MD5_BYTES
|
||||
.byte CHKSUM_TYPE_MD5
|
||||
.long 0xfedcba98
|
||||
.long 0x67452310
|
||||
.long 0x01234567
|
||||
.long 0x89abcdef
|
||||
.short 0 /* padding */
|
||||
|
||||
.chksms_end:
|
||||
|
||||
.balign 4
|
||||
|
||||
/*
|
||||
*** INLINEE LINES
|
||||
|
||||
InlineeId FileId StaringLine
|
||||
1003 0 42
|
||||
1004 18 28
|
||||
*/
|
||||
|
||||
.long DEBUG_S_INLINEELINES
|
||||
.long .lines_end - .lines_start
|
||||
|
||||
.lines_start:
|
||||
|
||||
.long CV_INLINEE_SOURCE_LINE_SIGNATURE
|
||||
|
||||
.long 0x1003
|
||||
.long .file1 - .chksms_start
|
||||
.long 42
|
||||
|
||||
.long 0x1004
|
||||
.long .file2 - .chksms_start
|
||||
.long 28
|
||||
|
||||
.lines_end:
|
@ -1744,6 +1744,99 @@ proc test9 { } {
|
||||
}
|
||||
}
|
||||
|
||||
proc test10 { } {
|
||||
global as
|
||||
global ar
|
||||
global ld
|
||||
global objdump
|
||||
global srcdir
|
||||
global subdir
|
||||
|
||||
if ![ld_assemble $as $srcdir/$subdir/pdb-inlineelines1a.s tmpdir/pdb-inlineelines1a.o] {
|
||||
unsupported "Build pdb-inlineelines1a.o"
|
||||
return
|
||||
}
|
||||
|
||||
if ![ld_assemble $as $srcdir/$subdir/pdb-inlineelines1b.s tmpdir/pdb-inlineelines1b.o] {
|
||||
unsupported "Build pdb-inlineelines1a.o"
|
||||
return
|
||||
}
|
||||
|
||||
if ![ld_link $ld "tmpdir/pdb-inlineelines1.exe" "--pdb=tmpdir/pdb-inlineelines1.pdb tmpdir/pdb-inlineelines1a.o tmpdir/pdb-inlineelines1b.o"] {
|
||||
unsupported "Create PE image with PDB file"
|
||||
return
|
||||
}
|
||||
|
||||
# read relevant bits from DBI stream
|
||||
|
||||
set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-inlineelines1.pdb 0003"]
|
||||
|
||||
if ![string match "" $exec_output] {
|
||||
fail "Could not extract DBI stream"
|
||||
return
|
||||
} else {
|
||||
pass "Extracted DBI stream"
|
||||
}
|
||||
|
||||
set fi [open tmpdir/0003]
|
||||
fconfigure $fi -translation binary
|
||||
|
||||
seek $fi 24
|
||||
|
||||
# read substream sizes
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i mod_info_size
|
||||
|
||||
seek $fi 36 current
|
||||
|
||||
set mod_info [read $fi $mod_info_size]
|
||||
|
||||
close $fi
|
||||
|
||||
# check C13 info in second module
|
||||
|
||||
# We're interested here that the inlinee function IDs get rewritten:
|
||||
# 1003 -> 1002, 1004 -> 1003. The numbers are lower because linking splits
|
||||
# the types into two separate streams, numbered individually.
|
||||
|
||||
# This is what cvdump.exe -inll pdb-inlineelines1.pdb should look like:
|
||||
|
||||
# *** INLINEE LINES
|
||||
#
|
||||
# InlineeId FileId StaringLine
|
||||
# 1002 0 42
|
||||
# 1003 1 28
|
||||
|
||||
# For some reason it numbers file IDs in bytes for object files but as an
|
||||
# index for PDBs, but they're stored on disk the same way.
|
||||
|
||||
set fn1_end [string first \000 $mod_info 64]
|
||||
set fn2_end [string first \000 $mod_info [expr $fn1_end + 1]]
|
||||
|
||||
set off [expr $fn2_end + 1]
|
||||
|
||||
if { [expr $off % 4] != 0 } {
|
||||
set off [expr $off + 4 - ($off % 4)]
|
||||
}
|
||||
|
||||
set c13_info [extract_c13_info "tmpdir/pdb-inlineelines1.pdb" [string range $mod_info $off [expr $off + 63]]]
|
||||
|
||||
set fi [open tmpdir/pdb-inlineelines1-c13-info2 w]
|
||||
fconfigure $fi -translation binary
|
||||
puts -nonewline $fi $c13_info
|
||||
close $fi
|
||||
|
||||
set exp [file_contents "$srcdir/$subdir/pdb-inlineelines1-c13-info2.d"]
|
||||
set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-inlineelines1-c13-info2"]
|
||||
|
||||
if [string match $exp $got] {
|
||||
pass "Correct C13 info for second module"
|
||||
} else {
|
||||
fail "Incorrect C13 info for second module"
|
||||
}
|
||||
}
|
||||
|
||||
test1
|
||||
test2
|
||||
test3
|
||||
@ -1753,3 +1846,4 @@ test6
|
||||
test7
|
||||
test8
|
||||
test9
|
||||
test10
|
||||
|
Loading…
Reference in New Issue
Block a user