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