1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +01:00

[llvm-pdbutil] Add -type-ref-stats to help find unused type info

Summary:
This considers module symbol streams and the global symbol stream to be
roots. Most types that this considers "unreferenced" are referenced by
LF_UDT_MOD_SRC_LINE id records, which VC seems to always include.
Essentially, they are types that the user can only find in the debugger
if they call them by name, they cannot be found by traversing a symbol.

In practice, around 80% of type information in a PDB is referenced by a
symbol. That seems like a reasonable number.

I don't really plan to do anything with this tool. It mostly just exists
for informational purposes, and to confirm that we probably don't need
to implement type reference tracking in LLD. We can continue to merge
all types as we do today without wasting space.

Reviewers: zturner, aganea

Subscribers: mgorny, hiraditya, arphaman, jdoerfert, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59620

llvm-svn: 356692
This commit is contained in:
Reid Kleckner 2019-03-21 18:02:34 +00:00
parent 36f9cb0c86
commit 0e0b4260d3
11 changed files with 898 additions and 21 deletions

View File

@ -363,14 +363,16 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
// values. One idea is to define some structures representing these types
// that would allow the use of offsetof().
switch (Kind) {
case SymbolKind::S_GPROC32:
case SymbolKind::S_LPROC32:
case SymbolKind::S_GPROC32_ID:
case SymbolKind::S_LPROC32_ID:
case SymbolKind::S_LPROC32_DPC:
case SymbolKind::S_LPROC32_DPC_ID:
Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
break;
case SymbolKind::S_GPROC32:
case SymbolKind::S_LPROC32:
Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
break;
case SymbolKind::S_UDT:
Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
break;

View File

@ -0,0 +1,577 @@
RUN: llvm-pdbutil dump -types -type-ref-stats %p/Inputs/every-class.pdb \
RUN: | FileCheck %s
CHECK: Types (TPI Stream)
CHECK: ============================================================
CHECK: Showing 157 records
CHECK: 0x1000 | LF_ARGLIST [size = 16, referenced]
CHECK: 0x0603 (void*): `void*`
CHECK: 0x0023 (unsigned __int64): `unsigned __int64`
CHECK: 0x1001 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 2, param list = 0x1000
CHECK: calling conv = cdecl, options = None
CHECK: 0x1002 | LF_ARGLIST [size = 16, referenced]
CHECK: 0x0603 (void*): `void*`
CHECK: 0x0075 (unsigned): `unsigned`
CHECK: 0x1003 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 2, param list = 0x1002
CHECK: calling conv = cdecl, options = None
CHECK: 0x1004 | LF_POINTER [size = 12, referenced]
CHECK: referent = 0x0670 (char*), mode = pointer, opts = None, kind = ptr64
CHECK: 0x1005 | LF_ARGLIST [size = 16, referenced]
CHECK: 0x0074 (int): `int`
CHECK: 0x1004: `char**`
CHECK: 0x1006 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0074 (int), # args = 2, param list = 0x1005
CHECK: calling conv = cdecl, options = None
CHECK: 0x1007 | LF_FIELDLIST [size = 4, referenced]
CHECK: 0x1008 | LF_STRUCTURE [size = 124, referenced] `main::__l2::<unnamed-type-Anonymous>`
CHECK: unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1007
CHECK: options: has unique name | scoped, sizeof 1
CHECK: 0x1009 | LF_STRUCTURE [size = 88, referenced] `main::__l2::Scoped`
CHECK: unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1007
CHECK: options: has unique name | scoped, sizeof 1
CHECK: 0x100A | LF_FIELDLIST [size = 48, unreferenced]
CHECK: - LF_ENUMERATE [native = 0]
CHECK: - LF_ENUMERATE [com = 1]
CHECK: - LF_ENUMERATE [managed = 2]
CHECK: 0x100B | LF_ENUM [size = 116, unreferenced] `__vc_attributes::event_sourceAttribute::type_e`
CHECK: unique name: `.?AW4type_e@event_sourceAttribute@__vc_attributes@@`
CHECK: field list: 0x100A, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x100C | LF_FIELDLIST [size = 28, unreferenced]
CHECK: - LF_ENUMERATE [speed = 0]
CHECK: - LF_ENUMERATE [size = 1]
CHECK: 0x100D | LF_ENUM [size = 124, unreferenced] `__vc_attributes::event_sourceAttribute::optimize_e`
CHECK: unique name: `.?AW4optimize_e@event_sourceAttribute@__vc_attributes@@`
CHECK: field list: 0x100C, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x100E | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::event_sourceAttribute`
CHECK: unique name: `.?AUevent_sourceAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1016) | has unique name, sizeof 0
CHECK: 0x100F | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x100E, mode = pointer, opts = const, kind = ptr64
CHECK: 0x1010 | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x100B: `__vc_attributes::event_sourceAttribute::type_e`
CHECK: 0x1011 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1010
CHECK: class type = 0x100E, this type = 0x100F, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1012 | LF_ARGLIST [size = 8, referenced]
CHECK: 0x1013 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 0, param list = 0x1012
CHECK: class type = 0x100E, this type = 0x100F, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1014 | LF_METHODLIST [size = 20, unreferenced]
CHECK: - Method [type = 0x1011, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x1013, vftable offset = -1, attrs = public]
CHECK: 0x1015 | LF_FIELDLIST [size = 128, unreferenced]
CHECK: - LF_NESTTYPE [name = `type_e`, parent = 0x100B]
CHECK: - LF_NESTTYPE [name = `optimize_e`, parent = 0x100D]
CHECK: - LF_METHOD [name = `event_sourceAttribute`, # overloads = 2, overload list = 0x1014]
CHECK: - LF_MEMBER [name = `type`, Type = 0x100B, offset = 0, attrs = public]
CHECK: - LF_MEMBER [name = `optimize`, Type = 0x100D, offset = 4, attrs = public]
CHECK: - LF_MEMBER [name = `decorate`, Type = 0x0030 (bool), offset = 8, attrs = public]
CHECK: 0x1016 | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::event_sourceAttribute`
CHECK: unique name: `.?AUevent_sourceAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1015
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 12
CHECK: 0x1017 | LF_FIELDLIST [size = 68, unreferenced]
CHECK: - LF_ENUMERATE [eBoolean = 0]
CHECK: - LF_ENUMERATE [eInteger = 1]
CHECK: - LF_ENUMERATE [eFloat = 2]
CHECK: - LF_ENUMERATE [eDouble = 3]
CHECK: 0x1018 | LF_ENUM [size = 148, unreferenced] `__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e`
CHECK: unique name: `.?AW4type_e@v1_alttypeAttribute@helper_attributes@__vc_attributes@@`
CHECK: field list: 0x1017, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x1019 | LF_STRUCTURE [size = 140, unreferenced] `__vc_attributes::helper_attributes::v1_alttypeAttribute`
CHECK: unique name: `.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x101E) | has unique name, sizeof 0
CHECK: 0x101A | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x1019, mode = pointer, opts = const, kind = ptr64
CHECK: 0x101B | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x1018: `__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e`
CHECK: 0x101C | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x101B
CHECK: class type = 0x1019, this type = 0x101A, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x101D | LF_FIELDLIST [size = 64, unreferenced]
CHECK: - LF_NESTTYPE [name = `type_e`, parent = 0x1018]
CHECK: - LF_ONEMETHOD [name = `v1_alttypeAttribute`]
CHECK: type = 0x101C, vftable offset = -1, attrs = public
CHECK: - LF_MEMBER [name = `type`, Type = 0x1018, offset = 0, attrs = public]
CHECK: 0x101E | LF_STRUCTURE [size = 140, unreferenced] `__vc_attributes::helper_attributes::v1_alttypeAttribute`
CHECK: unique name: `.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x101D
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 4
CHECK: 0x101F | LF_FIELDLIST [size = 756, unreferenced]
CHECK: - LF_ENUMERATE [eAnyUsage = 0]
CHECK: - LF_ENUMERATE [eCoClassUsage = 1]
CHECK: - LF_ENUMERATE [eCOMInterfaceUsage = 2]
CHECK: - LF_ENUMERATE [eInterfaceUsage = 6]
CHECK: - LF_ENUMERATE [eMemberUsage = 8]
CHECK: - LF_ENUMERATE [eMethodUsage = 16]
CHECK: - LF_ENUMERATE [eInterfaceMethodUsage = 32]
CHECK: - LF_ENUMERATE [eInterfaceMemberUsage = 64]
CHECK: - LF_ENUMERATE [eCoClassMemberUsage = 128]
CHECK: - LF_ENUMERATE [eCoClassMethodUsage = 256]
CHECK: - LF_ENUMERATE [eGlobalMethodUsage = 768]
CHECK: - LF_ENUMERATE [eGlobalDataUsage = 1024]
CHECK: - LF_ENUMERATE [eClassUsage = 2048]
CHECK: - LF_ENUMERATE [eInterfaceParameterUsage = 4096]
CHECK: - LF_ENUMERATE [eMethodParameterUsage = 12288]
CHECK: - LF_ENUMERATE [eIDLModuleUsage = 16384]
CHECK: - LF_ENUMERATE [eAnonymousUsage = 32768]
CHECK: - LF_ENUMERATE [eTypedefUsage = 65536]
CHECK: - LF_ENUMERATE [eUnionUsage = 131072]
CHECK: - LF_ENUMERATE [eEnumUsage = 262144]
CHECK: - LF_ENUMERATE [eDefineTagUsage = 524288]
CHECK: - LF_ENUMERATE [eStructUsage = 1048576]
CHECK: - LF_ENUMERATE [eLocalUsage = 2097152]
CHECK: - LF_ENUMERATE [ePropertyUsage = 4194304]
CHECK: - LF_ENUMERATE [eEventUsage = 8388608]
CHECK: - LF_ENUMERATE [eTemplateUsage = 16777216]
CHECK: - LF_ENUMERATE [eModuleUsage = 16777216]
CHECK: - LF_ENUMERATE [eIllegalUsage = 33554432]
CHECK: - LF_ENUMERATE [eAsynchronousUsage = 67108864]
CHECK: - LF_ENUMERATE [eAnyIDLUsage = 4161535]
CHECK: 0x1020 | LF_ENUM [size = 140, unreferenced] `__vc_attributes::helper_attributes::usageAttribute::usage_e`
CHECK: unique name: `.?AW4usage_e@usageAttribute@helper_attributes@__vc_attributes@@`
CHECK: field list: 0x101F, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x1021 | LF_STRUCTURE [size = 128, unreferenced] `__vc_attributes::helper_attributes::usageAttribute`
CHECK: unique name: `.?AUusageAttribute@helper_attributes@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1026) | has unique name, sizeof 0
CHECK: 0x1022 | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x1021, mode = pointer, opts = const, kind = ptr64
CHECK: 0x1023 | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x0075 (unsigned): `unsigned`
CHECK: 0x1024 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1023
CHECK: class type = 0x1021, this type = 0x1022, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1025 | LF_FIELDLIST [size = 60, unreferenced]
CHECK: - LF_NESTTYPE [name = `usage_e`, parent = 0x1020]
CHECK: - LF_ONEMETHOD [name = `usageAttribute`]
CHECK: type = 0x1024, vftable offset = -1, attrs = public
CHECK: - LF_MEMBER [name = `value`, Type = 0x0075 (unsigned), offset = 0, attrs = public]
CHECK: 0x1026 | LF_STRUCTURE [size = 128, unreferenced] `__vc_attributes::helper_attributes::usageAttribute`
CHECK: unique name: `.?AUusageAttribute@helper_attributes@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1025
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 4
CHECK: 0x1027 | LF_FIELDLIST [size = 76, unreferenced]
CHECK: - LF_ENUMERATE [apartment = 1]
CHECK: - LF_ENUMERATE [single = 2]
CHECK: - LF_ENUMERATE [free = 3]
CHECK: - LF_ENUMERATE [neutral = 4]
CHECK: - LF_ENUMERATE [both = 5]
CHECK: 0x1028 | LF_ENUM [size = 120, unreferenced] `__vc_attributes::threadingAttribute::threading_e`
CHECK: unique name: `.?AW4threading_e@threadingAttribute@__vc_attributes@@`
CHECK: field list: 0x1027, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x1029 | LF_STRUCTURE [size = 100, unreferenced] `__vc_attributes::threadingAttribute`
CHECK: unique name: `.?AUthreadingAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1030) | has unique name, sizeof 0
CHECK: 0x102A | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x1029, mode = pointer, opts = const, kind = ptr64
CHECK: 0x102B | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x1028: `__vc_attributes::threadingAttribute::threading_e`
CHECK: 0x102C | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x102B
CHECK: class type = 0x1029, this type = 0x102A, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x102D | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 0, param list = 0x1012
CHECK: class type = 0x1029, this type = 0x102A, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x102E | LF_METHODLIST [size = 20, unreferenced]
CHECK: - Method [type = 0x102C, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x102D, vftable offset = -1, attrs = public]
CHECK: 0x102F | LF_FIELDLIST [size = 68, unreferenced]
CHECK: - LF_NESTTYPE [name = `threading_e`, parent = 0x1028]
CHECK: - LF_METHOD [name = `threadingAttribute`, # overloads = 2, overload list = 0x102E]
CHECK: - LF_MEMBER [name = `value`, Type = 0x1028, offset = 0, attrs = public]
CHECK: 0x1030 | LF_STRUCTURE [size = 100, unreferenced] `__vc_attributes::threadingAttribute`
CHECK: unique name: `.?AUthreadingAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x102F
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 4
CHECK: 0x1031 | LF_FIELDLIST [size = 48, unreferenced]
CHECK: - LF_ENUMERATE [never = 0]
CHECK: - LF_ENUMERATE [allowed = 1]
CHECK: - LF_ENUMERATE [always = 2]
CHECK: 0x1032 | LF_ENUM [size = 116, unreferenced] `__vc_attributes::aggregatableAttribute::type_e`
CHECK: unique name: `.?AW4type_e@aggregatableAttribute@__vc_attributes@@`
CHECK: field list: 0x1031, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x1033 | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::aggregatableAttribute`
CHECK: unique name: `.?AUaggregatableAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x103A) | has unique name, sizeof 0
CHECK: 0x1034 | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x1033, mode = pointer, opts = const, kind = ptr64
CHECK: 0x1035 | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x1032: `__vc_attributes::aggregatableAttribute::type_e`
CHECK: 0x1036 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1035
CHECK: class type = 0x1033, this type = 0x1034, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1037 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 0, param list = 0x1012
CHECK: class type = 0x1033, this type = 0x1034, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1038 | LF_METHODLIST [size = 20, unreferenced]
CHECK: - Method [type = 0x1036, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x1037, vftable offset = -1, attrs = public]
CHECK: 0x1039 | LF_FIELDLIST [size = 68, unreferenced]
CHECK: - LF_NESTTYPE [name = `type_e`, parent = 0x1032]
CHECK: - LF_METHOD [name = `aggregatableAttribute`, # overloads = 2, overload list = 0x1038]
CHECK: - LF_MEMBER [name = `type`, Type = 0x1032, offset = 0, attrs = public]
CHECK: 0x103A | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::aggregatableAttribute`
CHECK: unique name: `.?AUaggregatableAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1039
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 4
CHECK: 0x103B | LF_ENUM [size = 120, unreferenced] `__vc_attributes::event_receiverAttribute::type_e`
CHECK: unique name: `.?AW4type_e@event_receiverAttribute@__vc_attributes@@`
CHECK: field list: 0x100A, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x103C | LF_STRUCTURE [size = 112, unreferenced] `__vc_attributes::event_receiverAttribute`
CHECK: unique name: `.?AUevent_receiverAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1045) | has unique name, sizeof 0
CHECK: 0x103D | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x103C, mode = pointer, opts = const, kind = ptr64
CHECK: 0x103E | LF_ARGLIST [size = 16, unreferenced]
CHECK: 0x103B: `__vc_attributes::event_receiverAttribute::type_e`
CHECK: 0x0030 (bool): `bool`
CHECK: 0x103F | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 2, param list = 0x103E
CHECK: class type = 0x103C, this type = 0x103D, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1040 | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x103B: `__vc_attributes::event_receiverAttribute::type_e`
CHECK: 0x1041 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1040
CHECK: class type = 0x103C, this type = 0x103D, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1042 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 0, param list = 0x1012
CHECK: class type = 0x103C, this type = 0x103D, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1043 | LF_METHODLIST [size = 28, unreferenced]
CHECK: - Method [type = 0x103F, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x1041, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x1042, vftable offset = -1, attrs = public]
CHECK: 0x1044 | LF_FIELDLIST [size = 96, unreferenced]
CHECK: - LF_NESTTYPE [name = `type_e`, parent = 0x103B]
CHECK: - LF_METHOD [name = `event_receiverAttribute`, # overloads = 3, overload list = 0x1043]
CHECK: - LF_MEMBER [name = `type`, Type = 0x103B, offset = 0, attrs = public]
CHECK: - LF_MEMBER [name = `layout_dependent`, Type = 0x0030 (bool), offset = 4, attrs = public]
CHECK: 0x1045 | LF_STRUCTURE [size = 112, unreferenced] `__vc_attributes::event_receiverAttribute`
CHECK: unique name: `.?AUevent_receiverAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1044
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 8
CHECK: 0x1046 | LF_FIELDLIST [size = 92, unreferenced]
CHECK: - LF_ENUMERATE [dll = 1]
CHECK: - LF_ENUMERATE [exe = 2]
CHECK: - LF_ENUMERATE [service = 3]
CHECK: - LF_ENUMERATE [unspecified = 4]
CHECK: - LF_ENUMERATE [EXE = 2]
CHECK: - LF_ENUMERATE [SERVICE = 3]
CHECK: 0x1047 | LF_ENUM [size = 104, unreferenced] `__vc_attributes::moduleAttribute::type_e`
CHECK: unique name: `.?AW4type_e@moduleAttribute@__vc_attributes@@`
CHECK: field list: 0x1046, underlying type: 0x0074 (int)
CHECK: options: has unique name | is nested
CHECK: 0x1048 | LF_STRUCTURE [size = 96, unreferenced] `__vc_attributes::moduleAttribute`
CHECK: unique name: `.?AUmoduleAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1053) | has unique name, sizeof 0
CHECK: 0x1049 | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x1048, mode = pointer, opts = const, kind = ptr64
CHECK: 0x104A | LF_MODIFIER [size = 12, unreferenced]
CHECK: referent = 0x0070 (char), modifiers = const
CHECK: 0x104B | LF_POINTER [size = 12, unreferenced]
CHECK: referent = 0x104A, mode = pointer, opts = None, kind = ptr64
CHECK: 0x104C | LF_ARGLIST [size = 68, unreferenced]
CHECK: 0x1047: `__vc_attributes::moduleAttribute::type_e`
CHECK: 0x104B: `const char*`
CHECK: 0x104B: `const char*`
CHECK: 0x104B: `const char*`
CHECK: 0x0074 (int): `int`
CHECK: 0x0030 (bool): `bool`
CHECK: 0x104B: `const char*`
CHECK: 0x0074 (int): `int`
CHECK: 0x104B: `const char*`
CHECK: 0x104B: `const char*`
CHECK: 0x0074 (int): `int`
CHECK: 0x0030 (bool): `bool`
CHECK: 0x0030 (bool): `bool`
CHECK: 0x104B: `const char*`
CHECK: 0x104B: `const char*`
CHECK: 0x104D | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 15, param list = 0x104C
CHECK: class type = 0x1048, this type = 0x1049, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x104E | LF_ARGLIST [size = 12, unreferenced]
CHECK: 0x1047: `__vc_attributes::moduleAttribute::type_e`
CHECK: 0x104F | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x104E
CHECK: class type = 0x1048, this type = 0x1049, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1050 | LF_MFUNCTION [size = 28, unreferenced]
CHECK: return type = 0x0003 (void), # args = 0, param list = 0x1012
CHECK: class type = 0x1048, this type = 0x1049, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x1051 | LF_METHODLIST [size = 28, unreferenced]
CHECK: - Method [type = 0x104D, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x104F, vftable offset = -1, attrs = public]
CHECK: - Method [type = 0x1050, vftable offset = -1, attrs = public]
CHECK: 0x1052 | LF_FIELDLIST [size = 356, unreferenced]
CHECK: - LF_NESTTYPE [name = `type_e`, parent = 0x1047]
CHECK: - LF_METHOD [name = `moduleAttribute`, # overloads = 3, overload list = 0x1051]
CHECK: - LF_MEMBER [name = `type`, Type = 0x1047, offset = 0, attrs = public]
CHECK: - LF_MEMBER [name = `name`, Type = 0x104B, offset = 8, attrs = public]
CHECK: - LF_MEMBER [name = `version`, Type = 0x104B, offset = 16, attrs = public]
CHECK: - LF_MEMBER [name = `uuid`, Type = 0x104B, offset = 24, attrs = public]
CHECK: - LF_MEMBER [name = `lcid`, Type = 0x0074 (int), offset = 32, attrs = public]
CHECK: - LF_MEMBER [name = `control`, Type = 0x0030 (bool), offset = 36, attrs = public]
CHECK: - LF_MEMBER [name = `helpstring`, Type = 0x104B, offset = 40, attrs = public]
CHECK: - LF_MEMBER [name = `helpstringcontext`, Type = 0x0074 (int), offset = 48, attrs = public]
CHECK: - LF_MEMBER [name = `helpstringdll`, Type = 0x104B, offset = 56, attrs = public]
CHECK: - LF_MEMBER [name = `helpfile`, Type = 0x104B, offset = 64, attrs = public]
CHECK: - LF_MEMBER [name = `helpcontext`, Type = 0x0074 (int), offset = 72, attrs = public]
CHECK: - LF_MEMBER [name = `hidden`, Type = 0x0030 (bool), offset = 76, attrs = public]
CHECK: - LF_MEMBER [name = `restricted`, Type = 0x0030 (bool), offset = 77, attrs = public]
CHECK: - LF_MEMBER [name = `custom`, Type = 0x104B, offset = 80, attrs = public]
CHECK: - LF_MEMBER [name = `resource_name`, Type = 0x104B, offset = 88, attrs = public]
CHECK: 0x1053 | LF_STRUCTURE [size = 96, unreferenced] `__vc_attributes::moduleAttribute`
CHECK: unique name: `.?AUmoduleAttribute@__vc_attributes@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1052
CHECK: options: has ctor / dtor | contains nested class | has unique name, sizeof 96
CHECK: 0x1054 | LF_STRUCTURE [size = 48, referenced] `Nested::F`
CHECK: unique name: `.?AUF@Nested@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1057) | has unique name | is nested, sizeof 0
CHECK: 0x1055 | LF_FIELDLIST [size = 16, referenced]
CHECK: - LF_NESTTYPE [name = `F`, parent = 0x1054]
CHECK: 0x1056 | LF_STRUCTURE [size = 44, referenced] `Nested`
CHECK: unique name: `.?AUNested@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1055
CHECK: options: contains nested class | has unique name, sizeof 1
CHECK: 0x1057 | LF_STRUCTURE [size = 48, referenced] `Nested::F`
CHECK: unique name: `.?AUF@Nested@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1007
CHECK: options: has unique name | is nested, sizeof 1
CHECK: 0x1058 | LF_STRUCTURE [size = 52, referenced] `Constructor`
CHECK: unique name: `.?AUConstructor@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x105C) | has unique name, sizeof 0
CHECK: 0x1059 | LF_POINTER [size = 12, referenced]
CHECK: referent = 0x1058, mode = pointer, opts = const, kind = ptr64
CHECK: 0x105A | LF_MFUNCTION [size = 28, referenced]
CHECK: return type = 0x0003 (void), # args = 0, param list = 0x1012
CHECK: class type = 0x1058, this type = 0x1059, this adjust = 0
CHECK: calling conv = cdecl, options = constructor
CHECK: 0x105B | LF_FIELDLIST [size = 24, referenced]
CHECK: - LF_ONEMETHOD [name = `Constructor`]
CHECK: type = 0x105A, vftable offset = -1, attrs = public
CHECK: 0x105C | LF_STRUCTURE [size = 52, referenced] `Constructor`
CHECK: unique name: `.?AUConstructor@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x105B
CHECK: options: has ctor / dtor | has unique name, sizeof 1
CHECK: 0x105D | LF_CLASS [size = 40, referenced] `Class`
CHECK: unique name: `.?AVClass@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1007
CHECK: options: has unique name, sizeof 1
CHECK: 0x105E | LF_UNION [size = 32, referenced] `Union`
CHECK: unique name: `.?ATUnion@@`
CHECK: field list: 0x1007
CHECK: options: has unique name | sealed, sizeof 1
CHECK: 0x105F | LF_STRUCTURE [size = 48, referenced] `Operator`
CHECK: unique name: `.?AUOperator@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1064) | has unique name, sizeof 0
CHECK: 0x1060 | LF_POINTER [size = 12, referenced]
CHECK: referent = 0x105F, mode = pointer, opts = const, kind = ptr64
CHECK: 0x1061 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x0074 (int): `int`
CHECK: 0x1062 | LF_MFUNCTION [size = 28, referenced]
CHECK: return type = 0x0074 (int), # args = 1, param list = 0x1061
CHECK: class type = 0x105F, this type = 0x1060, this adjust = 0
CHECK: calling conv = cdecl, options = None
CHECK: 0x1063 | LF_FIELDLIST [size = 24, referenced]
CHECK: - LF_ONEMETHOD [name = `operator+`]
CHECK: type = 0x1062, vftable offset = -1, attrs = public
CHECK: 0x1064 | LF_STRUCTURE [size = 48, referenced] `Operator`
CHECK: unique name: `.?AUOperator@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1063
CHECK: options: has unique name | overloaded operator, sizeof 1
CHECK: 0x1065 | LF_FIELDLIST [size = 12, referenced]
CHECK: - LF_ENUMERATE [A = 0]
CHECK: 0x1066 | LF_ENUM [size = 36, referenced] `Enum`
CHECK: unique name: `.?AW4Enum@@`
CHECK: field list: 0x1065, underlying type: 0x0074 (int)
CHECK: options: has unique name
CHECK: 0x1067 | LF_STRUCTURE [size = 40, referenced] `Cast`
CHECK: unique name: `.?AUCast@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x106B) | has unique name, sizeof 0
CHECK: 0x1068 | LF_POINTER [size = 12, referenced]
CHECK: referent = 0x1067, mode = pointer, opts = const, kind = ptr64
CHECK: 0x1069 | LF_MFUNCTION [size = 28, referenced]
CHECK: return type = 0x0074 (int), # args = 0, param list = 0x1012
CHECK: class type = 0x1067, this type = 0x1068, this adjust = 0
CHECK: calling conv = cdecl, options = None
CHECK: 0x106A | LF_FIELDLIST [size = 28, referenced]
CHECK: - LF_ONEMETHOD [name = `operator int`]
CHECK: type = 0x1069, vftable offset = -1, attrs = public
CHECK: 0x106B | LF_STRUCTURE [size = 40, referenced] `Cast`
CHECK: unique name: `.?AUCast@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x106A
CHECK: options: conversion operator | has unique name | overloaded operator, sizeof 1
CHECK: 0x106C | LF_STRUCTURE [size = 44, referenced] `Nothing`
CHECK: unique name: `.?AUNothing@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1007
CHECK: options: has unique name, sizeof 1
CHECK: 0x106D | LF_STRUCTURE [size = 52, referenced] `Assignment`
CHECK: unique name: `.?AUAssignment@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (-> 0x1073) | has unique name, sizeof 0
CHECK: 0x106E | LF_POINTER [size = 12, referenced]
CHECK: referent = 0x106D, mode = ref, opts = None, kind = ptr64
CHECK: 0x106F | LF_POINTER [size = 12, referenced]
CHECK: referent = 0x106D, mode = pointer, opts = const, kind = ptr64
CHECK: 0x1070 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x106D: `Assignment`
CHECK: 0x1071 | LF_MFUNCTION [size = 28, referenced]
CHECK: return type = 0x106E, # args = 1, param list = 0x1070
CHECK: class type = 0x106D, this type = 0x106F, this adjust = 0
CHECK: calling conv = cdecl, options = None
CHECK: 0x1072 | LF_FIELDLIST [size = 24, referenced]
CHECK: - LF_ONEMETHOD [name = `operator=`]
CHECK: type = 0x1071, vftable offset = -1, attrs = public
CHECK: 0x1073 | LF_STRUCTURE [size = 52, referenced] `Assignment`
CHECK: unique name: `.?AUAssignment@@`
CHECK: vtable: <no type>, base list: <no type>, field list: 0x1072
CHECK: options: has unique name | overloaded operator | overloaded operator=, sizeof 1
CHECK: 0x1074 | LF_STRUCTURE [size = 44, referenced] `Nothing`
CHECK: unique name: `.?AUNothing@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (<- 0x106C) | has unique name, sizeof 0
CHECK: 0x1075 | LF_MODIFIER [size = 12, referenced]
CHECK: referent = 0x1074, modifiers = const
CHECK: 0x1076 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1075: `const Nothing`
CHECK: 0x1077 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1076
CHECK: calling conv = cdecl, options = None
CHECK: 0x1078 | LF_MODIFIER [size = 12, referenced]
CHECK: referent = 0x1074, modifiers = volatile
CHECK: 0x1079 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1078: `volatile Nothing`
CHECK: 0x107A | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1079
CHECK: calling conv = cdecl, options = None
CHECK: 0x107B | LF_MODIFIER [size = 12, referenced]
CHECK: referent = 0x1074, modifiers = const | volatile
CHECK: 0x107C | LF_ARGLIST [size = 12, referenced]
CHECK: 0x107B: `const volatile Nothing`
CHECK: 0x107D | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x107C
CHECK: calling conv = cdecl, options = None
CHECK: 0x107E | LF_MODIFIER [size = 12, referenced]
CHECK: referent = 0x1074, modifiers = unaligned
CHECK: 0x107F | LF_ARGLIST [size = 12, referenced]
CHECK: 0x107E: `__unaligned Nothing`
CHECK: 0x1080 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x107F
CHECK: calling conv = cdecl, options = None
CHECK: 0x1081 | LF_UNION [size = 32, referenced] `Union`
CHECK: unique name: `.?ATUnion@@`
CHECK: field list: <no type>
CHECK: options: forward ref (<- 0x105E) | has unique name, sizeof 0
CHECK: 0x1082 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1081: `Union`
CHECK: 0x1083 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1082
CHECK: calling conv = cdecl, options = None
CHECK: 0x1084 | LF_STRUCTURE [size = 124, referenced] `main::__l2::<unnamed-type-Anonymous>`
CHECK: unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (<- 0x1008) | has unique name | scoped, sizeof 0
CHECK: 0x1085 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1084: `main::__l2::<unnamed-type-Anonymous>`
CHECK: 0x1086 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1085
CHECK: calling conv = cdecl, options = None
CHECK: 0x1087 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1070
CHECK: calling conv = cdecl, options = None
CHECK: 0x1088 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1067: `Cast`
CHECK: 0x1089 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1088
CHECK: calling conv = cdecl, options = None
CHECK: 0x108A | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1058: `Constructor`
CHECK: 0x108B | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x108A
CHECK: calling conv = cdecl, options = None
CHECK: 0x108C | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1054: `Nested::F`
CHECK: 0x108D | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x108C
CHECK: calling conv = cdecl, options = None
CHECK: 0x108E | LF_STRUCTURE [size = 44, referenced] `Nested`
CHECK: unique name: `.?AUNested@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (<- 0x1056) | has unique name, sizeof 0
CHECK: 0x108F | LF_ARGLIST [size = 12, referenced]
CHECK: 0x108E: `Nested`
CHECK: 0x1090 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x108F
CHECK: calling conv = cdecl, options = None
CHECK: 0x1091 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1074: `Nothing`
CHECK: 0x1092 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1091
CHECK: calling conv = cdecl, options = None
CHECK: 0x1093 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x105F: `Operator`
CHECK: 0x1094 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1093
CHECK: calling conv = cdecl, options = None
CHECK: 0x1095 | LF_STRUCTURE [size = 88, referenced] `main::__l2::Scoped`
CHECK: unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD@Z@`aa6523bc`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (<- 0x1009) | has unique name | scoped, sizeof 0
CHECK: 0x1096 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1095: `main::__l2::Scoped`
CHECK: 0x1097 | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1096
CHECK: calling conv = cdecl, options = None
CHECK: 0x1098 | LF_CLASS [size = 40, referenced] `Class`
CHECK: unique name: `.?AVClass@@`
CHECK: vtable: <no type>, base list: <no type>, field list: <no type>
CHECK: options: forward ref (<- 0x105D) | has unique name, sizeof 0
CHECK: 0x1099 | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1098: `Class`
CHECK: 0x109A | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x1099
CHECK: calling conv = cdecl, options = None
CHECK: 0x109B | LF_ARGLIST [size = 12, referenced]
CHECK: 0x1066: `Enum`
CHECK: 0x109C | LF_PROCEDURE [size = 16, referenced]
CHECK: return type = 0x0003 (void), # args = 1, param list = 0x109B
CHECK: calling conv = cdecl, options = None
CHECK: Type Reference Statistics
CHECK: ============================================================
CHECK: Records referenced: 84 / 157 53.50%
CHECK: Bytes referenced: 2,188 / 7,500 29.17%

