[PATCH] Fix PPC non-CFI + CFI unwinding (incomplete in HEAD)

Jan Kratochvil
2007-01-13T09:31:02Z

[-- Attachment #1: Type: text/plain, Size: 802 bytes --]

Hi,

attached patches unfortunately still do not fix the upstream gdb regarding
"-pie" code as there are more PPC patches in the Red Hat gdb fork.
Posting FYI as the Red Hat gdb fork started properly unwinding all the tested
combinations.

The testcase unfortunately does not test all the code possibilities.
It was tested on some `evolution' backtrace unwinding also Gnome libraries.

Providing FYI as the complete PPC gdb functionality would need resubmitting and
reviewing the other Red Hat PPC patches (not mine). Upon request.

The code needs to first accept Andreas Schwab's patch
http://sourceware.org/ml/gdb-patches/2006-05/msg00166.html
I believe it have not happened due to the Mark Kettenis's pending OS review:
http://sourceware.org/ml/gdb-patches/2006-05/msg00341.html

Regards,
Jan

[-- Attachment #2: gdb-6.3-bz140532-ppcnoncfi-skip_prologue-PIC.patch --]
[-- Type: text/plain, Size: 1718 bytes --]

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=140532

2007-01-01 Jan Kratochvil <jan.kratochvil@redhat.com>

* rs6000-tdep.c (skip_prologue): Handle bl->brlr used by PIC code.

diff -u -rup gdb-6.5-orig/gdb/rs6000-tdep.c gdb-6.5/gdb/rs6000-tdep.c
--- gdb-6.5-orig/gdb/rs6000-tdep.c 2006-12-30 15:53:52.000000000 -0500
+++ gdb-6.5/gdb/rs6000-tdep.c 2006-12-31 19:06:28.000000000 -0500
@@ -1182,6 +1182,40 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
else if ((op & 0xfc000001) == 0x48000001)
{ /* bl foo,
to save fprs??? */
+ CORE_ADDR bl_target;
+ gdb_byte bl_target_op_buf[4];
+
+ /* Safely skip:
+ prologue: ...
+ bl addr
+ ...
+ addr: blrl
+ as it could break the prologue by `prologue_sal.line'
+ or `prologue_sal.line != this_sal.line' conditions below. */
+ /* Sign-extend it to the upper 6 bits. */
+ if (op & 0x02000000)
+ bl_target = pc + -(long) (((~op) & 0x03fffffc) + 4);
+ else
+ bl_target = pc + (op & 0x03fffffc);
+ if (target_read_memory (bl_target, bl_target_op_buf, 4) == 0)
+ {
+ unsigned long bl_target_op;
+
+ bl_target_op = extract_signed_integer (bl_target_op_buf, 4);
+ if (bl_target_op == 0x4e800021) /* blrl */
+ {
+ /* If we did not yet retrieved LR into some GPR
+ all our chances are lost. On the other hand already
+ stored LR is still kept intact in its GPR. */
+ if (lr_reg == -1)
+ {
+ /* Invalidate lr_reg, but don't set it to -1.
+ That would mean that it had never been set. */
+ lr_reg = -2;
+ }
+ continue;
+ }
+ }

fdata->frameless = 0;
/* Don't skip over the subroutine call if it is not within

[-- Attachment #3: gdb-6.5-bz140532-ppc-debug_frame-return_address.patch --]
[-- Type: text/plain, Size: 5196 bytes --]

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=140532

2007-01-13 Jan Kratochvil <jan.kratochvil@redhat.com>

* dwarf2-frame.c (decode_frame_entry_1): Call
dwarf2_frame_return_address_regnum when processing CIE return address.
(struct dwarf2_frame_ops): Add return_address_regnum.
(dwarf2_frame_set_return_address_regnum): Define.
(dwarf2_frame_return_address_regnum): Define.
* dwarf2-frame.h (dwarf2_frame_set_return_address_regnum): Declare.
(dwarf2_frame_return_address_regnum): Declare.
* rs6000-tdep.c (rs6000_dwarf2_reg_to_regnum): Map also 64(CR) and
65(FPSCR) DWARF2 registers.
(rs6000_return_address_regnum): Define.
(rs6000_gdbarch_init): Register rs6000_return_address_regnum.

--- gdb-6.5-ppc/gdb/dwarf2-frame.c 2007-01-12 14:40:32.000000000 -0500
+++ gdb-6.5/gdb/dwarf2-frame.c 2007-01-12 18:46:32.000000000 -0500
@@ -586,6 +586,10 @@ struct dwarf2_frame_ops

/* Convert .eh_frame register number to DWARF register number. */
int (*eh_frame_regnum) (struct gdbarch *, int);
+
+ /* Convert .eh_frame/.debug_frame CIE return address register number to DWARF
+ register number. */
+ int (*return_address_regnum) (struct gdbarch *, int, int);
};

/* Default architecture-specific register state initialization
@@ -693,6 +697,32 @@ dwarf2_frame_signal_frame_p (struct gdba
return ops->signal_frame_p (gdbarch, next_frame);
}

+/* Set the architecture-specific mapping of .eh_frame/.debug_frame CIE return
+ address register number to DWARF register number. */
+
+void
+dwarf2_frame_set_return_address_regnum (struct gdbarch *gdbarch,
+ int (*return_address_regnum)
+ (struct gdbarch *, int, int))
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ ops->return_address_regnum = return_address_regnum;
+}
+
+/* Translate a .eh_frame/.debug_frame CIE register to DWARF register. */
+
+int
+dwarf2_frame_return_address_regnum (struct gdbarch *gdbarch, int regnum,
+ int eh_frame_p)
+{
+ struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
+
+ if (ops->return_address_regnum == NULL)
+ return regnum;
+ return ops->return_address_regnum (gdbarch, regnum, eh_frame_p);
+}
+
/* Set the architecture-specific mapping of .eh_frame register numbers to
DWARF register numbers. */

@@ -1618,6 +1648,11 @@ decode_frame_entry_1 (struct comp_unit *
else
cie->return_address_register = read_unsigned_leb128 (unit->abfd, buf,
&bytes_read);
+
+ cie->return_address_register
+ = dwarf2_frame_return_address_regnum (current_gdbarch,
+ cie->return_address_register,
+ eh_frame_p);
if (eh_frame_p)
cie->return_address_register
= dwarf2_frame_eh_frame_regnum (current_gdbarch,
--- gdb-6.5-ppc/gdb/dwarf2-frame.h 2007-01-12 14:40:32.000000000 -0500
+++ gdb-6.5/gdb/dwarf2-frame.h 2007-01-12 18:36:47.000000000 -0500
@@ -107,6 +107,20 @@ extern void
extern int
dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum);

+/* Set the architecture-specific mapping of .eh_frame/.debug_frame CIE return
+ address register number to DWARF register number. */
+
+extern void
+ dwarf2_frame_set_return_address_regnum (struct gdbarch *gdbarch,
+ int (*return_address_regnum)
+ (struct gdbarch *, int, int));
+
+/* Translate a .eh_frame/.debug_frame CIE register to DWARF register. */
+
+extern int
+ dwarf2_frame_return_address_regnum (struct gdbarch *gdbarch, int regnum,
+ int eh_frame_p);
+
/* Return the frame unwind methods for the function that contains PC,
or NULL if it can't be handled by DWARF CFI frame unwinder. */

--- gdb-6.5-ppc/gdb/rs6000-tdep.c 2007-01-12 14:40:32.000000000 -0500
+++ gdb-6.5/gdb/rs6000-tdep.c 2007-01-12 18:44:21.000000000 -0500
@@ -2307,6 +2307,11 @@ rs6000_dwarf2_reg_to_regnum (int num)
else
switch (num)
{
+ case 64:
+ return tdep->ppc_cr_regnum;
+ /* Broken GCC uses it for CIE `Return address column' as LR. */
+ case 65:
+ return tdep->ppc_fpscr_regnum;
case 67:
return tdep->ppc_vrsave_regnum - 1; /* vscr */
case 99:
@@ -2363,6 +2368,22 @@ rs6000_eh_frame_regnum (struct gdbarch *
}
}

