d0b10ff
From 1b2cd3f4dc581eed0fc1ee98f97aa492a19873b0 Mon Sep 17 00:00:00 2001
d0b10ff
From: Mark Wielaard <mark@klomp.org>
d0b10ff
Date: Sun, 21 May 2017 23:33:15 +0200
d0b10ff
Subject: [PATCH] ppc64: Add minimal fallback unwinder.
d0b10ff
d0b10ff
This adds a minimal fallback unwinder for ppc64[le] in case we cannot find
d0b10ff
CFI for a particular address. It simply always sets the program counter to
d0b10ff
the link register, picks the previous stack pointer from the backchain,
d0b10ff
and the previous link register from the LR save area.
d0b10ff
d0b10ff
This is enough for some simple situations when we don't have CFI and
d0b10ff
seems to work nicely in the case of perf with libdw powerpc support:
d0b10ff
https://lkml.org/lkml/2017/5/18/998
d0b10ff
d0b10ff
Signed-off-by: Mark Wielaard <mark@klomp.org>
d0b10ff
---
d0b10ff
 backends/ChangeLog                     |   6 +++
d0b10ff
 backends/Makefile.am                   |   2 +-
d0b10ff
 backends/ppc64_init.c                  |   1 +
d0b10ff
 backends/ppc64_unwind.c                |  76 +++++++++++++++++++++++++++++++++
d0b10ff
 tests/ChangeLog                        |  10 +++++
d0b10ff
 tests/Makefile.am                      |   3 ++
d0b10ff
 tests/backtrace-subr.sh                |   2 +-
d0b10ff
 tests/backtrace.ppc64le.fp.core.bz2    | Bin 0 -> 37786 bytes
d0b10ff
 tests/backtrace.ppc64le.fp.exec.bz2    | Bin 0 -> 383808 bytes
d0b10ff
 tests/run-backtrace-fp-core-ppc64le.sh |  29 +++++++++++++
d0b10ff
 10 files changed, 127 insertions(+), 2 deletions(-)
d0b10ff
 create mode 100644 backends/ppc64_unwind.c
d0b10ff
 create mode 100644 tests/backtrace.ppc64le.fp.core.bz2
d0b10ff
 create mode 100755 tests/backtrace.ppc64le.fp.exec.bz2
d0b10ff
 create mode 100755 tests/run-backtrace-fp-core-ppc64le.sh
d0b10ff
d0b10ff
index ff80a82..ac45a45 100644
d0b10ff
--- a/backends/Makefile.am
d0b10ff
+++ b/backends/Makefile.am
d0b10ff
@@ -98,7 +98,7 @@ am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os)
d0b10ff
 
d0b10ff
 ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \
d0b10ff
 	     ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
d0b10ff
-	     ppc_cfi.c ppc_initreg.c ppc64_resolve_sym.c
d0b10ff
+	     ppc_cfi.c ppc_initreg.c ppc64_unwind.c ppc64_resolve_sym.c
d0b10ff
 libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
d0b10ff
 am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
d0b10ff
 
