Revert "[PDB] Defer relocating .debug$S until commit time and parallelize it"

This reverts commit 1a9bd5b813.

I suspect that this patch may have caused https://crbug.com/1171438.
This commit is contained in:
Reid Kleckner
2021-01-28 13:17:27 -08:00
parent 1daaa6432e
commit bacf9cf2c5
6 changed files with 300 additions and 637 deletions

View File

@@ -367,89 +367,47 @@ void SectionChunk::writeTo(uint8_t *buf) const {
continue;
}
applyRelocation(buf + rel.VirtualAddress, rel);
}
}
uint8_t *off = buf + rel.VirtualAddress;
void SectionChunk::applyRelocation(uint8_t *off,
const coff_relocation &rel) const {
auto *sym = dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
auto *sym =
dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
// Get the output section of the symbol for this relocation. The output
// section is needed to compute SECREL and SECTION relocations used in debug
// info.
Chunk *c = sym ? sym->getChunk() : nullptr;
OutputSection *os = c ? c->getOutputSection() : nullptr;
// Get the output section of the symbol for this relocation. The output
// section is needed to compute SECREL and SECTION relocations used in debug
// info.
Chunk *c = sym ? sym->getChunk() : nullptr;
OutputSection *os = c ? c->getOutputSection() : nullptr;
// Skip the relocation if it refers to a discarded section, and diagnose it
// as an error if appropriate. If a symbol was discarded early, it may be
// null. If it was discarded late, the output section will be null, unless
// it was an absolute or synthetic symbol.
if (!sym ||
(!os && !isa<DefinedAbsolute>(sym) && !isa<DefinedSynthetic>(sym))) {
maybeReportRelocationToDiscarded(this, sym, rel);
return;
}
uint64_t s = sym->getRVA();
// Compute the RVA of the relocation for relative relocations.
uint64_t p = rva + rel.VirtualAddress;
switch (config->machine) {
case AMD64:
applyRelX64(off, rel.Type, os, s, p);
break;
case I386:
applyRelX86(off, rel.Type, os, s, p);
break;
case ARMNT:
applyRelARM(off, rel.Type, os, s, p);
break;
case ARM64:
applyRelARM64(off, rel.Type, os, s, p);
break;
default:
llvm_unreachable("unknown machine type");
}
}
// Defend against unsorted relocations. This may be overly conservative.
void SectionChunk::sortRelocations() {
auto cmpByVa = [](const coff_relocation &l, const coff_relocation &r) {
return l.VirtualAddress < r.VirtualAddress;
};
if (llvm::is_sorted(getRelocs(), cmpByVa))
return;
warn("some relocations in " + file->getName() + " are not sorted");
MutableArrayRef<coff_relocation> newRelocs(
bAlloc.Allocate<coff_relocation>(relocsSize), relocsSize);
memcpy(newRelocs.data(), relocsData, relocsSize * sizeof(coff_relocation));
llvm::sort(newRelocs, cmpByVa);
setRelocs(newRelocs);
}
// Similar to writeTo, but suitable for relocating a subsection of the overall
// section.
void SectionChunk::writeAndRelocateSubsection(ArrayRef<uint8_t> sec,
ArrayRef<uint8_t> subsec,
uint32_t &nextRelocIndex,
uint8_t *buf) const {
assert(!subsec.empty() && !sec.empty());
assert(sec.begin() <= subsec.begin() && subsec.end() <= sec.end() &&
"subsection is not part of this section");
size_t vaBegin = std::distance(sec.begin(), subsec.begin());
size_t vaEnd = std::distance(sec.begin(), subsec.end());
memcpy(buf, subsec.data(), subsec.size());
for (; nextRelocIndex < relocsSize; ++nextRelocIndex) {
const coff_relocation &rel = relocsData[nextRelocIndex];
// Only apply relocations that apply to this subsection. These checks
// assume that all subsections completely contain their relocations.
// Relocations must not straddle the beginning or end of a subsection.
if (rel.VirtualAddress < vaBegin)
// Skip the relocation if it refers to a discarded section, and diagnose it
// as an error if appropriate. If a symbol was discarded early, it may be
// null. If it was discarded late, the output section will be null, unless
// it was an absolute or synthetic symbol.
if (!sym ||
(!os && !isa<DefinedAbsolute>(sym) && !isa<DefinedSynthetic>(sym))) {
maybeReportRelocationToDiscarded(this, sym, rel);
continue;
if (rel.VirtualAddress + 1 >= vaEnd)
}
uint64_t s = sym->getRVA();
// Compute the RVA of the relocation for relative relocations.
uint64_t p = rva + rel.VirtualAddress;
switch (config->machine) {
case AMD64:
applyRelX64(off, rel.Type, os, s, p);
break;
applyRelocation(&buf[rel.VirtualAddress - vaBegin], rel);
case I386:
applyRelX86(off, rel.Type, os, s, p);
break;
case ARMNT:
applyRelARM(off, rel.Type, os, s, p);
break;
case ARM64:
applyRelARM64(off, rel.Type, os, s, p);
break;
default:
llvm_unreachable("unknown machine type");
}
}
}

View File

@@ -204,15 +204,6 @@ public:
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *buf) const;
// Defend against unsorted relocations. This may be overly conservative.
void sortRelocations();
// Write and relocate a portion of the section. This is intended to be called
// in a loop. Relocations must be sorted first.
void writeAndRelocateSubsection(ArrayRef<uint8_t> sec,
ArrayRef<uint8_t> subsec,
uint32_t &nextRelocIndex, uint8_t *buf) const;
uint32_t getOutputCharacteristics() const {
return header->Characteristics & (permMask | typeMask);
}
@@ -221,7 +212,6 @@ public:
}
void getBaserels(std::vector<Baserel> *res);
bool isCOMDAT() const;
void applyRelocation(uint8_t *off, const coff_relocation &rel) const;
void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
uint64_t p) const;
void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,

View File

