BytesOutputStyle.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. //===- BytesOutputStyle.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 "BytesOutputStyle.h"
  9. #include "StreamUtil.h"
  10. #include "llvm-pdbutil.h"
  11. #include "llvm/DebugInfo/CodeView/Formatters.h"
  12. #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
  13. #include "llvm/DebugInfo/MSF/MSFCommon.h"
  14. #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
  15. #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
  16. #include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
  17. #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
  18. #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
  19. #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
  20. #include "llvm/DebugInfo/PDB/Native/RawError.h"
  21. #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
  22. #include "llvm/Support/BinaryStreamReader.h"
  23. #include "llvm/Support/FormatAdapters.h"
  24. #include "llvm/Support/FormatVariadic.h"
  25. using namespace llvm;
  26. using namespace llvm::codeview;
  27. using namespace llvm::msf;
  28. using namespace llvm::pdb;
  29. namespace {
  30. struct StreamSpec {
  31. uint32_t SI = 0;
  32. uint32_t Begin = 0;
  33. uint32_t Size = 0;
  34. };
  35. } // namespace
  36. static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
  37. StreamSpec Result;
  38. if (Str.consumeInteger(0, Result.SI))
  39. return make_error<RawError>(raw_error_code::invalid_format,
  40. "Invalid Stream Specification");
  41. if (Str.consume_front(":")) {
  42. if (Str.consumeInteger(0, Result.Begin))
  43. return make_error<RawError>(raw_error_code::invalid_format,
  44. "Invalid Stream Specification");
  45. }
  46. if (Str.consume_front("@")) {
  47. if (Str.consumeInteger(0, Result.Size))
  48. return make_error<RawError>(raw_error_code::invalid_format,
  49. "Invalid Stream Specification");
  50. }
  51. if (!Str.empty())
  52. return make_error<RawError>(raw_error_code::invalid_format,
  53. "Invalid Stream Specification");
  54. return Result;
  55. }
  56. static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
  57. SmallVector<StreamSpec, 2> Result;
  58. for (auto &Str : opts::bytes::DumpStreamData) {
  59. auto ESS = parseStreamSpec(Str);
  60. if (!ESS) {
  61. P.formatLine("Error parsing stream spec {0}: {1}", Str,
  62. toString(ESS.takeError()));
  63. continue;
  64. }
  65. Result.push_back(*ESS);
  66. }
  67. return Result;
  68. }
  69. static void printHeader(LinePrinter &P, const Twine &S) {
  70. P.NewLine();
  71. P.formatLine("{0,=60}", S);
  72. P.formatLine("{0}", fmt_repeat('=', 60));
  73. }
  74. BytesOutputStyle::BytesOutputStyle(PDBFile &File)
  75. : File(File), P(2, false, outs(), opts::Filters) {}
  76. Error BytesOutputStyle::dump() {
  77. if (opts::bytes::DumpBlockRange) {
  78. auto &R = *opts::bytes::DumpBlockRange;
  79. uint32_t Max = R.Max.value_or(R.Min);
  80. if (Max < R.Min)
  81. return make_error<StringError>(
  82. "Invalid block range specified. Max < Min",
  83. inconvertibleErrorCode());
  84. if (Max >= File.getBlockCount())
  85. return make_error<StringError>(
  86. "Invalid block range specified. Requested block out of bounds",
  87. inconvertibleErrorCode());
  88. dumpBlockRanges(R.Min, Max);
  89. P.NewLine();
  90. }
  91. if (opts::bytes::DumpByteRange) {
  92. auto &R = *opts::bytes::DumpByteRange;
  93. uint32_t Max = R.Max.value_or(File.getFileSize());
  94. if (Max < R.Min)
  95. return make_error<StringError>("Invalid byte range specified. Max < Min",
  96. inconvertibleErrorCode());
  97. if (Max >= File.getFileSize())
  98. return make_error<StringError>(
  99. "Invalid byte range specified. Requested byte larger than file size",
  100. inconvertibleErrorCode());
  101. dumpByteRanges(R.Min, Max);
  102. P.NewLine();
  103. }
  104. if (opts::bytes::Fpm) {
  105. dumpFpm();
  106. P.NewLine();
  107. }
  108. if (!opts::bytes::DumpStreamData.empty()) {
  109. dumpStreamBytes();
  110. P.NewLine();
  111. }
  112. if (opts::bytes::NameMap) {
  113. dumpNameMap();
  114. P.NewLine();
  115. }
  116. if (opts::bytes::SectionContributions) {
  117. dumpSectionContributions();
  118. P.NewLine();
  119. }
  120. if (opts::bytes::SectionMap) {
  121. dumpSectionMap();
  122. P.NewLine();
  123. }
  124. if (opts::bytes::ModuleInfos) {
  125. dumpModuleInfos();
  126. P.NewLine();
  127. }
  128. if (opts::bytes::FileInfo) {
  129. dumpFileInfo();
  130. P.NewLine();
  131. }
  132. if (opts::bytes::TypeServerMap) {
  133. dumpTypeServerMap();
  134. P.NewLine();
  135. }
  136. if (opts::bytes::ECData) {
  137. dumpECData();
  138. P.NewLine();
  139. }
  140. if (!opts::bytes::TypeIndex.empty()) {
  141. dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
  142. P.NewLine();
  143. }
  144. if (!opts::bytes::IdIndex.empty()) {
  145. dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
  146. P.NewLine();
  147. }
  148. if (opts::bytes::ModuleSyms) {
  149. dumpModuleSyms();
  150. P.NewLine();
  151. }
  152. if (opts::bytes::ModuleC11) {
  153. dumpModuleC11();
  154. P.NewLine();
  155. }
  156. if (opts::bytes::ModuleC13) {
  157. dumpModuleC13();
  158. P.NewLine();
  159. }
  160. return Error::success();
  161. }
  162. void BytesOutputStyle::dumpNameMap() {
  163. printHeader(P, "Named Stream Map");
  164. AutoIndent Indent(P);
  165. auto &InfoS = Err(File.getPDBInfoStream());
  166. BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
  167. auto Layout = File.getStreamLayout(StreamPDB);
  168. P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
  169. }
  170. void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
  171. printHeader(P, "MSF Blocks");
  172. AutoIndent Indent(P);
  173. for (uint32_t I = Min; I <= Max; ++I) {
  174. uint64_t Base = I;
  175. Base *= File.getBlockSize();
  176. auto ExpectedData = File.getBlockData(I, File.getBlockSize());
  177. if (!ExpectedData) {
  178. P.formatLine("Could not get block {0}. Reason = {1}", I,
  179. toString(ExpectedData.takeError()));
  180. continue;
  181. }
  182. std::string Label = formatv("Block {0}", I).str();
  183. P.formatBinary(Label, *ExpectedData, Base, 0);
  184. }
  185. }
  186. void BytesOutputStyle::dumpSectionContributions() {
  187. printHeader(P, "Section Contributions");
  188. AutoIndent Indent(P);
  189. auto &DbiS = Err(File.getPDBDbiStream());
  190. BinarySubstreamRef NS = DbiS.getSectionContributionData();
  191. auto Layout = File.getStreamLayout(StreamDBI);
  192. P.formatMsfStreamData("Section Contributions", File, Layout, NS);
  193. }
  194. void BytesOutputStyle::dumpSectionMap() {
  195. printHeader(P, "Section Map");
  196. AutoIndent Indent(P);
  197. auto &DbiS = Err(File.getPDBDbiStream());
  198. BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
  199. auto Layout = File.getStreamLayout(StreamDBI);
  200. P.formatMsfStreamData("Section Map", File, Layout, NS);
  201. }
  202. void BytesOutputStyle::dumpModuleInfos() {
  203. printHeader(P, "Module Infos");
  204. AutoIndent Indent(P);
  205. auto &DbiS = Err(File.getPDBDbiStream());
  206. BinarySubstreamRef NS = DbiS.getModiSubstreamData();
  207. auto Layout = File.getStreamLayout(StreamDBI);
  208. P.formatMsfStreamData("Module Infos", File, Layout, NS);
  209. }
  210. void BytesOutputStyle::dumpFileInfo() {
  211. printHeader(P, "File Info");
  212. AutoIndent Indent(P);
  213. auto &DbiS = Err(File.getPDBDbiStream());
  214. BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
  215. auto Layout = File.getStreamLayout(StreamDBI);
  216. P.formatMsfStreamData("File Info", File, Layout, NS);
  217. }
  218. void BytesOutputStyle::dumpTypeServerMap() {
  219. printHeader(P, "Type Server Map");
  220. AutoIndent Indent(P);
  221. auto &DbiS = Err(File.getPDBDbiStream());
  222. BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
  223. auto Layout = File.getStreamLayout(StreamDBI);
  224. P.formatMsfStreamData("Type Server Map", File, Layout, NS);
  225. }
  226. void BytesOutputStyle::dumpECData() {
  227. printHeader(P, "Edit and Continue Data");
  228. AutoIndent Indent(P);
  229. auto &DbiS = Err(File.getPDBDbiStream());
  230. BinarySubstreamRef NS = DbiS.getECSubstreamData();
  231. auto Layout = File.getStreamLayout(StreamDBI);
  232. P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
  233. }
  234. void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
  235. ArrayRef<uint32_t> Indices) {
  236. assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
  237. assert(!Indices.empty());
  238. bool IsTpi = (StreamIdx == StreamTPI);
  239. StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
  240. printHeader(P, Label);
  241. auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
  242. AutoIndent Indent(P);
  243. auto Substream = Stream.getTypeRecordsSubstream();
  244. auto &Types = Err(initializeTypes(StreamIdx));
  245. auto Layout = File.getStreamLayout(StreamIdx);
  246. for (const auto &Id : Indices) {
  247. TypeIndex TI(Id);
  248. if (TI.toArrayIndex() >= Types.capacity()) {
  249. P.formatLine("Error: TypeIndex {0} does not exist", TI);
  250. continue;
  251. }
  252. auto Type = Types.getType(TI);
  253. uint32_t Offset = Types.getOffsetOfType(TI);
  254. auto OneType = Substream.slice(Offset, Type.length());
  255. P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
  256. }
  257. }
  258. template <typename CallbackT>
  259. static void iterateOneModule(PDBFile &File, LinePrinter &P,
  260. const DbiModuleList &Modules, uint32_t I,
  261. uint32_t Digits, uint32_t IndentLevel,
  262. CallbackT Callback) {
  263. if (I >= Modules.getModuleCount()) {
  264. P.formatLine("Mod {0:4} | Invalid module index ",
  265. fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
  266. return;
  267. }
  268. auto Modi = Modules.getModuleDescriptor(I);
  269. P.formatLine("Mod {0:4} | `{1}`: ",
  270. fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
  271. Modi.getModuleName());
  272. uint16_t ModiStream = Modi.getModuleStreamIndex();
  273. AutoIndent Indent2(P, IndentLevel);
  274. if (ModiStream == kInvalidStreamIndex)
  275. return;
  276. auto ModStreamData = File.createIndexedStream(ModiStream);
  277. ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
  278. if (auto EC = ModStream.reload()) {
  279. P.formatLine("Could not parse debug information.");
  280. return;
  281. }
  282. auto Layout = File.getStreamLayout(ModiStream);
  283. Callback(I, ModStream, Layout);
  284. }
  285. template <typename CallbackT>
  286. static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
  287. CallbackT Callback) {
  288. AutoIndent Indent(P);
  289. if (!File.hasPDBDbiStream()) {
  290. P.formatLine("DBI Stream not present");
  291. return;
  292. }
  293. ExitOnError Err("Unexpected error processing modules");
  294. auto &Stream = Err(File.getPDBDbiStream());
  295. const DbiModuleList &Modules = Stream.modules();
  296. if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
  297. iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
  298. Callback);
  299. } else {
  300. uint32_t Count = Modules.getModuleCount();
  301. uint32_t Digits = NumDigits(Count);
  302. for (uint32_t I = 0; I < Count; ++I) {
  303. iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
  304. }
  305. }
  306. }
  307. void BytesOutputStyle::dumpModuleSyms() {
  308. printHeader(P, "Module Symbols");
  309. AutoIndent Indent(P);
  310. iterateModules(File, P, 2,
  311. [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
  312. const MSFStreamLayout &Layout) {
  313. auto Symbols = Stream.getSymbolsSubstream();
  314. P.formatMsfStreamData("Symbols", File, Layout, Symbols);
  315. });
  316. }
  317. void BytesOutputStyle::dumpModuleC11() {
  318. printHeader(P, "C11 Debug Chunks");
  319. AutoIndent Indent(P);
  320. iterateModules(File, P, 2,
  321. [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
  322. const MSFStreamLayout &Layout) {
  323. auto Chunks = Stream.getC11LinesSubstream();
  324. P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
  325. Chunks);
  326. });
  327. }
  328. void BytesOutputStyle::dumpModuleC13() {
  329. printHeader(P, "Debug Chunks");
  330. AutoIndent Indent(P);
  331. iterateModules(
  332. File, P, 2,
  333. [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
  334. const MSFStreamLayout &Layout) {
  335. auto Chunks = Stream.getC13LinesSubstream();
  336. if (opts::bytes::SplitChunks) {
  337. for (const auto &SS : Stream.subsections()) {
  338. BinarySubstreamRef ThisChunk;
  339. std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
  340. P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
  341. ThisChunk);
  342. }
  343. } else {
  344. P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
  345. }
  346. });
  347. }
  348. void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
  349. printHeader(P, "MSF Bytes");
  350. AutoIndent Indent(P);
  351. BinaryStreamReader Reader(File.getMsfBuffer());
  352. ArrayRef<uint8_t> Data;
  353. consumeError(Reader.skip(Min));
  354. uint32_t Size = Max - Min + 1;
  355. auto EC = Reader.readBytes(Data, Size);
  356. assert(!EC);
  357. consumeError(std::move(EC));
  358. P.formatBinary("Bytes", Data, Min);
  359. }
  360. Expected<codeview::LazyRandomTypeCollection &>
  361. BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
  362. auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
  363. if (TypeCollection)
  364. return *TypeCollection;
  365. auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
  366. : File.getPDBIpiStream();
  367. if (!Tpi)
  368. return Tpi.takeError();
  369. auto &Types = Tpi->typeArray();
  370. uint32_t Count = Tpi->getNumTypeRecords();
  371. auto Offsets = Tpi->getTypeIndexOffsets();
  372. TypeCollection =
  373. std::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
  374. return *TypeCollection;
  375. }
  376. void BytesOutputStyle::dumpFpm() {
  377. printHeader(P, "Free Page Map");
  378. msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();
  379. P.formatMsfStreamBlocks(File, FpmLayout);
  380. }
  381. void BytesOutputStyle::dumpStreamBytes() {
  382. if (StreamPurposes.empty())
  383. discoverStreamPurposes(File, StreamPurposes);
  384. printHeader(P, "Stream Data");
  385. ExitOnError Err("Unexpected error reading stream data");
  386. auto Specs = parseStreamSpecs(P);
  387. for (const auto &Spec : Specs) {
  388. AutoIndent Indent(P);
  389. if (Spec.SI >= StreamPurposes.size()) {
  390. P.formatLine("Stream {0}: Not present", Spec.SI);
  391. continue;
  392. }
  393. P.formatMsfStreamData("Data", File, Spec.SI,
  394. StreamPurposes[Spec.SI].getShortName(), Spec.Begin,
  395. Spec.Size);
  396. }
  397. }