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