Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions tpde-llvm/src/LLVMCompilerBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "tpde/Assembler.hpp"
#include "tpde/CompilerBase.hpp"
#include "tpde/DwarfLineWriter.hpp"
#include "tpde/ValLocalIdx.hpp"
#include "tpde/ValueAssignment.hpp"
#include "tpde/base.hpp"
Expand Down Expand Up @@ -169,6 +170,8 @@ struct LLVMCompilerBase : public LLVMCompiler,

tpde::util::SmallVector<std::pair<IRValueRef, SymRef>, 16> type_info_syms;

std::unique_ptr<tpde::DwarfLineWriter> dw_line_writer;

enum class LibFunc {
divti3,
udivti3,
Expand Down Expand Up @@ -335,6 +338,66 @@ struct LLVMCompilerBase : public LLVMCompiler,
}

public:
/// Record a debug location at the current PC
void record_debug_location(llvm::DebugLoc debug_loc) {
if (!dw_line_writer || !debug_loc) {
return;
}

const u32 current_pc = this->text_writer.offset();
// Avoid emitting duplicate locations for the same PC, which can happen
// when multiple instructions share the same debug location.
if (dw_line_writer->offset_equals_last_offset(current_pc)) {
return;
}

const llvm::DILocation *di_loc = debug_loc.get();
const u32 line = di_loc->getLine();
// Line number 0 is used to indicate an unknown location, so skip it.
if (line == 0) {
return;
}

dw_line_writer->push_location(
current_pc,
tpde::DebugLocation{
.file_name = di_loc->getFilename(),
.directory = di_loc->getDirectory(),
.line = di_loc->getLine(),
.column = static_cast<u16>(di_loc->getColumn()),
});
}

void set_current_debug_location_function(const IRFuncRef func) {
if (!dw_line_writer) {
return;
}

const u32 current_pc = this->text_writer.offset();
if (const llvm::DISubprogram *sp = func->getSubprogram()) {
dw_line_writer->push_location(
current_pc,
tpde::DebugLocation{
.file_name = sp->getFilename(),
.directory = sp->getDirectory(),
.line = sp->getLine(),
.column = 0u,
});
dw_line_writer->set_subprogram_written();
}
}

void finish_debug_location_function(const IRFuncRef, const u32 func_idx) {
if (!dw_line_writer) {
return;
}

const u32 sym_id = this->func_syms[func_idx].id();
const auto it = this->func_sym_id_to_skew.find(sym_id);
const u32 skew = (it != this->func_sym_id_to_skew.end()) ? it->second : 0u;
dw_line_writer->end_function(skew);
}

