DumpOutputStyle.cpp 62 KB

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