mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-12-22 19:43:42 +01:00
Add memory_map direct providing method
Allow to give the memory map directly through the accessors, in case this is more handy than providing a PID for some reason (cf. perf integration)
This commit is contained in:
parent
07e6a1a96f
commit
1493c0ca4b
9 changed files with 152 additions and 15 deletions
|
@ -138,6 +138,37 @@ typedef struct unw_proc_info
|
|||
}
|
||||
unw_proc_info_t;
|
||||
|
||||
/// A structure containing the informations gathererd about a line in the
|
||||
/// memory map
|
||||
typedef struct {
|
||||
uintptr_t offset; ///< Total offset: ip + offset = ip in original ELF file
|
||||
char* object_name; ///< Name of the object mapped here
|
||||
uintptr_t beg_ip, end_ip; ///< Start and end IP of this object in memory
|
||||
} unw_mmap_entry_t;
|
||||
|
||||
typedef enum {
|
||||
UNW_EH_ELF_INIT_PID, ///< Use PID to init eh_elf
|
||||
UNW_EH_ELF_INIT_MMAP, ///< Directly provide a memory map yourself
|
||||
} unw_eh_elf_init_mode;
|
||||
|
||||
/** This structure is passed among the accessors, and contains what's needed to
|
||||
* init eh_elf unwinding. */
|
||||
struct unw_eh_elf_init_acc {
|
||||
unw_eh_elf_init_mode init_mode;
|
||||
union {
|
||||
/// Provide this with UNW_EH_ELF_INIT_PID.
|
||||
/// int get_pid(void* arg) returns the process' PID
|
||||
int (*get_pid) (void *);
|
||||
|
||||
/// Provide this with UNW_EH_ELF_INIT_MMAP
|
||||
void (*get_mmap)
|
||||
(unw_mmap_entry_t**, ///< An array of mmap_entries
|
||||
size_t*, ///< number of entries
|
||||
void* ///< `arg`
|
||||
);
|
||||
} init_data;
|
||||
};
|
||||
|
||||
/* These are backend callback routines that provide access to the
|
||||
state of a "remote" process. This can be used, for example, to
|
||||
unwind another process through the ptrace() interface. */
|
||||
|
@ -181,10 +212,8 @@ typedef struct unw_accessors
|
|||
int (*get_proc_name) (unw_addr_space_t, unw_word_t, char *, size_t,
|
||||
unw_word_t *, void *);
|
||||
|
||||
/* Retrieve the PID of the process this memory belongs to.
|
||||
Returns 0 for local memory or when undefined.
|
||||
This must be non-zero for init_remote. */
|
||||
int (*get_pid) (void *);
|
||||
/* A substructure of accessors used to init eh_elf unwinding. */
|
||||
struct unw_eh_elf_init_acc eh_elf_init;
|
||||
}
|
||||
unw_accessors_t;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ libunwind_ptrace_la_SOURCES = \
|
|||
ptrace/_UPT_find_proc_info.c ptrace/_UPT_get_dyn_info_list_addr.c \
|
||||
ptrace/_UPT_put_unwind_info.c ptrace/_UPT_get_proc_name.c \
|
||||
ptrace/_UPT_reg_offset.c ptrace/_UPT_resume.c \
|
||||
ptrace/_UPT_get_pid.c
|
||||
ptrace/_UPT_eh_elf_init.c
|
||||
noinst_HEADERS += ptrace/_UPT_internal.h
|
||||
|
||||
### libunwind-coredump:
|
||||
|
|
|
@ -23,9 +23,15 @@ int eh_elf_init_local() {
|
|||
}
|
||||
|
||||
int eh_elf_init_pid(pid_t pid) {
|
||||
Debug(3, "Init with pid\n");
|
||||
return mmap_init_pid(pid);
|
||||
}
|
||||
|
||||
int eh_elf_init_mmap(unw_mmap_entry_t* entries, size_t count) {
|
||||
Debug(3, "Init with mmap\n");
|
||||
return mmap_init_mmap(entries, count);
|
||||
}
|
||||
|
||||
void eh_elf_clear() {
|
||||
mmap_clear();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ int eh_elf_init_local();
|
|||
**/
|
||||
int eh_elf_init_pid(pid_t pid);
|
||||
|
||||
/** Initialize everything with the provided memory map
|
||||
* @return 0 on success, or a negative value upon failure
|
||||
**/
|
||||
int eh_elf_init_mmap(unw_mmap_entry_t* entries, size_t count);
|
||||
|
||||
/// Cleanup everything that was allocated by eh_elf_init_*
|
||||
void eh_elf_clear();
|
||||
|
||||
|
|
|
@ -13,6 +13,13 @@ static int _mmap_init_done = 0;
|
|||
/// Init the memory map with a given /proc/XX/ argument
|
||||
int mmap_init_procdir(const char* procdir);
|
||||
|
||||
/// Reorder the entries in `entries` by increasing (non-overlapping)
|
||||
/// memory region
|
||||
static int mmap_order_entries(mmap_entry_t* entries, size_t count);
|
||||
|
||||
/// `dlopen`s the corresponding eh_elf for each entry in `entries`.
|
||||
static int mmap_dlopen_eh_elfs(mmap_entry_t* entries, size_t count);
|
||||
|
||||
|
||||
static int compare_mmap_entry(const void* _e1, const void* _e2) {
|
||||
// We can't return e1->beg_ip - e2->beg_ip because of int overflows
|
||||
|
@ -101,22 +108,82 @@ int mmap_init_procdir(const char* procdir) {
|
|||
realloc(_memory_map, _memory_map_size * sizeof(mmap_entry_t));
|
||||
|
||||
// Ensure the entries are sorted by ascending ip range
|
||||
qsort(_memory_map, _memory_map_size, sizeof(mmap_entry_t),
|
||||
compare_mmap_entry);
|
||||
if(mmap_order_entries(_memory_map, _memory_map_size) < 0)
|
||||
return -3;
|
||||
|
||||
// dlopen corresponding eh_elf objects
|
||||
for(size_t id = 0; id < _memory_map_size; ++id) {
|
||||
char eh_elf_path[256];
|
||||
char* obj_basename = basename(_memory_map[id].object_name);
|
||||
sprintf(eh_elf_path, "%s.eh_elf.so", obj_basename);
|
||||
_memory_map[id].eh_elf = dlopen(eh_elf_path, RTLD_LAZY);
|
||||
}
|
||||
if(mmap_dlopen_eh_elfs(_memory_map, _memory_map_size) < 0)
|
||||
return -4;
|
||||
|
||||
_mmap_init_done = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmap_init_mmap(unw_mmap_entry_t* entries, size_t count) {
|
||||
Debug(3, "Start reading mmap (entries=%016lx)\n", (uintptr_t)entries);
|
||||
Debug(3, "%lu entries\n", count);
|
||||
_memory_map = (mmap_entry_t*) calloc(count, sizeof(mmap_entry_t));
|
||||
_memory_map_size = count;
|
||||
|
||||
int mmap_pos = 0;
|
||||
for(int pos=0; pos < (int)count; ++pos) {
|
||||
Debug(3, "> MMAP %016lx-%016lx %s\n",
|
||||
entries[pos].beg_ip,
|
||||
entries[pos].end_ip,
|
||||
entries[pos].object_name);
|
||||
|
||||
if(entries[pos].object_name[0] == '[') {
|
||||
// Special entry (stack,vdso, …)
|
||||
continue;
|
||||
}
|
||||
|
||||
_memory_map[mmap_pos].id = pos;
|
||||
_memory_map[mmap_pos].offset = entries[pos].offset;
|
||||
_memory_map[mmap_pos].beg_ip = entries[pos].beg_ip;
|
||||
_memory_map[mmap_pos].end_ip = entries[pos].end_ip;
|
||||
_memory_map[mmap_pos].object_name =
|
||||
malloc(strlen(entries[pos].object_name) + 1);
|
||||
strcpy(_memory_map[mmap_pos].object_name, entries[pos].object_name);
|
||||
|
||||
++mmap_pos;
|
||||
}
|
||||
|
||||
// Shrink memory map
|
||||
_memory_map_size = mmap_pos;
|
||||
_memory_map = (mmap_entry_t*)
|
||||
realloc(_memory_map, _memory_map_size * sizeof(mmap_entry_t));
|
||||
|
||||
if(mmap_order_entries(_memory_map, _memory_map_size) < 0)
|
||||
return -3;
|
||||
if(mmap_dlopen_eh_elfs(_memory_map, _memory_map_size) < 0)
|
||||
return -4;
|
||||
Debug(3, "Init complete");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Ensure entries in the memory map are ordered by ascending beg_ip
|
||||
static int mmap_order_entries(mmap_entry_t* entries, size_t count) {
|
||||
qsort(entries, count, sizeof(mmap_entry_t),
|
||||
compare_mmap_entry);
|
||||
for(size_t pos = 0; pos < count; ++pos)
|
||||
entries[pos].id = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// `dlopen` the needed eh_elf objects.
|
||||
static int mmap_dlopen_eh_elfs(mmap_entry_t* entries, size_t count) {
|
||||
for(size_t id = 0; id < count; ++id) {
|
||||
char eh_elf_path[256];
|
||||
char* obj_basename = basename(entries[id].object_name);
|
||||
sprintf(eh_elf_path, "%s.eh_elf.so", obj_basename);
|
||||
entries[id].eh_elf = dlopen(eh_elf_path, RTLD_LAZY);
|
||||
if(entries[id].eh_elf == NULL)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mmap_clear() {
|
||||
_mmap_init_done = 0;
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "libunwind.h"
|
||||
|
||||
/// A type representing a dlopen handle
|
||||
typedef void* dl_obj_t;
|
||||
|
||||
|
@ -44,6 +46,11 @@ int mmap_init_local();
|
|||
**/
|
||||
int mmap_init_pid(pid_t pid);
|
||||
|
||||
/** Init the memory map from a provided memory map
|
||||
* @returns 0 upon success, or a negative value upon failure.
|
||||
**/
|
||||
int mmap_init_mmap(unw_mmap_entry_t* entries, size_t count);
|
||||
|
||||
/** Get the `mmap_entry_t` corresponding to the given IP
|
||||
* @return a pointer to the corresponding memory map entry, or NULL upon
|
||||
* failure.
|
||||
|
|
|
@ -35,5 +35,10 @@ PROTECTED unw_accessors_t _UPT_accessors =
|
|||
.access_fpreg = _UPT_access_fpreg,
|
||||
.resume = _UPT_resume,
|
||||
.get_proc_name = _UPT_get_proc_name,
|
||||
.get_pid = _UPT_get_pid
|
||||
.eh_elf_init = {
|
||||
.init_mode = UNW_EH_ELF_INIT_PID,
|
||||
.init_data = {
|
||||
.get_pid = _UPT_get_pid
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -36,13 +36,31 @@ unw_init_remote (unw_cursor_t *cursor, unw_addr_space_t as, void *as_arg)
|
|||
return -UNW_EINVAL;
|
||||
#else /* !UNW_LOCAL_ONLY */
|
||||
struct cursor *c = (struct cursor *) cursor;
|
||||
int ret;
|
||||
struct unw_eh_elf_init_acc* eh_elf_acc = &as->acc.eh_elf_init;
|
||||
|
||||
if (!tdep_init_done)
|
||||
tdep_init ();
|
||||
|
||||
Debug (1, "(cursor=%p)\n", c);
|
||||
|
||||
eh_elf_init_pid(as->acc.get_pid(as_arg));
|
||||
switch(eh_elf_acc->init_mode) {
|
||||
case UNW_EH_ELF_INIT_PID:
|
||||
ret = eh_elf_init_pid(eh_elf_acc->init_data.get_pid(as_arg));
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case UNW_EH_ELF_INIT_MMAP: {
|
||||
unw_mmap_entry_t* entries;
|
||||
size_t entries_count;
|
||||
eh_elf_acc->init_data.get_mmap(&entries, &entries_count, as_arg);
|
||||
ret = eh_elf_init_mmap(entries, entries_count);
|
||||
free(entries);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c->dwarf.as = as;
|
||||
if (as == unw_local_addr_space)
|
||||
|
|
Loading…
Reference in a new issue