#include "libebl_CPU.h"
bool
-s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc,
- bool (*memory_read) (Dwfl_Frame_State_Process *process,
- Dwarf_Addr addr, Dwarf_Addr *result))
+s390_frame_unwind (Ebl *ebl, Dwfl_Frame_State **statep, Dwarf_Addr pc)
{
Dwfl_Frame_State *state = *statep;
Dwfl_Frame_State_Process *process = state->thread->process;
pc++;
/* We can assume big-endian read here. */
Dwarf_Addr instr;
- if (! memory_read (process, pc, &instr))
+ if (! process->memory_read (pc, &instr, process->memory_read_user_data))
return false;
/* Fetch only the very first two bytes. */
instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff;
/* "New-style RT frame" is not supported,
assuming "Old-style RT frame and all non-RT frames". */
Dwarf_Addr sigreg_ptr;
- if (! memory_read (process, next_cfa + 8, &sigreg_ptr))
+ if (! process->memory_read (next_cfa + 8, &sigreg_ptr,
+ process->memory_read_user_data))
return false;
/* Skip PSW mask. */
sigreg_ptr += word_size;
/* Read PSW address. */
Dwarf_Addr val;
- if (! memory_read (process, sigreg_ptr, &val))
+ if (! process->memory_read (sigreg_ptr, &val, process->memory_read_user_data))
return false;
sigreg_ptr += word_size;
size_t nregs = ebl->frame_state_nregs;
/* Then the GPRs. */
for (int i = 0; i < 16; i++)
{
- if (! memory_read (process, sigreg_ptr, &val))
+ if (! process->memory_read (sigreg_ptr, &val,
+ process->memory_read_user_data))
return false;
if (! dwfl_frame_state_reg_set (unwound, 0 + i, val))
return false;
/* And finally the FPRs. */
for (int i = 0; i < 16; i++)
{
- if (! memory_read (process, sigreg_ptr, &val))
+ if (! process->memory_read (sigreg_ptr, &val,
+ process->memory_read_user_data))
return false;
if (ebl->class == ELFCLASS32)
{
Dwarf_Addr val_low;
- if (! memory_read (process, sigreg_ptr + 4, &val_low))
+ if (! process->memory_read (sigreg_ptr + 4, &val_low,
+ process->memory_read_user_data))
return false;
val = (val << 32) | val_low;
}
sigreg_ptr += sigreg_high_off;
for (int i = 0; i < 16; i++)
{
- if (! memory_read (process, sigreg_ptr, &val))
+ if (! process->memory_read (sigreg_ptr, &val,
+ process->memory_read_user_data))
return false;
Dwarf_Addr val_low;
if (! dwfl_frame_state_reg_get (unwound, 0 + i, &val_low))
# define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
+/* Exact copy from libdwfl/segment.c. */
+
+static GElf_Addr
+segment_start (Dwfl *dwfl, GElf_Addr start)
+{
+ if (dwfl->segment_align > 1)
+ start &= -dwfl->segment_align;
+ return start;
+}
+
+/* Exact copy from libdwfl/segment.c. */
+
+static GElf_Addr
+segment_end (Dwfl *dwfl, GElf_Addr end)
+{
+ if (dwfl->segment_align > 1)
+ end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
+ return end;
+}
+
static bool
tid_is_attached (Dwfl *dwfl, pid_t tid)
{
}
static Dwfl_Frame_State_Process *
-process_alloc (Dwfl *dwfl)
+process_alloc (Dwfl *dwfl, dwfl_frame_memory_read_t *memory_read,
+ void *memory_read_user_data)
{
Dwfl_Frame_State_Process *process = malloc (sizeof (*process));
if (process == NULL)
process->dwfl = dwfl;
process->ebl = NULL;
process->ebl_close = NULL;
+ process->memory_read = memory_read;
+ process->memory_read_user_data = memory_read_user_data;
process->core = NULL;
process->core_fd = -1;
process->thread = NULL;
return true;
}
+static bool
+dwfl_frame_state_pid_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
+ void *user_data)
+{
+ Dwfl_Frame_State_Process *process = user_data;
+ assert (process->core == NULL && process->thread->tid);
+ if (process->ebl->class == ELFCLASS64)
+ {
+ errno = 0;
+ *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
+ (void *) (uintptr_t) addr, NULL);
+ if (errno != 0)
+ {
+ __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+ return false;
+ }
+ return true;
+ }
+#if SIZEOF_LONG == 8
+ /* We do not care about reads unaliged to 4 bytes boundary.
+ But 0x...ffc read of 8 bytes could overrun a page. */
+ bool lowered = (addr & 4) != 0;
+ if (lowered)
+ addr -= 4;
+#endif /* SIZEOF_LONG == 8 */
+ errno = 0;
+ *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
+ (void *) (uintptr_t) addr, NULL);
+ if (errno != 0)
+ {
+ __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+ return false;
+ }
+#if SIZEOF_LONG == 8
+# if BYTE_ORDER == BIG_ENDIAN
+ if (! lowered)
+ *result >>= 32;
+# else
+ if (lowered)
+ *result >>= 32;
+# endif
+#endif /* SIZEOF_LONG == 8 */
+ *result &= 0xffffffff;
+ return true;
+}
+
Dwfl_Frame_State *
dwfl_frame_state_pid (Dwfl *dwfl, pid_t pid)
{
char dirname[64];
int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid);
assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1);
- Dwfl_Frame_State_Process *process = process_alloc (dwfl);
+ Dwfl_Frame_State_Process *process;
+ process = process_alloc (dwfl, dwfl_frame_state_pid_memory_read, NULL);
if (process == NULL)
return NULL;
+ process->memory_read_user_data = process;
for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
{
Dwfl_Error error = __libdwfl_module_getebl (mod);
}
INTDEF (dwfl_frame_state_pid)
+static bool
+dwfl_frame_state_core_memory_read (Dwarf_Addr addr, Dwarf_Addr *result,
+ void *user_data)
+{
+ Dwfl_Frame_State_Process *process = user_data;
+ Elf *core = process->core;
+ assert (core != NULL);
+ Dwfl *dwfl = process->dwfl;
+ static size_t phnum;
+ if (elf_getphdrnum (core, &phnum) < 0)
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return false;
+ }
+ for (size_t cnt = 0; cnt < phnum; ++cnt)
+ {
+ GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
+ if (phdr == NULL || phdr->p_type != PT_LOAD)
+ continue;
+ /* Bias is zero here, a core file itself has no bias. */
+ GElf_Addr start = segment_start (dwfl, phdr->p_vaddr);
+ GElf_Addr end = segment_end (dwfl, phdr->p_vaddr + phdr->p_memsz);
+ unsigned bytes = process->ebl->class == ELFCLASS64 ? 8 : 4;
+ if (addr < start || addr + bytes > end)
+ continue;
+ Elf_Data *data;
+ data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
+ bytes, ELF_T_ADDR);
+ if (data == NULL)
+ {
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return false;
+ }
+ assert (data->d_size == bytes);
+ /* FIXME: Currently any arch supported for unwinding supports
+ unaligned access. */
+ if (bytes == 8)
+ *result = *(const uint64_t *) data->d_buf;
+ else
+ *result = *(const uint32_t *) data->d_buf;
+ return true;
+ }
+ __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
+ return false;
+}
+
Dwfl_Frame_State *
dwfl_frame_state_core (Dwfl *dwfl, const char *corefile)
{
- Dwfl_Frame_State_Process *process = process_alloc (dwfl);
+ Dwfl_Frame_State_Process *process;
+ process = process_alloc (dwfl, dwfl_frame_state_core_memory_read, NULL);
if (process == NULL)
return NULL;
+ process->memory_read_user_data = process;
int core_fd = open64 (corefile, O_RDONLY);
if (core_fd < 0)
{
Dwfl_Frame_State *
dwfl_frame_state_data (Dwfl *dwfl, int pc_set, Dwarf_Addr pc, unsigned nregs,
- const uint64_t *regs_set, const Dwarf_Addr *regs)
+ const uint64_t *regs_set, const Dwarf_Addr *regs,
+ dwfl_frame_memory_read_t *memory_read,
+ void *memory_read_user_data)
{
Ebl *ebl = NULL;
for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
__libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
return NULL;
}
- Dwfl_Frame_State_Process *process = process_alloc (dwfl);
+ Dwfl_Frame_State_Process *process;
+ process = process_alloc (dwfl, memory_read, memory_read_user_data);
if (process == NULL)
return NULL;
process->ebl = ebl;
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
-/* Exact copy from libdwfl/segment.c. */
-
-static GElf_Addr
-segment_start (Dwfl *dwfl, GElf_Addr start)
-{
- if (dwfl->segment_align > 1)
- start &= -dwfl->segment_align;
- return start;
-}
-
-/* Exact copy from libdwfl/segment.c. */
-
-static GElf_Addr
-segment_end (Dwfl *dwfl, GElf_Addr end)
-{
- if (dwfl->segment_align > 1)
- end = (end + dwfl->segment_align - 1) & -dwfl->segment_align;
- return end;
-}
-
static bool
state_get_reg (Dwfl_Frame_State *state, unsigned regno, Dwarf_Addr *val)
{
return true;
}
-static bool
-memory_read (Dwfl_Frame_State_Process *process, Dwarf_Addr addr,
- Dwarf_Addr *result)
-{
- if (process->core == NULL)
- {
- if (process->ebl->class == ELFCLASS64)
- {
- errno = 0;
- *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
- (void *) (uintptr_t) addr, NULL);
- if (errno != 0)
- {
- __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
- return false;
- }
- return true;
- }
-#if SIZEOF_LONG == 8
- /* We do not care about reads unaliged to 4 bytes boundary.
- But 0x...ffc read of 8 bytes could overrun a page. */
- bool lowered = (addr & 4) != 0;
- if (lowered)
- addr -= 4;
-#endif /* SIZEOF_LONG == 8 */
- errno = 0;
- *result = ptrace (PTRACE_PEEKDATA, process->thread->tid,
- (void *) (uintptr_t) addr, NULL);
- if (errno != 0)
- {
- __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
- return false;
- }
-#if SIZEOF_LONG == 8
-# if BYTE_ORDER == BIG_ENDIAN
- if (! lowered)
- *result >>= 32;
-# else
- if (lowered)
- *result >>= 32;
-# endif
-#endif /* SIZEOF_LONG == 8 */
- *result &= 0xffffffff;
- return true;
- }
- if (process->core)
- {
- Elf *core = process->core;
- Dwfl *dwfl = process->dwfl;
- static size_t phnum;
- if (elf_getphdrnum (core, &phnum) < 0)
- {
- __libdwfl_seterrno (DWFL_E_LIBELF);
- return false;
- }
- for (size_t cnt = 0; cnt < phnum; ++cnt)
- {
- GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
- if (phdr == NULL || phdr->p_type != PT_LOAD)
- continue;
- /* Bias is zero here, a core file itself has no bias. */
- GElf_Addr start = segment_start (dwfl, phdr->p_vaddr);
- GElf_Addr end = segment_end (dwfl, phdr->p_vaddr + phdr->p_memsz);
- unsigned bytes = process->ebl->class == ELFCLASS64 ? 8 : 4;
- if (addr < start || addr + bytes > end)
- continue;
- Elf_Data *data;
- data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
- bytes, ELF_T_ADDR);
- if (data == NULL)
- {
- __libdwfl_seterrno (DWFL_E_LIBELF);
- return false;
- }
- assert (data->d_size == bytes);
- /* FIXME: Currently any arch supported for unwinding supports
- unaligned access. */
- if (bytes == 8)
- *result = *(const uint64_t *) data->d_buf;
- else
- *result = *(const uint32_t *) data->d_buf;
- return true;
- }
- __libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
- return false;
- }
- abort ();
-}
-
static int
bra_compar (const void *key_voidp, const void *elem_voidp)
{
expr_eval (Dwfl_Frame_State *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
size_t nops, Dwarf_Addr *result)
{
+ Dwfl_Frame_State_Process *process = state->thread->process;
if (nops == 0)
{
__libdwfl_seterrno (DWFL_E_UNKNOWN_ERROR);
is_location = false;
break;
case DW_OP_deref:
- if (! pop (&val1) || ! memory_read (state->thread->process, val1, &val1)
+ if (! pop (&val1)
+ || ! process->memory_read (val1, &val1,
+ process->memory_read_user_data)
|| ! push (val1))
{
free (stack);
return false;
}
free (stack);
- if (is_location && ! memory_read (state->thread->process, *result, result))
+ if (is_location && ! process->memory_read (*result, result,
+ process->memory_read_user_data))
return false;
return true;
}
}
}
*statep = state;
- if (ebl_frame_unwind (state->thread->process->ebl, statep, pc, memory_read))
+ if (ebl_frame_unwind (state->thread->process->ebl, statep, pc))
return true;
if (state->unwound)
{
const char *corefile);
/* Fetch inferior registers from a caller supplied storage. */
+typedef bool dwfl_frame_memory_read_t (Dwarf_Addr addr, Dwarf_Addr *result,
+ void *user_data);
extern Dwfl_Frame_State *dwfl_frame_state_data (Dwfl *dwfl, int pc_set,
Dwarf_Addr pc, unsigned nregs,
const uint64_t *regs_set,
- const Dwarf_Addr *regs);
+ const Dwarf_Addr *regs,
+ dwfl_frame_memory_read_t
+ *memory_read,
+ void *memory_read_user_data);
/* Return TRUE and update *STATEP for the unwound frame for successful unwind.
Return TRUE and set *STATEP to NULL for the outermost frame. Return FALSE
struct ebl *ebl;
/* If it is false we share EBL with one of DWFL's Dwfl_Module->ebl. */
bool ebl_close : 1;
+ dwfl_frame_memory_read_t *memory_read;
+ void *memory_read_user_data;
/* If there is no core file both CORE is NULL and CORE_FD is -1. */
Elf *core;
int core_fd;
void EBLHOOK(normalize_pc) (Ebl *ebl, Dwarf_Addr *pc);
/* See dwfl_frame_unwind. */
-bool
- EBLHOOK(frame_unwind) (Ebl *ebl, struct Dwfl_Frame_State **statep,
- Dwarf_Addr pc,
- bool (*memory_read) (
- struct Dwfl_Frame_State_Process *process,
- Dwarf_Addr addr,
- Dwarf_Addr *result));
+bool EBLHOOK(frame_unwind) (Ebl *ebl, struct Dwfl_Frame_State **statep,
+ Dwarf_Addr pc);
/* Destructor for ELF backend handle. */
void EBLHOOK(destr) (struct ebl *);
#include <libeblP.h>
bool
-ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc,
- bool (*memory_read) (struct Dwfl_Frame_State_Process *process,
- Dwarf_Addr addr, Dwarf_Addr *result))
+ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc)
{
if (ebl == NULL || ebl->frame_unwind == NULL)
return false;
- return ebl->frame_unwind (ebl, statep, pc, memory_read);
+ return ebl->frame_unwind (ebl, statep, pc);
}
/* Get previous frame state for an existing frame state. */
struct Dwfl_Frame_State_Process;
extern bool
- ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc,
- bool
- (*memory_read) (struct Dwfl_Frame_State_Process *process,
- Dwarf_Addr addr, Dwarf_Addr *result))
- __nonnull_attribute__ (1, 2, 4);
+ ebl_frame_unwind (Ebl *ebl, struct Dwfl_Frame_State **statep, Dwarf_Addr pc)
+ __nonnull_attribute__ (1, 2);
/* Convert *REGNO as is in DWARF to a lower range. */
extern bool ebl_frame_dwarf_to_regno (Ebl *ebl, unsigned *regno)