summaryrefslogtreecommitdiff
path: root/COFF/PDB.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'COFF/PDB.cpp')
-rw-r--r--COFF/PDB.cpp174
1 files changed, 152 insertions, 22 deletions
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index c9842cfd1b9ab..508f59e3af1fd 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -18,19 +18,20 @@
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
-#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
@@ -124,26 +125,25 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
return true;
}
-static bool remapTypesInSymbolRecord(ObjectFile *File,
+static void remapTypesInSymbolRecord(ObjectFile *File,
MutableArrayRef<uint8_t> Contents,
ArrayRef<TypeIndex> TypeIndexMap,
ArrayRef<TiReference> TypeRefs) {
for (const TiReference &Ref : TypeRefs) {
unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
- if (Contents.size() < Ref.Offset + ByteSize) {
- log("ignoring short symbol record");
- return false;
- }
+ if (Contents.size() < Ref.Offset + ByteSize)
+ fatal("symbol record too short");
MutableArrayRef<TypeIndex> TIs(
reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count);
- for (TypeIndex &TI : TIs)
+ for (TypeIndex &TI : TIs) {
if (!remapTypeIndex(TI, TypeIndexMap)) {
+ TI = TypeIndex(SimpleTypeKind::NotTranslated);
log("ignoring symbol record in " + File->getName() +
" with bad type index 0x" + utohexstr(TI.getIndex()));
- return false;
+ continue;
}
+ }
}
- return true;
}
/// MSVC translates S_PROC_ID_END to S_END.
@@ -176,6 +176,70 @@ static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym,
return NewData;
}
+/// Return true if this symbol opens a scope. This implies that the symbol has
+/// "parent" and "end" fields, which contain the offset of the S_END or
+/// S_INLINESITE_END record.
+static bool symbolOpensScope(SymbolKind Kind) {
+ switch (Kind) {
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_BLOCK32:
+ case SymbolKind::S_SEPCODE:
+ case SymbolKind::S_THUNK32:
+ case SymbolKind::S_INLINESITE:
+ case SymbolKind::S_INLINESITE2:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool symbolEndsScope(SymbolKind Kind) {
+ switch (Kind) {
+ case SymbolKind::S_END:
+ case SymbolKind::S_PROC_ID_END:
+ case SymbolKind::S_INLINESITE_END:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+struct ScopeRecord {
+ ulittle32_t PtrParent;
+ ulittle32_t PtrEnd;
+};
+
+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);
+}
+
+static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
+ uint32_t CurOffset, ObjectFile *File) {
+ if (Stack.empty()) {
+ warn("symbol scopes are not balanced in " + File->getName());
+ return;
+ }
+ SymbolScope S = Stack.pop_back_val();
+ S.OpeningRecord->PtrEnd = CurOffset;
+}
+
static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
ArrayRef<TypeIndex> TypeIndexMap,
BinaryStreamRef SymData) {
@@ -184,6 +248,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
CVSymbolArray Syms;
BinaryStreamReader Reader(SymData);
ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+ SmallVector<SymbolScope, 4> Scopes;
for (const CVSymbol &Sym : Syms) {
// Discover type index references in the record. Skip it if we don't know
// where they are.
@@ -199,14 +264,17 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File,
// Re-map all the type index references.
MutableArrayRef<uint8_t> Contents =
NewData.drop_front(sizeof(RecordPrefix));
- if (!remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs))
- continue;
+ remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs);
- // FIXME: Fill in "Parent" and "End" fields by maintaining a stack of
- // scopes.
+ // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+ CVSymbol NewSym(Sym.kind(), NewData);
+ if (symbolOpensScope(Sym.kind()))
+ scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
+ else if (symbolEndsScope(Sym.kind()))
+ scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
// Add the symbol to the module.
- File->ModuleDBI->addSymbol(CVSymbol(Sym.kind(), NewData));
+ File->ModuleDBI->addSymbol(NewSym);
}
}
@@ -246,7 +314,9 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab,
bool InArchive = !File->ParentName.empty();
SmallString<128> Path = InArchive ? File->ParentName : File->getName();
sys::fs::make_absolute(Path);
+ sys::path::native(Path, llvm::sys::path::Style::windows);
StringRef Name = InArchive ? File->getName() : StringRef(Path);
+
File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
File->ModuleDBI->setObjFileName(Path);
@@ -325,9 +395,52 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab,
addTypeInfo(Builder.getIpiBuilder(), IDTable);
}
+static void addLinkerModuleSymbols(StringRef Path,
+ pdb::DbiModuleDescriptorBuilder &Mod,
+ BumpPtrAllocator &Allocator) {
+ codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb);
+ codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym);
+ codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym);
+ codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym);
+
+ ONS.Name = "* Linker *";
+ ONS.Signature = 0;
+
+ CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386;
+ CS.Flags = CompileSym3Flags::None;
+ CS.VersionBackendBuild = 0;
+ CS.VersionBackendMajor = 0;
+ CS.VersionBackendMinor = 0;
+ CS.VersionBackendQFE = 0;
+ CS.VersionFrontendBuild = 0;
+ CS.VersionFrontendMajor = 0;
+ CS.VersionFrontendMinor = 0;
+ CS.VersionFrontendQFE = 0;
+ CS.Version = "LLVM Linker";
+ CS.setLanguage(SourceLanguage::Link);
+
+ ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
+ std::string ArgStr = llvm::join(Args, " ");
+ EBS.Fields.push_back("cwd");
+ SmallString<64> cwd;
+ llvm::sys::fs::current_path(cwd);
+ EBS.Fields.push_back(cwd);
+ EBS.Fields.push_back("exe");
+ EBS.Fields.push_back(Config->Argv[0]);
+ EBS.Fields.push_back("pdb");
+ EBS.Fields.push_back(Path);
+ EBS.Fields.push_back("cmd");
+ EBS.Fields.push_back(ArgStr);
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ ONS, Allocator, CodeViewContainer::Pdb));
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ CS, Allocator, CodeViewContainer::Pdb));
+ Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol(
+ EBS, Allocator, CodeViewContainer::Pdb));
+}
+
// Creates a PDB file.
-void coff::createPDB(StringRef Path, SymbolTable *Symtab,
- ArrayRef<uint8_t> SectionTable,
+void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable,
const llvm::codeview::DebugInfo *DI) {
BumpPtrAllocator Alloc;
pdb::PDBFileBuilder Builder(Alloc);
@@ -342,22 +455,37 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
auto &InfoBuilder = Builder.getInfoBuilder();
InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
+ llvm::SmallString<128> NativePath(Config->PDBPath.begin(),
+ Config->PDBPath.end());
+ llvm::sys::fs::make_absolute(NativePath);
+ llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows);
+
pdb::PDB_UniqueId uuid{};
if (DI)
memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
InfoBuilder.setGuid(uuid);
- // Should be the current time, but set 0 for reproducibilty.
- InfoBuilder.setSignature(0);
+ InfoBuilder.setSignature(time(nullptr));
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
- // Add an empty DPI stream.
+ // Add an empty DBI stream.
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- DbiBuilder.setVersionHeader(pdb::PdbDbiV110);
+ DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
+ ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {}));
+
+ // It's not entirely clear what this is, but the * Linker * module uses it.
+ uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
TypeTableBuilder TypeTable(BAlloc);
TypeTableBuilder IDTable(BAlloc);
addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable);
+ // Add public and symbol records stream.
+
+ // For now we don't actually write any thing useful to the publics stream, but
+ // the act of "getting" it also creates it lazily so that we write an empty
+ // stream.
+ (void)Builder.getPublicsBuilder();
+
// Add Section Contributions.
addSectionContribs(Symtab, DbiBuilder);
@@ -369,12 +497,14 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
pdb::DbiStreamBuilder::createSectionMap(Sections);
DbiBuilder.setSectionMap(SectionMap);
- ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
+ auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
+ LinkerModule.setPdbFilePathNI(PdbFilePathNI);
+ addLinkerModuleSymbols(NativePath, LinkerModule, Alloc);
// Add COFF section header stream.
ExitOnErr(
DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
// Write to a file.
- ExitOnErr(Builder.commit(Path));
+ ExitOnErr(Builder.commit(Config->PDBPath));
}