From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1062) id 268423858D1E; Sat, 31 Dec 2022 08:56:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 268423858D1E Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Alan Modra To: bfd-cvs@sourceware.org Subject: [binutils-gdb] ld: Handle extended-length data structures in PDB types X-Act-Checkin: binutils-gdb X-Git-Author: Mark Harmstone X-Git-Refname: refs/heads/master X-Git-Oldrev: 826eed802778ceb59ad6f645130917d247f1415b X-Git-Newrev: fdf591c4c6d065d29461e7966809e97bcaea7e8b Message-Id: <20221231085653.268423858D1E@sourceware.org> Date: Sat, 31 Dec 2022 08:56:53 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 31 Dec 2022 08:56:53 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dfdf591c4c6d0= 65d29461e7966809e97bcaea7e8b commit fdf591c4c6d065d29461e7966809e97bcaea7e8b Author: Mark Harmstone Date: Mon Dec 26 20:47:49 2022 +0000 ld: Handle extended-length data structures in PDB types =20 A few fixes to minor issues I've discovered in my PDB patches. =20 * If sizes or offsets are greater than 0x8000, they get encoded as extended values in the same way as for enum values - e.g. a LF_ULONG .short followed by a .long. =20 * I've managed to coax MSVC to produce another type, LF_VFTABLE, which is seen when dealing with COM. I don't think LLVM emits this. Note that we can't just implement everything in Microsoft's header files, as most of it is obsolete. =20 * Fixes a stupid bug in the test program, where I was adding an index to a size. The index was hard-coded to 0, so this didn't cause any actual issues. Diff: --- ld/pdb.c | 228 +++++++++++++++++++++++++++= ---- ld/pdb.h | 1 - ld/testsuite/ld-pe/pdb-types1-hashlist.d | 4 +- ld/testsuite/ld-pe/pdb-types1-typelist.d | 16 ++- ld/testsuite/ld-pe/pdb-types1b.s | 121 +++++++++++++++- ld/testsuite/ld-pe/pdb.exp | 2 +- 6 files changed, 344 insertions(+), 28 deletions(-) diff --git a/ld/pdb.c b/ld/pdb.c index 6a5f737dcd4..60e9980407c 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -2476,6 +2476,7 @@ handle_type (uint8_t *data, struct type_entry **map, = uint32_t type_num, case LF_MEMBER: { struct lf_member *mem =3D (struct lf_member *) ptr; + uint16_t offset; size_t name_len, subtype_len; =20 if (left < offsetof (struct lf_member, name)) @@ -2488,9 +2489,34 @@ handle_type (uint8_t *data, struct type_entry **map,= uint32_t type_num, if (!remap_type (&mem->type, map, type_num, num_types)) return false; =20 + subtype_len =3D offsetof (struct lf_member, name); + + offset =3D bfd_getl16 (&mem->offset); + + /* If offset >=3D 0x8000, actual value follows. */ + if (offset >=3D 0x8000) + { + unsigned int param_len =3D extended_value_len (offset); + + if (param_len =3D=3D 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_MEMBER\n"), offset); + return false; + } + + subtype_len +=3D param_len; + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_MEMBER\n")); + return false; + } + } + name_len =3D - strnlen (mem->name, - left - offsetof (struct lf_member, name)); + strnlen ((char *) mem + subtype_len, left - subtype_len); =20 if (name_len =3D=3D left - offsetof (struct lf_member, name)) { @@ -2501,7 +2527,7 @@ handle_type (uint8_t *data, struct type_entry **map, = uint32_t type_num, =20 name_len++; =20 - subtype_len =3D offsetof (struct lf_member, name) + name_len; + subtype_len +=3D name_len; =20 if (subtype_len % 4 !=3D 0) subtype_len +=3D 4 - (subtype_len % 4); @@ -2706,6 +2732,8 @@ handle_type (uint8_t *data, struct type_entry **map, = uint32_t type_num, case LF_BCLASS: { struct lf_bclass *bc =3D (struct lf_bclass *) ptr; + size_t subtype_len; + uint16_t offset; =20 if (left < sizeof (struct lf_bclass)) { @@ -2718,8 +2746,44 @@ handle_type (uint8_t *data, struct type_entry **map,= uint32_t type_num, num_types)) return false; =20 - ptr +=3D sizeof (struct lf_bclass); - left -=3D sizeof (struct lf_bclass); + subtype_len =3D sizeof (struct lf_bclass); + + offset =3D bfd_getl16 (&bc->offset); + + /* If offset >=3D 0x8000, actual value follows. */ + if (offset >=3D 0x8000) + { + unsigned int param_len =3D extended_value_len (offset); + + if (param_len =3D=3D 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_BCLASS\n"), offset); + return false; + } + + subtype_len +=3D param_len; + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_BCLASS\n")); + return false; + } + } + + if (subtype_len % 4 !=3D 0) + subtype_len +=3D 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_BCLASS\n")); + return false; + } + + ptr +=3D subtype_len; + left -=3D subtype_len; =20 break; } @@ -2748,6 +2812,8 @@ handle_type (uint8_t *data, struct type_entry **map, = uint32_t type_num, case LF_IVBCLASS: { struct lf_vbclass *vbc =3D (struct lf_vbclass *) ptr; + size_t subtype_len; + uint16_t offset; =20 if (left < sizeof (struct lf_vbclass)) { @@ -2764,8 +2830,70 @@ handle_type (uint8_t *data, struct type_entry **map,= uint32_t type_num, type_num, num_types)) return false; =20 - ptr +=3D sizeof (struct lf_vbclass); - left -=3D sizeof (struct lf_vbclass); + subtype_len =3D offsetof (struct lf_vbclass, + virtual_base_vbtable_offset); + + offset =3D bfd_getl16 (&vbc->virtual_base_pointer_offset); + + /* If offset >=3D 0x8000, actual value follows. */ + if (offset >=3D 0x8000) + { + unsigned int param_len =3D extended_value_len (offset); + + if (param_len =3D=3D 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_VBCLASS/LF_IVBCLASS\n"), offset); + return false; + } + + subtype_len +=3D param_len; + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_VBCLASS/LF_IVBCLASS\n")); + return false; + } + } + + offset =3D bfd_getl16 ((char *)vbc + subtype_len); + subtype_len +=3D sizeof (uint16_t); + + /* If offset >=3D 0x8000, actual value follows. */ + if (offset >=3D 0x8000) + { + unsigned int param_len =3D extended_value_len (offset); + + if (param_len =3D=3D 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_VBCLASS/LF_IVBCLASS\n"), offset); + return false; + } + + subtype_len +=3D param_len; + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_VBCLASS/LF_IVBCLASS\n")); + return false; + } + } + + if (subtype_len % 4 !=3D 0) + subtype_len +=3D 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_VBCLASS/LF_IVBCLASS\n")); + return false; + } + + ptr +=3D subtype_len; + left -=3D subtype_len; =20 break; } @@ -2950,8 +3078,8 @@ handle_type (uint8_t *data, struct type_entry **map, = uint32_t type_num, case LF_STRUCTURE: { struct lf_class *cl =3D (struct lf_class *) data; - uint16_t prop; - size_t name_len; + uint16_t prop, num_bytes; + size_t name_len, name_off; =20 if (size < offsetof (struct lf_class, name)) { @@ -2969,9 +3097,35 @@ handle_type (uint8_t *data, struct type_entry **map,= uint32_t type_num, if (!remap_type (&cl->vshape, map, type_num, num_types)) return false; =20 - name_len =3D strnlen (cl->name, size - offsetof (struct lf_class, name)); + name_off =3D offsetof (struct lf_class, name); + + num_bytes =3D bfd_getl16 (&cl->length); =20 - if (name_len =3D=3D size - offsetof (struct lf_class, name)) + /* If num_bytes >=3D 0x8000, actual value follows. */ + if (num_bytes >=3D 0x8000) + { + unsigned int param_len =3D extended_value_len (num_bytes); + + if (param_len =3D=3D 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_CLASS/LF_STRUCTURE\n"), num_bytes); + return false; + } + + name_off +=3D param_len; + + if (size < name_off) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_CLASS/LF_STRUCTURE\n")); + return false; + } + } + + name_len =3D strnlen ((char *) cl + name_off, size - name_off); + + if (name_len =3D=3D size - name_off) { einfo (_("%P: warning: name for LF_CLASS/LF_STRUCTURE has no" " terminating zero\n")); @@ -2984,10 +3138,11 @@ handle_type (uint8_t *data, struct type_entry **map= , uint32_t type_num, { /* Structure has another name following first one. */ =20 - size_t len =3D offsetof (struct lf_class, name) + name_len + 1; + size_t len =3D name_off + name_len + 1; size_t unique_name_len; =20 - unique_name_len =3D strnlen (cl->name + name_len + 1, size - len); + unique_name_len =3D strnlen ((char *) cl + name_off + name_len + 1, + size - len); =20 if (unique_name_len =3D=3D size - len) { @@ -2998,10 +3153,10 @@ handle_type (uint8_t *data, struct type_entry **map= , uint32_t type_num, } =20 if (!(prop & (CV_PROP_FORWARD_REF | CV_PROP_SCOPED)) - && !is_name_anonymous (cl->name, name_len)) + && !is_name_anonymous ((char *) cl + name_off, name_len)) { other_hash =3D true; - cv_hash =3D crc32 ((uint8_t *) cl->name, name_len); + cv_hash =3D crc32 ((uint8_t *) cl + name_off, name_len); } =20 break; @@ -3010,8 +3165,8 @@ handle_type (uint8_t *data, struct type_entry **map, = uint32_t type_num, case LF_UNION: { struct lf_union *un =3D (struct lf_union *) data; - uint16_t prop; - size_t name_len; + uint16_t prop, num_bytes; + size_t name_len, name_off; =20 if (size < offsetof (struct lf_union, name)) { @@ -3023,9 +3178,35 @@ handle_type (uint8_t *data, struct type_entry **map,= uint32_t type_num, if (!remap_type (&un->field_list, map, type_num, num_types)) return false; =20 - name_len =3D strnlen (un->name, size - offsetof (struct lf_union, name)); + name_off =3D offsetof (struct lf_union, name); + + num_bytes =3D bfd_getl16 (&un->length); + + /* If num_bytes >=3D 0x8000, actual value follows. */ + if (num_bytes >=3D 0x8000) + { + unsigned int param_len =3D extended_value_len (num_bytes); + + if (param_len =3D=3D 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_UNION\n"), num_bytes); + return false; + } + + name_off +=3D param_len; + + if (size < name_off) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_UNION\n")); + return false; + } + } + + name_len =3D strnlen ((char *) un + name_off, size - name_off); =20 - if (name_len =3D=3D size - offsetof (struct lf_union, name)) + if (name_len =3D=3D size - name_off) { einfo (_("%P: warning: name for LF_UNION has no" " terminating zero\n")); @@ -3038,10 +3219,11 @@ handle_type (uint8_t *data, struct type_entry **map= , uint32_t type_num, { /* Structure has another name following first one. */ =20 - size_t len =3D offsetof (struct lf_union, name) + name_len + 1; + size_t len =3D name_off + name_len + 1; size_t unique_name_len; =20 - unique_name_len =3D strnlen (un->name + name_len + 1, size - len); + unique_name_len =3D strnlen ((char *) un + name_off + name_len + 1, + size - len); =20 if (unique_name_len =3D=3D size - len) { @@ -3052,10 +3234,10 @@ handle_type (uint8_t *data, struct type_entry **map= , uint32_t type_num, } =20 if (!(prop & (CV_PROP_FORWARD_REF | CV_PROP_SCOPED)) - && !is_name_anonymous (un->name, name_len)) + && !is_name_anonymous ((char *) un + name_off, name_len)) { other_hash =3D true; - cv_hash =3D crc32 ((uint8_t *) un->name, name_len); + cv_hash =3D crc32 ((uint8_t *) un + name_off, name_len); } =20 break; diff --git a/ld/pdb.h b/ld/pdb.h index 749a60249df..ddf731b99c9 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -480,7 +480,6 @@ struct lf_bclass uint16_t attributes; uint32_t base_class_type; uint16_t offset; - uint16_t padding; } ATTRIBUTE_PACKED; =20 /* lfVFuncTab in cvinfo.h */ diff --git a/ld/testsuite/ld-pe/pdb-types1-hashlist.d b/ld/testsuite/ld-pe/= pdb-types1-hashlist.d index b75f08c1de7..aa00aaf7593 100644 --- a/ld/testsuite/ld-pe/pdb-types1-hashlist.d +++ b/ld/testsuite/ld-pe/pdb-types1-hashlist.d @@ -10,4 +10,6 @@ Contents of section .data: 0050 ffd80200 b0260100 7c060200 e3240200 * 0060 63ff0100 fb6b0300 0ad90100 523c0200 * 0070 4d5e0200 8a940200 4b710300 6aa90300 * - 0080 0a2c0300 67e10300 4a3d0300 * \ No newline at end of file + 0080 0a2c0300 67e10300 4a3d0300 fa460300 * + 0090 db020200 ec4e0100 131e0300 fb120300 * + 00a0 aece0200 1db70100 * \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types1-typelist.d b/ld/testsuite/ld-pe/= pdb-types1-typelist.d index ff2d91c311e..df862c3f837 100644 --- a/ld/testsuite/ld-pe/pdb-types1-typelist.d +++ b/ld/testsuite/ld-pe/pdb-types1-typelist.d @@ -57,4 +57,18 @@ Contents of section .data: 0340 7200f2f1 10150000 20100000 6e657374 r....... ...nest 0350 65645f65 6e756d00 1a000515 01000000 ed_enum......... 0360 21100000 00000000 00000000 04007175 !.............qu - 0370 757800f1 ux.. =20 \ No newline at end of file + 0370 757800f1 12000315 10000000 74000000 ux..........t... + 0380 028060ea 00f3f2f1 2e000312 0d150300 ..`............. + 0390 23100000 00006100 0d150300 23100000 #.....a.....#... + 03a0 028060ea 6200f2f1 0d150300 23100000 ..`.b.......#... + 03b0 0480c0d4 01006300 26000515 03000000 ......c.&....... + 03c0 24100000 00000000 00000000 048020bf $............. . + 03d0 02006c6f 6e677374 72756374 00f3f2f1 ..longstruct.... + 03e0 1a000312 0d150300 23100000 00006100 ........#.....a. + 03f0 0d150300 23100000 00006200 1a000615 ....#.....b..... + 0400 02000000 26100000 028060ea 6c6f6e67 ....&.....`.long + 0410 756e696f 6e00f2f1 1e000312 00140000 union........... + 0420 25100000 0480c0d4 0100f2f1 0d150300 %............... + 0430 23100000 00006400 26000312 01140000 #.....d.&....... + 0440 25100000 00000000 028060ea 0480c0d4 %.........`..... + 0450 0100f2f1 0d150300 23100000 00006400 ........#.....d. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types1b.s b/ld/testsuite/ld-pe/pdb-type= s1b.s index 89ee6e3840f..544b338c251 100644 --- a/ld/testsuite/ld-pe/pdb-types1b.s +++ b/ld/testsuite/ld-pe/pdb-types1b.s @@ -33,6 +33,7 @@ =20 .equ LF_USHORT, 0x8002 .equ LF_LONG, 0x8003 +.equ LF_ULONG, 0x8004 .equ LF_UQUADWORD, 0x800a =20 .equ CV_PTR_NEAR32, 0xa @@ -447,7 +448,7 @@ =20 # Type 1021, struct quux, field list 1020 .struct4: -.short .types_end - .struct4 - 2 +.short .arr2 - .struct4 - 2 .short LF_STRUCTURE .short 1 # no. members .short 0 # property @@ -458,4 +459,122 @@ .asciz "quux" # name .byte 0xf1 # padding =20 +# Type 1022, array[60000] of char +.arr2: +.short .fieldlist8 - .arr2 - 2 +.short LF_ARRAY +.long T_CHAR # element type +.long T_INT4 # index type +.short LF_USHORT +.short 60000 # size in bytes +.byte 0 # name +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1023, field list for struct longstruct +.fieldlist8: +.short .struct5 - .fieldlist8 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short 0 # offset +.asciz "a" +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short LF_USHORT +.short 60000 # offset +.asciz "b" +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short LF_ULONG +.long 120000 # offset +.asciz "c" + +# Type 1024, struct longstruct +.struct5: +.short .fieldlist9 - .struct5 - 2 +.short LF_STRUCTURE +.short 3 # no. members +.short 0 # property +.long 0x1023 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short LF_ULONG +.long 180000 # size +.asciz "longstruct" # name +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1025, field list for union longunion +.fieldlist9: +.short .union4 - .fieldlist9 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short 0 # offset +.asciz "a" +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short 0 # offset +.asciz "b" + +# Type 1026, union longunion (field list 1025) +.union4: +.short .fieldlist10 - .union4 - 2 +.short LF_UNION +.short 2 # no. members +.short 0 # property +.long 0x1025 # field list +.short LF_USHORT +.short 60000 # size +.asciz "longunion" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1027, field list with base class longstruct +.fieldlist10: +.short .fieldlist11 - .fieldlist10 - 2 +.short LF_FIELDLIST +.short LF_BCLASS +.short 0 # attributes +.long 0x1024 # base class +.short LF_ULONG +.long 120000 # offset within class +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short 0 # offset +.asciz "d" + +# Type 1028, field list with virtual base class longstruct +.fieldlist11: +.short .types_end - .fieldlist11 - 2 +.short LF_FIELDLIST +.short LF_VBCLASS +.short 0 # attributes +.long 0x1024 # type index of direct virtual base class +.long 0 # type index of virtual base pointer +.short LF_USHORT +.short 60000 # virtual base pointer offset +.short LF_ULONG +.long 120000 # virtual base offset from vbtable +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_MEMBER +.short 3 # public +.long 0x1022 +.short 0 # offset +.asciz "d" + .types_end: diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index bd50b2fb076..fbc0cf949f1 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1029,7 +1029,7 @@ proc test5 { } { binary scan $data i end_type =20 # end_type is one greater than the last type in the stream - if { $end_type !=3D 0x1023 } { + if { $end_type !=3D 0x102a } { fail "Incorrect end type value in TPI stream." } else { pass "Correct end type value in TPI stream."