123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- //===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "BytesOutputStyle.h"
- #include "FormatUtil.h"
- #include "StreamUtil.h"
- #include "llvm-pdbutil.h"
- #include "llvm/DebugInfo/CodeView/Formatters.h"
- #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
- #include "llvm/DebugInfo/MSF/MSFCommon.h"
- #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
- #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
- #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
- #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
- #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
- #include "llvm/DebugInfo/PDB/Native/RawError.h"
- #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
- #include "llvm/Support/BinaryStreamReader.h"
- #include "llvm/Support/FormatAdapters.h"
- #include "llvm/Support/FormatVariadic.h"
- using namespace llvm;
- using namespace llvm::codeview;
- using namespace llvm::msf;
- using namespace llvm::pdb;
- namespace {
- struct StreamSpec {
- uint32_t SI = 0;
- uint32_t Begin = 0;
- uint32_t Size = 0;
- };
- } // namespace
- static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
- StreamSpec Result;
- if (Str.consumeInteger(0, Result.SI))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- if (Str.consume_front(":")) {
- if (Str.consumeInteger(0, Result.Begin))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- }
- if (Str.consume_front("@")) {
- if (Str.consumeInteger(0, Result.Size))
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- }
- if (!Str.empty())
- return make_error<RawError>(raw_error_code::invalid_format,
- "Invalid Stream Specification");
- return Result;
- }
- static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
- SmallVector<StreamSpec, 2> Result;
- for (auto &Str : opts::bytes::DumpStreamData) {
- auto ESS = parseStreamSpec(Str);
- if (!ESS) {
- P.formatLine("Error parsing stream spec {0}: {1}", Str,
- toString(ESS.takeError()));
- continue;
- }
- Result.push_back(*ESS);
- }
- return Result;
- }
- static void printHeader(LinePrinter &P, const Twine &S) {
- P.NewLine();
- P.formatLine("{0,=60}", S);
- P.formatLine("{0}", fmt_repeat('=', 60));
- }
- BytesOutputStyle::BytesOutputStyle(PDBFile &File)
- : File(File), P(2, false, outs()) {}
- Error BytesOutputStyle::dump() {
- if (opts::bytes::DumpBlockRange.hasValue()) {
- auto &R = *opts::bytes::DumpBlockRange;
- uint32_t Max = R.Max.getValueOr(R.Min);
- if (Max < R.Min)
- return make_error<StringError>(
- "Invalid block range specified. Max < Min",
- inconvertibleErrorCode());
- if (Max >= File.getBlockCount())
- return make_error<StringError>(
- "Invalid block range specified. Requested block out of bounds",
- inconvertibleErrorCode());
- dumpBlockRanges(R.Min, Max);
- P.NewLine();
- }
- if (opts::bytes::DumpByteRange.hasValue()) {
- auto &R = *opts::bytes::DumpByteRange;
- uint32_t Max = R.Max.getValueOr(File.getFileSize());
- if (Max < R.Min)
- return make_error<StringError>("Invalid byte range specified. Max < Min",
- inconvertibleErrorCode());
- if (Max >= File.getFileSize())
- return make_error<StringError>(
- "Invalid byte range specified. Requested byte larger than file size",
- inconvertibleErrorCode());
- dumpByteRanges(R.Min, Max);
- P.NewLine();
- }
- if (opts::bytes::Fpm) {
- dumpFpm();
- P.NewLine();
- }
- if (!opts::bytes::DumpStreamData.empty()) {
- dumpStreamBytes();
- P.NewLine();
- }
- if (opts::bytes::NameMap) {
- dumpNameMap();
- P.NewLine();
- }
- if (opts::bytes::SectionContributions) {
- dumpSectionContributions();
- P.NewLine();
- }
- if (opts::bytes::SectionMap) {
- dumpSectionMap();
- P.NewLine();
- }
- if (opts::bytes::ModuleInfos) {
- dumpModuleInfos();
- P.NewLine();
- }
- if (opts::bytes::FileInfo) {
- dumpFileInfo();
- P.NewLine();
- }
- if (opts::bytes::TypeServerMap) {
- dumpTypeServerMap();
- P.NewLine();
- }
- if (opts::bytes::ECData) {
- dumpECData();
- P.NewLine();
- }
- if (!opts::bytes::TypeIndex.empty()) {
- dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
- P.NewLine();
- }
- if (!opts::bytes::IdIndex.empty()) {
- dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
- P.NewLine();
- }
- if (opts::bytes::ModuleSyms) {
- dumpModuleSyms();
- P.NewLine();
- }
- if (opts::bytes::ModuleC11) {
- dumpModuleC11();
- P.NewLine();
- }
- if (opts::bytes::ModuleC13) {
- dumpModuleC13();
- P.NewLine();
- }
- return Error::success();
- }
- void BytesOutputStyle::dumpNameMap() {
- printHeader(P, "Named Stream Map");
- AutoIndent Indent(P);
- auto &InfoS = Err(File.getPDBInfoStream());
- BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
- auto Layout = File.getStreamLayout(StreamPDB);
- P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
- }
- void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
- printHeader(P, "MSF Blocks");
- AutoIndent Indent(P);
- for (uint32_t I = Min; I <= Max; ++I) {
- uint64_t Base = I;
- Base *= File.getBlockSize();
- auto ExpectedData = File.getBlockData(I, File.getBlockSize());
- if (!ExpectedData) {
- P.formatLine("Could not get block {0}. Reason = {1}", I,
- toString(ExpectedData.takeError()));
- continue;
- }
- std::string Label = formatv("Block {0}", I).str();
- P.formatBinary(Label, *ExpectedData, Base, 0);
- }
- }
- void BytesOutputStyle::dumpSectionContributions() {
- printHeader(P, "Section Contributions");
- AutoIndent Indent(P);
- auto &DbiS = Err(File.getPDBDbiStream());
- BinarySubstreamRef NS = DbiS.getSectionContributionData();
- auto Layout = File.getStreamLayout(StreamDBI);
- P.formatMsfStreamData("Section Contributions", File, Layout, NS);
- }
- void BytesOutputStyle::dumpSectionMap() {
- printHeader(P, "Section Map");
- AutoIndent Indent(P);
- auto &DbiS = Err(File.getPDBDbiStream());
- BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
- auto Layout = File.getStreamLayout(StreamDBI);
- P.formatMsfStreamData("Section Map", File, Layout, NS);
- }
- void BytesOutputStyle::dumpModuleInfos() {
- printHeader(P, "Module Infos");
- AutoIndent Indent(P);
- auto &DbiS = Err(File.getPDBDbiStream());
- BinarySubstreamRef NS = DbiS.getModiSubstreamData();
- auto Layout = File.getStreamLayout(StreamDBI);
- P.formatMsfStreamData("Module Infos", File, Layout, NS);
- }
- void BytesOutputStyle::dumpFileInfo() {
- printHeader(P, "File Info");
- AutoIndent Indent(P);
- auto &DbiS = Err(File.getPDBDbiStream());
- BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
- auto Layout = File.getStreamLayout(StreamDBI);
- P.formatMsfStreamData("File Info", File, Layout, NS);
- }
- void BytesOutputStyle::dumpTypeServerMap() {
- printHeader(P, "Type Server Map");
- AutoIndent Indent(P);
- auto &DbiS = Err(File.getPDBDbiStream());
- BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
- auto Layout = File.getStreamLayout(StreamDBI);
- P.formatMsfStreamData("Type Server Map", File, Layout, NS);
- }
- void BytesOutputStyle::dumpECData() {
- printHeader(P, "Edit and Continue Data");
- AutoIndent Indent(P);
- auto &DbiS = Err(File.getPDBDbiStream());
- BinarySubstreamRef NS = DbiS.getECSubstreamData();
- auto Layout = File.getStreamLayout(StreamDBI);
- P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
- }
- void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
- ArrayRef<uint32_t> Indices) {
- assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
- assert(!Indices.empty());
- bool IsTpi = (StreamIdx == StreamTPI);
- StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
- printHeader(P, Label);
- auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
- AutoIndent Indent(P);
- auto Substream = Stream.getTypeRecordsSubstream();
- auto &Types = Err(initializeTypes(StreamIdx));
- auto Layout = File.getStreamLayout(StreamIdx);
- for (const auto &Id : Indices) {
- TypeIndex TI(Id);
- if (TI.toArrayIndex() >= Types.capacity()) {
- P.formatLine("Error: TypeIndex {0} does not exist", TI);
- continue;
- }
- auto Type = Types.getType(TI);
- uint32_t Offset = Types.getOffsetOfType(TI);
- auto OneType = Substream.slice(Offset, Type.length());
- P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
- }
- }
- template <typename CallbackT>
- static void iterateOneModule(PDBFile &File, LinePrinter &P,
- const DbiModuleList &Modules, uint32_t I,
- uint32_t Digits, uint32_t IndentLevel,
- CallbackT Callback) {
- if (I >= Modules.getModuleCount()) {
- P.formatLine("Mod {0:4} | Invalid module index ",
- fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
- return;
- }
- auto Modi = Modules.getModuleDescriptor(I);
- P.formatLine("Mod {0:4} | `{1}`: ",
- fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
- Modi.getModuleName());
- uint16_t ModiStream = Modi.getModuleStreamIndex();
- AutoIndent Indent2(P, IndentLevel);
- if (ModiStream == kInvalidStreamIndex)
- return;
- auto ModStreamData = File.createIndexedStream(ModiStream);
- ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
- if (auto EC = ModStream.reload()) {
- P.formatLine("Could not parse debug information.");
- return;
- }
- auto Layout = File.getStreamLayout(ModiStream);
- Callback(I, ModStream, Layout);
- }
- template <typename CallbackT>
- static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
- CallbackT Callback) {
- AutoIndent Indent(P);
- if (!File.hasPDBDbiStream()) {
- P.formatLine("DBI Stream not present");
- return;
- }
- ExitOnError Err("Unexpected error processing modules");
- auto &Stream = Err(File.getPDBDbiStream());
- const DbiModuleList &Modules = Stream.modules();
- if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
- iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
- Callback);
- } else {
- uint32_t Count = Modules.getModuleCount();
- uint32_t Digits = NumDigits(Count);
- for (uint32_t I = 0; I < Count; ++I) {
- iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
- }
- }
- }
- void BytesOutputStyle::dumpModuleSyms() {
- printHeader(P, "Module Symbols");
- AutoIndent Indent(P);
- iterateModules(File, P, 2,
- [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
- const MSFStreamLayout &Layout) {
- auto Symbols = Stream.getSymbolsSubstream();
- P.formatMsfStreamData("Symbols", File, Layout, Symbols);
- });
- }
- void BytesOutputStyle::dumpModuleC11() {
- printHeader(P, "C11 Debug Chunks");
- AutoIndent Indent(P);
- iterateModules(File, P, 2,
- [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
- const MSFStreamLayout &Layout) {
- auto Chunks = Stream.getC11LinesSubstream();
- P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
- Chunks);
- });
- }
- void BytesOutputStyle::dumpModuleC13() {
- printHeader(P, "Debug Chunks");
- AutoIndent Indent(P);
- iterateModules(
- File, P, 2,
- [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
- const MSFStreamLayout &Layout) {
- auto Chunks = Stream.getC13LinesSubstream();
- if (opts::bytes::SplitChunks) {
- for (const auto &SS : Stream.subsections()) {
- BinarySubstreamRef ThisChunk;
- std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
- P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
- ThisChunk);
- }
- } else {
- P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
- }
- });
- }
- void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
- printHeader(P, "MSF Bytes");
- AutoIndent Indent(P);
- BinaryStreamReader Reader(File.getMsfBuffer());
- ArrayRef<uint8_t> Data;
- consumeError(Reader.skip(Min));
- uint32_t Size = Max - Min + 1;
- auto EC = Reader.readBytes(Data, Size);
- assert(!EC);
- consumeError(std::move(EC));
- P.formatBinary("Bytes", Data, Min);
- }
- Expected<codeview::LazyRandomTypeCollection &>
- BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
- auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
- if (TypeCollection)
- return *TypeCollection;
- auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
- : File.getPDBIpiStream();
- if (!Tpi)
- return Tpi.takeError();
- auto &Types = Tpi->typeArray();
- uint32_t Count = Tpi->getNumTypeRecords();
- auto Offsets = Tpi->getTypeIndexOffsets();
- TypeCollection =
- std::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
- return *TypeCollection;
- }
- void BytesOutputStyle::dumpFpm() {
- printHeader(P, "Free Page Map");
- msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();
- P.formatMsfStreamBlocks(File, FpmLayout);
- }
- void BytesOutputStyle::dumpStreamBytes() {
- if (StreamPurposes.empty())
- discoverStreamPurposes(File, StreamPurposes);
- printHeader(P, "Stream Data");
- ExitOnError Err("Unexpected error reading stream data");
- auto Specs = parseStreamSpecs(P);
- for (const auto &Spec : Specs) {
- AutoIndent Indent(P);
- if (Spec.SI >= StreamPurposes.size()) {
- P.formatLine("Stream {0}: Not present", Spec.SI);
- continue;
- }
- P.formatMsfStreamData("Data", File, Spec.SI,
- StreamPurposes[Spec.SI].getShortName(), Spec.Begin,
- Spec.Size);
- }
- }
|