mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-01 06:41:51 -04:00
unwinder: s390 and s390x
Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
2013-12-18 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
unwinder: s390 and s390x
|
||||
* Makefile.am (s390_SRCS): Add s390_initreg.c and s390_unwind.c.
|
||||
* s390_corenote.c (prstatus_regs): Set PC_REGISTER. Reindent all the
|
||||
entries.
|
||||
* s390_init.c (s390_init): Initialize frame_nregs,
|
||||
set_initial_registers_tid, normalize_pc and unwind.
|
||||
* s390_initreg.c: New file.
|
||||
* s390_unwind.c: New file.
|
||||
|
||||
2013-12-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
unwinder: ppc and ppc64
|
||||
|
||||
@@ -106,7 +106,8 @@ libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
|
||||
am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
|
||||
|
||||
s390_SRCS = s390_init.c s390_symbol.c s390_regs.c s390_retval.c \
|
||||
s390_corenote.c s390x_corenote.c s390_cfi.c
|
||||
s390_corenote.c s390x_corenote.c s390_cfi.c s390_initreg.c \
|
||||
s390_unwind.c
|
||||
libebl_s390_pic_a_SOURCES = $(s390_SRCS)
|
||||
am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os)
|
||||
|
||||
|
||||
@@ -47,13 +47,13 @@
|
||||
|
||||
static const Ebl_Register_Location prstatus_regs[] =
|
||||
{
|
||||
#define GR(at, n, dwreg, b) \
|
||||
#define GR(at, n, dwreg, b...) \
|
||||
{ .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = b }
|
||||
|
||||
GR ( 0, 1, 64, BITS), /* pswm */
|
||||
GR ( 1, 1, 65, BITS), /* pswa */
|
||||
GR ( 2, 16, 0, BITS), /* r0-r15 */
|
||||
GR (18, 16, 48, 32), /* ar0-ar15 */
|
||||
GR ( 0, 1, 64, BITS), /* pswm */
|
||||
GR ( 1, 1, 65, BITS, .pc_register = true ), /* pswa */
|
||||
GR ( 2, 16, 0, BITS), /* r0-r15 */
|
||||
GR (18, 16, 48, 32), /* ar0-ar15 */
|
||||
|
||||
#undef GR
|
||||
};
|
||||
|
||||
@@ -62,6 +62,15 @@ s390_init (elf, machine, eh, ehlen)
|
||||
else
|
||||
HOOK (eh, core_note);
|
||||
HOOK (eh, abi_cfi);
|
||||
/* gcc/config/ #define DWARF_FRAME_REGISTERS 34.
|
||||
But from the gcc/config/s390/s390.h "Register usage." comment it looks as
|
||||
if #32 (Argument pointer) and #33 (Condition code) are not used for
|
||||
unwinding. */
|
||||
eh->frame_nregs = 32;
|
||||
HOOK (eh, set_initial_registers_tid);
|
||||
if (eh->class == ELFCLASS32)
|
||||
HOOK (eh, normalize_pc);
|
||||
HOOK (eh, unwind);
|
||||
|
||||
/* Only the 64-bit format uses the incorrect hash table entry size. */
|
||||
if (eh->class == ELFCLASS64)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/* Fetch live process registers from TID.
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of either
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
elfutils is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include <assert.h>
|
||||
#ifdef __s390__
|
||||
# include <sys/user.h>
|
||||
# include <asm/ptrace.h>
|
||||
# include <sys/ptrace.h>
|
||||
#endif
|
||||
|
||||
#define BACKEND s390_
|
||||
#include "libebl_CPU.h"
|
||||
|
||||
bool
|
||||
s390_set_initial_registers_tid (pid_t tid __attribute__ ((unused)),
|
||||
ebl_tid_registers_t *setfunc __attribute__ ((unused)),
|
||||
void *arg __attribute__ ((unused)))
|
||||
{
|
||||
#ifndef __s390__
|
||||
return false;
|
||||
#else /* __s390__ */
|
||||
struct user user_regs;
|
||||
ptrace_area parea;
|
||||
parea.process_addr = (uintptr_t) &user_regs;
|
||||
parea.kernel_addr = 0;
|
||||
parea.len = sizeof (user_regs);
|
||||
if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, NULL) != 0)
|
||||
return false;
|
||||
/* If we run as s390x we get the 64-bit registers of tid.
|
||||
But -m31 executable seems to use only the 32-bit parts of its
|
||||
registers so we ignore the upper half. */
|
||||
Dwarf_Word dwarf_regs[16];
|
||||
for (unsigned u = 0; u < 16; u++)
|
||||
dwarf_regs[u] = user_regs.regs.gprs[u];
|
||||
if (! setfunc (0, 16, dwarf_regs, arg))
|
||||
return false;
|
||||
/* Avoid conversion double -> integer. */
|
||||
eu_static_assert (sizeof user_regs.regs.fp_regs.fprs[0]
|
||||
== sizeof dwarf_regs[0]);
|
||||
for (unsigned u = 0; u < 16; u++)
|
||||
dwarf_regs[u] = *((const __typeof (dwarf_regs[0]) *)
|
||||
&user_regs.regs.fp_regs.fprs[u]);
|
||||
if (! setfunc (16, 16, dwarf_regs, arg))
|
||||
return false;
|
||||
dwarf_regs[0] = user_regs.regs.psw.addr;
|
||||
return setfunc (-1, 1, dwarf_regs, arg);
|
||||
#endif /* __s390__ */
|
||||
}
|
||||
|
||||
void
|
||||
s390_normalize_pc (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr *pc)
|
||||
{
|
||||
assert (ebl->class == ELFCLASS32);
|
||||
|
||||
/* Clear S390 bit 31. */
|
||||
*pc &= (1U << 31) - 1;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/* Get previous frame state for an existing frame state.
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of either
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
elfutils is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define BACKEND s390_
|
||||
#include "libebl_CPU.h"
|
||||
|
||||
/* s390/s390x do not annotate signal handler frame by CFI. It would be also
|
||||
difficult as PC points into a stub built on stack. Function below is called
|
||||
only if unwinder could not find CFI. Function then verifies the register
|
||||
state for this frame really belongs to a signal frame. In such case it
|
||||
fetches original registers saved by the signal frame. */
|
||||
|
||||
bool
|
||||
s390_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc,
|
||||
ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc,
|
||||
void *arg, bool *signal_framep)
|
||||
{
|
||||
/* Caller already assumed caller adjustment but S390 instructions are 4 bytes
|
||||
long. Undo it. */
|
||||
if ((pc & 0x3) != 0x3)
|
||||
return false;
|
||||
pc++;
|
||||
/* We can assume big-endian read here. */
|
||||
Dwarf_Word instr;
|
||||
if (! readfunc (pc, &instr, arg))
|
||||
return false;
|
||||
/* Fetch only the very first two bytes. */
|
||||
instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff;
|
||||
/* See GDB s390_sigtramp_frame_sniffer. */
|
||||
/* Check for 'svc' as the first instruction. */
|
||||
if (((instr >> 8) & 0xff) != 0x0a)
|
||||
return false;
|
||||
/* Check for 'sigreturn' or 'rt_sigreturn' as the second instruction. */
|
||||
if ((instr & 0xff) != 119 && (instr & 0xff) != 173)
|
||||
return false;
|
||||
/* See GDB s390_sigtramp_frame_unwind_cache. */
|
||||
Dwarf_Word this_sp;
|
||||
if (! getfunc (0 + 15, 1, &this_sp, arg))
|
||||
return false;
|
||||
unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4;
|
||||
Dwarf_Addr next_cfa = this_sp + 16 * word_size + 32;
|
||||
/* "New-style RT frame" is not supported,
|
||||
assuming "Old-style RT frame and all non-RT frames".
|
||||
Pointer to the array of saved registers is at NEXT_CFA + 8. */
|
||||
Dwarf_Word sigreg_ptr;
|
||||
if (! readfunc (next_cfa + 8, &sigreg_ptr, arg))
|
||||
return false;
|
||||
/* Skip PSW mask. */
|
||||
sigreg_ptr += word_size;
|
||||
/* Read PSW address. */
|
||||
Dwarf_Word val;
|
||||
if (! readfunc (sigreg_ptr, &val, arg))
|
||||
return false;
|
||||
if (! setfunc (-1, 1, &val, arg))
|
||||
return false;
|
||||
sigreg_ptr += word_size;
|
||||
/* Then the GPRs. */
|
||||
Dwarf_Word gprs[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (! readfunc (sigreg_ptr, &gprs[i], arg))
|
||||
return false;
|
||||
sigreg_ptr += word_size;
|
||||
}
|
||||
/* Then the ACRs. Skip them, they are not used in CFI. */
|
||||
for (int i = 0; i < 16; i++)
|
||||
sigreg_ptr += 4;
|
||||
/* The floating-point control word. */
|
||||
sigreg_ptr += 8;
|
||||
/* And finally the FPRs. */
|
||||
Dwarf_Word fprs[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (! readfunc (sigreg_ptr, &val, arg))
|
||||
return false;
|
||||
if (ebl->class == ELFCLASS32)
|
||||
{
|
||||
Dwarf_Addr val_low;
|
||||
if (! readfunc (sigreg_ptr + 4, &val_low, arg))
|
||||
return false;
|
||||
val = (val << 32) | val_low;
|
||||
}
|
||||
fprs[i] = val;
|
||||
sigreg_ptr += 8;
|
||||
}
|
||||
/* If we have them, the GPR upper halves are appended at the end. */
|
||||
if (ebl->class == ELFCLASS32)
|
||||
{
|
||||
/* Skip signal number. */
|
||||
sigreg_ptr += 4;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (! readfunc (sigreg_ptr, &val, arg))
|
||||
return false;
|
||||
Dwarf_Word val_low = gprs[i];
|
||||
val = (val << 32) | val_low;
|
||||
gprs[i] = val;
|
||||
sigreg_ptr += 4;
|
||||
}
|
||||
}
|
||||
if (! setfunc (0, 16, gprs, arg))
|
||||
return false;
|
||||
if (! setfunc (16, 16, fprs, arg))
|
||||
return false;
|
||||
*signal_framep = true;
|
||||
return true;
|
||||
}
|
||||
@@ -1,3 +1,15 @@
|
||||
2013-12-18 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
unwinder: s390 and s390x
|
||||
* dwfl_frame_pc.c (dwfl_frame_pc): Call ebl_normalize_pc.
|
||||
* frame_unwind.c (new_unwound): New function from ...
|
||||
(handle_cfi): ... here. Call it.
|
||||
(setfunc, getfunc, readfunc): New functions.
|
||||
(__libdwfl_frame_unwind): Call ebl_unwind with those functions.
|
||||
* linux-core-attach.c (core_set_initial_registers): Always iterate
|
||||
through the Ebl_Register_Location loop. Call
|
||||
dwfl_thread_state_register_pc there.
|
||||
|
||||
2013-12-17 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* frame_unwind.c (handle_cfi): Call ebl_dwarf_to_regno for RA.
|
||||
|
||||
@@ -37,6 +37,7 @@ dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation)
|
||||
{
|
||||
assert (state->pc_state == DWFL_FRAME_STATE_PC_SET);
|
||||
*pc = state->pc;
|
||||
ebl_normalize_pc (state->thread->process->ebl, pc);
|
||||
if (isactivation)
|
||||
{
|
||||
/* Bottom frame? */
|
||||
|
||||
+84
-9
@@ -494,6 +494,26 @@ expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
new_unwound (Dwfl_Frame *state)
|
||||
{
|
||||
assert (state->unwound == NULL);
|
||||
Dwfl_Thread *thread = state->thread;
|
||||
Dwfl_Process *process = thread->process;
|
||||
Ebl *ebl = process->ebl;
|
||||
size_t nregs = ebl_frame_nregs (ebl);
|
||||
assert (nregs > 0);
|
||||
Dwfl_Frame *unwound;
|
||||
unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs);
|
||||
state->unwound = unwound;
|
||||
unwound->thread = thread;
|
||||
unwound->unwound = NULL;
|
||||
unwound->signal_frame = false;
|
||||
unwound->initial_frame = false;
|
||||
unwound->pc_state = DWFL_FRAME_STATE_ERROR;
|
||||
memset (unwound->regs_set, 0, sizeof (unwound->regs_set));
|
||||
}
|
||||
|
||||
/* The logic is to call __libdwfl_seterrno for any CFI bytecode interpretation
|
||||
error so one can easily catch the problem with a debugger. Still there are
|
||||
archs with invalid CFI for some registers where the registers are never used
|
||||
@@ -508,20 +528,14 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
|
||||
__libdwfl_seterrno (DWFL_E_LIBDW);
|
||||
return;
|
||||
}
|
||||
new_unwound (state);
|
||||
Dwfl_Frame *unwound = state->unwound;
|
||||
unwound->signal_frame = frame->fde->cie->signal_frame;
|
||||
Dwfl_Thread *thread = state->thread;
|
||||
Dwfl_Process *process = thread->process;
|
||||
Ebl *ebl = process->ebl;
|
||||
size_t nregs = ebl_frame_nregs (ebl);
|
||||
assert (nregs > 0);
|
||||
Dwfl_Frame *unwound;
|
||||
unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs);
|
||||
state->unwound = unwound;
|
||||
unwound->thread = thread;
|
||||
unwound->unwound = NULL;
|
||||
unwound->signal_frame = frame->fde->cie->signal_frame;
|
||||
unwound->initial_frame = false;
|
||||
unwound->pc_state = DWFL_FRAME_STATE_ERROR;
|
||||
memset (unwound->regs_set, 0, sizeof (unwound->regs_set));
|
||||
for (unsigned regno = 0; regno < nregs; regno++)
|
||||
{
|
||||
Dwarf_Op reg_ops_mem[3], *reg_ops;
|
||||
@@ -583,6 +597,47 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
|
||||
free (frame);
|
||||
}
|
||||
|
||||
static bool
|
||||
setfunc (int firstreg, unsigned nregs, const Dwarf_Word *regs, void *arg)
|
||||
{
|
||||
Dwfl_Frame *state = arg;
|
||||
Dwfl_Frame *unwound = state->unwound;
|
||||
if (firstreg < 0)
|
||||
{
|
||||
assert (firstreg == -1);
|
||||
assert (nregs == 1);
|
||||
assert (unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
|
||||
unwound->pc = *regs;
|
||||
unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
|
||||
return true;
|
||||
}
|
||||
while (nregs--)
|
||||
if (! __libdwfl_frame_reg_set (unwound, firstreg++, *regs++))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg)
|
||||
{
|
||||
Dwfl_Frame *state = arg;
|
||||
assert (firstreg >= 0);
|
||||
while (nregs--)
|
||||
if (! __libdwfl_frame_reg_get (state, firstreg++, regs++))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
readfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg)
|
||||
{
|
||||
Dwfl_Frame *state = arg;
|
||||
Dwfl_Thread *thread = state->thread;
|
||||
Dwfl_Process *process = thread->process;
|
||||
return process->callbacks->memory_read (process->dwfl, addr, datap,
|
||||
process->callbacks_arg);
|
||||
}
|
||||
|
||||
void
|
||||
internal_function
|
||||
__libdwfl_frame_unwind (Dwfl_Frame *state)
|
||||
@@ -619,4 +674,24 @@ __libdwfl_frame_unwind (Dwfl_Frame *state)
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert (state->unwound == NULL);
|
||||
Dwfl_Thread *thread = state->thread;
|
||||
Dwfl_Process *process = thread->process;
|
||||
Ebl *ebl = process->ebl;
|
||||
new_unwound (state);
|
||||
state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
|
||||
// &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield.
|
||||
bool signal_frame = false;
|
||||
if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame))
|
||||
{
|
||||
// Discard the unwind attempt. During next __libdwfl_frame_unwind call
|
||||
// we may have for example the appropriate Dwfl_Module already mapped.
|
||||
assert (state->unwound->unwound == NULL);
|
||||
free (state->unwound);
|
||||
state->unwound = NULL;
|
||||
// __libdwfl_seterrno has been called above.
|
||||
return;
|
||||
}
|
||||
assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
|
||||
state->unwound->signal_frame = signal_frame;
|
||||
}
|
||||
|
||||
@@ -228,12 +228,12 @@ core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
|
||||
for (size_t regloci = 0; regloci < nregloc; regloci++)
|
||||
{
|
||||
const Ebl_Register_Location *regloc = reglocs + regloci;
|
||||
if (regloc->regno >= nregs)
|
||||
// Iterate even regs out of NREGS range so that we can find pc_register.
|
||||
if (regloc->bits != 32 && regloc->bits != 64)
|
||||
continue;
|
||||
assert (regloc->bits == 32 || regloc->bits == 64);
|
||||
const char *reg_desc = desc + regloc->offset;
|
||||
for (unsigned regno = regloc->regno;
|
||||
regno < MIN (regloc->regno + (regloc->count ?: 1U), nregs);
|
||||
regno < regloc->regno + (regloc->count ?: 1U);
|
||||
regno++)
|
||||
{
|
||||
/* PPC provides DWARF register 65 irrelevant for
|
||||
@@ -241,7 +241,8 @@ core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
|
||||
LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
|
||||
FIXME: It depends now on their order in core notes.
|
||||
FIXME: It uses private function. */
|
||||
if (__libdwfl_frame_reg_get (thread->unwound, regno, NULL))
|
||||
if (regno < nregs
|
||||
&& __libdwfl_frame_reg_get (thread->unwound, regno, NULL))
|
||||
continue;
|
||||
Dwarf_Word val;
|
||||
switch (regloc->bits)
|
||||
@@ -266,7 +267,10 @@ core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
|
||||
abort ();
|
||||
}
|
||||
/* Registers not valid for CFI are just ignored. */
|
||||
INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val);
|
||||
if (regno < nregs)
|
||||
INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val);
|
||||
if (regloc->pc_register)
|
||||
INTUSE(dwfl_thread_state_register_pc) (thread, val);
|
||||
reg_desc += regloc->pad;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
2013-12-18 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
unwinder: s390 and s390x
|
||||
* Makefile.am (gen_SOURCES): Add eblnormalizepc.c and eblunwind.c.
|
||||
* ebl-hooks.h (normalize_pc, unwind): New.
|
||||
* eblnormalizepc.c: New file.
|
||||
* eblunwind.c: New file.
|
||||
* libebl.h (Ebl_Register_Location): Add field pc_register.
|
||||
(ebl_normalize_pc): New declaration.
|
||||
(ebl_tid_registers_get_t, ebl_pid_memory_read_t): New definitions.
|
||||
(ebl_unwind): New declaration.
|
||||
|
||||
2013-12-15 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
unwinder: ppc and ppc64
|
||||
|
||||
+2
-1
@@ -54,7 +54,8 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \
|
||||
eblreginfo.c eblnonerelocp.c eblrelativerelocp.c \
|
||||
eblsysvhashentrysize.c eblauxvinfo.c eblcheckobjattr.c \
|
||||
ebl_check_special_section.c ebl_syscall_abi.c eblabicfi.c \
|
||||
eblstother.c eblinitreg.c ebldwarftoregno.c
|
||||
eblstother.c eblinitreg.c ebldwarftoregno.c eblnormalizepc.c \
|
||||
eblunwind.c
|
||||
|
||||
libebl_a_SOURCES = $(gen_SOURCES)
|
||||
|
||||
|
||||
@@ -166,5 +166,22 @@ bool EBLHOOK(set_initial_registers_tid) (pid_t tid,
|
||||
Dwarf_Frame->REGS indexing. */
|
||||
bool EBLHOOK(dwarf_to_regno) (Ebl *ebl, unsigned *regno);
|
||||
|
||||
/* Optionally modify *PC as fetched from inferior data into valid PC
|
||||
instruction pointer. */
|
||||
void EBLHOOK(normalize_pc) (Ebl *ebl, Dwarf_Addr *pc);
|
||||
|
||||
/* Get previous frame state for an existing frame state. Method is called only
|
||||
if unwinder could not find CFI for current PC. PC is for the
|
||||
existing frame. SETFUNC sets register in the previous frame. GETFUNC gets
|
||||
register from the existing frame. Note that GETFUNC vs. SETFUNC act on
|
||||
a disjunct set of registers. READFUNC reads memory. ARG has to be passed
|
||||
for SETFUNC, GETFUNC and READFUNC. *SIGNAL_FRAMEP is initialized to false,
|
||||
it can be set to true if existing frame is a signal frame. SIGNAL_FRAMEP is
|
||||
never NULL. */
|
||||
bool EBLHOOK(unwind) (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc,
|
||||
ebl_tid_registers_get_t *getfunc,
|
||||
ebl_pid_memory_read_t *readfunc, void *arg,
|
||||
bool *signal_framep);
|
||||
|
||||
/* Destructor for ELF backend handle. */
|
||||
void EBLHOOK(destr) (struct ebl *);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Modify PC as fetched from inferior data into valid PC.
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of either
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
elfutils is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <libeblP.h>
|
||||
|
||||
void
|
||||
ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc)
|
||||
{
|
||||
if (ebl != NULL && ebl->normalize_pc != NULL)
|
||||
ebl->normalize_pc (ebl, pc);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Get previous frame state for an existing frame state.
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of either
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
elfutils is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <libeblP.h>
|
||||
|
||||
bool
|
||||
ebl_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc,
|
||||
ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc,
|
||||
void *arg, bool *signal_framep)
|
||||
{
|
||||
if (ebl == NULL || ebl->unwind == NULL)
|
||||
return false;
|
||||
return ebl->unwind (ebl, pc, setfunc, getfunc, readfunc, arg, signal_framep);
|
||||
}
|
||||
@@ -356,6 +356,7 @@ typedef struct
|
||||
uint8_t bits; /* Bits of data for one register. */
|
||||
uint8_t pad; /* Bytes of padding after register's data. */
|
||||
Dwarf_Half count; /* Consecutive register numbers here. */
|
||||
bool pc_register;
|
||||
} Ebl_Register_Location;
|
||||
|
||||
/* Non-register data items in core notes. */
|
||||
@@ -410,6 +411,34 @@ extern size_t ebl_frame_nregs (Ebl *ebl)
|
||||
extern bool ebl_dwarf_to_regno (Ebl *ebl, unsigned *regno)
|
||||
__nonnull_attribute__ (1, 2);
|
||||
|
||||
/* Modify PC as fetched from inferior data into valid PC. */
|
||||
extern void ebl_normalize_pc (Ebl *ebl, Dwarf_Addr *pc)
|
||||
__nonnull_attribute__ (1, 2);
|
||||
|
||||
/* Callback type for ebl_unwind's parameter getfunc. */
|
||||
typedef bool (ebl_tid_registers_get_t) (int firstreg, unsigned nregs,
|
||||
Dwarf_Word *regs, void *arg)
|
||||
__nonnull_attribute__ (3);
|
||||
|
||||
/* Callback type for ebl_unwind's parameter readfunc. */
|
||||
typedef bool (ebl_pid_memory_read_t) (Dwarf_Addr addr, Dwarf_Word *data,
|
||||
void *arg)
|
||||
__nonnull_attribute__ (3);
|
||||
|
||||
/* Get previous frame state for an existing frame state. Method is called only
|
||||
if unwinder could not find CFI for current PC. PC is for the
|
||||
existing frame. SETFUNC sets register in the previous frame. GETFUNC gets
|
||||
register from the existing frame. Note that GETFUNC vs. SETFUNC act on
|
||||
a disjunct set of registers. READFUNC reads memory. ARG has to be passed
|
||||
for SETFUNC, GETFUNC and READFUNC. *SIGNAL_FRAMEP is initialized to false,
|
||||
it can be set to true if existing frame is a signal frame. SIGNAL_FRAMEP is
|
||||
never NULL. */
|
||||
extern bool ebl_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc,
|
||||
ebl_tid_registers_get_t *getfunc,
|
||||
ebl_pid_memory_read_t *readfunc, void *arg,
|
||||
bool *signal_framep)
|
||||
__nonnull_attribute__ (1, 3, 4, 5, 7);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
2013-12-18 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
unwinder: s390 and s390x
|
||||
* Makefile.am (TESTS): Add run-backtrace-core-s390x.sh and
|
||||
run-backtrace-core-s390.sh.
|
||||
(EXTRA_DIST): Add backtrace.s390x.core.bz2, backtrace.s390x.exec.bz2,
|
||||
backtrace.s390.core.bz2, backtrace.s390.exec.bz2,
|
||||
run-backtrace-core-s390x.sh and run-backtrace-core-s390.sh.
|
||||
* backtrace.s390.core.bz2: New file.
|
||||
* backtrace.s390.exec.bz2: New file.
|
||||
* backtrace.s390x.core.bz2: New file.
|
||||
* backtrace.s390x.exec.bz2: New file.
|
||||
* run-backtrace-core-s390.sh: New file.
|
||||
* run-backtrace-core-s390x.sh: New file.
|
||||
|
||||
2013-12-17 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* backtrace-dwarf.c (executable, find_elf, dwfl_offline): Remove unused
|
||||
|
||||
+6
-2
@@ -106,7 +106,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
|
||||
run-backtrace-native.sh run-backtrace-data.sh run-backtrace-dwarf.sh \
|
||||
run-backtrace-native-biarch.sh run-backtrace-native-core.sh \
|
||||
run-backtrace-native-core-biarch.sh run-backtrace-core-x86_64.sh \
|
||||
run-backtrace-core-i386.sh run-backtrace-core-ppc.sh
|
||||
run-backtrace-core-i386.sh run-backtrace-core-ppc.sh \
|
||||
run-backtrace-core-s390x.sh run-backtrace-core-s390.sh
|
||||
|
||||
if !BIARCH
|
||||
export ELFUTILS_DISABLE_BIARCH = 1
|
||||
@@ -247,7 +248,10 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
|
||||
backtrace-subr.sh backtrace.i386.core.bz2 backtrace.i386.exec.bz2 \
|
||||
backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2 \
|
||||
backtrace.ppc.core.bz2 backtrace.ppc.exec.bz2 \
|
||||
run-backtrace-core-ppc.sh
|
||||
run-backtrace-core-ppc.sh \
|
||||
backtrace.s390x.core.bz2 backtrace.s390x.exec.bz2 \
|
||||
backtrace.s390.core.bz2 backtrace.s390.exec.bz2 \
|
||||
run-backtrace-core-s390x.sh run-backtrace-core-s390.sh
|
||||
|
||||
if USE_VALGRIND
|
||||
valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#! /bin/bash
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
# This file is part of elfutils.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# elfutils is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. $srcdir/backtrace-subr.sh
|
||||
|
||||
check_core s390
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#! /bin/bash
|
||||
# Copyright (C) 2013 Red Hat, Inc.
|
||||
# This file is part of elfutils.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# elfutils is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. $srcdir/backtrace-subr.sh
|
||||
|
||||
check_core s390x
|
||||
Reference in New Issue
Block a user