blob: fb52545df0f827c1e46db5dddaad47ed094cf02d [file] [log] [blame]
Zachary Turner6ac232c2017-03-13 23:28:25 +00001//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Diff.h"
11
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +000012#include "DiffPrinter.h"
13#include "FormatUtil.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000014#include "StreamUtil.h"
Zachary Turnerbd336e42017-06-09 20:46:17 +000015#include "llvm-pdbutil.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000016
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +000017#include "llvm/ADT/StringSet.h"
18
19#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
Zachary Turner02278ce2017-03-16 20:18:41 +000020#include "llvm/DebugInfo/PDB/Native/Formatters.h"
21#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000022#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
Zachary Turnere204a6c2017-05-02 18:00:13 +000023#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000024#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
25
Zachary Turnera9d944f2017-07-10 19:16:49 +000026#include "llvm/Support/FileSystem.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000027#include "llvm/Support/FormatAdapters.h"
Zachary Turner05d5e612017-03-16 20:19:11 +000028#include "llvm/Support/FormatProviders.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000029#include "llvm/Support/FormatVariadic.h"
Zachary Turnera9d944f2017-07-10 19:16:49 +000030#include "llvm/Support/Path.h"
Zachary Turner6ac232c2017-03-13 23:28:25 +000031
32using namespace llvm;
33using namespace llvm::pdb;
34
Zachary Turnera9d944f2017-07-10 19:16:49 +000035namespace {
36// Compare and format two stream numbers. Stream numbers are considered
37// identical if they contain the same value, equivalent if they are both
38// the invalid stream or neither is the invalid stream, and different if
39// one is the invalid stream and another isn't.
40struct StreamNumberProvider {
41 static DiffResult compare(uint16_t L, uint16_t R) {
42 if (L == R)
43 return DiffResult::IDENTICAL;
44 bool LP = L != kInvalidStreamIndex;
45 bool RP = R != kInvalidStreamIndex;
46 if (LP != RP)
47 return DiffResult::DIFFERENT;
48 return DiffResult::EQUIVALENT;
49 }
50
51 static std::string format(uint16_t SN, bool Right) {
52 if (SN == kInvalidStreamIndex)
53 return "(not present)";
54 return formatv("{0}", SN).str();
55 }
56};
57
58// Compares and formats two module indices. Modis are considered identical
59// if they are identical, equivalent if they either both contain a value or
60// both don't contain a value, and different if one contains a value and the
61// other doesn't.
62struct ModiProvider {
63 DiffResult compare(Optional<uint32_t> L, Optional<uint32_t> R) {
64 if (L == R)
65 return DiffResult::IDENTICAL;
66 if (L.hasValue() != R.hasValue())
67 return DiffResult::DIFFERENT;
68 return DiffResult::EQUIVALENT;
69 }
70
71 std::string format(Optional<uint32_t> Modi, bool Right) {
72 if (!Modi.hasValue())
73 return "(not present)";
74 return formatv("{0}", *Modi).str();
75 }
76};
77
78// Compares and formats two paths embedded in the PDB, ignoring the beginning
79// of the path if the user specified it as a "root path" on the command line.
80struct BinaryPathProvider {
81 explicit BinaryPathProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
82
83 DiffResult compare(StringRef L, StringRef R) {
84 if (L == R)
85 return DiffResult::IDENTICAL;
86
87 SmallString<64> LN = removeRoot(L, false);
88 SmallString<64> RN = removeRoot(R, true);
89
90 return (LN.equals_lower(RN)) ? DiffResult::EQUIVALENT
91 : DiffResult::DIFFERENT;
92 }
93
94 std::string format(StringRef S, bool Right) {
95 if (S.empty())
96 return "(empty)";
97
98 SmallString<64> Native = removeRoot(S, Right);
99 return truncateStringFront(Native.str(), MaxLen);
100 }
101
102 SmallString<64> removeRoot(StringRef Path, bool IsRight) const {
103 SmallString<64> Native(Path);
104 auto &RootOpt = IsRight ? opts::diff::RightRoot : opts::diff::LeftRoot;
105 SmallString<64> Root(static_cast<std::string>(RootOpt));
106 // pdb paths always use windows syntax, convert slashes to backslashes.
107 sys::path::native(Root, sys::path::Style::windows);
108 if (sys::path::has_stem(Root, sys::path::Style::windows))
109 sys::path::append(Root, sys::path::Style::windows,
110 sys::path::get_separator(sys::path::Style::windows));
111
112 sys::path::replace_path_prefix(Native, Root, "", sys::path::Style::windows);
113 return Native;
114 }
115 uint32_t MaxLen;
116};
117
118// Compare and format two stream purposes. For general streams, this just
119// compares the description. For module streams it uses the path comparison
120// algorithm taking into consideration the binary root, described above.
121// Formatting stream purposes just prints the stream purpose, except for
122// module streams and named streams, where it prefixes the name / module
123// with an identifier. Example:
124//
125// Named Stream "\names"
126// Module Stream "foo.obj"
127//
128// If a named stream is too long to fit in a column, it is truncated at the
129// end, and if a module is too long to fit in a column, it is truncated at the
130// beginning. Example:
131//
132// Named Stream "\Really Long Str..."
133// Module Stream "...puts\foo.obj"
134//
135struct StreamPurposeProvider {
136 explicit StreamPurposeProvider(uint32_t MaxLen) : MaxLen(MaxLen) {}
137
138 DiffResult compare(const std::pair<StreamPurpose, std::string> &L,
139 const std::pair<StreamPurpose, std::string> &R) {
140 if (L.first != R.first)
141 return DiffResult::DIFFERENT;
142 if (L.first == StreamPurpose::ModuleStream) {
143 BinaryPathProvider PathProvider(MaxLen);
144 return PathProvider.compare(L.second, R.second);
145 }
146 return (L.second == R.second) ? DiffResult::IDENTICAL
147 : DiffResult::DIFFERENT;
148 }
149
150 std::string format(const std::pair<StreamPurpose, std::string> &P,
151 bool Right) {
152 if (P.first == StreamPurpose::Other)
153 return truncateStringBack(P.second, MaxLen);
154 if (P.first == StreamPurpose::NamedStream)
155 return truncateQuotedNameBack("Named Stream", P.second, MaxLen);
156
157 assert(P.first == StreamPurpose::ModuleStream);
158 uint32_t ExtraChars = strlen("Module \"\"");
159 BinaryPathProvider PathProvider(MaxLen - ExtraChars);
160 std::string Result = PathProvider.format(P.second, Right);
161 return formatv("Module \"{0}\"", Result);
162 }
163
164 uint32_t MaxLen;
165};
166} // namespace
167
Zachary Turner05d5e612017-03-16 20:19:11 +0000168namespace llvm {
169template <> struct format_provider<PdbRaw_FeatureSig> {
170 static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream,
171 StringRef Style) {
172 switch (Sig) {
173 case PdbRaw_FeatureSig::MinimalDebugInfo:
174 Stream << "MinimalDebugInfo";
175 break;
176 case PdbRaw_FeatureSig::NoTypeMerge:
177 Stream << "NoTypeMerge";
178 break;
179 case PdbRaw_FeatureSig::VC110:
180 Stream << "VC110";
181 break;
182 case PdbRaw_FeatureSig::VC140:
183 Stream << "VC140";
184 break;
185 }
186 }
187};
188}
189
Zachary Turnera46533b2017-03-16 19:52:15 +0000190template <typename R> using ValueOfRange = llvm::detail::ValueOfRange<R>;
Zachary Turnerf1220082017-03-15 22:19:30 +0000191
Zachary Turner6ac232c2017-03-13 23:28:25 +0000192DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2)
193 : File1(File1), File2(File2) {}
194
195Error DiffStyle::dump() {
196 if (auto EC = diffSuperBlock())
197 return EC;
198
199 if (auto EC = diffFreePageMap())
200 return EC;
201
202 if (auto EC = diffStreamDirectory())
203 return EC;
204
205 if (auto EC = diffStringTable())
206 return EC;
207
208 if (auto EC = diffInfoStream())
209 return EC;
210
211 if (auto EC = diffDbiStream())
212 return EC;
213
214 if (auto EC = diffSectionContribs())
215 return EC;
216
217 if (auto EC = diffSectionMap())
218 return EC;
219
220 if (auto EC = diffFpoStream())
221 return EC;
222
223 if (auto EC = diffTpiStream(StreamTPI))
224 return EC;
225
226 if (auto EC = diffTpiStream(StreamIPI))
227 return EC;
228
229 if (auto EC = diffPublics())
230 return EC;
231
232 if (auto EC = diffGlobals())
233 return EC;
234
235 return Error::success();
236}
237
Zachary Turner6ac232c2017-03-13 23:28:25 +0000238Error DiffStyle::diffSuperBlock() {
Zachary Turnerc1e93e52017-07-07 18:45:56 +0000239 DiffPrinter D(2, "MSF Super Block", 16, 20, opts::diff::PrintResultColumn,
240 opts::diff::PrintValueColumns, outs());
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000241 D.printExplicit("File", DiffResult::UNSPECIFIED,
Zachary Turnera9d944f2017-07-10 19:16:49 +0000242 truncateStringFront(File1.getFilePath(), 18),
243 truncateStringFront(File2.getFilePath(), 18));
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000244 D.print("Block Size", File1.getBlockSize(), File2.getBlockSize());
245 D.print("Block Count", File1.getBlockCount(), File2.getBlockCount());
246 D.print("Unknown 1", File1.getUnknown1(), File2.getUnknown1());
247 D.print("Directory Size", File1.getNumDirectoryBytes(),
248 File2.getNumDirectoryBytes());
Zachary Turner6ac232c2017-03-13 23:28:25 +0000249 return Error::success();
250}
251
252Error DiffStyle::diffStreamDirectory() {
Zachary Turnerc1e93e52017-07-07 18:45:56 +0000253 DiffPrinter D(2, "Stream Directory", 30, 20, opts::diff::PrintResultColumn,
254 opts::diff::PrintValueColumns, outs());
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000255 D.printExplicit("File", DiffResult::UNSPECIFIED,
Zachary Turnera9d944f2017-07-10 19:16:49 +0000256 truncateStringFront(File1.getFilePath(), 18),
257 truncateStringFront(File2.getFilePath(), 18));
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000258
Zachary Turnera9d944f2017-07-10 19:16:49 +0000259 SmallVector<std::pair<StreamPurpose, std::string>, 32> P;
260 SmallVector<std::pair<StreamPurpose, std::string>, 32> Q;
261 discoverStreamPurposes(File1, P);
262 discoverStreamPurposes(File2, Q);
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000263 D.print("Stream Count", File1.getNumStreams(), File2.getNumStreams());
Zachary Turnered130b62017-06-20 18:50:30 +0000264 auto PI = to_vector<32>(enumerate(P));
265 auto QI = to_vector<32>(enumerate(Q));
266
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000267 // Scan all streams in the left hand side, looking for ones that are also
268 // in the right. Each time we find one, remove it. When we're done, Q
269 // should contain all the streams that are in the right but not in the left.
Zachary Turnera9d944f2017-07-10 19:16:49 +0000270 StreamPurposeProvider StreamProvider(28);
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000271 for (const auto &P : PI) {
272 typedef decltype(PI) ContainerType;
273 typedef typename ContainerType::value_type value_type;
Zachary Turnered130b62017-06-20 18:50:30 +0000274
Zachary Turnera9d944f2017-07-10 19:16:49 +0000275 auto Iter = llvm::find_if(QI, [P, &StreamProvider](const value_type &V) {
276 DiffResult Result = StreamProvider.compare(P.value(), V.value());
277 return Result == DiffResult::EQUIVALENT ||
278 Result == DiffResult::IDENTICAL;
279 });
Zachary Turnered130b62017-06-20 18:50:30 +0000280
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000281 if (Iter == QI.end()) {
Zachary Turnera9d944f2017-07-10 19:16:49 +0000282 D.printExplicit(StreamProvider.format(P.value(), false),
283 DiffResult::DIFFERENT, P.index(), "(not present)");
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000284 continue;
Zachary Turner6ac232c2017-03-13 23:28:25 +0000285 }
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000286
Zachary Turnera9d944f2017-07-10 19:16:49 +0000287 D.print<EquivalentDiffProvider>(StreamProvider.format(P.value(), false),
288 P.index(), Iter->index());
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000289 QI.erase(Iter);
Zachary Turner6ac232c2017-03-13 23:28:25 +0000290 }
291
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000292 for (const auto &Q : QI) {
Zachary Turnera9d944f2017-07-10 19:16:49 +0000293 D.printExplicit(StreamProvider.format(Q.value(), true),
294 DiffResult::DIFFERENT, "(not present)", Q.index());
Zachary Turnered130b62017-06-20 18:50:30 +0000295 }
Zachary Turnered130b62017-06-20 18:50:30 +0000296
Zachary Turner6ac232c2017-03-13 23:28:25 +0000297 return Error::success();
298}
299
Zachary Turnerf1220082017-03-15 22:19:30 +0000300Error DiffStyle::diffStringTable() {
Zachary Turnerc1e93e52017-07-07 18:45:56 +0000301 DiffPrinter D(2, "String Table", 30, 20, opts::diff::PrintResultColumn,
302 opts::diff::PrintValueColumns, outs());
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000303 D.printExplicit("File", DiffResult::UNSPECIFIED,
Zachary Turnera9d944f2017-07-10 19:16:49 +0000304 truncateStringFront(File1.getFilePath(), 18),
305 truncateStringFront(File2.getFilePath(), 18));
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000306
Zachary Turnerf1220082017-03-15 22:19:30 +0000307 auto ExpectedST1 = File1.getStringTable();
308 auto ExpectedST2 = File2.getStringTable();
Zachary Turnerf1220082017-03-15 22:19:30 +0000309 bool Has1 = !!ExpectedST1;
310 bool Has2 = !!ExpectedST2;
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000311 std::string Count1 = Has1 ? llvm::utostr(ExpectedST1->getNameCount())
312 : "(string table not present)";
313 std::string Count2 = Has2 ? llvm::utostr(ExpectedST2->getNameCount())
314 : "(string table not present)";
315 D.print("Number of Strings", Count1, Count2);
316
317 if (!Has1 || !Has2) {
Zachary Turnerf1220082017-03-15 22:19:30 +0000318 consumeError(ExpectedST1.takeError());
319 consumeError(ExpectedST2.takeError());
320 return Error::success();
321 }
322
Zachary Turnerf1220082017-03-15 22:19:30 +0000323 auto &ST1 = *ExpectedST1;
324 auto &ST2 = *ExpectedST2;
325
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000326 D.print("Hash Version", ST1.getHashVersion(), ST2.getHashVersion());
327 D.print("Byte Size", ST1.getByteSize(), ST2.getByteSize());
328 D.print("Signature", ST1.getSignature(), ST2.getSignature());
Zachary Turnerf1220082017-03-15 22:19:30 +0000329
330 // Both have a valid string table, dive in and compare individual strings.
331
332 auto IdList1 = ST1.name_ids();
333 auto IdList2 = ST2.name_ids();
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000334 StringSet<> LS;
335 StringSet<> RS;
336 uint32_t Empty1 = 0;
337 uint32_t Empty2 = 0;
Zachary Turnered130b62017-06-20 18:50:30 +0000338 for (auto ID : IdList1) {
339 auto S = ST1.getStringForID(ID);
340 if (!S)
341 return S.takeError();
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000342 if (S->empty())
343 ++Empty1;
344 else
345 LS.insert(*S);
Zachary Turnered130b62017-06-20 18:50:30 +0000346 }
347 for (auto ID : IdList2) {
348 auto S = ST2.getStringForID(ID);
349 if (!S)
350 return S.takeError();
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000351 if (S->empty())
352 ++Empty2;
353 else
354 RS.insert(*S);
355 }
356 D.print("Empty Strings", Empty1, Empty2);
357
358 for (const auto &S : LS) {
359 auto R = RS.find(S.getKey());
360 std::string Truncated = truncateStringMiddle(S.getKey(), 28);
361 uint32_t I = cantFail(ST1.getIDForString(S.getKey()));
362 if (R == RS.end()) {
363 D.printExplicit(Truncated, DiffResult::DIFFERENT, I, "(not present)");
364 continue;
365 }
366
367 uint32_t J = cantFail(ST2.getIDForString(R->getKey()));
368 D.print<EquivalentDiffProvider>(Truncated, I, J);
369 RS.erase(R);
Zachary Turnered130b62017-06-20 18:50:30 +0000370 }
Zachary Turnerf1220082017-03-15 22:19:30 +0000371
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000372 for (const auto &S : RS) {
373 auto L = LS.find(S.getKey());
374 std::string Truncated = truncateStringMiddle(S.getKey(), 28);
375 uint32_t J = cantFail(ST2.getIDForString(S.getKey()));
376 if (L == LS.end()) {
377 D.printExplicit(Truncated, DiffResult::DIFFERENT, "(not present)", J);
378 continue;
379 }
Zachary Turnerf1220082017-03-15 22:19:30 +0000380
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000381 uint32_t I = cantFail(ST1.getIDForString(L->getKey()));
382 D.print<EquivalentDiffProvider>(Truncated, I, J);
Zachary Turnerf1220082017-03-15 22:19:30 +0000383 }
Zachary Turnerf1220082017-03-15 22:19:30 +0000384 return Error::success();
385}
Zachary Turner6ac232c2017-03-13 23:28:25 +0000386
387Error DiffStyle::diffFreePageMap() { return Error::success(); }
388
Zachary Turner02278ce2017-03-16 20:18:41 +0000389Error DiffStyle::diffInfoStream() {
Zachary Turnerc1e93e52017-07-07 18:45:56 +0000390 DiffPrinter D(2, "PDB Stream", 22, 40, opts::diff::PrintResultColumn,
391 opts::diff::PrintValueColumns, outs());
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000392 D.printExplicit("File", DiffResult::UNSPECIFIED,
Zachary Turnera9d944f2017-07-10 19:16:49 +0000393 truncateStringFront(File1.getFilePath(), 38),
394 truncateStringFront(File2.getFilePath(), 38));
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000395
Zachary Turner02278ce2017-03-16 20:18:41 +0000396 auto ExpectedInfo1 = File1.getPDBInfoStream();
397 auto ExpectedInfo2 = File2.getPDBInfoStream();
398
Zachary Turner02278ce2017-03-16 20:18:41 +0000399 bool Has1 = !!ExpectedInfo1;
400 bool Has2 = !!ExpectedInfo2;
401 if (!(Has1 && Has2)) {
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000402 std::string L = Has1 ? "(present)" : "(not present)";
403 std::string R = Has2 ? "(present)" : "(not present)";
404 D.print("Stream", L, R);
405
406 consumeError(ExpectedInfo1.takeError());
Zachary Turner02278ce2017-03-16 20:18:41 +0000407 consumeError(ExpectedInfo2.takeError());
408 return Error::success();
409 }
410
Zachary Turner02278ce2017-03-16 20:18:41 +0000411 auto &IS1 = *ExpectedInfo1;
412 auto &IS2 = *ExpectedInfo2;
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000413 D.print("Stream Size", IS1.getStreamSize(), IS2.getStreamSize());
414 D.print("Age", IS1.getAge(), IS2.getAge());
415 D.print("Guid", IS1.getGuid(), IS2.getGuid());
416 D.print("Signature", IS1.getSignature(), IS2.getSignature());
417 D.print("Version", IS1.getVersion(), IS2.getVersion());
418 D.diffUnorderedArray("Feature", IS1.getFeatureSignatures(),
419 IS2.getFeatureSignatures());
420 D.print("Named Stream Size", IS1.getNamedStreamMapByteSize(),
421 IS2.getNamedStreamMapByteSize());
422 StringMap<uint32_t> NSL = IS1.getNamedStreams().getStringMap();
423 StringMap<uint32_t> NSR = IS2.getNamedStreams().getStringMap();
424 D.diffUnorderedMap<EquivalentDiffProvider>("Named Stream", NSL, NSR);
Zachary Turner02278ce2017-03-16 20:18:41 +0000425 return Error::success();
426}
Zachary Turner6ac232c2017-03-13 23:28:25 +0000427
Zachary Turner33eee192017-08-03 20:30:09 +0000428typedef std::pair<uint32_t, DbiModuleDescriptor> IndexedModuleDescriptor;
429typedef std::vector<IndexedModuleDescriptor> IndexedModuleDescriptorList;
430
431static IndexedModuleDescriptorList
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000432getModuleDescriptors(const DbiModuleList &ML) {
Zachary Turner33eee192017-08-03 20:30:09 +0000433 IndexedModuleDescriptorList List;
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000434 List.reserve(ML.getModuleCount());
435 for (uint32_t I = 0; I < ML.getModuleCount(); ++I)
436 List.emplace_back(I, ML.getModuleDescriptor(I));
437 return List;
438}
439
Zachary Turner33eee192017-08-03 20:30:09 +0000440static IndexedModuleDescriptorList::iterator
441findOverrideEquivalentModule(uint32_t Modi,
442 IndexedModuleDescriptorList &OtherList) {
443 auto &EqMap = opts::diff::Equivalences;
444
445 auto Iter = EqMap.find(Modi);
446 if (Iter == EqMap.end())
447 return OtherList.end();
448
449 uint32_t EqValue = Iter->second;
450
451 return llvm::find_if(OtherList,
452 [EqValue](const IndexedModuleDescriptor &Desc) {
453 return Desc.first == EqValue;
454 });
455}
456
457static IndexedModuleDescriptorList::iterator
458findEquivalentModule(const IndexedModuleDescriptor &Item,
459 IndexedModuleDescriptorList &OtherList, bool ItemIsRight) {
460
461 if (!ItemIsRight) {
462 uint32_t Modi = Item.first;
463 auto OverrideIter = findOverrideEquivalentModule(Modi, OtherList);
464 if (OverrideIter != OtherList.end())
465 return OverrideIter;
466 }
467
468 BinaryPathProvider PathProvider(28);
469
470 auto Iter = OtherList.begin();
471 auto End = OtherList.end();
472 for (; Iter != End; ++Iter) {
473 const IndexedModuleDescriptor *Left = &Item;
474 const IndexedModuleDescriptor *Right = &*Iter;
475 if (ItemIsRight)
476 std::swap(Left, Right);
477 DiffResult Result = PathProvider.compare(Left->second.getModuleName(),
478 Right->second.getModuleName());
479 if (Result == DiffResult::EQUIVALENT || Result == DiffResult::IDENTICAL)
480 return Iter;
481 }
482 return OtherList.end();
483}
484
485static void diffOneModule(DiffPrinter &D, const IndexedModuleDescriptor &Item,
486 IndexedModuleDescriptorList &Other,
487 bool ItemIsRight) {
Zachary Turnera9d944f2017-07-10 19:16:49 +0000488 StreamPurposeProvider HeaderProvider(70);
489 std::pair<StreamPurpose, std::string> Header;
490 Header.first = StreamPurpose::ModuleStream;
491 Header.second = Item.second.getModuleName();
492 D.printFullRow(HeaderProvider.format(Header, ItemIsRight));
Zachary Turner448dea42017-07-07 18:46:14 +0000493
Zachary Turnera9d944f2017-07-10 19:16:49 +0000494 const auto *L = &Item;
495
Zachary Turner33eee192017-08-03 20:30:09 +0000496 auto Iter = findEquivalentModule(Item, Other, ItemIsRight);
Zachary Turner448dea42017-07-07 18:46:14 +0000497 if (Iter == Other.end()) {
498 // We didn't find this module at all on the other side. Just print one row
499 // and continue.
Zachary Turner33eee192017-08-03 20:30:09 +0000500 if (ItemIsRight)
501 D.print<ModiProvider>("- Modi", None, Item.first);
502 else
503 D.print<ModiProvider>("- Modi", Item.first, None);
Zachary Turner448dea42017-07-07 18:46:14 +0000504 return;
505 }
506
507 // We did find this module. Go through and compare each field.
Zachary Turner448dea42017-07-07 18:46:14 +0000508 const auto *R = &*Iter;
Zachary Turnera9d944f2017-07-10 19:16:49 +0000509 if (ItemIsRight)
Zachary Turner448dea42017-07-07 18:46:14 +0000510 std::swap(L, R);
511
Zachary Turner33eee192017-08-03 20:30:09 +0000512 BinaryPathProvider PathProvider(28);
Zachary Turner448dea42017-07-07 18:46:14 +0000513 D.print<ModiProvider>("- Modi", L->first, R->first);
Zachary Turnera9d944f2017-07-10 19:16:49 +0000514 D.print<BinaryPathProvider>("- Obj File Name", L->second.getObjFileName(),
515 R->second.getObjFileName(), PathProvider);
Zachary Turner448dea42017-07-07 18:46:14 +0000516 D.print<StreamNumberProvider>("- Debug Stream",
517 L->second.getModuleStreamIndex(),
518 R->second.getModuleStreamIndex());
519 D.print("- C11 Byte Size", L->second.getC11LineInfoByteSize(),
520 R->second.getC11LineInfoByteSize());
521 D.print("- C13 Byte Size", L->second.getC13LineInfoByteSize(),
522 R->second.getC13LineInfoByteSize());
523 D.print("- # of files", L->second.getNumberOfFiles(),
524 R->second.getNumberOfFiles());
525 D.print("- Pdb File Path Index", L->second.getPdbFilePathNameIndex(),
526 R->second.getPdbFilePathNameIndex());
527 D.print("- Source File Name Index", L->second.getSourceFileNameIndex(),
528 R->second.getSourceFileNameIndex());
529 D.print("- Symbol Byte Size", L->second.getSymbolDebugInfoByteSize(),
530 R->second.getSymbolDebugInfoByteSize());
531 Other.erase(Iter);
532}
533
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000534Error DiffStyle::diffDbiStream() {
Zachary Turnerc1e93e52017-07-07 18:45:56 +0000535 DiffPrinter D(2, "DBI Stream", 40, 30, opts::diff::PrintResultColumn,
536 opts::diff::PrintValueColumns, outs());
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000537 D.printExplicit("File", DiffResult::UNSPECIFIED,
Zachary Turnera9d944f2017-07-10 19:16:49 +0000538 truncateStringFront(File1.getFilePath(), 28),
539 truncateStringFront(File2.getFilePath(), 28));
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000540
541 auto ExpectedDbi1 = File1.getPDBDbiStream();
542 auto ExpectedDbi2 = File2.getPDBDbiStream();
543
544 bool Has1 = !!ExpectedDbi1;
545 bool Has2 = !!ExpectedDbi2;
546 if (!(Has1 && Has2)) {
547 std::string L = Has1 ? "(present)" : "(not present)";
548 std::string R = Has2 ? "(present)" : "(not present)";
549 D.print("Stream", L, R);
550
551 consumeError(ExpectedDbi1.takeError());
552 consumeError(ExpectedDbi2.takeError());
553 return Error::success();
554 }
555
556 auto &DL = *ExpectedDbi1;
557 auto &DR = *ExpectedDbi2;
558
559 D.print("Dbi Version", (uint32_t)DL.getDbiVersion(),
560 (uint32_t)DR.getDbiVersion());
561 D.print("Age", DL.getAge(), DR.getAge());
562 D.print("Machine", (uint16_t)DL.getMachineType(),
563 (uint16_t)DR.getMachineType());
564 D.print("Flags", DL.getFlags(), DR.getFlags());
565 D.print("Build Major", DL.getBuildMajorVersion(), DR.getBuildMajorVersion());
566 D.print("Build Minor", DL.getBuildMinorVersion(), DR.getBuildMinorVersion());
567 D.print("Build Number", DL.getBuildNumber(), DR.getBuildNumber());
568 D.print("PDB DLL Version", DL.getPdbDllVersion(), DR.getPdbDllVersion());
569 D.print("PDB DLL RBLD", DL.getPdbDllRbld(), DR.getPdbDllRbld());
570 D.print<StreamNumberProvider>("DBG (FPO)",
571 DL.getDebugStreamIndex(DbgHeaderType::FPO),
572 DR.getDebugStreamIndex(DbgHeaderType::FPO));
573 D.print<StreamNumberProvider>(
574 "DBG (Exception)", DL.getDebugStreamIndex(DbgHeaderType::Exception),
575 DR.getDebugStreamIndex(DbgHeaderType::Exception));
576 D.print<StreamNumberProvider>("DBG (Fixup)",
577 DL.getDebugStreamIndex(DbgHeaderType::Fixup),
578 DR.getDebugStreamIndex(DbgHeaderType::Fixup));
579 D.print<StreamNumberProvider>(
580 "DBG (OmapToSrc)", DL.getDebugStreamIndex(DbgHeaderType::OmapToSrc),
581 DR.getDebugStreamIndex(DbgHeaderType::OmapToSrc));
582 D.print<StreamNumberProvider>(
583 "DBG (OmapFromSrc)", DL.getDebugStreamIndex(DbgHeaderType::OmapFromSrc),
584 DR.getDebugStreamIndex(DbgHeaderType::OmapFromSrc));
585 D.print<StreamNumberProvider>(
586 "DBG (SectionHdr)", DL.getDebugStreamIndex(DbgHeaderType::SectionHdr),
587 DR.getDebugStreamIndex(DbgHeaderType::SectionHdr));
588 D.print<StreamNumberProvider>(
589 "DBG (TokenRidMap)", DL.getDebugStreamIndex(DbgHeaderType::TokenRidMap),
590 DR.getDebugStreamIndex(DbgHeaderType::TokenRidMap));
591 D.print<StreamNumberProvider>("DBG (Xdata)",
592 DL.getDebugStreamIndex(DbgHeaderType::Xdata),
593 DR.getDebugStreamIndex(DbgHeaderType::Xdata));
594 D.print<StreamNumberProvider>("DBG (Pdata)",
595 DL.getDebugStreamIndex(DbgHeaderType::Pdata),
596 DR.getDebugStreamIndex(DbgHeaderType::Pdata));
597 D.print<StreamNumberProvider>("DBG (NewFPO)",
598 DL.getDebugStreamIndex(DbgHeaderType::NewFPO),
599 DR.getDebugStreamIndex(DbgHeaderType::NewFPO));
600 D.print<StreamNumberProvider>(
601 "DBG (SectionHdrOrig)",
602 DL.getDebugStreamIndex(DbgHeaderType::SectionHdrOrig),
603 DR.getDebugStreamIndex(DbgHeaderType::SectionHdrOrig));
604 D.print<StreamNumberProvider>("Globals Stream",
605 DL.getGlobalSymbolStreamIndex(),
606 DR.getGlobalSymbolStreamIndex());
607 D.print<StreamNumberProvider>("Publics Stream",
608 DL.getPublicSymbolStreamIndex(),
609 DR.getPublicSymbolStreamIndex());
610 D.print<StreamNumberProvider>("Symbol Records", DL.getSymRecordStreamIndex(),
611 DR.getSymRecordStreamIndex());
612 D.print("Has CTypes", DL.hasCTypes(), DR.hasCTypes());
613 D.print("Is Incrementally Linked", DL.isIncrementallyLinked(),
614 DR.isIncrementallyLinked());
615 D.print("Is Stripped", DL.isStripped(), DR.isStripped());
616 const DbiModuleList &ML = DL.modules();
617 const DbiModuleList &MR = DR.modules();
618 D.print("Module Count", ML.getModuleCount(), MR.getModuleCount());
619 D.print("Source File Count", ML.getSourceFileCount(),
620 MR.getSourceFileCount());
621 auto MDL = getModuleDescriptors(ML);
622 auto MDR = getModuleDescriptors(MR);
623 // Scan all module descriptors from the left, and look for corresponding
624 // module descriptors on the right.
Zachary Turner448dea42017-07-07 18:46:14 +0000625 for (const auto &L : MDL)
626 diffOneModule(D, L, MDR, false);
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000627
Zachary Turner448dea42017-07-07 18:46:14 +0000628 for (const auto &R : MDR)
629 diffOneModule(D, R, MDL, true);
Zachary Turnerf3b4b2d2017-07-07 18:45:37 +0000630
631 return Error::success();
632}
Zachary Turner6ac232c2017-03-13 23:28:25 +0000633
634Error DiffStyle::diffSectionContribs() { return Error::success(); }
635
636Error DiffStyle::diffSectionMap() { return Error::success(); }
637
638Error DiffStyle::diffFpoStream() { return Error::success(); }
639
640Error DiffStyle::diffTpiStream(int Index) { return Error::success(); }
641
642Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); }
643
644Error DiffStyle::diffPublics() { return Error::success(); }
645
646Error DiffStyle::diffGlobals() { return Error::success(); }