View File

@ -30,5 +30,6 @@ add_llvm_tool(llvm-pdbutil
PrettyTypedefDumper.cpp
PrettyVariableDumper.cpp
StreamUtil.cpp
TypeReferenceTracker.cpp
YAMLOutputStyle.cpp
)

View File

@ -13,6 +13,7 @@
#include "MinimalSymbolDumper.h"
#include "MinimalTypeDumper.h"
#include "StreamUtil.h"
#include "TypeReferenceTracker.h"
#include "llvm-pdbutil.h"
#include "llvm/ADT/STLExtras.h"
@ -60,7 +61,12 @@ using namespace llvm::msf;
using namespace llvm::pdb;
DumpOutputStyle::DumpOutputStyle(InputFile &File)
: File(File), P(2, false, outs()) {}
: File(File), P(2, false, outs()) {
if (opts::dump::DumpTypeRefStats)
RefTracker.reset(new TypeReferenceTracker(File));
}
DumpOutputStyle::~DumpOutputStyle() {}
PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
@ -76,6 +82,10 @@ void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) {
}
Error DumpOutputStyle::dump() {
// Walk symbols & globals if we are supposed to mark types referenced.
if (opts::dump::DumpTypeRefStats)
RefTracker->mark();
if (opts::dump::DumpSummary) {
if (auto EC = dumpFileSummary())
return EC;
@ -187,6 +197,11 @@ Error DumpOutputStyle::dump() {
return EC;
}
if (opts::dump::DumpTypeRefStats) {
if (auto EC = dumpTypeRefStats())
return EC;
}
if (opts::dump::DumpSectionHeaders) {
if (auto EC = dumpSectionHeaders())
return EC;
@ -1227,14 +1242,15 @@ static void buildDepSet(LazyRandomTypeCollection &Types,
static void
dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
uint32_t NumTypeRecords, uint32_t NumHashBuckets,
TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
uint32_t NumHashBuckets,
FixedStreamArray<support::ulittle32_t> HashValues,
TpiStream *Stream, bool Bytes, bool Extras) {
Printer.formatLine("Showing {0:N} records", NumTypeRecords);
uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
NumHashBuckets, HashValues, Stream);
if (auto EC = codeview::visitTypeStream(Types, V)) {
@ -1245,12 +1261,13 @@ dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
static void dumpPartialTypeStream(LinePrinter &Printer,
LazyRandomTypeCollection &Types,
TypeReferenceTracker *RefTracker,
TpiStream &Stream, ArrayRef<TypeIndex> TiList,
bool Bytes, bool Extras, bool Deps) {
uint32_t Width =
NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
Stream.getNumHashBuckets(), Stream.getHashValues(),
&Stream);
@ -1314,8 +1331,8 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {
Types.reset(Reader, 100);
if (opts::dump::DumpTypes) {
dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,
false);
dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
opts::dump::DumpTypeData, false);
} else if (opts::dump::DumpTypeExtras) {
auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
@ -1384,18 +1401,22 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
// Only emit notes about referenced/unreferenced for types.
TypeReferenceTracker *MaybeTracker =
(StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
// Enable resolving forward decls.
Stream.buildHashMap();
if (DumpTypes || !Indices.empty()) {
if (Indices.empty())
dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
Stream.getNumHashBuckets(), Stream.getHashValues(),
&Stream, DumpBytes, DumpExtras);
else {
std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
opts::dump::DumpTypeDependents);
dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
DumpExtras, opts::dump::DumpTypeDependents);
}
}
@ -1520,6 +1541,34 @@ Error DumpOutputStyle::dumpModuleSymsForPdb() {
return Error::success();
}
Error DumpOutputStyle::dumpTypeRefStats() {
printHeader(P, "Type Reference Statistics");
AutoIndent Indent(P);
// Sum the byte size of all type records, and the size and count of all
// referenced records.
size_t TotalRecs = File.types().size();
size_t RefRecs = 0;
size_t TotalBytes = 0;
size_t RefBytes = 0;
auto &Types = File.types();
for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
CVType Type = File.types().getType(*TI);
TotalBytes += Type.length();
if (RefTracker->isTypeReferenced(*TI)) {
++RefRecs;
RefBytes += Type.length();
}
}
P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
(double)RefRecs / TotalRecs);
P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
(double)RefBytes / TotalBytes);
return Error::success();
}
Error DumpOutputStyle::dumpGSIRecords() {
printHeader(P, "GSI Records");

View File

@ -34,6 +34,7 @@ class COFFObjectFile;
namespace pdb {
class GSIHashTable;
class InputFile;
class TypeReferenceTracker;
struct StatCollection {
struct Stat {
@ -62,6 +63,7 @@ class DumpOutputStyle : public OutputStyle {
public:
DumpOutputStyle(InputFile &File);
~DumpOutputStyle() override;
Error dump() override;
@ -89,6 +91,7 @@ private:
Error dumpNewFpo(PDBFile &File);
Error dumpTpiStream(uint32_t StreamIdx);
Error dumpTypesFromObjectFile();
Error dumpTypeRefStats();
Error dumpModules();
Error dumpModuleFiles();
Error dumpModuleSymsForPdb();
@ -104,6 +107,7 @@ private:
void dumpSectionHeaders(StringRef Label, DbgHeaderType Type);
InputFile &File;
std::unique_ptr<TypeReferenceTracker> RefTracker;
LinePrinter P;
SmallVector<StreamInfo, 32> StreamPurposes;
};

View File

@ -10,6 +10,7 @@
#include "FormatUtil.h"
#include "LinePrinter.h"
#include "TypeReferenceTracker.h"
#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
@ -221,11 +222,10 @@ Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
// formatLine puts the newline at the beginning, so we use formatLine here
// to start a new line, and then individual visit methods use format to
// append to the existing line.
if (!Hashes) {
P.formatLine("{0} | {1} [size = {2}]",
fmt_align(Index, AlignStyle::Right, Width),
formatTypeLeafKind(Record.Type), Record.length());
} else {
P.formatLine("{0} | {1} [size = {2}",
fmt_align(Index, AlignStyle::Right, Width),
formatTypeLeafKind(Record.Type), Record.length());
if (Hashes) {
std::string H;
if (Index.toArrayIndex() >= HashValues.size()) {
H = "(not present)";
@ -241,13 +241,19 @@ Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
else
H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
}
P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
fmt_align(Index, AlignStyle::Right, Width),
formatTypeLeafKind(Record.Type), Record.length(), H);
P.format(", hash = {0}", H);
}
if (RefTracker) {
if (RefTracker->isTypeReferenced(Index))
P.format(", referenced");
else
P.format(", unreferenced");
}
P.format("]");
P.Indent(Width + 3);
return Error::success();
}
Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
P.Unindent(Width + 3);
if (RecordBytes) {

View File

@ -20,17 +20,19 @@ class LazyRandomTypeCollection;
namespace pdb {
class LinePrinter;
class TpiStream;
class TypeReferenceTracker;
class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
public:
MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
bool Hashes, codeview::LazyRandomTypeCollection &Types,
TypeReferenceTracker *RefTracker,
uint32_t NumHashBuckets,
FixedStreamArray<support::ulittle32_t> HashValues,
pdb::TpiStream *Stream)
: P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues),
Stream(Stream) {}
Types(Types), RefTracker(RefTracker), NumHashBuckets(NumHashBuckets),
HashValues(HashValues), Stream(Stream) {}
Error visitTypeBegin(codeview::CVType &Record,
codeview::TypeIndex Index) override;
@ -56,6 +58,7 @@ private:
bool RecordBytes = false;
bool Hashes = false;
codeview::LazyRandomTypeCollection &Types;
pdb::TypeReferenceTracker *RefTracker = nullptr;
uint32_t NumHashBuckets;
codeview::TypeIndex CurrentTypeIndex;
FixedStreamArray<support::ulittle32_t> HashValues;

View File

@ -0,0 +1,160 @@
//===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "TypeReferenceTracker.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
using namespace llvm;
using namespace llvm::pdb;
using namespace llvm::codeview;
// LazyRandomTypeCollection doesn't appear to expose the number of records, so
// just iterate up front to find out.
static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) {
uint32_t NumTypes = 0;
for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI))
++NumTypes;
return NumTypes;
}
TypeReferenceTracker::TypeReferenceTracker(InputFile &File)
: File(File), Types(File.types()),
Ids(File.isPdb() ? &File.ids() : nullptr) {
NumTypeRecords = getNumRecordsInCollection(Types);
TypeReferenced.resize(NumTypeRecords, false);
// If this is a PDB, ids are stored separately, so make a separate bit vector.
if (Ids) {
NumIdRecords = getNumRecordsInCollection(*Ids);
IdReferenced.resize(NumIdRecords, false);
}
// Get the TpiStream pointer for forward decl resolution if this is a pdb.
// Build the hash map to enable resolving forward decls.
if (File.isPdb()) {
Tpi = &cantFail(File.pdb().getPDBTpiStream());
Tpi->buildHashMap();
}
}
void TypeReferenceTracker::mark() {
// Walk type roots:
// - globals
// - modi symbols
// - LF_UDT_MOD_SRC_LINE? VC always links these in.
for (SymbolGroup SG : File.symbol_groups()) {
if (File.isObj()) {
for (const auto &SS : SG.getDebugSubsections()) {
// FIXME: Are there other type-referencing subsections? Inlinees?
// Probably for IDs.
if (SS.kind() != DebugSubsectionKind::Symbols)
continue;
CVSymbolArray Symbols;
BinaryStreamReader Reader(SS.getRecordData());
cantFail(Reader.readArray(Symbols, Reader.getLength()));
for (const CVSymbol &S : Symbols)
addTypeRefsFromSymbol(S);
}
} else if (SG.hasDebugStream()) {
for (const CVSymbol &S : SG.getPdbModuleStream().getSymbolArray())
addTypeRefsFromSymbol(S);
}
}
// Walk globals and mark types referenced from globals.
if (File.isPdb() && File.pdb().hasPDBGlobalsStream()) {
SymbolStream &SymStream = cantFail(File.pdb().getPDBSymbolStream());
GlobalsStream &GS = cantFail(File.pdb().getPDBGlobalsStream());
for (uint32_t PubSymOff : GS.getGlobalsTable()) {
CVSymbol Sym = SymStream.readRecord(PubSymOff);
addTypeRefsFromSymbol(Sym);
}
}
// FIXME: Should we walk Ids?
}
void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind, TypeIndex RefTI) {
// If it's simple or already seen, no need to add to work list.
BitVector &TypeOrIdReferenced =
(Ids && RefKind == TiRefKind::IndexRef) ? IdReferenced : TypeReferenced;
if (RefTI.isSimple() || TypeOrIdReferenced.test(RefTI.toArrayIndex()))
return;
// Otherwise, mark it seen and add it to the work list.
TypeOrIdReferenced.set(RefTI.toArrayIndex());
RefWorklist.push_back({RefKind, RefTI});
}
void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol &Sym) {
SmallVector<TiReference, 4> DepList;
// FIXME: Check for failure.
discoverTypeIndicesInSymbol(Sym, DepList);
addReferencedTypes(Sym.content(), DepList);
markReferencedTypes();
}
void TypeReferenceTracker::addReferencedTypes(ArrayRef<uint8_t> RecData,
ArrayRef<TiReference> DepList) {
for (const auto &Ref : DepList) {
// FIXME: Report OOB slice instead of truncating.
ArrayRef<uint8_t> ByteSlice =
RecData.drop_front(Ref.Offset).take_front(4 * Ref.Count);
ArrayRef<TypeIndex> TIs(
reinterpret_cast<const TypeIndex *>(ByteSlice.data()),
ByteSlice.size() / 4);
// If this is a PDB and this is an item reference, track it in the IPI
// bitvector. Otherwise, it's a type ref, or there is only one stream.
for (TypeIndex RefTI : TIs)
addOneTypeRef(Ref.Kind, RefTI);
}
}
void TypeReferenceTracker::markReferencedTypes() {
while (!RefWorklist.empty()) {
TiRefKind RefKind;
TypeIndex RefTI;
std::tie(RefKind, RefTI) = RefWorklist.pop_back_val();
Optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)
? Ids->tryGetType(RefTI)
: Types.tryGetType(RefTI);
if (!Rec)
continue; // FIXME: Report a reference to a non-existant type.
SmallVector<TiReference, 4> DepList;
// FIXME: Check for failure.
discoverTypeIndices(*Rec, DepList);
addReferencedTypes(Rec->content(), DepList);
// If this is a tag kind and this is a PDB input, mark the complete type as
// referenced.
// FIXME: This limitation makes this feature somewhat useless on object file
// inputs.
if (Tpi) {
switch (Rec->kind()) {
default:
break;
case LF_CLASS:
case LF_INTERFACE:
case LF_STRUCTURE:
case LF_UNION:
case LF_ENUM:
addOneTypeRef(TiRefKind::TypeRef,
cantFail(Tpi->findFullDeclForForwardRef(RefTI)));
break;
}
}
}
}

