144 lines
4.1 KiB
C++
144 lines
4.1 KiB
C++
#include <DwarfInterpret.hpp>
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
#include <set>
|
|
|
|
#include <fileno.hpp>
|
|
#include <dwarfpp/lib.hpp>
|
|
#include <dwarfpp/regs.hpp>
|
|
#include <dwarfpp/frame.hpp>
|
|
#include <dwarfpp/attr.hpp>
|
|
#include <dwarfpp/frame.hpp>
|
|
#include <dwarfpp/root.hpp>
|
|
#include <gelf.h>
|
|
|
|
#include <ucontext.h>
|
|
|
|
#include "register_map.hpp"
|
|
|
|
using namespace std;
|
|
using namespace dwarf;
|
|
|
|
|
|
std::unique_ptr<DwarfInterpret> DwarfInterpret::instance(nullptr);
|
|
|
|
DwarfInterpret::DwarfInterpret(const std::string& elf_path)
|
|
: root_die(fileno(std::ifstream(elf_path)))
|
|
{
|
|
//std::ifstream file_in(elf_path);
|
|
//root_die = dwarf::core::root_die(fileno(file_in));
|
|
// FIXME this ^ deserves some checks. But this looks tedious.
|
|
|
|
GElf_Ehdr ehdr;
|
|
GElf_Ehdr *ret = gelf_getehdr(root_die.get_elf(), &ehdr);
|
|
assert(ret != 0);
|
|
elf_machine = ehdr.e_machine;
|
|
}
|
|
|
|
DwarfInterpret& DwarfInterpret::acquire() {
|
|
if(DwarfInterpret::instance == nullptr)
|
|
throw NotInstanciated();
|
|
return *(DwarfInterpret::instance);
|
|
}
|
|
|
|
DwarfInterpret& DwarfInterpret::instanciate(const std::string& elf_path) {
|
|
if(DwarfInterpret::instance != nullptr)
|
|
throw AlreadyInstanciated();
|
|
DwarfInterpret::instance = std::unique_ptr<DwarfInterpret>(
|
|
new DwarfInterpret(elf_path));
|
|
return *(DwarfInterpret::instance);
|
|
}
|
|
|
|
DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
|
|
const DwarfInterpret::DwarfRow& row,
|
|
const DwarfInterpret::DwarfRegister& reg
|
|
) const
|
|
{
|
|
switch(reg.k) {
|
|
case core::FrameSection::register_def::INDETERMINATE:
|
|
case core::FrameSection::register_def::UNDEFINED:
|
|
throw ValuelessRegister();
|
|
|
|
case core::FrameSection::register_def::REGISTER: {
|
|
ostringstream exprs;
|
|
int dwarf_regnum = reg.register_plus_offset_r().first;
|
|
assert(dwarf_regnum != DW_FRAME_CFA_COL3);
|
|
int cpu_regnum = REG_DWARF_TO_UCONTEXT[dwarf_regnum];
|
|
|
|
reg_content_t* cpu_content =
|
|
(reg_content_t*) get_cpu_register(cpu_regnum);
|
|
reg_content_t* addr =
|
|
cpu_content + reg.register_plus_offset_r().second;
|
|
|
|
return *addr;
|
|
} break;
|
|
|
|
case core::FrameSection::register_def::SAVED_AT_OFFSET_FROM_CFA: {
|
|
reg_content_t* cfa_loc =
|
|
(reg_content_t*) interpret_dw_register(row, DW_FRAME_CFA_COL3);
|
|
reg_content_t* addr = cfa_loc;
|
|
return *addr;
|
|
} break;
|
|
|
|
case core::FrameSection::register_def::SAVED_AT_EXPR:
|
|
throw NotImplemented();
|
|
break;
|
|
case core::FrameSection::register_def::VAL_IS_OFFSET_FROM_CFA:
|
|
case core::FrameSection::register_def::VAL_OF_EXPR:
|
|
default:
|
|
throw NotImplemented();
|
|
break;
|
|
}
|
|
}
|
|
|
|
DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
|
|
const DwarfInterpret::DwarfRow& row,
|
|
int reg_id
|
|
) const
|
|
{
|
|
return interpret_dw_register(row, get_column(row, reg_id));
|
|
}
|
|
|
|
template<typename Key>
|
|
static typename std::set<std::pair<int, Key> >::const_iterator find_column(
|
|
const std::set<std::pair<int, Key> >& set,
|
|
int key)
|
|
{
|
|
if(set.empty())
|
|
return set.end();
|
|
Key some_key_val = set.begin()->second;
|
|
auto it = set.upper_bound(make_pair(key - 1, some_key_val));
|
|
if(it == set.end())
|
|
return set.end();
|
|
while(it != set.end() && it->first != key)
|
|
++it;
|
|
if(it == set.end() || it->first != key)
|
|
return set.end();
|
|
return it;
|
|
}
|
|
|
|
DwarfInterpret::DwarfRegister DwarfInterpret::get_column(
|
|
const DwarfInterpret::DwarfRow& row,
|
|
int column
|
|
) const
|
|
{
|
|
auto it = find_column<DwarfRegister>(row, column);
|
|
if(it == row.end())
|
|
throw std::out_of_range("No such column");
|
|
return it->second;
|
|
}
|
|
|
|
DwarfInterpret::reg_content_t DwarfInterpret::get_cpu_register(
|
|
int reg_id) const
|
|
{
|
|
ucontext_t context;
|
|
if(getcontext(&context) != 0)
|
|
throw FailedGetContext();
|
|
|
|
// Let the user deal with reg_id correctness
|
|
return context.uc_mcontext.gregs[reg_id];
|
|
}
|