1 //===-- PdbUtil.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PdbUtil.h"
10 
11 #include "DWARFLocationExpression.h"
12 #include "PdbIndex.h"
13 #include "PdbSymUid.h"
14 
15 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
16 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
17 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
18 
19 #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
20 #include "lldb/Utility/LLDBAssert.h"
21 #include "lldb/lldb-enumerations.h"
22 
23 using namespace lldb_private;
24 using namespace lldb_private::npdb;
25 using namespace llvm::codeview;
26 using namespace llvm::pdb;
27 
28 static Variable::RangeList
29 MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,
30               llvm::ArrayRef<LocalVariableAddrGap> gaps) {
31   lldb::addr_t start =
32       index.MakeVirtualAddress(range.ISectStart, range.OffsetStart);
33   lldb::addr_t end = start + range.Range;
34 
35   Variable::RangeList result;
36   while (!gaps.empty()) {
37     const LocalVariableAddrGap &gap = gaps.front();
38 
39     lldb::addr_t size = gap.GapStartOffset - start;
40     result.Append(start, size);
41     start += gap.Range;
42     gaps = gaps.drop_front();
43   }
44 
45   result.Append(start, end);
46   return result;
47 }
48 
49 CVTagRecord CVTagRecord::create(CVType type) {
50   assert(IsTagRecord(type) && "type is not a tag record!");
51   switch (type.kind()) {
52   case LF_CLASS:
53   case LF_STRUCTURE:
54   case LF_INTERFACE: {
55     ClassRecord cr;
56     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));
57     return CVTagRecord(std::move(cr));
58   }
59   case LF_UNION: {
60     UnionRecord ur;
61     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));
62     return CVTagRecord(std::move(ur));
63   }
64   case LF_ENUM: {
65     EnumRecord er;
66     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));
67     return CVTagRecord(std::move(er));
68   }
69   default:
70     llvm_unreachable("Unreachable!");
71   }
72 }
73 
74 CVTagRecord::CVTagRecord(ClassRecord &&c)
75     : cvclass(std::move(c)),
76       m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}
77 CVTagRecord::CVTagRecord(UnionRecord &&u)
78     : cvunion(std::move(u)), m_kind(Union) {}
79 CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}
80 
81 PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
82   switch (kind) {
83   case S_COMPILE3:
84   case S_OBJNAME:
85     return PDB_SymType::CompilandDetails;
86   case S_ENVBLOCK:
87     return PDB_SymType::CompilandEnv;
88   case S_THUNK32:
89   case S_TRAMPOLINE:
90     return PDB_SymType::Thunk;
91   case S_COFFGROUP:
92     return PDB_SymType::CoffGroup;
93   case S_EXPORT:
94     return PDB_SymType::Export;
95   case S_LPROC32:
96   case S_GPROC32:
97   case S_LPROC32_DPC:
98     return PDB_SymType::Function;
99   case S_PUB32:
100     return PDB_SymType::PublicSymbol;
101   case S_INLINESITE:
102     return PDB_SymType::InlineSite;
103   case S_LOCAL:
104   case S_BPREL32:
105   case S_REGREL32:
106   case S_MANCONSTANT:
107   case S_CONSTANT:
108   case S_LDATA32:
109   case S_GDATA32:
110   case S_LMANDATA:
111   case S_GMANDATA:
112   case S_LTHREAD32:
113   case S_GTHREAD32:
114     return PDB_SymType::Data;
115   case S_BLOCK32:
116     return PDB_SymType::Block;
117   case S_LABEL32:
118     return PDB_SymType::Label;
119   case S_CALLSITEINFO:
120     return PDB_SymType::CallSite;
121   case S_HEAPALLOCSITE:
122     return PDB_SymType::HeapAllocationSite;
123   case S_CALLEES:
124     return PDB_SymType::Callee;
125   case S_CALLERS:
126     return PDB_SymType::Caller;
127   default:
128     lldbassert(false && "Invalid symbol record kind!");
129   }
130   return PDB_SymType::None;
131 }
132 
133 PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) {
134   switch (kind) {
135   case LF_ARRAY:
136     return PDB_SymType::ArrayType;
137   case LF_ARGLIST:
138     return PDB_SymType::FunctionSig;
139   case LF_BCLASS:
140     return PDB_SymType::BaseClass;
141   case LF_BINTERFACE:
142     return PDB_SymType::BaseInterface;
143   case LF_CLASS:
144   case LF_STRUCTURE:
145   case LF_INTERFACE:
146   case LF_UNION:
147     return PDB_SymType::UDT;
148   case LF_POINTER:
149     return PDB_SymType::PointerType;
150   case LF_ENUM:
151     return PDB_SymType::Enum;
152   case LF_PROCEDURE:
153     return PDB_SymType::FunctionSig;
154   case LF_BITFIELD:
155     return PDB_SymType::BuiltinType;
156   default:
157     lldbassert(false && "Invalid type record kind!");
158   }
159   return PDB_SymType::None;
160 }
161 
162 bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {
163   switch (sym.kind()) {
164   case S_GPROC32:
165   case S_LPROC32:
166   case S_GPROC32_ID:
167   case S_LPROC32_ID:
168   case S_LPROC32_DPC:
169   case S_LPROC32_DPC_ID:
170   case S_THUNK32:
171   case S_TRAMPOLINE:
172   case S_COFFGROUP:
173   case S_BLOCK32:
174   case S_LABEL32:
175   case S_CALLSITEINFO:
176   case S_HEAPALLOCSITE:
177   case S_LDATA32:
178   case S_GDATA32:
179   case S_LMANDATA:
180   case S_GMANDATA:
181   case S_LTHREAD32:
182   case S_GTHREAD32:
183     return true;
184   default:
185     return false;
186   }
187 }
188 
189 bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {
190   switch (sym.kind()) {
191   case S_GPROC32:
192   case S_LPROC32:
193   case S_GPROC32_ID:
194   case S_LPROC32_ID:
195   case S_LPROC32_DPC:
196   case S_LPROC32_DPC_ID:
197   case S_THUNK32:
198   case S_TRAMPOLINE:
199   case S_COFFGROUP:
200   case S_BLOCK32:
201     return true;
202   default:
203     return false;
204   }
205 }
206 
207 template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
208   RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
209   cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
210   return record;
211 }
212 
213 template <typename RecordT>
214 static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
215   RecordT record = createRecord<RecordT>(sym);
216   return {record.Segment, record.CodeOffset};
217 }
218 
219 template <>
220 SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
221   TrampolineSym record = createRecord<TrampolineSym>(sym);
222   return {record.ThunkSection, record.ThunkOffset};
223 }
224 
225 template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
226   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
227   return {record.Segment, record.Offset};
228 }
229 
230 template <>
231 SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
232   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
233   return {record.Segment, record.Offset};
234 }
235 
236 template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
237   DataSym record = createRecord<DataSym>(sym);
238   return {record.Segment, record.DataOffset};
239 }
240 
241 template <>
242 SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
243   ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
244   return {record.Segment, record.DataOffset};
245 }
246 
247 SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {
248   switch (sym.kind()) {
249   case S_GPROC32:
250   case S_LPROC32:
251   case S_GPROC32_ID:
252   case S_LPROC32_ID:
253   case S_LPROC32_DPC:
254   case S_LPROC32_DPC_ID:
255     return ::GetSegmentAndOffset<ProcSym>(sym);
256   case S_THUNK32:
257     return ::GetSegmentAndOffset<Thunk32Sym>(sym);
258     break;
259   case S_TRAMPOLINE:
260     return ::GetSegmentAndOffset<TrampolineSym>(sym);
261     break;
262   case S_COFFGROUP:
263     return ::GetSegmentAndOffset<CoffGroupSym>(sym);
264     break;
265   case S_BLOCK32:
266     return ::GetSegmentAndOffset<BlockSym>(sym);
267     break;
268   case S_LABEL32:
269     return ::GetSegmentAndOffset<LabelSym>(sym);
270     break;
271   case S_CALLSITEINFO:
272     return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
273     break;
274   case S_HEAPALLOCSITE:
275     return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
276     break;
277   case S_LDATA32:
278   case S_GDATA32:
279   case S_LMANDATA:
280   case S_GMANDATA:
281     return ::GetSegmentAndOffset<DataSym>(sym);
282     break;
283   case S_LTHREAD32:
284   case S_GTHREAD32:
285     return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
286     break;
287   default:
288     lldbassert(false && "Record does not have a segment/offset!");
289   }
290   return {0, 0};
291 }
292 
293 template <typename RecordT>
294 SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
295   RecordT record = createRecord<RecordT>(sym);
296   return {record.Segment, record.CodeOffset, record.CodeSize};
297 }
298 
299 template <>
300 SegmentOffsetLength
301 GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
302   TrampolineSym record = createRecord<TrampolineSym>(sym);
303   return {record.ThunkSection, record.ThunkOffset, record.Size};
304 }
305 
306 template <>
307 SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
308   Thunk32Sym record = createRecord<Thunk32Sym>(sym);
309   return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
310 }
311 
312 template <>
313 SegmentOffsetLength
314 GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
315   CoffGroupSym record = createRecord<CoffGroupSym>(sym);
316   return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
317 }
318 
319 SegmentOffsetLength
320 lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {
321   switch (sym.kind()) {
322   case S_GPROC32:
323   case S_LPROC32:
324   case S_GPROC32_ID:
325   case S_LPROC32_ID:
326   case S_LPROC32_DPC:
327   case S_LPROC32_DPC_ID:
328     return ::GetSegmentOffsetAndLength<ProcSym>(sym);
329   case S_THUNK32:
330     return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
331     break;
332   case S_TRAMPOLINE:
333     return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
334     break;
335   case S_COFFGROUP:
336     return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
337     break;
338   case S_BLOCK32:
339     return ::GetSegmentOffsetAndLength<BlockSym>(sym);
340     break;
341   default:
342     lldbassert(false && "Record does not have a segment/offset/length triple!");
343   }
344   return {0, 0, 0};
345 }
346 
347 bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {
348   ClassRecord cr;
349   UnionRecord ur;
350   EnumRecord er;
351   switch (cvt.kind()) {
352   case LF_CLASS:
353   case LF_STRUCTURE:
354   case LF_INTERFACE:
355     llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
356     return cr.isForwardRef();
357   case LF_UNION:
358     llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
359     return ur.isForwardRef();
360   case LF_ENUM:
361     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
362     return er.isForwardRef();
363   default:
364     return false;
365   }
366 }
367 
368 bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {
369   switch (cvt.kind()) {
370   case LF_CLASS:
371   case LF_STRUCTURE:
372   case LF_UNION:
373   case LF_ENUM:
374     return true;
375   default:
376     return false;
377   }
378 }
379 
380 bool lldb_private::npdb::IsClassStructUnion(llvm::codeview::CVType cvt) {
381   switch (cvt.kind()) {
382   case LF_CLASS:
383   case LF_STRUCTURE:
384   case LF_UNION:
385     return true;
386   default:
387     return false;
388   }
389 }
390 
391 bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id,
392                                          TpiStream &tpi) {
393   if (id.is_ipi || id.index.isSimple())
394     return false;
395   return IsForwardRefUdt(tpi.getType(id.index));
396 }
397 
398 bool lldb_private::npdb::IsTagRecord(const PdbTypeSymId &id, TpiStream &tpi) {
399   if (id.is_ipi || id.index.isSimple())
400     return false;
401   return IsTagRecord(tpi.getType(id.index));
402 }
403 
404 lldb::AccessType
405 lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
406   switch (access) {
407   case MemberAccess::Private:
408     return lldb::eAccessPrivate;
409   case MemberAccess::Protected:
410     return lldb::eAccessProtected;
411   case MemberAccess::Public:
412     return lldb::eAccessPublic;
413   case MemberAccess::None:
414     return lldb::eAccessNone;
415   }
416   llvm_unreachable("unreachable");
417 }
418 
419 TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
420   switch (cvt.kind()) {
421   case LF_CLASS:
422   case LF_STRUCTURE:
423   case LF_INTERFACE: {
424     ClassRecord cr;
425     cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
426     return cr.FieldList;
427   }
428   case LF_UNION: {
429     UnionRecord ur;
430     cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
431     return ur.FieldList;
432   }
433   case LF_ENUM: {
434     EnumRecord er;
435     cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
436     return er.FieldList;
437   }
438   default:
439     llvm_unreachable("Unreachable!");
440   }
441 }
442 
443 TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
444   lldbassert(modifier.kind() == LF_MODIFIER);
445   ModifierRecord mr;
446   llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
447   return mr.ModifiedType;
448 }
449 
450 llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
451   return MSVCUndecoratedNameParser::DropScope(name);
452 }
453 
454 VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
455   VariableInfo result;
456 
457   if (sym.kind() == S_REGREL32) {
458     RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
459     cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
460     result.type = reg.Type;
461     result.name = reg.Name;
462     return result;
463   }
464 
465   if (sym.kind() == S_REGISTER) {
466     RegisterSym reg(SymbolRecordKind::RegisterSym);
467     cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
468     result.type = reg.Index;
469     result.name = reg.Name;
470     return result;
471   }
472 
473   if (sym.kind() == S_LOCAL) {
474     LocalSym local(SymbolRecordKind::LocalSym);
475     cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
476     result.type = local.Type;
477     result.name = local.Name;
478     return result;
479   }
480 
481   if (sym.kind() == S_GDATA32 || sym.kind() == S_LDATA32) {
482     DataSym data(SymbolRecordKind::DataSym);
483     cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, data));
484     result.type = data.Type;
485     result.name = data.Name;
486     return result;
487   }
488 
489   if (sym.kind() == S_GTHREAD32 || sym.kind() == S_LTHREAD32) {
490     ThreadLocalDataSym data(SymbolRecordKind::ThreadLocalDataSym);
491     cantFail(SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, data));
492     result.type = data.Type;
493     result.name = data.Name;
494     return result;
495   }
496 
497   if (sym.kind() == S_CONSTANT) {
498     ConstantSym constant(SymbolRecordKind::ConstantSym);
499     cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym, constant));
500     result.type = constant.Type;
501     result.name = constant.Name;
502     return result;
503   }
504 
505   lldbassert(false && "Invalid variable record kind!");
506   return {};
507 }
508 
509 VariableInfo lldb_private::npdb::GetVariableLocationInfo(
510     PdbIndex &index, PdbCompilandSymId var_id, lldb::ModuleSP module) {
511 
512   CVSymbol sym = index.ReadSymbolRecord(var_id);
513 
514   VariableInfo result = GetVariableNameInfo(sym);
515 
516   if (sym.kind() == S_REGREL32) {
517     RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
518     cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
519     result.location =
520         MakeRegRelLocationExpression(reg.Register, reg.Offset, module);
521     result.ranges.emplace();
522     return result;
523   }
524 
525   if (sym.kind() == S_REGISTER) {
526     RegisterSym reg(SymbolRecordKind::RegisterSym);
527     cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
528     result.location = MakeEnregisteredLocationExpression(reg.Register, module);
529     result.ranges.emplace();
530     return result;
531   }
532 
533   if (sym.kind() == S_LOCAL) {
534     LocalSym local(SymbolRecordKind::LocalSym);
535     cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
536 
537     PdbCompilandSymId loc_specifier_id(var_id.modi,
538                                        var_id.offset + sym.RecordData.size());
539     CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);
540     if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) {
541       DefRangeFramePointerRelSym loc(
542           SymbolRecordKind::DefRangeFramePointerRelSym);
543       cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>(
544           loc_specifier_cvs, loc));
545       // FIXME: The register needs to come from the S_FRAMEPROC symbol.
546       result.location =
547           MakeRegRelLocationExpression(RegisterId::RSP, loc.Offset, module);
548       result.ranges = MakeRangeList(index, loc.Range, loc.Gaps);
549     } else {
550       // FIXME: Handle other kinds
551     }
552     return result;
553   }
554   llvm_unreachable("Symbol is not a local variable!");
555   return result;
556 }
557 
558 lldb::BasicType
559 lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
560   switch (kind) {
561   case SimpleTypeKind::Boolean128:
562   case SimpleTypeKind::Boolean16:
563   case SimpleTypeKind::Boolean32:
564   case SimpleTypeKind::Boolean64:
565   case SimpleTypeKind::Boolean8:
566     return lldb::eBasicTypeBool;
567   case SimpleTypeKind::Byte:
568   case SimpleTypeKind::UnsignedCharacter:
569     return lldb::eBasicTypeUnsignedChar;
570   case SimpleTypeKind::NarrowCharacter:
571     return lldb::eBasicTypeChar;
572   case SimpleTypeKind::SignedCharacter:
573   case SimpleTypeKind::SByte:
574     return lldb::eBasicTypeSignedChar;
575   case SimpleTypeKind::Character16:
576     return lldb::eBasicTypeChar16;
577   case SimpleTypeKind::Character32:
578     return lldb::eBasicTypeChar32;
579   case SimpleTypeKind::Complex80:
580     return lldb::eBasicTypeLongDoubleComplex;
581   case SimpleTypeKind::Complex64:
582     return lldb::eBasicTypeDoubleComplex;
583   case SimpleTypeKind::Complex32:
584     return lldb::eBasicTypeFloatComplex;
585   case SimpleTypeKind::Float128:
586   case SimpleTypeKind::Float80:
587     return lldb::eBasicTypeLongDouble;
588   case SimpleTypeKind::Float64:
589     return lldb::eBasicTypeDouble;
590   case SimpleTypeKind::Float32:
591     return lldb::eBasicTypeFloat;
592   case SimpleTypeKind::Float16:
593     return lldb::eBasicTypeHalf;
594   case SimpleTypeKind::Int128:
595     return lldb::eBasicTypeInt128;
596   case SimpleTypeKind::Int64:
597   case SimpleTypeKind::Int64Quad:
598     return lldb::eBasicTypeLongLong;
599   case SimpleTypeKind::Int32:
600     return lldb::eBasicTypeInt;
601   case SimpleTypeKind::Int16:
602   case SimpleTypeKind::Int16Short:
603     return lldb::eBasicTypeShort;
604   case SimpleTypeKind::UInt128:
605     return lldb::eBasicTypeUnsignedInt128;
606   case SimpleTypeKind::UInt64:
607   case SimpleTypeKind::UInt64Quad:
608     return lldb::eBasicTypeUnsignedLongLong;
609   case SimpleTypeKind::HResult:
610   case SimpleTypeKind::UInt32:
611     return lldb::eBasicTypeUnsignedInt;
612   case SimpleTypeKind::UInt16:
613   case SimpleTypeKind::UInt16Short:
614     return lldb::eBasicTypeUnsignedShort;
615   case SimpleTypeKind::Int32Long:
616     return lldb::eBasicTypeLong;
617   case SimpleTypeKind::UInt32Long:
618     return lldb::eBasicTypeUnsignedLong;
619   case SimpleTypeKind::Void:
620     return lldb::eBasicTypeVoid;
621   case SimpleTypeKind::WideCharacter:
622     return lldb::eBasicTypeWChar;
623   default:
624     return lldb::eBasicTypeInvalid;
625   }
626 }
627 
628 size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
629   switch (kind) {
630   case SimpleTypeKind::Boolean128:
631   case SimpleTypeKind::Int128:
632   case SimpleTypeKind::UInt128:
633   case SimpleTypeKind::Float128:
634     return 16;
635   case SimpleTypeKind::Complex80:
636   case SimpleTypeKind::Float80:
637     return 10;
638   case SimpleTypeKind::Boolean64:
639   case SimpleTypeKind::Complex64:
640   case SimpleTypeKind::UInt64:
641   case SimpleTypeKind::UInt64Quad:
642   case SimpleTypeKind::Float64:
643   case SimpleTypeKind::Int64:
644   case SimpleTypeKind::Int64Quad:
645     return 8;
646   case SimpleTypeKind::Boolean32:
647   case SimpleTypeKind::Character32:
648   case SimpleTypeKind::Complex32:
649   case SimpleTypeKind::Float32:
650   case SimpleTypeKind::Int32:
651   case SimpleTypeKind::Int32Long:
652   case SimpleTypeKind::UInt32Long:
653   case SimpleTypeKind::HResult:
654   case SimpleTypeKind::UInt32:
655     return 4;
656   case SimpleTypeKind::Boolean16:
657   case SimpleTypeKind::Character16:
658   case SimpleTypeKind::Float16:
659   case SimpleTypeKind::Int16:
660   case SimpleTypeKind::Int16Short:
661   case SimpleTypeKind::UInt16:
662   case SimpleTypeKind::UInt16Short:
663   case SimpleTypeKind::WideCharacter:
664     return 2;
665   case SimpleTypeKind::Boolean8:
666   case SimpleTypeKind::Byte:
667   case SimpleTypeKind::UnsignedCharacter:
668   case SimpleTypeKind::NarrowCharacter:
669   case SimpleTypeKind::SignedCharacter:
670   case SimpleTypeKind::SByte:
671     return 1;
672   case SimpleTypeKind::Void:
673   default:
674     return 0;
675   }
676 }
677 
678 PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id,
679                                                      TpiStream &tpi) {
680   if (id.index.isSimple())
681     return id;
682 
683   CVType cvt = tpi.getType(id.index);
684 
685   // Only tag records have a best and a worst record.
686   if (!IsTagRecord(cvt))
687     return id;
688 
689   // Tag records that are not forward decls are full decls, hence they are the
690   // best.
691   if (!IsForwardRefUdt(cvt))
692     return id;
693 
694   return llvm::cantFail(tpi.findFullDeclForForwardRef(id.index));
695 }
696 
697 template <typename RecordType> static size_t GetSizeOfTypeInternal(CVType cvt) {
698   RecordType record;
699   llvm::cantFail(TypeDeserializer::deserializeAs<RecordType>(cvt, record));
700   return record.getSize();
701 }
702 
703 size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id,
704                                          llvm::pdb::TpiStream &tpi) {
705   if (id.index.isSimple()) {
706     switch (id.index.getSimpleMode()) {
707     case SimpleTypeMode::Direct:
708       return GetTypeSizeForSimpleKind(id.index.getSimpleKind());
709     case SimpleTypeMode::NearPointer32:
710     case SimpleTypeMode::FarPointer32:
711       return 4;
712     case SimpleTypeMode::NearPointer64:
713       return 8;
714     case SimpleTypeMode::NearPointer128:
715       return 16;
716     default:
717       break;
718     }
719     return 0;
720   }
721 
722   TypeIndex index = id.index;
723   if (IsForwardRefUdt(index, tpi))
724     index = llvm::cantFail(tpi.findFullDeclForForwardRef(index));
725 
726   CVType cvt = tpi.getType(index);
727   switch (cvt.kind()) {
728   case LF_MODIFIER:
729     return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi);
730   case LF_ENUM: {
731     EnumRecord record;
732     llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, record));
733     return GetSizeOfType({record.UnderlyingType}, tpi);
734   }
735   case LF_POINTER:
736     return GetSizeOfTypeInternal<PointerRecord>(cvt);
737   case LF_ARRAY:
738     return GetSizeOfTypeInternal<ArrayRecord>(cvt);
739   case LF_CLASS:
740   case LF_STRUCTURE:
741   case LF_INTERFACE:
742     return GetSizeOfTypeInternal<ClassRecord>(cvt);
743   case LF_UNION:
744     return GetSizeOfTypeInternal<UnionRecord>(cvt);
745   default:
746     break;
747   }
748   return 0;
749 }
750