d0b10ff
diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c
d0b10ff
index 11d3a77..e567033 100644
d0b10ff
--- a/backends/ppc64_init.c
d0b10ff
+++ b/backends/ppc64_init.c
d0b10ff
@@ -73,6 +73,7 @@ ppc64_init (Elf *elf __attribute__ ((unused)),
d0b10ff
   eh->frame_nregs = (114 - 1) + 32;
d0b10ff
   HOOK (eh, set_initial_registers_tid);
d0b10ff
   HOOK (eh, dwarf_to_regno);
d0b10ff
+  HOOK (eh, unwind);
d0b10ff
   HOOK (eh, resolve_sym_value);
d0b10ff
 
d0b10ff
   /* Find the function descriptor .opd table for resolve_sym_value.  */
d0b10ff
diff --git a/backends/ppc64_unwind.c b/backends/ppc64_unwind.c
d0b10ff
new file mode 100644
d0b10ff
index 0000000..4fa0b5a
d0b10ff
--- /dev/null
d0b10ff
+++ b/backends/ppc64_unwind.c
d0b10ff
@@ -0,0 +1,76 @@
d0b10ff
+/* Get previous frame state for an existing frame state.
d0b10ff
+   Copyright (C) 2017 Red Hat, Inc.
d0b10ff
+   This file is part of elfutils.
d0b10ff
+
d0b10ff
+   This file is free software; you can redistribute it and/or modify
d0b10ff
+   it under the terms of either
d0b10ff
+
d0b10ff
+     * the GNU Lesser General Public License as published by the Free
d0b10ff
+       Software Foundation; either version 3 of the License, or (at
d0b10ff
+       your option) any later version
d0b10ff
+
d0b10ff
+   or
d0b10ff
+
d0b10ff
+     * the GNU General Public License as published by the Free
d0b10ff
+       Software Foundation; either version 2 of the License, or (at
d0b10ff
+       your option) any later version
d0b10ff
+
d0b10ff
+   or both in parallel, as here.
d0b10ff
+
d0b10ff
+   elfutils is distributed in the hope that it will be useful, but
d0b10ff
+   WITHOUT ANY WARRANTY; without even the implied warranty of
d0b10ff
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d0b10ff
+   General Public License for more details.
d0b10ff
+
d0b10ff
+   You should have received copies of the GNU General Public License and
d0b10ff
+   the GNU Lesser General Public License along with this program.  If
d0b10ff
+   not, see <http://www.gnu.org/licenses/>.  */
d0b10ff
+
d0b10ff
+#ifdef HAVE_CONFIG_H
d0b10ff
+# include <config.h>
d0b10ff
+#endif
d0b10ff
+
d0b10ff
+#define BACKEND ppc64_
d0b10ff
+
d0b10ff
+#define LR_REG 65 /* Not 108, see ppc_dwarf_to_regno.  */
d0b10ff
+#define SP_REG  1
d0b10ff
+
d0b10ff
+#define LR_OFFSET 16
d0b10ff
+
d0b10ff
+#include "libebl_CPU.h"
d0b10ff
+
d0b10ff
+/* Simplistic fallback frame unwinder. SP points to the backchain (contains
d0b10ff
+   address of previous stack pointer). At SP offset 16 is the LR save area
d0b10ff
+   (contains the value of the previous LR).  */
d0b10ff
+
d0b10ff
+bool
d0b10ff
+EBLHOOK(unwind) (Ebl *ebl __attribute__ ((unused)),
d0b10ff
+		 Dwarf_Addr pc __attribute__ ((unused)),
d0b10ff
+                 ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc,
d0b10ff
+                 ebl_pid_memory_read_t *readfunc, void *arg,
d0b10ff
+                 bool *signal_framep __attribute__ ((unused)))
d0b10ff
+{
d0b10ff
+  Dwarf_Word sp, newSp, lr, newLr;
d0b10ff
+
d0b10ff
+  /* Stack pointer points to the backchain which contains the previous sp.  */
d0b10ff
+  if (! getfunc (SP_REG, 1, &sp, arg))
d0b10ff
+    sp = 0;
d0b10ff
+
d0b10ff
+  /* Link register contains previous program counter.  */
d0b10ff
+  if (! getfunc (LR_REG, 1, &lr, arg)
d0b10ff
+      || lr == 0
d0b10ff
+      || ! setfunc (-1, 1, &lr, arg))
d0b10ff
+    return false;
d0b10ff
+
d0b10ff
+  if (! readfunc(sp, &newSp, arg))
d0b10ff
+    newSp = 0;
d0b10ff
+
d0b10ff
+  if (! readfunc(newSp + LR_OFFSET, &newLr, arg))
d0b10ff
+    newLr = 0;
d0b10ff
+
d0b10ff
+  setfunc(SP_REG, 1, &newSp, arg);
d0b10ff
+  setfunc(LR_REG, 1, &newLr, arg);
d0b10ff
+
d0b10ff
+  /* Sanity check the stack grows down.  */
d0b10ff
+  return newSp > sp;
d0b10ff
+}
d0b10ff
diff --git a/tests/Makefile.am b/tests/Makefile.am
d0b10ff
index 3a12fe3..50648db 100644
d0b10ff
--- a/tests/Makefile.am
d0b10ff
+++ b/tests/Makefile.am
d0b10ff
@@ -117,6 +117,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
d0b10ff
 	run-backtrace-native-core-biarch.sh run-backtrace-core-x86_64.sh \
d0b10ff
 	run-backtrace-fp-core-x86_64.sh \
d0b10ff
 	run-backtrace-fp-core-aarch64.sh \
d0b10ff
+	run-backtrace-fp-core-ppc64le.sh \
d0b10ff
 	run-backtrace-core-x32.sh \
d0b10ff
 	run-backtrace-core-i386.sh run-backtrace-fp-core-i386.sh \
d0b10ff
 	run-backtrace-core-ppc.sh \
d0b10ff
@@ -303,6 +304,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
d0b10ff
 	     backtrace-subr.sh backtrace.i386.core.bz2 backtrace.i386.exec.bz2 \
d0b10ff
 	     run-backtrace-fp-core-i386.sh \
d0b10ff
 	     backtrace.i386.fp.core.bz2 backtrace.i386.fp.exec.bz2 \
d0b10ff
+	     run-backtrace-fp-core-ppc64le.sh \
d0b10ff
+	     backtrace.ppc64le.fp.core.bz2 backtrace.ppc64le.fp.exec.bz2 \
d0b10ff
 	     backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2 \
d0b10ff
 	     backtrace.x86_64.fp.core.bz2 backtrace.x86_64.fp.exec.bz2 \
d0b10ff
 	     backtrace.ppc.core.bz2 backtrace.ppc.exec.bz2 \
d0b10ff
diff --git a/tests/backtrace-subr.sh b/tests/backtrace-subr.sh
d0b10ff
index 9731c43..c1f3156 100644
d0b10ff
--- a/tests/backtrace-subr.sh
d0b10ff
+++ b/tests/backtrace-subr.sh
d0b10ff
@@ -59,7 +59,7 @@ check_backtracegen()
d0b10ff
 # Ignore it here as it is a bug of OS, not a bug of elfutils.
d0b10ff
 check_err()
d0b10ff
 {
d0b10ff
-  if [ $(egrep -v <$1 'dwfl_thread_getframes: (No DWARF information found|no matching address range|address out of range|Invalid register)$' \
d0b10ff
+  if [ $(egrep -v <$1 'dwfl_thread_getframes: (No DWARF information found|no matching address range|address out of range|Invalid register|\(null\))$' \
d0b10ff
          | wc -c) \
d0b10ff
        -eq 0 ]
d0b10ff
   then
d0b10ff
diff --git a/tests/run-backtrace-fp-core-ppc64le.sh b/tests/run-backtrace-fp-core-ppc64le.sh
d0b10ff
new file mode 100755
d0b10ff
index 0000000..326ca34
d0b10ff
--- /dev/null
d0b10ff
+++ b/tests/run-backtrace-fp-core-ppc64le.sh
d0b10ff
@@ -0,0 +1,29 @@
d0b10ff
+#! /bin/bash
d0b10ff
+# Copyright (C) 2017 Red Hat, Inc.
d0b10ff
+# This file is part of elfutils.
d0b10ff
+#
d0b10ff
+# This file is free software; you can redistribute it and/or modify
d0b10ff
+# it under the terms of the GNU General Public License as published by
d0b10ff
+# the Free Software Foundation; either version 3 of the License, or
d0b10ff
+# (at your option) any later version.
d0b10ff
+#
d0b10ff
+# elfutils is distributed in the hope that it will be useful, but
d0b10ff
+# WITHOUT ANY WARRANTY; without even the implied warranty of
d0b10ff
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d0b10ff
+# GNU General Public License for more details.
d0b10ff
+#
d0b10ff
+# You should have received a copy of the GNU General Public License
d0b10ff
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
d0b10ff
+
d0b10ff
+. $srcdir/backtrace-subr.sh
d0b10ff
+
d0b10ff
+# The binary is generated by compiling backtrace-child without unwind
d0b10ff
+# information, but with -fno-omit-frame-pointer.
d0b10ff
+#
d0b10ff
+# gcc -static -O2 -fno-omit-frame-pointer -fno-asynchronous-unwind-tables \
d0b10ff
+#     -D_GNU_SOURCE -pthread -o tests/backtrace.ppc64le.fp.exec -I. -Ilib \
d0b10ff
+#     tests/backtrace-child.c
d0b10ff
+#
d0b10ff
+# The core is generated by calling tests/backtrace.ppc64le.fp.exec --gencore
d0b10ff
+
d0b10ff
+check_core ppc64le.fp
d0b10ff
-- 
d0b10ff
1.8.3.1
d0b10ff
d0b10ff
diff -ru elfutils-0.169.orig/backends/Makefile.in elfutils-0.169/backends/Makefile.in
d0b10ff
--- elfutils-0.169.orig/backends/Makefile.in	2017-05-30 21:43:28.725454717 +0200
d0b10ff
+++ elfutils-0.169/backends/Makefile.in	2017-05-30 21:43:55.681944556 +0200
d0b10ff
@@ -159,7 +159,7 @@
d0b10ff
 	ppc64_retval.$(OBJEXT) ppc64_corenote.$(OBJEXT) \
d0b10ff
 	ppc_regs.$(OBJEXT) ppc_auxv.$(OBJEXT) ppc_attrs.$(OBJEXT) \
d0b10ff
 	ppc_syscall.$(OBJEXT) ppc_cfi.$(OBJEXT) ppc_initreg.$(OBJEXT) \
d0b10ff
-	ppc64_resolve_sym.$(OBJEXT)
d0b10ff
+	ppc64_unwind.$(OBJEXT) ppc64_resolve_sym.$(OBJEXT)
d0b10ff
 libebl_ppc64_pic_a_OBJECTS = $(am_libebl_ppc64_pic_a_OBJECTS)
d0b10ff
 libebl_ppc_pic_a_AR = $(AR) $(ARFLAGS)
d0b10ff
 libebl_ppc_pic_a_LIBADD =
d0b10ff
@@ -505,7 +505,7 @@
d0b10ff
 am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os)
d0b10ff
 ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \
d0b10ff
 	     ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \
d0b10ff
-	     ppc_cfi.c ppc_initreg.c ppc64_resolve_sym.c
d0b10ff
+	     ppc_cfi.c ppc_initreg.c ppc64_unwind.c ppc64_resolve_sym.c
d0b10ff
 
d0b10ff
 libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS)
d0b10ff
 am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os)
d0b10ff
@@ -696,6 +696,7 @@
d0b10ff
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc64_resolve_sym.Po@am__quote@
d0b10ff
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc64_retval.Po@am__quote@
d0b10ff
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc64_symbol.Po@am__quote@
d0b10ff
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc64_unwind.Po@am__quote@
d0b10ff
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc_attrs.Po@am__quote@
d0b10ff
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc_auxv.Po@am__quote@
d0b10ff
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppc_cfi.Po@am__quote@
d0b10ff
diff -ru elfutils-0.169.orig/tests/Makefile.in elfutils-0.169/tests/Makefile.in
d0b10ff
--- elfutils-0.169.orig/tests/Makefile.in	2017-05-30 21:43:28.743454377 +0200
d0b10ff
+++ elfutils-0.169/tests/Makefile.in	2017-05-30 21:43:56.191934904 +0200
d0b10ff
@@ -174,7 +174,8 @@
d0b10ff
 	run-backtrace-native-biarch.sh run-backtrace-native-core.sh \
d0b10ff
 	run-backtrace-native-core-biarch.sh \
d0b10ff
 	run-backtrace-core-x86_64.sh run-backtrace-fp-core-x86_64.sh \
d0b10ff
-	run-backtrace-fp-core-aarch64.sh run-backtrace-core-x32.sh \
d0b10ff
+	run-backtrace-fp-core-aarch64.sh \
d0b10ff
+	run-backtrace-fp-core-ppc64le.sh run-backtrace-core-x32.sh \
d0b10ff
 	run-backtrace-core-i386.sh run-backtrace-fp-core-i386.sh \
d0b10ff
 	run-backtrace-core-ppc.sh run-backtrace-core-s390x.sh \
d0b10ff
 	run-backtrace-core-s390.sh run-backtrace-core-aarch64.sh \
d0b10ff
@@ -1174,6 +1175,8 @@
d0b10ff
 	     backtrace-subr.sh backtrace.i386.core.bz2 backtrace.i386.exec.bz2 \
d0b10ff
 	     run-backtrace-fp-core-i386.sh \
d0b10ff
 	     backtrace.i386.fp.core.bz2 backtrace.i386.fp.exec.bz2 \
d0b10ff
+	     run-backtrace-fp-core-ppc64le.sh \
d0b10ff
+	     backtrace.ppc64le.fp.core.bz2 backtrace.ppc64le.fp.exec.bz2 \
d0b10ff
 	     backtrace.x86_64.core.bz2 backtrace.x86_64.exec.bz2 \
d0b10ff
 	     backtrace.x86_64.fp.core.bz2 backtrace.x86_64.fp.exec.bz2 \
d0b10ff
 	     backtrace.ppc.core.bz2 backtrace.ppc.exec.bz2 \
d0b10ff
@@ -2924,6 +2927,13 @@
d0b10ff
 	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
d0b10ff
 	--log-file $$b.log --trs-file $$b.trs \
d0b10ff
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
d0b10ff
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
d0b10ff
+run-backtrace-fp-core-ppc64le.sh.log: run-backtrace-fp-core-ppc64le.sh
d0b10ff
+	@p='run-backtrace-fp-core-ppc64le.sh'; \
d0b10ff
+	b='run-backtrace-fp-core-ppc64le.sh'; \
d0b10ff
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
d0b10ff
+	--log-file $$b.log --trs-file $$b.trs \
d0b10ff
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
d0b10ff
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
d0b10ff
 run-backtrace-core-x32.sh.log: run-backtrace-core-x32.sh
d0b10ff
 	@p='run-backtrace-core-x32.sh'; \