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