diff --git a/src/eh_elf/context_struct.h b/src/eh_elf/context_struct.h new file mode 100644 index 00000000..ae6ffeb9 --- /dev/null +++ b/src/eh_elf/context_struct.h @@ -0,0 +1,13 @@ +#include + +typedef struct { + uintptr_t rip, rsp, rbp; +} unwind_context_t; + +typedef uintptr_t (*deref_func_t)(uintptr_t); + +typedef unwind_context_t (*_fde_func_t)(unwind_context_t, uintptr_t); +typedef unwind_context_t (*_fde_func_with_deref_t)( + unwind_context_t, + uintptr_t, + deref_func_t); diff --git a/src/eh_elf/eh_elf.c b/src/eh_elf/eh_elf.c index b4129f9a..8e1b768c 100644 --- a/src/eh_elf/eh_elf.c +++ b/src/eh_elf/eh_elf.c @@ -13,6 +13,10 @@ ************************************************/ #include "eh_elf.h" +#include "context_struct.h" +#include "libunwind.h" +#include "memory_map.h" +#include "remote.h" int eh_elf_init_local() { return mmap_init_local(); @@ -26,7 +30,70 @@ void eh_elf_clear() { mmap_clear(); } -int eh_elf_step_cursor(struct cursor *cursor) { - // TODO implement - return 0; +static struct { + unw_addr_space_t addr_space; + unw_accessors_t *accessors; + void* arg; +} _fetch_state; + +static uintptr_t fetchw_here(uintptr_t addr) { + uintptr_t out; + fetchw(_fetch_state.addr_space, + _fetch_state.accessors, + &addr, + &out, + _fetch_state.arg); + return out; +} + +int eh_elf_step_cursor(struct cursor *cursor) { + uintptr_t ip = cursor->dwarf.ip; + + // Retrieve memory map entry + mmap_entry_t* mmap_entry = mmap_get_entry(ip); + if(mmap_entry == NULL) + return -1; + + // Retrieve a pointer to the eh_elf function + _fde_func_with_deref_t fde_func = + (_fde_func_t) (dlsym(mmap_entry->eh_elf, "_eh_elf")); + if(fde_func == NULL) + return -2; + + // Setup an eh_elf context + unwind_context_t eh_elf_context; + eh_elf_context.rip = ip; + eh_elf_context.rsp = cursor->dwarf.loc[UNW_TDEP_SP].val; + eh_elf_context.rbp = cursor->dwarf.loc[UNW_TDEP_BP].val; + + // Set _fetch_state before passing fetchw_here + _fetch_state.addr_space = cursor->dwarf.as; + _fetch_state.accessors = &cursor->dwarf.as->acc; + + // Call fde_func + eh_elf_context = fde_func( + eh_elf_context, + ip - mmap_entry->offset, + fetchw_here); + + // Check for the end of the call chain + if(eh_elf_context.rbp == 0 || eh_elf_context.rip + 1 == 0) + return 0; + + // Push back the data into libunwind's structures + for (int i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i) + cursor->dwarf.loc[i] = DWARF_NULL_LOC; + + cursor->dwarf.loc[UNW_TDEP_BP].val = eh_elf_context.rbp; + cursor->dwarf.loc[UNW_TDEP_SP].val = eh_elf_context.rsp; + cursor->dwarf.loc[UNW_TDEP_IP].val = eh_elf_context.rip; + cursor->dwarf.use_prev_instr = 1; + + cursor->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED; + cursor->frame_info.cfa_reg_rsp = 0; + cursor->frame_info.cfa_reg_offset = 16; + cursor->frame_info.rbp_cfa_offset = -16; + cursor->dwarf.cfa += 16; + + return 1; } diff --git a/src/eh_elf/eh_elf.h b/src/eh_elf/eh_elf.h index fa01398e..6c18230d 100644 --- a/src/eh_elf/eh_elf.h +++ b/src/eh_elf/eh_elf.h @@ -17,11 +17,6 @@ #include #include "libunwind_i.h" -/// Store the necessary data for a single eh_elf -typedef struct { - // TODO -} eh_elf_handle_t; - /** Initialize everything for local memory analysis * @return 0 on success, or a negative value upon failure **/ @@ -37,6 +32,7 @@ void eh_elf_clear(); /** Step the cursor using eh_elf mechanisms. * - * Return 0 if everything went fine, otherwise, return a negative value. + * @return a positive value upon success, 0 if the frame before this unwinding + * was the last one, or a negative value upon failure. **/ int eh_elf_step_cursor(struct cursor *cursor);