+/* Convert a .eh_frame/.debug_frame CIE return address register number to DWARF
+ register number. */
+static int
+rs6000_return_address_regnum (struct gdbarch *gdbarch, int regnum,
+ int eh_frame_p)
+{
+ if (eh_frame_p != 0)
+ return regnum;
+
+ /* Broken GCC uses it for CIE `Return address column' as LR. */
+ if (regnum == 65)
+ return 108;
+
+ return regnum;
+}
+
static void
rs6000_store_return_value (struct type *type,
struct regcache *regcache,
@@ -3584,6 +3605,8 @@ rs6000_gdbarch_init (struct gdbarch_info
/* Hook in the DWARF CFI frame unwinder. */
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
dwarf2_frame_set_eh_frame_regnum (gdbarch, rs6000_eh_frame_regnum);
+ dwarf2_frame_set_return_address_regnum (gdbarch,
+ rs6000_return_address_regnum);

/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);

[-- Attachment #4: gdb-6.5-bz140532-ppc-debug_frame-return_address-test.patch --]
[-- Type: text/plain, Size: 4511 bytes --]

2007-01-13 Jan Kratochvil <jan.kratochvil@redhat.com>

* gdb.base/bt-ppc.c, gdb.base/bt-ppc.exp: New files.

diff -u -rupN gdb-6.5-ppc/gdb/testsuite/gdb.base/bt-ppc.c gdb-6.5/gdb/testsuite/gdb.base/bt-ppc.c
--- gdb-6.5-ppc/gdb/testsuite/gdb.base/bt-ppc.c 1969-12-31 19:00:00.000000000 -0500
+++ gdb-6.5/gdb/testsuite/gdb.base/bt-ppc.c 2007-01-12 21:34:55.000000000 -0500
@@ -0,0 +1,41 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2007 Free Software Foundation, Inc.
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <stdlib.h>
+
+/* Force `-fpie' double jump bl->blrl. */
+volatile int var;
+
+int func0 (void) __attribute__((__noinline__));
+int func0 (void)
+{
+ abort ();
+ return var;
+}
+
+int func1 (void) __attribute__((__noinline__));
+int func1 (void)
+{
+ return func0 () + var;
+}
+
+int main (void)
+{
+ func1 ();
+ return 0;
+}
diff -u -rupN gdb-6.5-ppc/gdb/testsuite/gdb.base/bt-ppc.exp gdb-6.5/gdb/testsuite/gdb.base/bt-ppc.exp
--- gdb-6.5-ppc/gdb/testsuite/gdb.base/bt-ppc.exp 1969-12-31 19:00:00.000000000 -0500
+++ gdb-6.5/gdb/testsuite/gdb.base/bt-ppc.exp 2007-01-12 21:27:25.000000000 -0500
@@ -0,0 +1,86 @@
+# Copyright 2006, 2007 Free Software Foundation, Inc.
+
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Test multiple unwinding fixes of PPC platform.
+# As the tests are platform independent we can run it everywhere.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+# This test uses GCC-specific syntax.
+if [get_compiler_info not-used] {
+ return -1
+}
+
+if {![test_compiler_info "gcc-*"]} {
+ return 0
+}
+
+proc do_test { opts addons } {
+ global objdir srcdir subdir gdb_prompt
+
+ set testfile "bt-ppc"
+ set srcfile ${testfile}.c
+ set binfile ${objdir}/${subdir}/${testfile}
+
+ # `additional_flags' should be last as it eats arguments till eol.
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" ${binfile} executable [list $opts additional_flags=$addons]] != ""} {
+ return -1
+ }
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ # We should stop in abort(3).
+
+ gdb_run_cmd
+
+ gdb_test_multiple {} "continue to abort()" {
+ -re ".*Program received signal SIGABRT,.*$gdb_prompt $" {
+ pass "continue to abort()"
+ }
+ }
+
+ # Check backtrace:
+ # #3 0x0804835f in func0 ()
+ # #4 0x0804836a in func1 ()
+ # #5 0x0804838c in main ()
+ # (gdb)
+ # `\\.?' prefixes are needed for ppc64 without `debug' (another bug).
+
+ set show [concat $opts $addons]
+ gdb_test_multiple "bt" "Correct unwind for: $show" {
+ -re "\r\n#\[0-9\]\[^\r\n\]* in \\.?func0 \\(\[^\r\n\]*\r\n#\[0-9\]\[^\r\n\]* in \\.?func1 \\(\[^\r\n\]*\r\n#\[0-9\]\[^\r\n\]* in \\.?main \\(\[^\r\n\]*\r\n$gdb_prompt $" {
+ pass "Correct unwind for: $show"
+ }
+ }
+}
+
+foreach eh_frame {{-fno-asynchronous-unwind-tables}
+ {-fasynchronous-unwind-tables}} {
+ foreach pie {{} {-fpie -pie}} {
+ foreach optim {{} {-O2}} {
+ foreach is_debug {{} {debug}} {
+ do_test $is_debug [concat $eh_frame $pie $optim]
+ }
+ }
+ }
+}