Index: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h @@ -25,6 +25,9 @@ namespace msf { class MSFBuilder; } +namespace object { +struct coff_section; +} namespace pdb { class DbiStream; struct DbiStreamHeader; @@ -44,6 +47,7 @@ void setPdbDllRbld(uint16_t R); void setFlags(uint16_t F); void setMachineType(PDB_Machine M); + void setSectionMap(ArrayRef SecMap); // Add given bytes as a new stream. Error addDbgStream(pdb::DbgHeaderType Type, ArrayRef Data); @@ -60,6 +64,10 @@ Error commit(const msf::MSFLayout &Layout, const msf::WritableStream &Buffer); + // A helper function to create a Section Map from a COFF section header. + static std::vector + createSectionMap(ArrayRef SecHdrs); + private: struct DebugStream { ArrayRef Data; @@ -68,6 +76,7 @@ Error finalize(); uint32_t calculateModiSubstreamSize() const; + uint32_t calculateSectionMapStreamSize() const; uint32_t calculateFileInfoSubstreamSize() const; uint32_t calculateNamesBufferSize() const; uint32_t calculateDbgStreamsSize() const; @@ -102,6 +111,7 @@ msf::WritableStreamRef NamesBuffer; msf::MutableByteStream ModInfoBuffer; msf::MutableByteStream FileInfoBuffer; + ArrayRef SectionMap; llvm::SmallVector DbgStreams; }; } Index: llvm/trunk/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp @@ -15,6 +15,8 @@ #include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/COFF.h" using namespace llvm; using namespace llvm::codeview; @@ -44,6 +46,10 @@ void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } +void DbiStreamBuilder::setSectionMap(ArrayRef SecMap) { + SectionMap = SecMap; +} + Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, ArrayRef Data) { if (DbgStreams[(int)Type].StreamNumber) @@ -61,7 +67,8 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const { // For now we only support serializing the header. return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() + - calculateModiSubstreamSize() + calculateDbgStreamsSize(); + calculateModiSubstreamSize() + calculateSectionMapStreamSize() + + calculateDbgStreamsSize(); } Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) { @@ -99,6 +106,12 @@ return Size; } +uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const { + if (SectionMap.empty()) + return 0; + return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size(); +} + uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const { uint32_t Size = 0; Size += sizeof(ulittle16_t); // NumModules @@ -237,7 +250,7 @@ H->ModiSubstreamSize = ModInfoBuffer.getLength(); H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); H->SecContrSubstreamSize = 0; - H->SectionMapSize = 0; + H->SectionMapSize = calculateSectionMapStreamSize(); H->TypeServerSize = 0; H->SymRecordStreamIndex = kInvalidStreamIndex; H->PublicSymbolStreamIndex = kInvalidStreamIndex; @@ -255,6 +268,65 @@ return Error::success(); } +static uint16_t toSecMapFlags(uint32_t Flags) { + uint16_t Ret = 0; + if (Flags & COFF::IMAGE_SCN_MEM_READ) + Ret |= static_cast(OMFSegDescFlags::Read); + if (Flags & COFF::IMAGE_SCN_MEM_WRITE) + Ret |= static_cast(OMFSegDescFlags::Write); + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) + Ret |= static_cast(OMFSegDescFlags::Execute); + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) + Ret |= static_cast(OMFSegDescFlags::Execute); + if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT)) + Ret |= static_cast(OMFSegDescFlags::AddressIs32Bit); + + // This seems always 1. + Ret |= static_cast(OMFSegDescFlags::IsSelector); + + return Ret; +} + +// A utility function to create a Section Map for a given list of COFF sections. +// +// A Section Map seem to be a copy of a COFF section list in other format. +// I don't know why a PDB file contains both a COFF section header and +// a Section Map, but it seems it must be present in a PDB. +std::vector DbiStreamBuilder::createSectionMap( + ArrayRef SecHdrs) { + std::vector Ret; + int Idx = 0; + + auto Add = [&]() -> SecMapEntry & { + Ret.emplace_back(); + auto &Entry = Ret.back(); + memset(&Entry, 0, sizeof(Entry)); + + Entry.Frame = Idx + 1; + + // We don't know the meaning of these fields yet. + Entry.SecName = UINT16_MAX; + Entry.ClassName = UINT16_MAX; + + return Entry; + }; + + for (auto &Hdr : SecHdrs) { + auto &Entry = Add(); + Entry.Flags = toSecMapFlags(Hdr.Characteristics); + Entry.SecByteLength = Hdr.VirtualSize; + ++Idx; + } + + // The last entry is for absolute symbols. + auto &Entry = Add(); + Entry.Flags = static_cast(OMFSegDescFlags::AddressIs32Bit) | + static_cast(OMFSegDescFlags::IsAbsoluteAddress); + Entry.SecByteLength = UINT32_MAX; + + return Ret; +} + Expected> DbiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) { if (!VerHeader.hasValue()) @@ -290,8 +362,19 @@ if (auto EC = Writer.writeStreamRef(ModInfoBuffer)) return EC; + + if (!SectionMap.empty()) { + ulittle16_t Size = static_cast(SectionMap.size()); + SecMapHeader SMHeader = {Size, Size}; + if (auto EC = Writer.writeObject(SMHeader)) + return EC; + if (auto EC = Writer.writeArray(SectionMap)) + return EC; + } + if (auto EC = Writer.writeStreamRef(FileInfoBuffer)) return EC; + for (auto &Stream : DbgStreams) if (auto EC = Writer.writeInteger(Stream.StreamNumber)) return EC;