Skip to content

Commit 511bff2

Browse files
author
Zachary Turner
committedOct 30, 2018
[NativePDB] Add support for dumping global variables of class type.
Previous patches added support for dumping global variables of primitive types, so we now do the same for class types. For the most part, everything just worked, there was only one minor bug needing fixed, which was that for variables of modified types (e.g. const, volatile, etc) we can't resolve the forward decl in CreateAndCacheType because the PdbSymUid must point to the LF_MODIFIER which must point to the forward decl. So when it comes time to call CompleteType, an assert was firing because we expected to get a class, struct, union, or enum, but we were getting an LF_MODIFIER instead. The other issue is that one the newly added tests is for an array member, which was not yet supported, so we add support for that now in this patch. There's probably room for other interesting layout test cases here, but this at least should test the basics. Differential Revision: https://reviews.llvm.org/D53822 llvm-svn: 345629
1 parent e2b1a9c commit 511bff2

File tree

6 files changed

+345
-3
lines changed

6 files changed

+345
-3
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
settings set auto-one-line-summaries false
2+
3+
target variable -T ClassWithPaddingInstance
4+
target variable -T ClassNoPaddingInstance
5+
target variable -T DC
6+
target variable -T EBOC
7+
target variable -T PBC
8+
9+
target variable -T UnnamedClassInstance
10+
11+
target variable -T PointersInstance
12+
target variable -T ReferencesInstance
13+
14+
quit
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
// clang-format off
2+
// REQUIRES: lld
3+
4+
// Test that we can display tag types.
5+
// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
6+
// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
7+
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
8+
// RUN: %p/Inputs/globals-classes.lldbinit | FileCheck %s
9+
10+
enum class EnumType : unsigned {
11+
A = 1,
12+
B = 2
13+
};
14+
15+
class ClassNoPadding {
16+
/* [ 0] */ unsigned char a = 86;
17+
/* [ 1] */ char b = 'a';
18+
/* [ 2] */ bool c = false;
19+
/* [ 3] */ bool d = true;
20+
/* [ 4] */ short e = -1234;
21+
/* [ 6] */ unsigned short f = 8123;
22+
/* [ 8] */ unsigned int g = 123908;
23+
/* [12] */ int h = -890234;
24+
/* [16] */ unsigned long i = 2908234;
25+
/* [20] */ long j = 7234890;
26+
/* [24] */ float k = 908234.12392;
27+
/* [28] */ EnumType l = EnumType::A;
28+
/* [32] */ double m = 23890.897423;
29+
/* [40] */ unsigned long long n = 23490782;
30+
/* [48] */ long long o = -923409823;
31+
/* [56] */ int p[5] = { 2, 3, 5, 8, 13 };
32+
};
33+
34+
class ClassWithPadding {
35+
/* [ 0] */ char a = '0';
36+
// char padding[1];
37+
/* [ 2] */ short b = 50;
38+
/* [ 4] */ char c[2] = { '0', '1' };
39+
// char padding[2];
40+
/* [ 8] */ int d = 100;
41+
/* [12] */ char e = '0';
42+
// char padding[3];
43+
/* [16] */ int f = 200;
44+
// char padding[4];
45+
/* [24] */ long long g = 300;
46+
/* [32] */ char h[3] = { '0', '1', '2' };
47+
// char padding[5];
48+
/* [40] */ long long i = 400;
49+
/* [48] */ char j[2] = { '0', '1' };
50+
// char padding[6];
51+
/* [56] */ long long k = 500;
52+
/* [64] */ char l = '0';
53+
// char padding[7];
54+
/* [72] */ long long m = 600;
55+
} ;
56+
57+
struct EmptyBase {};
58+
59+
template<typename T>
60+
struct BaseClass {
61+
constexpr BaseClass(int N)
62+
: BaseMember(N) {}
63+
64+
int BaseMember;
65+
};
66+
67+
struct DerivedClass : public BaseClass<int> {
68+
constexpr DerivedClass(int Base, int Derived)
69+
: BaseClass(Base), DerivedMember(Derived) {}
70+
71+
int DerivedMember;
72+
};
73+
74+
struct EBO : public EmptyBase {
75+
constexpr EBO(int N) : Member(N) {}
76+
int Member;
77+
};
78+
79+
struct PaddedBases : public BaseClass<char>, public BaseClass<short>, BaseClass<int> {
80+
constexpr PaddedBases(char CH, short S, int N, long long D)
81+
: BaseClass<char>(CH), BaseClass<short>(S), BaseClass<int>(N), DerivedMember(D) {}
82+
long long DerivedMember;
83+
};
84+
85+
struct Statics {
86+
static char a;
87+
static bool b;
88+
static short c;
89+
static unsigned short d;
90+
static unsigned int e;
91+
static int f;
92+
static unsigned long g;
93+
static long h;
94+
static float i;
95+
static EnumType j;
96+
static double k;
97+
static unsigned long long l;
98+
static long long m;
99+
};
100+
101+
char Statics::a = 'a';
102+
bool Statics::b = true;
103+
short Statics::c = 1234;
104+
unsigned short Statics::d = 2345;
105+
unsigned int Statics::e = 3456;
106+
int Statics::f = 4567;
107+
unsigned long Statics::g = 5678;
108+
long Statics::h = 6789;
109+
float Statics::i = 7890.1234;
110+
EnumType Statics::j = EnumType::A;
111+
double Statics::k = 8901.2345;
112+
unsigned long long Statics::l = 9012345;
113+
long long Statics::m = 1234567;
114+
115+
116+
struct Pointers {
117+
void *a = nullptr;
118+
char *b = &Statics::a;
119+
bool *c = &Statics::b;
120+
short *e = &Statics::c;
121+
unsigned short *f = &Statics::d;
122+
unsigned int *g = &Statics::e;
123+
int *h = &Statics::f;
124+
unsigned long *i = &Statics::g;
125+
long *j = &Statics::h;
126+
float *k = &Statics::i;
127+
EnumType *l = &Statics::j;
128+
double *m = &Statics::k;
129+
unsigned long long *n = &Statics::l;
130+
long long *o = &Statics::m;
131+
};
132+
133+
struct References {
134+
char &a = Statics::a;
135+
bool &b = Statics::b;
136+
short &c = Statics::c;
137+
unsigned short &d = Statics::d;
138+
unsigned int &e = Statics::e;
139+
int &f = Statics::f;
140+
unsigned long &g = Statics::g;
141+
long &h = Statics::h;
142+
float &i = Statics::i;
143+
EnumType &j = Statics::j;
144+
double &k = Statics::k;
145+
unsigned long long &l = Statics::l;
146+
long long &m = Statics::m;
147+
};
148+
149+
150+
constexpr ClassWithPadding ClassWithPaddingInstance;
151+
// CHECK: (lldb) target variable -T ClassWithPaddingInstance
152+
// CHECK-NEXT: (const ClassWithPadding) ClassWithPaddingInstance = {
153+
// CHECK-NEXT: (char) a = '0'
154+
// CHECK-NEXT: (short) b = 50
155+
// CHECK-NEXT: (char [2]) c = "01"
156+
// CHECK-NEXT: (int) d = 100
157+
// CHECK-NEXT: (char) e = '0'
158+
// CHECK-NEXT: (int) f = 200
159+
// CHECK-NEXT: (long long) g = 300
160+
// CHECK-NEXT: (char [3]) h = "012"
161+
// CHECK-NEXT: (long long) i = 400
162+
// CHECK-NEXT: (char [2]) j = "01"
163+
// CHECK-NEXT: (long long) k = 500
164+
// CHECK-NEXT: (char) l = '0'
165+
// CHECK-NEXT: (long long) m = 600
166+
// CHECK-NEXT: }
167+
168+
constexpr ClassNoPadding ClassNoPaddingInstance;
169+
// CHECK: (lldb) target variable -T ClassNoPaddingInstance
170+
// CHECK-NEXT: (const ClassNoPadding) ClassNoPaddingInstance = {
171+
// CHECK-NEXT: (unsigned char) a = 'V'
172+
// CHECK-NEXT: (char) b = 'a'
173+
// CHECK-NEXT: (bool) c = false
174+
// CHECK-NEXT: (bool) d = true
175+
// CHECK-NEXT: (short) e = -1234
176+
// CHECK-NEXT: (unsigned short) f = 8123
177+
// CHECK-NEXT: (unsigned int) g = 123908
178+
// CHECK-NEXT: (int) h = -890234
179+
// CHECK-NEXT: (unsigned long) i = 2908234
180+
// CHECK-NEXT: (long) j = 7234890
181+
// CHECK-NEXT: (float) k = 908234.125
182+
// CHECK-NEXT: (EnumType) l = A
183+
// CHECK-NEXT: (double) m = 23890.897422999999
184+
// CHECK-NEXT: (unsigned long long) n = 23490782
185+
// CHECK-NEXT: (long long) o = -923409823
186+
// CHECK-NEXT: (int [5]) p = {
187+
// CHECK-NEXT: (int) [0] = 2
188+
// CHECK-NEXT: (int) [1] = 3
189+
// CHECK-NEXT: (int) [2] = 5
190+
// CHECK-NEXT: (int) [3] = 8
191+
// CHECK-NEXT: (int) [4] = 13
192+
// CHECK-NEXT: }
193+
// CHECK-NEXT: }
194+
195+
constexpr DerivedClass DC(10, 20);
196+
// CHECK: (lldb) target variable -T DC
197+
// CHECK-NEXT: (const DerivedClass) DC = {
198+
// CHECK-NEXT: (BaseClass<int>) BaseClass<int> = {
199+
// CHECK-NEXT: (int) BaseMember = 10
200+
// CHECK-NEXT: }
201+
// CHECK-NEXT: (int) DerivedMember = 20
202+
// CHECK-NEXT: }
203+
204+
constexpr EBO EBOC(20);
205+
// CHECK: (lldb) target variable -T EBOC
206+
// CHECK-NEXT: (const EBO) EBOC = {
207+
// CHECK-NEXT: (int) Member = 20
208+
// CHECK-NEXT: }
209+
210+
constexpr PaddedBases PBC('a', 12, 120, 1200);
211+
// CHECK: (lldb) target variable -T PBC
212+
// CHECK-NEXT: (const PaddedBases) PBC = {
213+
// CHECK-NEXT: (BaseClass<char>) BaseClass<char> = {
214+
// CHECK-NEXT: (int) BaseMember = 97
215+
// CHECK-NEXT: }
216+
// CHECK-NEXT: (BaseClass<short>) BaseClass<short> = {
217+
// CHECK-NEXT: (int) BaseMember = 12
218+
// CHECK-NEXT: }
219+
// CHECK-NEXT: (BaseClass<int>) BaseClass<int> = {
220+
// CHECK-NEXT: (int) BaseMember = 120
221+
// CHECK-NEXT: }
222+
// CHECK-NEXT: (long long) DerivedMember = 1200
223+
// CHECK-NEXT: }
224+
225+
constexpr struct {
226+
int x = 12;
227+
EBO EBOC{ 42 };
228+
} UnnamedClassInstance;
229+
// CHECK: (lldb) target variable -T UnnamedClassInstance
230+
// CHECK-NEXT: (const <unnamed-type-UnnamedClassInstance>) UnnamedClassInstance = {
231+
// CHECK-NEXT: (int) x = 12
232+
// CHECK-NEXT: (EBO) EBOC = {
233+
// CHECK-NEXT: (int) Member = 42
234+
// CHECK-NEXT: }
235+
// CHECK-NEXT: }
236+
237+
constexpr Pointers PointersInstance;
238+
// CHECK: (lldb) target variable -T PointersInstance
239+
// CHECK-NEXT: (const Pointers) PointersInstance = {
240+
// CHECK-NEXT: (void *) a = {{.*}}
241+
// CHECK-NEXT: (char *) b = {{.*}}
242+
// CHECK-NEXT: (bool *) c = {{.*}}
243+
// CHECK-NEXT: (short *) e = {{.*}}
244+
// CHECK-NEXT: (unsigned short *) f = {{.*}}
245+
// CHECK-NEXT: (unsigned int *) g = {{.*}}
246+
// CHECK-NEXT: (int *) h = {{.*}}
247+
// CHECK-NEXT: (unsigned long *) i = {{.*}}
248+
// CHECK-NEXT: (long *) j = {{.*}}
249+
// CHECK-NEXT: (float *) k = {{.*}}
250+
// CHECK-NEXT: (EnumType *) l = {{.*}}
251+
// CHECK-NEXT: (double *) m = {{.*}}
252+
// CHECK-NEXT: (unsigned long long *) n = {{.*}}
253+
// CHECK-NEXT: (long long *) o = {{.*}}
254+
// CHECK-NEXT: }
255+
constexpr References ReferencesInstance;
256+
// CHECK: (lldb) target variable -T ReferencesInstance
257+
// CHECK-NEXT: (const References) ReferencesInstance = {
258+
// CHECK-NEXT: (char &) a = {{.*}}
259+
// CHECK-NEXT: (bool &) b = {{.*}}
260+
// CHECK-NEXT: (short &) c = {{.*}}
261+
// CHECK-NEXT: (unsigned short &) d = {{.*}}
262+
// CHECK-NEXT: (unsigned int &) e = {{.*}}
263+
// CHECK-NEXT: (int &) f = {{.*}}
264+
// CHECK-NEXT: (unsigned long &) g = {{.*}}
265+
// CHECK-NEXT: (long &) h = {{.*}}
266+
// CHECK-NEXT: (float &) i = {{.*}}
267+
// CHECK-NEXT: (EnumType &) j = {{.*}}
268+
// CHECK-NEXT: (double &) k = {{.*}}
269+
// CHECK-NEXT: (unsigned long long &) l = {{.*}}
270+
// CHECK-NEXT: (long long &) m = {{.*}}
271+
// CHECK-NEXT: }
272+
273+
int main(int argc, char **argv) {
274+
return 0;
275+
}

