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