ld: Write types into IPI stream of PDB
This commit is contained in:
parent
d5b4c0ddb9
commit
fca9096a94
204
ld/pdb.c
204
ld/pdb.c
@ -1124,13 +1124,16 @@ is_name_anonymous (char *name, size_t len)
|
||||
already seen add it to types (for TPI types) or ids (for IPI types). */
|
||||
static bool
|
||||
handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
|
||||
uint32_t num_types, struct types *types)
|
||||
uint32_t num_types, struct types *types,
|
||||
struct types *ids)
|
||||
{
|
||||
uint16_t size, type;
|
||||
void **slot;
|
||||
hashval_t hash;
|
||||
bool other_hash = false;
|
||||
uint32_t cv_hash;
|
||||
struct types *t;
|
||||
bool ipi = false;
|
||||
|
||||
size = bfd_getl16 (data) + sizeof (uint16_t);
|
||||
type = bfd_getl16 (data + sizeof (uint16_t));
|
||||
@ -1911,6 +1914,168 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
|
||||
/* Does not reference any types, nothing to be done. */
|
||||
break;
|
||||
|
||||
case LF_STRING_ID:
|
||||
{
|
||||
struct lf_string_id *str = (struct lf_string_id *) data;
|
||||
size_t string_len;
|
||||
|
||||
if (size < offsetof (struct lf_string_id, string))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_STRING_ID\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!remap_type (&str->substring, map, type_num, num_types))
|
||||
return false;
|
||||
|
||||
string_len = strnlen (str->string,
|
||||
size - offsetof (struct lf_string_id, string));
|
||||
|
||||
if (string_len == size - offsetof (struct lf_string_id, string))
|
||||
{
|
||||
einfo (_("%P: warning: string for LF_STRING_ID has no"
|
||||
" terminating zero\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
ipi = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LF_SUBSTR_LIST:
|
||||
{
|
||||
uint32_t num_entries;
|
||||
struct lf_arglist *ssl = (struct lf_arglist *) data;
|
||||
|
||||
if (size < offsetof (struct lf_arglist, args))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_SUBSTR_LIST\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
num_entries = bfd_getl32 (&ssl->num_entries);
|
||||
|
||||
if (size < offsetof (struct lf_arglist, args)
|
||||
+ (num_entries * sizeof (uint32_t)))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_SUBSTR_LIST\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_entries; i++)
|
||||
{
|
||||
if (!remap_type (&ssl->args[i], map, type_num, num_types))
|
||||
return false;
|
||||
}
|
||||
|
||||
ipi = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LF_BUILDINFO:
|
||||
{
|
||||
uint16_t num_entries;
|
||||
struct lf_build_info *bi = (struct lf_build_info *) data;
|
||||
|
||||
if (size < offsetof (struct lf_build_info, strings))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_BUILDINFO\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
num_entries = bfd_getl16 (&bi->count);
|
||||
|
||||
if (size < offsetof (struct lf_build_info, strings)
|
||||
+ (num_entries * sizeof (uint32_t)))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_BUILDINFO\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_entries; i++)
|
||||
{
|
||||
if (!remap_type (&bi->strings[i], map, type_num, num_types))
|
||||
return false;
|
||||
}
|
||||
|
||||
ipi = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LF_FUNC_ID:
|
||||
{
|
||||
struct lf_func_id *func = (struct lf_func_id *) data;
|
||||
size_t name_len;
|
||||
|
||||
if (size < offsetof (struct lf_func_id, name))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_FUNC_ID\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!remap_type (&func->parent_scope, map, type_num, num_types))
|
||||
return false;
|
||||
|
||||
if (!remap_type (&func->function_type, map, type_num, num_types))
|
||||
return false;
|
||||
|
||||
name_len = strnlen (func->name,
|
||||
size - offsetof (struct lf_func_id, name));
|
||||
|
||||
if (name_len == size - offsetof (struct lf_func_id, name))
|
||||
{
|
||||
einfo (_("%P: warning: string for LF_FUNC_ID has no"
|
||||
" terminating zero\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
ipi = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LF_MFUNC_ID:
|
||||
{
|
||||
struct lf_mfunc_id *mfunc = (struct lf_mfunc_id *) data;
|
||||
size_t name_len;
|
||||
|
||||
if (size < offsetof (struct lf_mfunc_id, name))
|
||||
{
|
||||
einfo (_("%P: warning: truncated CodeView type record"
|
||||
" LF_MFUNC_ID\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!remap_type (&mfunc->parent_type, map, type_num, num_types))
|
||||
return false;
|
||||
|
||||
if (!remap_type (&mfunc->function_type, map, type_num, num_types))
|
||||
return false;
|
||||
|
||||
name_len = strnlen (mfunc->name,
|
||||
size - offsetof (struct lf_mfunc_id, name));
|
||||
|
||||
if (name_len == size - offsetof (struct lf_mfunc_id, name))
|
||||
{
|
||||
einfo (_("%P: warning: string for LF_MFUNC_ID has no"
|
||||
" terminating zero\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
ipi = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
einfo (_("%P: warning: unrecognized CodeView type %v\n"), type);
|
||||
return false;
|
||||
@ -1918,7 +2083,9 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
|
||||
|
||||
hash = iterative_hash (data, size, 0);
|
||||
|
||||
slot = htab_find_slot_with_hash (types->hashmap, data, hash, INSERT);
|
||||
t = ipi ? ids : types;
|
||||
|
||||
slot = htab_find_slot_with_hash (t->hashmap, data, hash, INSERT);
|
||||
if (!slot)
|
||||
return false;
|
||||
|
||||
@ -1931,7 +2098,7 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
|
||||
e = (struct type_entry *) *slot;
|
||||
|
||||
e->next = NULL;
|
||||
e->index = types->num_types;
|
||||
e->index = t->num_types;
|
||||
|
||||
if (other_hash)
|
||||
e->cv_hash = cv_hash;
|
||||
@ -1940,16 +2107,16 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
|
||||
|
||||
memcpy (e->data, data, size);
|
||||
|
||||
if (types->last)
|
||||
types->last->next = e;
|
||||
if (t->last)
|
||||
t->last->next = e;
|
||||
else
|
||||
types->first = e;
|
||||
t->first = e;
|
||||
|
||||
types->last = e;
|
||||
t->last = e;
|
||||
|
||||
map[type_num] = e;
|
||||
|
||||
types->num_types++;
|
||||
t->num_types++;
|
||||
}
|
||||
else /* duplicate */
|
||||
{
|
||||
@ -1962,7 +2129,8 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
|
||||
/* Parse the .debug$T section of a module, and pass any type definitions
|
||||
found to handle_type. */
|
||||
static bool
|
||||
handle_debugt_section (asection *s, bfd *mod, struct types *types)
|
||||
handle_debugt_section (asection *s, bfd *mod, struct types *types,
|
||||
struct types *ids)
|
||||
{
|
||||
bfd_byte *data = NULL;
|
||||
size_t off;
|
||||
@ -2019,7 +2187,7 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types)
|
||||
|
||||
size = bfd_getl16 (data + off);
|
||||
|
||||
if (!handle_type (data + off, map, type_num, num_types, types))
|
||||
if (!handle_type (data + off, map, type_num, num_types, types, ids))
|
||||
{
|
||||
free (data);
|
||||
free (map);
|
||||
@ -2044,7 +2212,8 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
|
||||
struct string_table *strings,
|
||||
uint32_t *c13_info_size,
|
||||
struct mod_source_files *mod_source,
|
||||
bfd *abfd, struct types *types)
|
||||
bfd *abfd, struct types *types,
|
||||
struct types *ids)
|
||||
{
|
||||
uint8_t int_buf[sizeof (uint32_t)];
|
||||
uint8_t *c13_info = NULL;
|
||||
@ -2068,7 +2237,7 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
|
||||
}
|
||||
else if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t))
|
||||
{
|
||||
if (!handle_debugt_section (s, mod, types))
|
||||
if (!handle_debugt_section (s, mod, types, ids))
|
||||
{
|
||||
free (c13_info);
|
||||
free (mod_source->files);
|
||||
@ -2113,7 +2282,7 @@ static bool
|
||||
create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
|
||||
uint32_t *size, struct string_table *strings,
|
||||
struct source_files_info *source,
|
||||
struct types *types)
|
||||
struct types *types, struct types *ids)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
unsigned int mod_num;
|
||||
@ -2202,7 +2371,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
|
||||
if (!populate_module_stream (stream, in, &sym_byte_size,
|
||||
strings, &c13_info_size,
|
||||
&source->mods[mod_num], abfd,
|
||||
types))
|
||||
types, ids))
|
||||
{
|
||||
for (unsigned int i = 0; i < source->mod_count; i++)
|
||||
{
|
||||
@ -2525,7 +2694,8 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
|
||||
uint16_t sym_rec_stream_num,
|
||||
uint16_t publics_stream_num,
|
||||
struct string_table *strings,
|
||||
struct types *types)
|
||||
struct types *types,
|
||||
struct types *ids)
|
||||
{
|
||||
struct pdb_dbi_stream_header h;
|
||||
struct optional_dbg_header opt;
|
||||
@ -2537,7 +2707,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
|
||||
source.mods = NULL;
|
||||
|
||||
if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size,
|
||||
strings, &source, types))
|
||||
strings, &source, types, ids))
|
||||
return false;
|
||||
|
||||
if (!create_section_contrib_substream (abfd, &sc, &sc_size))
|
||||
@ -3210,7 +3380,7 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid)
|
||||
|
||||
if (!populate_dbi_stream (dbi_stream, abfd, pdb, section_header_stream_num,
|
||||
sym_rec_stream_num, publics_stream_num,
|
||||
&strings, &types))
|
||||
&strings, &types, &ids))
|
||||
{
|
||||
einfo (_("%P: warning: cannot populate DBI stream "
|
||||
"in PDB file: %E\n"));
|
||||
|
45
ld/pdb.h
45
ld/pdb.h
@ -54,6 +54,11 @@
|
||||
#define LF_METHOD 0x150f
|
||||
#define LF_NESTTYPE 0x1510
|
||||
#define LF_ONEMETHOD 0x1511
|
||||
#define LF_FUNC_ID 0x1601
|
||||
#define LF_MFUNC_ID 0x1602
|
||||
#define LF_BUILDINFO 0x1603
|
||||
#define LF_SUBSTR_LIST 0x1604
|
||||
#define LF_STRING_ID 0x1605
|
||||
|
||||
#define LF_CHAR 0x8000
|
||||
#define LF_SHORT 0x8001
|
||||
@ -265,7 +270,7 @@ struct lf_pointer
|
||||
uint32_t attributes;
|
||||
} ATTRIBUTE_PACKED;
|
||||
|
||||
/* lfArgList in cvinfo.h */
|
||||
/* lfArgList in cvinfo.h (used for both LF_ARGLIST and LF_SUBSTR_LIST) */
|
||||
struct lf_arglist
|
||||
{
|
||||
uint16_t size;
|
||||
@ -474,6 +479,44 @@ struct lf_nest_type
|
||||
char name[];
|
||||
} ATTRIBUTE_PACKED;
|
||||
|
||||
/* lfStringId in cvinfo.h */
|
||||
struct lf_string_id
|
||||
{
|
||||
uint16_t size;
|
||||
uint16_t kind;
|
||||
uint32_t substring;
|
||||
char string[];
|
||||
} ATTRIBUTE_PACKED;
|
||||
|
||||
/* lfBuildInfo in cvinfo.h */
|
||||
struct lf_build_info
|
||||
{
|
||||
uint16_t size;
|
||||
uint16_t kind;
|
||||
uint16_t count;
|
||||
uint32_t strings[];
|
||||
} ATTRIBUTE_PACKED;
|
||||
|
||||
/* lfFuncId in cvinfo.h */
|
||||
struct lf_func_id
|
||||
{
|
||||
uint16_t size;
|
||||
uint16_t kind;
|
||||
uint32_t parent_scope;
|
||||
uint32_t function_type;
|
||||
char name[];
|
||||
} ATTRIBUTE_PACKED;
|
||||
|
||||
/* lfMFuncId in cvinfo.h */
|
||||
struct lf_mfunc_id
|
||||
{
|
||||
uint16_t size;
|
||||
uint16_t kind;
|
||||
uint32_t parent_type;
|
||||
uint32_t function_type;
|
||||
char name[];
|
||||
} ATTRIBUTE_PACKED;
|
||||
|
||||
extern bool create_pdb_file (bfd *, const char *, const unsigned char *);
|
||||
|
||||
#endif
|
||||
|
8
ld/testsuite/ld-pe/pdb-types2-hashlist.d
Normal file
8
ld/testsuite/ld-pe/pdb-types2-hashlist.d
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
*: file format binary
|
||||
|
||||
Contents of section .data:
|
||||
0000 75cf0100 8d660300 f2a20300 aea00000 *
|
||||
0010 ef990300 223d0000 d6b60000 24070100 *
|
||||
0020 7f220100 f6d10200 16100200 010a0300 *
|
||||
0030 0b4f0300 12690300 a56d0300 *
|
5
ld/testsuite/ld-pe/pdb-types2-skiplist.d
Normal file
5
ld/testsuite/ld-pe/pdb-types2-skiplist.d
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
*: file format binary
|
||||
|
||||
Contents of section .data:
|
||||
0000 00100000 00000000 *
|
20
ld/testsuite/ld-pe/pdb-types2-typelist.d
Normal file
20
ld/testsuite/ld-pe/pdb-types2-typelist.d
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
*: file format binary
|
||||
|
||||
Contents of section .data:
|
||||
0000 0e000516 00000000 74657374 00f3f2f1 ........test....
|
||||
0010 0a000516 00000000 666f6f00 0a000516 ........foo.....
|
||||
0020 00000000 62617200 0e000416 02000000 ....bar.........
|
||||
0030 01100000 02100000 0a000516 03100000 ................
|
||||
0040 62617a00 0e000516 00000000 2f746d70 baz........./tmp
|
||||
0050 00f3f2f1 0a000516 00000000 67636300 ............gcc.
|
||||
0060 0e000516 00000000 746d702e 6300f2f1 ........tmp.c...
|
||||
0070 0e000516 00000000 746d702e 70646200 ........tmp.pdb.
|
||||
0080 12000516 00000000 2d67636f 64657669 ........-gcodevi
|
||||
0090 657700f1 1a000316 05000510 00000610 ew..............
|
||||
00a0 00000710 00000810 00000910 0000f2f1 ................
|
||||
00b0 12000516 00000000 6e616d65 73706163 ........namespac
|
||||
00c0 6500f2f1 12000116 00000000 01100000 e...............
|
||||
00d0 66756e63 3100f2f1 12000116 0b100000 func1...........
|
||||
00e0 01100000 66756e63 3200f2f1 12000216 ....func2.......
|
||||
00f0 02100000 04100000 6d657468 6f6400f1 ........method..
|
42
ld/testsuite/ld-pe/pdb-types2a.s
Normal file
42
ld/testsuite/ld-pe/pdb-types2a.s
Normal file
@ -0,0 +1,42 @@
|
||||
.equ CV_SIGNATURE_C13, 4
|
||||
|
||||
.equ T_VOID, 0x0003
|
||||
.equ T_INT4, 0x0074
|
||||
|
||||
.equ LF_PROCEDURE, 0x1008
|
||||
.equ LF_MFUNCTION, 0x1009
|
||||
.equ LF_POINTER, 0x1002
|
||||
.equ LF_ARGLIST, 0x1201
|
||||
.equ LF_FIELDLIST, 0x1203
|
||||
.equ LF_CLASS, 0x1504
|
||||
.equ LF_ONEMETHOD, 0x1511
|
||||
.equ LF_FUNC_ID, 0x1601
|
||||
.equ LF_MFUNC_ID, 0x1602
|
||||
.equ LF_BUILDINFO, 0x1603
|
||||
.equ LF_SUBSTR_LIST, 0x1604
|
||||
.equ LF_STRING_ID, 0x1605
|
||||
|
||||
.equ CV_PTR_64, 0xc
|
||||
|
||||
.section ".debug$T", "rn"
|
||||
|
||||
.long CV_SIGNATURE_C13
|
||||
|
||||
# Type 1000, string "test"
|
||||
.string1:
|
||||
.short .string2 - .string1 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "test"
|
||||
.byte 0xf3
|
||||
.byte 0xf2
|
||||
.byte 0xf1
|
||||
|
||||
# Type 1001, string "foo"
|
||||
.string2:
|
||||
.short .types_end - .string2 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "foo"
|
||||
|
||||
.types_end:
|
221
ld/testsuite/ld-pe/pdb-types2b.s
Normal file
221
ld/testsuite/ld-pe/pdb-types2b.s
Normal file
@ -0,0 +1,221 @@
|
||||
.equ CV_SIGNATURE_C13, 4
|
||||
|
||||
.equ T_VOID, 0x0003
|
||||
.equ T_INT4, 0x0074
|
||||
|
||||
.equ LF_PROCEDURE, 0x1008
|
||||
.equ LF_MFUNCTION, 0x1009
|
||||
.equ LF_POINTER, 0x1002
|
||||
.equ LF_ARGLIST, 0x1201
|
||||
.equ LF_FIELDLIST, 0x1203
|
||||
.equ LF_CLASS, 0x1504
|
||||
.equ LF_ONEMETHOD, 0x1511
|
||||
.equ LF_FUNC_ID, 0x1601
|
||||
.equ LF_MFUNC_ID, 0x1602
|
||||
.equ LF_BUILDINFO, 0x1603
|
||||
.equ LF_SUBSTR_LIST, 0x1604
|
||||
.equ LF_STRING_ID, 0x1605
|
||||
|
||||
.equ CV_PTR_64, 0xc
|
||||
|
||||
.section ".debug$T", "rn"
|
||||
|
||||
.long CV_SIGNATURE_C13
|
||||
|
||||
# Type 1000, string "foo"
|
||||
.string1:
|
||||
.short .string2 - .string1 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "foo"
|
||||
|
||||
# Type 1001, string "bar"
|
||||
.string2:
|
||||
.short .substrlist1 - .string2 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "bar"
|
||||
|
||||
# Type 1002, substr list of "foo" and "bar"
|
||||
.substrlist1:
|
||||
.short .string3 - .substrlist1 - 2
|
||||
.short LF_SUBSTR_LIST
|
||||
.long 2 # count
|
||||
.long 0x1000
|
||||
.long 0x1001
|
||||
|
||||
# Type 1003, string "baz" referencing substr list 1002
|
||||
.string3:
|
||||
.short .string4 - .string3 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0x1002
|
||||
.asciz "baz"
|
||||
|
||||
# Type 1004, string "/tmp" (build directory)
|
||||
.string4:
|
||||
.short .string5 - .string4 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "/tmp"
|
||||
.byte 0xf3 # padding
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 1005, string "gcc" (compiler)
|
||||
.string5:
|
||||
.short .string6 - .string5 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "gcc"
|
||||
|
||||
# Type 1006, string "tmp.c" (source file)
|
||||
.string6:
|
||||
.short .string7 - .string6 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "tmp.c"
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 1007, string "tmp.pdb" (PDB file)
|
||||
.string7:
|
||||
.short .string8 - .string7 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "tmp.pdb"
|
||||
|
||||
# Type 1008, string "-gcodeview" (command arguments)
|
||||
.string8:
|
||||
.short .buildinfo1 - .string8 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "-gcodeview"
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# The 1009, build info
|
||||
.buildinfo1:
|
||||
.short .string9 - .buildinfo1 - 2
|
||||
.short LF_BUILDINFO
|
||||
.short 5 # count
|
||||
.long 0x1004 # build directory
|
||||
.long 0x1005 # compiler
|
||||
.long 0x1006 # source file
|
||||
.long 0x1007 # PDB file
|
||||
.long 0x1008 # command arguments
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 100a, string "namespace"
|
||||
.string9:
|
||||
.short .arglist1 - .string9 - 2
|
||||
.short LF_STRING_ID
|
||||
.long 0 # sub-string
|
||||
.asciz "namespace"
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 100b, arg list of type T_INT4
|
||||
.arglist1:
|
||||
.short .proc1 - .arglist1 - 2
|
||||
.short LF_ARGLIST
|
||||
.long 1 # no. entries
|
||||
.long T_INT4
|
||||
|
||||
# Type 100c, procedure, return type T_VOID, arg list 100b
|
||||
.proc1:
|
||||
.short .func1 - .proc1 - 2
|
||||
.short LF_PROCEDURE
|
||||
.long T_VOID
|
||||
.byte 0 # calling convention
|
||||
.byte 0 # attributes
|
||||
.short 1 # no. parameters
|
||||
.long 0x100b
|
||||
|
||||
# Type 100d, function "func1"
|
||||
.func1:
|
||||
.short .func2 - .func1 - 2
|
||||
.short LF_FUNC_ID
|
||||
.long 0 # parent scope
|
||||
.long 0x100c # type
|
||||
.asciz "func1"
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 100e, function "func2" within scope "namespace"
|
||||
.func2:
|
||||
.short .class1 - .func2 - 2
|
||||
.short LF_FUNC_ID
|
||||
.long 0x100a # parent scope
|
||||
.long 0x100c # type
|
||||
.asciz "func2"
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 100f, forward declaration of class foo
|
||||
.class1:
|
||||
.short .ptr1 - .class1 - 2
|
||||
.short LF_CLASS
|
||||
.short 0 # no. members
|
||||
.short 0x80 # property (has unique name, forward declaration)
|
||||
.long 0 # field list
|
||||
.long 0 # type derived from
|
||||
.long 0 # type of vshape table
|
||||
.short 0 # size
|
||||
.asciz "foo" # name
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 1010, pointer to 100f
|
||||
.ptr1:
|
||||
.short .mfunction1 - .ptr1 - 2
|
||||
.short LF_POINTER
|
||||
.long 0x100f
|
||||
.long (8 << 13) | CV_PTR_64
|
||||
|
||||
# Type 1011, member function of 100f, return type void, arg list 100b
|
||||
.mfunction1:
|
||||
.short .fieldlist1 - .mfunction1 - 2
|
||||
.short LF_MFUNCTION
|
||||
.long T_VOID
|
||||
.long 0x100f
|
||||
.long 0x1010 # type of "this" pointer
|
||||
.byte 0 # calling convention
|
||||
.byte 0 # attributes
|
||||
.short 1 # no. parameters
|
||||
.long 0x100b # arg list
|
||||
.long 0 # "this" adjustment
|
||||
|
||||
# Type 1012, field list for class foo
|
||||
.fieldlist1:
|
||||
.short .class2 - .fieldlist1 - 2
|
||||
.short LF_FIELDLIST
|
||||
.short LF_ONEMETHOD
|
||||
.short 0 # method attribute
|
||||
.long 0x1010 # method type
|
||||
.asciz "method"
|
||||
.byte 0xf1
|
||||
|
||||
# Type 1013, actual declaration of class foo
|
||||
.class2:
|
||||
.short .mfunc1 - .class2 - 2
|
||||
.short LF_CLASS
|
||||
.short 0 # no. members
|
||||
.short 0 # property
|
||||
.long 0x1012 # field list
|
||||
.long 0 # type derived from
|
||||
.long 0 # type of vshape table
|
||||
.short 0 # size
|
||||
.asciz "foo" # name
|
||||
.byte 0xf2 # padding
|
||||
.byte 0xf1 # padding
|
||||
|
||||
# Type 1014, function "method" within class "foo"
|
||||
.mfunc1:
|
||||
.short .types_end - .mfunc1 - 2
|
||||
.short LF_MFUNC_ID
|
||||
.long 0x100f # parent class
|
||||
.long 0x1011 # function type
|
||||
.asciz "method"
|
||||
.byte 0xf1 # padding
|
||||
|
||||
.types_end:
|
@ -1148,8 +1148,180 @@ proc test5 { } {
|
||||
}
|
||||
}
|
||||
|
||||
proc test6 { } {
|
||||
global as
|
||||
global ar
|
||||
global ld
|
||||
global objdump
|
||||
global srcdir
|
||||
global subdir
|
||||
|
||||
if ![ld_assemble $as $srcdir/$subdir/pdb-types2a.s tmpdir/pdb-types2a.o] {
|
||||
unsupported "Build pdb-types2a.o"
|
||||
return
|
||||
}
|
||||
|
||||
if ![ld_assemble $as $srcdir/$subdir/pdb-types2b.s tmpdir/pdb-types2b.o] {
|
||||
unsupported "Build pdb-types2b.o"
|
||||
return
|
||||
}
|
||||
|
||||
if ![ld_link $ld "tmpdir/pdb-types2.exe" "--pdb=tmpdir/pdb-types2.pdb tmpdir/pdb-types2a.o tmpdir/pdb-types2b.o"] {
|
||||
unsupported "Create PE image with PDB file"
|
||||
return
|
||||
}
|
||||
|
||||
set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb 0004"]
|
||||
|
||||
if ![string match "" $exec_output] {
|
||||
fail "Could not extract IPI stream"
|
||||
return
|
||||
} else {
|
||||
pass "Extracted IPI stream"
|
||||
}
|
||||
|
||||
# check values in IPI header, and save anything interesting
|
||||
|
||||
set fi [open tmpdir/0004]
|
||||
fconfigure $fi -translation binary
|
||||
|
||||
seek $fi 8 current
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i first_type
|
||||
|
||||
if { $first_type != 0x1000 } {
|
||||
fail "Incorrect first type value in IPI stream."
|
||||
} else {
|
||||
pass "Correct first type value in IPI stream."
|
||||
}
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i end_type
|
||||
|
||||
# end_type is one greater than the last type in the stream
|
||||
if { $end_type != 0x100f } {
|
||||
fail "Incorrect end type value in IPI stream."
|
||||
} else {
|
||||
pass "Correct end type value in IPI stream."
|
||||
}
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i type_list_size
|
||||
|
||||
set data [read $fi 2]
|
||||
binary scan $data s hash_stream_index
|
||||
|
||||
seek $fi 2 current
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i hash_size
|
||||
|
||||
if { $hash_size != 4 } {
|
||||
fail "Incorrect hash size in IPI stream."
|
||||
} else {
|
||||
pass "Correct hash size in IPI stream."
|
||||
}
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i num_buckets
|
||||
|
||||
if { $num_buckets != 0x3ffff } {
|
||||
fail "Incorrect number of buckets in IPI stream."
|
||||
} else {
|
||||
pass "Correct number of buckets in IPI stream."
|
||||
}
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i hash_list_offset
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i hash_list_size
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i skip_list_offset
|
||||
|
||||
set data [read $fi 4]
|
||||
binary scan $data i skip_list_size
|
||||
|
||||
seek $fi 8 current
|
||||
|
||||
set type_list [read $fi $type_list_size]
|
||||
|
||||
close $fi
|
||||
|
||||
set fi [open tmpdir/pdb-types2-typelist w]
|
||||
fconfigure $fi -translation binary
|
||||
puts -nonewline $fi $type_list
|
||||
close $fi
|
||||
|
||||
# check type list
|
||||
|
||||
set exp [file_contents "$srcdir/$subdir/pdb-types2-typelist.d"]
|
||||
set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-typelist"]
|
||||
if ![string match $exp $got] {
|
||||
fail "Incorrect type list in IPI stream."
|
||||
} else {
|
||||
pass "Correct type list in IPI stream."
|
||||
}
|
||||
|
||||
# extract hash list and skip list
|
||||
|
||||
set index_str [format "%04x" $hash_stream_index]
|
||||
|
||||
set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb $index_str"]
|
||||
|
||||
if ![string match "" $exec_output] {
|
||||
fail "Could not extract IPI hash stream."
|
||||
} else {
|
||||
pass "Extracted IPI hash stream."
|
||||
}
|
||||
|
||||
set fi [open tmpdir/$index_str]
|
||||
fconfigure $fi -translation binary
|
||||
|
||||
seek $fi $hash_list_offset
|
||||
set hash_list [read $fi $hash_list_size]
|
||||
|
||||
seek $fi $skip_list_offset
|
||||
set skip_list [read $fi $skip_list_size]
|
||||
|
||||
close $fi
|
||||
|
||||
# check hash list
|
||||
|
||||
set fi [open tmpdir/pdb-types2-hashlist w]
|
||||
fconfigure $fi -translation binary
|
||||
puts -nonewline $fi $hash_list
|
||||
close $fi
|
||||
|
||||
set exp [file_contents "$srcdir/$subdir/pdb-types2-hashlist.d"]
|
||||
set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-hashlist"]
|
||||
if ![string match $exp $got] {
|
||||
fail "Incorrect hash list in IPI stream."
|
||||
} else {
|
||||
pass "Correct hash list in IPI stream."
|
||||
}
|
||||
|
||||
# check skip list
|
||||
|
||||
set fi [open tmpdir/pdb-types2-skiplist w]
|
||||
fconfigure $fi -translation binary
|
||||
puts -nonewline $fi $skip_list
|
||||
close $fi
|
||||
|
||||
set exp [file_contents "$srcdir/$subdir/pdb-types2-skiplist.d"]
|
||||
set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-skiplist"]
|
||||
if ![string match $exp $got] {
|
||||
fail "Incorrect skip list in IPI stream."
|
||||
} else {
|
||||
pass "Correct skip list in IPI stream."
|
||||
}
|
||||
}
|
||||
|
||||
test1
|
||||
test2
|
||||
test3
|
||||
test4
|
||||
test5
|
||||
test6
|
||||
|
Loading…
x
Reference in New Issue
Block a user