‎lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,13 @@ TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
343343
}
344344
}
345345

346+
TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
347+
lldbassert(modifier.kind() == LF_MODIFIER);
348+
ModifierRecord mr;
349+
llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
350+
return mr.ModifiedType;
351+
}
352+
346353
llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
347354
// Not all PDB names can be parsed with CPlusPlusNameParser.
348355
// E.g. it fails on names containing `anonymous namespace'.

‎lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ bool IsForwardRefUdt(llvm::codeview::CVType cvt);
5959

6060
lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access);
6161
llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt);
62+
llvm::codeview::TypeIndex
63+
LookThroughModifierRecord(llvm::codeview::CVType modifier);
6264

6365
llvm::StringRef DropNameScope(llvm::StringRef name);
6466

‎lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp

+45-3
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,7 @@ static PDB_SymType GetPdbSymType(TpiStream &tpi, TypeIndex ti) {
391391
// If this is an LF_MODIFIER, look through it to get the kind that it
392392
// modifies. Note that it's not possible to have an LF_MODIFIER that
393393
// modifies another LF_MODIFIER, although this would handle that anyway.
394-
ModifierRecord mr;
395-
llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mr));
396-
return GetPdbSymType(tpi, mr.ModifiedType);
394+
return GetPdbSymType(tpi, LookThroughModifierRecord(cvt));
397395
}
398396

