* [patch] Support -fsplit-stack (previous frame inner to this frame)
@ 2010-11-23 0:13 Jan Kratochvil
2010-11-23 0:34 ` Doug Evans
0 siblings, 1 reply; 8+ messages in thread
From: Jan Kratochvil @ 2010-11-23 0:13 UTC (permalink / raw)
To: gdb-patches; +Cc: Ian Lance Taylor
Hi,
currently on a code with gcc -fsplit-stack `backtrace' does not work (after
the stack gets split):
(gdb) bt
#0 down (i=499) at split.c:36
#1 0x0000000000400e74 in __morestack () at ../../../gcchead/libgcc/config/i386/morestack.S:374
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
There were some intentions to remove frame_id_inner at all but then many
corrupt stacks would backtrace indefinitely. Moreover as the current stop
PC==0 should be removed one day for corrupted backtraces unwinding (PR by me
backtrace/12237).
I had an idea to instead create non-NORMAL_FRAME by a separate sniffer like
currently present in inline-frame.c. The problem is unwinders currently
cannot easily chain for a single frame. And this unwinder specific for the
__morestack function needs to do standard DWARF frame unwinding. Chaining
directly to dwarf2_frame_prev_register&co. is also not right as the code can
be compiled for example with STABS instead.
Maybe a proper unwinders chaining gets implemented one day (hacked in one for
archer-jankratochvil-entryval) but for now I find this hack acceptable myself.
Do you?
No regressions on {x86_64,x86_64-m32,i686}-fedora14-linux-gnu. But the
testcase works for me only for GCC HEAD on Fedora 14 (+not on Fedora 13),
tested it there on x86_64 and x86_64-m32.
Thanks,
Jan
gdb/
2010-11-23 Jan Kratochvil <jan.kratochvil@redhat.com>
* frame.c (morestack_start, morestack_end, frame_new_objfile): New.
(frame_id_inner): Check l.code_addr against them.
(_initialize_frame): Install frame_new_objfile).
gdb/testsuite/
2010-11-23 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/morestack.exp: New file.
* gdb.base/morestack.c: New file.
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -487,6 +487,30 @@ frame_id_eq (struct frame_id l, struct frame_id r)
return eq;
}
+/* Start and end of the `__morestack' function. MORESTACK_END address is the
+ end plus one (exclusive) one. */
+static CORE_ADDR morestack_start, morestack_end;
+
+/* Initialize MORESTACK_START and MORESTACK_END, provided as a cache. */
+
+static void
+frame_new_objfile (struct objfile *objfile)
+{
+ struct minimal_symbol *msymbol;
+
+ morestack_start = morestack_end = 0;
+
+ msymbol = lookup_minimal_symbol ("__morestack", NULL, NULL);
+ if (msymbol == NULL)
+ return;
+
+ morestack_start = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+
+ morestack_end = morestack_start + MSYMBOL_SIZE (msymbol);
+}
+
/* Safety net to check whether frame ID L should be inner to
frame ID R, according to their stack addresses.
@@ -550,6 +574,12 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
block with the greater depth. */
inner = contained_in (lb, rb);
}
+ else if (l.code_addr_p && morestack_start <= l.code_addr
+ && l.code_addr < morestack_end)
+ {
+ /* gcc -fsplit-stack __morestack can continue the stack anywhere. */
+ inner = 0;
+ }
else
/* Only return non-zero when strictly inner than. Note that, per
comment in "frame.h", there is some fuzz here. Frameless
@@ -2218,6 +2248,7 @@ _initialize_frame (void)
obstack_init (&frame_cache_obstack);
observer_attach_target_changed (frame_observer_target_changed);
+ observer_attach_new_objfile (frame_new_objfile);
add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
Set backtrace specific variables.\n\
--- /dev/null
+++ b/gdb/testsuite/gdb.base/morestack.c
@@ -0,0 +1,105 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* Based on the gcc testcase `gcc/testsuite/gcc.dg/split-1.c'. This test
+ needs to use setrlimit to set the stack size, so it can only run on Unix.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+/* Use a noinline function to ensure that the buffer is not removed
+ from the stack. */
+static void use_buffer (char *buf) __attribute__ ((noinline));
+static void
+use_buffer (char *buf)
+{
+ buf[0] = '\0';
+}
+
+static volatile int marker_var;
+
+static void
+marker_miss (void)
+{
+ marker_var = 0;
+}
+
+static void
+marker_hit (void)
+{
+ marker_var = 0;
+}
+
+void *reserved;
+#define RESERVED_SIZE 0x1000000
+
+/* Each recursive call uses 10,000 bytes. We call it 1000 times,
+ using a total of 10,000,000 bytes. If -fsplit-stack is not
+ working, that will overflow our stack limit. */
+
+static void
+down (int i)
+{
+ char buf[10000];
+ static void *last;
+
+ if (last && last < (void *) buf)
+ {
+ printf ("%d: %p < %p\n", i, last, buf);
+ marker_hit ();
+ }
+ last = buf;
+
+ if (i == 500)
+ {
+ if (munmap (reserved, RESERVED_SIZE) != 0)
+ abort ();
+ reserved = NULL;
+ }
+
+ if (i > 0)
+ {
+ use_buffer (buf);
+ down (i - 1);
+ }
+ else
+ marker_miss ();
+}
+
+int
+main (void)
+{
+ struct rlimit r;
+
+ reserved = mmap (NULL, RESERVED_SIZE, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (reserved == MAP_FAILED)
+ abort ();
+
+ /* We set a stack limit because we are usually invoked via make, and
+ make sets the stack limit to be as large as possible. */
+ r.rlim_cur = 8192 * 1024;
+ r.rlim_max = 8192 * 1024;
+ if (setrlimit (RLIMIT_STACK, &r) != 0)
+ abort ();
+ down (1000);
+ return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/morestack.exp
@@ -0,0 +1,52 @@
+# Copyright (C) 2010 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 3 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, see <http://www.gnu.org/licenses/>.
+
+if [get_compiler_info "ignored"] {
+ return -1
+}
+
+if {$gcc_compiled == 0} {
+ return -1
+}
+
+set testfile morestack
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c {additional_flags=-fsplit-stack}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint "marker_hit"
+gdb_breakpoint "marker_miss"
+
+set test "continue"
+gdb_test_multiple $test $test {
+ -re "marker_hit.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "marker_miss.*$gdb_prompt $" {
+ # The testcase failed to violated the frame_id_inner condition by
+ # handing inner frame with higher (on the stack-grows-down arches)
+ # $sp address than the outer frame.
+ xfail $test
+ return 0
+ }
+}
+
+# FAIL was on `bt' producing:
+# Backtrace stopped: previous frame inner to this frame (corrupt stack?)
+gdb_test "up 3000" " in main .*"
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-23 0:13 [patch] Support -fsplit-stack (previous frame inner to this frame) Jan Kratochvil
@ 2010-11-23 0:34 ` Doug Evans
2010-11-23 2:12 ` Jan Kratochvil
0 siblings, 1 reply; 8+ messages in thread
From: Doug Evans @ 2010-11-23 0:34 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, Ian Lance Taylor
On Mon, Nov 22, 2010 at 4:13 PM, Jan Kratochvil
<jan.kratochvil@redhat.com> wrote:
> Hi,
>
> currently on a code with gcc -fsplit-stack `backtrace' does not work (after
> the stack gets split):
>
> (gdb) bt
> #0 down (i=499) at split.c:36
> #1 0x0000000000400e74 in __morestack () at ../../../gcchead/libgcc/config/i386/morestack.S:374
> Backtrace stopped: previous frame inner to this frame (corrupt stack?)
>
> There were some intentions to remove frame_id_inner at all but then many
> corrupt stacks would backtrace indefinitely. Moreover as the current stop
> PC==0 should be removed one day for corrupted backtraces unwinding (PR by me
> backtrace/12237).
>
> I had an idea to instead create non-NORMAL_FRAME by a separate sniffer like
> currently present in inline-frame.c. The problem is unwinders currently
> cannot easily chain for a single frame. And this unwinder specific for the
> __morestack function needs to do standard DWARF frame unwinding. Chaining
> directly to dwarf2_frame_prev_register&co. is also not right as the code can
> be compiled for example with STABS instead.
>
> Maybe a proper unwinders chaining gets implemented one day (hacked in one for
> archer-jankratochvil-entryval) but for now I find this hack acceptable myself.
> Do you?
>
> No regressions on {x86_64,x86_64-m32,i686}-fedora14-linux-gnu. But the
> testcase works for me only for GCC HEAD on Fedora 14 (+not on Fedora 13),
> tested it there on x86_64 and x86_64-m32.
>
>
> Thanks,
> Jan
>
>
> gdb/
> 2010-11-23 Jan Kratochvil <jan.kratochvil@redhat.com>
>
> * frame.c (morestack_start, morestack_end, frame_new_objfile): New.
> (frame_id_inner): Check l.code_addr against them.
> (_initialize_frame): Install frame_new_objfile).
Nit: Do we have the framework for recording these globals per process?
[or some such - e.g. if/when gdb can debug multiple different
programs]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-23 0:34 ` Doug Evans
@ 2010-11-23 2:12 ` Jan Kratochvil
2010-11-23 20:41 ` Tom Tromey
0 siblings, 1 reply; 8+ messages in thread
From: Jan Kratochvil @ 2010-11-23 2:12 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches, Ian Lance Taylor
On Tue, 23 Nov 2010 01:34:12 +0100, Doug Evans wrote:
> Nit: Do we have the framework for recording these globals per process?
> [or some such - e.g. if/when gdb can debug multiple different
> programs]
Oops.
Thanks,
Jan
gdb/
2010-11-23 Jan Kratochvil <jan.kratochvil@redhat.com>
* frame.c (frame_inferior_data, struct frame_inferior_data)
(frame_inferior_data_cleanup, frame_inferior_data_get)
(frame_new_objfile): New.
(frame_id_inner): New variable inf_data. Check l.code_addr with
MORESTACK_START and MORESTACK_END.
(_initialize_frame): Install frame_new_objfile). Initialize
frame_inferior_data.
gdb/testsuite/
2010-11-23 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/morestack.exp: New file.
* gdb.base/morestack.c: New file.
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -155,6 +155,40 @@ frame_stash_find (struct frame_id id)
return NULL;
}
+/* Per-inferior data key. */
+static const struct inferior_data *frame_inferior_data;
+
+struct frame_inferior_data
+ {
+ /* Start and end of the `__morestack' function. MORESTACK_END address is
+ the end plus one (exclusive) one. */
+
+ CORE_ADDR morestack_start, morestack_end;
+ };
+
+static void
+frame_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+ struct frame_inferior_data *inf_data = arg;
+
+ xfree (inf_data);
+}
+
+static struct frame_inferior_data *
+frame_inferior_data_get (void)
+{
+ struct frame_inferior_data *inf_data;
+
+ inf_data = inferior_data (current_inferior (), frame_inferior_data);
+ if (inf_data == NULL)
+ {
+ inf_data = xzalloc (sizeof (*inf_data));
+ set_inferior_data (current_inferior (), frame_inferior_data, inf_data);
+ }
+
+ return inf_data;
+}
+
/* Invalidate the frame stash by removing all entries in it. */
static void
@@ -487,6 +521,29 @@ frame_id_eq (struct frame_id l, struct frame_id r)
return eq;
}
+/* Initialize MORESTACK_START and MORESTACK_END. */
+
+static void
+frame_new_objfile (struct objfile *objfile)
+{
+ struct frame_inferior_data *inf_data = frame_inferior_data_get ();
+ struct minimal_symbol *msymbol;
+
+ inf_data->morestack_start = inf_data->morestack_end = 0;
+
+ msymbol = lookup_minimal_symbol ("__morestack", NULL, NULL);
+ if (msymbol == NULL)
+ return;
+
+ inf_data->morestack_start
+ = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
+ SYMBOL_VALUE_ADDRESS (msymbol),
+ ¤t_target);
+
+ inf_data->morestack_end = (inf_data->morestack_start
+ + MSYMBOL_SIZE (msymbol));
+}
+
/* Safety net to check whether frame ID L should be inner to
frame ID R, according to their stack addresses.
@@ -522,6 +579,7 @@ frame_id_eq (struct frame_id l, struct frame_id r)
static int
frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
{
+ struct frame_inferior_data *inf_data = frame_inferior_data_get ();
int inner;
if (!l.stack_addr_p || !r.stack_addr_p)
@@ -550,6 +608,12 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
block with the greater depth. */
inner = contained_in (lb, rb);
}
+ else if (l.code_addr_p && inf_data->morestack_start <= l.code_addr
+ && l.code_addr < inf_data->morestack_end)
+ {
+ /* gcc -fsplit-stack __morestack can continue the stack anywhere. */
+ inner = 0;
+ }
else
/* Only return non-zero when strictly inner than. Note that, per
comment in "frame.h", there is some fuzz here. Frameless
@@ -2218,6 +2282,7 @@ _initialize_frame (void)
obstack_init (&frame_cache_obstack);
observer_attach_target_changed (frame_observer_target_changed);
+ observer_attach_new_objfile (frame_new_objfile);
add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
Set backtrace specific variables.\n\
@@ -2275,4 +2340,7 @@ When non-zero, frame specific internal debugging is enabled."),
NULL,
show_frame_debug,
&setdebuglist, &showdebuglist);
+
+ frame_inferior_data
+ = register_inferior_data_with_cleanup (frame_inferior_data_cleanup);
}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/morestack.c
@@ -0,0 +1,105 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* Based on the gcc testcase `gcc/testsuite/gcc.dg/split-1.c'. This test
+ needs to use setrlimit to set the stack size, so it can only run on Unix.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+/* Use a noinline function to ensure that the buffer is not removed
+ from the stack. */
+static void use_buffer (char *buf) __attribute__ ((noinline));
+static void
+use_buffer (char *buf)
+{
+ buf[0] = '\0';
+}
+
+static volatile int marker_var;
+
+static void
+marker_miss (void)
+{
+ marker_var = 0;
+}
+
+static void
+marker_hit (void)
+{
+ marker_var = 0;
+}
+
+void *reserved;
+#define RESERVED_SIZE 0x1000000
+
+/* Each recursive call uses 10,000 bytes. We call it 1000 times,
+ using a total of 10,000,000 bytes. If -fsplit-stack is not
+ working, that will overflow our stack limit. */
+
+static void
+down (int i)
+{
+ char buf[10000];
+ static void *last;
+
+ if (last && last < (void *) buf)
+ {
+ printf ("%d: %p < %p\n", i, last, buf);
+ marker_hit ();
+ }
+ last = buf;
+
+ if (i == 500)
+ {
+ if (munmap (reserved, RESERVED_SIZE) != 0)
+ abort ();
+ reserved = NULL;
+ }
+
+ if (i > 0)
+ {
+ use_buffer (buf);
+ down (i - 1);
+ }
+ else
+ marker_miss ();
+}
+
+int
+main (void)
+{
+ struct rlimit r;
+
+ reserved = mmap (NULL, RESERVED_SIZE, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (reserved == MAP_FAILED)
+ abort ();
+
+ /* We set a stack limit because we are usually invoked via make, and
+ make sets the stack limit to be as large as possible. */
+ r.rlim_cur = 8192 * 1024;
+ r.rlim_max = 8192 * 1024;
+ if (setrlimit (RLIMIT_STACK, &r) != 0)
+ abort ();
+ down (1000);
+ return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/morestack.exp
@@ -0,0 +1,52 @@
+# Copyright (C) 2010 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 3 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, see <http://www.gnu.org/licenses/>.
+
+if [get_compiler_info "ignored"] {
+ return -1
+}
+
+if {$gcc_compiled == 0} {
+ return -1
+}
+
+set testfile morestack
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c {additional_flags=-fsplit-stack}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint "marker_hit"
+gdb_breakpoint "marker_miss"
+
+set test "continue"
+gdb_test_multiple $test $test {
+ -re "marker_hit.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "marker_miss.*$gdb_prompt $" {
+ # The testcase failed to violated the frame_id_inner condition by
+ # handing inner frame with higher (on the stack-grows-down arches)
+ # $sp address than the outer frame.
+ xfail $test
+ return 0
+ }
+}
+
+# FAIL was on `bt' producing:
+# Backtrace stopped: previous frame inner to this frame (corrupt stack?)
+gdb_test "up 3000" " in main .*"
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-23 2:12 ` Jan Kratochvil
@ 2010-11-23 20:41 ` Tom Tromey
2010-11-23 22:38 ` Ian Lance Taylor
2010-11-24 0:29 ` Jan Kratochvil
0 siblings, 2 replies; 8+ messages in thread
From: Tom Tromey @ 2010-11-23 20:41 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Doug Evans, gdb-patches, Ian Lance Taylor
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> + /* Start and end of the `__morestack' function. MORESTACK_END address is
Jan> + the end plus one (exclusive) one. */
One of the "one"s seems redundant.
Jan> + CORE_ADDR morestack_start, morestack_end;
Is it impossible for __morestack to appear in multiple objfiles? What
if you have a program that dlmopen()s two versions of the shared library
defining it? I don't know how strict we want to be about this kind of
thing -- we don't actually support dlmopen in any meaningful way right
now anyway.
I think this would also need to hook into objfile_relocate.
A new frame type seems like an ok idea.
I don't mind this approach, though I'm also interested to hear what
others think.
Tom
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-23 20:41 ` Tom Tromey
@ 2010-11-23 22:38 ` Ian Lance Taylor
2010-11-24 0:29 ` Jan Kratochvil
1 sibling, 0 replies; 8+ messages in thread
From: Ian Lance Taylor @ 2010-11-23 22:38 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, Doug Evans, gdb-patches
Tom Tromey <tromey@redhat.com> writes:
> Is it impossible for __morestack to appear in multiple objfiles?
The __morestack function has hidden visibility when using ELF, so if
both the executable and a shared library are compiled with -fsplit-stack
they will each have their own copy of __morestack.
Ian
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-23 20:41 ` Tom Tromey
2010-11-23 22:38 ` Ian Lance Taylor
@ 2010-11-24 0:29 ` Jan Kratochvil
2010-11-24 18:34 ` Tom Tromey
1 sibling, 1 reply; 8+ messages in thread
From: Jan Kratochvil @ 2010-11-24 0:29 UTC (permalink / raw)
To: Tom Tromey, Ian Lance Taylor; +Cc: Doug Evans, gdb-patches
On Tue, 23 Nov 2010 21:40:49 +0100, Tom Tromey wrote:
> A new frame type seems like an ok idea.
Maybe later if this patch still has concerns. The chaining of frames
complication may not be worth it.
On Tue, 23 Nov 2010 23:38:11 +0100, Ian Lance Taylor wrote:
> The __morestack function has hidden visibility when using ELF, so if
> both the executable and a shared library are compiled with -fsplit-stack
> they will each have their own copy of __morestack.
That optimization makes no sense there:
* This check is done only in the error case.
(For frame_find_by_id it does not seem to be needed.)
* Frames are already cached.
* Symbols are already looked up for the PC when printing the frame.
* Frame is not resolved until it needs to be printed.
* Any lookup caching should be done rather in the symbols lookup code anyway.
No regressions on {x86_64,x86_64-m32,i686}-fedora14-linux-gnu.
Thanks,
Jan
gdb/
2010-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>
* frame.c (get_prev_frame_1) <UNWIND_INNER_ID>: New variables
this_pc_in_block, morestack_msym and morestack_name. Check for
"__morestack" minimal symbol there.
gdb/testsuite/
2010-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/morestack.exp: New file.
* gdb.base/morestack.c: New file.
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1501,14 +1501,26 @@ get_prev_frame_1 (struct frame_info *this_frame)
&& frame_id_inner (get_frame_arch (this_frame->next), this_id,
get_frame_id (this_frame->next)))
{
- if (frame_debug)
+ CORE_ADDR this_pc_in_block;
+ struct minimal_symbol *morestack_msym;
+ const char *morestack_name = NULL;
+
+ /* gcc -fsplit-stack __morestack can continue the stack anywhere. */
+ this_pc_in_block = get_frame_address_in_block (this_frame);
+ morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block);
+ if (morestack_msym)
+ morestack_name = SYMBOL_LINKAGE_NAME (morestack_msym);
+ if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
{
- fprintf_unfiltered (gdb_stdlog, "-> ");
- fprint_frame (gdb_stdlog, NULL);
- fprintf_unfiltered (gdb_stdlog, " // this frame ID is inner }\n");
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame (gdb_stdlog, NULL);
+ fprintf_unfiltered (gdb_stdlog, " // this frame ID is inner }\n");
+ }
+ this_frame->stop_reason = UNWIND_INNER_ID;
+ return NULL;
}
- this_frame->stop_reason = UNWIND_INNER_ID;
- return NULL;
}
/* Check that this and the next frame are not identical. If they
--- /dev/null
+++ b/gdb/testsuite/gdb.base/morestack.c
@@ -0,0 +1,105 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/* Based on the gcc testcase `gcc/testsuite/gcc.dg/split-1.c'. This test
+ needs to use setrlimit to set the stack size, so it can only run on Unix.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+/* Use a noinline function to ensure that the buffer is not removed
+ from the stack. */
+static void use_buffer (char *buf) __attribute__ ((noinline));
+static void
+use_buffer (char *buf)
+{
+ buf[0] = '\0';
+}
+
+static volatile int marker_var;
+
+static void
+marker_miss (void)
+{
+ marker_var = 0;
+}
+
+static void
+marker_hit (void)
+{
+ marker_var = 0;
+}
+
+void *reserved;
+#define RESERVED_SIZE 0x1000000
+
+/* Each recursive call uses 10,000 bytes. We call it 1000 times,
+ using a total of 10,000,000 bytes. If -fsplit-stack is not
+ working, that will overflow our stack limit. */
+
+static void
+down (int i)
+{
+ char buf[10000];
+ static void *last;
+
+ if (last && last < (void *) buf)
+ {
+ printf ("%d: %p < %p\n", i, last, buf);
+ marker_hit ();
+ }
+ last = buf;
+
+ if (i == 500)
+ {
+ if (munmap (reserved, RESERVED_SIZE) != 0)
+ abort ();
+ reserved = NULL;
+ }
+
+ if (i > 0)
+ {
+ use_buffer (buf);
+ down (i - 1);
+ }
+ else
+ marker_miss ();
+}
+
+int
+main (void)
+{
+ struct rlimit r;
+
+ reserved = mmap (NULL, RESERVED_SIZE, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (reserved == MAP_FAILED)
+ abort ();
+
+ /* We set a stack limit because we are usually invoked via make, and
+ make sets the stack limit to be as large as possible. */
+ r.rlim_cur = 8192 * 1024;
+ r.rlim_max = 8192 * 1024;
+ if (setrlimit (RLIMIT_STACK, &r) != 0)
+ abort ();
+ down (1000);
+ return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/morestack.exp
@@ -0,0 +1,52 @@
+# Copyright (C) 2010 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 3 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, see <http://www.gnu.org/licenses/>.
+
+if [get_compiler_info "ignored"] {
+ return -1
+}
+
+if {$gcc_compiled == 0} {
+ return -1
+}
+
+set testfile morestack
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c {additional_flags=-fsplit-stack}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_breakpoint "marker_hit"
+gdb_breakpoint "marker_miss"
+
+set test "continue"
+gdb_test_multiple $test $test {
+ -re "marker_hit.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "marker_miss.*$gdb_prompt $" {
+ # The testcase failed to violated the frame_id_inner condition by
+ # handing inner frame with higher (on the stack-grows-down arches)
+ # $sp address than the outer frame.
+ xfail $test
+ return 0
+ }
+}
+
+# FAIL was on `bt' producing:
+# Backtrace stopped: previous frame inner to this frame (corrupt stack?)
+gdb_test "up 3000" " in main .*"
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-24 0:29 ` Jan Kratochvil
@ 2010-11-24 18:34 ` Tom Tromey
2011-01-03 13:11 ` Jan Kratochvil
0 siblings, 1 reply; 8+ messages in thread
From: Tom Tromey @ 2010-11-24 18:34 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Ian Lance Taylor, Doug Evans, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> That optimization makes no sense there:
Jan> * This check is done only in the error case.
Jan> (For frame_find_by_id it does not seem to be needed.)
Good point.
Jan> * Any lookup caching should be done rather in the symbols lookup
Jan> code anyway.
Yeah.
Jan> * frame.c (get_prev_frame_1) <UNWIND_INNER_ID>: New variables
Jan> this_pc_in_block, morestack_msym and morestack_name. Check for
Jan> "__morestack" minimal symbol there.
It looks good to me.
Tom
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch] Support -fsplit-stack (previous frame inner to this frame)
2010-11-24 18:34 ` Tom Tromey
@ 2011-01-03 13:11 ` Jan Kratochvil
0 siblings, 0 replies; 8+ messages in thread
From: Jan Kratochvil @ 2011-01-03 13:11 UTC (permalink / raw)
To: Tom Tromey; +Cc: Ian Lance Taylor, Doug Evans, gdb-patches
On Wed, 24 Nov 2010 19:34:26 +0100, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
> Jan> * frame.c (get_prev_frame_1) <UNWIND_INNER_ID>: New variables
> Jan> this_pc_in_block, morestack_msym and morestack_name. Check for
> Jan> "__morestack" minimal symbol there.
>
> It looks good to me.
Checked in:
http://sourceware.org/ml/gdb-cvs/2011-01/msg00012.html
Thanks,
Jan
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-01-03 13:11 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-23 0:13 [patch] Support -fsplit-stack (previous frame inner to this frame) Jan Kratochvil
2010-11-23 0:34 ` Doug Evans
2010-11-23 2:12 ` Jan Kratochvil
2010-11-23 20:41 ` Tom Tromey
2010-11-23 22:38 ` Ian Lance Taylor
2010-11-24 0:29 ` Jan Kratochvil
2010-11-24 18:34 ` Tom Tromey
2011-01-03 13:11 ` Jan Kratochvil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox