diff options
Diffstat (limited to 'tools/llvm-pdbutil/BytesOutputStyle.cpp')
| -rw-r--r-- | tools/llvm-pdbutil/BytesOutputStyle.cpp | 501 | 
1 files changed, 501 insertions, 0 deletions
diff --git a/tools/llvm-pdbutil/BytesOutputStyle.cpp b/tools/llvm-pdbutil/BytesOutputStyle.cpp new file mode 100644 index 000000000000..9e5a28c2b98b --- /dev/null +++ b/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -0,0 +1,501 @@ +//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/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::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 = MappedBlockStream::createIndexedStream( +      File.getMsfLayout(), File.getMsfBuffer(), ModiStream, +      File.getAllocator()); +  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); +                 }); +} + +static std::string formatChunkKind(DebugSubsectionKind Kind) { +  switch (Kind) { +    RETURN_CASE(DebugSubsectionKind, None, "none"); +    RETURN_CASE(DebugSubsectionKind, Symbols, "symbols"); +    RETURN_CASE(DebugSubsectionKind, Lines, "lines"); +    RETURN_CASE(DebugSubsectionKind, StringTable, "strings"); +    RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums"); +    RETURN_CASE(DebugSubsectionKind, FrameData, "frames"); +    RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines"); +    RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi"); +    RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme"); +    RETURN_CASE(DebugSubsectionKind, ILLines, "il lines"); +    RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map"); +    RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map"); +    RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput, +                "merged assembly input"); +    RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva"); +  } +  return formatUnknownEnum(Kind); +} + +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 = +      llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets); + +  return *TypeCollection; +} + +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], +                          Spec.Begin, Spec.Size); +  } +}  | 
