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