From: Mark Harmstone Date: Mon, 26 Aug 2024 12:58:56 +0000 (+0100) Subject: ld/PDB: handle pointers to members X-Git-Tag: gdb-16-branchpoint~1075 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=91555eddd48726592478fc3fbe4a4dbce31384bf;p=thirdparty%2Fbinutils-gdb.git ld/PDB: handle pointers to members If the CV_PTR_MODE_PMEM or CV_PTR_MODE_PMFUNC flags were set in an LF_POINTER entry's attributes, there's a few extra bytes on the end that we weren't accounting for. Change handle_type so that we remap the containing_class field if it's present, and add a test for this. --- diff --git a/ld/pdb.c b/ld/pdb.c index fcbe325603c..a15da9db73d 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -2375,6 +2375,7 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, case LF_POINTER: { struct lf_pointer *ptr = (struct lf_pointer *) data; + uint32_t attributes; if (size < offsetof (struct lf_pointer, attributes)) { @@ -2386,6 +2387,22 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, if (!remap_type (&ptr->base_type, map, type_num, num_types)) return false; + attributes = bfd_getl32 (&ptr->attributes); + + if ((attributes & CV_PTR_MODE_MASK) == CV_PTR_MODE_PMEM + || (attributes & CV_PTR_MODE_MASK) == CV_PTR_MODE_PMFUNC) + { + if (size < offsetof (struct lf_pointer, ptr_to_mem_type)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_POINTER\n")); + return false; + } + + if (!remap_type (&ptr->containing_class, map, type_num, num_types)) + return false; + } + break; } diff --git a/ld/pdb.h b/ld/pdb.h index b98d3868354..a9b518a9f99 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -303,6 +303,11 @@ struct lf_modifier uint16_t padding; } ATTRIBUTE_PACKED; +/* enum CV_ptrmode_e in cvinfo.h, shifted by 5 for the lfPointerAttr bitfield */ +#define CV_PTR_MODE_MASK 0xe0 +#define CV_PTR_MODE_PMEM 0x40 +#define CV_PTR_MODE_PMFUNC 0x60 + /* lfPointer in cvinfo.h */ struct lf_pointer { @@ -310,6 +315,10 @@ struct lf_pointer uint16_t kind; uint32_t base_type; uint32_t attributes; + /* following only if CV_PTR_MODE_PMEM or CV_PTR_MODE_PMFUNC in attributes */ + uint32_t containing_class; + uint16_t ptr_to_mem_type; + uint16_t padding; } ATTRIBUTE_PACKED; /* lfArgList in cvinfo.h (used for both LF_ARGLIST and LF_SUBSTR_LIST) */ diff --git a/ld/testsuite/ld-pe/pdb-types1-typelist.d b/ld/testsuite/ld-pe/pdb-types1-typelist.d index 1caa074ac56..e97c4f7aa58 100644 --- a/ld/testsuite/ld-pe/pdb-types1-typelist.d +++ b/ld/testsuite/ld-pe/pdb-types1-typelist.d @@ -80,4 +80,6 @@ Contents of section .data: 04b0 65660052 656c6561 736500f1 02000312 ef.Release...... 04c0 22000515 00000000 2c100000 00000000 ".......,....... 04d0 00000000 0100656d 7074795f 73747275 ......empty_stru - 04e0 637400f1 ct.. + 04e0 637400f1 12000210 11100000 6c000100 ct..........l... + 04f0 0d100000 0500f2f1 12000210 75000000 ............u... + 0500 4c000100 0d100000 0100f2f1 L........... diff --git a/ld/testsuite/ld-pe/pdb-types1b.s b/ld/testsuite/ld-pe/pdb-types1b.s index 8bfc973c1c8..0cb301ce60b 100644 --- a/ld/testsuite/ld-pe/pdb-types1b.s +++ b/ld/testsuite/ld-pe/pdb-types1b.s @@ -40,6 +40,12 @@ .equ CV_PTR_NEAR32, 0xa .equ CV_PTR_64, 0xc +.equ CV_PTR_MODE_PMEM, 0x40 +.equ CV_PTR_MODE_PMFUNC, 0x60 + +.equ CV_PMTYPE_D_Single, 0x01 +.equ CV_PMTYPE_F_Single, 0x05 + .section ".debug$T", "rn" .long CV_SIGNATURE_C13 @@ -614,7 +620,7 @@ /* Type 102c, empty struct */ .struct7: -.short .types_end - .struct7 - 2 +.short .ptr5 - .struct7 - 2 .short LF_STRUCTURE .short 0 /* no. members */ .short 0 /* property */ @@ -625,4 +631,26 @@ .asciz "empty_struct" /* name */ .byte 0xf1 /* padding */ +/* Type 102d, pointer to member function method2 in struct foo */ +.ptr5: +.short .ptr6 - .ptr5 - 2 +.short LF_POINTER +.long 0x1010 /* base type */ +.long (8 << 13) | CV_PTR_MODE_PMFUNC | CV_PTR_64 /* attributes */ +.long 0x100c /* containing class */ +.short CV_PMTYPE_F_Single /* member function, single inheritance */ +.byte 0xf2 /* padding */ +.byte 0xf1 /* padding */ + +/* Type 102e, pointer to member num in struct foo */ +.ptr6: +.short .types_end - .ptr6 - 2 +.short LF_POINTER +.long T_UINT4 /* base type */ +.long (8 << 13) | CV_PTR_MODE_PMEM | CV_PTR_64 /* attributes */ +.long 0x100c /* containing class */ +.short CV_PMTYPE_D_Single /* member data, single inheritance */ +.byte 0xf2 /* padding */ +.byte 0xf1 /* padding */ + .types_end: diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index b583e877f01..7ca0fb66246 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1036,7 +1036,7 @@ proc test5 { } { binary scan $data i end_type # end_type is one greater than the last type in the stream - if { $end_type != 0x102e } { + if { $end_type != 0x1030 } { fail "Incorrect end type value in TPI stream." } else { pass "Correct end type value in TPI stream."