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