From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2125 invoked by alias); 1 Oct 2007 14:39:13 -0000 Received: (qmail 2117 invoked by uid 22791); 1 Oct 2007 14:39:13 -0000 X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 01 Oct 2007 14:39:10 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id B3F722AAB9F; Mon, 1 Oct 2007 10:39:08 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id k-Bjyyy0u5zC; Mon, 1 Oct 2007 10:39:08 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id 4EDA02AAB5A; Mon, 1 Oct 2007 10:39:08 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 48A55E7B58; Mon, 1 Oct 2007 07:39:06 -0700 (PDT) Date: Mon, 01 Oct 2007 14:39:00 -0000 From: Joel Brobecker To: Gordon Prieur Cc: Eli Zaretskii , gdb@sourceware.org Subject: Re: Strange stack trace on Windows Message-ID: <20071001143906.GL20912@adacore.com> References: <46FEC75E.9010207@Sun.COM> <4700FE1E.6040201@sun.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4700FE1E.6040201@sun.com> User-Agent: Mutt/1.4.2.2i Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2007-10/txt/msg00006.txt.bz2 > Sometime yes, sometimes no. I implemented that solution abotu 6 months > ago but backed it out because it was just as likely to crash gdb:-( > or hang my IDE (netbeans). We have experienced the same type of problem at AdaCore, and decided to make some compromises: We decided to trust the %ebp registers when unwinding frameless functions from a DLL. This comes with a price: We miss a frame in the backtrace. But because tasking is so important in Ada, we felt it was a better compromise than not being able to unwind from tasks that are blocked waiting for a rendez-vous. Which compromise is best actually depends on the user, which is why this code, or a variation of it, never made it to the FSF tree. This is what our i386_frame_cache() does in case of frameless routines: if (cache->locals < 0) { /* We didn't find a valid frame, which means that CACHE->base currently holds the frame pointer for our calling frame. If we're at the start of a function, or somewhere half-way its prologue, the function's frame probably hasn't been fully setup yet. Try to reconstruct the base address for the stack frame by looking at the stack pointer. For truly "frameless" functions this might work too. */ 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. */ cache->saved_regs[I386_EBP_REGNUM] = 0; } else { i386_frameless_adjust_cache_hack (cache, frame_pc_unwind (next_frame)); if (cache->stack_align) { /* We're halfway aligning the stack. */ cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4; cache->saved_regs[I386_EIP_REGNUM] = cache->saved_sp - 4; /* This will be added back below. */ cache->saved_regs[I386_EIP_REGNUM] -= cache->base; } else { frame_unwind_register (next_frame, I386_ESP_REGNUM, buf); cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset; } } } And the two helper functions are defined as: /* 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] == '.'); } -- Joel