From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30983 invoked by alias); 4 Feb 2008 20:50:24 -0000 Received: (qmail 30973 invoked by uid 22791); 4 Feb 2008 20:50:22 -0000 X-Spam-Check-By: sourceware.org Received: from ranger.systems.pipex.net (HELO ranger.systems.pipex.net) (62.241.162.32) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 04 Feb 2008 20:49:52 +0000 Received: from [192.168.123.6] (88-106-248-241.dynamic.dsl.as9105.com [88.106.248.241]) by ranger.systems.pipex.net (Postfix) with ESMTP id D19D9E0000C2; Mon, 4 Feb 2008 20:49:49 +0000 (GMT) Message-ID: <47A77A6C.8050007@undo-software.com> Date: Mon, 04 Feb 2008 20:50:00 -0000 From: Greg Law User-Agent: Thunderbird 2.0.0.6 (X11/20071022) MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: SIGSEGV on gdb 6.7* Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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/msg00080.txt.bz2 Hi list, I have been playing with gdb-6.7 and it appears there is a bug whereby reading registers can cause a SIGSEGV in gdb. The simplest way I've found to cause the problem is to try to read a register after calling the flushregs maintenance command: $ cat hello.c #include int main (void) { printf ("hello, world\n"); return 0; } $ gcc -g hello.c $ ./gdb a.out GNU gdb 6.7.1 Copyright (C) 2007 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1". (gdb) start Breakpoint 1 at 0x8048385: file hello.c, line 6. Starting program: /mnt/duron/tests/a.out main () at hello.c:6 6 printf ("Hello world\n"); (gdb) flushregs Register cache flushed. (gdb) print $pc Segmentation fault (core dumped) $ I realise that flushregs is not exactly a "supported" feature, but since the implementation of that command is simply: static void reg_flush_command (char *command, int from_tty) { /* Force-flush the register cache. */ registers_changed (); if (from_tty) printf_filtered (_("Register cache flushed.\n")); } one wonders if there aren't other ways this issue can be triggered. I have had a look around the code, and it's one of those "how could it ever have worked?" occasions (which of course typically means I've missed something important). The implementation of registers_changed() is (essentially): void registers_changed (void) { int i; regcache_xfree (current_regcache); current_regcache = NULL; yet there appear to be pointers to the regcache squirrelled away in various other places, notably the prologue_cache member of the frame_info structure. I'm sure I'm missing something here -- how come freeing current_regcache is safe with pointers to the register cache out-living it? I have found that the following simple patch appears to fix (or at least work round) the SEGV triggered by flushregs: Index: regcache.c =================================================================== RCS file: /cvs/src/src/gdb/regcache.c,v retrieving revision 1.163 diff -u -r1.163 regcache.c --- regcache.c 1 Jan 2008 22:53:12 -0000 1.163 +++ regcache.c 3 Feb 2008 21:35:19 -0000 @@ -885,6 +885,7 @@ { /* Force-flush the register cache. */ registers_changed (); + get_current_regcache (); if (from_tty) printf_filtered (_("Register cache flushed.\n")); } However, I am insufficiently familiar with the gdb internals to know which, if any, of the other call-sites to register_changed() should be similarly updated. Perhaps it would be safer simply to call get_current_regcache() from the end of registers_changed(): Index: regcache.c =================================================================== RCS file: /cvs/src/src/gdb/regcache.c,v retrieving revision 1.163 diff -u -r1.163 regcache.c --- regcache.c 1 Jan 2008 22:53:12 -0000 1.163 +++ regcache.c 3 Feb 2008 21:49:37 -0000 @@ -472,6 +472,9 @@ regcache_xfree (current_regcache); current_regcache = NULL; + /* Update the cache with the new registers. */ + get_current_regcache (); + /* Force cleanup of any alloca areas if using C alloca instead of a builtin alloca. This particular call is used to clean up areas allocated by low level target code which may build up I guess this might result in some "unnecessary" fetches of the register state, but that has to be favourable to a SEGV :) Cheers, Greg -- Greg Law, Undo Software http://undo-software.com/