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