llvm.org GIT mirror llvm / 80e0f20
Fix pdb-diff test. A test was checked in on Friday that worked by checking in an object file and PDB generated locally by MSVC, and then having the test run lld-link on the object file and diffing LLD's PDB against the checked in PDB. This failed because part of the diffing algorithm involves determining if two modules are the same, and if so drilling into the module and diffing individual fields of the module. The only thing we can use to make this determination though is the "name" of the module, which is a path to where the module (obj file) was read from on the machine where it was linked. This fails for obvious reasons when comparing a PDB generated on one machine to a PDB on another machine. The fix employed here is to add two command line options to the diff subcommand, which allow the user to specify a "binary root path". The bin root path, if specified, is stripped from the beginning of any embedded PDB paths. The test is updated to specify the user's local test output directory for the left PDB, and is hardcoded to the location where the original PDB was created for the right PDB. This way all the equivalence comparisons should succeed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@307555 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 3 years ago
7 changed file(s) with 291 addition(s) and 149 deletion(s). Raw diff Collapse all Expand all
2222 #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
2323 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
2424
25 #include "llvm/Support/FileSystem.h"
2526 #include "llvm/Support/FormatAdapters.h"
2627 #include "llvm/Support/FormatProviders.h"
2728 #include "llvm/Support/FormatVariadic.h"
29 #include "llvm/Support/Path.h"
2830
2931 using namespace llvm;
3032 using namespace llvm::pdb;
33
34 namespace {
35 // Compare and format two stream numbers. Stream numbers are considered
36 // identical if they contain the same value, equivalent if they are both
37 // the invalid stream or neither is the invalid stream, and different if
38 // one is the invalid stream and another isn't.
39 struct StreamNumberProvider {
40 static DiffResult compare(uint16_t L, uint16_t R) {
41 if (L == R)
42 return DiffResult::IDENTICAL;
43 bool LP = L != kInvalidStreamIndex;
44 bool RP = R != kInvalidStreamIndex;
45 if (LP != RP)
46 return DiffResult::DIFFERENT;
47 return DiffResult::EQUIVALENT;
48 }
49
50 static std::string format(uint16_t SN, bool Right) {
51 if (SN == kInvalidStreamIndex)
52 return "(not present)";
53 return formatv("{0}", SN).str();
54 }
55 };
56
57 // Compares and formats two module indices. Modis are considered identical
58 // if they are identical, equivalent if they either both contain a value or
59 // both don't contain a value, and different if one contains a value and the
60 // other doesn't.
61 struct ModiProvider {
62 DiffResult compare(Optional L, Optional R) {
63 if (L == R)
64 return DiffResult::IDENTICAL;
65 if (L.hasValue() != R.hasValue())
66 return DiffResult::DIFFERENT;
67 return DiffResult::EQUIVALENT;
68 }
69
70 std::string format(Optional Modi, bool Right) {
71 if (!Modi.hasValue())
72 return "(not present)";
73 return formatv("{0}", *Modi).str();
74 }
75 };
76
77 // Compares and formats two paths embedded in the PDB, ignoring the beginning
78 // of the path if the user specified it as a "root path" on the command line.
79 struct BinaryPathProvider {
80 explicit BinaryPathProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
81
82 DiffResult compare(StringRef L, StringRef R) {
83 if (L == R)
84 return DiffResult::IDENTICAL;
85
86 SmallString<64> LN = removeRoot(L, false);
87 SmallString<64> RN = removeRoot(R, true);
88
89 return (LN.equals_lower(RN)) ? DiffResult::EQUIVALENT
90 : DiffResult::DIFFERENT;
91 }
92
93 std::string format(StringRef S, bool Right) {
94 if (S.empty())
95 return "(empty)";
96
97 SmallString<64> Native = removeRoot(S, Right);
98 return truncateStringFront(Native.str(), MaxLen);
99 }
100
101 SmallString<64> removeRoot(StringRef Path, bool IsRight) const {
102 SmallString<64> Native(Path);
103 SmallString<64> Root =
104 IsRight ? opts::diff::RightRoot : opts::diff::LeftRoot;
105 // pdb paths always use windows syntax, convert slashes to backslashes.
106 sys::path::native(Root, sys::path::Style::windows);
107 if (sys::path::has_stem(Root, sys::path::Style::windows))
108 sys::path::append(Root,
109 sys::path::get_separator(sys::path::Style::windows));
110
111 sys::path::replace_path_prefix(Native, Root, "");
112 return Native;
113 }
114 uint32_t MaxLen;
115 };
116
117 // Compare and format two stream purposes. For general streams, this just
118 // compares the description. For module streams it uses the path comparison
119 // algorithm taking into consideration the binary root, described above.
120 // Formatting stream purposes just prints the stream purpose, except for
121 // module streams and named streams, where it prefixes the name / module
122 // with an identifier. Example:
123 //
124 // Named Stream "\names"
125 // Module Stream "foo.obj"
126 //
127 // If a named stream is too long to fit in a column, it is truncated at the
128 // end, and if a module is too long to fit in a column, it is truncated at the
129 // beginning. Example:
130 //
131 // Named Stream "\Really Long Str..."
132 // Module Stream "...puts\foo.obj"
133 //
134 struct StreamPurposeProvider {
135 explicit StreamPurposeProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
136
137 DiffResult compare(const std::pair &L,
138 const std::pair &R) {
139 if (L.first != R.first)
140 return DiffResult::DIFFERENT;
141 if (L.first == StreamPurpose::ModuleStream) {
142 BinaryPathProvider PathProvider(MaxLen);
143 return PathProvider.compare(L.second, R.second);
144 }
145 return (L.second == R.second) ? DiffResult::IDENTICAL
146 : DiffResult::DIFFERENT;
147 }
148
149 std::string format(const std::pair &P,
150 bool Right) {
151 if (P.first == StreamPurpose::Other)
152 return truncateStringBack(P.second, MaxLen);
153 if (P.first == StreamPurpose::NamedStream)
154 return truncateQuotedNameBack("Named Stream", P.second, MaxLen);
155
156 assert(P.first == StreamPurpose::ModuleStream);
157 uint32_t ExtraChars = strlen("Module \"\"");
158 BinaryPathProvider PathProvider(MaxLen - ExtraChars);
159 std::string Result = PathProvider.format(P.second, Right);
160 return formatv("Module \"{0}\"", Result);
161 }
162
163 uint32_t MaxLen;
164 };
165 }
31166
32167 namespace llvm {
33168 template <> struct format_provider {
99234 return Error::success();
100235 }
101236
102 static std::string shortFilePath(StringRef Path, uint32_t Width) {
103 if (Path.size() <= Width)
104 return Path;
105 Path = Path.take_back(Width - 3);
106 return std::string("...") + Path.str();
107 }
108
109237 Error DiffStyle::diffSuperBlock() {
110238 DiffPrinter D(2, "MSF Super Block", 16, 20, opts::diff::PrintResultColumn,
111239 opts::diff::PrintValueColumns, outs());
112240 D.printExplicit("File", DiffResult::UNSPECIFIED,
113 shortFilePath(File1.getFilePath(), 18),
114 shortFilePath(File2.getFilePath(), 18));
241 truncateStringFront(File1.getFilePath(), 18),
242 truncateStringFront(File2.getFilePath(), 18));
115243 D.print("Block Size", File1.getBlockSize(), File2.getBlockSize());
116244 D.print("Block Count", File1.getBlockCount(), File2.getBlockCount());
117245 D.print("Unknown 1", File1.getUnknown1(), File2.getUnknown1());
124252 DiffPrinter D(2, "Stream Directory", 30, 20, opts::diff::PrintResultColumn,
125253 opts::diff::PrintValueColumns, outs());
126254 D.printExplicit("File", DiffResult::UNSPECIFIED,
127 shortFilePath(File1.getFilePath(), 18),
128 shortFilePath(File2.getFilePath(), 18));
129
130 SmallVector P;
131 SmallVector Q;
132 discoverStreamPurposes(File1, P, 28);
133 discoverStreamPurposes(File2, Q, 28);
255 truncateStringFront(File1.getFilePath(), 18),
256 truncateStringFront(File2.getFilePath(), 18));
257
258 SmallVector, 32> P;
259 SmallVector, 32> Q;
260 discoverStreamPurposes(File1, P);
261 discoverStreamPurposes(File2, Q);
134262 D.print("Stream Count", File1.getNumStreams(), File2.getNumStreams());
135263 auto PI = to_vector<32>(enumerate(P));
136264 auto QI = to_vector<32>(enumerate(Q));
138266 // Scan all streams in the left hand side, looking for ones that are also
139267 // in the right. Each time we find one, remove it. When we're done, Q
140268 // should contain all the streams that are in the right but not in the left.
269 StreamPurposeProvider StreamProvider(28);
141270 for (const auto &P : PI) {
142271 typedef decltype(PI) ContainerType;
143272 typedef typename ContainerType::value_type value_type;
144273
145 auto Iter = llvm::find_if(
146 QI, [P](const value_type &V) { return V.value() == P.value(); });
274 auto Iter = llvm::find_if(QI, [P, &StreamProvider](const value_type &V) {
275 DiffResult Result = StreamProvider.compare(P.value(), V.value());
276 return Result == DiffResult::EQUIVALENT ||
277 Result == DiffResult::IDENTICAL;
278 });
147279
148280 if (Iter == QI.end()) {
149 D.printExplicit(P.value(), DiffResult::DIFFERENT, P.index(),
150 "(not present)");
281 D.printExplicit(StreamProvider.format(P.value(), false),
282 DiffResult::DIFFERENT, P.index(), "(not present)");
151283 continue;
152284 }
153285
154 D.print(P.value(), P.index(), Iter->index());
286 D.print(StreamProvider.format(P.value(), false),
287 P.index(), Iter->index());
155288 QI.erase(Iter);
156289 }
157290
158291 for (const auto &Q : QI) {
159 D.printExplicit(Q.value(), DiffResult::DIFFERENT, "(not present)",
160 Q.index());
292 D.printExplicit(StreamProvider.format(Q.value(), true),
293 DiffResult::DIFFERENT, "(not present)", Q.index());
161294 }
162295
163296 return Error::success();
167300 DiffPrinter D(2, "String Table", 30, 20, opts::diff::PrintResultColumn,
168301 opts::diff::PrintValueColumns, outs());
169302 D.printExplicit("File", DiffResult::UNSPECIFIED,
170 shortFilePath(File1.getFilePath(), 18),
171 shortFilePath(File2.getFilePath(), 18));
303 truncateStringFront(File1.getFilePath(), 18),
304 truncateStringFront(File2.getFilePath(), 18));
172305
173306 auto ExpectedST1 = File1.getStringTable();
174307 auto ExpectedST2 = File2.getStringTable();
256389 DiffPrinter D(2, "PDB Stream", 22, 40, opts::diff::PrintResultColumn,
257390 opts::diff::PrintValueColumns, outs());
258391 D.printExplicit("File", DiffResult::UNSPECIFIED,
259 shortFilePath(File1.getFilePath(), 38),
260 shortFilePath(File2.getFilePath(), 38));
392 truncateStringFront(File1.getFilePath(), 38),
393 truncateStringFront(File2.getFilePath(), 38));
261394
262395 auto ExpectedInfo1 = File1.getPDBInfoStream();
263396 auto ExpectedInfo2 = File2.getPDBInfoStream();
291424 return Error::success();
292425 }
293426
294 struct StreamNumberProvider {
295 static DiffResult compare(uint16_t L, uint16_t R) {
296 if (L == R)
297 return DiffResult::IDENTICAL;
298 bool LP = L != kInvalidStreamIndex;
299 bool RP = R != kInvalidStreamIndex;
300 if (LP != RP)
301 return DiffResult::DIFFERENT;
302 return DiffResult::EQUIVALENT;
303 }
304
305 static std::string format(uint16_t SN) {
306 if (SN == kInvalidStreamIndex)
307 return "(not present)";
308 return formatv("{0}", SN).str();
309 }
310 };
311
312 struct ModiProvider {
313 DiffResult compare(Optional L, Optional R) {
314 if (L == R)
315 return DiffResult::IDENTICAL;
316 if (L.hasValue() != R.hasValue())
317 return DiffResult::DIFFERENT;
318 return DiffResult::EQUIVALENT;
319 }
320
321 std::string format(Optional Modi) {
322 if (!Modi.hasValue())
323 return "(not present)";
324 return formatv("{0}", *Modi).str();
325 }
326 };
327
328 struct StringProvider {
329 DiffResult compare(StringRef L, StringRef R) {
330 IdenticalDiffProvider I;
331 return I.compare(L, R);
332 }
333
334 std::string format(StringRef S) {
335 if (S.empty())
336 return "(empty)";
337 return S;
338 }
339 };
340
341427 static std::vector>
342428 getModuleDescriptors(const DbiModuleList &ML) {
343429 std::vector> List;
347433 return List;
348434 }
349435
350 static void diffOneModule(
351 DiffPrinter &D, const std::pair Item,
352 std::vector> &Other, bool Invert) {
353 D.printFullRow(
354 truncateQuotedNameFront("Module", Item.second.getModuleName(), 70));
355
436 static void
437 diffOneModule(DiffPrinter &D,
438 const std::pair Item,
439 std::vector> &Other,
440 bool ItemIsRight) {
441 StreamPurposeProvider HeaderProvider(70);
442 std::pair Header;
443 Header.first = StreamPurpose::ModuleStream;
444 Header.second = Item.second.getModuleName();
445 D.printFullRow(HeaderProvider.format(Header, ItemIsRight));
446
447 const auto *L = &Item;
448
449 BinaryPathProvider PathProvider(28);
356450 auto Iter = llvm::find_if(
357 Other, [&Item](const std::pair &Other) {
358 return Other.second.getModuleName().equals_lower(
359 Item.second.getModuleName());
451 Other, [&Item, &PathProvider, ItemIsRight,
452 L](const std::pair &Other) {
453 const auto *Left = L;
454 const auto *Right = &Other;
455 if (ItemIsRight)
456 std::swap(Left, Right);
457 DiffResult Result = PathProvider.compare(Left->second.getModuleName(),
458 Right->second.getModuleName());
459 return Result == DiffResult::EQUIVALENT ||
460 Result == DiffResult::IDENTICAL;
360461 });
361462 if (Iter == Other.end()) {
362463 // We didn't find this module at all on the other side. Just print one row
366467 }
367468
368469 // We did find this module. Go through and compare each field.
369 const auto *L = &Item;
370470 const auto *R = &*Iter;
371 if (Invert)
471 if (ItemIsRight)
372472 std::swap(L, R);
373473
374474 D.print("- Modi", L->first, R->first);
375 D.print("- Obj File Name",
376 shortFilePath(L->second.getObjFileName(), 28),
377 shortFilePath(R->second.getObjFileName(), 28));
475 D.print("- Obj File Name", L->second.getObjFileName(),
476 R->second.getObjFileName(), PathProvider);
378477 D.print("- Debug Stream",
379478 L->second.getModuleStreamIndex(),
380479 R->second.getModuleStreamIndex());
397496 DiffPrinter D(2, "DBI Stream", 40, 30, opts::diff::PrintResultColumn,
398497 opts::diff::PrintValueColumns, outs());
399498 D.printExplicit("File", DiffResult::UNSPECIFIED,
400 shortFilePath(File1.getFilePath(), 28),
401 shortFilePath(File2.getFilePath(), 28));
499 truncateStringFront(File1.getFilePath(), 28),
500 truncateStringFront(File2.getFilePath(), 28));
402501
403502 auto ExpectedDbi1 = File1.getPDBDbiStream();
404503 auto ExpectedDbi2 = File2.getPDBDbiStream();
55 using namespace llvm;
66 using namespace llvm::pdb;
77
8 static void setColor(llvm::raw_ostream &OS, DiffResult Result) {
9 switch (Result) {
10 case DiffResult::IDENTICAL:
11 OS.changeColor(raw_ostream::Colors::GREEN, false);
12 break;
13 case DiffResult::EQUIVALENT:
14 OS.changeColor(raw_ostream::Colors::YELLOW, true);
15 break;
16 default:
17 OS.changeColor(raw_ostream::Colors::RED, false);
18 break;
8 namespace {
9 struct Colorize {
10 Colorize(raw_ostream &OS, DiffResult Result) : OS(OS) {
11 if (!OS.has_colors())
12 return;
13 switch (Result) {
14 case DiffResult::IDENTICAL:
15 OS.changeColor(raw_ostream::Colors::GREEN, false);
16 break;
17 case DiffResult::EQUIVALENT:
18 OS.changeColor(raw_ostream::Colors::YELLOW, true);
19 break;
20 default:
21 OS.changeColor(raw_ostream::Colors::RED, false);
22 break;
23 }
1924 }
25
26 ~Colorize() {
27 if (OS.has_colors())
28 OS.resetColor();
29 }
30
31 raw_ostream &OS;
32 };
2033 }
2134
2235 DiffPrinter::DiffPrinter(uint32_t Indent, StringRef Header,
123136 std::string FormattedItem =
124137 formatv("{0}", fmt_align(Value, Style, Width)).str();
125138 if (C != DiffResult::UNSPECIFIED) {
126 setColor(OS, C);
139 Colorize Color(OS, C);
127140 OS << FormattedItem;
128 OS.resetColor();
129141 } else
130142 OS << FormattedItem;
131143 if (Style == AlignStyle::Right)
4242 return (Left == Right) ? DiffResult::IDENTICAL : DiffResult::DIFFERENT;
4343 }
4444
45 template std::string format(const T &Item) {
45 template std::string format(const T &Item, bool Right) {
4646 return formatv("{0}", Item).str();
4747 }
4848 };
5353 return (Left == Right) ? DiffResult::IDENTICAL : DiffResult::EQUIVALENT;
5454 }
5555
56 template std::string format(const T &Item) {
56 template std::string format(const T &Item, bool Right) {
5757 return formatv("{0}", Item).str();
5858 }
5959 };
7070 template
7171 void print(StringRef Property, const T &Left, const U &Right,
7272 Provider P = Provider()) {
73 std::string L = P.format(Left);
74 std::string R = P.format(Right);
73 std::string L = P.format(Left, false);
74 std::string R = P.format(Right, true);
7575
7676 DiffResult Result = P.compare(Left, Right);
7777 printExplicit(Property, Result, L, R);
2121 using namespace llvm;
2222 using namespace llvm::pdb;
2323
24 void llvm::pdb::discoverStreamPurposes(PDBFile &File,
25 SmallVectorImpl &Purposes,
26 uint32_t MaxLen) {
27
24 void llvm::pdb::discoverStreamPurposes(
25 PDBFile &File,
26 SmallVectorImpl> &Purposes) {
2827 // It's OK if we fail to load some of these streams, we still attempt to print
2928 // what we can.
3029 auto Dbi = File.getPDBDbiStream();
5453
5554 Purposes.resize(StreamCount);
5655 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
57 std::string Value;
56 std::pair Value;
5857 if (StreamIdx == OldMSFDirectory)
59 Value = truncateStringBack("Old MSF Directory", MaxLen);
58 Value = std::make_pair(StreamPurpose::Other, "Old MSF Directory");
6059 else if (StreamIdx == StreamPDB)
61 Value = truncateStringBack("PDB Stream", MaxLen);
60 Value = std::make_pair(StreamPurpose::Other, "PDB Stream");
6261 else if (StreamIdx == StreamDBI)
63 Value = truncateStringBack("DBI Stream", MaxLen);
62 Value = std::make_pair(StreamPurpose::Other, "DBI Stream");
6463 else if (StreamIdx == StreamTPI)
65 Value = truncateStringBack("TPI Stream", MaxLen);
64 Value = std::make_pair(StreamPurpose::Other, "TPI Stream");
6665 else if (StreamIdx == StreamIPI)
67 Value = truncateStringBack("IPI Stream", MaxLen);
66 Value = std::make_pair(StreamPurpose::Other, "IPI Stream");
6867 else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
69 Value = truncateStringBack("Global Symbol Hash", MaxLen);
68 Value = std::make_pair(StreamPurpose::Other, "Global Symbol Hash");
7069 else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
71 Value = truncateStringBack("Public Symbol Hash", MaxLen);
70 Value = std::make_pair(StreamPurpose::Other, "Public Symbol Hash");
7271 else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
73 Value = truncateStringBack("Public Symbol Records", MaxLen);
72 Value = std::make_pair(StreamPurpose::Other, "Public Symbol Records");
7473 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
75 Value = truncateStringBack("TPI Hash", MaxLen);
74 Value = std::make_pair(StreamPurpose::Other, "TPI Hash");
7675 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
77 Value = truncateStringBack("TPI Aux Hash", MaxLen);
76 Value = std::make_pair(StreamPurpose::Other, "TPI Aux Hash");
7877 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
79 Value = truncateStringBack("IPI Hash", MaxLen);
78 Value = std::make_pair(StreamPurpose::Other, "IPI Hash");
8079 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
81 Value = truncateStringBack("IPI Aux Hash", MaxLen);
80 Value = std::make_pair(StreamPurpose::Other, "IPI Aux Hash");
8281 else if (Dbi &&
8382 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
84 Value = truncateStringBack("Exception Data", MaxLen);
83 Value = std::make_pair(StreamPurpose::Other, "Exception Data");
8584 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
86 Value = truncateStringBack("Fixup Data", MaxLen);
85 Value = std::make_pair(StreamPurpose::Other, "Fixup Data");
8786 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
88 Value = truncateStringBack("FPO Data", MaxLen);
87 Value = std::make_pair(StreamPurpose::Other, "FPO Data");
8988 else if (Dbi &&
9089 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
91 Value = truncateStringBack("New FPO Data", MaxLen);
90 Value = std::make_pair(StreamPurpose::Other, "New FPO Data");
9291 else if (Dbi &&
9392 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
94 Value = truncateStringBack("Omap From Source Data", MaxLen);
93 Value = std::make_pair(StreamPurpose::Other, "Omap From Source Data");
9594 else if (Dbi &&
9695 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
97 Value = truncateStringBack("Omap To Source Data", MaxLen);
96 Value = std::make_pair(StreamPurpose::Other, "Omap To Source Data");
9897 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
99 Value = truncateStringBack("Pdata", MaxLen);
98 Value = std::make_pair(StreamPurpose::Other, "Pdata");
10099 else if (Dbi &&
101100 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
102 Value = truncateStringBack("Section Header Data", MaxLen);
101 Value = std::make_pair(StreamPurpose::Other, "Section Header Data");
103102 else if (Dbi &&
104103 StreamIdx ==
105104 Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
106 Value = truncateStringBack("Section Header Original Data", MaxLen);
105 Value =
106 std::make_pair(StreamPurpose::Other, "Section Header Original Data");
107107 else if (Dbi &&
108108 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
109 Value = truncateStringBack("Token Rid Data", MaxLen);
109 Value = std::make_pair(StreamPurpose::Other, "Token Rid Data");
110110 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
111 Value = truncateStringBack("Xdata", MaxLen);
111 Value = std::make_pair(StreamPurpose::Other, "Xdata");
112112 else {
113113 auto ModIter = ModStreams.find(StreamIdx);
114114 auto NSIter = NamedStreams.find(StreamIdx);
115115 if (ModIter != ModStreams.end()) {
116 Value = truncateQuotedNameFront(
117 "Module", ModIter->second.getModuleName(), MaxLen);
116 Value = std::make_pair(StreamPurpose::ModuleStream,
117 ModIter->second.getModuleName());
118118 } else if (NSIter != NamedStreams.end()) {
119 Value = truncateQuotedNameBack("Named Stream", NSIter->second, MaxLen);
119 Value = std::make_pair(StreamPurpose::NamedStream, NSIter->second);
120120 } else {
121 Value = "???";
121 Value = std::make_pair(StreamPurpose::Other, "???");
122122 }
123123 }
124124 Purposes[StreamIdx] = Value;
134134 if (!Info)
135135 consumeError(Info.takeError());
136136 }
137
138 void llvm::pdb::discoverStreamPurposes(PDBFile &File,
139 SmallVectorImpl &Purposes) {
140 SmallVector, 24> SP;
141 discoverStreamPurposes(File, SP);
142 Purposes.reserve(SP.size());
143 for (const auto &P : SP) {
144 if (P.first == StreamPurpose::NamedStream)
145 Purposes.push_back(formatv("Named Stream \"{0}\"", P.second));
146 else if (P.first == StreamPurpose::ModuleStream)
147 Purposes.push_back(formatv("Module \"{0}\"", P.second));
148 else
149 Purposes.push_back(P.second);
150 }
151 }
1616 namespace llvm {
1717 namespace pdb {
1818 class PDBFile;
19 enum class StreamPurpose { NamedStream, ModuleStream, Other };
20
1921 void discoverStreamPurposes(PDBFile &File,
20 SmallVectorImpl &Purposes,
21 uint32_t MaxLen = 0);
22 SmallVectorImpl &Purposes);
23 void discoverStreamPurposes(
24 PDBFile &File,
25 SmallVectorImpl> &Purposes);
2226 }
2327 }
2428
292292 cl::desc("Print a column with the result status"),
293293 cl::Optional, cl::sub(DiffSubcommand));
294294
295 cl::list InputFilenames(cl::Positional,
296 cl::desc(" "),
297 cl::OneOrMore, cl::sub(DiffSubcommand));
295 cl::opt LeftRoot(
296 "left-bin-root", cl::Optional,
297 cl::desc("Treats the specified path as the root of the tree containing "
298 "binaries referenced by the left PDB. The root is stripped from "
299 "embedded paths when doing equality comparisons."),
300 cl::sub(DiffSubcommand));
301 cl::opt RightRoot(
302 "right-bin-root", cl::Optional,
303 cl::desc("Treats the specified path as the root of the tree containing "
304 "binaries referenced by the right PDB. The root is stripped from "
305 "embedded paths when doing equality comparisons"),
306 cl::sub(DiffSubcommand));
307
308 cl::opt Left(cl::Positional, cl::desc(""),
309 cl::sub(DiffSubcommand));
310 cl::opt Right(cl::Positional, cl::desc(""),
311 cl::sub(DiffSubcommand));
298312 }
299313
300314 cl::OptionCategory FileOptions("Module & File Options");
11501164 std::for_each(opts::bytes::InputFilenames.begin(),
11511165 opts::bytes::InputFilenames.end(), dumpBytes);
11521166 } else if (opts::DiffSubcommand) {
1153 if (opts::diff::InputFilenames.size() != 2) {
1154 errs() << "diff subcommand expects exactly 2 arguments.\n";
1155 exit(1);
1156 }
1157 diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]);
1167 diff(opts::diff::Left, opts::diff::Right);
11581168 } else if (opts::MergeSubcommand) {
11591169 if (opts::merge::InputFilenames.size() < 2) {
11601170 errs() << "merge subcommand requires at least 2 input files.\n";
171171 namespace diff {
172172 extern llvm::cl::opt PrintValueColumns;
173173 extern llvm::cl::opt PrintResultColumn;
174 extern llvm::cl::opt LeftRoot;
175 extern llvm::cl::opt RightRoot;
174176 } // namespace diff
175177 }
176178