1
0
Fork 0
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:
Théophile Bastian 2018-06-11 19:53:29 +02:00
parent 07e6a1a96f
commit 1493c0ca4b
9 changed files with 152 additions and 15 deletions

View file

@ -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;

View file

@ -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:

View file

@ -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();
}

View file

@ -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();

View file

@ -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;

View file

@ -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.

View file

@ -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
}
}
};

View file

@ -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)