[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / lib / DebugInfo / CodeView / RecordName.cpp
blob1ca899789bef2024230db83bb0d77134ac5d48d6
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 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/CodeView/RecordName.h"
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"
19 using namespace llvm;
20 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();
28 /// Name of the current type. Only valid before visitTypeEnd.
29 SmallString<256> Name;
31 public:
32 explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {}
34 StringRef name() const { return Name; }
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;
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"
48 } // namespace
50 Error TypeNameComputer::visitTypeBegin(CVType &Record) {
51 llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
52 return Error::success();
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();
62 Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
64 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
65 FieldListRecord &FieldList) {
66 Name = "<field list>";
67 return Error::success();
70 Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
71 StringIdRecord &String) {
72 Name = String.getString();
73 return Error::success();
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(", ");
88 Name.push_back(')');
89 return Error::success();
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("\" \"");
102 Name.push_back('\"');
103 return Error::success();
106 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
107 Name = Class.getName();
108 return Error::success();
111 Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
112 Name = Union.getName();
113 return Error::success();
116 Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
117 Name = Enum.getName();
118 return Error::success();
121 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
122 Name = AT.getName();
123 return Error::success();
126 Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
127 Name = VFT.getName();
128 return Error::success();
131 Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
132 Name = Id.getName();
133 return Error::success();
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();
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();
152 Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
153 Name = Func.getName();
154 return Error::success();
157 Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
158 Name = TS.getName();
159 return Error::success();
162 Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
164 if (Ptr.isPointerToMember()) {
165 const MemberPointerInfo &MI = Ptr.getMemberInfo();
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()));
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("*");
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");
191 return Error::success();
194 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
195 uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
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();
207 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
208 VFTableShapeRecord &Shape) {
209 Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
210 return Error::success();
213 Error TypeNameComputer::visitKnownRecord(
214 CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
215 return Error::success();
218 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
219 UdtSourceLineRecord &SourceLine) {
220 return Error::success();
223 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
224 return Error::success();
227 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
228 MethodOverloadListRecord &Overloads) {
229 return Error::success();
232 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
233 return Error::success();
236 Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
237 return Error::success();
240 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
241 PrecompRecord &Precomp) {
242 return Error::success();
245 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
246 EndPrecompRecord &EndPrecomp) {
247 return Error::success();
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>";
258 return std::string(Computer.name());
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;
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;
333 int Offset = getSymbolNameOffset(Sym);
334 if (Offset == -1)
335 return StringRef();
337 StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
338 return StringData.split('\0').first;