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