DumpOutputStyle.cpp 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989
  1. //===- DumpOutputStyle.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. //===----------------------------------------------------------------------===//
  8. #include "DumpOutputStyle.h"
  9. #include "FormatUtil.h"
  10. #include "InputFile.h"
  11. #include "MinimalSymbolDumper.h"
  12. #include "MinimalTypeDumper.h"
  13. #include "StreamUtil.h"
  14. #include "TypeReferenceTracker.h"
  15. #include "llvm-pdbutil.h"
  16. #include "llvm/ADT/STLExtras.h"
  17. #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
  18. #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
  19. #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
  20. #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
  21. #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
  22. #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
  23. #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
  24. #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
  25. #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
  26. #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
  27. #include "llvm/DebugInfo/CodeView/Formatters.h"
  28. #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
  29. #include "llvm/DebugInfo/CodeView/Line.h"
  30. #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
  31. #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
  32. #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
  33. #include "llvm/DebugInfo/CodeView/TypeHashing.h"
  34. #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
  35. #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
  36. #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
  37. #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
  38. #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
  39. #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
  40. #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
  41. #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
  42. #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
  43. #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
  44. #include "llvm/DebugInfo/PDB/Native/RawError.h"
  45. #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
  46. #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
  47. #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
  48. #include "llvm/Object/COFF.h"
  49. #include "llvm/Support/BinaryStreamReader.h"
  50. #include "llvm/Support/FormatAdapters.h"
  51. #include "llvm/Support/FormatVariadic.h"
  52. #include <cctype>
  53. using namespace llvm;
  54. using namespace llvm::codeview;
  55. using namespace llvm::msf;
  56. using namespace llvm::pdb;
  57. DumpOutputStyle::DumpOutputStyle(InputFile &File)
  58. : File(File), P(2, false, outs()) {
  59. if (opts::dump::DumpTypeRefStats)
  60. RefTracker.reset(new TypeReferenceTracker(File));
  61. }
  62. DumpOutputStyle::~DumpOutputStyle() {}
  63. PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
  64. object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
  65. void DumpOutputStyle::printStreamNotValidForObj() {
  66. AutoIndent Indent(P, 4);
  67. P.formatLine("Dumping this stream is not valid for object files");
  68. }
  69. void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) {
  70. AutoIndent Indent(P, 4);
  71. P.formatLine("{0} stream not present", StreamName);
  72. }
  73. Error DumpOutputStyle::dump() {
  74. // Walk symbols & globals if we are supposed to mark types referenced.
  75. if (opts::dump::DumpTypeRefStats)
  76. RefTracker->mark();
  77. if (opts::dump::DumpSummary) {
  78. if (auto EC = dumpFileSummary())
  79. return EC;
  80. P.NewLine();
  81. }
  82. if (opts::dump::DumpStreams) {
  83. if (auto EC = dumpStreamSummary())
  84. return EC;
  85. P.NewLine();
  86. }
  87. if (opts::dump::DumpSymbolStats) {
  88. if (auto EC = dumpSymbolStats())
  89. return EC;
  90. P.NewLine();
  91. }
  92. if (opts::dump::DumpUdtStats) {
  93. if (auto EC = dumpUdtStats())
  94. return EC;
  95. P.NewLine();
  96. }
  97. if (opts::dump::DumpTypeStats || opts::dump::DumpIDStats) {
  98. if (auto EC = dumpTypeStats())
  99. return EC;
  100. P.NewLine();
  101. }
  102. if (opts::dump::DumpNamedStreams) {
  103. if (auto EC = dumpNamedStreams())
  104. return EC;
  105. P.NewLine();
  106. }
  107. if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) {
  108. if (auto EC = dumpStringTable())
  109. return EC;
  110. P.NewLine();
  111. }
  112. if (opts::dump::DumpModules) {
  113. if (auto EC = dumpModules())
  114. return EC;
  115. }
  116. if (opts::dump::DumpModuleFiles) {
  117. if (auto EC = dumpModuleFiles())
  118. return EC;
  119. }
  120. if (opts::dump::DumpLines) {
  121. if (auto EC = dumpLines())
  122. return EC;
  123. }
  124. if (opts::dump::DumpInlineeLines) {
  125. if (auto EC = dumpInlineeLines())
  126. return EC;
  127. }
  128. if (opts::dump::DumpXmi) {
  129. if (auto EC = dumpXmi())
  130. return EC;
  131. }
  132. if (opts::dump::DumpXme) {
  133. if (auto EC = dumpXme())
  134. return EC;
  135. }
  136. if (opts::dump::DumpFpo) {
  137. if (auto EC = dumpFpo())
  138. return EC;
  139. }
  140. if (File.isObj()) {
  141. if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
  142. opts::dump::DumpTypeExtras)
  143. if (auto EC = dumpTypesFromObjectFile())
  144. return EC;
  145. } else {
  146. if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
  147. opts::dump::DumpTypeExtras) {
  148. if (auto EC = dumpTpiStream(StreamTPI))
  149. return EC;
  150. }
  151. if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
  152. opts::dump::DumpIdExtras) {
  153. if (auto EC = dumpTpiStream(StreamIPI))
  154. return EC;
  155. }
  156. }
  157. if (opts::dump::DumpGSIRecords) {
  158. if (auto EC = dumpGSIRecords())
  159. return EC;
  160. }
  161. if (opts::dump::DumpGlobals) {
  162. if (auto EC = dumpGlobals())
  163. return EC;
  164. }
  165. if (opts::dump::DumpPublics) {
  166. if (auto EC = dumpPublics())
  167. return EC;
  168. }
  169. if (opts::dump::DumpSymbols) {
  170. auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj();
  171. if (EC)
  172. return EC;
  173. }
  174. if (opts::dump::DumpTypeRefStats) {
  175. if (auto EC = dumpTypeRefStats())
  176. return EC;
  177. }
  178. if (opts::dump::DumpSectionHeaders) {
  179. if (auto EC = dumpSectionHeaders())
  180. return EC;
  181. }
  182. if (opts::dump::DumpSectionContribs) {
  183. if (auto EC = dumpSectionContribs())
  184. return EC;
  185. }
  186. if (opts::dump::DumpSectionMap) {
  187. if (auto EC = dumpSectionMap())
  188. return EC;
  189. }
  190. P.NewLine();
  191. return Error::success();
  192. }
  193. static void printHeader(LinePrinter &P, const Twine &S) {
  194. P.NewLine();
  195. P.formatLine("{0,=60}", S);
  196. P.formatLine("{0}", fmt_repeat('=', 60));
  197. }
  198. Error DumpOutputStyle::dumpFileSummary() {
  199. printHeader(P, "Summary");
  200. if (File.isObj()) {
  201. printStreamNotValidForObj();
  202. return Error::success();
  203. }
  204. AutoIndent Indent(P);
  205. ExitOnError Err("Invalid PDB Format: ");
  206. P.formatLine("Block Size: {0}", getPdb().getBlockSize());
  207. P.formatLine("Number of blocks: {0}", getPdb().getBlockCount());
  208. P.formatLine("Number of streams: {0}", getPdb().getNumStreams());
  209. auto &PS = Err(getPdb().getPDBInfoStream());
  210. P.formatLine("Signature: {0}", PS.getSignature());
  211. P.formatLine("Age: {0}", PS.getAge());
  212. P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
  213. P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
  214. P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream());
  215. P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream());
  216. P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream());
  217. P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream());
  218. P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream());
  219. if (getPdb().hasPDBDbiStream()) {
  220. auto &DBI = Err(getPdb().getPDBDbiStream());
  221. P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
  222. P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
  223. P.formatLine("Is stripped: {0}", DBI.isStripped());
  224. }
  225. return Error::success();
  226. }
  227. static StatCollection getSymbolStats(const SymbolGroup &SG,
  228. StatCollection &CumulativeStats) {
  229. StatCollection Stats;
  230. if (SG.getFile().isPdb() && SG.hasDebugStream()) {
  231. // For PDB files, all symbols are packed into one stream.
  232. for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) {
  233. Stats.update(S.kind(), S.length());
  234. CumulativeStats.update(S.kind(), S.length());
  235. }
  236. return Stats;
  237. }
  238. for (const auto &SS : SG.getDebugSubsections()) {
  239. // For object files, all symbols are spread across multiple Symbol
  240. // subsections of a given .debug$S section.
  241. if (SS.kind() != DebugSubsectionKind::Symbols)
  242. continue;
  243. DebugSymbolsSubsectionRef Symbols;
  244. BinaryStreamReader Reader(SS.getRecordData());
  245. cantFail(Symbols.initialize(Reader));
  246. for (const auto &S : Symbols) {
  247. Stats.update(S.kind(), S.length());
  248. CumulativeStats.update(S.kind(), S.length());
  249. }
  250. }
  251. return Stats;
  252. }
  253. static StatCollection getChunkStats(const SymbolGroup &SG,
  254. StatCollection &CumulativeStats) {
  255. StatCollection Stats;
  256. for (const auto &Chunk : SG.getDebugSubsections()) {
  257. Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
  258. CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
  259. }
  260. return Stats;
  261. }
  262. static inline std::string formatModuleDetailKind(DebugSubsectionKind K) {
  263. return formatChunkKind(K, false);
  264. }
  265. static inline std::string formatModuleDetailKind(SymbolKind K) {
  266. return formatSymbolKind(K);
  267. }
  268. // Get the stats sorted by size, descending.
  269. std::vector<StatCollection::KindAndStat>
  270. StatCollection::getStatsSortedBySize() const {
  271. std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end());
  272. llvm::stable_sort(SortedStats,
  273. [](const KindAndStat &LHS, const KindAndStat &RHS) {
  274. return LHS.second.Size > RHS.second.Size;
  275. });
  276. return SortedStats;
  277. }
  278. template <typename Kind>
  279. static void printModuleDetailStats(LinePrinter &P, StringRef Label,
  280. const StatCollection &Stats) {
  281. P.NewLine();
  282. P.formatLine(" {0}", Label);
  283. AutoIndent Indent(P);
  284. P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total",
  285. Stats.Totals.Count, Stats.Totals.Size);
  286. P.formatLine("{0}", fmt_repeat('-', 74));
  287. for (const auto &K : Stats.getStatsSortedBySize()) {
  288. std::string KindName = formatModuleDetailKind(Kind(K.first));
  289. P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName,
  290. K.second.Count, K.second.Size);
  291. }
  292. }
  293. static bool isMyCode(const SymbolGroup &Group) {
  294. if (Group.getFile().isObj())
  295. return true;
  296. StringRef Name = Group.name();
  297. if (Name.startswith("Import:"))
  298. return false;
  299. if (Name.endswith_insensitive(".dll"))
  300. return false;
  301. if (Name.equals_insensitive("* linker *"))
  302. return false;
  303. if (Name.startswith_insensitive("f:\\binaries\\Intermediate\\vctools"))
  304. return false;
  305. if (Name.startswith_insensitive("f:\\dd\\vctools\\crt"))
  306. return false;
  307. return true;
  308. }
  309. static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) {
  310. if (opts::dump::JustMyCode && !isMyCode(Group))
  311. return false;
  312. // If the arg was not specified on the command line, always dump all modules.
  313. if (opts::dump::DumpModi.getNumOccurrences() == 0)
  314. return true;
  315. // Otherwise, only dump if this is the same module specified.
  316. return (opts::dump::DumpModi == Idx);
  317. }
  318. Error DumpOutputStyle::dumpStreamSummary() {
  319. printHeader(P, "Streams");
  320. if (File.isObj()) {
  321. printStreamNotValidForObj();
  322. return Error::success();
  323. }
  324. AutoIndent Indent(P);
  325. if (StreamPurposes.empty())
  326. discoverStreamPurposes(getPdb(), StreamPurposes);
  327. uint32_t StreamCount = getPdb().getNumStreams();
  328. uint32_t MaxStreamSize = getPdb().getMaxStreamSize();
  329. for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
  330. P.formatLine(
  331. "Stream {0} ({1} bytes): [{2}]",
  332. fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
  333. fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right,
  334. NumDigits(MaxStreamSize)),
  335. StreamPurposes[StreamIdx].getLongName());
  336. if (opts::dump::DumpStreamBlocks) {
  337. auto Blocks = getPdb().getStreamBlockList(StreamIdx);
  338. std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
  339. P.formatLine(" {0} Blocks: [{1}]",
  340. fmt_repeat(' ', NumDigits(StreamCount)),
  341. make_range(BV.begin(), BV.end()));
  342. }
  343. }
  344. return Error::success();
  345. }
  346. static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
  347. uint32_t Index) {
  348. ExitOnError Err("Unexpected error: ");
  349. auto &Dbi = Err(File.getPDBDbiStream());
  350. const auto &Modules = Dbi.modules();
  351. auto Modi = Modules.getModuleDescriptor(Index);
  352. uint16_t ModiStream = Modi.getModuleStreamIndex();
  353. if (ModiStream == kInvalidStreamIndex)
  354. return make_error<RawError>(raw_error_code::no_stream,
  355. "Module stream not present");
  356. auto ModStreamData = File.createIndexedStream(ModiStream);
  357. ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
  358. if (auto EC = ModS.reload())
  359. return make_error<RawError>(raw_error_code::corrupt_file,
  360. "Invalid module stream");
  361. return std::move(ModS);
  362. }
  363. template <typename CallbackT>
  364. static void
  365. iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope,
  366. const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) {
  367. if (HeaderScope) {
  368. HeaderScope->P.formatLine(
  369. "Mod {0:4} | `{1}`: ",
  370. fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name());
  371. }
  372. AutoIndent Indent(HeaderScope);
  373. Callback(Modi, SG);
  374. }
  375. template <typename CallbackT>
  376. static void iterateSymbolGroups(InputFile &Input,
  377. const Optional<PrintScope> &HeaderScope,
  378. CallbackT Callback) {
  379. AutoIndent Indent(HeaderScope);
  380. ExitOnError Err("Unexpected error processing modules: ");
  381. if (opts::dump::DumpModi.getNumOccurrences() > 0) {
  382. assert(opts::dump::DumpModi.getNumOccurrences() == 1);
  383. uint32_t Modi = opts::dump::DumpModi;
  384. SymbolGroup SG(&Input, Modi);
  385. iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG,
  386. Modi, Callback);
  387. return;
  388. }
  389. uint32_t I = 0;
  390. for (const auto &SG : Input.symbol_groups()) {
  391. if (shouldDumpSymbolGroup(I, SG))
  392. iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I,
  393. Callback);
  394. ++I;
  395. }
  396. }
  397. template <typename SubsectionT>
  398. static void iterateModuleSubsections(
  399. InputFile &File, const Optional<PrintScope> &HeaderScope,
  400. llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)>
  401. Callback) {
  402. iterateSymbolGroups(File, HeaderScope,
  403. [&](uint32_t Modi, const SymbolGroup &SG) {
  404. for (const auto &SS : SG.getDebugSubsections()) {
  405. SubsectionT Subsection;
  406. if (SS.kind() != Subsection.kind())
  407. continue;
  408. BinaryStreamReader Reader(SS.getRecordData());
  409. if (auto EC = Subsection.initialize(Reader))
  410. continue;
  411. Callback(Modi, SG, Subsection);
  412. }
  413. });
  414. }
  415. static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
  416. ArrayRef<llvm::object::coff_section>>>
  417. loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
  418. if (!File.hasPDBDbiStream())
  419. return make_error<StringError>(
  420. "Section headers require a DBI Stream, which could not be loaded",
  421. inconvertibleErrorCode());
  422. auto &Dbi = cantFail(File.getPDBDbiStream());
  423. uint32_t SI = Dbi.getDebugStreamIndex(Type);
  424. if (SI == kInvalidStreamIndex)
  425. return make_error<StringError>(
  426. "PDB does not contain the requested image section header type",
  427. inconvertibleErrorCode());
  428. auto Stream = File.createIndexedStream(SI);
  429. if (!Stream)
  430. return make_error<StringError>("Could not load the required stream data",
  431. inconvertibleErrorCode());
  432. ArrayRef<object::coff_section> Headers;
  433. if (Stream->getLength() % sizeof(object::coff_section) != 0)
  434. return make_error<StringError>(
  435. "Section header array size is not a multiple of section header size",
  436. inconvertibleErrorCode());
  437. uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
  438. BinaryStreamReader Reader(*Stream);
  439. cantFail(Reader.readArray(Headers, NumHeaders));
  440. return std::make_pair(std::move(Stream), Headers);
  441. }
  442. static std::vector<std::string> getSectionNames(PDBFile &File) {
  443. auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
  444. if (!ExpectedHeaders)
  445. return {};
  446. std::unique_ptr<MappedBlockStream> Stream;
  447. ArrayRef<object::coff_section> Headers;
  448. std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
  449. std::vector<std::string> Names;
  450. for (const auto &H : Headers)
  451. Names.push_back(H.Name);
  452. return Names;
  453. }
  454. static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC,
  455. ArrayRef<std::string> SectionNames,
  456. uint32_t FieldWidth) {
  457. std::string NameInsert;
  458. if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) {
  459. StringRef SectionName = SectionNames[SC.ISect - 1];
  460. NameInsert = formatv("[{0}]", SectionName).str();
  461. } else
  462. NameInsert = "[???]";
  463. P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
  464. "crc = {4}",
  465. formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
  466. fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
  467. fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2));
  468. AutoIndent Indent(P, FieldWidth + 2);
  469. P.formatLine(" {0}",
  470. formatSectionCharacteristics(P.getIndentLevel() + 6,
  471. SC.Characteristics, 3, " | "));
  472. }
  473. static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC,
  474. ArrayRef<std::string> SectionNames,
  475. uint32_t FieldWidth) {
  476. P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
  477. "crc = {4}, coff section = {5}",
  478. formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
  479. fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc),
  480. fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff));
  481. P.formatLine(" {0}",
  482. formatSectionCharacteristics(P.getIndentLevel() + 6,
  483. SC.Base.Characteristics, 3, " | "));
  484. }
  485. Error DumpOutputStyle::dumpModules() {
  486. printHeader(P, "Modules");
  487. if (File.isObj()) {
  488. printStreamNotValidForObj();
  489. return Error::success();
  490. }
  491. if (!getPdb().hasPDBDbiStream()) {
  492. printStreamNotPresent("DBI");
  493. return Error::success();
  494. }
  495. AutoIndent Indent(P);
  496. ExitOnError Err("Unexpected error processing modules: ");
  497. auto &Stream = Err(getPdb().getPDBDbiStream());
  498. const DbiModuleList &Modules = Stream.modules();
  499. iterateSymbolGroups(
  500. File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) {
  501. auto Desc = Modules.getModuleDescriptor(Modi);
  502. if (opts::dump::DumpSectionContribs) {
  503. std::vector<std::string> Sections = getSectionNames(getPdb());
  504. dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0);
  505. }
  506. P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
  507. P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
  508. Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
  509. Desc.hasECInfo());
  510. StringRef PdbFilePath =
  511. Err(Stream.getECName(Desc.getPdbFilePathNameIndex()));
  512. StringRef SrcFilePath =
  513. Err(Stream.getECName(Desc.getSourceFileNameIndex()));
  514. P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
  515. Desc.getPdbFilePathNameIndex(), PdbFilePath,
  516. Desc.getSourceFileNameIndex(), SrcFilePath);
  517. });
  518. return Error::success();
  519. }
  520. Error DumpOutputStyle::dumpModuleFiles() {
  521. printHeader(P, "Files");
  522. if (File.isObj()) {
  523. printStreamNotValidForObj();
  524. return Error::success();
  525. }
  526. if (!getPdb().hasPDBDbiStream()) {
  527. printStreamNotPresent("DBI");
  528. return Error::success();
  529. }
  530. ExitOnError Err("Unexpected error processing modules: ");
  531. iterateSymbolGroups(File, PrintScope{P, 11},
  532. [this, &Err](uint32_t Modi, const SymbolGroup &Strings) {
  533. auto &Stream = Err(getPdb().getPDBDbiStream());
  534. const DbiModuleList &Modules = Stream.modules();
  535. for (const auto &F : Modules.source_files(Modi)) {
  536. Strings.formatFromFileName(P, F);
  537. }
  538. });
  539. return Error::success();
  540. }
  541. Error DumpOutputStyle::dumpSymbolStats() {
  542. printHeader(P, "Module Stats");
  543. if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
  544. printStreamNotPresent("DBI");
  545. return Error::success();
  546. }
  547. ExitOnError Err("Unexpected error processing modules: ");
  548. StatCollection SymStats;
  549. StatCollection ChunkStats;
  550. Optional<PrintScope> Scope;
  551. if (File.isPdb())
  552. Scope.emplace(P, 2);
  553. iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) {
  554. StatCollection SS = getSymbolStats(SG, SymStats);
  555. StatCollection CS = getChunkStats(SG, ChunkStats);
  556. if (SG.getFile().isPdb()) {
  557. AutoIndent Indent(P);
  558. auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules();
  559. uint32_t ModCount = Modules.getModuleCount();
  560. DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi);
  561. uint32_t StreamIdx = Desc.getModuleStreamIndex();
  562. if (StreamIdx == kInvalidStreamIndex) {
  563. P.formatLine("Mod {0} (debug info not present): [{1}]",
  564. fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)),
  565. Desc.getModuleName());
  566. return;
  567. }
  568. P.formatLine("Stream {0}, {1} bytes", StreamIdx,
  569. getPdb().getStreamByteSize(StreamIdx));
  570. printModuleDetailStats<SymbolKind>(P, "Symbols", SS);
  571. printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS);
  572. }
  573. });
  574. if (SymStats.Totals.Count > 0) {
  575. P.printLine(" Summary |");
  576. AutoIndent Indent(P, 4);
  577. printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats);
  578. printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats);
  579. }
  580. return Error::success();
  581. }
  582. Error DumpOutputStyle::dumpTypeStats() {
  583. printHeader(P, "Type Record Stats");
  584. // Iterate the types, categorize by kind, accumulate size stats.
  585. StatCollection TypeStats;
  586. LazyRandomTypeCollection &Types =
  587. opts::dump::DumpTypeStats ? File.types() : File.ids();
  588. for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
  589. CVType Type = Types.getType(*TI);
  590. TypeStats.update(uint32_t(Type.kind()), Type.length());
  591. }
  592. P.NewLine();
  593. P.formatLine(" Types");
  594. AutoIndent Indent(P);
  595. P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total",
  596. TypeStats.Totals.Count, TypeStats.Totals.Size,
  597. (double)TypeStats.Totals.Size / TypeStats.Totals.Count);
  598. P.formatLine("{0}", fmt_repeat('-', 74));
  599. for (const auto &K : TypeStats.getStatsSortedBySize()) {
  600. P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)",
  601. formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count,
  602. K.second.Size, (double)K.second.Size / K.second.Count);
  603. }
  604. return Error::success();
  605. }
  606. static bool isValidNamespaceIdentifier(StringRef S) {
  607. if (S.empty())
  608. return false;
  609. if (std::isdigit(S[0]))
  610. return false;
  611. return llvm::all_of(S, [](char C) { return std::isalnum(C); });
  612. }
  613. namespace {
  614. constexpr uint32_t kNoneUdtKind = 0;
  615. constexpr uint32_t kSimpleUdtKind = 1;
  616. constexpr uint32_t kUnknownUdtKind = 2;
  617. } // namespace
  618. static std::string getUdtStatLabel(uint32_t Kind) {
  619. if (Kind == kNoneUdtKind)
  620. return "<none type>";
  621. if (Kind == kSimpleUdtKind)
  622. return "<simple type>";
  623. if (Kind == kUnknownUdtKind)
  624. return "<unknown type>";
  625. return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind));
  626. }
  627. static uint32_t getLongestTypeLeafName(const StatCollection &Stats) {
  628. size_t L = 0;
  629. for (const auto &Stat : Stats.Individual) {
  630. std::string Label = getUdtStatLabel(Stat.first);
  631. L = std::max(L, Label.size());
  632. }
  633. return static_cast<uint32_t>(L);
  634. }
  635. Error DumpOutputStyle::dumpUdtStats() {
  636. printHeader(P, "S_UDT Record Stats");
  637. if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) {
  638. printStreamNotPresent("Globals");
  639. return Error::success();
  640. }
  641. StatCollection UdtStats;
  642. StatCollection UdtTargetStats;
  643. AutoIndent Indent(P, 4);
  644. auto &TpiTypes = File.types();
  645. StringMap<StatCollection::Stat> NamespacedStats;
  646. size_t LongestNamespace = 0;
  647. auto HandleOneSymbol = [&](const CVSymbol &Sym) {
  648. if (Sym.kind() != SymbolKind::S_UDT)
  649. return;
  650. UdtStats.update(SymbolKind::S_UDT, Sym.length());
  651. UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym));
  652. uint32_t Kind = 0;
  653. uint32_t RecordSize = 0;
  654. if (UDT.Type.isNoneType())
  655. Kind = kNoneUdtKind;
  656. else if (UDT.Type.isSimple())
  657. Kind = kSimpleUdtKind;
  658. else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
  659. Kind = T->kind();
  660. RecordSize = T->length();
  661. } else
  662. Kind = kUnknownUdtKind;
  663. UdtTargetStats.update(Kind, RecordSize);
  664. size_t Pos = UDT.Name.find("::");
  665. if (Pos == StringRef::npos)
  666. return;
  667. StringRef Scope = UDT.Name.take_front(Pos);
  668. if (Scope.empty() || !isValidNamespaceIdentifier(Scope))
  669. return;
  670. LongestNamespace = std::max(LongestNamespace, Scope.size());
  671. NamespacedStats[Scope].update(RecordSize);
  672. };
  673. P.NewLine();
  674. if (File.isPdb()) {
  675. auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream());
  676. auto ExpGlobals = getPdb().getPDBGlobalsStream();
  677. if (!ExpGlobals)
  678. return ExpGlobals.takeError();
  679. for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) {
  680. CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
  681. HandleOneSymbol(Sym);
  682. }
  683. } else {
  684. for (const auto &Sec : File.symbol_groups()) {
  685. for (const auto &SS : Sec.getDebugSubsections()) {
  686. if (SS.kind() != DebugSubsectionKind::Symbols)
  687. continue;
  688. DebugSymbolsSubsectionRef Symbols;
  689. BinaryStreamReader Reader(SS.getRecordData());
  690. cantFail(Symbols.initialize(Reader));
  691. for (const auto &S : Symbols)
  692. HandleOneSymbol(S);
  693. }
  694. }
  695. }
  696. LongestNamespace += StringRef(" namespace ''").size();
  697. size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
  698. size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
  699. // Compute the max number of digits for count and size fields, including comma
  700. // separators.
  701. StringRef CountHeader("Count");
  702. StringRef SizeHeader("Size");
  703. size_t CD = NumDigits(UdtStats.Totals.Count);
  704. CD += (CD - 1) / 3;
  705. CD = std::max(CD, CountHeader.size());
  706. size_t SD = NumDigits(UdtStats.Totals.Size);
  707. SD += (SD - 1) / 3;
  708. SD = std::max(SD, SizeHeader.size());
  709. uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
  710. P.formatLine("{0} | {1} {2}",
  711. fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
  712. fmt_align(CountHeader, AlignStyle::Right, CD),
  713. fmt_align(SizeHeader, AlignStyle::Right, SD));
  714. P.formatLine("{0}", fmt_repeat('-', TableWidth));
  715. for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) {
  716. std::string Label = getUdtStatLabel(Stat.first);
  717. P.formatLine("{0} | {1:N} {2:N}",
  718. fmt_align(Label, AlignStyle::Right, FieldWidth),
  719. fmt_align(Stat.second.Count, AlignStyle::Right, CD),
  720. fmt_align(Stat.second.Size, AlignStyle::Right, SD));
  721. }
  722. P.formatLine("{0}", fmt_repeat('-', TableWidth));
  723. P.formatLine("{0} | {1:N} {2:N}",
  724. fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
  725. fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
  726. fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
  727. P.formatLine("{0}", fmt_repeat('-', TableWidth));
  728. struct StrAndStat {
  729. StringRef Key;
  730. StatCollection::Stat Stat;
  731. };
  732. // Print namespace stats in descending order of size.
  733. std::vector<StrAndStat> NamespacedStatsSorted;
  734. for (const auto &Stat : NamespacedStats)
  735. NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second});
  736. llvm::stable_sort(NamespacedStatsSorted,
  737. [](const StrAndStat &L, const StrAndStat &R) {
  738. return L.Stat.Size > R.Stat.Size;
  739. });
  740. for (const auto &Stat : NamespacedStatsSorted) {
  741. std::string Label = std::string(formatv("namespace '{0}'", Stat.Key));
  742. P.formatLine("{0} | {1:N} {2:N}",
  743. fmt_align(Label, AlignStyle::Right, FieldWidth),
  744. fmt_align(Stat.Stat.Count, AlignStyle::Right, CD),
  745. fmt_align(Stat.Stat.Size, AlignStyle::Right, SD));
  746. }
  747. return Error::success();
  748. }
  749. static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
  750. const LineColumnEntry &E) {
  751. const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
  752. uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
  753. // Let's try to keep it under 100 characters
  754. constexpr uint32_t kMaxRowLength = 100;
  755. // At least 3 spaces between columns.
  756. uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
  757. uint32_t ItemsLeft = E.LineNumbers.size();
  758. auto LineIter = E.LineNumbers.begin();
  759. while (ItemsLeft != 0) {
  760. uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
  761. for (uint32_t I = 0; I < RowColumns; ++I) {
  762. LineInfo Line(LineIter->Flags);
  763. std::string LineStr;
  764. if (Line.isAlwaysStepInto())
  765. LineStr = "ASI";
  766. else if (Line.isNeverStepInto())
  767. LineStr = "NSI";
  768. else
  769. LineStr = utostr(Line.getStartLine());
  770. char Statement = Line.isStatement() ? ' ' : '!';
  771. P.format("{0} {1:X-} {2} ",
  772. fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
  773. fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
  774. Statement);
  775. ++LineIter;
  776. --ItemsLeft;
  777. }
  778. P.NewLine();
  779. }
  780. }
  781. Error DumpOutputStyle::dumpLines() {
  782. printHeader(P, "Lines");
  783. if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
  784. printStreamNotPresent("DBI");
  785. return Error::success();
  786. }
  787. uint32_t LastModi = UINT32_MAX;
  788. uint32_t LastNameIndex = UINT32_MAX;
  789. iterateModuleSubsections<DebugLinesSubsectionRef>(
  790. File, PrintScope{P, 4},
  791. [this, &LastModi, &LastNameIndex](uint32_t Modi,
  792. const SymbolGroup &Strings,
  793. DebugLinesSubsectionRef &Lines) {
  794. uint16_t Segment = Lines.header()->RelocSegment;
  795. uint32_t Begin = Lines.header()->RelocOffset;
  796. uint32_t End = Begin + Lines.header()->CodeSize;
  797. for (const auto &Block : Lines) {
  798. if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
  799. LastModi = Modi;
  800. LastNameIndex = Block.NameIndex;
  801. Strings.formatFromChecksumsOffset(P, Block.NameIndex);
  802. }
  803. AutoIndent Indent(P, 2);
  804. P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
  805. uint32_t Count = Block.LineNumbers.size();
  806. if (Lines.hasColumnInfo())
  807. P.format("line/column/addr entries = {0}", Count);
  808. else
  809. P.format("line/addr entries = {0}", Count);
  810. P.NewLine();
  811. typesetLinesAndColumns(P, Begin, Block);
  812. }
  813. });
  814. return Error::success();
  815. }
  816. Error DumpOutputStyle::dumpInlineeLines() {
  817. printHeader(P, "Inlinee Lines");
  818. if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
  819. printStreamNotPresent("DBI");
  820. return Error::success();
  821. }
  822. iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
  823. File, PrintScope{P, 2},
  824. [this](uint32_t Modi, const SymbolGroup &Strings,
  825. DebugInlineeLinesSubsectionRef &Lines) {
  826. P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
  827. for (const auto &Entry : Lines) {
  828. P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
  829. fmtle(Entry.Header->SourceLineNum));
  830. Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
  831. for (const auto &ExtraFileID : Entry.ExtraFiles) {
  832. P.formatLine(" ");
  833. Strings.formatFromChecksumsOffset(P, ExtraFileID, true);
  834. }
  835. }
  836. P.NewLine();
  837. });
  838. return Error::success();
  839. }
  840. Error DumpOutputStyle::dumpXmi() {
  841. printHeader(P, "Cross Module Imports");
  842. if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
  843. printStreamNotPresent("DBI");
  844. return Error::success();
  845. }
  846. iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
  847. File, PrintScope{P, 2},
  848. [this](uint32_t Modi, const SymbolGroup &Strings,
  849. DebugCrossModuleImportsSubsectionRef &Imports) {
  850. P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
  851. for (const auto &Xmi : Imports) {
  852. auto ExpectedModule =
  853. Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
  854. StringRef Module;
  855. SmallString<32> ModuleStorage;
  856. if (!ExpectedModule) {
  857. Module = "(unknown module)";
  858. consumeError(ExpectedModule.takeError());
  859. } else
  860. Module = *ExpectedModule;
  861. if (Module.size() > 32) {
  862. ModuleStorage = "...";
  863. ModuleStorage += Module.take_back(32 - 3);
  864. Module = ModuleStorage;
  865. }
  866. std::vector<std::string> TIs;
  867. for (const auto I : Xmi.Imports)
  868. TIs.push_back(std::string(formatv("{0,+10:X+}", fmtle(I))));
  869. std::string Result =
  870. typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
  871. P.formatLine("{0,+32} | {1}", Module, Result);
  872. }
  873. });
  874. return Error::success();
  875. }
  876. Error DumpOutputStyle::dumpXme() {
  877. printHeader(P, "Cross Module Exports");
  878. if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
  879. printStreamNotPresent("DBI");
  880. return Error::success();
  881. }
  882. iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
  883. File, PrintScope{P, 2},
  884. [this](uint32_t Modi, const SymbolGroup &Strings,
  885. DebugCrossModuleExportsSubsectionRef &Exports) {
  886. P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
  887. for (const auto &Export : Exports) {
  888. P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
  889. TypeIndex(Export.Global));
  890. }
  891. });
  892. return Error::success();
  893. }
  894. std::string formatFrameType(object::frame_type FT) {
  895. switch (FT) {
  896. case object::frame_type::Fpo:
  897. return "FPO";
  898. case object::frame_type::NonFpo:
  899. return "Non-FPO";
  900. case object::frame_type::Trap:
  901. return "Trap";
  902. case object::frame_type::Tss:
  903. return "TSS";
  904. }
  905. return "<unknown>";
  906. }
  907. Error DumpOutputStyle::dumpOldFpo(PDBFile &File) {
  908. printHeader(P, "Old FPO Data");
  909. ExitOnError Err("Error dumping old fpo data:");
  910. auto &Dbi = Err(File.getPDBDbiStream());
  911. if (!Dbi.hasOldFpoRecords()) {
  912. printStreamNotPresent("FPO");
  913. return Error::success();
  914. }
  915. const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords();
  916. P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use "
  917. "BP | Has SEH | Frame Type");
  918. for (const object::FpoData &FD : Records) {
  919. P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | "
  920. "{7,7} | {8,9}",
  921. uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals),
  922. uint32_t(FD.NumParams), FD.getPrologSize(),
  923. FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(),
  924. formatFrameType(FD.getFP()));
  925. }
  926. return Error::success();
  927. }
  928. Error DumpOutputStyle::dumpNewFpo(PDBFile &File) {
  929. printHeader(P, "New FPO Data");
  930. ExitOnError Err("Error dumping new fpo data:");
  931. auto &Dbi = Err(File.getPDBDbiStream());
  932. if (!Dbi.hasNewFpoRecords()) {
  933. printStreamNotPresent("New FPO");
  934. return Error::success();
  935. }
  936. const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords();
  937. P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs "
  938. "| Has SEH | Has C++EH | Start | Program");
  939. for (const FrameData &FD : FDS) {
  940. bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart;
  941. bool HasEH = FD.Flags & FrameData::HasEH;
  942. bool HasSEH = FD.Flags & FrameData::HasSEH;
  943. auto &StringTable = Err(File.getStringTable());
  944. auto Program = Err(StringTable.getStringForID(FD.FrameFunc));
  945. P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | "
  946. "{7,7} | {8,9} | {9,5} | {10}",
  947. uint32_t(FD.RvaStart), uint32_t(FD.CodeSize),
  948. uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize),
  949. uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize),
  950. uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart,
  951. Program);
  952. }
  953. return Error::success();
  954. }
  955. Error DumpOutputStyle::dumpFpo() {
  956. if (!File.isPdb()) {
  957. printStreamNotValidForObj();
  958. return Error::success();
  959. }
  960. PDBFile &File = getPdb();
  961. if (!File.hasPDBDbiStream()) {
  962. printStreamNotPresent("DBI");
  963. return Error::success();
  964. }
  965. if (auto EC = dumpOldFpo(File))
  966. return EC;
  967. if (auto EC = dumpNewFpo(File))
  968. return EC;
  969. return Error::success();
  970. }
  971. Error DumpOutputStyle::dumpStringTableFromPdb() {
  972. AutoIndent Indent(P);
  973. auto IS = getPdb().getStringTable();
  974. if (!IS) {
  975. P.formatLine("Not present in file");
  976. consumeError(IS.takeError());
  977. return Error::success();
  978. }
  979. if (opts::dump::DumpStringTable) {
  980. if (IS->name_ids().empty())
  981. P.formatLine("Empty");
  982. else {
  983. auto MaxID =
  984. std::max_element(IS->name_ids().begin(), IS->name_ids().end());
  985. uint32_t Digits = NumDigits(*MaxID);
  986. P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
  987. "String");
  988. std::vector<uint32_t> SortedIDs(IS->name_ids().begin(),
  989. IS->name_ids().end());
  990. llvm::sort(SortedIDs);
  991. for (uint32_t I : SortedIDs) {
  992. auto ES = IS->getStringForID(I);
  993. llvm::SmallString<32> Str;
  994. if (!ES) {
  995. consumeError(ES.takeError());
  996. Str = "Error reading string";
  997. } else if (!ES->empty()) {
  998. Str.append("'");
  999. Str.append(*ES);
  1000. Str.append("'");
  1001. }
  1002. if (!Str.empty())
  1003. P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits),
  1004. Str);
  1005. }
  1006. }
  1007. }
  1008. if (opts::dump::DumpStringTableDetails) {
  1009. P.NewLine();
  1010. {
  1011. P.printLine("String Table Header:");
  1012. AutoIndent Indent(P);
  1013. P.formatLine("Signature: {0}", IS->getSignature());
  1014. P.formatLine("Hash Version: {0}", IS->getHashVersion());
  1015. P.formatLine("Name Buffer Size: {0}", IS->getByteSize());
  1016. P.NewLine();
  1017. }
  1018. BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer();
  1019. ArrayRef<uint8_t> Contents;
  1020. cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents));
  1021. P.formatBinary("Name Buffer", Contents, 0);
  1022. P.NewLine();
  1023. {
  1024. P.printLine("Hash Table:");
  1025. AutoIndent Indent(P);
  1026. P.formatLine("Bucket Count: {0}", IS->name_ids().size());
  1027. for (const auto &Entry : enumerate(IS->name_ids()))
  1028. P.formatLine("Bucket[{0}] : {1}", Entry.index(),
  1029. uint32_t(Entry.value()));
  1030. P.formatLine("Name Count: {0}", IS->getNameCount());
  1031. }
  1032. }
  1033. return Error::success();
  1034. }
  1035. Error DumpOutputStyle::dumpStringTableFromObj() {
  1036. iterateModuleSubsections<DebugStringTableSubsectionRef>(
  1037. File, PrintScope{P, 4},
  1038. [&](uint32_t Modi, const SymbolGroup &Strings,
  1039. DebugStringTableSubsectionRef &Strings2) {
  1040. BinaryStreamRef StringTableBuffer = Strings2.getBuffer();
  1041. BinaryStreamReader Reader(StringTableBuffer);
  1042. while (Reader.bytesRemaining() > 0) {
  1043. StringRef Str;
  1044. uint32_t Offset = Reader.getOffset();
  1045. cantFail(Reader.readCString(Str));
  1046. if (Str.empty())
  1047. continue;
  1048. P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4),
  1049. Str);
  1050. }
  1051. });
  1052. return Error::success();
  1053. }
  1054. Error DumpOutputStyle::dumpNamedStreams() {
  1055. printHeader(P, "Named Streams");
  1056. if (File.isObj()) {
  1057. printStreamNotValidForObj();
  1058. return Error::success();
  1059. }
  1060. AutoIndent Indent(P);
  1061. ExitOnError Err("Invalid PDB File: ");
  1062. auto &IS = Err(File.pdb().getPDBInfoStream());
  1063. const NamedStreamMap &NS = IS.getNamedStreams();
  1064. for (const auto &Entry : NS.entries()) {
  1065. P.printLine(Entry.getKey());
  1066. AutoIndent Indent2(P, 2);
  1067. P.formatLine("Index: {0}", Entry.getValue());
  1068. P.formatLine("Size in bytes: {0}",
  1069. File.pdb().getStreamByteSize(Entry.getValue()));
  1070. }
  1071. return Error::success();
  1072. }
  1073. Error DumpOutputStyle::dumpStringTable() {
  1074. printHeader(P, "String Table");
  1075. if (File.isPdb())
  1076. return dumpStringTableFromPdb();
  1077. return dumpStringTableFromObj();
  1078. }
  1079. static void buildDepSet(LazyRandomTypeCollection &Types,
  1080. ArrayRef<TypeIndex> Indices,
  1081. std::map<TypeIndex, CVType> &DepSet) {
  1082. SmallVector<TypeIndex, 4> DepList;
  1083. for (const auto &I : Indices) {
  1084. TypeIndex TI(I);
  1085. if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
  1086. continue;
  1087. CVType Type = Types.getType(TI);
  1088. DepSet[TI] = Type;
  1089. codeview::discoverTypeIndices(Type, DepList);
  1090. buildDepSet(Types, DepList, DepSet);
  1091. }
  1092. }
  1093. static void
  1094. dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
  1095. TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
  1096. uint32_t NumHashBuckets,
  1097. FixedStreamArray<support::ulittle32_t> HashValues,
  1098. TpiStream *Stream, bool Bytes, bool Extras) {
  1099. Printer.formatLine("Showing {0:N} records", NumTypeRecords);
  1100. uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
  1101. MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
  1102. NumHashBuckets, HashValues, Stream);
  1103. if (auto EC = codeview::visitTypeStream(Types, V)) {
  1104. Printer.formatLine("An error occurred dumping type records: {0}",
  1105. toString(std::move(EC)));
  1106. }
  1107. }
  1108. static void dumpPartialTypeStream(LinePrinter &Printer,
  1109. LazyRandomTypeCollection &Types,
  1110. TypeReferenceTracker *RefTracker,
  1111. TpiStream &Stream, ArrayRef<TypeIndex> TiList,
  1112. bool Bytes, bool Extras, bool Deps) {
  1113. uint32_t Width =
  1114. NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
  1115. MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
  1116. Stream.getNumHashBuckets(), Stream.getHashValues(),
  1117. &Stream);
  1118. if (opts::dump::DumpTypeDependents) {
  1119. // If we need to dump all dependents, then iterate each index and find
  1120. // all dependents, adding them to a map ordered by TypeIndex.
  1121. std::map<TypeIndex, CVType> DepSet;
  1122. buildDepSet(Types, TiList, DepSet);
  1123. Printer.formatLine(
  1124. "Showing {0:N} records and their dependents ({1:N} records total)",
  1125. TiList.size(), DepSet.size());
  1126. for (auto &Dep : DepSet) {
  1127. if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
  1128. Printer.formatLine("An error occurred dumping type record {0}: {1}",
  1129. Dep.first, toString(std::move(EC)));
  1130. }
  1131. } else {
  1132. Printer.formatLine("Showing {0:N} records.", TiList.size());
  1133. for (const auto &I : TiList) {
  1134. TypeIndex TI(I);
  1135. CVType Type = Types.getType(TI);
  1136. if (auto EC = codeview::visitTypeRecord(Type, TI, V))
  1137. Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
  1138. toString(std::move(EC)));
  1139. }
  1140. }
  1141. }
  1142. Error DumpOutputStyle::dumpTypesFromObjectFile() {
  1143. LazyRandomTypeCollection Types(100);
  1144. for (const auto &S : getObj().sections()) {
  1145. Expected<StringRef> NameOrErr = S.getName();
  1146. if (!NameOrErr)
  1147. return NameOrErr.takeError();
  1148. StringRef SectionName = *NameOrErr;
  1149. // .debug$T is a standard CodeView type section, while .debug$P is the same
  1150. // format but used for MSVC precompiled header object files.
  1151. if (SectionName == ".debug$T")
  1152. printHeader(P, "Types (.debug$T)");
  1153. else if (SectionName == ".debug$P")
  1154. printHeader(P, "Precompiled Types (.debug$P)");
  1155. else
  1156. continue;
  1157. Expected<StringRef> ContentsOrErr = S.getContents();
  1158. if (!ContentsOrErr)
  1159. return ContentsOrErr.takeError();
  1160. uint32_t Magic;
  1161. BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little);
  1162. if (auto EC = Reader.readInteger(Magic))
  1163. return EC;
  1164. if (Magic != COFF::DEBUG_SECTION_MAGIC)
  1165. return make_error<StringError>("Invalid CodeView debug section.",
  1166. inconvertibleErrorCode());
  1167. Types.reset(Reader, 100);
  1168. if (opts::dump::DumpTypes) {
  1169. dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
  1170. opts::dump::DumpTypeData, false);
  1171. } else if (opts::dump::DumpTypeExtras) {
  1172. auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
  1173. auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
  1174. assert(LocalHashes.size() == GlobalHashes.size());
  1175. P.formatLine("Local / Global hashes:");
  1176. TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
  1177. for (auto H : zip(LocalHashes, GlobalHashes)) {
  1178. AutoIndent Indent2(P);
  1179. LocallyHashedType &L = std::get<0>(H);
  1180. GloballyHashedType &G = std::get<1>(H);
  1181. P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G);
  1182. ++TI;
  1183. }
  1184. P.NewLine();
  1185. }
  1186. }
  1187. return Error::success();
  1188. }
  1189. Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
  1190. assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
  1191. if (StreamIdx == StreamTPI) {
  1192. printHeader(P, "Types (TPI Stream)");
  1193. } else if (StreamIdx == StreamIPI) {
  1194. printHeader(P, "Types (IPI Stream)");
  1195. }
  1196. assert(!File.isObj());
  1197. bool Present = false;
  1198. bool DumpTypes = false;
  1199. bool DumpBytes = false;
  1200. bool DumpExtras = false;
  1201. std::vector<uint32_t> Indices;
  1202. if (StreamIdx == StreamTPI) {
  1203. Present = getPdb().hasPDBTpiStream();
  1204. DumpTypes = opts::dump::DumpTypes;
  1205. DumpBytes = opts::dump::DumpTypeData;
  1206. DumpExtras = opts::dump::DumpTypeExtras;
  1207. Indices.assign(opts::dump::DumpTypeIndex.begin(),
  1208. opts::dump::DumpTypeIndex.end());
  1209. } else if (StreamIdx == StreamIPI) {
  1210. Present = getPdb().hasPDBIpiStream();
  1211. DumpTypes = opts::dump::DumpIds;
  1212. DumpBytes = opts::dump::DumpIdData;
  1213. DumpExtras = opts::dump::DumpIdExtras;
  1214. Indices.assign(opts::dump::DumpIdIndex.begin(),
  1215. opts::dump::DumpIdIndex.end());
  1216. }
  1217. if (!Present) {
  1218. printStreamNotPresent(StreamIdx == StreamTPI ? "TPI" : "IPI");
  1219. return Error::success();
  1220. }
  1221. AutoIndent Indent(P);
  1222. ExitOnError Err("Unexpected error processing types: ");
  1223. auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
  1224. : getPdb().getPDBIpiStream());
  1225. auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
  1226. // Only emit notes about referenced/unreferenced for types.
  1227. TypeReferenceTracker *MaybeTracker =
  1228. (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
  1229. // Enable resolving forward decls.
  1230. Stream.buildHashMap();
  1231. if (DumpTypes || !Indices.empty()) {
  1232. if (Indices.empty())
  1233. dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
  1234. Stream.getNumHashBuckets(), Stream.getHashValues(),
  1235. &Stream, DumpBytes, DumpExtras);
  1236. else {
  1237. std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
  1238. dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
  1239. DumpExtras, opts::dump::DumpTypeDependents);
  1240. }
  1241. }
  1242. if (DumpExtras) {
  1243. P.NewLine();
  1244. P.formatLine("Header Version: {0}",
  1245. static_cast<uint32_t>(Stream.getTpiVersion()));
  1246. P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex());
  1247. P.formatLine("Aux Hash Stream Index: {0}",
  1248. Stream.getTypeHashStreamAuxIndex());
  1249. P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize());
  1250. P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets());
  1251. auto IndexOffsets = Stream.getTypeIndexOffsets();
  1252. P.formatLine("Type Index Offsets:");
  1253. for (const auto &IO : IndexOffsets) {
  1254. AutoIndent Indent2(P);
  1255. P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
  1256. }
  1257. if (getPdb().hasPDBStringTable()) {
  1258. P.NewLine();
  1259. P.formatLine("Hash Adjusters:");
  1260. auto &Adjusters = Stream.getHashAdjusters();
  1261. auto &Strings = Err(getPdb().getStringTable());
  1262. for (const auto &A : Adjusters) {
  1263. AutoIndent Indent2(P);
  1264. auto ExpectedStr = Strings.getStringForID(A.first);
  1265. TypeIndex TI(A.second);
  1266. if (ExpectedStr)
  1267. P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
  1268. else {
  1269. P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
  1270. consumeError(ExpectedStr.takeError());
  1271. }
  1272. }
  1273. }
  1274. }
  1275. return Error::success();
  1276. }
  1277. Error DumpOutputStyle::dumpModuleSymsForObj() {
  1278. printHeader(P, "Symbols");
  1279. AutoIndent Indent(P);
  1280. ExitOnError Err("Unexpected error processing symbols: ");
  1281. auto &Types = File.types();
  1282. SymbolVisitorCallbackPipeline Pipeline;
  1283. SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
  1284. MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
  1285. Pipeline.addCallbackToPipeline(Deserializer);
  1286. Pipeline.addCallbackToPipeline(Dumper);
  1287. CVSymbolVisitor Visitor(Pipeline);
  1288. std::unique_ptr<llvm::Error> SymbolError;
  1289. iterateModuleSubsections<DebugSymbolsSubsectionRef>(
  1290. File, PrintScope{P, 2},
  1291. [&](uint32_t Modi, const SymbolGroup &Strings,
  1292. DebugSymbolsSubsectionRef &Symbols) {
  1293. Dumper.setSymbolGroup(&Strings);
  1294. for (auto Symbol : Symbols) {
  1295. if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
  1296. SymbolError = std::make_unique<Error>(std::move(EC));
  1297. return;
  1298. }
  1299. }
  1300. });
  1301. if (SymbolError)
  1302. return std::move(*SymbolError);
  1303. return Error::success();
  1304. }
  1305. Error DumpOutputStyle::dumpModuleSymsForPdb() {
  1306. printHeader(P, "Symbols");
  1307. if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
  1308. printStreamNotPresent("DBI");
  1309. return Error::success();
  1310. }
  1311. AutoIndent Indent(P);
  1312. ExitOnError Err("Unexpected error processing symbols: ");
  1313. auto &Ids = File.ids();
  1314. auto &Types = File.types();
  1315. iterateSymbolGroups(
  1316. File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) {
  1317. auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
  1318. if (!ExpectedModS) {
  1319. P.formatLine("Error loading module stream {0}. {1}", I,
  1320. toString(ExpectedModS.takeError()));
  1321. return;
  1322. }
  1323. ModuleDebugStreamRef &ModS = *ExpectedModS;
  1324. SymbolVisitorCallbackPipeline Pipeline;
  1325. SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
  1326. MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings,
  1327. Ids, Types);
  1328. Pipeline.addCallbackToPipeline(Deserializer);
  1329. Pipeline.addCallbackToPipeline(Dumper);
  1330. CVSymbolVisitor Visitor(Pipeline);
  1331. auto SS = ModS.getSymbolsSubstream();
  1332. if (auto EC =
  1333. Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
  1334. P.formatLine("Error while processing symbol records. {0}",
  1335. toString(std::move(EC)));
  1336. return;
  1337. }
  1338. });
  1339. return Error::success();
  1340. }
  1341. Error DumpOutputStyle::dumpTypeRefStats() {
  1342. printHeader(P, "Type Reference Statistics");
  1343. AutoIndent Indent(P);
  1344. // Sum the byte size of all type records, and the size and count of all
  1345. // referenced records.
  1346. size_t TotalRecs = File.types().size();
  1347. size_t RefRecs = 0;
  1348. size_t TotalBytes = 0;
  1349. size_t RefBytes = 0;
  1350. auto &Types = File.types();
  1351. for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
  1352. CVType Type = File.types().getType(*TI);
  1353. TotalBytes += Type.length();
  1354. if (RefTracker->isTypeReferenced(*TI)) {
  1355. ++RefRecs;
  1356. RefBytes += Type.length();
  1357. }
  1358. }
  1359. P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
  1360. (double)RefRecs / TotalRecs);
  1361. P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
  1362. (double)RefBytes / TotalBytes);
  1363. return Error::success();
  1364. }
  1365. Error DumpOutputStyle::dumpGSIRecords() {
  1366. printHeader(P, "GSI Records");
  1367. if (File.isObj()) {
  1368. printStreamNotValidForObj();
  1369. return Error::success();
  1370. }
  1371. if (!getPdb().hasPDBSymbolStream()) {
  1372. printStreamNotPresent("GSI Common Symbol");
  1373. return Error::success();
  1374. }
  1375. AutoIndent Indent(P);
  1376. auto &Records = cantFail(getPdb().getPDBSymbolStream());
  1377. auto &Types = File.types();
  1378. auto &Ids = File.ids();
  1379. P.printLine("Records");
  1380. SymbolVisitorCallbackPipeline Pipeline;
  1381. SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
  1382. MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
  1383. Pipeline.addCallbackToPipeline(Deserializer);
  1384. Pipeline.addCallbackToPipeline(Dumper);
  1385. CVSymbolVisitor Visitor(Pipeline);
  1386. BinaryStreamRef SymStream = Records.getSymbolArray().getUnderlyingStream();
  1387. if (auto E = Visitor.visitSymbolStream(Records.getSymbolArray(), 0))
  1388. return E;
  1389. return Error::success();
  1390. }
  1391. Error DumpOutputStyle::dumpGlobals() {
  1392. printHeader(P, "Global Symbols");
  1393. if (File.isObj()) {
  1394. printStreamNotValidForObj();
  1395. return Error::success();
  1396. }
  1397. if (!getPdb().hasPDBGlobalsStream()) {
  1398. printStreamNotPresent("Globals");
  1399. return Error::success();
  1400. }
  1401. AutoIndent Indent(P);
  1402. ExitOnError Err("Error dumping globals stream: ");
  1403. auto &Globals = Err(getPdb().getPDBGlobalsStream());
  1404. if (opts::dump::DumpGlobalNames.empty()) {
  1405. const GSIHashTable &Table = Globals.getGlobalsTable();
  1406. Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
  1407. } else {
  1408. SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream());
  1409. auto &Types = File.types();
  1410. auto &Ids = File.ids();
  1411. SymbolVisitorCallbackPipeline Pipeline;
  1412. SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
  1413. MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
  1414. Pipeline.addCallbackToPipeline(Deserializer);
  1415. Pipeline.addCallbackToPipeline(Dumper);
  1416. CVSymbolVisitor Visitor(Pipeline);
  1417. using ResultEntryType = std::pair<uint32_t, CVSymbol>;
  1418. for (StringRef Name : opts::dump::DumpGlobalNames) {
  1419. AutoIndent Indent(P);
  1420. P.formatLine("Global Name `{0}`", Name);
  1421. std::vector<ResultEntryType> Results =
  1422. Globals.findRecordsByName(Name, SymRecords);
  1423. if (Results.empty()) {
  1424. AutoIndent Indent(P);
  1425. P.printLine("(no matching records found)");
  1426. continue;
  1427. }
  1428. for (ResultEntryType Result : Results) {
  1429. if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first))
  1430. return E;
  1431. }
  1432. }
  1433. }
  1434. return Error::success();
  1435. }
  1436. Error DumpOutputStyle::dumpPublics() {
  1437. printHeader(P, "Public Symbols");
  1438. if (File.isObj()) {
  1439. printStreamNotValidForObj();
  1440. return Error::success();
  1441. }
  1442. if (!getPdb().hasPDBPublicsStream()) {
  1443. printStreamNotPresent("Publics");
  1444. return Error::success();
  1445. }
  1446. AutoIndent Indent(P);
  1447. ExitOnError Err("Error dumping publics stream: ");
  1448. auto &Publics = Err(getPdb().getPDBPublicsStream());
  1449. const GSIHashTable &PublicsTable = Publics.getPublicsTable();
  1450. if (opts::dump::DumpPublicExtras) {
  1451. P.printLine("Publics Header");
  1452. AutoIndent Indent(P);
  1453. P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
  1454. formatSegmentOffset(Publics.getThunkTableSection(),
  1455. Publics.getThunkTableOffset()));
  1456. }
  1457. Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
  1458. // Skip the rest if we aren't dumping extras.
  1459. if (!opts::dump::DumpPublicExtras)
  1460. return Error::success();
  1461. P.formatLine("Address Map");
  1462. {
  1463. // These are offsets into the publics stream sorted by secidx:secrel.
  1464. AutoIndent Indent2(P);
  1465. for (uint32_t Addr : Publics.getAddressMap())
  1466. P.formatLine("off = {0}", Addr);
  1467. }
  1468. // The thunk map is optional debug info used for ILT thunks.
  1469. if (!Publics.getThunkMap().empty()) {
  1470. P.formatLine("Thunk Map");
  1471. AutoIndent Indent2(P);
  1472. for (uint32_t Addr : Publics.getThunkMap())
  1473. P.formatLine("{0:x8}", Addr);
  1474. }
  1475. // The section offsets table appears to be empty when incremental linking
  1476. // isn't in use.
  1477. if (!Publics.getSectionOffsets().empty()) {
  1478. P.formatLine("Section Offsets");
  1479. AutoIndent Indent2(P);
  1480. for (const SectionOffset &SO : Publics.getSectionOffsets())
  1481. P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
  1482. }
  1483. return Error::success();
  1484. }
  1485. Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
  1486. bool HashExtras) {
  1487. auto ExpectedSyms = getPdb().getPDBSymbolStream();
  1488. if (!ExpectedSyms)
  1489. return ExpectedSyms.takeError();
  1490. auto &Types = File.types();
  1491. auto &Ids = File.ids();
  1492. if (HashExtras) {
  1493. P.printLine("GSI Header");
  1494. AutoIndent Indent(P);
  1495. P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
  1496. Table.getVerSignature(), Table.getVerHeader(),
  1497. Table.getHashRecordSize(), Table.getNumBuckets());
  1498. }
  1499. {
  1500. P.printLine("Records");
  1501. SymbolVisitorCallbackPipeline Pipeline;
  1502. SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
  1503. MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
  1504. Pipeline.addCallbackToPipeline(Deserializer);
  1505. Pipeline.addCallbackToPipeline(Dumper);
  1506. CVSymbolVisitor Visitor(Pipeline);
  1507. BinaryStreamRef SymStream =
  1508. ExpectedSyms->getSymbolArray().getUnderlyingStream();
  1509. for (uint32_t PubSymOff : Table) {
  1510. Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
  1511. if (!Sym)
  1512. return Sym.takeError();
  1513. if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
  1514. return E;
  1515. }
  1516. }
  1517. // Return early if we aren't dumping public hash table and address map info.
  1518. if (HashExtras) {
  1519. P.formatLine("Hash Entries");
  1520. {
  1521. AutoIndent Indent2(P);
  1522. for (const PSHashRecord &HR : Table.HashRecords)
  1523. P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
  1524. uint32_t(HR.CRef));
  1525. }
  1526. P.formatLine("Hash Buckets");
  1527. {
  1528. AutoIndent Indent2(P);
  1529. for (uint32_t Hash : Table.HashBuckets)
  1530. P.formatLine("{0:x8}", Hash);
  1531. }
  1532. }
  1533. return Error::success();
  1534. }
  1535. static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
  1536. OMFSegDescFlags Flags) {
  1537. std::vector<std::string> Opts;
  1538. if (Flags == OMFSegDescFlags::None)
  1539. return "none";
  1540. PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
  1541. PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
  1542. PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
  1543. PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
  1544. PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
  1545. PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
  1546. PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
  1547. return typesetItemList(Opts, IndentLevel, 4, " | ");
  1548. }
  1549. Error DumpOutputStyle::dumpSectionHeaders() {
  1550. dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
  1551. dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
  1552. return Error::success();
  1553. }
  1554. void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
  1555. printHeader(P, Label);
  1556. if (File.isObj()) {
  1557. printStreamNotValidForObj();
  1558. return;
  1559. }
  1560. if (!getPdb().hasPDBDbiStream()) {
  1561. printStreamNotPresent("DBI");
  1562. return;
  1563. }
  1564. AutoIndent Indent(P);
  1565. ExitOnError Err("Error dumping section headers: ");
  1566. std::unique_ptr<MappedBlockStream> Stream;
  1567. ArrayRef<object::coff_section> Headers;
  1568. auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
  1569. if (!ExpectedHeaders) {
  1570. P.printLine(toString(ExpectedHeaders.takeError()));
  1571. return;
  1572. }
  1573. std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
  1574. uint32_t I = 1;
  1575. for (const auto &Header : Headers) {
  1576. P.NewLine();
  1577. P.formatLine("SECTION HEADER #{0}", I);
  1578. P.formatLine("{0,8} name", Header.Name);
  1579. P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
  1580. P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
  1581. P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
  1582. P.formatLine("{0,8:X-} file pointer to raw data",
  1583. uint32_t(Header.PointerToRawData));
  1584. P.formatLine("{0,8:X-} file pointer to relocation table",
  1585. uint32_t(Header.PointerToRelocations));
  1586. P.formatLine("{0,8:X-} file pointer to line numbers",
  1587. uint32_t(Header.PointerToLinenumbers));
  1588. P.formatLine("{0,8:X-} number of relocations",
  1589. uint32_t(Header.NumberOfRelocations));
  1590. P.formatLine("{0,8:X-} number of line numbers",
  1591. uint32_t(Header.NumberOfLinenumbers));
  1592. P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
  1593. AutoIndent IndentMore(P, 9);
  1594. P.formatLine("{0}", formatSectionCharacteristics(
  1595. P.getIndentLevel(), Header.Characteristics, 1, ""));
  1596. ++I;
  1597. }
  1598. }
  1599. Error DumpOutputStyle::dumpSectionContribs() {
  1600. printHeader(P, "Section Contributions");
  1601. if (File.isObj()) {
  1602. printStreamNotValidForObj();
  1603. return Error::success();
  1604. }
  1605. if (!getPdb().hasPDBDbiStream()) {
  1606. printStreamNotPresent("DBI");
  1607. return Error::success();
  1608. }
  1609. AutoIndent Indent(P);
  1610. ExitOnError Err("Error dumping section contributions: ");
  1611. auto &Dbi = Err(getPdb().getPDBDbiStream());
  1612. class Visitor : public ISectionContribVisitor {
  1613. public:
  1614. Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
  1615. auto Max = std::max_element(
  1616. Names.begin(), Names.end(),
  1617. [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); });
  1618. MaxNameLen = (Max == Names.end() ? 0 : Max->size());
  1619. }
  1620. void visit(const SectionContrib &SC) override {
  1621. dumpSectionContrib(P, SC, Names, MaxNameLen);
  1622. }
  1623. void visit(const SectionContrib2 &SC) override {
  1624. dumpSectionContrib(P, SC, Names, MaxNameLen);
  1625. }
  1626. private:
  1627. LinePrinter &P;
  1628. uint32_t MaxNameLen;
  1629. ArrayRef<std::string> Names;
  1630. };
  1631. std::vector<std::string> Names = getSectionNames(getPdb());
  1632. Visitor V(P, makeArrayRef(Names));
  1633. Dbi.visitSectionContributions(V);
  1634. return Error::success();
  1635. }
  1636. Error DumpOutputStyle::dumpSectionMap() {
  1637. printHeader(P, "Section Map");
  1638. if (File.isObj()) {
  1639. printStreamNotValidForObj();
  1640. return Error::success();
  1641. }
  1642. if (!getPdb().hasPDBDbiStream()) {
  1643. printStreamNotPresent("DBI");
  1644. return Error::success();
  1645. }
  1646. AutoIndent Indent(P);
  1647. ExitOnError Err("Error dumping section map: ");
  1648. auto &Dbi = Err(getPdb().getPDBDbiStream());
  1649. uint32_t I = 0;
  1650. for (auto &M : Dbi.getSectionMap()) {
  1651. P.formatLine(
  1652. "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
  1653. fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
  1654. P.formatLine(" class = {0}, offset = {1}, size = {2}",
  1655. fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
  1656. P.formatLine(" flags = {0}",
  1657. formatSegMapDescriptorFlag(
  1658. P.getIndentLevel() + 13,
  1659. static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
  1660. ++I;
  1661. }
  1662. return Error::success();
  1663. }