399397
static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
@@ -775,6 +773,25 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
775773
lldb_private::Type::eResolveStateForward);
776774
}
777775

776+
TypeSP SymbolFileNativePDB::CreateArrayType(PdbSymUid type_uid,
777+
const ArrayRecord &ar) {
778+
TypeSP element_type = GetOrCreateType(ar.ElementType);
779+
uint64_t element_count = ar.Size / element_type->GetByteSize();
780+
781+
CompilerType element_ct = element_type->GetFullCompilerType();
782+
783+
CompilerType array_ct =
784+
m_clang->CreateArrayType(element_ct, element_count, false);
785+
786+
Declaration decl;
787+
TypeSP array_sp = std::make_shared<lldb_private::Type>(
788+
type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(), ar.Size,
789+
nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
790+
array_ct, lldb_private::Type::eResolveStateFull);
791+
array_sp->SetEncodingType(element_type.get());
792+
return array_sp;
793+
}
794+
778795
TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) {
779796
const PdbTypeSymId &tsid = type_uid.asTypeSym();
780797
TypeIndex index(tsid.index);
@@ -817,6 +834,12 @@ TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) {
817834
return CreateTagType(type_uid, ur);
818835
}
819836

837+
if (cvt.kind() == LF_ARRAY) {
838+
ArrayRecord ar;
839+
llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
840+
return CreateArrayType(type_uid, ar);
841+
}
842+
820843
return nullptr;
821844
}
822845

