llvm.org GIT mirror llvm / 119b4ed
Resubmit "Support embedding natvis files in PDBs." The issue causing this to fail in certain configurations should be fixed. It was due to the fact that DIA apparently expects there to be a null string at ID 1 in the string table. I'm not sure why this is important but it seems to make a difference, so set it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@328002 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 1 year, 6 months ago
19 changed file(s) with 310 addition(s) and 43 deletion(s). Raw diff Collapse all Expand all
99 #ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGSTRINGTABLESUBSECTION_H
1010 #define LLVM_DEBUGINFO_CODEVIEW_DEBUGSTRINGTABLESUBSECTION_H
1111
12 #include "llvm/ADT/DenseMap.h"
1213 #include "llvm/ADT/StringMap.h"
1314 #include "llvm/ADT/StringRef.h"
1415 #include "llvm/DebugInfo/CodeView/CodeView.h"
6566 uint32_t insert(StringRef S);
6667
6768 // Return the ID for string S. Assumes S exists in the table.
68 uint32_t getStringId(StringRef S) const;
69 uint32_t getIdForString(StringRef S) const;
70
71 StringRef getStringForId(uint32_t Id) const;
6972
7073 uint32_t calculateSerializedSize() const override;
7174 Error commit(BinaryStreamWriter &Writer) const override;
7275
7376 uint32_t size() const;
7477
75 StringMap::const_iterator begin() const { return Strings.begin(); }
78 StringMap::const_iterator begin() const {
79 return StringToId.begin();
80 }
7681
77 StringMap::const_iterator end() const { return Strings.end(); }
82 StringMap::const_iterator end() const { return StringToId.end(); }
7883
7984 private:
80 StringMap Strings;
85 DenseMap IdToString;
86 StringMap StringToId;
8187 uint32_t StringSize = 1;
8288 };
8389
1818
1919 class DIAInjectedSource : public IPDBInjectedSource {
2020 public:
21 explicit DIAInjectedSource(const DIASession &Session,
22 CComPtr DiaSourceFile);
21 explicit DIAInjectedSource(CComPtr DiaSourceFile);
2322
2423 uint32_t getCrc32() const override;
2524 uint64_t getCodeByteSize() const override;
3029 std::string getCode() const override;
3130
3231 private:
33 const DIASession &Session;
3432 CComPtr SourceFile;
3533 };
3634 } // namespace pdb
212212 Deleted.clear();
213213 }
214214
215 bool empty() const { return size() == 0; }
215216 uint32_t capacity() const { return Buckets.size(); }
216217 uint32_t size() const { return Present.count(); }
217218
302303
303304 void grow() {
304305 uint32_t S = size();
306 uint32_t MaxLoad = maxLoad(capacity());
305307 if (S < maxLoad(capacity()))
306308 return;
307309 assert(capacity() != UINT32_MAX && "Can't grow Hash table!");
308310
309 uint32_t NewCapacity =
310 (capacity() <= INT32_MAX) ? capacity() * 2 : UINT32_MAX;
311 uint32_t NewCapacity = (capacity() <= INT32_MAX) ? MaxLoad * 2 : UINT32_MAX;
311312
312313 // Growing requires rebuilding the table and re-hashing every item. Make a
313314 // copy with a larger capacity, insert everything into the copy, then swap
1616 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
1717 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
1818 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
19 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
1920 #include "llvm/Support/Allocator.h"
2021 #include "llvm/Support/Endian.h"
2122 #include "llvm/Support/Error.h"
23 #include "llvm/Support/MemoryBuffer.h"
2224
2325 #include
2426 #include
5355 Error commit(StringRef Filename);
5456
5557 Expected getNamedStreamIndex(StringRef Name) const;
56 Error addNamedStream(StringRef Name, uint32_t Size);
58 Error addNamedStream(StringRef Name, StringRef Data);
59 void addInjectedSource(StringRef Name, std::unique_ptr Buffer);
5760
5861 private:
62 struct InjectedSourceDescriptor {
63 // The full name of the stream that contains the contents of this injected
64 // source. This is built as a concatenation of the literal "/src/files"
65 // plus the "vname".
66 std::string StreamName;
67
68 // The exact name of the file name as specified by the user.
69 uint32_t NameIndex;
70
71 // The string table index of the "vname" of the file. As far as we
72 // understand, this is the same as the name, except it is lowercased and
73 // forward slashes are converted to backslashes.
74 uint32_t VNameIndex;
75 std::unique_ptr Content;
76 };
77
5978 Expected finalizeMsfLayout();
79 Expected allocateNamedStream(StringRef Name, uint32_t Size);
6080
6181 void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout);
82 void commitInjectedSources(WritableBinaryStream &MsfBuffer,
83 const msf::MSFLayout &Layout);
84 void commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
85 const msf::MSFLayout &Layout);
6286
6387 BumpPtrAllocator &Allocator;
6488
7094 std::unique_ptr Ipi;
7195
7296 PDBStringTableBuilder Strings;
97 StringTableHashTraits InjectedSourceHashTraits;
98 HashTable InjectedSourceTable;
99
100 SmallVector InjectedSources;
101
73102 NamedStreamMap NamedStreams;
103 DenseMap NamedStreamData;
74104 };
75105 }
76106 }
3030 namespace pdb {
3131
3232 class PDBFileBuilder;
33 class PDBStringTableBuilder;
34
35 struct StringTableHashTraits {
36 PDBStringTableBuilder *Table;
37
38 explicit StringTableHashTraits(PDBStringTableBuilder &Table);
39 uint32_t hashLookupKey(StringRef S) const;
40 StringRef storageKeyToLookupKey(uint32_t Offset) const;
41 uint32_t lookupKeyToStorageKey(StringRef S);
42 };
3343
3444 class PDBStringTableBuilder {
3545 public:
3646 // If string S does not exist in the string table, insert it.
3747 // Returns the ID for S.
3848 uint32_t insert(StringRef S);
49
50 uint32_t getIdForString(StringRef S) const;
51 StringRef getStringForId(uint32_t Id) const;
3952
4053 uint32_t calculateSerializedSize() const;
4154 Error commit(BinaryStreamWriter &Writer) const;
3030 PdbImplVC110 = 20091201,
3131 PdbImplVC140 = 20140508,
3232 };
33
34 enum class PdbRaw_SrcHeaderBlockVer : uint32_t { SrcVerOne = 19980827 };
3335
3436 enum class PdbRaw_FeatureSig : uint32_t {
3537 VC110 = PdbImplVC110,
327327
328328 const uint32_t PDBStringTableSignature = 0xEFFEEFFE;
329329
330 /// The header preceding the /src/headerblock stream.
331 struct SrcHeaderBlockHeader {
332 support::ulittle32_t Version; // PdbRaw_SrcHeaderBlockVer enumeration.
333 support::ulittle32_t Size; // Size of entire stream.
334 uint64_t FileTime; // Time stamp (Windows FILETIME format).
335 support::ulittle32_t Age; // Age
336 uint8_t Padding[44]; // Pad to 64 bytes.
337 };
338 static_assert(sizeof(SrcHeaderBlockHeader) == 64, "Incorrect struct size!");
339
340 /// A single file record entry within the /src/headerblock stream.
341 struct SrcHeaderBlockEntry {
342 support::ulittle32_t Size; // Record Length.
343 support::ulittle32_t Version; // PdbRaw_SrcHeaderBlockVer enumeration.
344 support::ulittle32_t CRC; // CRC of the original file contents.
345 support::ulittle32_t FileSize; // Size of original source file.
346 support::ulittle32_t FileNI; // String table index of file name.
347 support::ulittle32_t ObjNI; // String table index of object name.
348 support::ulittle32_t VFileNI; // String table index of virtual file name.
349 uint8_t Compression; // PDB_SourceCompression enumeration.
350 uint8_t IsVirtual; // Is this a virtual file (injected)?
351 short Padding; // Pad to 4 bytes.
352 char Reserved[8];
353 };
354
355 constexpr int I = sizeof(SrcHeaderBlockEntry);
356 static_assert(sizeof(SrcHeaderBlockEntry) == 40, "Incorrect struct size!");
357
330358 } // namespace pdb
331359 } // namespace llvm
332360
108108 }
109109
110110 uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {
111 uint32_t Offset = Strings.getStringId(FileName);
111 uint32_t Offset = Strings.getIdForString(FileName);
112112 auto Iter = OffsetMap.find(Offset);
113113 assert(Iter != OffsetMap.end());
114114 return Iter->second;
7979 Ids.push_back(&M);
8080
8181 std::sort(Ids.begin(), Ids.end(), [this](const T &L1, const T &L2) {
82 return Strings.getStringId(L1->getKey()) <
83 Strings.getStringId(L2->getKey());
82 return Strings.getIdForString(L1->getKey()) <
83 Strings.getIdForString(L2->getKey());
8484 });
8585
8686 for (const auto &Item : Ids) {
8787 CrossModuleImport Imp;
88 Imp.ModuleNameOffset = Strings.getStringId(Item->getKey());
88 Imp.ModuleNameOffset = Strings.getIdForString(Item->getKey());
8989 Imp.Count = Item->getValue().size();
9090 if (auto EC = Writer.writeObject(Imp))
9191 return EC;
4545 : DebugSubsection(DebugSubsectionKind::StringTable) {}
4646
4747 uint32_t DebugStringTableSubsection::insert(StringRef S) {
48 auto P = Strings.insert({S, StringSize});
48 auto P = StringToId.insert({S, StringSize});
4949
5050 // If a given string didn't exist in the string table, we want to increment
51 // the string table size.
52 if (P.second)
51 // the string table size and insert it into the reverse lookup.
52 if (P.second) {
53 IdToString.insert({P.first->getValue(), P.first->getKey()});
5354 StringSize += S.size() + 1; // +1 for '\0'
55 }
56
5457 return P.first->second;
5558 }
5659
6669 if (auto EC = Writer.writeCString(StringRef()))
6770 return EC;
6871
69 for (auto &Pair : Strings) {
72 for (auto &Pair : StringToId) {
7073 StringRef S = Pair.getKey();
7174 uint32_t Offset = Begin + Pair.getValue();
7275 Writer.setOffset(Offset);
8083 return Error::success();
8184 }
8285
83 uint32_t DebugStringTableSubsection::size() const { return Strings.size(); }
86 uint32_t DebugStringTableSubsection::size() const { return StringToId.size(); }
8487
85 uint32_t DebugStringTableSubsection::getStringId(StringRef S) const {
86 auto Iter = Strings.find(S);
87 assert(Iter != Strings.end());
88 uint32_t DebugStringTableSubsection::getIdForString(StringRef S) const {
89 auto Iter = StringToId.find(S);
90 assert(Iter != StringToId.end());
8891 return Iter->second;
8992 }
93
94 StringRef DebugStringTableSubsection::getStringForId(uint32_t Id) const {
95 auto Iter = IdToString.find(Id);
96 assert(Iter != IdToString.end());
97 return Iter->second;
98 }
2929 if (S_OK != Enumerator->Item(Index, &Item))
3030 return nullptr;
3131
32 return std::unique_ptr(
33 new DIAInjectedSource(Session, Item));
32 return std::unique_ptr(new DIAInjectedSource(Item));
3433 }
3534
3635 std::unique_ptr DIAEnumInjectedSources::getNext() {
3938 if (S_OK != Enumerator->Next(1, &Item, &NumFetched))
4039 return nullptr;
4140
42 return std::unique_ptr(
43 new DIAInjectedSource(Session, Item));
41 return std::unique_ptr(new DIAInjectedSource(Item));
4442 }
4543
4644 void DIAEnumInjectedSources::reset() { Enumerator->Reset(); }
1515 using namespace llvm;
1616 using namespace llvm::pdb;
1717
18 DIAInjectedSource::DIAInjectedSource(const DIASession &Session,
19 CComPtr DiaSourceFile)
20 : Session(Session), SourceFile(DiaSourceFile) {}
18 DIAInjectedSource::DIAInjectedSource(CComPtr DiaSourceFile)
19 : SourceFile(DiaSourceFile) {}
2120
2221 uint32_t DIAInjectedSource::getCrc32() const {
2322 DWORD Crc;
7272 if (auto EC = Writer.writeEnum(E))
7373 return EC;
7474 }
75 assert(Writer.bytesRemaining() == 0);
7576 return Error::success();
7677 }
2323 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
2424 #include "llvm/Support/BinaryStream.h"
2525 #include "llvm/Support/BinaryStreamWriter.h"
26 #include "llvm/Support/JamCRC.h"
27 #include "llvm/Support/Path.h"
2628
2729 using namespace llvm;
2830 using namespace llvm::codeview;
3133 using namespace llvm::support;
3234
3335 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
34 : Allocator(Allocator) {}
36 : Allocator(Allocator), InjectedSourceHashTraits(Strings),
37 InjectedSourceTable(2, InjectedSourceHashTraits) {}
3538
3639 PDBFileBuilder::~PDBFileBuilder() {}
3740
7982 return *Gsi;
8083 }
8184
82 Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
85 Expected PDBFileBuilder::allocateNamedStream(StringRef Name,
86 uint32_t Size) {
8387 auto ExpectedStream = Msf->addStream(Size);
84 if (!ExpectedStream)
85 return ExpectedStream.takeError();
86 NamedStreams.set(Name, *ExpectedStream);
88 if (ExpectedStream)
89 NamedStreams.set(Name, *ExpectedStream);
90 return ExpectedStream;
91 }
92
93 Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
94 Expected ExpectedIndex = allocateNamedStream(Name, Data.size());
95 if (!ExpectedIndex)
96 return ExpectedIndex.takeError();
97 assert(NamedStreamData.count(*ExpectedIndex) == 0);
98 NamedStreamData[*ExpectedIndex] = Data;
8799 return Error::success();
100 }
101
102 void PDBFileBuilder::addInjectedSource(StringRef Name,
103 std::unique_ptr Buffer) {
104 // Stream names must be exact matches, since they get looked up in a hash
105 // table and the hash value is dependent on the exact contents of the string.
106 // link.exe lowercases a path and converts / to \, so we must do the same.
107 SmallString<64> VName;
108 sys::path::native(Name.lower(), VName);
109
110 uint32_t NI = getStringTableBuilder().insert(Name);
111 uint32_t VNI = getStringTableBuilder().insert(VName);
112
113 InjectedSourceDescriptor Desc;
114 Desc.Content = std::move(Buffer);
115 Desc.NameIndex = NI;
116 Desc.VNameIndex = VNI;
117 Desc.StreamName = "/src/files/";
118
119 Desc.StreamName += VName;
120
121 InjectedSources.push_back(std::move(Desc));
88122 }
89123
90124 Expected PDBFileBuilder::finalizeMsfLayout() {
100134
101135 uint32_t StringsLen = Strings.calculateSerializedSize();
102136
103 if (auto EC = addNamedStream("/names", StringsLen))
104 return std::move(EC);
105 if (auto EC = addNamedStream("/LinkInfo", 0))
106 return std::move(EC);
107
108 if (Info) {
109 if (auto EC = Info->finalizeMsfLayout())
110 return std::move(EC);
111 }
137 Expected SN = allocateNamedStream("/names", StringsLen);
138 if (!SN)
139 return SN.takeError();
140 SN = allocateNamedStream("/LinkInfo", 0);
141 if (!SN)
142 return SN.takeError();
143
112144 if (Dbi) {
113145 if (auto EC = Dbi->finalizeMsfLayout())
114146 return std::move(EC);
129161 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
130162 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
131163 }
164 }
165
166 if (!InjectedSources.empty()) {
167 for (const auto &IS : InjectedSources) {
168 JamCRC CRC(0);
169 CRC.update(makeArrayRef(IS.Content->getBufferStart(),
170 IS.Content->getBufferSize()));
171
172 SrcHeaderBlockEntry Entry;
173 ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
174 Entry.Size = sizeof(SrcHeaderBlockEntry);
175 Entry.FileSize = IS.Content->getBufferSize();
176 Entry.FileNI = IS.NameIndex;
177 Entry.VFileNI = IS.VNameIndex;
178 Entry.IsVirtual = 0;
179 Entry.Version =
180 static_cast(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
181 Entry.CRC = CRC.getCRC();
182 StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
183 InjectedSourceTable.set_as(VName, std::move(Entry));
184 }
185
186 uint32_t SrcHeaderBlockSize =
187 sizeof(SrcHeaderBlockHeader) +
188 InjectedSourceTable.calculateSerializedLength();
189 SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
190 if (!SN)
191 return SN.takeError();
192 for (const auto &IS : InjectedSources) {
193 SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
194 if (!SN)
195 return SN.takeError();
196 }
197 }
198
199 // Do this last, since it relies on the named stream map being complete, and
200 // that can be updated by previous steps in the finalization.
201 if (Info) {
202 if (auto EC = Info->finalizeMsfLayout())
203 return std::move(EC);
132204 }
133205
134206 return Msf->build();
166238 assert(FpmWriter.bytesRemaining() == 0);
167239 }
168240
241 void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
242 const msf::MSFLayout &Layout) {
243 assert(!InjectedSourceTable.empty());
244
245 uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
246 auto Stream = WritableMappedBlockStream::createIndexedStream(
247 Layout, MsfBuffer, SN, Allocator);
248 BinaryStreamWriter Writer(*Stream);
249
250 SrcHeaderBlockHeader Header;
251 ::memset(&Header, 0, sizeof(Header));
252 Header.Version = static_cast(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
253 Header.Size = Writer.bytesRemaining();
254
255 cantFail(Writer.writeObject(Header));
256 cantFail(InjectedSourceTable.commit(Writer));
257
258 assert(Writer.bytesRemaining() == 0);
259 }
260
261 void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
262 const msf::MSFLayout &Layout) {
263 if (InjectedSourceTable.empty())
264 return;
265
266 commitSrcHeaderBlock(MsfBuffer, Layout);
267
268 for (const auto &IS : InjectedSources) {
269 uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
270
271 auto SourceStream = WritableMappedBlockStream::createIndexedStream(
272 Layout, MsfBuffer, SN, Allocator);
273 BinaryStreamWriter SourceWriter(*SourceStream);
274 assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
275 cantFail(SourceWriter.writeBytes(
276 arrayRefFromStringRef(IS.Content->getBuffer())));
277 }
278 }
279
169280 Error PDBFileBuilder::commit(StringRef Filename) {
170281 assert(!Filename.empty());
171282 auto ExpectedLayout = finalizeMsfLayout();
218329 if (auto EC = Strings.commit(NSWriter))
219330 return EC;
220331
332 for (const auto &NSE : NamedStreamData) {
333 if (NSE.second.empty())
334 continue;
335
336 auto NS = WritableMappedBlockStream::createIndexedStream(
337 Layout, Buffer, NSE.first, Allocator);
338 BinaryStreamWriter NSW(*NS);
339 if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
340 return EC;
341 }
342
221343 if (Info) {
222344 if (auto EC = Info->commit(Layout, Buffer))
223345 return EC;
249371 blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
250372 InfoStreamHeader *H = reinterpret_cast(
251373 FOB->getBufferStart() + InfoStreamFileOffset);
374
375 commitInjectedSources(Buffer, Layout);
252376
253377 // Set the build id at the very end, after every other byte of the PDB
254378 // has been written.
2020 using namespace llvm::support::endian;
2121 using namespace llvm::pdb;
2222
23 StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table)
24 : Table(&Table) {}
25
26 uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const {
27 return Table->getIdForString(S);
28 }
29
30 StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const {
31 return Table->getStringForId(Offset);
32 }
33
34 uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) {
35 return Table->insert(S);
36 }
37
2338 uint32_t PDBStringTableBuilder::insert(StringRef S) {
2439 return Strings.insert(S);
40 }
41
42 uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const {
43 return Strings.getIdForString(S);
44 }
45
46 StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const {
47 return Strings.getStringForId(Id);
2548 }
2649
2750 static uint32_t computeBucketCount(uint32_t NumStrings) {
8989 P.NewLine();
9090 }
9191
92 if (opts::dump::DumpNamedStreams) {
93 if (auto EC = dumpNamedStreams())
94 return EC;
95 P.NewLine();
96 }
97
9298 if (opts::dump::DumpStringTable) {
9399 if (auto EC = dumpStringTable())
94100 return EC;
908914 return Error::success();
909915 }
910916
917 Error DumpOutputStyle::dumpNamedStreams() {
918 printHeader(P, "Named Streams");
919 AutoIndent Indent(P, 2);
920
921 if (File.isObj()) {
922 P.formatLine("Dumping Named Streams is only supported for PDB files.");
923 return Error::success();
924 }
925 ExitOnError Err("Invalid PDB File: ");
926
927 auto &IS = Err(File.pdb().getPDBInfoStream());
928 const NamedStreamMap &NS = IS.getNamedStreams();
929 for (const auto &Entry : NS.entries()) {
930 P.printLine(Entry.getKey());
931 AutoIndent Indent2(P, 2);
932 P.formatLine("Index: {0}", Entry.getValue());
933 P.formatLine("Size in bytes: {0}",
934 File.pdb().getStreamByteSize(Entry.getValue()));
935 }
936
937 return Error::success();
938 }
939
911940 Error DumpOutputStyle::dumpStringTable() {
912941 printHeader(P, "String Table");
913942
7373 Error dumpStreamSummary();
7474 Error dumpSymbolStats();
7575 Error dumpUdtStats();
76 Error dumpNamedStreams();
7677 Error dumpStringTable();
7778 Error dumpStringTableFromPdb();
7879 Error dumpStringTableFromObj();
533533 cl::cat(FileOptions), cl::sub(DumpSubcommand));
534534
535535 // MISCELLANEOUS OPTIONS
536 cl::opt DumpNamedStreams("named-streams",
537 cl::desc("dump PDB named stream table"),
538 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
539
536540 cl::opt DumpStringTable("string-table", cl::desc("dump PDB String Table"),
537541 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
538542
141141 extern llvm::cl::opt DumpInlineeLines;
142142 extern llvm::cl::opt DumpXmi;
143143 extern llvm::cl::opt DumpXme;
144 extern llvm::cl::opt DumpNamedStreams;
144145 extern llvm::cl::opt DumpStringTable;
145146 extern llvm::cl::opt DumpTypes;
146147 extern llvm::cl::opt DumpTypeData;