[BOLT][DWARF] Move line info emission into BOLT

Summary:
BOLT needs to generate line info tables using absolute addresses as well
as using the standard MC way of labels attached to instructions. Move
line table generation code under BOLT.

Ideally, we should be able to extend existing interfaces in LLVM, but
without other users of the interface it will be hard to justify the
change.

(cherry picked from FBD30723466)
This commit is contained in:
Maksim Panchenko 2021-09-01 21:40:54 -07:00
parent ba1f503f1b
commit d4a0e8526a
6 changed files with 330 additions and 25 deletions

View File

@ -1396,6 +1396,16 @@ void BinaryContext::printGlobalSymbols(raw_ostream& OS) const {
} }
} }
Expected<unsigned>
BinaryContext::getDwarfFile(StringRef Directory, StringRef FileName,
unsigned FileNumber,
Optional<MD5::MD5Result> Checksum,
Optional<StringRef> Source, unsigned CUID) {
DwarfLineTable &Table = DwarfLineTablesCUMap[CUID];
return Table.tryGetFile(Directory, FileName, Checksum, Source,
Ctx->getDwarfVersion(), FileNumber);
}
unsigned BinaryContext::addDebugFilenameToUnit(const uint32_t DestCUID, unsigned BinaryContext::addDebugFilenameToUnit(const uint32_t DestCUID,
const uint32_t SrcCUID, const uint32_t SrcCUID,
unsigned FileIndex) { unsigned FileIndex) {
@ -1421,7 +1431,7 @@ unsigned BinaryContext::addDebugFilenameToUnit(const uint32_t DestCUID,
dwarf::toString(FileNames[FileIndex - 1].Name)) dwarf::toString(FileNames[FileIndex - 1].Name))
FileName = *FName; FileName = *FName;
assert(FileName != ""); assert(FileName != "");
return cantFail(Ctx->getDwarfFile(Dir, FileName, 0, None, None, DestCUID)); return cantFail(getDwarfFile(Dir, FileName, 0, None, None, DestCUID));
} }
std::vector<BinaryFunction *> BinaryContext::getSortedFunctions() { std::vector<BinaryFunction *> BinaryContext::getSortedFunctions() {
@ -1545,12 +1555,12 @@ void BinaryContext::preprocessDebugInfo() {
LineTable->Prologue.FileNames; LineTable->Prologue.FileNames;
// Assign a unique label to every line table, one per CU. // Assign a unique label to every line table, one per CU.
Ctx->getMCDwarfLineTable(CUID).setLabel( getDwarfLineTable(CUID).setLabel(Ctx->getOrCreateSymbol(
Ctx->getOrCreateSymbol(GlobalPrefix + "line_table_start" + Twine(CUID))); GlobalPrefix + "line_table_start" + Twine(CUID)));
// Make sure empty debug line tables are registered too. // Make sure empty debug line tables are registered too.
if (FileNames.empty()) { if (FileNames.empty()) {
cantFail(Ctx->getDwarfFile("", "<unknown>", 0, None, None, CUID)); cantFail(getDwarfFile("", "<unknown>", 0, None, None, CUID));
continue; continue;
} }
for (size_t I = 0, Size = FileNames.size(); I != Size; ++I) { for (size_t I = 0, Size = FileNames.size(); I != Size; ++I) {
@ -1566,7 +1576,7 @@ void BinaryContext::preprocessDebugInfo() {
if (Optional<const char *> FName = dwarf::toString(FileNames[I].Name)) if (Optional<const char *> FName = dwarf::toString(FileNames[I].Name))
FileName = *FName; FileName = *FName;
assert(FileName != ""); assert(FileName != "");
cantFail(Ctx->getDwarfFile(Dir, FileName, 0, None, None, CUID)); cantFail(getDwarfFile(Dir, FileName, 0, None, None, CUID));
} }
} }

View File

@ -28,6 +28,7 @@
#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h" #include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCObjectWriter.h"
@ -207,6 +208,9 @@ class BinaryContext {
/// Preprocess DWO debug information. /// Preprocess DWO debug information.
void preprocessDWODebugInfo(); void preprocessDWODebugInfo();
/// DWARF line info for CUs.
std::map<unsigned, DwarfLineTable> DwarfLineTablesCUMap;
public: public:
static std::unique_ptr<BinaryContext> static std::unique_ptr<BinaryContext>
createBinaryContext(const ObjectFile *File, bool IsPIC, createBinaryContext(const ObjectFile *File, bool IsPIC,
@ -221,6 +225,19 @@ public:
/// Get Number of DWOCUs in a map. /// Get Number of DWOCUs in a map.
uint32_t getNumDWOCUs() { return DWOCUs.size(); } uint32_t getNumDWOCUs() { return DWOCUs.size(); }
const std::map<unsigned, DwarfLineTable> &getDwarfLineTables() const {
return DwarfLineTablesCUMap;
}
DwarfLineTable &getDwarfLineTable(unsigned CUID) {
return DwarfLineTablesCUMap[CUID];
}
Expected<unsigned> getDwarfFile(StringRef Directory, StringRef FileName,
unsigned FileNumber,
Optional<MD5::MD5Result> Checksum,
Optional<StringRef> Source, unsigned CUID);
/// [start memory address] -> [segment info] mapping. /// [start memory address] -> [segment info] mapping.
std::map<uint64_t, SegmentInfo> SegmentMapInfo; std::map<uint64_t, SegmentInfo> SegmentMapInfo;

View File

@ -210,8 +210,10 @@ void BinaryEmitter::emitAll(StringRef OrgSecPrefix) {
emitFunctions(); emitFunctions();
if (opts::UpdateDebugSections) if (opts::UpdateDebugSections) {
emitDebugLineInfoForOriginalFunctions(); emitDebugLineInfoForOriginalFunctions();
DwarfLineTable::emit(BC, Streamer);
}
emitDataSections(OrgSecPrefix); emitDataSections(OrgSecPrefix);
@ -654,7 +656,16 @@ SMLoc BinaryEmitter::emitLineInfo(const BinaryFunction &BF, SMLoc NewLoc,
Flags, Flags,
CurrentRow.Isa, CurrentRow.Isa,
CurrentRow.Discriminator); CurrentRow.Discriminator);
BC.Ctx->setDwarfCompileUnitID(FunctionUnitIndex); const MCDwarfLoc &DwarfLoc = BC.Ctx->getCurrentDwarfLoc();
BC.Ctx->clearDwarfLocSeen();
MCSymbol *LineSym = BC.Ctx->createTempSymbol();
Streamer.emitLabel(LineSym);
BC.getDwarfLineTable(FunctionUnitIndex)
.getMCLineSections()
.addLineEntry(MCDwarfLineEntry(LineSym, DwarfLoc),
Streamer.getCurrentSectionOnly());
return NewLoc; return NewLoc;
} }
@ -1010,34 +1021,30 @@ void BinaryEmitter::emitDebugLineInfoForOriginalFunctions() {
uint64_t Address = It.first; uint64_t Address = It.first;
if (LineTable->lookupAddressRange({Address, 0}, Function.getMaxSize(), if (LineTable->lookupAddressRange({Address, 0}, Function.getMaxSize(),
Results)) { Results)) {
MCLineSection &OutputLineTable = BinaryLineSection &OutputLineTable =
BC.Ctx->getMCDwarfLineTable(Unit->getOffset()).getMCLineSections(); BC.getDwarfLineTable(Unit->getOffset()).getBinaryLineSections();
for (uint32_t RowIndex : Results) { for (uint32_t RowIndex : Results) {
const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex];
BC.Ctx->setCurrentDwarfLoc( BC.Ctx->setCurrentDwarfLoc(
Row.File, Row.File, Row.Line, Row.Column,
Row.Line,
Row.Column,
(DWARF2_FLAG_IS_STMT * Row.IsStmt) | (DWARF2_FLAG_IS_STMT * Row.IsStmt) |
(DWARF2_FLAG_BASIC_BLOCK * Row.BasicBlock) | (DWARF2_FLAG_BASIC_BLOCK * Row.BasicBlock) |
(DWARF2_FLAG_PROLOGUE_END * Row.PrologueEnd) | (DWARF2_FLAG_PROLOGUE_END * Row.PrologueEnd) |
(DWARF2_FLAG_EPILOGUE_BEGIN * Row.EpilogueBegin), (DWARF2_FLAG_EPILOGUE_BEGIN * Row.EpilogueBegin),
Row.Isa, Row.Isa, Row.Discriminator);
Row.Discriminator,
Row.Address.Address);
MCDwarfLoc Loc = BC.Ctx->getCurrentDwarfLoc(); MCDwarfLoc Loc = BC.Ctx->getCurrentDwarfLoc();
BC.Ctx->clearDwarfLocSeen(); BC.Ctx->clearDwarfLocSeen();
OutputLineTable.addLineEntry(MCDwarfLineEntry{nullptr, Loc}, OutputLineTable.addLineEntry(
FunctionSection); BinaryDwarfLineEntry{Row.Address.Address, Loc}, FunctionSection);
} }
// Add an empty entry past the end of the function // Add an empty entry past the end of the function
// for end_sequence mark. // for end_sequence mark.
BC.Ctx->setCurrentDwarfLoc(0, 0, 0, 0, 0, 0, BC.Ctx->setCurrentDwarfLoc(0, 0, 0, 0, 0, 0);
Address + Function.getMaxSize());
MCDwarfLoc Loc = BC.Ctx->getCurrentDwarfLoc(); MCDwarfLoc Loc = BC.Ctx->getCurrentDwarfLoc();
BC.Ctx->clearDwarfLocSeen(); BC.Ctx->clearDwarfLocSeen();
OutputLineTable.addLineEntry(MCDwarfLineEntry{nullptr, Loc}, OutputLineTable.addLineEntry(
FunctionSection); BinaryDwarfLineEntry{Address + Function.getMaxSize(), Loc},
FunctionSection);
} else { } else {
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: function " << Function LLVM_DEBUG(dbgs() << "BOLT-DEBUG: function " << Function
<< " has no associated line number information\n"); << " has no associated line number information\n");

View File

@ -705,7 +705,7 @@ void DWARFRewriter::updateLineTableOffsets() {
for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) { for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
const unsigned CUID = CU->getOffset(); const unsigned CUID = CU->getOffset();
MCSymbol *Label = BC.Ctx->getMCDwarfLineTable(CUID).getLabel(); MCSymbol *Label = BC.getDwarfLineTable(CUID).getLabel();
if (!Label) if (!Label)
continue; continue;

View File

@ -12,6 +12,7 @@
#include "BinaryBasicBlock.h" #include "BinaryBasicBlock.h"
#include "BinaryFunction.h" #include "BinaryFunction.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbol.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/EndianStream.h" #include "llvm/Support/EndianStream.h"
@ -522,5 +523,204 @@ std::unique_ptr<DebugBufferVector> DebugAbbrevWriter::finalize() {
return std::make_unique<DebugBufferVector>(ReturnBuffer); return std::make_unique<DebugBufferVector>(ReturnBuffer);
} }
static void emitDwarfSetLineAddrAbs(MCStreamer &OS,
MCDwarfLineTableParams Params,
int64_t LineDelta, uint64_t Address,
int PointerSize) {
// emit the sequence to set the address
OS.emitIntValue(dwarf::DW_LNS_extended_op, 1);
OS.emitULEB128IntValue(PointerSize + 1);
OS.emitIntValue(dwarf::DW_LNE_set_address, 1);
OS.emitIntValue(Address, PointerSize);
// emit the sequence for the LineDelta (from 1) and a zero address delta.
MCDwarfLineAddr::Emit(&OS, Params, LineDelta, 0);
}
static inline void emitBinaryDwarfLineTable(
MCStreamer *MCOS, MCDwarfLineTableParams Params,
const BinaryLineSection::BinaryDwarfLineEntryCollection &LineEntries) {
unsigned FileNum = 1;
unsigned LastLine = 1;
unsigned Column = 0;
unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
unsigned Isa = 0;
unsigned Discriminator = 0;
uint64_t LastAddress = -1ULL;
const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo();
// Loop through each line entry and encode the dwarf line number table.
for (auto It = LineEntries.begin(), Ie = LineEntries.end(); It != Ie; ++It) {
const BinaryDwarfLineEntry &LineEntry = *It;
int64_t LineDelta = static_cast<int64_t>(LineEntry.getLine()) - LastLine;
const uint64_t Address = LineEntry.getAddress();
if (std::next(It) == Ie) {
// If emitting absolute addresses, the last entry only carries address
// info for the DW_LNE_end_sequence. This entry compensates for the lack
// of the section context used to emit the end of section label.
MCDwarfLineAddr::Emit(MCOS, Params, INT64_MAX, Address - LastAddress);
return;
}
if (FileNum != LineEntry.getFileNum()) {
FileNum = LineEntry.getFileNum();
MCOS->emitInt8(dwarf::DW_LNS_set_file);
MCOS->emitULEB128IntValue(FileNum);
}
if (Column != LineEntry.getColumn()) {
Column = LineEntry.getColumn();
MCOS->emitInt8(dwarf::DW_LNS_set_column);
MCOS->emitULEB128IntValue(Column);
}
if (Discriminator != LineEntry.getDiscriminator() &&
MCOS->getContext().getDwarfVersion() >= 4) {
Discriminator = LineEntry.getDiscriminator();
unsigned Size = getULEB128Size(Discriminator);
MCOS->emitInt8(dwarf::DW_LNS_extended_op);
MCOS->emitULEB128IntValue(Size + 1);
MCOS->emitInt8(dwarf::DW_LNE_set_discriminator);
MCOS->emitULEB128IntValue(Discriminator);
}
if (Isa != LineEntry.getIsa()) {
Isa = LineEntry.getIsa();
MCOS->emitInt8(dwarf::DW_LNS_set_isa);
MCOS->emitULEB128IntValue(Isa);
}
if ((LineEntry.getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) {
Flags = LineEntry.getFlags();
MCOS->emitInt8(dwarf::DW_LNS_negate_stmt);
}
if (LineEntry.getFlags() & DWARF2_FLAG_BASIC_BLOCK)
MCOS->emitInt8(dwarf::DW_LNS_set_basic_block);
if (LineEntry.getFlags() & DWARF2_FLAG_PROLOGUE_END)
MCOS->emitInt8(dwarf::DW_LNS_set_prologue_end);
if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN)
MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin);
if (LastAddress == -1ULL) {
emitDwarfSetLineAddrAbs(*MCOS, Params, LineDelta, Address,
AsmInfo->getCodePointerSize());
} else {
MCDwarfLineAddr::Emit(MCOS, Params, LineDelta, Address - LastAddress);
}
LastAddress = Address;
Discriminator = 0;
LastLine = LineEntry.getLine();
}
}
static inline void emitDwarfLineTable(
MCStreamer *MCOS, MCSection *Section,
const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
unsigned FileNum = 1;
unsigned LastLine = 1;
unsigned Column = 0;
unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
unsigned Isa = 0;
unsigned Discriminator = 0;
MCSymbol *LastLabel = nullptr;
const MCAsmInfo *AsmInfo = MCOS->getContext().getAsmInfo();
// Loop through each MCDwarfLineEntry and encode the dwarf line number table.
for (const MCDwarfLineEntry &LineEntry : LineEntries) {
int64_t LineDelta = static_cast<int64_t>(LineEntry.getLine()) - LastLine;
if (FileNum != LineEntry.getFileNum()) {
FileNum = LineEntry.getFileNum();
MCOS->emitInt8(dwarf::DW_LNS_set_file);
MCOS->emitULEB128IntValue(FileNum);
}
if (Column != LineEntry.getColumn()) {
Column = LineEntry.getColumn();
MCOS->emitInt8(dwarf::DW_LNS_set_column);
MCOS->emitULEB128IntValue(Column);
}
if (Discriminator != LineEntry.getDiscriminator() &&
MCOS->getContext().getDwarfVersion() >= 4) {
Discriminator = LineEntry.getDiscriminator();
unsigned Size = getULEB128Size(Discriminator);
MCOS->emitInt8(dwarf::DW_LNS_extended_op);
MCOS->emitULEB128IntValue(Size + 1);
MCOS->emitInt8(dwarf::DW_LNE_set_discriminator);
MCOS->emitULEB128IntValue(Discriminator);
}
if (Isa != LineEntry.getIsa()) {
Isa = LineEntry.getIsa();
MCOS->emitInt8(dwarf::DW_LNS_set_isa);
MCOS->emitULEB128IntValue(Isa);
}
if ((LineEntry.getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) {
Flags = LineEntry.getFlags();
MCOS->emitInt8(dwarf::DW_LNS_negate_stmt);
}
if (LineEntry.getFlags() & DWARF2_FLAG_BASIC_BLOCK)
MCOS->emitInt8(dwarf::DW_LNS_set_basic_block);
if (LineEntry.getFlags() & DWARF2_FLAG_PROLOGUE_END)
MCOS->emitInt8(dwarf::DW_LNS_set_prologue_end);
if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN)
MCOS->emitInt8(dwarf::DW_LNS_set_epilogue_begin);
MCSymbol *Label = LineEntry.getLabel();
// At this point we want to emit/create the sequence to encode the delta
// in line numbers and the increment of the address from the previous
// Label and the current Label.
MCOS->emitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label,
AsmInfo->getCodePointerSize());
Discriminator = 0;
LastLine = LineEntry.getLine();
LastLabel = Label;
}
// Generate DWARF line end entry.
MCOS->emitDwarfLineEndEntry(Section, LastLabel);
}
void DwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
Optional<MCDwarfLineStr> &LineStr) const {
MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second;
// Put out the line tables.
for (const auto &LineSec : MCLineSections.getMCLineEntries())
emitDwarfLineTable(MCOS, LineSec.first, LineSec.second);
// Emit line tables for the original code.
for (const auto &LineSec : BinaryLineSections.getBinaryLineEntries())
emitBinaryDwarfLineTable(MCOS, Params, LineSec.second);
// This is the end of the section, so set the value of the symbol at the end
// of this section (that was used in a previous expression).
MCOS->emitLabel(LineEndSym);
}
void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) {
MCAssembler &Assembler =
static_cast<MCObjectStreamer *>(&Streamer)->getAssembler();
MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams();
auto &LineTables = BC.getDwarfLineTables();
// Bail out early so we don't switch to the debug_line section needlessly and
// in doing so create an unnecessary (if empty) section.
if (LineTables.empty())
return;
// In a v5 non-split line table, put the strings in a separate section.
Optional<MCDwarfLineStr> LineStr(None);
if (BC.Ctx->getDwarfVersion() >= 5)
LineStr = MCDwarfLineStr(*BC.Ctx);
// Switch to the section where the table will be emitted into.
Streamer.SwitchSection(BC.MOFI->getDwarfLineSection());
// Handle the rest of the Compile Units.
for (auto &CUIDTablePair : LineTables) {
CUIDTablePair.second.emitCU(&Streamer, Params, LineStr);
}
}
} // namespace bolt } // namespace bolt
} // namespace llvm } // namespace llvm