@@ -62,7 +62,6 @@ using namespace lld;
using namespace lld::coff;
using llvm::object::coff_section;
using llvm::pdb::StringTableFixup;
static ExitOnError exitOnErr;
@@ -109,8 +108,6 @@ public:
/// Link info for each import file in the symbol table into the PDB.
void addImportFilesToPDB(ArrayRef<OutputSection *> outputSections);
void createModuleDBI(ObjFile *file);
/// Link CodeView from a single object file into the target (output) PDB.
/// When a precompiled headers object is linked, its TPI map might be provided
/// externally.
@@ -118,30 +115,9 @@ public:
void addDebugSymbols(TpiSource *source);
// Analyze the symbol records to separate module symbols from global symbols,
// find string references, and calculate how large the symbol stream will be
// in the PDB.
void analyzeSymbolSubsection(SectionChunk *debugChunk,
uint32_t &moduleSymOffset,
uint32_t &nextRelocIndex,
std::vector<StringTableFixup> &stringTableFixups,
BinaryStreamRef symData);
// Write all module symbols from all all live debug symbol subsections of the
// given object file into the given stream writer.
Error writeAllModuleSymbolRecords(ObjFile *file, BinaryStreamWriter &writer);
// Callback to copy and relocate debug symbols during PDB file writing.
static Error commitSymbolsForObject(void *ctx, void *obj,
BinaryStreamWriter &writer);
// Copy the symbol record, relocate it, and fix the alignment if necessary.
// Rewrite type indices in the record. Replace unrecognized symbol records
// with S_SKIP records.
void writeSymbolRecord(SectionChunk *debugChunk,
ArrayRef<uint8_t> sectionContents, CVSymbol sym,
size_t alignedSize, uint32_t &nextRelocIndex,
std::vector<uint8_t> &storage);
void mergeSymbolRecords(TpiSource *source,
std::vector<ulittle32_t *> &stringTableRefs,
BinaryStreamRef symData);
/// Add the section map and section contributions to the PDB.
void addSections(ArrayRef<OutputSection *> outputSections,
@@ -174,16 +150,6 @@ private:
uint64_t nbTypeRecordsBytes = 0;
};
/// Represents an unrelocated DEBUG_S_FRAMEDATA subsection.
struct UnrelocatedFpoData {
SectionChunk *debugChunk = nullptr;
ArrayRef<uint8_t> subsecData;
uint32_t relocIndex = 0;
};
/// The size of the magic bytes at the beginning of a symbol section or stream.
enum : uint32_t { kSymbolStreamMagicSize = 4 };
class DebugSHandler {
PDBLinker &linker;
@@ -210,36 +176,23 @@ class DebugSHandler {
/// contain string table references which need to be re-written, so we
/// collect them all here and re-write them after all subsections have been
/// discovered and processed.
std::vector<UnrelocatedFpoData> frameDataSubsecs;
std::vector<DebugFrameDataSubsectionRef> newFpoFrames;
/// List of string table references in symbol records. Later they will be
/// applied to the symbols during PDB writing.
std::vector<StringTableFixup> stringTableFixups;
/// Pointers to raw memory that we determine have string table references
/// that need to be re-written. We first process all .debug$S subsections
/// to ensure that we can handle subsections written in any order, building
/// up this list as we go. At the end, we use the string table (which must
/// have been discovered by now else it is an error) to re-write these
/// references.
std::vector<ulittle32_t *> stringTableReferences;
/// Sum of the size of all module symbol records across all .debug$S sections.
/// Includes record realignment and the size of the symbol stream magic
/// prefix.
uint32_t moduleStreamSize = kSymbolStreamMagicSize;
/// Next relocation index in the current .debug$S section. Resets every
/// handleDebugS call.
uint32_t nextRelocIndex = 0;
void advanceRelocIndex(SectionChunk *debugChunk, ArrayRef<uint8_t> subsec);
void addUnrelocatedSubsection(SectionChunk *debugChunk,
const DebugSubsectionRecord &ss);
void addFrameDataSubsection(SectionChunk *debugChunk,
const DebugSubsectionRecord &ss);
void recordStringTableReferences(CVSymbol sym, uint32_t symOffset);
void mergeInlineeLines(const DebugSubsectionRecord &inlineeLines);
public:
DebugSHandler(PDBLinker &linker, ObjFile &file, TpiSource *source)
: linker(linker), file(file), source(source) {}
void handleDebugS(SectionChunk *debugChunk);
void handleDebugS(ArrayRef<uint8_t> relocatedDebugContents);
void finish();
};
@@ -313,19 +266,27 @@ static void addGHashTypeInfo(pdb::PDBFileBuilder &builder) {
}
static void
recordStringTableReferences(CVSymbol sym, uint32_t symOffset,
std::vector<StringTableFixup> &stringTableFixups) {
recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> contents,
uint32_t offset,
std::vector<ulittle32_t *> &strTableRefs) {
contents =
contents.drop_front(offset).take_front(sizeof(support::ulittle32_t));
ulittle32_t *index = reinterpret_cast<ulittle32_t *>(contents.data());
strTableRefs.push_back(index);
}
static void
recordStringTableReferences(SymbolKind kind, MutableArrayRef<uint8_t> contents,
std::vector<ulittle32_t *> &strTableRefs) {
// For now we only handle S_FILESTATIC, but we may need the same logic for
// S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any
// PDBs that contain these types of records, so because of the uncertainty
// they are omitted here until we can prove that it's necessary.
switch (sym.kind()) {
case SymbolKind::S_FILESTATIC: {
switch (kind) {
case SymbolKind::S_FILESTATIC:
// FileStaticSym::ModFileOffset
uint32_t ref = *reinterpret_cast<const ulittle32_t *>(&sym.data()[8]);
stringTableFixups.push_back({ref, symOffset + 8});
recordStringTableReferenceAtOffset(contents, 8, strTableRefs);
break;
}
case SymbolKind::S_DEFRANGE:
case SymbolKind::S_DEFRANGE_SUBFIELD:
log("Not fixing up string table reference in S_DEFRANGE / "
@@ -398,48 +359,60 @@ static void translateIdSymbols(MutableArrayRef<uint8_t> &recordData,
}
}
namespace {
/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned.
/// The object file may not be aligned.
static MutableArrayRef<uint8_t>
copyAndAlignSymbol(const CVSymbol &sym, MutableArrayRef<uint8_t> &alignedMem) {
size_t size = alignTo(sym.length(), alignOf(CodeViewContainer::Pdb));
assert(size >= 4 && "record too short");
assert(size <= MaxRecordLength && "record too long");
assert(alignedMem.size() >= size && "didn't preallocate enough");
// Copy the symbol record and zero out any padding bytes.
MutableArrayRef<uint8_t> newData = alignedMem.take_front(size);
alignedMem = alignedMem.drop_front(size);
memcpy(newData.data(), sym.data().data(), sym.length());
memset(newData.data() + sym.length(), 0, size - sym.length());
// Update the record prefix length. It should point to the beginning of the
// next record.
auto *prefix = reinterpret_cast<RecordPrefix *>(newData.data());
prefix->RecordLen = size - 2;
return newData;
}
struct ScopeRecord {
ulittle32_t ptrParent;
ulittle32_t ptrEnd;
};
} // namespace
/// Given a pointer to a symbol record that opens a scope, return a pointer to
/// the scope fields.
static ScopeRecord *getSymbolScopeFields(void *sym) {
return reinterpret_cast<ScopeRecord *>(reinterpret_cast<char *>(sym) +
sizeof(RecordPrefix));
struct SymbolScope {
ScopeRecord *openingRecord;
uint32_t scopeOffset;
};
static void scopeStackOpen(SmallVectorImpl<SymbolScope> &stack,
uint32_t curOffset, CVSymbol &sym) {
assert(symbolOpensScope(sym.kind()));
SymbolScope s;
s.scopeOffset = curOffset;
s.openingRecord = const_cast<ScopeRecord *>(
reinterpret_cast<const ScopeRecord *>(sym.content().data()));
s.openingRecord->ptrParent = stack.empty() ? 0 : stack.back().scopeOffset;
stack.push_back(s);
}
// To open a scope, push the offset of the current symbol record onto the
// stack.
static void scopeStackOpen(SmallVectorImpl<uint32_t> &stack,
std::vector<uint8_t> &storage) {
stack.push_back(storage.size());
}
// To close a scope, update the record that opened the scope.
static void scopeStackClose(SmallVectorImpl<uint32_t> &stack,
std::vector<uint8_t> &storage,
uint32_t storageBaseOffset, ObjFile *file) {
static void scopeStackClose(SmallVectorImpl<SymbolScope> &stack,
uint32_t curOffset, InputFile *file) {
if (stack.empty()) {
warn("symbol scopes are not balanced in " + file->getName());
return;
}
// Update ptrEnd of the record that opened the scope to point to the
// current record, if we are writing into the module symbol stream.
uint32_t offOpen = stack.pop_back_val();
uint32_t offEnd = storageBaseOffset + storage.size();
uint32_t offParent = stack.empty() ? 0 : (stack.back() + storageBaseOffset);
ScopeRecord *scopeRec = getSymbolScopeFields(&(storage)[offOpen]);
scopeRec->ptrParent = offParent;
scopeRec->ptrEnd = offEnd;
SymbolScope s = stack.pop_back_val();
s.openingRecord->ptrEnd = curOffset;
}
static bool symbolGoesInModuleStream(const CVSymbol &sym,
unsigned symbolScopeDepth) {
static bool symbolGoesInModuleStream(const CVSymbol &sym, bool isGlobalScope) {
switch (sym.kind()) {
case SymbolKind::S_GDATA32:
case SymbolKind::S_CONSTANT:
@@ -453,7 +426,7 @@ static bool symbolGoesInModuleStream(const CVSymbol &sym,
return false;
// S_UDT records go in the module stream if it is not a global S_UDT.
case SymbolKind::S_UDT:
return symbolScopeDepth > 0;
return !isGlobalScope;
// S_GDATA32 does not go in the module stream, but S_LDATA32 does.
case SymbolKind::S_LDATA32:
case SymbolKind::S_LTHREAD32:
@@ -463,15 +436,13 @@ static bool symbolGoesInModuleStream(const CVSymbol &sym,
}
static bool symbolGoesInGlobalsStream(const CVSymbol &sym,
unsigned symbolScopeDepth) {
bool isFunctionScope) {
switch (sym.kind()) {
case SymbolKind::S_CONSTANT:
case SymbolKind::S_GDATA32:
case SymbolKind::S_GTHREAD32:
case SymbolKind::S_GPROC32:
case SymbolKind::S_LPROC32:
case SymbolKind::S_GPROC32_ID:
case SymbolKind::S_LPROC32_ID:
// We really should not be seeing S_PROCREF and S_LPROCREF in the first place
// since they are synthesized by the linker in response to S_GPROC32 and
// S_LPROC32, but if we do see them, copy them straight through.
@@ -482,16 +453,14 @@ static bool symbolGoesInGlobalsStream(const CVSymbol &sym,
case SymbolKind::S_UDT:
case SymbolKind::S_LDATA32:
case SymbolKind::S_LTHREAD32:
return symbolScopeDepth == 0;
return !isFunctionScope;
default:
return false;
}
}
static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex,
unsigned symOffset,
std::vector<uint8_t> &symStorage) {
CVSymbol sym(makeArrayRef(symStorage));
unsigned symOffset, const CVSymbol &sym) {
switch (sym.kind()) {
case SymbolKind::S_CONSTANT:
case SymbolKind::S_UDT:
@@ -500,14 +469,9 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex,
case SymbolKind::S_LTHREAD32:
case SymbolKind::S_LDATA32:
case SymbolKind::S_PROCREF:
case SymbolKind::S_LPROCREF: {
// sym is a temporary object, so we have to copy and reallocate the record
// to stabilize it.
uint8_t *mem = bAlloc.Allocate<uint8_t>(sym.length());
memcpy(mem, sym.data().data(), sym.length());
builder.addGlobalSymbol(CVSymbol(makeArrayRef(mem, sym.length())));
case SymbolKind::S_LPROCREF:
builder.addGlobalSymbol(sym);
break;
}
case SymbolKind::S_GPROC32:
case SymbolKind::S_LPROC32: {
SymbolRecordKind k = SymbolRecordKind::ProcRefSym;
@@ -528,189 +492,117 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &builder, uint16_t modIndex,
}
}
// Check if the given symbol record was padded for alignment. If so, zero out
// the padding bytes and update the record prefix with the new size.
static void fixRecordAlignment(MutableArrayRef<uint8_t> recordBytes,
size_t oldSize) {
size_t alignedSize = recordBytes.size();
if (oldSize == alignedSize)
return;
reinterpret_cast<RecordPrefix *>(recordBytes.data())->RecordLen =
alignedSize - 2;
memset(recordBytes.data() + oldSize, 0, alignedSize - oldSize);
}
// Replace any record with a skip record of the same size. This is useful when
// we have reserved size for a symbol record, but type index remapping fails.
static void replaceWithSkipRecord(MutableArrayRef<uint8_t> recordBytes) {
memset(recordBytes.data(), 0, recordBytes.size());
auto *prefix = reinterpret_cast<RecordPrefix *>(recordBytes.data());
prefix->RecordKind = SymbolKind::S_SKIP;
prefix->RecordLen = recordBytes.size() - 2;
}
// Copy the symbol record, relocate it, and fix the alignment if necessary.
// Rewrite type indices in the record. Replace unrecognized symbol records with
// S_SKIP records.
void PDBLinker::writeSymbolRecord(SectionChunk *debugChunk,
ArrayRef<uint8_t> sectionContents,
CVSymbol sym, size_t alignedSize,
uint32_t &nextRelocIndex,
std::vector<uint8_t> &storage) {
// Allocate space for the new record at the end of the storage.
storage.resize(storage.size() + alignedSize);
auto recordBytes = MutableArrayRef<uint8_t>(storage).take_back(alignedSize);
// Copy the symbol record and relocate it.
debugChunk->writeAndRelocateSubsection(sectionContents, sym.data(),
nextRelocIndex, recordBytes.data());
fixRecordAlignment(recordBytes, sym.length());
// Re-map all the type index references.
TpiSource *source = debugChunk->file->debugTypesObj;
if (!source->remapTypesInSymbolRecord(recordBytes)) {
log("ignoring unknown symbol record with kind 0x" + utohexstr(sym.kind()));
replaceWithSkipRecord(recordBytes);
}
// An object file may have S_xxx_ID symbols, but these get converted to
// "real" symbols in a PDB.
translateIdSymbols(recordBytes, tMerger, source);
}
void PDBLinker::analyzeSymbolSubsection(
SectionChunk *debugChunk, uint32_t &moduleSymOffset,
uint32_t &nextRelocIndex, std::vector<StringTableFixup> &stringTableFixups,
BinaryStreamRef symData) {
ObjFile *file = debugChunk->file;
uint32_t moduleSymStart = moduleSymOffset;
uint32_t scopeLevel = 0;
std::vector<uint8_t> storage;
ArrayRef<uint8_t> sectionContents = debugChunk->getContents();
void PDBLinker::mergeSymbolRecords(TpiSource *source,
std::vector<ulittle32_t *> &stringTableRefs,
BinaryStreamRef symData) {
ObjFile *file = source->file;
ArrayRef<uint8_t> symsBuffer;
cantFail(symData.readBytes(0, symData.getLength(), symsBuffer));
SmallVector<SymbolScope, 4> scopes;
if (symsBuffer.empty())
warn("empty symbols subsection in " + file->getName());
Error ec = forEachCodeViewRecord<CVSymbol>(
// Iterate every symbol to check if any need to be realigned, and if so, how
// much space we need to allocate for them.
bool needsRealignment = false;
unsigned totalRealignedSize = 0;
auto ec = forEachCodeViewRecord<CVSymbol>(
symsBuffer, [&](CVSymbol sym) -> llvm::Error {
// Track the current scope.
if (symbolOpensScope(sym.kind()))
++scopeLevel;
else if (symbolEndsScope(sym.kind()))
--scopeLevel;
uint32_t alignedSize =
unsigned realignedSize =
alignTo(sym.length(), alignOf(CodeViewContainer::Pdb));
// Copy global records. Some global records (mainly procedures)
// reference the current offset into the module stream.
if (symbolGoesInGlobalsStream(sym, scopeLevel)) {
storage.clear();
writeSymbolRecord(debugChunk, sectionContents, sym, alignedSize,
nextRelocIndex, storage);
addGlobalSymbol(builder.getGsiBuilder(),
file->moduleDBI->getModuleIndex(), moduleSymOffset,
storage);
++globalSymbols;
}
// Update the module stream offset and record any string table index
// references. There are very few of these and they will be rewritten
// later during PDB writing.
if (symbolGoesInModuleStream(sym, scopeLevel)) {
recordStringTableReferences(sym, moduleSymOffset, stringTableFixups);
moduleSymOffset += alignedSize;
++moduleSymbols;
}
needsRealignment |= realignedSize != sym.length();
totalRealignedSize += realignedSize;
return Error::success();
});
// If we encountered corrupt records, ignore the whole subsection. If we wrote
// any partial records, undo that. For globals, we just keep what we have and
// continue.
// If any of the symbol record lengths was corrupt, ignore them all, warn
// about it, and move on.
if (ec) {
warn("corrupt symbol records in " + file->getName());
moduleSymOffset = moduleSymStart;
consumeError(std::move(ec));
}
}
Error PDBLinker::writeAllModuleSymbolRecords(ObjFile *file,
BinaryStreamWriter &writer) {
std::vector<uint8_t> storage;
SmallVector<uint32_t, 4> scopes;
// Visit all live .debug$S sections a second time, and write them to the PDB.
for (SectionChunk *debugChunk : file->getDebugChunks()) {
if (!debugChunk->live || debugChunk->getSize() == 0 ||
debugChunk->getSectionName() != ".debug$S")
continue;
ArrayRef<uint8_t> sectionContents = debugChunk->getContents();
auto contents =
SectionChunk::consumeDebugMagic(sectionContents, ".debug$S");
DebugSubsectionArray subsections;
BinaryStreamReader reader(contents, support::little);
exitOnErr(reader.readArray(subsections, contents.size()));
uint32_t nextRelocIndex = 0;
for (const DebugSubsectionRecord &ss : subsections) {
if (ss.kind() != DebugSubsectionKind::Symbols)
continue;
uint32_t moduleSymStart = writer.getOffset();
scopes.clear();
storage.clear();
ArrayRef<uint8_t> symsBuffer;
BinaryStreamRef sr = ss.getRecordData();
cantFail(sr.readBytes(0, sr.getLength(), symsBuffer));
auto ec = forEachCodeViewRecord<CVSymbol>(
symsBuffer, [&](CVSymbol sym) -> llvm::Error {
// Track the current scope. Only update records in the postmerge
// pass.
if (symbolOpensScope(sym.kind()))
scopeStackOpen(scopes, storage);
else if (symbolEndsScope(sym.kind()))
scopeStackClose(scopes, storage, moduleSymStart, file);
// Copy, relocate, and rewrite each module symbol.
if (symbolGoesInModuleStream(sym, scopes.size())) {
uint32_t alignedSize =
alignTo(sym.length(), alignOf(CodeViewContainer::Pdb));
writeSymbolRecord(debugChunk, sectionContents, sym, alignedSize,
nextRelocIndex, storage);
}
return Error::success();
});
// If we encounter corrupt records in the second pass, ignore them. We
// already warned about them in the first analysis pass.
if (ec) {
consumeError(std::move(ec));
storage.clear();
}
// Writing bytes has a very high overhead, so write the entire subsection
// at once.
// TODO: Consider buffering symbols for the entire object file to reduce
// overhead even further.
if (Error e = writer.writeBytes(storage))
return e;
}
return;
}
return Error::success();
}
// If any symbol needed realignment, allocate enough contiguous memory for
// them all. Typically symbol subsections are small enough that this will not
// cause fragmentation.
MutableArrayRef<uint8_t> alignedSymbolMem;
if (needsRealignment) {
void *alignedData =
bAlloc.Allocate(totalRealignedSize, alignOf(CodeViewContainer::Pdb));
alignedSymbolMem = makeMutableArrayRef(
reinterpret_cast<uint8_t *>(alignedData), totalRealignedSize);
}
Error PDBLinker::commitSymbolsForObject(void *ctx, void *obj,
BinaryStreamWriter &writer) {
return static_cast<PDBLinker *>(ctx)->writeAllModuleSymbolRecords(
static_cast<ObjFile *>(obj), writer);
// Iterate again, this time doing the real work.
unsigned curSymOffset = file->moduleDBI->getNextSymbolOffset();
ArrayRef<uint8_t> bulkSymbols;
cantFail(forEachCodeViewRecord<CVSymbol>(
symsBuffer, [&](CVSymbol sym) -> llvm::Error {
// Align the record if required.
MutableArrayRef<uint8_t> recordBytes;
if (needsRealignment) {
recordBytes = copyAndAlignSymbol(sym, alignedSymbolMem);
sym = CVSymbol(recordBytes);
} else {
// Otherwise, we can actually mutate the symbol directly, since we
// copied it to apply relocations.
recordBytes = makeMutableArrayRef(
const_cast<uint8_t *>(sym.data().data()), sym.length());
}
// Re-map all the type index references.
if (!source->remapTypesInSymbolRecord(recordBytes)) {
log("error remapping types in symbol of kind 0x" +
utohexstr(sym.kind()) + ", ignoring");
return Error::success();
}
// An object file may have S_xxx_ID symbols, but these get converted to
// "real" symbols in a PDB.
translateIdSymbols(recordBytes, tMerger, source);
sym = CVSymbol(recordBytes);
// If this record refers to an offset in the object file's string table,
// add that item to the global PDB string table and re-write the index.
recordStringTableReferences(sym.kind(), recordBytes, stringTableRefs);
// Fill in "Parent" and "End" fields by maintaining a stack of scopes.
if (symbolOpensScope(sym.kind()))
scopeStackOpen(scopes, curSymOffset, sym);
else if (symbolEndsScope(sym.kind()))
scopeStackClose(scopes, curSymOffset, file);
// Add the symbol to the globals stream if necessary. Do this before
// adding the symbol to the module since we may need to get the next
// symbol offset, and writing to the module's symbol stream will update
// that offset.
if (symbolGoesInGlobalsStream(sym, !scopes.empty())) {
addGlobalSymbol(builder.getGsiBuilder(),
file->moduleDBI->getModuleIndex(), curSymOffset, sym);
++globalSymbols;
}
if (symbolGoesInModuleStream(sym, scopes.empty())) {
// Add symbols to the module in bulk. If this symbol is contiguous
// with the previous run of symbols to add, combine the ranges. If
// not, close the previous range of symbols and start a new one.
if (sym.data().data() == bulkSymbols.end()) {
bulkSymbols = makeArrayRef(bulkSymbols.data(),
bulkSymbols.size() + sym.length());
} else {
file->moduleDBI->addSymbolsInBulk(bulkSymbols);
bulkSymbols = recordBytes;
}
curSymOffset += sym.length();
++moduleSymbols;
}
return Error::success();
}));
// Add any remaining symbols we've accumulated.
file->moduleDBI->addSymbolsInBulk(bulkSymbols);
}
static pdb::SectionContrib createSectionContrib(const Chunk *c, uint32_t modi) {
@@ -750,18 +642,13 @@ translateStringTableIndex(uint32_t objIndex,
return pdbStrTable.insert(*expectedString);
}
void DebugSHandler::handleDebugS(SectionChunk *debugChunk) {
// Note that we are processing the *unrelocated* section contents. They will
// be relocated later during PDB writing.
ArrayRef<uint8_t> contents = debugChunk->getContents();
contents = SectionChunk::consumeDebugMagic(contents, ".debug$S");
DebugSubsectionArray subsections;
BinaryStreamReader reader(contents, support::little);
exitOnErr(reader.readArray(subsections, contents.size()));
debugChunk->sortRelocations();
void DebugSHandler::handleDebugS(ArrayRef<uint8_t> relocatedDebugContents) {
relocatedDebugContents =
SectionChunk::consumeDebugMagic(relocatedDebugContents, ".debug$S");
// Reset the relocation index, since this is a new section.
nextRelocIndex = 0;
DebugSubsectionArray subsections;
BinaryStreamReader reader(relocatedDebugContents, support::little);
exitOnErr(reader.readArray(subsections, relocatedDebugContents.size()));
for (const DebugSubsectionRecord &ss : subsections) {
// Ignore subsections with the 'ignore' bit. Some versions of the Visual C++
@@ -782,17 +669,30 @@ void DebugSHandler::handleDebugS(SectionChunk *debugChunk) {
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::InlineeLines:
addUnrelocatedSubsection(debugChunk, ss);
// The inlinee lines subsection also has file checksum table references
// that can be used directly, but it contains function id references that
// must be remapped.
mergeInlineeLines(ss);
break;
case DebugSubsectionKind::FrameData:
addFrameDataSubsection(debugChunk, ss);
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:
linker.analyzeSymbolSubsection(debugChunk, moduleStreamSize,
nextRelocIndex, stringTableFixups,
ss.getRecordData());
}
case DebugSubsectionKind::Symbols: {
linker.mergeSymbolRecords(source, stringTableReferences,
ss.getRecordData());
break;
}
case DebugSubsectionKind::CrossScopeImports:
case DebugSubsectionKind::CrossScopeExports:
@@ -819,85 +719,6 @@ void DebugSHandler::handleDebugS(SectionChunk *debugChunk) {
}
}
void DebugSHandler::advanceRelocIndex(SectionChunk *sc,
ArrayRef<uint8_t> subsec) {
ptrdiff_t vaBegin = subsec.data() - sc->getContents().data();
assert(vaBegin > 0);
auto relocs = sc->getRelocs();
for (; nextRelocIndex < relocs.size(); ++nextRelocIndex) {
if (relocs[nextRelocIndex].VirtualAddress >= vaBegin)
break;
}
}
namespace {
/// Wrapper class for unrelocated line and inlinee line subsections, which
/// require only relocation and type index remapping to add to the PDB.
class UnrelocatedDebugSubsection : public DebugSubsection {
public:
UnrelocatedDebugSubsection(DebugSubsectionKind k, SectionChunk *debugChunk,
ArrayRef<uint8_t> subsec, uint32_t relocIndex)
: DebugSubsection(k), debugChunk(debugChunk), subsec(subsec),
relocIndex(relocIndex) {}
Error commit(BinaryStreamWriter &writer) const override;
uint32_t calculateSerializedSize() const override { return subsec.size(); }
SectionChunk *debugChunk;
ArrayRef<uint8_t> subsec;
uint32_t relocIndex;
};
} // namespace
Error UnrelocatedDebugSubsection::commit(BinaryStreamWriter &writer) const {
std::vector<uint8_t> relocatedBytes(subsec.size());
uint32_t tmpRelocIndex = relocIndex;
debugChunk->writeAndRelocateSubsection(debugChunk->getContents(), subsec,
tmpRelocIndex, relocatedBytes.data());
// Remap type indices in inlinee line records in place. Skip the remapping if
// there is no type source info.
if (kind() == DebugSubsectionKind::InlineeLines &&
debugChunk->file->debugTypesObj) {
TpiSource *source = debugChunk->file->debugTypesObj;
DebugInlineeLinesSubsectionRef inlineeLines;
BinaryStreamReader storageReader(relocatedBytes, support::little);
exitOnErr(inlineeLines.initialize(storageReader));
for (const InlineeSourceLine &line : inlineeLines) {
TypeIndex &inlinee = *const_cast<TypeIndex *>(&line.Header->Inlinee);
if (!source->remapTypeIndex(inlinee, TiRefKind::IndexRef)) {
log("bad inlinee line record in " + debugChunk->file->getName() +
" with bad inlinee index 0x" + utohexstr(inlinee.getIndex()));
}
}
}
return writer.writeBytes(relocatedBytes);
}
void DebugSHandler::addUnrelocatedSubsection(SectionChunk *debugChunk,
const DebugSubsectionRecord &ss) {
ArrayRef<uint8_t> subsec;
BinaryStreamRef sr = ss.getRecordData();
cantFail(sr.readBytes(0, sr.getLength(), subsec));
advanceRelocIndex(debugChunk, subsec);
file.moduleDBI->addDebugSubsection(
std::make_shared<UnrelocatedDebugSubsection>(ss.kind(), debugChunk,
subsec, nextRelocIndex));
}
void DebugSHandler::addFrameDataSubsection(SectionChunk *debugChunk,
const DebugSubsectionRecord &ss) {
// 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.
ArrayRef<uint8_t> subsec;
BinaryStreamRef sr = ss.getRecordData();
cantFail(sr.readBytes(0, sr.getLength(), subsec));
advanceRelocIndex(debugChunk, subsec);
frameDataSubsecs.push_back({debugChunk, subsec, nextRelocIndex});
}
static Expected<StringRef>
getFileName(const DebugStringTableSubsectionRef &strings,
const DebugChecksumsSubsectionRef &checksums, uint32_t fileID) {
@@ -908,14 +729,31 @@ getFileName(const DebugStringTableSubsectionRef &strings,
return strings.getString(offset);
}
void DebugSHandler::mergeInlineeLines(
const DebugSubsectionRecord &inlineeSubsection) {
DebugInlineeLinesSubsectionRef inlineeLines;
exitOnErr(inlineeLines.initialize(inlineeSubsection.getRecordData()));
if (!source) {
warn("ignoring inlinee lines section in file that lacks type information");
return;
}
// Remap type indices in inlinee line records in place.
for (const InlineeSourceLine &line : inlineeLines) {
TypeIndex &inlinee = *const_cast<TypeIndex *>(&line.Header->Inlinee);
if (!source->remapTypeIndex(inlinee, TiRefKind::IndexRef)) {
log("bad inlinee line record in " + file.getName() +
" with bad inlinee index 0x" + utohexstr(inlinee.getIndex()));
}
}
// Add the modified inlinee line subsection directly.
file.moduleDBI->addDebugSubsection(inlineeSubsection);
}
void DebugSHandler::finish() {
pdb::DbiStreamBuilder &dbiBuilder = linker.builder.getDbiBuilder();
// If we found any symbol records for the module symbol stream, defer them.
if (moduleStreamSize > kSymbolStreamMagicSize)
file.moduleDBI->addUnmergedSymbols(&file, moduleStreamSize -
kSymbolStreamMagicSize);
// We should have seen all debug subsections across the entire object file now
// which means that if a StringTable subsection and Checksums subsection were
// present, now is the time to handle them.
@@ -924,50 +762,26 @@ void DebugSHandler::finish() {
fatal(".debug$S sections with a checksums subsection must also contain a "
"string table subsection");
if (!stringTableFixups.empty())
if (!stringTableReferences.empty())
warn("No StringTable subsection was encountered, but there are string "
"table references");
return;
}
// Handle FPO data. Each subsection begins with a single image base
// relocation, which is then added to the RvaStart of each frame data record
// when it is added to the PDB. The string table indices for the FPO program
// must also be rewritten to use the PDB string table.
for (const UnrelocatedFpoData &subsec : frameDataSubsecs) {
// Relocate the first four bytes of the subection and reinterpret them as a
// 32 bit integer.
SectionChunk *debugChunk = subsec.debugChunk;
ArrayRef<uint8_t> subsecData = subsec.subsecData;
uint32_t relocIndex = subsec.relocIndex;
auto unrelocatedRvaStart = subsecData.take_front(sizeof(uint32_t));
uint8_t relocatedRvaStart[sizeof(uint32_t)];
debugChunk->writeAndRelocateSubsection(debugChunk->getContents(),
unrelocatedRvaStart, relocIndex,
&relocatedRvaStart[0]);
uint32_t rvaStart;
memcpy(&rvaStart, &relocatedRvaStart[0], sizeof(uint32_t));
// Copy each frame data record, add in rvaStart, translate string table
// indices, and add the record to the PDB.
DebugFrameDataSubsectionRef fds;
BinaryStreamReader reader(subsecData, support::little);
exitOnErr(fds.initialize(reader));
// 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 : newFpoFrames) {
const ulittle32_t *reloc = fds.getRelocPtr();
for (codeview::FrameData fd : fds) {
fd.RvaStart += rvaStart;
fd.RvaStart += *reloc;
fd.FrameFunc =
translateStringTableIndex(fd.FrameFunc, cvStrTab, linker.pdbStrTab);
dbiBuilder.addNewFpoData(fd);
}
}
// Translate the fixups and pass them off to the module builder so they will
// be applied during writing.
for (StringTableFixup &ref : stringTableFixups) {
ref.StrTabOffset =
translateStringTableIndex(ref.StrTabOffset, cvStrTab, linker.pdbStrTab);
}
file.moduleDBI->setStringTableFixups(std::move(stringTableFixups));
for (ulittle32_t *ref : stringTableReferences)
*ref = translateStringTableIndex(*ref, cvStrTab, linker.pdbStrTab);
// Make a new file checksum table that refers to offsets in the PDB-wide
// string table. Generally the string table subsection appears after the
@@ -1030,12 +844,11 @@ void PDBLinker::addDebugSymbols(TpiSource *source) {
if (!isDebugS && !isDebugF)
continue;
ArrayRef<uint8_t> relocatedDebugContents = relocateDebugChunk(*debugChunk);
if (isDebugS) {
dsh.handleDebugS(debugChunk);
dsh.handleDebugS(relocatedDebugContents);
} else if (isDebugF) {
// Handle old FPO data .debug$F sections. These are relatively rare.
ArrayRef<uint8_t> relocatedDebugContents =
relocateDebugChunk(*debugChunk);
FixedStreamArray<object::FpoData> fpoRecords;
BinaryStreamReader reader(relocatedDebugContents, support::little);
uint32_t count = relocatedDebugContents.size() / sizeof(object::FpoData);
@@ -1056,7 +869,7 @@ void PDBLinker::addDebugSymbols(TpiSource *source) {
// path to the object into the PDB. If this is a plain object, we make its
// path absolute. If it's an object in an archive, we make the archive path
// absolute.
void PDBLinker::createModuleDBI(ObjFile *file) {
static void createModuleDBI(pdb::PDBFileBuilder &builder, ObjFile *file) {
pdb::DbiStreamBuilder &dbiBuilder = builder.getDbiBuilder();
SmallString<128> objName;
@@ -1067,7 +880,6 @@ void PDBLinker::createModuleDBI(ObjFile *file) {
file->moduleDBI = &exitOnErr(dbiBuilder.addModuleInfo(modName));
file->moduleDBI->setObjFileName(objName);
file->moduleDBI->setMergeSymbolsCallback(this, &commitSymbolsForObject);
ArrayRef<Chunk *> chunks = file->getChunks();
uint32_t modi = file->moduleDBI->getModuleIndex();
@@ -1134,7 +946,8 @@ void PDBLinker::addObjectsToPDB() {
ScopedTimer t1(addObjectsTimer);
// Create module descriptors
for_each(ObjFile::instances, [&](ObjFile *obj) { createModuleDBI(obj); });
for_each(ObjFile::instances,
[&](ObjFile *obj) { createModuleDBI(builder, obj); });
// Reorder dependency type sources to come first.
TpiSource::sortDependencies();
@@ -1517,18 +1330,16 @@ void PDBLinker::addImportFilesToPDB(ArrayRef<OutputSection *> outputSections) {
mod->addSymbol(codeview::SymbolSerializer::writeOneSymbol(
cs, bAlloc, CodeViewContainer::Pdb));
SmallVector<SymbolScope, 4> scopes;
CVSymbol newSym = codeview::SymbolSerializer::writeOneSymbol(
ts, bAlloc, CodeViewContainer::Pdb);
// Write ptrEnd for the S_THUNK32.
ScopeRecord *thunkSymScope =
getSymbolScopeFields(const_cast<uint8_t *>(newSym.data().data()));
scopeStackOpen(scopes, mod->getNextSymbolOffset(), newSym);
mod->addSymbol(newSym);
newSym = codeview::SymbolSerializer::writeOneSymbol(es, bAlloc,
CodeViewContainer::Pdb);
thunkSymScope->ptrEnd = mod->getNextSymbolOffset();
scopeStackClose(scopes, mod->getNextSymbolOffset(), file);
mod->addSymbol(newSym);

View File

@@ -34,34 +34,6 @@ struct MSFLayout;
}
namespace pdb {
// Represents merged or unmerged symbols. Merged symbols can be written to the
// output file as is, but unmerged symbols must be rewritten first. In either
// case, the size must be known up front.
struct SymbolListWrapper {
explicit SymbolListWrapper(ArrayRef<uint8_t> Syms)
: SymPtr(const_cast<uint8_t *>(Syms.data())), SymSize(Syms.size()),
NeedsToBeMerged(false) {}
explicit SymbolListWrapper(void *SymSrc, uint32_t Length)
: SymPtr(SymSrc), SymSize(Length), NeedsToBeMerged(true) {}
ArrayRef<uint8_t> asArray() const {
return ArrayRef<uint8_t>(static_cast<const uint8_t *>(SymPtr), SymSize);
}
uint32_t size() const { return SymSize; }
void *SymPtr = nullptr;
uint32_t SymSize = 0;
bool NeedsToBeMerged = false;
};
/// Represents a string table reference at some offset in the module symbol
/// stream.
struct StringTableFixup {
uint32_t StrTabOffset = 0;
uint32_t SymOffsetOfReference = 0;
};
class DbiModuleDescriptorBuilder {
friend class DbiStreamBuilder;
@@ -76,28 +48,10 @@ public:
void setPdbFilePathNI(uint32_t NI);
void setObjFileName(StringRef Name);
// Callback to merge one source of unmerged symbols.
using MergeSymbolsCallback = Error (*)(void *Ctx, void *Symbols,
BinaryStreamWriter &Writer);
void setMergeSymbolsCallback(void *Ctx, MergeSymbolsCallback Callback) {
MergeSymsCtx = Ctx;
MergeSymsCallback = Callback;
}
void setStringTableFixups(std::vector<StringTableFixup> &&Fixups) {
StringTableFixups = std::move(Fixups);
}
void setFirstSectionContrib(const SectionContrib &SC);
void addSymbol(codeview::CVSymbol Symbol);
void addSymbolsInBulk(ArrayRef<uint8_t> BulkSymbols);
// Add symbols of known size which will be merged (rewritten) when committing
// the PDB to disk.
void addUnmergedSymbols(void *SymSrc, uint32_t SymLength);
void
addDebugSubsection(std::shared_ptr<codeview::DebugSubsection> Subsection);
@@ -123,14 +77,8 @@ public:
void finalize();
Error finalizeMsfLayout();
/// Commit the DBI descriptor to the DBI stream.
Error commit(BinaryStreamWriter &ModiWriter);
/// Commit the accumulated symbols to the module symbol stream. Safe to call
/// in parallel on different DbiModuleDescriptorBuilder objects. Only modifies
/// the pre-allocated stream in question.
Error commitSymbolStream(const msf::MSFLayout &MsfLayout,
WritableBinaryStreamRef MsfBuffer);
Error commit(BinaryStreamWriter &ModiWriter, const msf::MSFLayout &MsfLayout,
WritableBinaryStreamRef MsfBuffer);
private:
uint32_t calculateC13DebugInfoSize() const;
@@ -143,12 +91,7 @@ private:
std::string ModuleName;
std::string ObjFileName;
std::vector<std::string> SourceFiles;
std::vector<SymbolListWrapper> Symbols;
void *MergeSymsCtx = nullptr;
MergeSymbolsCallback MergeSymsCallback = nullptr;
std::vector<StringTableFixup> StringTableFixups;
std::vector<ArrayRef<uint8_t>> Symbols;
std::vector<codeview::DebugSubsectionRecordBuilder> C13Builders;

View File

@@ -74,7 +74,7 @@ void DbiModuleDescriptorBuilder::addSymbolsInBulk(
if (BulkSymbols.empty())
return;
Symbols.push_back(SymbolListWrapper(BulkSymbols));
Symbols.push_back(BulkSymbols);
// Symbols written to a PDB file are required to be 4 byte aligned. The same
// is not true of object files.
assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 &&
@@ -82,18 +82,6 @@ void DbiModuleDescriptorBuilder::addSymbolsInBulk(
SymbolByteSize += BulkSymbols.size();
}
void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc,
uint32_t SymLength) {
assert(SymLength > 0);
Symbols.push_back(SymbolListWrapper(SymSrc, SymLength));
// Symbols written to a PDB file are required to be 4 byte aligned. The same
// is not true of object files.
assert(SymLength % alignOf(CodeViewContainer::Pdb) == 0 &&
"Invalid Symbol alignment!");
SymbolByteSize += SymLength;
}
void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
SourceFiles.push_back(std::string(Path));
}
@@ -143,7 +131,9 @@ Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {
return Error::success();
}
Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {
Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
const msf::MSFLayout &MsfLayout,
WritableBinaryStreamRef MsfBuffer) {
// We write the Modi record to the `ModiWriter`, but we additionally write its
// symbol stream to a brand new stream.
if (auto EC = ModiWriter.writeObject(Layout))
@@ -154,55 +144,34 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {
return EC;
if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
return EC;
return Error::success();
}
Error DbiModuleDescriptorBuilder::commitSymbolStream(
const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) {
if (Layout.ModDiStream == kInvalidStreamIndex)
return Error::success();
auto NS = WritableMappedBlockStream::createIndexedStream(
MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
WritableBinaryStreamRef Ref(*NS);
BinaryStreamWriter SymbolWriter(Ref);
// Write the symbols.
if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
return EC;
for (const SymbolListWrapper &Sym : Symbols) {
if (Sym.NeedsToBeMerged) {
assert(MergeSymsCallback);
if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter))
return EC;
} else {
if (auto EC = SymbolWriter.writeBytes(Sym.asArray()))
if (Layout.ModDiStream != kInvalidStreamIndex) {
auto NS = WritableMappedBlockStream::createIndexedStream(
MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
WritableBinaryStreamRef Ref(*NS);
BinaryStreamWriter SymbolWriter(Ref);
// Write the symbols.
if (auto EC =
SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
return EC;
for (ArrayRef<uint8_t> Syms : Symbols) {
if (auto EC = SymbolWriter.writeBytes(Syms))
return EC;
}
assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
"Invalid debug section alignment!");
// TODO: Write C11 Line data
for (const auto &Builder : C13Builders) {
if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))
return EC;
}
}
// Apply the string table fixups.
auto SavedOffset = SymbolWriter.getOffset();
for (const StringTableFixup &Fixup : StringTableFixups) {
SymbolWriter.setOffset(Fixup.SymOffsetOfReference);
if (auto E = SymbolWriter.writeInteger<uint32_t>(Fixup.StrTabOffset))
return E;
}
SymbolWriter.setOffset(SavedOffset);
assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
"Invalid debug section alignment!");
// TODO: Write C11 Line data
for (const auto &Builder : C13Builders) {
if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))
// TODO: Figure out what GlobalRefs substream actually is and populate it.
if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
return EC;
if (SymbolWriter.bytesRemaining() > 0)
return make_error<RawError>(raw_error_code::stream_too_long);
}
// TODO: Figure out what GlobalRefs substream actually is and populate it.
if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
return EC;
if (SymbolWriter.bytesRemaining() > 0)
return make_error<RawError>(raw_error_code::stream_too_long);
return Error::success();
}

View File

@@ -18,7 +18,6 @@
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Parallel.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -395,17 +394,10 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
return EC;
for (auto &M : ModiList) {
if (auto EC = M->commit(Writer))
if (auto EC = M->commit(Writer, Layout, MsfBuffer))
return EC;
}
// Commit symbol streams. This is a lot of data, so do it in parallel.
if (auto EC = parallelForEachError(
ModiList, [&](std::unique_ptr<DbiModuleDescriptorBuilder> &M) {
return M->commitSymbolStream(Layout, MsfBuffer);
}))
return EC;
if (!SectionContribs.empty()) {
if (auto EC = Writer.writeEnum(DbiSecContribVer60))
return EC;