llvm.org GIT mirror llvm / 2757ca6
[CodeView] Fix random access of type names. Suppose we had a type index offsets array with a boundary at type index N. Then you request the name of the type with index N+1, and that name requires the name of index N-1 (think a parameter list, for example). We didn't handle this, and we would print something like (<unknown UDT>, <unknown UDT>). The fix for this is not entirely trivial, and speaks to a larger problem. I think we need to kill TypeDatabase, or at the very least kill TypeDatabaseVisitor. We need a thing that doesn't do any caching whatsoever, just given a type index it can compute the type name "the slow way". The reason for the bug is that we don't have anything like that. Everything goes through the type database, and if we've visited a record, then we're "done". It doesn't know how to do the expensive thing of re-visiting dependent records if they've not yet been visited. What I've done here is more or less copied the code (albeit greatly simplified) from TypeDatabaseVisitor, but wrapped it in an interface that just returns a std::string. The logic of caching the name is now in LazyRandomTypeCollection. Eventually I'd like to move the record database here as well and the visited record bitfield here as well, at which point we can actually just delete TypeDatabase. I don't see any reason for it if a "sequential" collection is just a special case of a random access collection with an empty partial offsets array. Differential Revision: https://reviews.llvm.org/D34297 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305612 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
6 changed file(s) with 337 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
7575 Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End);
7676 Error visitOneRecord(TypeIndex TI, uint32_t Offset, CVType &Record);
7777
78 BumpPtrAllocator Allocator;
79 StringSaver NameStorage;
80
81 SmallVector TypeNames;
82
7883 /// Visited records get automatically added to the type database.
7984 TypeDatabase Database;
8085
0 //===- TypeName.h --------------------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H
11
12 #include "llvm/DebugInfo/CodeView/TypeCollection.h"
13 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
14
15 namespace llvm {
16 namespace codeview {
17 std::string computeTypeName(TypeCollection &Types, TypeIndex Index);
18 }
19 } // namespace llvm
20
21 #endif
2828 TypeDumpVisitor.cpp
2929 TypeIndex.cpp
3030 TypeIndexDiscovery.cpp
31 TypeName.cpp
3132 TypeRecordMapping.cpp
3233 TypeSerializer.cpp
3334 TypeStreamMerger.cpp
1111 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1212 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
1313 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
14 #include "llvm/DebugInfo/CodeView/TypeName.h"
1415 #include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
1516 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
1617
3031 LazyRandomTypeCollection::LazyRandomTypeCollection(
3132 const CVTypeArray &Types, uint32_t RecordCountHint,
3233 PartialOffsetArray PartialOffsets)
33 : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database),
34 PartialOffsets(PartialOffsets) {
34 : NameStorage(Allocator), Database(RecordCountHint), Types(Types),
35 DatabaseVisitor(Database), PartialOffsets(PartialOffsets) {
3536 KnownOffsets.resize(Database.capacity());
3637 }
3738
7071 }
7172
7273 StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) {
73 if (!Index.isSimple()) {
74 // Try to make sure the type exists. Even if it doesn't though, it may be
75 // because we're dumping a symbol stream with no corresponding type stream
76 // present, in which case we still want to be able to print
77 // for the type names.
78 consumeError(ensureTypeExists(Index));
79 }
80
81 return Database.getTypeName(Index);
74 if (Index.isNoneType() || Index.isSimple())
75 return TypeIndex::simpleTypeName(Index);
76
77 uint32_t I = Index.toArrayIndex();
78 if (I >= TypeNames.size())
79 TypeNames.resize(I + 1);
80
81 if (TypeNames[I].data() == nullptr) {
82 StringRef Result = NameStorage.save(computeTypeName(*this, Index));
83 TypeNames[I] = Result;
84 }
85 return TypeNames[I];
8286 }
8387
8488 bool LazyRandomTypeCollection::contains(TypeIndex Index) {
0 //===- TypeName.cpp ------------------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeName.h"
10
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
14 #include "llvm/Support/FormatVariadic.h"
15
16 using namespace llvm;
17 using namespace llvm::codeview;
18
19 namespace {
20 class TypeNameComputer : public TypeVisitorCallbacks {
21 /// The type collection. Used to calculate names of nested types.
22 TypeCollection &Types;
23 TypeIndex CurrentTypeIndex = TypeIndex::None();
24
25 /// Name of the current type. Only valid before visitTypeEnd.
26 SmallString<256> Name;
27
28 public:
29 explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {}
30
31 StringRef name() const { return Name; }
32
33 /// Paired begin/end actions for all types. Receives all record data,
34 /// including the fixed-length record prefix.
35 Error visitTypeBegin(CVType &Record) override;
36 Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
37 Error visitTypeEnd(CVType &Record) override;
38
39 #define TYPE_RECORD(EnumName, EnumVal, Name) \
40 Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
41 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
42 #define MEMBER_RECORD(EnumName, EnumVal, Name)
43 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
44 };
45 } // namespace
46
47 Error TypeNameComputer::visitTypeBegin(CVType &Record) {
48 llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
49 return Error::success();
50 }
51
52 Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) {
53 // Reset Name to the empty string. If the visitor sets it, we know it.
54 Name = "";
55 CurrentTypeIndex = Index;
56 return Error::success();
57 }
58
59 Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
60
61 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
62 FieldListRecord &FieldList) {
63 Name = "";
64 return Error::success();
65 }
66
67 Error TypeNameComputer::visitKnownRecord(CVRecord &CVR,
68 StringIdRecord &String) {
69 Name = String.getString();
70 return Error::success();
71 }
72
73 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
74 auto Indices = Args.getIndices();
75 uint32_t Size = Indices.size();
76 Name = "(";
77 for (uint32_t I = 0; I < Size; ++I) {
78 assert(Indices[I] < CurrentTypeIndex);
79
80 Name.append(Types.getTypeName(Indices[I]));
81 if (I + 1 != Size)
82 Name.append(", ");
83 }
84 Name.push_back(')');
85 return Error::success();
86 }
87
88 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
89 StringListRecord &Strings) {
90 auto Indices = Strings.getIndices();
91 uint32_t Size = Indices.size();
92 Name = "\"";
93 for (uint32_t I = 0; I < Size; ++I) {
94 Name.append(Types.getTypeName(Indices[I]));
95 if (I + 1 != Size)
96 Name.append("\" \"");
97 }
98 Name.push_back('\"');
99 return Error::success();
100 }
101
102 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
103 Name = Class.getName();
104 return Error::success();
105 }
106
107 Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
108 Name = Union.getName();
109 return Error::success();
110 }
111
112 Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
113 Name = Enum.getName();
114 return Error::success();
115 }
116
117 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
118 Name = AT.getName();
119 return Error::success();
120 }
121
122 Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
123 Name = VFT.getName();
124 return Error::success();
125 }
126
127 Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
128 Name = Id.getName();
129 return Error::success();
130 }
131
132 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
133 StringRef Ret = Types.getTypeName(Proc.getReturnType());
134 StringRef Params = Types.getTypeName(Proc.getArgumentList());
135 Name = formatv("{0} {1}", Ret, Params).sstr<256>();
136 return Error::success();
137 }
138
139 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
140 MemberFunctionRecord &MF) {
141 StringRef Ret = Types.getTypeName(MF.getReturnType());
142 StringRef Class = Types.getTypeName(MF.getClassType());
143 StringRef Params = Types.getTypeName(MF.getArgumentList());
144 Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>();
145 return Error::success();
146 }
147
148 Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
149 Name = Func.getName();
150 return Error::success();
151 }
152
153 Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
154 Name = TS.getName();
155 return Error::success();
156 }
157
158 Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
159
160 if (Ptr.isPointerToMember()) {
161 const MemberPointerInfo &MI = Ptr.getMemberInfo();
162
163 StringRef Pointee = Types.getTypeName(Ptr.getReferentType());
164 StringRef Class = Types.getTypeName(MI.getContainingType());
165 Name = formatv("{0} {1}::*", Pointee, Class);
166 } else {
167 if (Ptr.isConst())
168 Name.append("const ");
169 if (Ptr.isVolatile())
170 Name.append("volatile ");
171 if (Ptr.isUnaligned())
172 Name.append("__unaligned ");
173
174 Name.append(Types.getTypeName(Ptr.getReferentType()));
175
176 if (Ptr.getMode() == PointerMode::LValueReference)
177 Name.append("&");
178 else if (Ptr.getMode() == PointerMode::RValueReference)
179 Name.append("&&");
180 else if (Ptr.getMode() == PointerMode::Pointer)
181 Name.append("*");
182 }
183 return Error::success();
184 }
185
186 Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
187 uint16_t Mods = static_cast(Mod.getModifiers());
188
189 SmallString<256> TypeName;
190 if (Mods & uint16_t(ModifierOptions::Const))
191 Name.append("const ");
192 if (Mods & uint16_t(ModifierOptions::Volatile))
193 Name.append("volatile ");
194 if (Mods & uint16_t(ModifierOptions::Unaligned))
195 Name.append("__unaligned ");
196 Name.append(Types.getTypeName(Mod.getModifiedType()));
197 return Error::success();
198 }
199
200 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
201 VFTableShapeRecord &Shape) {
202 Name = formatv("", Shape.getEntryCount());
203 return Error::success();
204 }
205
206 Error TypeNameComputer::visitKnownRecord(
207 CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
208 return Error::success();
209 }
210
211 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
212 UdtSourceLineRecord &SourceLine) {
213 return Error::success();
214 }
215
216 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
217 return Error::success();
218 }
219
220 Error TypeNameComputer::visitKnownRecord(CVType &CVR,
221 MethodOverloadListRecord &Overloads) {
222 return Error::success();
223 }
224
225 Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
226 return Error::success();
227 }
228
229 Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
230 return Error::success();
231 }
232
233 std::string llvm::codeview::computeTypeName(TypeCollection &Types,
234 TypeIndex Index) {
235 TypeNameComputer Computer(Types);
236 CVType Record = Types.getType(Index);
237 if (auto EC = visitTypeRecord(Record, Index, Computer)) {
238 consumeError(std::move(EC));
239 return "";
240 }
241 return Computer.name();
242 }
350350 for (auto &I : enumerate(IndicesToVisit))
351351 EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
352352 }
353
354 TEST_F(RandomAccessVisitorTest, CrossChunkName) {
355 TypeTableBuilder Builder(GlobalState->Allocator);
356
357 // TypeIndex 0
358 ClassRecord Class(TypeRecordKind::Class);
359 Class.Name = "FooClass";
360 Class.Options = ClassOptions::None;
361 Class.MemberCount = 0;
362 Class.DerivationList = TypeIndex::fromArrayIndex(0);
363 Class.FieldList = TypeIndex::fromArrayIndex(0);
364 Class.VTableShape = TypeIndex::fromArrayIndex(0);
365 TypeIndex IndexZero = Builder.writeKnownType(Class);
366
367 // TypeIndex 1 refers to type index 0.
368 ModifierRecord Modifier(TypeRecordKind::Modifier);
369 Modifier.ModifiedType = TypeIndex::fromArrayIndex(0);
370 Modifier.Modifiers = ModifierOptions::Const;
371 TypeIndex IndexOne = Builder.writeKnownType(Modifier);
372
373 // set up a type stream that refers to the above two serialized records.
374 std::vector TypeArray;
375 TypeArray.push_back(
376 CVType(static_cast(Class.Kind), Builder.records()[0]));
377 TypeArray.push_back(
378 CVType(static_cast(Modifier.Kind), Builder.records()[1]));
379 BinaryItemStream ItemStream(llvm::support::little);
380 ItemStream.setItems(TypeArray);
381 VarStreamArray TypeStream(ItemStream);
382
383 // Figure out the byte offset of the second item.
384 auto ItemOneIter = TypeStream.begin();
385 ++ItemOneIter;
386
387 // Set up a partial offsets buffer that contains the first and second items
388 // in separate chunks.
389 std::vector TIO;
390 TIO.push_back({IndexZero, ulittle32_t(0u)});
391 TIO.push_back({IndexOne, ulittle32_t(ItemOneIter.offset())});
392 ArrayRef Buffer(reinterpret_cast(TIO.data()),
393 TIO.size() * sizeof(TypeIndexOffset));
394
395 BinaryStreamReader Reader(Buffer, llvm::support::little);
396 FixedStreamArray PartialOffsets;
397 ASSERT_THAT_ERROR(Reader.readArray(PartialOffsets, 2), Succeeded());
398
399 LazyRandomTypeCollection Types(TypeStream, 2, PartialOffsets);
400
401 StringRef Name = Types.getTypeName(IndexOne);
402 EXPECT_EQ("const FooClass", Name);
403 }