1ee9906d8SZachary Turner //===- RecordName.cpp ----------------------------------------- *- C++ --*-===// 2ee9906d8SZachary Turner // 3ee9906d8SZachary Turner // The LLVM Compiler Infrastructure 4ee9906d8SZachary Turner // 5ee9906d8SZachary Turner // This file is distributed under the University of Illinois Open Source 6ee9906d8SZachary Turner // License. See LICENSE.TXT for details. 7ee9906d8SZachary Turner // 8ee9906d8SZachary Turner //===----------------------------------------------------------------------===// 9ee9906d8SZachary Turner 10ee9906d8SZachary Turner #include "llvm/DebugInfo/CodeView/RecordName.h" 11ee9906d8SZachary Turner 12ee9906d8SZachary Turner #include "llvm/ADT/SmallString.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) { 81ee9906d8SZachary Turner assert(Indices[I] < CurrentTypeIndex); 82ee9906d8SZachary Turner 83ee9906d8SZachary Turner Name.append(Types.getTypeName(Indices[I])); 84ee9906d8SZachary Turner if (I + 1 != Size) 85ee9906d8SZachary Turner Name.append(", "); 86ee9906d8SZachary Turner } 87ee9906d8SZachary Turner Name.push_back(')'); 88ee9906d8SZachary Turner return Error::success(); 89ee9906d8SZachary Turner } 90ee9906d8SZachary Turner 91ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 92ee9906d8SZachary Turner StringListRecord &Strings) { 93ee9906d8SZachary Turner auto Indices = Strings.getIndices(); 94ee9906d8SZachary Turner uint32_t Size = Indices.size(); 95ee9906d8SZachary Turner Name = "\""; 96ee9906d8SZachary Turner for (uint32_t I = 0; I < Size; ++I) { 97ee9906d8SZachary Turner Name.append(Types.getTypeName(Indices[I])); 98ee9906d8SZachary Turner if (I + 1 != Size) 99ee9906d8SZachary Turner Name.append("\" \""); 100ee9906d8SZachary Turner } 101ee9906d8SZachary Turner Name.push_back('\"'); 102ee9906d8SZachary Turner return Error::success(); 103ee9906d8SZachary Turner } 104ee9906d8SZachary Turner 105ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { 106ee9906d8SZachary Turner Name = Class.getName(); 107ee9906d8SZachary Turner return Error::success(); 108ee9906d8SZachary Turner } 109ee9906d8SZachary Turner 110ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { 111ee9906d8SZachary Turner Name = Union.getName(); 112ee9906d8SZachary Turner return Error::success(); 113ee9906d8SZachary Turner } 114ee9906d8SZachary Turner 115ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { 116ee9906d8SZachary Turner Name = Enum.getName(); 117ee9906d8SZachary Turner return Error::success(); 118ee9906d8SZachary Turner } 119ee9906d8SZachary Turner 120ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { 121ee9906d8SZachary Turner Name = AT.getName(); 122ee9906d8SZachary Turner return Error::success(); 123ee9906d8SZachary Turner } 124ee9906d8SZachary Turner 125ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { 126ee9906d8SZachary Turner Name = VFT.getName(); 127ee9906d8SZachary Turner return Error::success(); 128ee9906d8SZachary Turner } 129ee9906d8SZachary Turner 130ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { 131ee9906d8SZachary Turner Name = Id.getName(); 132ee9906d8SZachary Turner return Error::success(); 133ee9906d8SZachary Turner } 134ee9906d8SZachary Turner 135ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { 136ee9906d8SZachary Turner StringRef Ret = Types.getTypeName(Proc.getReturnType()); 137ee9906d8SZachary Turner StringRef Params = Types.getTypeName(Proc.getArgumentList()); 138ee9906d8SZachary Turner Name = formatv("{0} {1}", Ret, Params).sstr<256>(); 139ee9906d8SZachary Turner return Error::success(); 140ee9906d8SZachary Turner } 141ee9906d8SZachary Turner 142ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 143ee9906d8SZachary Turner MemberFunctionRecord &MF) { 144ee9906d8SZachary Turner StringRef Ret = Types.getTypeName(MF.getReturnType()); 145ee9906d8SZachary Turner StringRef Class = Types.getTypeName(MF.getClassType()); 146ee9906d8SZachary Turner StringRef Params = Types.getTypeName(MF.getArgumentList()); 147ee9906d8SZachary Turner Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); 148ee9906d8SZachary Turner return Error::success(); 149ee9906d8SZachary Turner } 150ee9906d8SZachary Turner 151ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { 152ee9906d8SZachary Turner Name = Func.getName(); 153ee9906d8SZachary Turner return Error::success(); 154ee9906d8SZachary Turner } 155ee9906d8SZachary Turner 156ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { 157ee9906d8SZachary Turner Name = TS.getName(); 158ee9906d8SZachary Turner return Error::success(); 159ee9906d8SZachary Turner } 160ee9906d8SZachary Turner 161ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { 162ee9906d8SZachary Turner 163ee9906d8SZachary Turner if (Ptr.isPointerToMember()) { 164ee9906d8SZachary Turner const MemberPointerInfo &MI = Ptr.getMemberInfo(); 165ee9906d8SZachary Turner 166ee9906d8SZachary Turner StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); 167ee9906d8SZachary Turner StringRef Class = Types.getTypeName(MI.getContainingType()); 168ee9906d8SZachary Turner Name = formatv("{0} {1}::*", Pointee, Class); 169ee9906d8SZachary Turner } else { 170ee9906d8SZachary Turner Name.append(Types.getTypeName(Ptr.getReferentType())); 171ee9906d8SZachary Turner 172ee9906d8SZachary Turner if (Ptr.getMode() == PointerMode::LValueReference) 173ee9906d8SZachary Turner Name.append("&"); 174ee9906d8SZachary Turner else if (Ptr.getMode() == PointerMode::RValueReference) 175ee9906d8SZachary Turner Name.append("&&"); 176ee9906d8SZachary Turner else if (Ptr.getMode() == PointerMode::Pointer) 177ee9906d8SZachary Turner Name.append("*"); 1783acdc677SReid Kleckner 1793acdc677SReid Kleckner // Qualifiers in pointer records apply to the pointer, not the pointee, so 1803acdc677SReid Kleckner // they go on the right. 1813acdc677SReid Kleckner if (Ptr.isConst()) 1823acdc677SReid Kleckner Name.append(" const"); 1833acdc677SReid Kleckner if (Ptr.isVolatile()) 1843acdc677SReid Kleckner Name.append(" volatile"); 1853acdc677SReid Kleckner if (Ptr.isUnaligned()) 1863acdc677SReid Kleckner Name.append(" __unaligned"); 1873acdc677SReid Kleckner if (Ptr.isRestrict()) 1883acdc677SReid Kleckner Name.append(" __restrict"); 189ee9906d8SZachary Turner } 190ee9906d8SZachary Turner return Error::success(); 191ee9906d8SZachary Turner } 192ee9906d8SZachary Turner 193ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { 194ee9906d8SZachary Turner uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); 195ee9906d8SZachary Turner 196ee9906d8SZachary Turner if (Mods & uint16_t(ModifierOptions::Const)) 197ee9906d8SZachary Turner Name.append("const "); 198ee9906d8SZachary Turner if (Mods & uint16_t(ModifierOptions::Volatile)) 199ee9906d8SZachary Turner Name.append("volatile "); 200ee9906d8SZachary Turner if (Mods & uint16_t(ModifierOptions::Unaligned)) 201ee9906d8SZachary Turner Name.append("__unaligned "); 202ee9906d8SZachary Turner Name.append(Types.getTypeName(Mod.getModifiedType())); 203ee9906d8SZachary Turner return Error::success(); 204ee9906d8SZachary Turner } 205ee9906d8SZachary Turner 206ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 207ee9906d8SZachary Turner VFTableShapeRecord &Shape) { 208ee9906d8SZachary Turner Name = formatv("<vftable {0} methods>", Shape.getEntryCount()); 209ee9906d8SZachary Turner return Error::success(); 210ee9906d8SZachary Turner } 211ee9906d8SZachary Turner 212ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord( 213ee9906d8SZachary Turner CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { 214ee9906d8SZachary Turner return Error::success(); 215ee9906d8SZachary Turner } 216ee9906d8SZachary Turner 217ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 218ee9906d8SZachary Turner UdtSourceLineRecord &SourceLine) { 219ee9906d8SZachary Turner return Error::success(); 220ee9906d8SZachary Turner } 221ee9906d8SZachary Turner 222ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { 223ee9906d8SZachary Turner return Error::success(); 224ee9906d8SZachary Turner } 225ee9906d8SZachary Turner 226ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, 227ee9906d8SZachary Turner MethodOverloadListRecord &Overloads) { 228ee9906d8SZachary Turner return Error::success(); 229ee9906d8SZachary Turner } 230ee9906d8SZachary Turner 231ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { 232ee9906d8SZachary Turner return Error::success(); 233ee9906d8SZachary Turner } 234ee9906d8SZachary Turner 235ee9906d8SZachary Turner Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { 236ee9906d8SZachary Turner return Error::success(); 237ee9906d8SZachary Turner } 238ee9906d8SZachary Turner 239d9e96741SAlexandre Ganea Error TypeNameComputer::visitKnownRecord(CVType &CVR, 240d9e96741SAlexandre Ganea PrecompRecord &Precomp) { 241d9e96741SAlexandre Ganea return Error::success(); 242d9e96741SAlexandre Ganea } 243d9e96741SAlexandre Ganea 244d9e96741SAlexandre Ganea Error TypeNameComputer::visitKnownRecord(CVType &CVR, 245d9e96741SAlexandre Ganea EndPrecompRecord &EndPrecomp) { 246d9e96741SAlexandre Ganea return Error::success(); 247d9e96741SAlexandre Ganea } 248d9e96741SAlexandre Ganea 249ee9906d8SZachary Turner std::string llvm::codeview::computeTypeName(TypeCollection &Types, 250ee9906d8SZachary Turner TypeIndex Index) { 251ee9906d8SZachary Turner TypeNameComputer Computer(Types); 252ee9906d8SZachary Turner CVType Record = Types.getType(Index); 253ee9906d8SZachary Turner if (auto EC = visitTypeRecord(Record, Index, Computer)) { 254ee9906d8SZachary Turner consumeError(std::move(EC)); 255ee9906d8SZachary Turner return "<unknown UDT>"; 256ee9906d8SZachary Turner } 257ee9906d8SZachary Turner return Computer.name(); 258ee9906d8SZachary Turner } 259ee9906d8SZachary Turner 260ee9906d8SZachary Turner static int getSymbolNameOffset(CVSymbol Sym) { 261ee9906d8SZachary Turner switch (Sym.kind()) { 262ee9906d8SZachary Turner // See ProcSym 263ee9906d8SZachary Turner case SymbolKind::S_GPROC32: 264ee9906d8SZachary Turner case SymbolKind::S_LPROC32: 265ee9906d8SZachary Turner case SymbolKind::S_GPROC32_ID: 266ee9906d8SZachary Turner case SymbolKind::S_LPROC32_ID: 267ee9906d8SZachary Turner case SymbolKind::S_LPROC32_DPC: 268ee9906d8SZachary Turner case SymbolKind::S_LPROC32_DPC_ID: 269ee9906d8SZachary Turner return 35; 270ee9906d8SZachary Turner // See Thunk32Sym 271ee9906d8SZachary Turner case SymbolKind::S_THUNK32: 272ee9906d8SZachary Turner return 21; 273ee9906d8SZachary Turner // See SectionSym 274ee9906d8SZachary Turner case SymbolKind::S_SECTION: 275ee9906d8SZachary Turner return 16; 276ee9906d8SZachary Turner // See CoffGroupSym 277ee9906d8SZachary Turner case SymbolKind::S_COFFGROUP: 278ee9906d8SZachary Turner return 14; 279ee9906d8SZachary Turner // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym 280ee9906d8SZachary Turner case SymbolKind::S_PUB32: 281ee9906d8SZachary Turner case SymbolKind::S_FILESTATIC: 282ee9906d8SZachary Turner case SymbolKind::S_REGREL32: 283ee9906d8SZachary Turner case SymbolKind::S_GDATA32: 284ee9906d8SZachary Turner case SymbolKind::S_LDATA32: 285ee9906d8SZachary Turner case SymbolKind::S_LMANDATA: 286ee9906d8SZachary Turner case SymbolKind::S_GMANDATA: 287ee9906d8SZachary Turner case SymbolKind::S_LTHREAD32: 288ee9906d8SZachary Turner case SymbolKind::S_GTHREAD32: 28968e1919dSZachary Turner case SymbolKind::S_PROCREF: 29068e1919dSZachary Turner case SymbolKind::S_LPROCREF: 291ee9906d8SZachary Turner return 10; 292ee9906d8SZachary Turner // See RegisterSym and LocalSym 293ee9906d8SZachary Turner case SymbolKind::S_REGISTER: 294ee9906d8SZachary Turner case SymbolKind::S_LOCAL: 295ee9906d8SZachary Turner return 6; 296ee9906d8SZachary Turner // See BlockSym 297ee9906d8SZachary Turner case SymbolKind::S_BLOCK32: 298ee9906d8SZachary Turner return 18; 299ee9906d8SZachary Turner // See LabelSym 300ee9906d8SZachary Turner case SymbolKind::S_LABEL32: 301ee9906d8SZachary Turner return 7; 302ee9906d8SZachary Turner // See ObjNameSym, ExportSym, and UDTSym 303ee9906d8SZachary Turner case SymbolKind::S_OBJNAME: 304ee9906d8SZachary Turner case SymbolKind::S_EXPORT: 305ee9906d8SZachary Turner case SymbolKind::S_UDT: 306ee9906d8SZachary Turner return 4; 307ee9906d8SZachary Turner // See BPRelativeSym 308ee9906d8SZachary Turner case SymbolKind::S_BPREL32: 309ee9906d8SZachary Turner return 8; 310*ee8a7200SAlexandre Ganea // See UsingNamespaceSym 311*ee8a7200SAlexandre Ganea case SymbolKind::S_UNAMESPACE: 312*ee8a7200SAlexandre Ganea return 0; 313ee9906d8SZachary Turner default: 314ee9906d8SZachary Turner return -1; 315ee9906d8SZachary Turner } 316ee9906d8SZachary Turner } 317ee9906d8SZachary Turner 318ee9906d8SZachary Turner StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { 319ee9906d8SZachary Turner if (Sym.kind() == SymbolKind::S_CONSTANT) { 320ee9906d8SZachary Turner // S_CONSTANT is preceded by an APSInt, which has a variable length. So we 321ee9906d8SZachary Turner // have to do a full deserialization. 322ee9906d8SZachary Turner BinaryStreamReader Reader(Sym.content(), llvm::support::little); 323ee9906d8SZachary Turner // The container doesn't matter for single records. 324ee9906d8SZachary Turner SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); 325ee9906d8SZachary Turner ConstantSym Const(SymbolKind::S_CONSTANT); 326ee9906d8SZachary Turner cantFail(Mapping.visitSymbolBegin(Sym)); 327ee9906d8SZachary Turner cantFail(Mapping.visitKnownRecord(Sym, Const)); 328ee9906d8SZachary Turner cantFail(Mapping.visitSymbolEnd(Sym)); 329ee9906d8SZachary Turner return Const.Name; 330ee9906d8SZachary Turner } 331ee9906d8SZachary Turner 332ee9906d8SZachary Turner int Offset = getSymbolNameOffset(Sym); 333ee9906d8SZachary Turner if (Offset == -1) 334ee9906d8SZachary Turner return StringRef(); 335ee9906d8SZachary Turner 336ee9906d8SZachary Turner StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); 337ee9906d8SZachary Turner return StringData.split('\0').first; 338ee9906d8SZachary Turner } 339