From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11626 invoked by alias); 25 May 2007 18:13:41 -0000 Received: (qmail 11617 invoked by uid 22791); 25 May 2007 18:13:40 -0000 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 25 May 2007 18:13:38 +0000 Received: (qmail 26100 invoked from network); 25 May 2007 16:26:55 -0000 Received: from unknown (HELO localhost) (jimb@127.0.0.2) by mail.codesourcery.com with ESMTPA; 25 May 2007 16:26:55 -0000 To: Nick Roberts Cc: gdb@sourceware.org Subject: Re: Questions about MI variable objects References: <18006.22885.672223.12136@kahikatea.snap.net.nz> From: Jim Blandy Date: Fri, 25 May 2007 18:13:00 -0000 In-Reply-To: <18006.22885.672223.12136@kahikatea.snap.net.nz> (Nick Roberts's message of "Fri, 25 May 2007 15:35:01 +1200") Message-ID: User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-IsSubscribed: yes 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-05/txt/msg00159.txt.bz2 Nick Roberts writes: > > Suppose I'm stopped where the stack is like this: > > > > main -> foo (2) -> foo (1) -> foo (0) > > > > Suppose the top frame is selected, and the user adds a display for > > 'x'. Clearly, it should show '0'. > > > > These are questions about what the GUI should display --- not what GDB > > or MI or varobjs should do. They're about what you want the user to > > see. > > > > 1) If the user selects the 'foo (1)' frame, what should happen to the > > display of 'x'? Should it grey out? Should it now show 1? (I'd > > say it should show 1.) > > I think "-var-create - @ var1" does this i.e. follows the selected frame but I > currently only use "-var-create - * var1" to generate watch expressions for > Emacs. I only grey expressions out when the frame they are created in > disappears. Oh, I see --- USE_SELECTED_FRAME. That's not documented; we should fix that. So, if Emacs wants displays to grey out when the frame disappears, does it ever expect those expressions to become ungrey again? After all, that frame is gone forever. Under what conditions should the display become ungrey? > > 4) If the user lets control run to 'foo' again, so the stack now looks > > like: > > > > main -> bar (10) -> foo (9) > > > > what should happen to the display of 'x'? (I'd say it should show > > '9'.) > > That's what Emacs currently does and what the default GDB behaviour gives, > although Daniel J doesn't seem to think it's useful. Actually, I don't believe you. :) Would you humor me and try this out? - Start with the program I posted. - Set a breakpoint on foo. - Run to the third hit (that is, foo (0)) - Display 'x'. - finish three times, so that we're back in main. We all agree the display should be 'greyed' out at this point. - continue to the next hit of foo. When I do this with what I assume are the corresponding MI commands, the varobj I made for x in foo (0) is still out of scope. If I continue again, I happen to get a frame whose address matches the original foo (0) address, and the varobj comes back in scope, but this is, again, a spurious frame ID match. It happens only because the frames sizes on the stack happen to line up. The compiler could generate different, correct, code and the varobj behavior would stop working. So, at the moment, your displays based on '*'-frame varobjs ungrey at times that appear reasonable in simple test programs, but are actually dependent on flukes of your compiler's stack management. Setting aside MI and GDB and varobjs, from your users' point of view, when should that display come alive again? > > If there's some general agreement on how these ought to behave (not > > necessarily my guesses, just any agreement) then maybe we could make > > MI varobjs match that behavior, so that each GUI variable display > > could be backed by exactly one varobj, and GDB's reports on changes to > > the varobj's state would correspond closely to changes in the GUI's > > display. Varobjs exist to help GUIs, and GDB shouldn't be making GUIs > > jump through hoops to get the behavior they want. > > I'm not sure how you intend to change GDB's behaviour but I think it should > provide options rather than define the policy. MI is a protocol; I don't want to break backwards compatibility. But there's no point in retaining backwards compatibility with a bug --- when that bug's behavior is unpredictable. > > The principle behind my guesses is that a display should refer to a > > particular variable in the source code --- a particular declaration > > --- and should show its value whenever that declaration is in scope in > > the selected frame. This is less specific than having the display > > refer to a particular frame's instance of that variable, and more > > specific than having it refer to any variable that happens to be in > > scope under that name. But it's what I'd expect from a GUI. > > I don't know what to expect. I've always intended to base the display > behavior on user feedback, but until Emacs is released I guess I won't get > much. > > > At the moment, GDB tries to associate each varobj with a specific > > function invocation. It's so easy to concoct a case where frame ID's > > collide that in casual testing, the varobj code may appear to > > implement something more like my suggested behavior. But it doesn't. > > I don't really follow. Can you give an real example where frame IDs collide? Well, since it depends on the stack management code the compiler emits, it's compiler-specific. But on a Fedora Core 6 x86 machine: $ cat vo.c void foo (int x) { if (x > 0) foo (x - 1); } void bar (int x) { foo (x - 1); } int main (int argc, char **argv) { foo (2); bar (2); return 0; } $ gcc -g vo.c -o vo $ ~/uberbaum/build-cvs-out/gdb/gdb vo GNU gdb 6.6.50.20070516-cvs Copyright (C) 2007 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... Using host libthread_db library "/lib/libthread_db.so.1". (gdb) break foo if x == 0 Breakpoint 1 at 0x804832a: file vo.c, line 4. (gdb) run Starting program: /home/jimb/play/vo Breakpoint 1, foo (x=0) at vo.c:4 4 if (x > 0) (gdb) info frame Stack level 0, frame at 0xbf9c98d8: eip = 0x804832a in foo (vo.c:4); saved eip 0x804833e called by frame at 0xbf9c98e4 source language c. Arglist at 0xbf9c98d0, args: x=0 Locals at 0xbf9c98d0, Previous frame's sp is 0xbf9c98d8 Saved registers: ebp at 0xbf9c98d0, eip at 0xbf9c98d4 Since the breakpoint was conditional on x being zero, the stack now looks like this: main -> foo (2) -> foo (1) -> foo (0) Note the "frame at" address. The frame ID is that address, along with the entry point of foo. We'll create a varobj looking at x, just for fun: (gdb) interpreter mi3 "-var-create a * x" ^done,name="a",numchild="0",value="0",type="int" (gdb) (gdb) finish Run till exit from #0 foo (x=0) at vo.c:4 foo (x=1) at vo.c:6 6 } (gdb) interpreter mi3 "-var-update *" ^done,changelist=[{name="a",in_scope="false"}] (gdb) So, we're in a different call to foo, but it's got a different frame ID, and MI considers our varobj to be out of scope. Which is fine: we created it with '*', so it's attached to the now-popped 'foo (0)' frame. (gdb) finish Run till exit from #0 foo (x=1) at vo.c:6 foo (x=2) at vo.c:6 6 } (gdb) finish #0 fooRun till exit from (x=2) at vo.c:6 main () at vo.c:18 18 bar (2); (gdb) info frame Stack level 0, frame at 0xbf9c9900: eip = 0x8048373 in main (vo.c:18); saved eip 0x98cf2c source language c. Arglist at 0xbf9c98f8, args: Locals at 0xbf9c98f8, Previous frame's sp at 0xbf9c98f4 Saved registers: ebp at 0xbf9c98f8, eip at 0xbf9c98fc (gdb) interpreter mi3 "-var-update *" ^done,changelist=[{name="a",in_scope="false"}] (gdb) This is all as we'd expect: the frame address for 'main' is greater (the stack grows towards lower addresses), and the varobj is out of scope. We'll run until the next hit of the breakpoint --- which is conditional on x == 0, remember, so the stack will look like this: main -> bar (2) -> foo (1) -> foo (0) (gdb) continue Continuing. Breakpoint 1, foo (x=0) at vo.c:4 4 if (x > 0) (gdb) info frame Stack level 0, frame at 0xbf9c98d8: eip = 0x804832a in foo (vo.c:4); saved eip 0x804833e called by frame at 0xbf9c98e4 source language c. Arglist at 0xbf9c98d0, args: x=0 Locals at 0xbf9c98d0, Previous frame's sp is 0xbf9c98d8 Saved registers: ebp at 0xbf9c98d0, eip at 0xbf9c98d4 Here is the spurious frame ID collision. This call to foo is entirely distict from the one in which we created the varobj, but because 1) main didn't change its stack size, 2) bar (2) happens to have the same frame size as foo (2), and 3) foo happens to use consistent frame sizes each time it's called, the frame address is the same for the second foo (0) as it was for the first. And indeed, MI considers the varobj to be back in scope: (gdb) interpreter mi3 "-var-update *" ^done,changelist=[{name="a",in_scope="true",type_changed="false"}] (gdb) (gdb) Now, if I add a local variable 'int a[1];' to bar, and compile again without optimization, that changes bar's frame size, and the exact same series of commands plays out differently: the varobj won't come back into scope. Any GUI which relies on '*'-frame varobjs coming back into scope has behavior dependent on internal details of the compiler's behavior, and is buggy.