mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-11 05:35:11 +00:00
[llvm-pdbutil] Dump first section contribution for each module.
The DBI stream contains a list of module descriptors. At the beginning of each descriptor is a structure representing the first section contribution in the output file for that module. LLD currently doesn't fill out this structure at all, but link.exe does. So as a precursor to emitting this data in LLD, we first need a way to dump it so that it can be checked. This patch adds support for the dumping, and verifies via a test that LLD emits bogus information. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@330208 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
de9490f767
commit
8995c860d6
@ -47,6 +47,8 @@ public:
|
||||
|
||||
uint32_t getRecordLength() const;
|
||||
|
||||
const SectionContrib &getSectionContrib() const;
|
||||
|
||||
private:
|
||||
StringRef ModuleName;
|
||||
StringRef ObjFileName;
|
||||
|
@ -177,18 +177,6 @@ struct DbiStreamHeader {
|
||||
};
|
||||
static_assert(sizeof(DbiStreamHeader) == 64, "Invalid DbiStreamHeader size!");
|
||||
|
||||
struct SectionContribEntry {
|
||||
support::ulittle16_t Section;
|
||||
char Padding1[2];
|
||||
support::little32_t Offset;
|
||||
support::little32_t Size;
|
||||
support::ulittle32_t Characteristics;
|
||||
support::ulittle16_t ModuleIndex;
|
||||
char Padding2[2];
|
||||
support::ulittle32_t DataCrc;
|
||||
support::ulittle32_t RelocCrc;
|
||||
};
|
||||
|
||||
/// The header preceeding the File Info Substream of the DBI stream.
|
||||
struct FileInfoSubstreamHeader {
|
||||
/// Total # of modules, should match number of records in the ModuleInfo
|
||||
@ -230,7 +218,7 @@ struct ModuleInfoHeader {
|
||||
support::ulittle32_t Mod;
|
||||
|
||||
/// First section contribution of this module.
|
||||
SectionContribEntry SC;
|
||||
SectionContrib SC;
|
||||
|
||||
/// See ModInfoFlags definition.
|
||||
support::ulittle16_t Flags;
|
||||
|
@ -49,6 +49,10 @@ uint16_t DbiModuleDescriptor::getTypeServerIndex() const {
|
||||
ModInfoFlags::TypeServerIndexShift;
|
||||
}
|
||||
|
||||
const SectionContrib &DbiModuleDescriptor::getSectionContrib() const {
|
||||
return Layout->SC;
|
||||
}
|
||||
|
||||
uint16_t DbiModuleDescriptor::getModuleStreamIndex() const {
|
||||
return Layout->ModDiStream;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::finalize() {
|
||||
Layout.SC.ModuleIndex = Layout.Mod;
|
||||
Layout.SC.Imod = Layout.Mod;
|
||||
Layout.FileNameOffs = 0; // TODO: Fix this
|
||||
Layout.Flags = 0; // TODO: Fix this
|
||||
Layout.C11Bytes = 0;
|
||||
|
@ -65,10 +65,15 @@ ALL-NEXT: 134 | '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = '
|
||||
ALL: Modules
|
||||
ALL-NEXT: ============================================================
|
||||
ALL-NEXT: Mod 0000 | `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`:
|
||||
ALL-NEXT: SC[.text] | mod = 0, 0001:0016, size = 10, data crc = 3617027124, reloc crc = 0
|
||||
ALL-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
|
||||
ALL-NEXT: IMAGE_SCN_MEM_READ
|
||||
ALL-NEXT: Obj: `d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj`:
|
||||
ALL-NEXT: debug stream: 12, # files: 1, has ec info: false
|
||||
ALL-NEXT: pdb file ni: 0 ``, src file ni: 0 ``
|
||||
ALL-NEXT: Mod 0001 | `* Linker *`:
|
||||
ALL-NEXT: SC[.text] | mod = 1, 0001:0000, size = 10, data crc = 0, reloc crc = 0
|
||||
ALL-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
|
||||
ALL-NEXT: Obj: ``:
|
||||
ALL-NEXT: debug stream: 14, # files: 0, has ec info: false
|
||||
ALL-NEXT: pdb file ni: 1 `{{.*empty.pdb}}`, src file ni: 0 ``
|
||||
|
@ -440,6 +440,86 @@ static void iterateModuleSubsections(
|
||||
});
|
||||
}
|
||||
|
||||
static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
|
||||
ArrayRef<llvm::object::coff_section>>>
|
||||
loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
|
||||
if (!File.hasPDBDbiStream())
|
||||
return make_error<StringError>(
|
||||
"Section headers require a DBI Stream, which could not be loaded",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
auto &Dbi = cantFail(File.getPDBDbiStream());
|
||||
uint32_t SI = Dbi.getDebugStreamIndex(Type);
|
||||
|
||||
if (SI == kInvalidStreamIndex)
|
||||
return make_error<StringError>(
|
||||
"PDB does not contain the requested image section header type",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
auto Stream = File.createIndexedStream(SI);
|
||||
if (!Stream)
|
||||
return make_error<StringError>("Could not load the required stream data",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
ArrayRef<object::coff_section> Headers;
|
||||
if (Stream->getLength() % sizeof(object::coff_section) != 0)
|
||||
return make_error<StringError>(
|
||||
"Section header array size is not a multiple of section header size",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
|
||||
BinaryStreamReader Reader(*Stream);
|
||||
cantFail(Reader.readArray(Headers, NumHeaders));
|
||||
return std::make_pair(std::move(Stream), Headers);
|
||||
}
|
||||
|
||||
static std::vector<std::string> getSectionNames(PDBFile &File) {
|
||||
auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
|
||||
if (!ExpectedHeaders)
|
||||
return {};
|
||||
|
||||
std::unique_ptr<MappedBlockStream> Stream;
|
||||
ArrayRef<object::coff_section> Headers;
|
||||
std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
|
||||
std::vector<std::string> Names;
|
||||
for (const auto &H : Headers)
|
||||
Names.push_back(H.Name);
|
||||
return Names;
|
||||
}
|
||||
|
||||
static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC,
|
||||
ArrayRef<std::string> SectionNames,
|
||||
uint32_t FieldWidth) {
|
||||
std::string NameInsert;
|
||||
if (SC.ISect > 0 && SC.ISect < SectionNames.size()) {
|
||||
StringRef SectionName = SectionNames[SC.ISect - 1];
|
||||
NameInsert = formatv("[{0}]", SectionName).str();
|
||||
} else
|
||||
NameInsert = "[???]";
|
||||
P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
|
||||
"crc = {4}",
|
||||
formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
|
||||
fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
|
||||
fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2));
|
||||
AutoIndent Indent(P, FieldWidth + 2);
|
||||
P.formatLine(" {0}",
|
||||
formatSectionCharacteristics(P.getIndentLevel() + 6,
|
||||
SC.Characteristics, 3, " | "));
|
||||
}
|
||||
|
||||
static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC,
|
||||
ArrayRef<std::string> SectionNames,
|
||||
uint32_t FieldWidth) {
|
||||
P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
|
||||
"crc = {4}, coff section = {5}",
|
||||
formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
|
||||
fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc),
|
||||
fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff));
|
||||
P.formatLine(" {0}",
|
||||
formatSectionCharacteristics(P.getIndentLevel() + 6,
|
||||
SC.Base.Characteristics, 3, " | "));
|
||||
}
|
||||
|
||||
Error DumpOutputStyle::dumpModules() {
|
||||
printHeader(P, "Modules");
|
||||
AutoIndent Indent(P);
|
||||
@ -462,6 +542,10 @@ Error DumpOutputStyle::dumpModules() {
|
||||
iterateSymbolGroups(
|
||||
File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) {
|
||||
auto Desc = Modules.getModuleDescriptor(Modi);
|
||||
if (opts::dump::DumpSectionContribs) {
|
||||
std::vector<std::string> Sections = getSectionNames(getPdb());
|
||||
dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0);
|
||||
}
|
||||
P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
|
||||
P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
|
||||
Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
|
||||
@ -1435,39 +1519,6 @@ Error DumpOutputStyle::dumpSectionHeaders() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
|
||||
ArrayRef<llvm::object::coff_section>>>
|
||||
loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
|
||||
if (!File.hasPDBDbiStream())
|
||||
return make_error<StringError>(
|
||||
"Section headers require a DBI Stream, which could not be loaded",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
auto &Dbi = cantFail(File.getPDBDbiStream());
|
||||
uint32_t SI = Dbi.getDebugStreamIndex(Type);
|
||||
|
||||
if (SI == kInvalidStreamIndex)
|
||||
return make_error<StringError>(
|
||||
"PDB does not contain the requested image section header type",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
auto Stream = File.createIndexedStream(SI);
|
||||
if (!Stream)
|
||||
return make_error<StringError>("Could not load the required stream data",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
ArrayRef<object::coff_section> Headers;
|
||||
if (Stream->getLength() % sizeof(object::coff_section) != 0)
|
||||
return make_error<StringError>(
|
||||
"Section header array size is not a multiple of section header size",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
|
||||
BinaryStreamReader Reader(*Stream);
|
||||
cantFail(Reader.readArray(Headers, NumHeaders));
|
||||
return std::make_pair(std::move(Stream), Headers);
|
||||
}
|
||||
|
||||
void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
|
||||
printHeader(P, Label);
|
||||
|
||||
@ -1514,20 +1565,6 @@ void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> getSectionNames(PDBFile &File) {
|
||||
auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
|
||||
if (!ExpectedHeaders)
|
||||
return {};
|
||||
|
||||
std::unique_ptr<MappedBlockStream> Stream;
|
||||
ArrayRef<object::coff_section> Headers;
|
||||
std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
|
||||
std::vector<std::string> Names;
|
||||
for (const auto &H : Headers)
|
||||
Names.push_back(H.Name);
|
||||
return Names;
|
||||
}
|
||||
|
||||
Error DumpOutputStyle::dumpSectionContribs() {
|
||||
printHeader(P, "Section Contributions");
|
||||
|
||||
@ -1556,33 +1593,10 @@ Error DumpOutputStyle::dumpSectionContribs() {
|
||||
MaxNameLen = (Max == Names.end() ? 0 : Max->size());
|
||||
}
|
||||
void visit(const SectionContrib &SC) override {
|
||||
assert(SC.ISect > 0);
|
||||
std::string NameInsert;
|
||||
if (SC.ISect < Names.size()) {
|
||||
StringRef SectionName = Names[SC.ISect - 1];
|
||||
NameInsert = formatv("[{0}]", SectionName).str();
|
||||
} else
|
||||
NameInsert = "[???]";
|
||||
P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
|
||||
"crc = {4}",
|
||||
formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
|
||||
fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
|
||||
fmt_align(NameInsert, AlignStyle::Left, MaxNameLen + 2));
|
||||
AutoIndent Indent(P, MaxNameLen + 2);
|
||||
P.formatLine(" {0}",
|
||||
formatSectionCharacteristics(P.getIndentLevel() + 6,
|
||||
SC.Characteristics, 3, " | "));
|
||||
dumpSectionContrib(P, SC, Names, MaxNameLen);
|
||||
}
|
||||
void visit(const SectionContrib2 &SC) override {
|
||||
P.formatLine(
|
||||
"SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
|
||||
"crc = {4}, coff section = {5}",
|
||||
formatSegmentOffset(SC.Base.ISect, SC.Base.Off), fmtle(SC.Base.Size),
|
||||
fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
|
||||
fmtle(SC.ISectCoff));
|
||||
P.formatLine(" {0}", formatSectionCharacteristics(
|
||||
P.getIndentLevel() + 6,
|
||||
SC.Base.Characteristics, 3, " | "));
|
||||
dumpSectionContrib(P, SC, Names, MaxNameLen);
|
||||
}
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user