Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/COFF/PDB.cpp @@ -785,15 +785,18 @@ cantFail(std::move(EC)); } -// Allocate memory for a .debug$S section and relocate it. +// Allocate memory for a .debug$S / .debug$F section and relocate it. static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, - SectionChunk *DebugChunk) { + SectionChunk *DebugChunk, + bool HasMagic) { uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); assert(DebugChunk->OutputSectionOff == 0 && "debug sections should not be in output sections"); DebugChunk->writeTo(Buffer); - return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()), - ".debug$S"); + ArrayRef Result = makeArrayRef(Buffer, DebugChunk->getSize()); + if (HasMagic) + Result = consumeDebugMagic(Result, DebugChunk->getSectionName()); + return Result; } static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) { @@ -886,62 +889,82 @@ DebugStringTableSubsectionRef CVStrTab; DebugChecksumsSubsectionRef Checksums; std::vector StringTableReferences; - std::vector FpoFrames; + std::vector NewFpoFrames; for (SectionChunk *DebugChunk : File->getDebugChunks()) { - if (!DebugChunk->Live || DebugChunk->getSectionName() != ".debug$S") + if (!DebugChunk->Live) continue; - ArrayRef RelocatedDebugContents = - relocateDebugChunk(Alloc, DebugChunk); - if (RelocatedDebugContents.empty()) + ArrayRef RelocatedDebugContents; + + if (DebugChunk->getSectionName() == ".debug$S") + RelocatedDebugContents = relocateDebugChunk(Alloc, DebugChunk, true); + else if (DebugChunk->getSectionName() == ".debug$F") + RelocatedDebugContents = relocateDebugChunk(Alloc, DebugChunk, false); + else continue; - DebugSubsectionArray Subsections; - BinaryStreamReader Reader(RelocatedDebugContents, support::little); - ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); + if (RelocatedDebugContents.empty()) + continue; - for (const DebugSubsectionRecord &SS : Subsections) { - switch (SS.kind()) { - case DebugSubsectionKind::StringTable: { - assert(!CVStrTab.valid() && - "Encountered multiple string table subsections!"); - ExitOnErr(CVStrTab.initialize(SS.getRecordData())); - break; - } - case DebugSubsectionKind::FileChecksums: - assert(!Checksums.valid() && - "Encountered multiple checksum subsections!"); - ExitOnErr(Checksums.initialize(SS.getRecordData())); - break; - case DebugSubsectionKind::Lines: - // We can add the relocated line table directly to the PDB without - // modification because the file checksum offsets will stay the same. - File->ModuleDBI->addDebugSubsection(SS); - break; - case DebugSubsectionKind::FrameData: { - // We need to re-write string table indices here, so save off all - // frame data subsections until we've processed the entire list of - // subsections so that we can be sure we have the string table. - DebugFrameDataSubsectionRef FDS; - ExitOnErr(FDS.initialize(SS.getRecordData())); - FpoFrames.push_back(std::move(FDS)); - break; - } - case DebugSubsectionKind::Symbols: - if (Config->DebugGHashes) { - mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - GlobalIDTable, StringTableReferences, - SS.getRecordData()); - } else { - mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - IDTable, StringTableReferences, - SS.getRecordData()); + if (DebugChunk->getSectionName() == ".debug$S") { + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); + + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: { + assert(!CVStrTab.valid() && + "Encountered multiple string table subsections!"); + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + } + case DebugSubsectionKind::FileChecksums: + assert(!Checksums.valid() && + "Encountered multiple checksum subsections!"); + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: + // We can add the relocated line table directly to the PDB without + // modification because the file checksum offsets will stay the same. + File->ModuleDBI->addDebugSubsection(SS); + break; + case DebugSubsectionKind::FrameData: { + // We need to re-write string table indices here, so save off all + // frame data subsections until we've processed the entire list of + // subsections so that we can be sure we have the string table. + DebugFrameDataSubsectionRef FDS; + ExitOnErr(FDS.initialize(SS.getRecordData())); + NewFpoFrames.push_back(std::move(FDS)); + break; + } + case DebugSubsectionKind::Symbols: + if (Config->DebugGHashes) { + mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, + GlobalIDTable, StringTableReferences, + SS.getRecordData()); + } else { + mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, + IDTable, StringTableReferences, + SS.getRecordData()); + } + break; + default: + // FIXME: Process the rest of the subsections. + break; } - break; - default: - // FIXME: Process the rest of the subsections. - break; } + } else { + // Handle .debug$F. + FixedStreamArray FpoRecords; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData); + ExitOnErr(Reader.readArray(FpoRecords, Count)); + + // These are already relocated and don't refer to the string table, so we + // can just copy it. + for (const object::FpoData &FD : FpoRecords) + DbiBuilder.addOldFpoData(FD); } } @@ -961,13 +984,13 @@ // Rewrite string table indices in the Fpo Data and symbol records to refer to // the global PDB string table instead of the object file string table. - for (DebugFrameDataSubsectionRef &FDS : FpoFrames) { + for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) { const uint32_t *Reloc = FDS.getRelocPtr(); for (codeview::FrameData FD : FDS) { FD.RvaStart += *Reloc; FD.FrameFunc = translateStringTableIndex(FD.FrameFunc, CVStrTab, PDBStrTab); - DbiBuilder.addFrameData(FD); + DbiBuilder.addNewFpoData(FD); } } Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -33,6 +33,7 @@ } namespace object { struct coff_section; +struct FpoData; } namespace pdb { class DbiStream; @@ -69,7 +70,8 @@ void setGlobalsStreamIndex(uint32_t Index); void setPublicsStreamIndex(uint32_t Index); void setSymbolRecordStreamIndex(uint32_t Index); - void addFrameData(const codeview::FrameData &FD); + void addNewFpoData(const codeview::FrameData &FD); + void addOldFpoData(const object::FpoData &Fpo); Expected addModuleInfo(StringRef ModuleName); Error addModuleSourceFile(DbiModuleDescriptorBuilder &Module, StringRef File); @@ -123,7 +125,8 @@ std::vector> ModiList; - Optional FrameData; + Optional NewFpoData; + std::vector OldFpoData; StringMap SourceFileNames; Index: llvm/include/llvm/Object/COFF.h =================================================================== --- llvm/include/llvm/Object/COFF.h +++ llvm/include/llvm/Object/COFF.h @@ -594,6 +594,8 @@ FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes }; +enum class frame_type : uint16_t { Fpo = 0, Trap = 1, Tss = 2, NonFpo = 3 }; + struct coff_load_config_code_integrity { support::ulittle16_t Flags; support::ulittle16_t Catalog; @@ -1228,7 +1230,7 @@ bool useBP() const { return (Attributes >> 10) & 1; } // cbFrame: frame pointer - int getFP() const { return Attributes >> 14; } + frame_type getFP() const { return static_cast(Attributes >> 14); } }; } // end namespace object Index: llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -75,11 +75,15 @@ PublicsStreamIndex = Index; } -void DbiStreamBuilder::addFrameData(const codeview::FrameData &FD) { - if (!FrameData.hasValue()) - FrameData.emplace(false); +void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) { + if (!NewFpoData.hasValue()) + NewFpoData.emplace(false); - FrameData->addFrameData(FD); + NewFpoData->addFrameData(FD); +} + +void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { + OldFpoData.push_back(FD); } Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, @@ -286,13 +290,23 @@ } Error DbiStreamBuilder::finalizeMsfLayout() { - if (FrameData.hasValue()) { + if (NewFpoData.hasValue()) { DbgStreams[(int)DbgHeaderType::NewFPO].emplace(); DbgStreams[(int)DbgHeaderType::NewFPO]->Size = - FrameData->calculateSerializedSize(); + NewFpoData->calculateSerializedSize(); DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = [this](BinaryStreamWriter &Writer) { - return FrameData->commit(Writer); + return NewFpoData->commit(Writer); + }; + } + + if (!OldFpoData.empty()) { + DbgStreams[(int)DbgHeaderType::FPO].emplace(); + DbgStreams[(int)DbgHeaderType::FPO]->Size = + sizeof(object::FpoData) * OldFpoData.size(); + DbgStreams[(int)DbgHeaderType::FPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return Writer.writeArray(makeArrayRef(OldFpoData)); }; } Index: llvm/tools/llvm-pdbutil/DumpOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbutil/DumpOutputStyle.h +++ llvm/tools/llvm-pdbutil/DumpOutputStyle.h @@ -86,6 +86,8 @@ Error dumpXmi(); Error dumpXme(); Error dumpFpo(); + Error dumpOldFpo(PDBFile &File); + Error dumpNewFpo(PDBFile &File); Error dumpTpiStream(uint32_t StreamIdx); Error dumpTypesFromObjectFile(); Error dumpModules(); Index: llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -991,22 +991,56 @@ return Error::success(); } -Error DumpOutputStyle::dumpFpo() { - printHeader(P, "New FPO Data"); +std::string formatFrameType(object::frame_type FT) { + switch (FT) { + case object::frame_type::Fpo: + return "FPO"; + case object::frame_type::NonFpo: + return "Non-FPO"; + case object::frame_type::Trap: + return "Trap"; + case object::frame_type::Tss: + return "TSS"; + } + return ""; +} - if (!File.isPdb()) { - printStreamNotValidForObj(); +Error DumpOutputStyle::dumpOldFpo(PDBFile &File) { + printHeader(P, "Old FPO Data"); + + ExitOnError Err("Error dumping old fpo data:"); + auto &Dbi = Err(File.getPDBDbiStream()); + + uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::FPO); + if (Index == kInvalidStreamIndex) { + printStreamNotPresent("FPO"); return Error::success(); } - PDBFile &File = getPdb(); - if (!File.hasPDBDbiStream()) { - printStreamNotPresent("DBI"); - return Error::success(); + std::unique_ptr OldFpo = File.createIndexedStream(Index); + BinaryStreamReader Reader(*OldFpo); + FixedStreamArray Records; + Err(Reader.readArray(Records, + Reader.bytesRemaining() / sizeof(object::FpoData))); + + P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use " + "BP | Has SEH | Frame Type"); + + for (const object::FpoData &FD : Records) { + P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | " + "{7,7} | {8,9}", + uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals), + uint32_t(FD.NumParams), FD.getPrologSize(), + FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(), + formatFrameType(FD.getFP())); } + return Error::success(); +} - ExitOnError Err("Error dumping fpo data:"); +Error DumpOutputStyle::dumpNewFpo(PDBFile &File) { + printHeader(P, "New FPO Data"); + ExitOnError Err("Error dumping new fpo data:"); auto &Dbi = Err(File.getPDBDbiStream()); uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::NewFPO); @@ -1043,6 +1077,25 @@ return Error::success(); } +Error DumpOutputStyle::dumpFpo() { + if (!File.isPdb()) { + printStreamNotValidForObj(); + return Error::success(); + } + + PDBFile &File = getPdb(); + if (!File.hasPDBDbiStream()) { + printStreamNotPresent("DBI"); + return Error::success(); + } + + if (auto EC = dumpOldFpo(File)) + return EC; + if (auto EC = dumpNewFpo(File)) + return EC; + return Error::success(); +} + Error DumpOutputStyle::dumpStringTableFromPdb() { AutoIndent Indent(P); auto IS = getPdb().getStringTable();