1ee9906d8SZachary Turner //===- RecordName.cpp ----------------------------------------- *- C++ --*-===// 2ee9906d8SZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ee9906d8SZachary Turner // 7ee9906d8SZachary Turner //===----------------------------------------------------------------------===// 8ee9906d8SZachary Turner 9ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/RecordName.h" 10ee9906d8SZachary Turner 11ee9906d8SZachary Turner #include "llvm/ADT/SmallString.h" 12ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" 13ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 14ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" 15ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" 16ee9906d8SZachary Turner #include "llvm/Support/FormatVariadic.h" 17ee9906d8SZachary Turner 18ee9906d8SZachary Turner using namespace llvm; 19ee9906d8SZachary Turner using namespace llvm::codeview; 20ee9906d8SZachary Turner 21ee9906d8SZachary Turner namespace { 22ee9906d8SZachary Turner class TypeNameComputer : public TypeVisitorCallbacks { 23ee9906d8SZachary Turner /// The type collection. Used to calculate names of nested types. 24ee9906d8SZachary Turner TypeCollection &Types; 25ee9906d8SZachary Turner TypeIndex CurrentTypeIndex = TypeIndex::None(); 26ee9906d8SZachary Turner 27ee9906d8SZachary Turner /// Name of the current type. Only valid before visitTypeEnd. 28ee9906d8SZachary Turner SmallString<256> Name; 29ee9906d8SZachary Turner 30ee9906d8SZachary Turner public: 31ee9906d8SZachary Turner explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} 32ee9906d8SZachary Turner 33ee9906d8SZachary Turner StringRef name() const { return Name; } 34ee9906d8SZachary Turner 35ee9906d8SZachary Turner /// Paired begin/end actions for all types. Receives all record data, 36ee9906d8SZachary Turner /// including the fixed-length record prefix. 37ee9906d8SZachary Turner Error visitTypeBegin(CVType &Record) override; 38ee9906d8SZachary Turner Error visitTypeBegin(CVType &Record, TypeIndex Index) override; 39ee9906d8SZachary Turner Error visitTypeEnd(CVType &Record) override; 40ee9906d8SZachary Turner 41ee9906d8SZachary Turner #define TYPE_RECORD(EnumName, EnumVal, Name) \ 42ee9906d8SZachary Turner Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; 43ee9906d8SZachary Turner #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) 44ee9906d8SZachary Turner #define MEMBER_RECORD(EnumName, EnumVal, Name) 45ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" 46ee9906d8SZachary Turner }; 47ee9906d8SZachary Turner } // namespace 48ee9906d8SZachary Turner 49ee9906d8SZachary Turner Error TypeNameComputer::visitTypeBegin(CVType &Record) { 50ee9906d8SZachary Turner llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); 51ee9906d8SZachary Turner return Error::success(); 52ee9906d8SZachary Turner } 53ee9906d8SZachary Turner 54ee9906d8SZachary Turner Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { 55ee9906d8SZachary Turner // Reset Name to the empty string. If the visitor sets it, we know it. 56ee9906d8SZachary Turner Name = ""; 57ee9906d8SZachary Turner CurrentTypeIndex = Index; 58ee9906d8SZachary Turner return Error::success(); 59ee9906d8SZachary Turner } 60ee9906d8SZachary Turner 61ee9906d8SZachary Turner Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } 62ee9906d8SZachary Turner 63ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 64ee9906d8SZachary Turner FieldListRecord &FieldList) { 65ee9906d8SZachary Turner Name = "<field list>"; 66ee9906d8SZachary Turner return Error::success(); 67ee9906d8SZachary Turner } 68ee9906d8SZachary Turner 69ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, 70ee9906d8SZachary Turner StringIdRecord &String) { 71ee9906d8SZachary Turner Name = String.getString(); 72ee9906d8SZachary Turner return Error::success(); 73ee9906d8SZachary Turner } 74ee9906d8SZachary Turner 75ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { 76ee9906d8SZachary Turner auto Indices = Args.getIndices(); 77ee9906d8SZachary Turner uint32_t Size = Indices.size(); 78ee9906d8SZachary Turner Name = "("; 79ee9906d8SZachary Turner for (uint32_t I = 0; I < Size; ++I) { 80ee9906d8SZachary Turner assert(Indices[I] < CurrentTypeIndex); 81ee9906d8SZachary Turner 82ee9906d8SZachary Turner Name.append(Types.getTypeName(Indices[I])); 83ee9906d8SZachary Turner if (I + 1 != Size) 84ee9906d8SZachary Turner Name.append(", "); 85ee9906d8SZachary Turner } 86ee9906d8SZachary Turner Name.push_back(')'); 87ee9906d8SZachary Turner return Error::success(); 88ee9906d8SZachary Turner } 89ee9906d8SZachary Turner 90ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 91ee9906d8SZachary Turner StringListRecord &Strings) { 92ee9906d8SZachary Turner auto Indices = Strings.getIndices(); 93ee9906d8SZachary Turner uint32_t Size = Indices.size(); 94ee9906d8SZachary Turner Name = "\""; 95ee9906d8SZachary Turner for (uint32_t I = 0; I < Size; ++I) { 96ee9906d8SZachary Turner Name.append(Types.getTypeName(Indices[I])); 97ee9906d8SZachary Turner if (I + 1 != Size) 98ee9906d8SZachary Turner Name.append("\" \""); 99ee9906d8SZachary Turner } 100ee9906d8SZachary Turner Name.push_back('\"'); 101ee9906d8SZachary Turner return Error::success(); 102ee9906d8SZachary Turner } 103ee9906d8SZachary Turner 104ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { 105ee9906d8SZachary Turner Name = Class.getName(); 106ee9906d8SZachary Turner return Error::success(); 107ee9906d8SZachary Turner } 108ee9906d8SZachary Turner 109ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { 110ee9906d8SZachary Turner Name = Union.getName(); 111ee9906d8SZachary Turner return Error::success(); 112ee9906d8SZachary Turner } 113ee9906d8SZachary Turner 114ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { 115ee9906d8SZachary Turner Name = Enum.getName(); 116ee9906d8SZachary Turner return Error::success(); 117ee9906d8SZachary Turner } 118ee9906d8SZachary Turner 119ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { 120ee9906d8SZachary Turner Name = AT.getName(); 121ee9906d8SZachary Turner return Error::success(); 122ee9906d8SZachary Turner } 123ee9906d8SZachary Turner 124ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { 125ee9906d8SZachary Turner Name = VFT.getName(); 126ee9906d8SZachary Turner return Error::success(); 127ee9906d8SZachary Turner } 128ee9906d8SZachary Turner 129ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { 130ee9906d8SZachary Turner Name = Id.getName(); 131ee9906d8SZachary Turner return Error::success(); 132ee9906d8SZachary Turner } 133ee9906d8SZachary Turner 134ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { 135ee9906d8SZachary Turner StringRef Ret = Types.getTypeName(Proc.getReturnType()); 136ee9906d8SZachary Turner StringRef Params = Types.getTypeName(Proc.getArgumentList()); 137ee9906d8SZachary Turner Name = formatv("{0} {1}", Ret, Params).sstr<256>(); 138ee9906d8SZachary Turner return Error::success(); 139ee9906d8SZachary Turner } 140ee9906d8SZachary Turner 141ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 142ee9906d8SZachary Turner MemberFunctionRecord &MF) { 143ee9906d8SZachary Turner StringRef Ret = Types.getTypeName(MF.getReturnType()); 144ee9906d8SZachary Turner StringRef Class = Types.getTypeName(MF.getClassType()); 145ee9906d8SZachary Turner StringRef Params = Types.getTypeName(MF.getArgumentList()); 146ee9906d8SZachary Turner Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); 147ee9906d8SZachary Turner return Error::success(); 148ee9906d8SZachary Turner } 149ee9906d8SZachary Turner 150ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { 151ee9906d8SZachary Turner Name = Func.getName(); 152ee9906d8SZachary Turner return Error::success(); 153ee9906d8SZachary Turner } 154ee9906d8SZachary Turner 155ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { 156ee9906d8SZachary Turner Name = TS.getName(); 157ee9906d8SZachary Turner return Error::success(); 158ee9906d8SZachary Turner } 159ee9906d8SZachary Turner 160ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { 161ee9906d8SZachary Turner 162ee9906d8SZachary Turner if (Ptr.isPointerToMember()) { 163ee9906d8SZachary Turner const MemberPointerInfo &MI = Ptr.getMemberInfo(); 164ee9906d8SZachary Turner 165ee9906d8SZachary Turner StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); 166ee9906d8SZachary Turner StringRef Class = Types.getTypeName(MI.getContainingType()); 167ee9906d8SZachary Turner Name = formatv("{0} {1}::*", Pointee, Class); 168ee9906d8SZachary Turner } else { 169ee9906d8SZachary Turner Name.append(Types.getTypeName(Ptr.getReferentType())); 170ee9906d8SZachary Turner 171ee9906d8SZachary Turner if (Ptr.getMode() == PointerMode::LValueReference) 172ee9906d8SZachary Turner Name.append("&"); 173ee9906d8SZachary Turner else if (Ptr.getMode() == PointerMode::RValueReference) 174ee9906d8SZachary Turner Name.append("&&"); 175ee9906d8SZachary Turner else if (Ptr.getMode() == PointerMode::Pointer) 176ee9906d8SZachary Turner Name.append("*"); 1773acdc677SReid Kleckner 1783acdc677SReid Kleckner // Qualifiers in pointer records apply to the pointer, not the pointee, so 1793acdc677SReid Kleckner // they go on the right. 1803acdc677SReid Kleckner if (Ptr.isConst()) 1813acdc677SReid Kleckner Name.append(" const"); 1823acdc677SReid Kleckner if (Ptr.isVolatile()) 1833acdc677SReid Kleckner Name.append(" volatile"); 1843acdc677SReid Kleckner if (Ptr.isUnaligned()) 1853acdc677SReid Kleckner Name.append(" __unaligned"); 1863acdc677SReid Kleckner if (Ptr.isRestrict()) 1873acdc677SReid Kleckner Name.append(" __restrict"); 188ee9906d8SZachary Turner } 189ee9906d8SZachary Turner return Error::success(); 190ee9906d8SZachary Turner } 191ee9906d8SZachary Turner 192ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { 193ee9906d8SZachary Turner uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); 194ee9906d8SZachary Turner 195ee9906d8SZachary Turner if (Mods & uint16_t(ModifierOptions::Const)) 196ee9906d8SZachary Turner Name.append("const "); 197ee9906d8SZachary Turner if (Mods & uint16_t(ModifierOptions::Volatile)) 198ee9906d8SZachary Turner Name.append("volatile "); 199ee9906d8SZachary Turner if (Mods & uint16_t(ModifierOptions::Unaligned)) 200ee9906d8SZachary Turner Name.append("__unaligned "); 201ee9906d8SZachary Turner Name.append(Types.getTypeName(Mod.getModifiedType())); 202ee9906d8SZachary Turner return Error::success(); 203ee9906d8SZachary Turner } 204ee9906d8SZachary Turner 205ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 206ee9906d8SZachary Turner VFTableShapeRecord &Shape) { 207ee9906d8SZachary Turner Name = formatv("<vftable {0} methods>", Shape.getEntryCount()); 208ee9906d8SZachary Turner return Error::success(); 209ee9906d8SZachary Turner } 210ee9906d8SZachary Turner 211ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord( 212ee9906d8SZachary Turner CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { 213ee9906d8SZachary Turner return Error::success(); 214ee9906d8SZachary Turner } 215ee9906d8SZachary Turner 216ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 217ee9906d8SZachary Turner UdtSourceLineRecord &SourceLine) { 218ee9906d8SZachary Turner return Error::success(); 219ee9906d8SZachary Turner } 220ee9906d8SZachary Turner 221ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { 222ee9906d8SZachary Turner return Error::success(); 223ee9906d8SZachary Turner } 224ee9906d8SZachary Turner 225ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 226ee9906d8SZachary Turner MethodOverloadListRecord &Overloads) { 227ee9906d8SZachary Turner return Error::success(); 228ee9906d8SZachary Turner } 229ee9906d8SZachary Turner 230ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { 231ee9906d8SZachary Turner return Error::success(); 232ee9906d8SZachary Turner } 233ee9906d8SZachary Turner 234ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { 235ee9906d8SZachary Turner return Error::success(); 236ee9906d8SZachary Turner } 237ee9906d8SZachary Turner 238d9e96741SAlexandre Ganea Error TypeNameComputer::visitKnownRecord(CVType &CVR, 239d9e96741SAlexandre Ganea PrecompRecord &Precomp) { 240d9e96741SAlexandre Ganea return Error::success(); 241d9e96741SAlexandre Ganea } 242d9e96741SAlexandre Ganea 243d9e96741SAlexandre Ganea Error TypeNameComputer::visitKnownRecord(CVType &CVR, 244d9e96741SAlexandre Ganea EndPrecompRecord &EndPrecomp) { 245d9e96741SAlexandre Ganea return Error::success(); 246d9e96741SAlexandre Ganea } 247d9e96741SAlexandre Ganea 248ee9906d8SZachary Turner std::string llvm::codeview::computeTypeName(TypeCollection &Types, 249ee9906d8SZachary Turner TypeIndex Index) { 250ee9906d8SZachary Turner TypeNameComputer Computer(Types); 251ee9906d8SZachary Turner CVType Record = Types.getType(Index); 252ee9906d8SZachary Turner if (auto EC = visitTypeRecord(Record, Index, Computer)) { 253ee9906d8SZachary Turner consumeError(std::move(EC)); 254ee9906d8SZachary Turner return "<unknown UDT>"; 255ee9906d8SZachary Turner } 256*adcd0268SBenjamin Kramer return std::string(Computer.name()); 257ee9906d8SZachary Turner } 258ee9906d8SZachary Turner 259ee9906d8SZachary Turner static int getSymbolNameOffset(CVSymbol Sym) { 260ee9906d8SZachary Turner switch (Sym.kind()) { 261ee9906d8SZachary Turner // See ProcSym 262ee9906d8SZachary Turner case SymbolKind::S_GPROC32: 263ee9906d8SZachary Turner case SymbolKind::S_LPROC32: 264ee9906d8SZachary Turner case SymbolKind::S_GPROC32_ID: 265ee9906d8SZachary Turner case SymbolKind::S_LPROC32_ID: 266ee9906d8SZachary Turner case SymbolKind::S_LPROC32_DPC: 267ee9906d8SZachary Turner case SymbolKind::S_LPROC32_DPC_ID: 268ee9906d8SZachary Turner return 35; 269ee9906d8SZachary Turner // See Thunk32Sym 270ee9906d8SZachary Turner case SymbolKind::S_THUNK32: 271ee9906d8SZachary Turner return 21; 272ee9906d8SZachary Turner // See SectionSym 273ee9906d8SZachary Turner case SymbolKind::S_SECTION: 274ee9906d8SZachary Turner return 16; 275ee9906d8SZachary Turner // See CoffGroupSym 276ee9906d8SZachary Turner case SymbolKind::S_COFFGROUP: 277ee9906d8SZachary Turner return 14; 278ee9906d8SZachary Turner // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym 279ee9906d8SZachary Turner case SymbolKind::S_PUB32: 280ee9906d8SZachary Turner case SymbolKind::S_FILESTATIC: 281ee9906d8SZachary Turner case SymbolKind::S_REGREL32: 282ee9906d8SZachary Turner case SymbolKind::S_GDATA32: 283ee9906d8SZachary Turner case SymbolKind::S_LDATA32: 284ee9906d8SZachary Turner case SymbolKind::S_LMANDATA: 285ee9906d8SZachary Turner case SymbolKind::S_GMANDATA: 286ee9906d8SZachary Turner case SymbolKind::S_LTHREAD32: 287ee9906d8SZachary Turner case SymbolKind::S_GTHREAD32: 28868e1919dSZachary Turner case SymbolKind::S_PROCREF: 28968e1919dSZachary Turner case SymbolKind::S_LPROCREF: 290ee9906d8SZachary Turner return 10; 291ee9906d8SZachary Turner // See RegisterSym and LocalSym 292ee9906d8SZachary Turner case SymbolKind::S_REGISTER: 293ee9906d8SZachary Turner case SymbolKind::S_LOCAL: 294ee9906d8SZachary Turner return 6; 295ee9906d8SZachary Turner // See BlockSym 296ee9906d8SZachary Turner case SymbolKind::S_BLOCK32: 297ee9906d8SZachary Turner return 18; 298ee9906d8SZachary Turner // See LabelSym 299ee9906d8SZachary Turner case SymbolKind::S_LABEL32: 300ee9906d8SZachary Turner return 7; 301ee9906d8SZachary Turner // See ObjNameSym, ExportSym, and UDTSym 302ee9906d8SZachary Turner case SymbolKind::S_OBJNAME: 303ee9906d8SZachary Turner case SymbolKind::S_EXPORT: 304ee9906d8SZachary Turner case SymbolKind::S_UDT: 305ee9906d8SZachary Turner return 4; 306ee9906d8SZachary Turner // See BPRelativeSym 307ee9906d8SZachary Turner case SymbolKind::S_BPREL32: 308ee9906d8SZachary Turner return 8; 309ee8a7200SAlexandre Ganea // See UsingNamespaceSym 310ee8a7200SAlexandre Ganea case SymbolKind::S_UNAMESPACE: 311ee8a7200SAlexandre Ganea return 0; 312ee9906d8SZachary Turner default: 313ee9906d8SZachary Turner return -1; 314ee9906d8SZachary Turner } 315ee9906d8SZachary Turner } 316ee9906d8SZachary Turner 317ee9906d8SZachary Turner StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { 318ee9906d8SZachary Turner if (Sym.kind() == SymbolKind::S_CONSTANT) { 319ee9906d8SZachary Turner // S_CONSTANT is preceded by an APSInt, which has a variable length. So we 320ee9906d8SZachary Turner // have to do a full deserialization. 321ee9906d8SZachary Turner BinaryStreamReader Reader(Sym.content(), llvm::support::little); 322ee9906d8SZachary Turner // The container doesn't matter for single records. 323ee9906d8SZachary Turner SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); 324ee9906d8SZachary Turner ConstantSym Const(SymbolKind::S_CONSTANT); 325ee9906d8SZachary Turner cantFail(Mapping.visitSymbolBegin(Sym)); 326ee9906d8SZachary Turner cantFail(Mapping.visitKnownRecord(Sym, Const)); 327ee9906d8SZachary Turner cantFail(Mapping.visitSymbolEnd(Sym)); 328ee9906d8SZachary Turner return Const.Name; 329ee9906d8SZachary Turner } 330ee9906d8SZachary Turner 331ee9906d8SZachary Turner int Offset = getSymbolNameOffset(Sym); 332ee9906d8SZachary Turner if (Offset == -1) 333ee9906d8SZachary Turner return StringRef(); 334ee9906d8SZachary Turner 335ee9906d8SZachary Turner StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); 336ee9906d8SZachary Turner return StringData.split('\0').first; 337ee9906d8SZachary Turner } 338