RecordName.cpp 11 KB

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