From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7148 invoked by alias); 22 Feb 2008 17:12:47 -0000 Received: (qmail 7137 invoked by uid 22791); 22 Feb 2008 17:12:46 -0000 X-Spam-Check-By: sourceware.org Received: from dmz.mips-uk.com (HELO dmz.mips-uk.com) (194.74.144.194) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 22 Feb 2008 17:12:29 +0000 Received: from internal-mx1 ([192.168.192.240] helo=ukservices1.mips.com) by dmz.mips-uk.com with esmtp (Exim 3.35 #1 (Debian)) id 1JSbRi-0003Ky-00; Fri, 22 Feb 2008 17:12:26 +0000 Received: from perivale.mips.com ([192.168.192.200]) by ukservices1.mips.com with esmtp (Exim 3.36 #1 (Debian)) id 1JSbRa-0007cc-00; Fri, 22 Feb 2008 17:12:18 +0000 Received: from macro (helo=localhost) by perivale.mips.com with local-esmtp (Exim 4.63) (envelope-from ) id 1JSbRa-0002z6-GN; Fri, 22 Feb 2008 17:12:18 +0000 Date: Fri, 22 Feb 2008 17:21:00 -0000 From: "Maciej W. Rozycki" To: gdb-patches@sourceware.org cc: Nigel Stephens , "Maciej W. Rozycki" Subject: Do not unwind frames past NULL PC Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-MIPS-Technologies-UK-MailScanner: Found to be clean X-MIPS-Technologies-UK-MailScanner-From: macro@mips.com 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: 2008-02/txt/msg00359.txt.bz2 Hello, Some architectures, like MIPS, specify in the ABI that the value of the return address in a frame (or in other words the value of the PC the frame would have been called from) being zero denotes the outermost frame. At the moment GDB does not seem to have a way to terminate frame unwinding in an architecture-specific way (or to that matter any that would not imply an error condition) in get_prev_frame_1(), which is where such a check would be needed. However even for these architectures which may not necessarily specify in the relevant ABI that a NULL PC is the terminating value it seems rather unlikely for a function to have been called in a way which would make its return address to be zero and yet it having a genuine caller with an associated frame. Therefore I propose the following check to be introduced to get_prev_frame_1(). It removes the confusing bogus frame at the bottom of a backtrace like below: (gdb) bt #0 main (argc=1, argv=0x8114fdd0, envp=0x801065a8) at gdb/testsuite/gdb.base/run.c:59 #1 0x801003a3 in __wrap_main () #2 0x801000a4 in _start () at sdemdi/crt0.S:93 #3 0x00000000 in ?? () (gdb) If my assumption is in fact wrong for some other architecture, then please let me know. Otherwise this change has been tested using the mipsisa32-sde-elf target, with the mips-sim-sde32/-EB/-mips32r2 and mips-sim-sde32/-EL/-mips32r2 boards with no regressions. 2008-02-22 Maciej W. Rozycki * frame.c (get_prev_frame_1): Stop unwinding if the PC of zero has been reached. OK to apply? Maciej gdb-get_prev_frame.diff Index: binutils-quilt/ChangeLog-gdb-get_prev_frame =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ binutils-quilt/ChangeLog-gdb-get_prev_frame 2008-02-22 16:38:40.000000000 +0000 @@ -0,0 +1,4 @@ +2008-02-22 Maciej W. Rozycki + + * frame.c (get_prev_frame_1): Stop unwinding if the PC of zero + has been reached. Index: binutils-quilt/src/gdb/frame.c =================================================================== --- binutils-quilt.orig/src/gdb/frame.c 2008-02-22 14:52:45.000000000 +0000 +++ binutils-quilt/src/gdb/frame.c 2008-02-22 16:38:40.000000000 +0000 @@ -1122,13 +1122,18 @@ static struct frame_info * get_prev_frame_1 (struct frame_info *this_frame) { + enum frame_type this_frame_type; struct frame_info *prev_frame; struct frame_id this_id; struct gdbarch *gdbarch; + int pc_regnum; gdb_assert (this_frame != NULL); gdbarch = get_frame_arch (this_frame); + pc_regnum = gdbarch_pc_regnum (gdbarch); + this_frame_type = get_frame_type (this_frame); + if (frame_debug) { fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame="); @@ -1219,19 +1224,17 @@ method set the same lval and location information as frame_register_unwind. */ if (this_frame->level > 0 - && gdbarch_pc_regnum (gdbarch) >= 0 - && get_frame_type (this_frame) == NORMAL_FRAME + && pc_regnum >= 0 + && this_frame_type == NORMAL_FRAME && get_frame_type (this_frame->next) == NORMAL_FRAME) { int optimized, realnum, nrealnum; enum lval_type lval, nlval; CORE_ADDR addr, naddr; - frame_register_unwind_location (this_frame, - gdbarch_pc_regnum (gdbarch), + frame_register_unwind_location (this_frame, pc_regnum, &optimized, &lval, &addr, &realnum); - frame_register_unwind_location (get_next_frame (this_frame), - gdbarch_pc_regnum (gdbarch), + frame_register_unwind_location (get_next_frame (this_frame), pc_regnum, &optimized, &nlval, &naddr, &nrealnum); if ((lval == lval_memory && lval == nlval && addr == naddr) @@ -1250,6 +1253,23 @@ } } + /* Check for the unwound PC being zero, which means this is + the outermost frame. */ + if (pc_regnum >= 0 + && this_frame_type == NORMAL_FRAME + && frame_pc_unwind (this_frame) == 0) + { + if (frame_debug) + { + fprintf_unfiltered (gdb_stdlog, "-> "); + fprint_frame (gdb_stdlog, NULL); + fprintf_unfiltered (gdb_stdlog, " // NULL saved PC }\n"); + } + + this_frame->prev = NULL; + return NULL; + } + /* Allocate the new frame but do not wire it in to the frame chain. Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along frame->next to pull some fancy tricks (of course such code is, by