diff --git a/src/DwarfReader.cpp b/src/DwarfReader.cpp index 8d53378..68860ca 100644 --- a/src/DwarfReader.cpp +++ b/src/DwarfReader.cpp @@ -9,9 +9,6 @@ using namespace std; using namespace dwarf; -typedef std::set > - dwarfpp_row_t; - DwarfReader::DwarfReader(const string& path): root(fileno(ifstream(path))) {} @@ -30,7 +27,7 @@ static void dump_expr(const core::FrameSection::register_def& reg) { fprintf(stderr, "\n"); } -SimpleDwarf DwarfReader::read() const { +SimpleDwarf DwarfReader::read() { const core::FrameSection& fs = root.get_frame_section(); SimpleDwarf output; @@ -42,57 +39,119 @@ SimpleDwarf DwarfReader::read() const { return output; } -SimpleDwarf::Fde DwarfReader::read_fde(const core::Fde& fde) const { +void DwarfReader::add_cell_to_row( + const dwarf::core::FrameSection::register_def& reg, + int reg_id, + int ra_reg, + SimpleDwarf::DwRow& cur_row) +{ + if(reg_id == DW_FRAME_CFA_COL3) { + cur_row.cfa = read_register(reg); + } + else { + try { + SimpleDwarf::MachineRegister reg_type = + from_dwarfpp_reg(reg_id, ra_reg); + switch(reg_type) { + case SimpleDwarf::REG_RBP: + cur_row.rbp = read_register(reg); + break; + case SimpleDwarf::REG_RBX: + cur_row.rbx = read_register(reg); + break; + case SimpleDwarf::REG_RA: + cur_row.ra = read_register(reg); + break; + default: + break; + } + } + catch(const UnsupportedRegister&) {} // Just ignore it. + } +} + +void DwarfReader::append_row_to_fde( + const dwarfpp_row_t& row, + uintptr_t row_addr, + int ra_reg, + SimpleDwarf::Fde& output) +{ + SimpleDwarf::DwRow cur_row; + + cur_row.ip = row_addr; + + for(const auto& cell: row) { + add_cell_to_row(cell.second, cell.first, ra_reg, cur_row); + } + + if(cur_row.cfa.type == SimpleDwarf::DwRegister::REG_UNDEFINED) + { + // Not set + throw InvalidDwarf(); + } + + output.rows.push_back(cur_row); +} + +template +static std::set > map_to_setpair( + const std::map& src_map) +{ + std::set > out; + for(const auto map_it: src_map) { + out.insert(map_it); + } + return out; +} + +void DwarfReader::append_results_to_fde( + const dwarf::core::FrameSection::instrs_results& results, + int ra_reg, + SimpleDwarf::Fde& output) +{ + for(const auto row_pair: results.rows) { + append_row_to_fde( + row_pair.second, + row_pair.first.lower(), + ra_reg, + output); + } + if(results.unfinished_row.size() > 0) { + try { + append_row_to_fde( + map_to_setpair(results.unfinished_row), + results.unfinished_row_addr, + ra_reg, + output); + } catch(const InvalidDwarf&) { + // Ignore: the unfinished_row can be undefined + } + } +} + +SimpleDwarf::Fde DwarfReader::read_fde(const core::Fde& fde) { SimpleDwarf::Fde output; output.fde_offset = fde.get_fde_offset(); output.beg_ip = fde.get_low_pc(); output.end_ip = fde.get_low_pc() + fde.get_func_length(); - auto rows = fde.decode().rows; const core::Cie& cie = *fde.find_cie(); int ra_reg = cie.get_return_address_register_rule(); - for(const auto row_pair: rows) { - SimpleDwarf::DwRow cur_row; + // CIE rows + core::FrameSection cie_fs(root.get_dbg(), true); + auto cie_rows = cie_fs.interpret_instructions( + cie, + fde.get_low_pc(), + cie.get_initial_instructions(), + cie.get_initial_instructions_length()); - cur_row.ip = row_pair.first.lower(); + // FDE rows + auto fde_rows = fde.decode(); - const dwarfpp_row_t& row = row_pair.second; - - for(const auto& cell: row) { - if(cell.first == DW_FRAME_CFA_COL3) { - cur_row.cfa = read_register(cell.second); - } - else { - try { - SimpleDwarf::MachineRegister reg_type = - from_dwarfpp_reg(cell.first, ra_reg); - switch(reg_type) { - case SimpleDwarf::REG_RBP: - cur_row.rbp = read_register(cell.second); - break; - case SimpleDwarf::REG_RBX: - cur_row.rbx = read_register(cell.second); - break; - case SimpleDwarf::REG_RA: - cur_row.ra = read_register(cell.second); - break; - default: - break; - } - } - catch(const UnsupportedRegister&) {} // Just ignore it. - } - } - - if(cur_row.cfa.type == SimpleDwarf::DwRegister::REG_UNDEFINED) - { - // Not set - throw InvalidDwarf(); - } - - output.rows.push_back(cur_row); - } + // instrs + append_results_to_fde(cie_rows, ra_reg, output); + append_results_to_fde(fde_rows, ra_reg, output); return output; } diff --git a/src/DwarfReader.hpp b/src/DwarfReader.hpp index 1c94f42..dafc471 100644 --- a/src/DwarfReader.hpp +++ b/src/DwarfReader.hpp @@ -13,6 +13,9 @@ #include "SimpleDwarf.hpp" +typedef std::set > + dwarfpp_row_t; + class DwarfReader { public: class InvalidDwarf: public std::exception {}; @@ -21,14 +24,31 @@ class DwarfReader { DwarfReader(const std::string& path); /** Actually read the ELF file, generating a `SimpleDwarf` output. */ - SimpleDwarf read() const; + SimpleDwarf read(); private: //meth - SimpleDwarf::Fde read_fde(const dwarf::core::Fde& fde) const; + SimpleDwarf::Fde read_fde(const dwarf::core::Fde& fde); + + void append_results_to_fde( + const dwarf::core::FrameSection::instrs_results& results, + int ra_reg, + SimpleDwarf::Fde& output); SimpleDwarf::DwRegister read_register( const dwarf::core::FrameSection::register_def& reg) const; + void add_cell_to_row( + const dwarf::core::FrameSection::register_def& reg, + int reg_id, + int ra_reg, + SimpleDwarf::DwRow& cur_row); + + void append_row_to_fde( + const dwarfpp_row_t& row, + uintptr_t row_addr, + int ra_reg, + SimpleDwarf::Fde& output); + SimpleDwarf::MachineRegister from_dwarfpp_reg( int reg_id, int ra_reg=-1 diff --git a/src/Makefile b/src/Makefile index d35476b..650c69b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,6 +14,7 @@ OBJS=\ PcHoleFiller.o \ EmptyFdeDeleter.o \ ConseqEquivFilter.o \ + OverriddenRowFilter.o \ SwitchStatement.o \ NativeSwitchCompiler.o \ FactoredSwitchCompiler.o \ diff --git a/src/OverriddenRowFilter.cpp b/src/OverriddenRowFilter.cpp new file mode 100644 index 0000000..f870f86 --- /dev/null +++ b/src/OverriddenRowFilter.cpp @@ -0,0 +1,31 @@ +#include "OverriddenRowFilter.hpp" + +OverriddenRowFilter::OverriddenRowFilter(bool enable) + : SimpleDwarfFilter(enable) +{} + +SimpleDwarf OverriddenRowFilter::do_apply(const SimpleDwarf& dw) const { + SimpleDwarf out; + + for(const auto& fde: dw.fde_list) { + out.fde_list.push_back(SimpleDwarf::Fde()); + SimpleDwarf::Fde& cur_fde = out.fde_list.back(); + cur_fde.fde_offset = fde.fde_offset; + cur_fde.beg_ip = fde.beg_ip; + cur_fde.end_ip = fde.end_ip; + + if(fde.rows.empty()) + continue; + + for(size_t pos=0; pos < fde.rows.size(); ++pos) { + const auto& row = fde.rows[pos]; + if(pos == fde.rows.size() - 1 + || row.ip != fde.rows[pos+1].ip) + { + cur_fde.rows.push_back(row); + } + } + } + + return out; +} diff --git a/src/OverriddenRowFilter.hpp b/src/OverriddenRowFilter.hpp new file mode 100644 index 0000000..cc152a9 --- /dev/null +++ b/src/OverriddenRowFilter.hpp @@ -0,0 +1,15 @@ +/** SimpleDwarfFilter to remove the first `n-1` rows of a block of `n` + * contiguous rows that have the exact same address. */ + +#pragma once + +#include "SimpleDwarf.hpp" +#include "SimpleDwarfFilter.hpp" + +class OverriddenRowFilter: public SimpleDwarfFilter { + public: + OverriddenRowFilter(bool enable=true); + + private: + SimpleDwarf do_apply(const SimpleDwarf& dw) const; +}; diff --git a/src/main.cpp b/src/main.cpp index a98c36b..9649eee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "PcHoleFiller.hpp" #include "EmptyFdeDeleter.hpp" #include "ConseqEquivFilter.hpp" +#include "OverriddenRowFilter.hpp" #include "settings.hpp" @@ -106,8 +107,9 @@ int main(int argc, char** argv) { SimpleDwarf filtered_dwarf = PcHoleFiller(!settings::keep_holes)( EmptyFdeDeleter()( + OverriddenRowFilter()( ConseqEquivFilter()( - parsed_dwarf))); + parsed_dwarf)))); FactoredSwitchCompiler* sw_compiler = new FactoredSwitchCompiler(1); CodeGenerator code_gen(