10b57cec5SDimitry Andric //===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "StreamUtil.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
120b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleList.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
15*81ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric using namespace llvm::pdb;
220b57cec5SDimitry Andric
getLongName() const230b57cec5SDimitry Andric std::string StreamInfo::getLongName() const {
240b57cec5SDimitry Andric if (Purpose == StreamPurpose::NamedStream)
250b57cec5SDimitry Andric return formatv("Named Stream \"{0}\"", Name).str();
260b57cec5SDimitry Andric if (Purpose == StreamPurpose::ModuleStream)
270b57cec5SDimitry Andric return formatv("Module \"{0}\"", Name).str();
280b57cec5SDimitry Andric return Name;
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric
createStream(StreamPurpose Purpose,StringRef Name,uint32_t StreamIndex)310b57cec5SDimitry Andric StreamInfo StreamInfo::createStream(StreamPurpose Purpose, StringRef Name,
320b57cec5SDimitry Andric uint32_t StreamIndex) {
330b57cec5SDimitry Andric StreamInfo Result;
345ffd83dbSDimitry Andric Result.Name = std::string(Name);
350b57cec5SDimitry Andric Result.StreamIndex = StreamIndex;
360b57cec5SDimitry Andric Result.Purpose = Purpose;
370b57cec5SDimitry Andric return Result;
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric
createModuleStream(StringRef Module,uint32_t StreamIndex,uint32_t Modi)400b57cec5SDimitry Andric StreamInfo StreamInfo::createModuleStream(StringRef Module,
410b57cec5SDimitry Andric uint32_t StreamIndex, uint32_t Modi) {
420b57cec5SDimitry Andric StreamInfo Result;
435ffd83dbSDimitry Andric Result.Name = std::string(Module);
440b57cec5SDimitry Andric Result.StreamIndex = StreamIndex;
450b57cec5SDimitry Andric Result.ModuleIndex = Modi;
460b57cec5SDimitry Andric Result.Purpose = StreamPurpose::ModuleStream;
470b57cec5SDimitry Andric return Result;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
stream(StreamPurpose Purpose,StringRef Label,uint32_t Idx)500b57cec5SDimitry Andric static inline StreamInfo stream(StreamPurpose Purpose, StringRef Label,
510b57cec5SDimitry Andric uint32_t Idx) {
520b57cec5SDimitry Andric return StreamInfo::createStream(Purpose, Label, Idx);
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric
moduleStream(StringRef Label,uint32_t StreamIdx,uint32_t Modi)550b57cec5SDimitry Andric static inline StreamInfo moduleStream(StringRef Label, uint32_t StreamIdx,
560b57cec5SDimitry Andric uint32_t Modi) {
570b57cec5SDimitry Andric return StreamInfo::createModuleStream(Label, StreamIdx, Modi);
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric struct IndexedModuleDescriptor {
610b57cec5SDimitry Andric uint32_t Modi;
620b57cec5SDimitry Andric DbiModuleDescriptor Descriptor;
630b57cec5SDimitry Andric };
640b57cec5SDimitry Andric
discoverStreamPurposes(PDBFile & File,SmallVectorImpl<StreamInfo> & Streams)650b57cec5SDimitry Andric void llvm::pdb::discoverStreamPurposes(PDBFile &File,
660b57cec5SDimitry Andric SmallVectorImpl<StreamInfo> &Streams) {
670b57cec5SDimitry Andric // It's OK if we fail to load some of these streams, we still attempt to print
680b57cec5SDimitry Andric // what we can.
690b57cec5SDimitry Andric auto Dbi = File.getPDBDbiStream();
700b57cec5SDimitry Andric auto Tpi = File.getPDBTpiStream();
710b57cec5SDimitry Andric auto Ipi = File.getPDBIpiStream();
720b57cec5SDimitry Andric auto Info = File.getPDBInfoStream();
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric uint32_t StreamCount = File.getNumStreams();
750b57cec5SDimitry Andric DenseMap<uint16_t, IndexedModuleDescriptor> ModStreams;
760b57cec5SDimitry Andric DenseMap<uint16_t, std::string> NamedStreams;
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric if (Dbi) {
790b57cec5SDimitry Andric const DbiModuleList &Modules = Dbi->modules();
800b57cec5SDimitry Andric for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
810b57cec5SDimitry Andric IndexedModuleDescriptor IMD;
820b57cec5SDimitry Andric IMD.Modi = I;
830b57cec5SDimitry Andric IMD.Descriptor = Modules.getModuleDescriptor(I);
840b57cec5SDimitry Andric uint16_t SN = IMD.Descriptor.getModuleStreamIndex();
850b57cec5SDimitry Andric if (SN != kInvalidStreamIndex)
860b57cec5SDimitry Andric ModStreams[SN] = IMD;
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric if (Info) {
900b57cec5SDimitry Andric for (auto &NSE : Info->named_streams()) {
910b57cec5SDimitry Andric if (NSE.second != kInvalidStreamIndex)
925ffd83dbSDimitry Andric NamedStreams[NSE.second] = std::string(NSE.first());
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric Streams.resize(StreamCount);
97*81ad6265SDimitry Andric for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
980b57cec5SDimitry Andric if (StreamIdx == OldMSFDirectory)
990b57cec5SDimitry Andric Streams[StreamIdx] =
1000b57cec5SDimitry Andric stream(StreamPurpose::Other, "Old MSF Directory", StreamIdx);
1010b57cec5SDimitry Andric else if (StreamIdx == StreamPDB)
1020b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::PDB, "PDB Stream", StreamIdx);
1030b57cec5SDimitry Andric else if (StreamIdx == StreamDBI)
1040b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::DBI, "DBI Stream", StreamIdx);
1050b57cec5SDimitry Andric else if (StreamIdx == StreamTPI)
1060b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::TPI, "TPI Stream", StreamIdx);
1070b57cec5SDimitry Andric else if (StreamIdx == StreamIPI)
1080b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::IPI, "IPI Stream", StreamIdx);
1090b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
1100b57cec5SDimitry Andric Streams[StreamIdx] =
1110b57cec5SDimitry Andric stream(StreamPurpose::GlobalHash, "Global Symbol Hash", StreamIdx);
1120b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
1130b57cec5SDimitry Andric Streams[StreamIdx] =
1140b57cec5SDimitry Andric stream(StreamPurpose::PublicHash, "Public Symbol Hash", StreamIdx);
1150b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
1160b57cec5SDimitry Andric Streams[StreamIdx] =
1170b57cec5SDimitry Andric stream(StreamPurpose::Symbols, "Symbol Records", StreamIdx);
1180b57cec5SDimitry Andric else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
1190b57cec5SDimitry Andric Streams[StreamIdx] =
1200b57cec5SDimitry Andric stream(StreamPurpose::TpiHash, "TPI Hash", StreamIdx);
1210b57cec5SDimitry Andric else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
1220b57cec5SDimitry Andric Streams[StreamIdx] =
1230b57cec5SDimitry Andric stream(StreamPurpose::Other, "TPI Aux Hash", StreamIdx);
1240b57cec5SDimitry Andric else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
1250b57cec5SDimitry Andric Streams[StreamIdx] =
1260b57cec5SDimitry Andric stream(StreamPurpose::IpiHash, "IPI Hash", StreamIdx);
1270b57cec5SDimitry Andric else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
1280b57cec5SDimitry Andric Streams[StreamIdx] =
1290b57cec5SDimitry Andric stream(StreamPurpose::Other, "IPI Aux Hash", StreamIdx);
1300b57cec5SDimitry Andric else if (Dbi &&
1310b57cec5SDimitry Andric StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
1320b57cec5SDimitry Andric Streams[StreamIdx] =
1330b57cec5SDimitry Andric stream(StreamPurpose::Other, "Exception Data", StreamIdx);
1340b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
1350b57cec5SDimitry Andric Streams[StreamIdx] =
1360b57cec5SDimitry Andric stream(StreamPurpose::Other, "Fixup Data", StreamIdx);
1370b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
1380b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::Other, "FPO Data", StreamIdx);
1390b57cec5SDimitry Andric else if (Dbi &&
1400b57cec5SDimitry Andric StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
1410b57cec5SDimitry Andric Streams[StreamIdx] =
1420b57cec5SDimitry Andric stream(StreamPurpose::Other, "New FPO Data", StreamIdx);
1430b57cec5SDimitry Andric else if (Dbi &&
1440b57cec5SDimitry Andric StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
1450b57cec5SDimitry Andric Streams[StreamIdx] =
1460b57cec5SDimitry Andric stream(StreamPurpose::Other, "Omap From Source Data", StreamIdx);
1470b57cec5SDimitry Andric else if (Dbi &&
1480b57cec5SDimitry Andric StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
1490b57cec5SDimitry Andric Streams[StreamIdx] =
1500b57cec5SDimitry Andric stream(StreamPurpose::Other, "Omap To Source Data", StreamIdx);
1510b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
1520b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::Other, "Pdata", StreamIdx);
1530b57cec5SDimitry Andric else if (Dbi &&
1540b57cec5SDimitry Andric StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
1550b57cec5SDimitry Andric Streams[StreamIdx] =
1560b57cec5SDimitry Andric stream(StreamPurpose::Other, "Section Header Data", StreamIdx);
1570b57cec5SDimitry Andric else if (Dbi &&
1580b57cec5SDimitry Andric StreamIdx ==
1590b57cec5SDimitry Andric Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
1600b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::Other,
1610b57cec5SDimitry Andric "Section Header Original Data", StreamIdx);
1620b57cec5SDimitry Andric else if (Dbi &&
1630b57cec5SDimitry Andric StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
1640b57cec5SDimitry Andric Streams[StreamIdx] =
1650b57cec5SDimitry Andric stream(StreamPurpose::Other, "Token Rid Data", StreamIdx);
1660b57cec5SDimitry Andric else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
1670b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::Other, "Xdata", StreamIdx);
1680b57cec5SDimitry Andric else {
1690b57cec5SDimitry Andric auto ModIter = ModStreams.find(StreamIdx);
1700b57cec5SDimitry Andric auto NSIter = NamedStreams.find(StreamIdx);
1710b57cec5SDimitry Andric if (ModIter != ModStreams.end()) {
1720b57cec5SDimitry Andric Streams[StreamIdx] =
1730b57cec5SDimitry Andric moduleStream(ModIter->second.Descriptor.getModuleName(), StreamIdx,
1740b57cec5SDimitry Andric ModIter->second.Modi);
1750b57cec5SDimitry Andric } else if (NSIter != NamedStreams.end()) {
1760b57cec5SDimitry Andric Streams[StreamIdx] =
1770b57cec5SDimitry Andric stream(StreamPurpose::NamedStream, NSIter->second, StreamIdx);
1780b57cec5SDimitry Andric } else {
1790b57cec5SDimitry Andric Streams[StreamIdx] = stream(StreamPurpose::Other, "???", StreamIdx);
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric // Consume errors from missing streams.
1850b57cec5SDimitry Andric if (!Dbi)
1860b57cec5SDimitry Andric consumeError(Dbi.takeError());
1870b57cec5SDimitry Andric if (!Tpi)
1880b57cec5SDimitry Andric consumeError(Tpi.takeError());
1890b57cec5SDimitry Andric if (!Ipi)
1900b57cec5SDimitry Andric consumeError(Ipi.takeError());
1910b57cec5SDimitry Andric if (!Info)
1920b57cec5SDimitry Andric consumeError(Info.takeError());
1930b57cec5SDimitry Andric }
194