From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21366 invoked by alias); 23 Aug 2006 17:38:56 -0000 Received: (qmail 21358 invoked by uid 22791); 23 Aug 2006 17:38:55 -0000 X-Spam-Check-By: sourceware.org Received: from nile.gnat.com (HELO nile.gnat.com) (205.232.38.5) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 23 Aug 2006 17:38:52 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-nile.gnat.com (Postfix) with ESMTP id 8BF9148CEB5 for ; Wed, 23 Aug 2006 13:38:50 -0400 (EDT) Received: from nile.gnat.com ([127.0.0.1]) by localhost (nile.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 17293-01-2 for ; Wed, 23 Aug 2006 13:38:50 -0400 (EDT) Received: from takamaka.act-europe.fr (unknown [70.71.0.212]) by nile.gnat.com (Postfix) with ESMTP id E603848CBDB for ; Wed, 23 Aug 2006 13:38:49 -0400 (EDT) Received: by takamaka.act-europe.fr (Postfix, from userid 507) id 3527F47EFA; Wed, 23 Aug 2006 10:38:49 -0700 (PDT) Date: Wed, 23 Aug 2006 18:17:00 -0000 From: Joel Brobecker To: gdb-patches@sources.redhat.com Subject: [i386/fyi] small adjustment to i386 frame code Message-ID: <20060823173849.GG11591@adacore.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="YZ5djTAD1cGYuMQK" Content-Disposition: inline User-Agent: Mutt/1.4i Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2006-08/txt/msg00182.txt.bz2 --YZ5djTAD1cGYuMQK Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1813 Hello, Since this has been discussed here in several occasions... Since GDB 6.0, the debugger has been using a more sophisticated frame unwinder. It used to blindly follow the %ebp register, but no longer does that unless it is sure that the frame base address has been saved there. Although the new frame code gives more much more accurate results most of the time, there are some occasional cases where we have to unwind through functions which do not follow the ABI, and for which no frame debugging info seem to be provided. In these particular cases, the unwinder fails, and a backtrace from such function aborts prematurely. One such example is WaitForSingleObjectEx (in one of the windows DLL). I posted the assembly of this function a long while ago, it's just plain impossible to determine where the frame base is. Unfortunately for us, that function is used fairly regularly by any application which would use tasking (a high-level equivalent of threads in C), which is something relatively common in the Ada world. So we really need to be able to unwind past that function. When it comes to unwinding using prologue analysis, there is probably no perfect solution. Here is the approach we are going to try out: Follow blindly the %ebp register for "the complicated functions". And because we've only encountered this type of code in a DLL, we've limited this hack to code in DLLs. I added a comment in the code explaining the condition that implements "complicated". We know there is a risk of %ebp being clobbered, we also know that %ebp is the base address of the caller's frame, now ours. But that will at least give us a chance of having the backtrace reach the user code. If this is something of general interest, in this form or any variation, I would be happy to contribute it. -- Joel --YZ5djTAD1cGYuMQK Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ebp.diff" Content-length: 3402 Index: i386-tdep.c =================================================================== RCS file: /gnat.dev/cvs/Dev/gdb/gdb-6.4/gdb/i386-tdep.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -p -r1.4 -r1.5 --- i386-tdep.c 10 Aug 2006 22:18:30 -0000 1.4 +++ i386-tdep.c 22 Aug 2006 21:45:53 -0000 1.5 @@ -1029,6 +1029,41 @@ i386_frameless_adjust_cache_hack (struct } } +/* Return non-zero if the function starting at START_PC has a prologue + that sets up a standard frame. */ + +static int +i386_function_has_frame (CORE_ADDR start_pc) +{ + struct i386_frame_cache cache; + + cache.locals = -1; + i386_analyze_prologue (start_pc, 0xffffffff, &cache); + + return (cache.locals >= 0); +} + +/* Return non-zero if PC is inside one of the inferior's DLLs. */ + +static int +i386_in_dll (CORE_ADDR pc) +{ + char *so_name = solib_address (pc); + int len; + + if (so_name == NULL) + return 0; + + len = strlen (so_name); + if (len < 5) + return 0; + + return ((so_name[len - 1] == 'l' || so_name[len - 1] == 'L') + && (so_name[len - 2] == 'l' || so_name[len - 2] == 'L') + && (so_name[len - 3] == 'd' || so_name[len - 3] == 'D') + && so_name[len - 4] == '.'); +} + /* Normal frames. */ static struct i386_frame_cache * @@ -1075,10 +1110,38 @@ i386_frame_cache (struct frame_info *nex frame by looking at the stack pointer. For truly "frameless" functions this might work too. */ - i386_frameless_adjust_cache_hack (cache, frame_pc_unwind (next_frame)); + if (i386_in_dll (cache->pc) + && !i386_function_has_frame (cache->pc)) + { + /* Functions in DLL for which do not seem to create a standard + frame are unwound using %ebp. This is actually the caller's + frame base instead of our own, but there are some functions + such as WaitForSingleObjectEx in one of the Windows system + DLLs for which the frame base cannot possibly be determined + from the stack pointer. As a consequence, our caller will be + missing from the backtrace, but this is better than having + an aborted backtrace due to a bogus frame base. + + We use this approach only for functions in DLLs because + this is the only place where we have seen the type of + highly optimized code that cause us trouble. In other + cases, we expect the code to come with frame debugging + information, making prologue scanning unnecessary. + + We also avoid blindly following %ebp if we are midway through + setting up a standard frame. In that case, we know how to + determine the frame base using the stack pointer. */ - frame_unwind_register (next_frame, I386_ESP_REGNUM, buf); - cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset; + cache->saved_regs[I386_EBP_REGNUM] = 0; + } + else + { + i386_frameless_adjust_cache_hack (cache, + frame_pc_unwind (next_frame)); + + frame_unwind_register (next_frame, I386_ESP_REGNUM, buf); + cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset; + } } /* Now that we have the base address for the stack frame we can --YZ5djTAD1cGYuMQK--