109467b48Spatrick //===- RecordName.cpp ----------------------------------------- *- C++ --*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick
909467b48Spatrick #include "llvm/DebugInfo/CodeView/RecordName.h"
1009467b48Spatrick
1109467b48Spatrick #include "llvm/ADT/SmallString.h"
1273471bf0Spatrick #include "llvm/ADT/StringExtras.h"
1309467b48Spatrick #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
14*d415bd75Srobert #include "llvm/DebugInfo/CodeView/CodeView.h"
15*d415bd75Srobert #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
1609467b48Spatrick #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h"
17*d415bd75Srobert #include "llvm/DebugInfo/CodeView/TypeCollection.h"
18*d415bd75Srobert #include "llvm/DebugInfo/CodeView/TypeIndex.h"
19*d415bd75Srobert #include "llvm/DebugInfo/CodeView/TypeRecord.h"
2009467b48Spatrick #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
2109467b48Spatrick #include "llvm/Support/FormatVariadic.h"
2209467b48Spatrick
2309467b48Spatrick using namespace llvm;
2409467b48Spatrick using namespace llvm::codeview;
2509467b48Spatrick
2609467b48Spatrick namespace {
2709467b48Spatrick class TypeNameComputer : public TypeVisitorCallbacks {
2809467b48Spatrick /// The type collection. Used to calculate names of nested types.
2909467b48Spatrick TypeCollection &Types;
3009467b48Spatrick TypeIndex CurrentTypeIndex = TypeIndex::None();
3109467b48Spatrick
3209467b48Spatrick /// Name of the current type. Only valid before visitTypeEnd.
3309467b48Spatrick SmallString<256> Name;
3409467b48Spatrick
3509467b48Spatrick public:
TypeNameComputer(TypeCollection & Types)3609467b48Spatrick explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {}
3709467b48Spatrick
name() const3809467b48Spatrick StringRef name() const { return Name; }
3909467b48Spatrick
4009467b48Spatrick /// Paired begin/end actions for all types. Receives all record data,
4109467b48Spatrick /// including the fixed-length record prefix.
4209467b48Spatrick Error visitTypeBegin(CVType &Record) override;
4309467b48Spatrick Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
4409467b48Spatrick Error visitTypeEnd(CVType &Record) override;
4509467b48Spatrick
4609467b48Spatrick #define TYPE_RECORD(EnumName, EnumVal, Name) \
4709467b48Spatrick Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
4809467b48Spatrick #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
4909467b48Spatrick #define MEMBER_RECORD(EnumName, EnumVal, Name)
5009467b48Spatrick #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
5109467b48Spatrick };
5209467b48Spatrick } // namespace
5309467b48Spatrick
visitTypeBegin(CVType & Record)5409467b48Spatrick Error TypeNameComputer::visitTypeBegin(CVType &Record) {
5509467b48Spatrick llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
5609467b48Spatrick return Error::success();
5709467b48Spatrick }
5809467b48Spatrick
visitTypeBegin(CVType & Record,TypeIndex Index)5909467b48Spatrick Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) {
6009467b48Spatrick // Reset Name to the empty string. If the visitor sets it, we know it.
6109467b48Spatrick Name = "";
6209467b48Spatrick CurrentTypeIndex = Index;
6309467b48Spatrick return Error::success();
6409467b48Spatrick }
6509467b48Spatrick
visitTypeEnd(CVType & CVR)6609467b48Spatrick Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
6709467b48Spatrick
visitKnownRecord(CVType & CVR,FieldListRecord & FieldList)6809467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
6909467b48Spatrick FieldListRecord &FieldList) {
7009467b48Spatrick Name = "<field list>";
7109467b48Spatrick return Error::success();
7209467b48Spatrick }
7309467b48Spatrick
visitKnownRecord(CVRecord<TypeLeafKind> & CVR,StringIdRecord & String)7409467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
7509467b48Spatrick StringIdRecord &String) {
7609467b48Spatrick Name = String.getString();
7709467b48Spatrick return Error::success();
7809467b48Spatrick }
7909467b48Spatrick
visitKnownRecord(CVType & CVR,ArgListRecord & Args)8009467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
8109467b48Spatrick auto Indices = Args.getIndices();
8209467b48Spatrick uint32_t Size = Indices.size();
8309467b48Spatrick Name = "(";
8409467b48Spatrick for (uint32_t I = 0; I < Size; ++I) {
8573471bf0Spatrick if (Indices[I] < CurrentTypeIndex)
8609467b48Spatrick Name.append(Types.getTypeName(Indices[I]));
8773471bf0Spatrick else
8873471bf0Spatrick Name.append("<unknown 0x" + utohexstr(Indices[I].getIndex()) + ">");
8909467b48Spatrick if (I + 1 != Size)
9009467b48Spatrick Name.append(", ");
9109467b48Spatrick }
9209467b48Spatrick Name.push_back(')');
9309467b48Spatrick return Error::success();
9409467b48Spatrick }
9509467b48Spatrick
visitKnownRecord(CVType & CVR,StringListRecord & Strings)9609467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
9709467b48Spatrick StringListRecord &Strings) {
9809467b48Spatrick auto Indices = Strings.getIndices();
9909467b48Spatrick uint32_t Size = Indices.size();
10009467b48Spatrick Name = "\"";
10109467b48Spatrick for (uint32_t I = 0; I < Size; ++I) {
10209467b48Spatrick Name.append(Types.getTypeName(Indices[I]));
10309467b48Spatrick if (I + 1 != Size)
10409467b48Spatrick Name.append("\" \"");
10509467b48Spatrick }
10609467b48Spatrick Name.push_back('\"');
10709467b48Spatrick return Error::success();
10809467b48Spatrick }
10909467b48Spatrick
visitKnownRecord(CVType & CVR,ClassRecord & Class)11009467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
11109467b48Spatrick Name = Class.getName();
11209467b48Spatrick return Error::success();
11309467b48Spatrick }
11409467b48Spatrick
visitKnownRecord(CVType & CVR,UnionRecord & Union)11509467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
11609467b48Spatrick Name = Union.getName();
11709467b48Spatrick return Error::success();
11809467b48Spatrick }
11909467b48Spatrick
visitKnownRecord(CVType & CVR,EnumRecord & Enum)12009467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
12109467b48Spatrick Name = Enum.getName();
12209467b48Spatrick return Error::success();
12309467b48Spatrick }
12409467b48Spatrick
visitKnownRecord(CVType & CVR,ArrayRecord & AT)12509467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
12609467b48Spatrick Name = AT.getName();
12709467b48Spatrick return Error::success();
12809467b48Spatrick }
12909467b48Spatrick
visitKnownRecord(CVType & CVR,VFTableRecord & VFT)13009467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
13109467b48Spatrick Name = VFT.getName();
13209467b48Spatrick return Error::success();
13309467b48Spatrick }
13409467b48Spatrick
visitKnownRecord(CVType & CVR,MemberFuncIdRecord & Id)13509467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
13609467b48Spatrick Name = Id.getName();
13709467b48Spatrick return Error::success();
13809467b48Spatrick }
13909467b48Spatrick
visitKnownRecord(CVType & CVR,ProcedureRecord & Proc)14009467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
14109467b48Spatrick StringRef Ret = Types.getTypeName(Proc.getReturnType());
14209467b48Spatrick StringRef Params = Types.getTypeName(Proc.getArgumentList());
14309467b48Spatrick Name = formatv("{0} {1}", Ret, Params).sstr<256>();
14409467b48Spatrick return Error::success();
14509467b48Spatrick }
14609467b48Spatrick
visitKnownRecord(CVType & CVR,MemberFunctionRecord & MF)14709467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
14809467b48Spatrick MemberFunctionRecord &MF) {
14909467b48Spatrick StringRef Ret = Types.getTypeName(MF.getReturnType());
15009467b48Spatrick StringRef Class = Types.getTypeName(MF.getClassType());
15109467b48Spatrick StringRef Params = Types.getTypeName(MF.getArgumentList());
15209467b48Spatrick Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>();
15309467b48Spatrick return Error::success();
15409467b48Spatrick }
15509467b48Spatrick
visitKnownRecord(CVType & CVR,FuncIdRecord & Func)15609467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
15709467b48Spatrick Name = Func.getName();
15809467b48Spatrick return Error::success();
15909467b48Spatrick }
16009467b48Spatrick
visitKnownRecord(CVType & CVR,TypeServer2Record & TS)16109467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
16209467b48Spatrick Name = TS.getName();
16309467b48Spatrick return Error::success();
16409467b48Spatrick }
16509467b48Spatrick
visitKnownRecord(CVType & CVR,PointerRecord & Ptr)16609467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
16709467b48Spatrick
16809467b48Spatrick if (Ptr.isPointerToMember()) {
16909467b48Spatrick const MemberPointerInfo &MI = Ptr.getMemberInfo();
17009467b48Spatrick
17109467b48Spatrick StringRef Pointee = Types.getTypeName(Ptr.getReferentType());
17209467b48Spatrick StringRef Class = Types.getTypeName(MI.getContainingType());
17309467b48Spatrick Name = formatv("{0} {1}::*", Pointee, Class);
17409467b48Spatrick } else {
17509467b48Spatrick Name.append(Types.getTypeName(Ptr.getReferentType()));
17609467b48Spatrick
17709467b48Spatrick if (Ptr.getMode() == PointerMode::LValueReference)
17809467b48Spatrick Name.append("&");
17909467b48Spatrick else if (Ptr.getMode() == PointerMode::RValueReference)
18009467b48Spatrick Name.append("&&");
18109467b48Spatrick else if (Ptr.getMode() == PointerMode::Pointer)
18209467b48Spatrick Name.append("*");
18309467b48Spatrick
18409467b48Spatrick // Qualifiers in pointer records apply to the pointer, not the pointee, so
18509467b48Spatrick // they go on the right.
18609467b48Spatrick if (Ptr.isConst())
18709467b48Spatrick Name.append(" const");
18809467b48Spatrick if (Ptr.isVolatile())
18909467b48Spatrick Name.append(" volatile");
19009467b48Spatrick if (Ptr.isUnaligned())
19109467b48Spatrick Name.append(" __unaligned");
19209467b48Spatrick if (Ptr.isRestrict())
19309467b48Spatrick Name.append(" __restrict");
19409467b48Spatrick }
19509467b48Spatrick return Error::success();
19609467b48Spatrick }
19709467b48Spatrick
visitKnownRecord(CVType & CVR,ModifierRecord & Mod)19809467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
19909467b48Spatrick uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
20009467b48Spatrick
20109467b48Spatrick if (Mods & uint16_t(ModifierOptions::Const))
20209467b48Spatrick Name.append("const ");
20309467b48Spatrick if (Mods & uint16_t(ModifierOptions::Volatile))
20409467b48Spatrick Name.append("volatile ");
20509467b48Spatrick if (Mods & uint16_t(ModifierOptions::Unaligned))
20609467b48Spatrick Name.append("__unaligned ");
20709467b48Spatrick Name.append(Types.getTypeName(Mod.getModifiedType()));
20809467b48Spatrick return Error::success();
20909467b48Spatrick }
21009467b48Spatrick
visitKnownRecord(CVType & CVR,VFTableShapeRecord & Shape)21109467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
21209467b48Spatrick VFTableShapeRecord &Shape) {
21309467b48Spatrick Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
21409467b48Spatrick return Error::success();
21509467b48Spatrick }
21609467b48Spatrick
visitKnownRecord(CVType & CVR,UdtModSourceLineRecord & ModSourceLine)21709467b48Spatrick Error TypeNameComputer::visitKnownRecord(
21809467b48Spatrick CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
21909467b48Spatrick return Error::success();
22009467b48Spatrick }
22109467b48Spatrick
visitKnownRecord(CVType & CVR,UdtSourceLineRecord & SourceLine)22209467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
22309467b48Spatrick UdtSourceLineRecord &SourceLine) {
22409467b48Spatrick return Error::success();
22509467b48Spatrick }
22609467b48Spatrick
visitKnownRecord(CVType & CVR,BitFieldRecord & BF)22709467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
22809467b48Spatrick return Error::success();
22909467b48Spatrick }
23009467b48Spatrick
visitKnownRecord(CVType & CVR,MethodOverloadListRecord & Overloads)23109467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
23209467b48Spatrick MethodOverloadListRecord &Overloads) {
23309467b48Spatrick return Error::success();
23409467b48Spatrick }
23509467b48Spatrick
visitKnownRecord(CVType & CVR,BuildInfoRecord & BI)23609467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
23709467b48Spatrick return Error::success();
23809467b48Spatrick }
23909467b48Spatrick
visitKnownRecord(CVType & CVR,LabelRecord & R)24009467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
24109467b48Spatrick return Error::success();
24209467b48Spatrick }
24309467b48Spatrick
visitKnownRecord(CVType & CVR,PrecompRecord & Precomp)24409467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
24509467b48Spatrick PrecompRecord &Precomp) {
24609467b48Spatrick return Error::success();
24709467b48Spatrick }
24809467b48Spatrick
visitKnownRecord(CVType & CVR,EndPrecompRecord & EndPrecomp)24909467b48Spatrick Error TypeNameComputer::visitKnownRecord(CVType &CVR,
25009467b48Spatrick EndPrecompRecord &EndPrecomp) {
25109467b48Spatrick return Error::success();
25209467b48Spatrick }
25309467b48Spatrick
computeTypeName(TypeCollection & Types,TypeIndex Index)25409467b48Spatrick std::string llvm::codeview::computeTypeName(TypeCollection &Types,
25509467b48Spatrick TypeIndex Index) {
25609467b48Spatrick TypeNameComputer Computer(Types);
25709467b48Spatrick CVType Record = Types.getType(Index);
25809467b48Spatrick if (auto EC = visitTypeRecord(Record, Index, Computer)) {
25909467b48Spatrick consumeError(std::move(EC));
26009467b48Spatrick return "<unknown UDT>";
26109467b48Spatrick }
262097a140dSpatrick return std::string(Computer.name());
26309467b48Spatrick }
26409467b48Spatrick
getSymbolNameOffset(CVSymbol Sym)26509467b48Spatrick static int getSymbolNameOffset(CVSymbol Sym) {
26609467b48Spatrick switch (Sym.kind()) {
26709467b48Spatrick // See ProcSym
26809467b48Spatrick case SymbolKind::S_GPROC32:
26909467b48Spatrick case SymbolKind::S_LPROC32:
27009467b48Spatrick case SymbolKind::S_GPROC32_ID:
27109467b48Spatrick case SymbolKind::S_LPROC32_ID:
27209467b48Spatrick case SymbolKind::S_LPROC32_DPC:
27309467b48Spatrick case SymbolKind::S_LPROC32_DPC_ID:
27409467b48Spatrick return 35;
27509467b48Spatrick // See Thunk32Sym
27609467b48Spatrick case SymbolKind::S_THUNK32:
27709467b48Spatrick return 21;
27809467b48Spatrick // See SectionSym
27909467b48Spatrick case SymbolKind::S_SECTION:
28009467b48Spatrick return 16;
28109467b48Spatrick // See CoffGroupSym
28209467b48Spatrick case SymbolKind::S_COFFGROUP:
28309467b48Spatrick return 14;
28409467b48Spatrick // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
28509467b48Spatrick case SymbolKind::S_PUB32:
28609467b48Spatrick case SymbolKind::S_FILESTATIC:
28709467b48Spatrick case SymbolKind::S_REGREL32:
28809467b48Spatrick case SymbolKind::S_GDATA32:
28909467b48Spatrick case SymbolKind::S_LDATA32:
29009467b48Spatrick case SymbolKind::S_LMANDATA:
29109467b48Spatrick case SymbolKind::S_GMANDATA:
29209467b48Spatrick case SymbolKind::S_LTHREAD32:
29309467b48Spatrick case SymbolKind::S_GTHREAD32:
29409467b48Spatrick case SymbolKind::S_PROCREF:
29509467b48Spatrick case SymbolKind::S_LPROCREF:
29609467b48Spatrick return 10;
29709467b48Spatrick // See RegisterSym and LocalSym
29809467b48Spatrick case SymbolKind::S_REGISTER:
29909467b48Spatrick case SymbolKind::S_LOCAL:
30009467b48Spatrick return 6;
30109467b48Spatrick // See BlockSym
30209467b48Spatrick case SymbolKind::S_BLOCK32:
30309467b48Spatrick return 18;
30409467b48Spatrick // See LabelSym
30509467b48Spatrick case SymbolKind::S_LABEL32:
30609467b48Spatrick return 7;
30709467b48Spatrick // See ObjNameSym, ExportSym, and UDTSym
30809467b48Spatrick case SymbolKind::S_OBJNAME:
30909467b48Spatrick case SymbolKind::S_EXPORT:
31009467b48Spatrick case SymbolKind::S_UDT:
31109467b48Spatrick return 4;
31209467b48Spatrick // See BPRelativeSym
31309467b48Spatrick case SymbolKind::S_BPREL32:
31409467b48Spatrick return 8;
31509467b48Spatrick // See UsingNamespaceSym
31609467b48Spatrick case SymbolKind::S_UNAMESPACE:
31709467b48Spatrick return 0;
31809467b48Spatrick default:
31909467b48Spatrick return -1;
32009467b48Spatrick }
32109467b48Spatrick }
32209467b48Spatrick
getSymbolName(CVSymbol Sym)32309467b48Spatrick StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
32409467b48Spatrick if (Sym.kind() == SymbolKind::S_CONSTANT) {
32509467b48Spatrick // S_CONSTANT is preceded by an APSInt, which has a variable length. So we
32609467b48Spatrick // have to do a full deserialization.
32709467b48Spatrick BinaryStreamReader Reader(Sym.content(), llvm::support::little);
32809467b48Spatrick // The container doesn't matter for single records.
32909467b48Spatrick SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
33009467b48Spatrick ConstantSym Const(SymbolKind::S_CONSTANT);
33109467b48Spatrick cantFail(Mapping.visitSymbolBegin(Sym));
33209467b48Spatrick cantFail(Mapping.visitKnownRecord(Sym, Const));
33309467b48Spatrick cantFail(Mapping.visitSymbolEnd(Sym));
33409467b48Spatrick return Const.Name;
33509467b48Spatrick }
33609467b48Spatrick
33709467b48Spatrick int Offset = getSymbolNameOffset(Sym);
33809467b48Spatrick if (Offset == -1)
33909467b48Spatrick return StringRef();
34009467b48Spatrick
34109467b48Spatrick StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
34209467b48Spatrick return StringData.split('\0').first;
34309467b48Spatrick }
344