1 //===-- PdbUtil.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PdbUtil.h"
11 #include "PdbSymUid.h"
12 
13 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
14 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
15 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
16 
17 #include "lldb/Utility/LLDBAssert.h"
18 
19 #include "lldb/lldb-enumerations.h"
20 
21 using namespace lldb_private;
22 using namespace lldb_private::npdb;
23 using namespace llvm::codeview;
24 using namespace llvm::pdb;
25 
26 CVTagRecord CVTagRecord::create(CVType type) {
27   assert(IsTagRecord(type) && "type is not a tag record!");
28   switch (type.kind()) {
29   case LF_CLASS:
30   case LF_STRUCTURE:
31   case LF_INTERFACE: {
32     ClassRecord cr;
33     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));
34     return CVTagRecord(std::move(cr));
35   }
36   case LF_UNION: {
37     UnionRecord ur;
38     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));
39     return CVTagRecord(std::move(ur));
40   }
41   case LF_ENUM: {
42     EnumRecord er;
43     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));
44     return CVTagRecord(std::move(er));
45   }
46   default:
47     llvm_unreachable("Unreachable!");
48   }
49 }
50 
51 CVTagRecord::CVTagRecord(ClassRecord &&c)
52     : cvclass(std::move(c)),
53       m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}
54 CVTagRecord::CVTagRecord(UnionRecord &&u)
55     : cvunion(std::move(u)), m_kind(Union) {}
56 CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}
57 
58 PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
59   switch (kind) {
60   case S_COMPILE3:
61   case S_OBJNAME:
62     return PDB_SymType::CompilandDetails;
63   case S_ENVBLOCK:
64     return PDB_SymType::CompilandEnv;
65   case S_THUNK32:
66   case S_TRAMPOLINE:
67     return PDB_SymType::Thunk;
68   case S_COFFGROUP:
69     return PDB_SymType::CoffGroup;
70   case S_EXPORT:
71     return PDB_SymType::Export;
72   case S_LPROC32:
73   case S_GPROC32:
74   case S_LPROC32_DPC:
75     return PDB_SymType::Function;
76   case S_PUB32:
77     return PDB_SymType::PublicSymbol;
78   case S_INLINESITE:
79     return PDB_SymType::InlineSite;
80   case S_LOCAL:
81   case S_BPREL32:
82   case S_REGREL32:
83   case S_MANCONSTANT:
84   case S_CONSTANT:
85   case S_LDATA32:
86   case S_GDATA32:
87   case S_LMANDATA:
88   case S_GMANDATA:
89   case S_LTHREAD32:
90   case S_GTHREAD32:
91     return PDB_SymType::Data;
92   case S_BLOCK32:
93     return PDB_SymType::Block;
94   case S_LABEL32:
95     return PDB_SymType::Label;
96   case S_CALLSITEINFO:
97     return PDB_SymType::CallSite;
98   case S_HEAPALLOCSITE:
99     return PDB_SymType::HeapAllocationSite;
100   case S_CALLEES:
101     return PDB_SymType::Callee;
102   case S_CALLERS:
103     return PDB_SymType::Caller;
104   default:
105     lldbassert(false && "Invalid symbol record kind!");
106   }
107   return PDB_SymType::None;
108 }
109 
110 PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) {
111   switch (kind) {
112   case LF_ARRAY:
113     return PDB_SymType::ArrayType;
114   case LF_ARGLIST:
115     return PDB_SymType::FunctionSig;
116   case LF_BCLASS:
117     return PDB_SymType::BaseClass;
118   case LF_BINTERFACE:
119     return PDB_SymType::BaseInterface;
120   case LF_CLASS:
121   case LF_STRUCTURE:
122   case LF_INTERFACE:
123   case LF_UNION:
124     return PDB_SymType::UDT;
125   case LF_POINTER:
126     return PDB_SymType::PointerType;
127   case LF_ENUM:
128     return PDB_SymType::Enum;
129   case LF_PROCEDURE:
130     return PDB_SymType::FunctionSig;
131   case LF_BITFIELD:
132     return PDB_SymType::BuiltinType;
133   default:
134     lldbassert(false && "Invalid type record kind!");
135   }
136   return PDB_SymType::None;
137 }
138 
139 bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {
140   switch (sym.kind()) {
141   case S_GPROC32:
142   case S_LPROC32:
143   case S_GPROC32_ID:
144   case S_LPROC32_ID:
145   case S_LPROC32_DPC:
146   case S_LPROC32_DPC_ID:
147   case S_THUNK32:
148   case S_TRAMPOLINE:
149   case S_COFFGROUP:
150   case S_BLOCK32:
151   case S_LABEL32:
152   case S_CALLSITEINFO:
153   case S_HEAPALLOCSITE:
154   case S_LDATA32:
155   case S_GDATA32:
156   case S_LMANDATA:
157   case S_GMANDATA:
158   case S_LTHREAD32:
159   case S_GTHREAD32:
160     return true;
161   default:
162     return false;
163   }
164 }
165 
166 bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {
167   switch (sym.kind()) {
168   case S_GPROC32:
169   case S_LPROC32:
170   case S_GPROC32_ID:
171   case S_LPROC32_ID:
172   case S_LPROC32_DPC:
173   case S_LPROC32_DPC_ID:
174   case S_THUNK32:
175   case S_TRAMPOLINE:
176   case S_COFFGROUP:
177   case S_BLOCK32:
178     return true;
179   default:
180     return false;
181   }
182 }
183 
184 template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
185   RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
186   cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
187   return record;
188 }
189 
190 template <typename RecordT>
191 static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
192   RecordT record = createRecord<RecordT>(sym);
193   return {record.Segment, record.CodeOffset};
194 }
195 
196 template <>
197 SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
198   TrampolineSym record = createRecord<TrampolineSym>(sym);
199   return {record.ThunkSection, record.ThunkOffset};
200 }
201 
202 template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
203   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
204   return {record.Segment, record.Offset};
205 }
206 
207 template <>
208 SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
209   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
210   return {record.Segment, record.Offset};
211 }
212 
213 template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
214   DataSym record = createRecord<DataSym>(sym);
215   return {record.Segment, record.DataOffset};
216 }
217 
218 template <>
219 SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
220   ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
221   return {record.Segment, record.DataOffset};
222 }
223 
224 SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {
225   switch (sym.kind()) {
226   case S_GPROC32:
227   case S_LPROC32:
228   case S_GPROC32_ID:
229   case S_LPROC32_ID:
230   case S_LPROC32_DPC:
231   case S_LPROC32_DPC_ID:
232     return ::GetSegmentAndOffset<ProcSym>(sym);
233   case S_THUNK32:
234     return ::GetSegmentAndOffset<Thunk32Sym>(sym);
235     break;
236   case S_TRAMPOLINE:
237     return ::GetSegmentAndOffset<TrampolineSym>(sym);
238     break;
239   case S_COFFGROUP:
240     return ::GetSegmentAndOffset<CoffGroupSym>(sym);
241     break;
242   case S_BLOCK32:
243     return ::GetSegmentAndOffset<BlockSym>(sym);
244     break;
245   case S_LABEL32:
246     return ::GetSegmentAndOffset<LabelSym>(sym);
247     break;
248   case S_CALLSITEINFO:
249     return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
250     break;
251   case S_HEAPALLOCSITE:
252     return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
253     break;
254   case S_LDATA32:
255   case S_GDATA32:
256   case S_LMANDATA:
257   case S_GMANDATA:
258     return ::GetSegmentAndOffset<DataSym>(sym);
259     break;
260   case S_LTHREAD32:
261   case S_GTHREAD32:
262     return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
263     break;
264   default:
265     lldbassert(false && "Record does not have a segment/offset!");
266   }
267   return {0, 0};
268 }
269 
270 template <typename RecordT>
271 SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
272   RecordT record = createRecord<RecordT>(sym);
273   return {record.Segment, record.CodeOffset, record.CodeSize};
274 }
275 
276 template <>
277 SegmentOffsetLength
278 GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
279   TrampolineSym record = createRecord<TrampolineSym>(sym);
280   return {record.ThunkSection, record.ThunkOffset, record.Size};
281 }
282 
283 template <>
284 SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
285   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
286   return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
287 }
288 
289 template <>
290 SegmentOffsetLength
291 GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
292   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
293   return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
294 }
295 
296 SegmentOffsetLength
297 lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {
298   switch (sym.kind()) {
299   case S_GPROC32:
300   case S_LPROC32:
301   case S_GPROC32_ID:
302   case S_LPROC32_ID:
303   case S_LPROC32_DPC:
304   case S_LPROC32_DPC_ID:
305     return ::GetSegmentOffsetAndLength<ProcSym>(sym);
306   case S_THUNK32:
307     return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
308     break;
309   case S_TRAMPOLINE:
310     return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
311     break;
312   case S_COFFGROUP:
313     return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
314     break;
315   case S_BLOCK32:
316     return ::GetSegmentOffsetAndLength<BlockSym>(sym);
317     break;
318   default:
319     lldbassert(false && "Record does not have a segment/offset/length triple!");
320   }
321   return {0, 0, 0};
322 }
323 
324 bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {
325   ClassRecord cr;
326   UnionRecord ur;
327   EnumRecord er;
328   switch (cvt.kind()) {
329   case LF_CLASS:
330   case LF_STRUCTURE:
331   case LF_INTERFACE:
332     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
333     return cr.isForwardRef();
334   case LF_UNION:
335     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
336     return ur.isForwardRef();
337   case LF_ENUM:
338     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
339     return er.isForwardRef();
340   default:
341     return false;
342   }
343 }
344 
345 bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {
346   switch (cvt.kind()) {
347   case LF_CLASS:
348   case LF_STRUCTURE:
349   case LF_UNION:
350   case LF_ENUM:
351     return true;
352   default:
353     return false;
354   }
355 }
356 
357 bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id,
358                                          TpiStream &tpi) {
359   if (id.is_ipi || id.index.isSimple())
360     return false;
361   return IsForwardRefUdt(tpi.getType(id.index));
362 }
363 
364 bool lldb_private::npdb::IsTagRecord(const PdbTypeSymId &id, TpiStream &tpi) {
365   if (id.is_ipi || id.index.isSimple())
366     return false;
367   return IsTagRecord(tpi.getType(id.index));
368 }
369 
370 lldb::AccessType
371 lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
372   switch (access) {
373   case MemberAccess::Private:
374     return lldb::eAccessPrivate;
375   case MemberAccess::Protected:
376     return lldb::eAccessProtected;
377   case MemberAccess::Public:
378     return lldb::eAccessPublic;
379   case MemberAccess::None:
380     return lldb::eAccessNone;
381   }
382   llvm_unreachable("unreachable");
383 }
384 
385 TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
386   switch (cvt.kind()) {
387   case LF_CLASS:
388   case LF_STRUCTURE:
389   case LF_INTERFACE: {
390     ClassRecord cr;
391     cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
392     return cr.FieldList;
393   }
394   case LF_UNION: {
395     UnionRecord ur;
396     cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
397     return ur.FieldList;
398   }
399   case LF_ENUM: {
400     EnumRecord er;
401     cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
402     return er.FieldList;
403   }
404   default:
405     llvm_unreachable("Unreachable!");
406   }
407 }
408 
409 TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
410   lldbassert(modifier.kind() == LF_MODIFIER);
411   ModifierRecord mr;
412   llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
413   return mr.ModifiedType;
414 }
415 
416 llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
417   // Not all PDB names can be parsed with CPlusPlusNameParser.
418   // E.g. it fails on names containing `anonymous namespace'.
419   // So we simply drop everything before '::'
420 
421   auto offset = name.rfind("::");
422   if (offset == llvm::StringRef::npos)
423     return name;
424   assert(offset + 2 <= name.size());
425 
426   return name.substr(offset + 2);
427 }
428