From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27608 invoked by alias); 19 Feb 2003 13:27:46 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 27601 invoked from network); 19 Feb 2003 13:27:46 -0000 Received: from unknown (HELO localhost.redhat.com) (172.16.49.200) by 172.16.49.205 with SMTP; 19 Feb 2003 13:27:46 -0000 Received: from redhat.com (localhost [127.0.0.1]) by localhost.redhat.com (Postfix) with ESMTP id 3092E2D37; Wed, 19 Feb 2003 08:32:32 -0500 (EST) Message-ID: <3E538770.6070209@redhat.com> Date: Wed, 19 Feb 2003 13:27:00 -0000 From: Andrew Cagney User-Agent: Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.0.2) Gecko/20030217 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Michal Ludvig Cc: GDB Patches Subject: Re: [patch/rfc] Add a sentinel frame References: <3E305670.3020700@redhat.com> <3E48378E.6090007@suse.cz> <3E492953.8010001@redhat.com> <3E52173B.1030800@suse.cz> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit X-SW-Source: 2003-02/txt/msg00400.txt.bz2 (I hate jet lag, I'm never up at 7am, well ok ...) > I got back to the mainline/"sentinel" problem and have found that it happens when a program's function is called from a gdb prompt. > > To reproduce create a very simple program: > int func(int arg) { return 2*arg; } > int main(int argc) { return func(argc); } > > Then run mainline GDB on x86-64: > (gdb) break main > (gdb) run > (gdb) print func(1) > ../../gdb-head/gdb/sentinel-frame.c:102: internal-error: Function sentinal_frame_pop called > A problem internal to GDB has been detected. Further > debugging may prove unreliable. > Quit this debugging session? (y or n) > > Attached is a backtrace of this failing GDB. > Any ideas? Yes! > #6 0x00000000005446d1 in sentinel_frame_pop (frame=0x82c100, cache=0x82c130, > regcache=0x850610) at ../../gdb-head/gdb/sentinel-frame.c:102 At this point GDB is hosed. As I mentioned before, popping the sentinal frame is meaningless so the question is, where did that frame come from. A wild guess is that it is trying to pop the dummy frame having finished the inferior function call. A confirmation is: (gdb) break func (gdb) print func(1) It should manage to stop in func, the stack being something like (assuming bt doesn't also internal error :-): (gdb) bt .... func ... .... ... .... main ... Returning from func(), causing the dummy-frame to be discarded should then trigger things: (gdb) finish ... barf ... Can you confirm that the PC for this frame is falling in the stack dummy? > #7 0x00000000004e6692 in frame_pop (frame=0x82c100) > at ../../gdb-head/gdb/frame.c:164 > #8 0x000000000048a3c4 in normal_stop () at ../../gdb-head/gdb/infrun.c:3113 The code reads: if (stop_stack_dummy) { /* Pop the empty frame that contains the stack dummy. POP_FRAME ends with a setting of the current frame, so we can use that next. */ frame_pop (get_current_frame ()); /* Set stop_pc to what it was before we called the function. Can't rely on restore_inferior_status because that only gets called if we don't stop in the called function. */ stop_pc = read_pc (); select_frame (get_current_frame ()); } Hmm, not so good. I was expecting something involving sentinal frames. Anyway ... get_current_frame() does the sequence: if (current_frame == NULL) { This is where the sentinel frame comes from. struct frame_info *sentinel_frame = create_sentinel_frame (current_regcache); This is where it tries to unwind it back to the current frame (a dummy frame in this case). Note that unwind_to_current_frame() calls get_prev_frame(). if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame, NULL, RETURN_MASK_ERROR) != 0) { And if it fails, it does this: /* Oops! Fake a current frame? Is this useful? It has a PC of zero, for instance. */ current_frame = sentinel_frame; } } So lets assume that get_prev_frame() is failing. It can do it two ways: - noisily via an error() call such as when a memory read fails (I don't think it is this 'cos we'd see that error). - silently because get_prev_frame() thinks that chaining is invalid (more likely) So I think it is one of these tests going awall: if (next_frame->level >= 0 && !backtrace_below_main && inside_main_func (get_frame_pc (next_frame))) /* Don't unwind past main(), bug always unwind the sentinel frame. Note, this is done _before_ the frame has been marked as previously unwound. That way if the user later decides to allow unwinds past main(), that just happens. */ return NULL; /* If we're inside the entry file, it isn't valid. */ /* NOTE: drow/2002-12-25: should there be a way to disable this check? It assumes a single small entry file, and the way some debug readers (e.g. dbxread) figure out which object is the entry file is somewhat hokey. */ /* NOTE: cagney/2003-01-10: If there is a way of disabling this test then it should probably be moved to before the ->prev_p test, above. */ if (inside_entry_file (get_frame_pc (next_frame))) return NULL; The second looks worrying (the dummy frame breakpoint lives in the entry file ...). Perhaphs something like: if (dummy_frame_p (get_frame_pc (next_frame) != NULL && inside_entry_file (get_frame_pc (next_frame)) return NULL; Andrew