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:
parent
36f9cb0c86
commit
0e0b4260d3
@ -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;
|
||||
|
577
test/DebugInfo/PDB/pdb-type-ref-stats.test
Normal file
577
test/DebugInfo/PDB/pdb-type-ref-stats.test
Normal 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%
|
@ -30,5 +30,6 @@ add_llvm_tool(llvm-pdbutil
|
||||
PrettyTypedefDumper.cpp
|
||||
PrettyVariableDumper.cpp
|
||||
StreamUtil.cpp
|
||||
TypeReferenceTracker.cpp
|
||||
YAMLOutputStyle.cpp
|
||||
)
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
160
tools/llvm-pdbutil/TypeReferenceTracker.cpp
Normal file
160
tools/llvm-pdbutil/TypeReferenceTracker.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
tools/llvm-pdbutil/TypeReferenceTracker.h
Normal file
69
tools/llvm-pdbutil/TypeReferenceTracker.h
Normal 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
|
@ -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"),
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user