#include "DwarfReader.hpp" #include "plt_std_expr.hpp" #include #include #include using namespace std; using namespace dwarf; DwarfReader::DwarfReader(const string& path): root(fileno(ifstream(path))) {} // Debug function -- dumps an expression static void dump_expr(const core::FrameSection::register_def& reg) { assert(reg.k == core::FrameSection::register_def::SAVED_AT_EXPR || reg.k == core::FrameSection::register_def::VAL_OF_EXPR); const encap::loc_expr& expr = reg.saved_at_expr_r(); for(const auto& elt: expr) { fprintf(stderr, "(%02x, %02llx, %02llx, %02llx) :: ", elt.lr_atom, elt.lr_number, elt.lr_number2, elt.lr_offset); } fprintf(stderr, "\n"); } SimpleDwarf DwarfReader::read() { const core::FrameSection& fs = root.get_frame_section(); SimpleDwarf output; for(auto fde_it = fs.fde_begin(); fde_it != fs.fde_end(); ++fde_it) { SimpleDwarf::Fde parsed_fde = read_fde(*fde_it); output.fde_list.push_back(parsed_fde); } return output; } 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(); const core::Cie& cie = *fde.find_cie(); int ra_reg = cie.get_return_address_register_rule(); // 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()); // FDE rows auto fde_rows = fde.decode(); // instrs append_results_to_fde(cie_rows, ra_reg, output); append_results_to_fde(fde_rows, ra_reg, output); return output; } SimpleDwarf::DwRegister DwarfReader::read_register( const core::FrameSection::register_def& reg ) const { SimpleDwarf::DwRegister output; try { switch(reg.k) { case core::FrameSection::register_def::REGISTER: output.type = SimpleDwarf::DwRegister::REG_REGISTER; output.offset = reg.register_plus_offset_r().second; output.reg = from_dwarfpp_reg( reg.register_plus_offset_r().first); break; case core::FrameSection::register_def::SAVED_AT_OFFSET_FROM_CFA: output.type = SimpleDwarf::DwRegister::REG_CFA_OFFSET; output.offset = reg.saved_at_offset_from_cfa_r(); break; case core::FrameSection::register_def::INDETERMINATE: case core::FrameSection::register_def::UNDEFINED: output.type = SimpleDwarf::DwRegister::REG_UNDEFINED; break; case core::FrameSection::register_def::SAVED_AT_EXPR: if(is_plt_expr(reg)) output.type = SimpleDwarf::DwRegister::REG_PLT_EXPR; else if(!interpret_simple_expr(reg, output)) output.type = SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED; break; default: output.type = SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED; break; } } catch(const UnsupportedRegister& e) { output.type = SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED; } return output; } SimpleDwarf::MachineRegister DwarfReader::from_dwarfpp_reg( int reg_id, int ra_reg ) const { if(reg_id == ra_reg) return SimpleDwarf::REG_RA; switch(reg_id) { case lib::DWARF_X86_64_RIP: return SimpleDwarf::REG_RIP; case lib::DWARF_X86_64_RSP: return SimpleDwarf::REG_RSP; case lib::DWARF_X86_64_RBP: return SimpleDwarf::REG_RBP; case lib::DWARF_X86_64_RBX: return SimpleDwarf::REG_RBX; default: throw UnsupportedRegister(); } } static bool compare_dw_expr( const encap::loc_expr& e1, const encap::loc_expr& e2) { const std::vector& e1_vec = static_cast&>(e1); const std::vector& e2_vec = static_cast&>(e2); return e1_vec == e2_vec; } bool DwarfReader::is_plt_expr( const core::FrameSection::register_def& reg) const { if(reg.k != core::FrameSection::register_def::SAVED_AT_EXPR) return false; const encap::loc_expr& expr = reg.saved_at_expr_r(); bool res = compare_dw_expr(expr, REFERENCE_PLT_EXPR); return res; } bool DwarfReader::interpret_simple_expr( const dwarf::core::FrameSection::register_def& reg, SimpleDwarf::DwRegister& output ) const { bool deref = false; if(reg.k == core::FrameSection::register_def::SAVED_AT_EXPR) deref = true; else if(reg.k == core::FrameSection::register_def::VAL_OF_EXPR) deref = false; else return false; const encap::loc_expr& expr = reg.saved_at_expr_r(); if(expr.size() > 2 || expr.empty()) return false; const auto& exp_reg = expr[0]; if(0x70 <= exp_reg.lr_atom && exp_reg.lr_atom <= 0x8f) { // DW_OP_breg int reg_id = exp_reg.lr_atom - 0x70; try { output.reg = from_dwarfpp_reg(reg_id, -1); // Cannot be CFA anyway output.offset = exp_reg.lr_number; } catch(const UnsupportedRegister& /* exn */) { return false; // Unsupported register } } if(expr.size() == 2) { // OK if deref if(expr[1].lr_atom == 0x06) { // deref if(deref) return false; deref = true; } else return false; } if(deref) return false; // TODO try stats? Mabye it's worth implementing output.type = SimpleDwarf::DwRegister::REG_REGISTER; return true; }