View File

@ -15,6 +15,7 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/Support/SMLoc.h" #include "llvm/Support/SMLoc.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <cstdint> #include <cstdint>
@ -497,6 +498,76 @@ public:
} }
}; };
/// Similar to MCDwarfLineEntry, but identifies the location by its address
/// instead of MCLabel.
class BinaryDwarfLineEntry : public MCDwarfLoc {
uint64_t Address;
public:
// Constructor to create an BinaryDwarfLineEntry given a symbol and the dwarf
// loc.
BinaryDwarfLineEntry(uint64_t Address, const MCDwarfLoc loc)
: MCDwarfLoc(loc), Address(Address) {}
uint64_t getAddress() const { return Address; }
};
/// Similar to MCLineSection, store line entries per CU but use absolute
/// addresses for line locations.
class BinaryLineSection {
public:
// Add an entry to this MCLineSection's line entries.
void addLineEntry(const BinaryDwarfLineEntry &LineEntry, MCSection *Sec) {
BinaryLineDivisions[Sec].push_back(LineEntry);
}
using BinaryDwarfLineEntryCollection = std::vector<BinaryDwarfLineEntry>;
using BinaryLineDivisionMap =
MapVector<MCSection *, BinaryDwarfLineEntryCollection>;
private:
// A collection of BinaryDwarfLineEntry for each section.
BinaryLineDivisionMap BinaryLineDivisions;
public:
// Returns the collection of BinaryDwarfLineEntry for a given Compile Unit ID.
const BinaryLineDivisionMap &getBinaryLineEntries() const {
return BinaryLineDivisions;
}
};
/// Line number information for all parts of the binary.
class DwarfLineTable {
MCDwarfLineTableHeader Header;
MCLineSection MCLineSections;
BinaryLineSection BinaryLineSections;
public:
/// Emit line info for all units in the binary context.
static void emit(BinaryContext &BC, MCStreamer &Streamer);
// Emit the Dwarf file and the line tables for a given CU.
void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
Optional<MCDwarfLineStr> &LineStr) const;
Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
Optional<MD5::MD5Result> Checksum,
Optional<StringRef> Source,
uint16_t DwarfVersion,
unsigned FileNumber = 0) {
return Header.tryGetFile(Directory, FileName, Checksum, Source,
DwarfVersion, FileNumber);
}
MCSymbol *getLabel() const { return Header.Label; }
void setLabel(MCSymbol *Label) { Header.Label = Label; }
MCLineSection &getMCLineSections() { return MCLineSections; }
BinaryLineSection &getBinaryLineSections() { return BinaryLineSections; }
};
} // namespace bolt } // namespace bolt
} // namespace llvm } // namespace llvm