From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15933 invoked by alias); 23 Nov 2010 00:13:49 -0000 Received: (qmail 15921 invoked by uid 22791); 23 Nov 2010 00:13:46 -0000 X-SWARE-Spam-Status: No, hits=-5.4 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BJ,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 23 Nov 2010 00:13:35 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id oAN0DXbO025629 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 22 Nov 2010 19:13:33 -0500 Received: from host0.dyn.jankratochvil.net (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id oAN0DS8l016327 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 22 Nov 2010 19:13:32 -0500 Received: from host0.dyn.jankratochvil.net (localhost.localdomain [127.0.0.1]) by host0.dyn.jankratochvil.net (8.14.4/8.14.4) with ESMTP id oAN0DSwZ012275; Tue, 23 Nov 2010 01:13:28 +0100 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.14.4/8.14.4/Submit) id oAN0DP5p012274; Tue, 23 Nov 2010 01:13:25 +0100 Date: Tue, 23 Nov 2010 00:13:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Cc: Ian Lance Taylor Subject: [patch] Support -fsplit-stack (previous frame inner to this frame) Message-ID: <20101123001325.GA11983@host0.dyn.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-11/txt/msg00318.txt.bz2 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 * 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 * 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 . */ + +/* 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 +#include +#include +#include +#include + +/* 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 . + +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 .*"