Make context acquisition behave correctly wrt. calling site

It now actually returns the context at the call site of the function,
instead of somewhere inside DwarfInterpret
This commit is contained in:
Théophile Bastian 2018-04-06 16:26:24 +02:00
parent 18d3655890
commit c4895ed0d1
4 changed files with 30 additions and 72 deletions

View file

@ -141,16 +141,6 @@ class DwarfInterpret {
const UnwindContext& ctx
) const;
/** Get the return address at a given program counter, assuming the
* correct registers are stored */
uintptr_t get_return_address(uintptr_t cur_pc) const;
/** Get the return address of the current program point */
uintptr_t get_self_return_address() const;
/// Get the current program counter
static uintptr_t get_current_pc();
/// Get the current UnwindContext (from the caller's point of view)
static UnwindContext get_current_unwind_context();
@ -161,15 +151,12 @@ class DwarfInterpret {
DwarfInterpret(const MemoryMap::MapEntry& memory_object);
DwarfRegister get_column(const DwarfRow& row, int column) const;
reg_content_t get_cpu_register(int reg_id) const;
const dwarf::core::FrameSection::fde_iterator fde_at(
uintptr_t pc) const;
const dwarf::core::FrameSection::cie_iterator cie_at(
uintptr_t pc) const;
uintptr_t get_caller_pc() const;
/** Get the #DwarfInterpret instance responsible for the given PC, or
* nullptr if the current instance is responsible. */
DwarfInterpret* get_responsible_instance(uintptr_t pc) const;

View file

@ -24,6 +24,15 @@ using namespace std;
using namespace dwarf;
#define get_cpu_register(reg_id, dest) {\
ucontext_t context; \
if(getcontext(&context) != 0) \
throw DwarfInterpret::FailedGetContext(); \
(dest) = context.uc_mcontext.gregs[(reg_id)]; \
}
MemoryMap DwarfInterpret::memory_map;
map<int, unique_ptr<DwarfInterpret> > DwarfInterpret::instances;
@ -179,53 +188,18 @@ DwarfInterpret::reg_content_t DwarfInterpret::interpret_dw_register(
return interpret_dw_register(row, get_column(row, reg_id), ctx);
}
uintptr_t DwarfInterpret::get_return_address(uintptr_t cur_pc) const {
DwarfInterpret* responsible = get_responsible_instance(cur_pc);
if(responsible != nullptr)
return responsible->get_return_address(cur_pc);
const core::Cie& cie = *cie_at(cur_pc);
const DwarfRow& row = dwarf_row_at(cur_pc);
UnwindContext ctx = get_current_unwind_context();
// FIXME ^^^ ugly patch, this should not be a thing
uintptr_t translated_ra =
interpret_dw_register(row,
cie.get_return_address_register_rule(),
ctx);
cerr << "Return address from 0x" << hex << cur_pc << ": "
<< "0x" << translated_ra << endl;
return translated_ra;
}
uintptr_t DwarfInterpret::get_self_return_address() const {
// Aaaaand now we have to get_return_address thrice.
return get_return_address(get_caller_pc());
}
uintptr_t DwarfInterpret::get_current_pc() {
// Assumes the PC is stored in REG_RIP **AND** the PC we want is this
// function's return address
DwarfInterpret& dw = DwarfInterpret::acquire();
reg_content_t pc_here = dw.get_cpu_register(REG_RIP);
fprintf(stderr, "PC=%p <inside>\n", pc_here);
fprintf(stderr, "actual PC=%p <inside>\n", __builtin_return_address(0));
return dw.get_return_address(pc_here);
}
DwarfInterpret::UnwindContext DwarfInterpret::get_current_unwind_context() {
// FIXME for now this returns SOME unwind context (actually, the unwind
// context snapshot naively taken from inside this function). Unwinding
// it some number of times should yield the expected context
uintptr_t rsp = DwarfInterpret::acquire().get_cpu_register(REG_RSP);
uintptr_t rsp;
get_cpu_register(REG_RSP, rsp);
UnwindContext ctx(StackDump::snapshot(rsp));
DwarfInterpret& dw = DwarfInterpret::acquire();
ctx.rip = dw.get_cpu_register(REG_RIP);
get_cpu_register(REG_RIP, ctx.rip);
ctx.rsp = rsp;
ctx.rbp = dw.get_cpu_register(REG_RBP);
get_cpu_register(REG_RBP, ctx.rbp);
cerr << "CREATING CONTEXT. %rsp=0x" << hex
<< ctx.rsp
@ -233,7 +207,9 @@ DwarfInterpret::UnwindContext DwarfInterpret::get_current_unwind_context() {
<< ", %rip=0x" << ctx.rip
<< dec << endl;
return ctx;
DwarfInterpret& dw = DwarfInterpret::acquire(ctx.rip);
return dw.unwind_context(ctx);
}
DwarfInterpret::UnwindContext DwarfInterpret::unwind_context(
@ -269,13 +245,6 @@ DwarfInterpret::UnwindContext DwarfInterpret::unwind_context(
return new_context;
}
uintptr_t DwarfInterpret::get_caller_pc() const {
// We assume we want the PC of the caller of the calling function. This
// means we have to unwind twice. `get_current_pc` unwinds once.
return get_return_address(DwarfInterpret::get_current_pc());
}
template<typename Key>
static typename std::set<std::pair<int, Key> >::const_iterator find_column(
const std::set<std::pair<int, Key> >& set,
@ -305,17 +274,6 @@ DwarfInterpret::DwarfRegister DwarfInterpret::get_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];
}
const core::FrameSection::fde_iterator DwarfInterpret::fde_at(
uintptr_t pc
) const

View file

@ -13,8 +13,13 @@ all: $(TARGET)
%.bin: %.o
$(CXX) $(CXXFLAGS) $(CXXDIRS) $(CXXLIBS) $< -o "$@"
dump_my_stack.bin: dump_my_stack.o
$(CXX) $(CXXFLAGS) $(CXXDIRS) $(CXXLIBS) -ldl -rdynamic $< -o "$@"
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(CXXDIRS) -c "$<" -o "$@"
.PRECIOUS: %.o
clean:
rm -f $(OBJS) $(TARGET)

View file

@ -1,4 +1,5 @@
#include <cstdio>
#include <dlfcn.h>
#include <DwarfInterpret.hpp>
using namespace std;
@ -13,12 +14,19 @@ void dump_my_stack() {
MemoryMap mmap;
while(true) {
Dl_info dl_inf;
int dl_rc = dladdr((void *) unw_context.rip, &dl_inf);
printf(">> PC = %lX ", unw_context.rip);
MemoryMap::MapEntry cur_map_entry =
mmap[mmap.id_of_address(unw_context.rip)];
uintptr_t inelf_pc = unw_context.rip
- cur_map_entry.mem_region.begin + cur_map_entry.offset;
printf("(in ELF: %lX) <<\n", inelf_pc);
printf("(in ELF: 0x%lX, func %s, path %s) <<\n",
inelf_pc,
(dl_rc && dl_inf.dli_sname) ? dl_inf.dli_sname : "(no symbol)",
cur_map_entry.pathname.c_str());
fflush(stdout);
unw_context = dw.unwind_context(unw_context);
}