From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12341 invoked by alias); 31 Mar 2009 00:44:36 -0000 Received: (qmail 12332 invoked by uid 22791); 31 Mar 2009 00:44:35 -0000 X-SWARE-Spam-Status: No, hits=-1.6 required=5.0 tests=AWL,BAYES_00,MISSING_HEADERS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from hq2.tensilica.com (HELO maia.hq.tensilica.com) (65.205.227.30) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 31 Mar 2009 00:44:30 +0000 Received: from [172.16.150.11] (nose.hq.tensilica.com [172.16.150.11]) (authenticated bits=0) by maia.hq.tensilica.com (8.13.1/8.13.1) with ESMTP id n2V0iL4h029887; Mon, 30 Mar 2009 17:44:22 -0700 Message-ID: <49D16764.2040706@tensilica.com> Date: Tue, 31 Mar 2009 00:44:00 -0000 From: Ross Morley User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040805 Netscape/7.2 MIME-Version: 1.0 CC: gdb@sourceware.org Subject: Re: RFC: Program Breakpoints References: <49C7BDD6.3060305@tensilica.com> In-Reply-To: <49C7BDD6.3060305@tensilica.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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: 2009-03/txt/msg00186.txt.bz2 I'm preparing the simplified version I described earlier for submission. In stepping over a program break I increment the PC without running the inferior (in step_1 of infcmd.c - see trimmed post below for context). Then I update the frame cache and report the stop reason, new PC, etc. My old pre-6.x implementation used a function that was deprecated in 6.x and recently removed. What is the proper way to update the frame without the call to deprecated_update_frame_pc_hack (get_current_frame (), read_pc ()); I tried calling get_frame_pc (get_current_frame ()) and ignoring the result. That should call frame_pc_unwind (). But the subsequent print_stack_frame (get_selected_frame (NULL), -1, LOC_AND_ADDRESS); reports the address of the break to MI, not the incremented PC. I also tried reinit_frame_cache () and it works OK. Seems drastic though. For convenience, here's the code snippet from step_1 of infcmd.c: else if (STOPPED_BY_PROGRAM_BREAKPOINT (&program_break_size) && program_break_size != 0 && read_pc() == stop_pc && count > 0) { /* "stepi" off program breakpoint: the first step is to just increment the PC past the break, then there are count-1 steps to go. Note proceed() won't be called the first time, and on subsequent steps the PC will already be off the break, so the entire handling of "stepi" off a program breakpoint is done here. If stopping after the break, display location information as for normal_stop. */ count--; write_pc (read_pc () + program_break_size); if (count == 0) { deprecated_update_frame_pc_hack (get_current_frame (), read_pc ()); if (ui_out_is_mi_like_p (uiout)) { ui_out_field_string (uiout, "reason", async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); ui_out_field_int (uiout, "thread-id", pid_to_thread_id (inferior_ptid)); print_stack_frame (get_selected_frame (NULL), -1, LOC_AND_ADDRESS); } else print_stack_frame (get_selected_frame (NULL), -1, SRC_LINE); } } Thanks, Ross Ross Morley wrote: > > The Problem > ----------- > > When the target program hits a breakpoint of any kind, GDB receives > a SIGTRAP event. As Aleksander pointed out, if the PC is not in the > breakpoint table GDB stops because it doesn't know what to do with > this event. In fact it doesn't always stop. When GDB is stepping > (for example when a software watchpoint is set) it sees the SIGTRAP > as a normal step event, so it continues stepping. If the break > instruction didn't increment the PC, it keeps executing the same > break instruction forever. This is very frustrating for users (who > reported this as a bug) because when you have a s/w watchpoint and > are stepping, execution is expected to be slow, so you wait a long > time before you realize it's hung. > > The Solution > ------------ > > The first part is to recognize when you hit a program break. > The second is to step over it when you want to resume. > > Having discovered that it stopped for a program breakpoint, GDB > is able to report the fact to both the CLI and MI. I also defined > a gdbarch function to report the meaning of "kind" in an arch- > specific way. This improves the debugging experience when the > target uses different kinds of breakpoints to denote different > reasons for stopping. (However, in the interest of simplicity, > my revised proposal won't report all that - it is anyway obvious > from a disassembly if not a symbol associated with the PC; GDB > itself only needs to know the size to skip the breakpoint). > > When the user elects to continue after a program breakpoint, > GDB increments the PC by the size of the break that was reported > in the "kind" argument. A gdbarch function handles this. Of > course it might do nothing if the PC was already advanced. > > I haven't discussed all the implementation details here. > Please see the attached 6.8 based patch for the actual code. > Note this patch does not pretend to be ready for submission! > > Proposed Improved, Simplified Solution > -------------------------------------- > > The remote protocol extension would be: > TAAtrap[:size] > where ":size" is optional and may only be provided to GDB by the > target agent if the PC is in fact pointing to the instruction > that caused the break, and if omitted is taken to be 0. > GDB will skip the break by PC += size (no effect if size is 0). > Note it is not necessary to call gdbarch_breakpoint_from_pc(). > > The gdbarch functions to extract the size and decipher "kind" > are not needed. The target interface function > STOPPED_BY_PROGRAM_BREAKPOINT(k) > becomes > STOPPED_BY_PROGRAM_BREAKPOINT(size) > where 'size' is an address in which the size is returned. > > We might also want to consider calling it "program trap" and > keep the term "breakpoint" for things that GDB knows about. > > > Comments are welcome. We at Tensilica would like to see this > refined and incorporated into mainline GDB. > > This can certainly coexist with permanent breakpoints, > however it is (I think) a bit more general. If the people > who use permanent breakpoints would care to comment, > perhaps we can somehow reconcile these into one feature. > > Thanks, > Ross Morley > Tensilca, Inc. > ross@tensilica.com > > >diff -urN gdb-6.8-orig/gdb/infcmd.c gdb-6.8-new/gdb/infcmd.c >--- gdb-6.8-orig/gdb/infcmd.c 2009-03-19 17:29:48.000000000 -0700 >+++ gdb-6.8-new/gdb/infcmd.c 2009-03-20 11:33:21.000000000 -0700 >@@ -696,6 +696,9 @@ > struct frame_info *frame; > struct cleanup *cleanups = 0; > int async_exec = 0; >+/* TENSILICA_LOCAL */ >+ int program_break_kind; >+/* END TENSILICA_LOCAL */ > > ERROR_NO_INFERIOR; > >@@ -725,6 +728,33 @@ > else > make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); > } >+/* TENSILICA_LOCAL */ >+ else if (STOPPED_BY_PROGRAM_BREAKPOINT (&program_break_kind) && >+ read_pc() == stop_pc && count > 0) >+ { >+ /* "stepi" off program breakpoint: the first step is to just increment >+ the PC past the break, then there are count-1 steps to go. >+ Note proceed() won't be called the first time, and on subsequent >+ steps the PC will already be off the break, so the entire handling >+ of "stepi" off a program breakpoint is done here. If stopping after >+ the break, display location information as for normal_stop. */ >+ count--; >+ gdbarch_skip_program_breakpoint (current_gdbarch, program_break_kind); >+ if (count == 0) >+ { >+ deprecated_update_frame_pc_hack (get_current_frame (), read_pc ()); >+ if (ui_out_is_mi_like_p (uiout)) >+ { >+ ui_out_field_string (uiout, "reason", "end-stepping-range"); >+ ui_out_field_int (uiout, "thread-id", >+ pid_to_thread_id (inferior_ptid)); >+ print_stack_frame (get_selected_frame (NULL), -1, LOC_AND_ADDRESS); >+ } >+ else >+ print_stack_frame (get_selected_frame (NULL), -1, SRC_LINE); >+ } >+ } >+/* END TENSILICA_LOCAL */ > > > >