/// Whether to use a DSO-local access instead of going through the GOT.
static bool use_local_access(const llvm::GlobalValue *gv) {
// If the symbol is preemptible, don't generate a local access.
Expand Down Expand Up @@ -1250,6 +1313,11 @@ bool LLVMCompilerBase<Adaptor, Derived, Config>::compile(llvm::Module &mod) {
group_secs.clear();
libfunc_syms.fill({});

if (mod.getNamedMetadata("llvm.dbg.cu") != nullptr) {
const tpde::DwarfConfig cfg(Config::MIN_INST_WIDTH);
dw_line_writer = std::make_unique<tpde::DwarfLineWriter>(cfg);
}

if (!Base::compile()) {
return false;
}
Expand All @@ -1270,6 +1338,12 @@ bool LLVMCompilerBase<Adaptor, Derived, Config>::compile(llvm::Module &mod) {
this->assembler.sym_copy(dst_sym, from_sym);
}

// Write DWARF 5 line information if enabled and the module has debug info.
if (dw_line_writer) {
llvm::TimeTraceScope time_scope("TPDE_DebugLine_Write");
dw_line_writer->finalize(this->assembler);
}

return true;
}

Expand Down Expand Up @@ -1366,6 +1440,9 @@ bool LLVMCompilerBase<Adaptor, Derived, Config>::compile_inst(
return res;
}();

// Record debug location before instruction
record_debug_location(i->getDebugLoc());

const ValInfo &val_info = this->adaptor->val_info(i);
assert(i->getOpcode() < fns.size());
const auto [compile_fn, arg] = fns[i->getOpcode()];
Expand Down
2 changes: 2 additions & 0 deletions tpde/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ target_sources(tpde PRIVATE
src/Assembler.cpp
src/AssemblerElf.cpp
src/base.cpp
src/DwarfLineWriter.cpp
src/ElfMapper.cpp
src/FunctionWriter.cpp
src/StringTable.cpp
Expand All @@ -52,6 +53,7 @@ target_sources(tpde PRIVATE
include/tpde/CompilerBase.hpp
include/tpde/CompilerConfig.hpp
include/tpde/DWARF.hpp
include/tpde/DwarfLineWriter.hpp
include/tpde/ELF.hpp
include/tpde/ElfMapper.hpp
include/tpde/FunctionWriter.hpp
Expand Down
21 changes: 12 additions & 9 deletions tpde/include/tpde/Assembler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,18 @@ struct Relocation {

/// Section kinds, lowered to file-format specific flags.
enum class SectionKind : u8 {
Text, ///< Text section, executable code (ELF .text)
ReadOnly, ///< Read-only data section (ELF .rodata)
EHFrame, ///< EH Frame section (ELF .eh_frame)
LSDA, ///< LSDA section (ELF .gcc_except_table)
Data, ///< Writable data section (ELF .data)
DataRelRO, ///< Read-only data section with relocations (ELF .data.rel.ro)
BSS, ///< Zero-initialized data section (ELF .bss)
ThreadData, ///< Initialized thread-local data section (ELF .tdata)
ThreadBSS, ///< Zero-initialized thread-local data section (ELF .tbss)
Text, ///< Text section, executable code (ELF .text)
ReadOnly, ///< Read-only data section (ELF .rodata)
EHFrame, ///< EH Frame section (ELF .eh_frame)
LSDA, ///< LSDA section (ELF .gcc_except_table)
Data, ///< Writable data section (ELF .data)
DataRelRO, ///< Read-only data section with relocations (ELF .data.rel.ro)
BSS, ///< Zero-initialized data section (ELF .bss)
ThreadData, ///< Initialized thread-local data section (ELF .tdata)
ThreadBSS, ///< Zero-initialized thread-local data section (ELF .tbss)
DebugInfo, ///< DWARF debug info (ELF .debug_info)
DebugLine, ///< DWARF line information (ELF .debug_line)
DebugAbbrev, ///< DWARF abbreviations (ELF .debug_abbrev)

Max
};
Expand Down
9 changes: 9 additions & 0 deletions tpde/include/tpde/CompilerBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ struct CompilerBase {
// allocations
util::SmallVector<Label> block_labels;

std::unordered_map<u32, u32> func_sym_id_to_skew; // Map SymRef.id() to address skew

util::SmallVector<std::pair<SymRef, SymRef>, 4> personality_syms = {};

struct ScratchReg;
Expand Down Expand Up @@ -578,6 +580,10 @@ struct CompilerBase {

void analysis_end() {}

void set_current_debug_location_function(const IRFuncRef) {}

void finish_debug_location_function(const IRFuncRef, const u32) {}

void reloc_text(SymRef sym, u32 type, u64 offset, i64 addend = 0) {
this->assembler.reloc_sec(
text_writer.get_sec_ref(), sym, type, offset, addend);
Expand Down Expand Up @@ -2315,6 +2321,8 @@ bool CompilerBase<Adaptor, Derived, Config>::compile_func(const IRFuncRef func,

derived()->start_func(func_idx);

derived()->set_current_debug_location_function(func);

block_labels.clear();
block_labels.resize_uninitialized(analyzer.block_layout.size());
for (u32 i = 0; i < analyzer.block_layout.size(); ++i) {
Expand Down Expand Up @@ -2403,6 +2411,7 @@ bool CompilerBase<Adaptor, Derived, Config>::compile_func(const IRFuncRef func,
"found non-freed ValueAssignment, maybe missing ref-count?");

derived()->finish_func(func_idx);
derived()->finish_debug_location_function(func, func_idx);
this->text_writer.finish_func();

return true;
Expand Down
2 changes: 2 additions & 0 deletions tpde/include/tpde/CompilerConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ concept CompilerConfig = requires {
{ T::PLATFORM_POINTER_SIZE } -> SameBaseAs<u32>;
{ T::NUM_BANKS } -> SameBaseAs<u32>;
{ T::DEFAULT_VAR_REF_HANDLING } -> SameBaseAs<bool>;
{ T::MIN_INST_WIDTH } -> SameBaseAs<u8>;

typename T::DefaultCCAssigner;
requires std::derived_from<typename T::DefaultCCAssigner, CCAssigner>;
Expand All @@ -33,6 +34,7 @@ concept CompilerConfig = requires {

struct CompilerConfigDefault {
constexpr static bool DEFAULT_VAR_REF_HANDLING = true;
constexpr static u8 MIN_INST_WIDTH = 1;
};

} // namespace tpde
39 changes: 39 additions & 0 deletions tpde/include/tpde/DWARF.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,45 @@ constexpr u8 DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;

constexpr u32 EH_FDE_FUNC_START_OFF = 0x8;

constexpr u8 DW_LNS_extended_op = 0;
constexpr u8 DW_LNS_copy = 1;
constexpr u8 DW_LNS_advance_pc = 2;
constexpr u8 DW_LNS_advance_line = 3;
constexpr u8 DW_LNS_set_file = 4;
constexpr u8 DW_LNS_set_column = 5;
constexpr u8 DW_LNS_negate_stmt = 6;
constexpr u8 DW_LNS_set_basic_block = 7;
constexpr u8 DW_LNS_const_add_pc = 8;
constexpr u8 DW_LNS_fixed_advance_pc = 9;
constexpr u8 DW_LNS_set_prologue_end = 10;
constexpr u8 DW_LNS_set_epilogue_begin = 11;
constexpr u8 DW_LNS_set_isa = 12;

constexpr u8 DW_LNE_end_sequence = 1;
constexpr u8 DW_LNE_set_address = 2;
constexpr u8 DW_LNE_define_file = 3;
constexpr u8 DW_LNE_set_discriminator = 4;

constexpr u8 DW_TAG_compile_unit = 17;

constexpr u8 DW_AT_stmt_list = 16;
constexpr u8 DW_AT_low_pc = 17;
constexpr u8 DW_AT_high_pc = 18;

constexpr u8 DW_FORM_addr = 1;
constexpr u8 DW_FORM_string = 8;
constexpr u8 DW_FORM_udata = 0x0f;
constexpr u8 DW_FORM_sec_offset = 23;

// DWARF 5 line content type codes
constexpr u8 DW_LNCT_path = 1;
constexpr u8 DW_LNCT_directory_index = 2;

// DWARF 5 unit type codes
constexpr u8 DW_UT_compile = 0x01;

constexpr u8 DW_CHILDREN_no = 0;

namespace x64 {
constexpr u8 DW_reg_rax = 0;
constexpr u8 DW_reg_rdx = 1;
Expand Down
Loading