View File

@ -0,0 +1,69 @@
//===- TypeReferenceTracker.h --------------------------------- *- C++ --*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
#define LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
#include "InputFile.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace pdb {
class TpiStream;
/// Maintains bitvector to track whether a type was referenced by a symbol
/// record.
class TypeReferenceTracker {
public:
TypeReferenceTracker(InputFile &File);
// Do the work of marking referenced types.
void mark();
// Return true if a symbol record transitively references this type.
bool isTypeReferenced(codeview::TypeIndex TI) {
return TI.toArrayIndex() <= NumTypeRecords &&
TypeReferenced.test(TI.toArrayIndex());
}
private:
void addTypeRefsFromSymbol(const codeview::CVSymbol &Sym);
// Mark types on this list as referenced.
void addReferencedTypes(ArrayRef<uint8_t> RecData,
ArrayRef<codeview::TiReference> Refs);
// Consume all types on the worklist.
void markReferencedTypes();
void addOneTypeRef(codeview::TiRefKind RefKind, codeview::TypeIndex RefTI);
InputFile &File;
codeview::LazyRandomTypeCollection &Types;
codeview::LazyRandomTypeCollection *Ids = nullptr;
TpiStream *Tpi = nullptr;
BitVector TypeReferenced;
BitVector IdReferenced;
SmallVector<std::pair<codeview::TiRefKind, codeview::TypeIndex>, 10>
RefWorklist;
uint32_t NumTypeRecords = 0;
uint32_t NumIdRecords = 0;
};
} // namespace pdb
} // namespace llvm
#endif // LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H

View File

@ -476,6 +476,11 @@ cl::opt<bool> DumpTypeData(
"type-data",
cl::desc("dump CodeView type record raw bytes from TPI stream"),
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool>
DumpTypeRefStats("type-ref-stats",
cl::desc("dump statistics on the number and size of types "
"transitively referenced by symbol records"),
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
cl::opt<bool> DumpTypeExtras("type-extras",
cl::desc("dump type hashes and index offsets"),

View File

@ -155,6 +155,7 @@ extern llvm::cl::opt<bool> DumpTypeData;
extern llvm::cl::opt<bool> DumpTypeExtras;
extern llvm::cl::list<uint32_t> DumpTypeIndex;
extern llvm::cl::opt<bool> DumpTypeDependents;
extern llvm::cl::opt<bool> DumpTypeRefStats;
extern llvm::cl::opt<bool> DumpSectionHeaders;
extern llvm::cl::opt<bool> DumpIds;