492 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "BytesOutputStyle.h"10 11#include "StreamUtil.h"12#include "llvm-pdbutil.h"13 14#include "llvm/DebugInfo/CodeView/Formatters.h"15#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"16#include "llvm/DebugInfo/MSF/MSFCommon.h"17#include "llvm/DebugInfo/MSF/MappedBlockStream.h"18#include "llvm/DebugInfo/PDB/Native/DbiStream.h"19#include "llvm/DebugInfo/PDB/Native/FormatUtil.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 29using namespace llvm;30using namespace llvm::codeview;31using namespace llvm::msf;32using namespace llvm::pdb;33 34namespace {35struct StreamSpec {36 uint32_t SI = 0;37 uint32_t Begin = 0;38 uint32_t Size = 0;39};40} // namespace41 42static 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 64static 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 79static 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 85BytesOutputStyle::BytesOutputStyle(PDBFile &File)86 : File(File), P(2, false, outs(), opts::Filters) {}87 88Error BytesOutputStyle::dump() {89 90 if (opts::bytes::DumpBlockRange) {91 auto &R = *opts::bytes::DumpBlockRange;92 uint32_t Max = R.Max.value_or(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) {108 auto &R = *opts::bytes::DumpByteRange;109 uint32_t Max = R.Max.value_or(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 196void 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 207void 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 226void 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 237void 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 248void 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 259void 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 270void 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 281void 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 292void 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 322template <typename CallbackT>323static 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 353template <typename CallbackT>354static 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 380void 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 393void 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 407void 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 430void 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 445Expected<codeview::LazyRandomTypeCollection &>446BytesOutputStyle::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 465void BytesOutputStyle::dumpFpm() {466 printHeader(P, "Free Page Map");467 468 msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();469 P.formatMsfStreamBlocks(File, FpmLayout);470}471 472void 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