mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-01-09 19:03:43 +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;
|
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
|
/* These are backend callback routines that provide access to the
|
||||||
state of a "remote" process. This can be used, for example, to
|
state of a "remote" process. This can be used, for example, to
|
||||||
unwind another process through the ptrace() interface. */
|
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,
|
int (*get_proc_name) (unw_addr_space_t, unw_word_t, char *, size_t,
|
||||||
unw_word_t *, void *);
|
unw_word_t *, void *);
|
||||||
|
|
||||||
/* Retrieve the PID of the process this memory belongs to.
|
/* A substructure of accessors used to init eh_elf unwinding. */
|
||||||
Returns 0 for local memory or when undefined.
|
struct unw_eh_elf_init_acc eh_elf_init;
|
||||||
This must be non-zero for init_remote. */
|
|
||||||
int (*get_pid) (void *);
|
|
||||||
}
|
}
|
||||||
unw_accessors_t;
|
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_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_put_unwind_info.c ptrace/_UPT_get_proc_name.c \
|
||||||
ptrace/_UPT_reg_offset.c ptrace/_UPT_resume.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
|
noinst_HEADERS += ptrace/_UPT_internal.h
|
||||||
|
|
||||||
### libunwind-coredump:
|
### libunwind-coredump:
|
||||||
|
|
|
@ -23,9 +23,15 @@ int eh_elf_init_local() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int eh_elf_init_pid(pid_t pid) {
|
int eh_elf_init_pid(pid_t pid) {
|
||||||
|
Debug(3, "Init with pid\n");
|
||||||
return mmap_init_pid(pid);
|
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() {
|
void eh_elf_clear() {
|
||||||
mmap_clear();
|
mmap_clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,11 @@ int eh_elf_init_local();
|
||||||
**/
|
**/
|
||||||
int eh_elf_init_pid(pid_t pid);
|
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_*
|
/// Cleanup everything that was allocated by eh_elf_init_*
|
||||||
void eh_elf_clear();
|
void eh_elf_clear();
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,13 @@ static int _mmap_init_done = 0;
|
||||||
/// Init the memory map with a given /proc/XX/ argument
|
/// Init the memory map with a given /proc/XX/ argument
|
||||||
int mmap_init_procdir(const char* procdir);
|
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) {
|
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
|
// 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));
|
realloc(_memory_map, _memory_map_size * sizeof(mmap_entry_t));
|
||||||
|
|
||||||
// Ensure the entries are sorted by ascending ip range
|
// Ensure the entries are sorted by ascending ip range
|
||||||
qsort(_memory_map, _memory_map_size, sizeof(mmap_entry_t),
|
if(mmap_order_entries(_memory_map, _memory_map_size) < 0)
|
||||||
compare_mmap_entry);
|
return -3;
|
||||||
|
|
||||||
// dlopen corresponding eh_elf objects
|
// dlopen corresponding eh_elf objects
|
||||||
for(size_t id = 0; id < _memory_map_size; ++id) {
|
if(mmap_dlopen_eh_elfs(_memory_map, _memory_map_size) < 0)
|
||||||
char eh_elf_path[256];
|
return -4;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
_mmap_init_done = 1;
|
_mmap_init_done = 1;
|
||||||
|
|
||||||
return 0;
|
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() {
|
void mmap_clear() {
|
||||||
_mmap_init_done = 0;
|
_mmap_init_done = 0;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include "libunwind.h"
|
||||||
|
|
||||||
/// A type representing a dlopen handle
|
/// A type representing a dlopen handle
|
||||||
typedef void* dl_obj_t;
|
typedef void* dl_obj_t;
|
||||||
|
|
||||||
|
@ -44,6 +46,11 @@ int mmap_init_local();
|
||||||
**/
|
**/
|
||||||
int mmap_init_pid(pid_t pid);
|
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
|
/** Get the `mmap_entry_t` corresponding to the given IP
|
||||||
* @return a pointer to the corresponding memory map entry, or NULL upon
|
* @return a pointer to the corresponding memory map entry, or NULL upon
|
||||||
* failure.
|
* failure.
|
||||||
|
|
|
@ -35,5 +35,10 @@ PROTECTED unw_accessors_t _UPT_accessors =
|
||||||
.access_fpreg = _UPT_access_fpreg,
|
.access_fpreg = _UPT_access_fpreg,
|
||||||
.resume = _UPT_resume,
|
.resume = _UPT_resume,
|
||||||
.get_proc_name = _UPT_get_proc_name,
|
.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;
|
return -UNW_EINVAL;
|
||||||
#else /* !UNW_LOCAL_ONLY */
|
#else /* !UNW_LOCAL_ONLY */
|
||||||
struct cursor *c = (struct cursor *) cursor;
|
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)
|
if (!tdep_init_done)
|
||||||
tdep_init ();
|
tdep_init ();
|
||||||
|
|
||||||
Debug (1, "(cursor=%p)\n", c);
|
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;
|
c->dwarf.as = as;
|
||||||
if (as == unw_local_addr_space)
|
if (as == unw_local_addr_space)
|
||||||
|
|
Loading…
Reference in a new issue