From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21701 invoked by alias); 31 Jul 2002 20:09:37 -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 21693 invoked from network); 31 Jul 2002 20:09:36 -0000 Received: from unknown (HELO takamaka.act-europe.fr) (142.179.108.108) by sources.redhat.com with SMTP; 31 Jul 2002 20:09:36 -0000 Received: by takamaka.act-europe.fr (Postfix, from userid 507) id 31667D2CBD; Wed, 31 Jul 2002 13:09:36 -0700 (PDT) Date: Wed, 31 Jul 2002 13:14:00 -0000 From: Joel Brobecker To: gdb-patches@sources.redhat.com Subject: [RFA] GDB/624 - tbreak commands not executed when breakpoint hit Message-ID: <20020731200936.GL683@gnat.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="qcHopEYAB45HaUaB" Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2002-07/txt/msg00626.txt.bz2 --qcHopEYAB45HaUaB Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2693 As described in PR GDB/624: Using the small program from gdb.base/commands.exp, the following copy of a GDB sessions shows that commands associated to temporary breakpoints are not executed when the breakpoint is hit: (gdb) tbreak factorial Breakpoint 1 at 0x8048582: file ./gdb.base/run.c, line 77. (gdb) commands Type commands for when breakpoint 1 is hit, one per line. End with a line saying just "end". >silent >printf "factorial command-list executed\n" >cont >end (gdb) run 1 Starting program: [...]/gdb.base/commands 1 (gdb) The backtrace confirms that the program executed up to the factorial breakpoint, and then stopped. (gdb) bt #0 factorial (value=1) at ./gdb.base/run.c:77 #1 0x0804855e in main (argc=2, argv=0xbffffa34, envp=0xbffffa40) at ./gdb.base/run.c:57 #2 0x4005514f in __libc_start_main () from /lib/libc.so.6 (gdb) p /x $pc $1 = 0x8048582 <<<--- $pc is equal to bp #1 address The expected output after the run command was: (gdb) run 1 Starting program: [...]/gdb.base/commands 1 factorial command-list executed 1 Program exited normally. (gdb) The problem is that the breakpoint is deleted very early in the inferior stop handling, so the rest of the code does not have a chance to see that there was a temporary breakpoint there with a commands list to execute. To fix this, it is necessary to delay a bit the deletion of this breakpoint. This is what the attached patch does. There is a small side-effect, which I think should be ok, is that the after the temporary breakpoint is hit, there is a small period during which the breakpoint is still visible when doing ``info break''. The status report is disabled, and to be deleted at the next stop. I also attached an extra test in gdb.base/commands.exp. No new regression introduced on x86-linux. Ok to apply? 2002-07-31 Joel Brobecker * breakpoint.c (breakpoint_auto_delete): Do not delete temporary breakpoints to which a list of commands is attached. Mark them for deletion at the next stop instead. Also disable them to avoid hitting these breakpoints again. Move the part that deletes the to-be-deleted breakpoints before the part that deletes the temporary breakpoints, to avoid immediately deleting the temporary breakpoints that we just marked for deletion. 2002-07-31 Joel Brobecker * gdb.base/commands.exp (temporary_breakpoint_commands): New test. Thanks, -- Joel --qcHopEYAB45HaUaB Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="tbreak_commands.diff" Content-length: 5320 Index: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.78 diff -c -3 -p -r1.78 breakpoint.c *** breakpoint.c 26 Jun 2002 05:20:04 -0000 1.78 --- breakpoint.c 31 Jul 2002 20:08:35 -0000 *************** top: *** 1882,1888 **** breakpoint_proceeded = 0; for (; bs != NULL; bs = bs->next) { ! cmd = bs->commands; while (cmd != NULL) { execute_control_command (cmd); --- 1882,1892 ---- breakpoint_proceeded = 0; for (; bs != NULL; bs = bs->next) { ! /* Use a temporary copy of the commands, as one command in the list ! may cause this breakpoint and its commands to be deleted. */ ! cmd = copy_command_lines (bs->commands); ! make_cleanup_free_command_lines (&cmd); ! while (cmd != NULL) { execute_control_command (cmd); *************** breakpoint_auto_delete (bpstat bs) *** 6575,6590 **** { struct breakpoint *b, *temp; - for (; bs; bs = bs->next) - if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del - && bs->stop) - delete_breakpoint (bs->breakpoint_at); - ALL_BREAKPOINTS_SAFE (b, temp) { if (b->disposition == disp_del_at_next_stop) delete_breakpoint (b); } } /* Delete a breakpoint and clean up all traces of it in the data --- 6579,6607 ---- { struct breakpoint *b, *temp; ALL_BREAKPOINTS_SAFE (b, temp) { if (b->disposition == disp_del_at_next_stop) delete_breakpoint (b); } + + for (; bs; bs = bs->next) + if (bs->breakpoint_at && bs->breakpoint_at->disposition == disp_del + && bs->stop) + { + if (bs->commands) + { + /* Don't delete this breakpoint yet, as there are some + commands associated to this temporary breakpoint that + need to be executed before. Mark this breakpoint for + deletion at the next stop, and also disable this breakpoint + to avoid hitting it later on. */ + bs->breakpoint_at->disposition = disp_del_at_next_stop; + disable_breakpoint (bs->breakpoint_at); + } + else + delete_breakpoint (bs->breakpoint_at); + } } /* Delete a breakpoint and clean up all traces of it in the data Index: testsuite/gdb.base/commands.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/commands.exp,v retrieving revision 1.10 diff -c -3 -p -r1.10 commands.exp *** testsuite/gdb.base/commands.exp 13 Dec 2001 22:42:23 -0000 1.10 --- testsuite/gdb.base/commands.exp 31 Jul 2002 20:08:36 -0000 *************** proc deprecated_command_test {} { *** 440,445 **** --- 440,498 ---- "deprecate with no arguments" } + proc temporary_breakpoint_commands {} { + global gdb_prompt + + gdb_test "set args 1" "" "set args in temporary_breakpoint_commands" + delete_breakpoints + + # Create a temporary breakpoint, and associate a commands list to it. + # This test will verify that this commands list is executed when the + # breakpoint is hit. + gdb_test "tbreak factorial" \ + "Breakpoint \[0-9\]+ at .*: file .*/run.c, line \[0-9\]+\." \ + "breakpoint in temporary_breakpoint_commands" + + send_gdb "commands\n" + gdb_expect { + -re "Type commands for when breakpoint .* is hit, one per line.*>" { + pass "begin commands in bp_deleted_in_command_test" + } + -re "$gdb_prompt $" {fail "begin commands in bp_deleted_in_command_test"} + timeout {fail "(timeout) begin commands bp_deleted_in_command_test"} + } + send_gdb "silent\n" + gdb_expect { + -re ">" {pass "add silent tbreak command"} + -re "$gdb_prompt $" {fail "add silent tbreak command"} + timeout {fail "(timeout) add silent tbreak command"} + } + send_gdb "printf \"factorial tbreak commands executed\\n\"\n" + gdb_expect { + -re ">" {pass "add printf tbreak command"} + -re "$gdb_prompt $" {fail "add printf tbreak command"} + timeout {fail "(timeout) add printf tbreak command"} + } + send_gdb "cont\n" + gdb_expect { + -re ">" {pass "add cont tbreak command"} + -re "$gdb_prompt $" {fail "add cont tbreak command"} + timeout {fail "(timeout) add cont tbreak command"} } + send_gdb "end\n" + gdb_expect { + -re "$gdb_prompt $" {pass "end tbreak commands"} + timeout {fail "(timeout) end tbreak commands"} + } + + gdb_run_cmd + gdb_expect { + -re ".*factorial tbreak commands executed.*1.*Program exited normally.*" { + pass "run factorial until temporary breakpoint" + } + timeout { fail "(timeout) run factorial until temporary breakpoint" } + } + + } gdbvar_simple_if_test gdbvar_simple_while_test *************** user_defined_command_test *** 454,456 **** --- 507,510 ---- watchpoint_command_test test_command_prompt_position deprecated_command_test + temporary_breakpoint_commands --qcHopEYAB45HaUaB--