@@ -1442,6 +1465,25 @@ bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
14421465
auto types_iter = m_types.find(uid.toOpaqueId());
14431466
lldbassert(types_iter != m_types.end());
14441467

1468+
if (cvt.kind() == LF_MODIFIER) {
1469+
TypeIndex unmodified_type = LookThroughModifierRecord(cvt);
1470+
cvt = m_index->tpi().getType(unmodified_type);
1471+
// LF_MODIFIERS usually point to forward decls, so this is the one case
1472+
// where we won't have been able to resolve a forward decl to a full decl
1473+
// earlier on. So we need to do that now.
1474+
if (IsForwardRefUdt(cvt)) {
1475+
llvm::Expected<TypeIndex> expected_full_ti =
1476+
m_index->tpi().findFullDeclForForwardRef(unmodified_type);
1477+
if (!expected_full_ti) {
1478+
llvm::consumeError(expected_full_ti.takeError());
1479+
return false;
1480+
}
1481+
cvt = m_index->tpi().getType(*expected_full_ti);
1482+
lldbassert(!IsForwardRefUdt(cvt));
1483+
unmodified_type = *expected_full_ti;
1484+
}
1485+
uid = PdbSymUid::makeTypeSymId(uid.tag(), unmodified_type, false);
1486+
}
14451487
TypeIndex field_list_ti = GetFieldListIndex(cvt);
14461488
CVType field_list_cvt = m_index->tpi().getType(field_list_ti);
14471489
if (field_list_cvt.kind() != LF_FIELDLIST)

0 commit comments

Comments
 (0)
Please sign in to comment.