This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch 4/4] unwinder: s390 and s390x


Hi Mark,

jankratochvil/ynonx86base-attach-firstreg-ppc-s390

I have left ebl API extensions together with s390 and s390x all in one.


Thanks,
Jan


unwinder: s390 and s390x

backends/
2013-11-10  Jan Kratochvil  <jan.kratochvil@redhat.com>

	unwinder: s390 and s390x
	* Makefile.am (s390_SRCS): Add s390_initreg.c and s390_unwind.c.
	* s390_init.c (s390_init): Initialize frame_nregs, core_pc_offset,
	set_initial_registers_tid, normalize_pc and unwind.
	* s390_initreg.c: New file.
	* s390_unwind.c: New file.

libdwfl/
2013-11-10  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.
	Call also ebl_dwarf_to_regno.
	(setfunc, getfunc, readfunc): New functions.
	(__libdwfl_frame_unwind): Call ebl_unwind with those functions.

libebl/
2013-11-10  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_normalize_pc): New declaration.
	(ebl_tid_registers_get_t, ebl_pid_memory_read_t): New definitions.
	(ebl_unwind): New declaration.

tests/
2013-11-10  Jan Kratochvil  <jan.kratochvil@redhat.com>

	unwinder: s390 and s390x
	* Makefile.am (EXTRA_DIST): Add backtrace.s390.core.bz2,
	backtrace.s390.exec.bz2, backtrace.s390x.core.bz2 and
	backtrace.s390x.exec.bz2.
	* 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.sh: Test also s390 and s390x.

Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>

--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -99,7 +99,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)
 
--- a/backends/s390_init.c
+++ b/backends/s390_init.c
@@ -62,6 +62,16 @@ 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;
+  eh->core_pc_offset = eh->class == ELFCLASS64 ? 0x78 : 0x4c;
+  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)
--- /dev/null
+++ b/backends/s390_initreg.c
@@ -0,0 +1,92 @@
+/* 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 <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]);
+  return setfunc (0, 16, dwarf_regs, arg);
+  /* Avoid conversion double -> integer.  */
+  eu_static_assert (sizeof user_regs.regs.fp_regs.fprs[0]
+		    == sizeof state->regs[0]);
+  for (unsigned u = 0; u < 16; u++)
+    dwarf_regs[u] = *((const __typeof (*state->regs) *)
+		      &user_regs.regs.fp_regs.fprs[u]));
+  if (! setfunc (0, 16, dwarf_regs, arg))
+    return false;
+  for (unsigned u = 0; u < 16; u++)
+    dwarf_frame_state_reg_set (state, 16 + u,
+			       *((const __typeof (*state->regs) *)
+				 &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))
+    return false;
+#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;
+}
--- /dev/null
+++ b/backends/s390_unwind.c
@@ -0,0 +1,133 @@
+/* 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"
+
+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'.  */
+  if (((instr >> 8) & 0xff) != 0x0a)
+    return false;
+  /* Check for 'sigreturn' or 'rt_sigreturn'.  */
+  if ((instr & 0xff) != 119 && (instr & 0xff) != 173)
+    return false;
+  /* See GDB s390_sigtramp_frame_unwind_cache.  */
+# define S390_SP_REGNUM (0 + 15) /* S390_R15_REGNUM */
+  Dwarf_Word this_sp;
+  if (! getfunc (S390_SP_REGNUM, 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".  */
+  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)
+    {
+      unsigned sigreg_high_off = 4;
+      sigreg_ptr += sigreg_high_off;
+      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;
+}
--- a/libdwfl/dwfl_frame_pc.c
+++ b/libdwfl/dwfl_frame_pc.c
@@ -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?  */
--- a/libdwfl/frame_unwind.c
+++ b/libdwfl/frame_unwind.c
@@ -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;
@@ -539,7 +553,7 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
 	    {
 	      /* REGNO is undefined.  */
 	      unsigned ra = frame->fde->cie->return_address_register;
-	      if (regno == ra)
+	      if (ebl_dwarf_to_regno (ebl, &ra) && regno == ra)
 		unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
 	      continue;
 	    }
@@ -582,6 +596,58 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
     }
 }
 
+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 > 0);
+      assert (unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
+      unwound->pc = *regs;
+      unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
+      firstreg++;
+      nregs--;
+      regs++;
+    }
+  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;
+  if (firstreg < 0)
+    {
+      assert (firstreg == -1);
+      assert (nregs > 0);
+      assert (state->pc_state == DWFL_FRAME_STATE_PC_SET);
+      *regs = state->pc;
+      firstreg++;
+      nregs--;
+      regs++;
+    }
+  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)
@@ -618,4 +684,20 @@ __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))
+    {
+      state->unwound->pc_state = DWFL_FRAME_STATE_ERROR;
+      // __libdwfl_seterrno has been called above.
+      return;
+    }
+  assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
+  state->unwound->signal_frame = signal_frame;
 }
--- a/libebl/Makefile.am
+++ b/libebl/Makefile.am
@@ -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 eblgetsymbol.c ebldwarftoregno.c
+	      eblstother.c eblinitreg.c eblgetsymbol.c ebldwarftoregno.c \
+	      eblnormalizepc.c eblunwind.c
 
 libebl_a_SOURCES = $(gen_SOURCES)
 
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -184,5 +184,21 @@ const char *EBLHOOK(get_symbol) (Ebl *ebl, size_t ndx, GElf_Sym *symp,
    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.  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 *);
--- /dev/null
+++ b/libebl/eblnormalizepc.c
@@ -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);
+}
--- /dev/null
+++ b/libebl/eblunwind.c
@@ -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);
+}
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -433,6 +433,33 @@ extern const char *ebl_get_symbol (Ebl *ebl, size_t ndx, GElf_Sym *symp,
 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 FIXME.
+   Register -1 is mapped to PC (if arch PC has no DWARF number).  */
+typedef bool (ebl_tid_registers_get_t) (int firstreg, unsigned nregs,
+					Dwarf_Word *regs, void *arg)
+  __nonnull_attribute__ (3);
+
+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.  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
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -231,7 +231,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     testfile_implicit_value.c testfile_implicit_value.bz2 \
 	     testfile66.bz2 run-backtrace.sh \
 	     backtrace.ppc.core.bz2 backtrace.ppc.exec.bz2 \
-	     backtrace.ppc64.core.bz2 backtrace.ppc64.exec.bz2
+	     backtrace.ppc64.core.bz2 backtrace.ppc64.exec.bz2 \
+	     backtrace.s390.core.bz2 backtrace.s390.exec.bz2 \
+	     backtrace.s390x.core.bz2 backtrace.s390x.exec.bz2
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --trace-children=yes --error-exitcode=1 --run-libc-freeres=no'
Binary files /dev/null and b/tests/backtrace.s390.core.bz2 differ
Binary files /dev/null and b/tests/backtrace.s390.exec.bz2 differ
Binary files /dev/null and b/tests/backtrace.s390x.core.bz2 differ
Binary files /dev/null and b/tests/backtrace.s390x.exec.bz2 differ
--- a/tests/run-backtrace.sh
+++ b/tests/run-backtrace.sh
@@ -91,7 +91,7 @@ for child in backtrace-child{,-biarch}; do
 
 done
 
-for arch in ppc ppc64; do
+for arch in ppc ppc64 s390 s390x; do
   testfiles backtrace.$arch.{exec,core}
   tempfiles backtrace.$arch.{bt,err}
   echo ./backtrace ./backtrace.$arch.{exec,core}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]