From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19982 invoked by alias); 19 May 2009 17:30:04 -0000 Received: (qmail 19858 invoked by uid 22791); 19 May 2009 17:29:56 -0000 X-SWARE-Spam-Status: No, hits=-0.5 required=5.0 tests=AWL,BAYES_05,J_CHICKENPOX_37,J_CHICKENPOX_51,SPF_HELO_PASS,SPF_SOFTFAIL X-Spam-Check-By: sourceware.org Received: from mailgw.tensilica.com (HELO mailgw.tensilica.com) (65.205.227.134) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 19 May 2009 17:29:39 +0000 Received: from localhost (unknown [127.0.0.1]) by mailgw.tensilica.com (Postfix) with ESMTP id 3FC9C11604E5 for ; Tue, 19 May 2009 17:29:38 +0000 (UTC) Received: from mailgw.tensilica.com ([127.0.0.1]) by localhost (mailgw.tensilica.com [127.0.0.1]) (amavisd-maia, port 10024) with ESMTP id 28996-04 for ; Tue, 19 May 2009 10:29:38 -0700 (PDT) Received: from mail.tensilica.com (mail.tensilica.com [192.168.15.138]) by mailgw.tensilica.com (Postfix) with ESMTP id 0637B11604C5 for ; Tue, 19 May 2009 10:29:34 -0700 (PDT) Received: from [172.16.150.11] (172.16.150.11) by exch.hq.tensilica.com (192.168.15.138) with Microsoft SMTP Server (TLS) id 8.1.358.0; Tue, 19 May 2009 10:28:37 -0700 Message-ID: <4A12EC43.3010107@tensilica.com> Date: Tue, 19 May 2009 17:30: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 To: GDB Patches Subject: [Fwd: Re: [PATCH] Program Breakpoints] Content-Type: multipart/mixed; boundary="------------000409040607070807000502" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-05/txt/msg00401.txt.bz2 --------------000409040607070807000502 Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit Content-length: 6861 Time for the weekly ping. It's been almost a month now. Is there anybody who can review this? Thanks, Ross -- Ross Morley ross@tensilica.com ross@computer.org -------- Original Message -------- Subject: Re: [PATCH] Program Breakpoints Date: Thu, 30 Apr 2009 11:05:01 -0700 From: Ross Morley To: GDB Patches Ping code reviewers... (it's been over a week and doc is approved). I know you're all busy. I hope to get this wrapped up while its fresh in my mind and before the code base diverges too much. :-) Thanks, Ross -------- Original Message -------- Subject: Re: [PATCH] Program Breakpoints Date: Tue, 21 Apr 2009 18:21:52 -0700 From: Ross Morley To: GDB Patches CC: Maxim Grigoriev References: <49E93221.7010502@tensilica.com> Hello, I was able to run the regressions on x86 linux native, and fixed a problem. I've also incorporated Eli's feedback on the doc and NEWS (maybe I went a bit verbose on the NEWS, but you can tell me what to cut). I kept using the term "target" in the remote protocol section because it's common there. New patch attached, replaces previous. Awaiting technical review. I am least confident about my merge with non-stop thread support, though it causes no new test failures on x86 linux native. Thanks, Ross -- Ross Morley ross@tensilica.com ross@computer.org Ross Morley wrote: > Sorry, there was a minor technical glitch with the patch. Fixed patch > attached. > > -------- Original Message -------- > Subject: [PATCH] Program Breakpoints > Date: Fri, 17 Apr 2009 18:32:59 -0700 > From: Ross Morley > To: GDB Patches > CC: Maxim Grigoriev > > > > Hello GDB reviewers, > > This is the result of the RFC discussion on the GDB list late March. > I have simplified and updated the feature as discussed. In addition > I have supported it in gdbserver (only the Xtensa target so far). > In gdb and gdbserver, target support is optional, and targets that > do not support it behave as before. User guide updates are included. > > *** A patch is submitted for your review (attached). *** > > A detailed discussion follows... > > A "program breakpoint" is a trap instruction inherent to the target > program and unknown to GDB. It is like a permanent breakpoint except: > - it is unknown to GDB (not in the breakpoint table). > - it need not be the same instruction used by GDB for breakpoints. > > Here is the current behavior this patch fixes: > > GDB cannot distinguish a SIGTRAP due to a trap instruction in the > program from one due to single stepping (or other reasons). Breakpoints > are recognized only if they are known to (and usually planted by) GDB. > A trap instruction inherent in the target program is not recognized. > If the target hits one during normal run, GDB receives a SIGTRAP and > sees it as a random signal, reports SIGTRAP and (fortuituously) stops. > If this happens during stepping, GDB assumes the SIGTRAP is from a > single-step and keeps going, repeatedly hitting the trap. A user using > software watchpoints expects slow exection, so may wait a long time > before suspecting a problem, only to find out GDB is hung. > > Here's a description of the feature and the reasons for it: > > A new target.h macro is provided to allow GDB to determine that it > was stopped by a trap instruction: STOPPED_BY_TRAP_INSTRUCTION(size). > The optional size parameter is a pointer into which the size of the > instruction is written if the PC is pointing to it, allowing GDB to > skip it on resume or step. Targets that implement this recognize > program breakpoints by knowing they hit a trap that is not in the > breakpoint table. A GDB planted breakpoint always takes precedence > over a program breakpoint (in fact GDB might plant a breakpoint > over a program breakpoint). I have only implemented it for the > (remote) targets we support. > > Any target may implement this macro, receiving information from the > inferior or probing the instruction in memory, as appropriate. For > remote targets it is usually much more efficient to have the target > communicate that it hit a trap instruction (especially since some > targets may modify the PC to back out of an exception handler the > trap is used in, leaving GDB no way to know directly). > > Remote targets may notify GDB of hitting a trap instruction by an > extension to the stop-reply packet for SIGTRAP: "TAAtrap:r", where > r is a single digit representing the size of the trap instruction > if and only if the PC is pointing to it (it needs to be skipped). > That result is passed to infrun and infcmd via the macro above. > Note that the remote target is not expected to distinguish a > program breakpoint from a GDB-planted software breakpoint (that > distinction is made in infrun by looking up the breakpoint table). > > When GDB detects a program breakpoint (even while stepping) it > stops and reports it to both CLI and MI. When stopped by one (and > if the PC has not been altered while stopped), on resume or step > GDB will step over it by incrementing the PC by the size (if != 0). > In the case of step-instruction where PC points to the trap, the > first step does not actually run the inferior but merely increments > the PC, simulating the expected advance of 1 instruction. > > gdbserver has been modified to recognize a trap as distinct from > a single step, and pass the information from the low target up > to the remote interface. The target must support this for the > information to be passed to GDB via the stop-reply extension. > > This has been implemented and well tested in Xtensa toolchains > with the Xtensa instruction set simulator as the target agent. > It has now also been tested with gdbserver on Xtensa. No other > targets yet implement this. > > The user manual has been updated. I will update the internals > manual after this patch has been (possibly changed and) accepted. > > We have a target specific regression test internally. However I > don't know how to make a generic test case because it needs to > embed an arch-specific trap instruction with an __asm__ construct. > Advice on this would be appreciated. We could submit the test as > a target or arch specific test. > > In merging from our GDB 6.8 based internal source base (on which > our extensive testing was done) to the CVS head, I had to merge > with non-stop thread support and reverse debugging. I believe > I have handled those correctly, but have no target to test them > on. I hope someone can integrate this patch and run all the > regressions to make sure I didn't break anything. > > Thanks and best regards, > Ross > > -- > Ross Morley > ross@tensilica.com > ross@computer.org > > --------------000409040607070807000502 Content-Type: text/x-patch; name="program-breakpoints-20090421.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="program-breakpoints-20090421.diff" Content-length: 29207 2009-04-21 Ross Morley doc * doc/gdb.texinfo: Mention program breakpoints and associated remote protocol 'TAAtrap:r' stop-reply packet extension, and MI async record. gdb * NEWS: GDB recognizes program breakpoints (trap instructions in the target program and unknown to GDB) and can step over them. Includes remote protocol extension and requires target support. * gdbthread.h (struct thread_info): Add program_breakpoint_hit and program_breakpoint_size. * remote.c (remote_stopped_by_trap_instruction_p): New. (remote_trap_instruction_size): New. (struct stop_reply): New stopped_by_trap_instruction_p and trap_instruction_size. (remote_parse_stop_reply): Handle 'trap:size' remote protocol extension. (process_stop_reply): Set remote_stopped_by_trap_instruction_p and remote_trap_instruction_size from stop_reply. (remote_wait_as): Initialize remote_stopped_by_trap_instruction_p. (remote_stopped_by_trap_instruction): New. (init_remote_ops): Initialize new callback in remote_ops. * target.h (struct target_ops): Add to_stopped_by_trap_instruction. (STOPPED_BY_TRAP_INSTRUCTION): New. * target.c (update_current_target): Inherit and de_fault to_stopped_by_trap_instruction. (debug_to_stopped_by_trap_instruction): New. (setup_target_debug): Initialize to_stopped_by_trap_instruction. * infcmd.c: Include mi/mi-common.h. (step_1): Step-i over program breakpoint and report. * infrun.c (resume): Skip program breakpoint. (enum inferior_stop_reason): Add PROGRAM_BREAKPOINT stop reason. (handle_inferior_event): Recognize program breakpoint hit and avoid treating it as a random signal. Add debug diagnostic. (process_event_stop_test): Handle program breakpoint hit. (print_stop_reason): Handle PROGRAM_BREAKPOINT stop reason. (normal_stop): Print stop reason and location for program breakpoint. * mi/mi_common.h (enum async_reply_reason): New async reply reason EXEC_ASYNC_PROGRAM_BREAKPOINT. * mi/mi_common.c (async_reason_string_lookup): New program-breakpoint reason string for EXEC_ASYNC_PROGRAM_BREAKPOINT. gdbserver * NEWS: gdbserver recognizes trap instructions whether or not they are used by GDB for breakpoints, and reports them to the host GDB. * linux-low.c (linux_stopped_by_trap_instruction): New. (struct target_ops): Add linux_stopped_by_trap_instruction. * linux-low.h (struct linux_target_ops): New trap_size_at function. Comment breakpoint_at to clarify distinction from trap_size_at. * linux-xtensa-low.c (XTENSA_BREAKPOINT): Comment only 'density'. (xtensa_trap_size-at): New. (struct linux_target_ops): Add xtensa_trap_size_at + padding. Change '0' entries to 'NULL' for pointer fields. * remote-utils.c (prepare_resume_reply): Append 'trap:r' extension to 'TAA' stop-reply for SIGTRAP when stopped by trap instruction. * target.h (struct target_ops): Add stopped_by_trap_instruction. Index: gdb/doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.582 diff -u -r1.582 gdb.texinfo --- gdb/doc/gdb.texinfo 21 Apr 2009 16:31:06 -0000 1.582 +++ gdb/doc/gdb.texinfo 21 Apr 2009 22:23:28 -0000 @@ -2961,6 +2961,14 @@ (for example, routines that are arguments in a @code{pthread_create} call). +Some programs may contain embedded break or trap instructions that are +unknown to @value{GDBN}. These are called @dfn{program breakpoints} +because they belong to the program itself. If encountered, the inferior +may stop execution and report this to @value{GDBN} along with how much to +increment the PC to step over it. Because they are part of the program +code, program breakpoints cannot be deleted or disabled and do not show +up in @value{GDBN}'s list of breakpoints. + @cindex watchpoints @cindex data breakpoints @cindex memory tracing @@ -20185,6 +20193,8 @@ The inferior exited normally. @item signal-received A signal was received by the inferior. +@item program-breakpoint +A program breakpoint (trap instruction unknown to @value{GDBN}) was reached. @end table The @var{id} field identifies the thread that directly caused the stop @@ -26736,6 +26746,12 @@ @value{GDBN} should use @samp{qXfer:libraries:read} to fetch a new list of loaded libraries. @var{r} is ignored. +@item trap +The packet indicates that a break or trap instruction was hit. +@var{r} is the size of the instruction if the PC is pointing to it, +else 0 (for example if the hardware already incremented the PC). +@var{r} is ignored if the instruction was inserted by @value{GDBN}. + @cindex replay log events, remote reply @item replaylog The packet indicates that the target cannot continue replaying Index: gdb/NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.308 diff -u -r1.308 NEWS --- gdb/NEWS 20 Apr 2009 21:11:05 -0000 1.308 +++ gdb/NEWS 21 Apr 2009 22:23:30 -0000 @@ -7,6 +7,19 @@ feature is available with a native GDB running on kernel version 2.6.28 or later. +* GDB now supports handling embedded trap instructions that are unknown +to GDB. These are called "program breakpoints" because they belong to +the program itself. An inferior can report hitting a trap instruction +along with its size (it need not know whether the trap was inserted by +GDB as a breakpoint). If a trap is reported that GDB did not insert, +GDB will stop and report to the user or MI that a program breakpoint +was hit, and will be able to step over it on resume. Remote targets +use a new extension to the 'T' stop reply packet to report hitting a +trap ("TAAtrap:size"). Previously GDB was unable to distinguish a trap +instruction from a single step stop reason, so if stepping would try to +keep going and repeatedly hit the trap. Initially only Xtensa remote +targets report hitting a trap instruction. + * GDB now has support for multi-byte and wide character sets on the target. Strings whose character type is wchar_t, char16_t, or char32_t are now correctly printed. GDB supports wide- and unicode- Index: gdb/gdbthread.h =================================================================== RCS file: /cvs/src/src/gdb/gdbthread.h,v retrieving revision 1.47 diff -u -r1.47 gdbthread.h --- gdb/gdbthread.h 31 Mar 2009 15:23:57 -0000 1.47 +++ gdb/gdbthread.h 21 Apr 2009 22:23:31 -0000 @@ -131,6 +131,13 @@ back to user code before stopping and reporting the event. */ int stepping_through_solib_after_catch; + /* program_breakpoint_hit is set when a break or trap instruction was hit at + an address not in the breakpoint table (it's part of the program). If so, + program_breakpoint_size is the size of the instruction if it needs to be + skipped, else 0 (for example, the target already incremented the PC). */ + int program_breakpoint_hit; + int program_breakpoint_size; + /* When stepping_through_solib_after_catch is TRUE, this is a list of the catchpoints that should be reported as triggering when we finally do stop stepping. */ Index: gdb/remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.354 diff -u -r1.354 remote.c --- gdb/remote.c 16 Apr 2009 19:31:03 -0000 1.354 +++ gdb/remote.c 21 Apr 2009 22:23:34 -0000 @@ -528,6 +528,17 @@ /* This is non-zero if target stopped for a watchpoint. */ static int remote_stopped_by_watchpoint_p; +/* This is non-zero if target stopped for a trap instruction, whether or + not it was a software breakpoint planted by GDB. */ +static int remote_stopped_by_trap_instruction_p = 0; + +/* When remote_stopped_by_trap_instruction_p is non-zero, this is the size + of the instruction (or 0 if it should not be skipped) as reported by the + target. If non-zero GDB must increment the PC by size before resuming. + Generally this is non-zero if and only if the target stopped with PC at + the breakpoint. */ +static int remote_trap_instruction_size = 0; + static struct target_ops remote_ops; static struct target_ops extended_remote_ops; @@ -4157,6 +4168,9 @@ int stopped_by_watchpoint_p; CORE_ADDR watch_data_address; + int stopped_by_trap_instruction_p; + int trap_instruction_size; + int solibs_changed; int replay_event; }; @@ -4321,6 +4335,7 @@ event->solibs_changed = 0; event->replay_event = 0; event->stopped_by_watchpoint_p = 0; + event->stopped_by_trap_instruction_p = 0; event->regcache = NULL; switch (buf[0]) @@ -4343,6 +4358,7 @@ char *p_temp; int fieldsize; LONGEST pnum = 0; + ULONGEST size; /* If the packet contains a register number, save it in pnum and set p1 to point to the character following it. @@ -4387,6 +4403,12 @@ event->solibs_changed = 1; p = p_temp; } + else if (strncmp (p, "trap", p1 - p) == 0) + { + event->stopped_by_trap_instruction_p = 1; + p = unpack_varlen_hex (++p1, &size); + event->trap_instruction_size = (int) size; + } else if (strncmp (p, "replaylog", p1 - p) == 0) { /* NO_HISTORY event. @@ -4637,6 +4659,10 @@ remote_stopped_by_watchpoint_p = stop_reply->stopped_by_watchpoint_p; remote_watch_data_address = stop_reply->watch_data_address; + remote_stopped_by_trap_instruction_p + = stop_reply->stopped_by_trap_instruction_p; + remote_trap_instruction_size = stop_reply->trap_instruction_size; + remote_notice_new_inferior (ptid, 0); } @@ -4756,6 +4782,7 @@ buf = rs->buf; remote_stopped_by_watchpoint_p = 0; + remote_stopped_by_trap_instruction_p = 0; /* We got something. */ rs->waiting_for_stop_reply = 0; @@ -7041,6 +7068,13 @@ return rc; } +static int +remote_stopped_by_trap_instruction (int *size) +{ + if (remote_stopped_by_trap_instruction_p && size) + *size = remote_trap_instruction_size; + return remote_stopped_by_trap_instruction_p; +} static int remote_insert_hw_breakpoint (struct bp_target_info *bp_tgt) @@ -8800,6 +8834,8 @@ remote_ops.to_remove_breakpoint = remote_remove_breakpoint; remote_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint; remote_ops.to_stopped_data_address = remote_stopped_data_address; + remote_ops.to_stopped_by_trap_instruction = + remote_stopped_by_trap_instruction; remote_ops.to_can_use_hw_breakpoint = remote_check_watch_resources; remote_ops.to_insert_hw_breakpoint = remote_insert_hw_breakpoint; remote_ops.to_remove_hw_breakpoint = remote_remove_hw_breakpoint; Index: gdb/target.h =================================================================== RCS file: /cvs/src/src/gdb/target.h,v retrieving revision 1.149 diff -u -r1.149 target.h --- gdb/target.h 17 Mar 2009 19:28:09 -0000 1.149 +++ gdb/target.h 21 Apr 2009 22:23:35 -0000 @@ -372,6 +372,7 @@ int (*to_watchpoint_addr_within_range) (struct target_ops *, CORE_ADDR, CORE_ADDR, int); int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int); + int (*to_stopped_by_trap_instruction) (int *); void (*to_terminal_init) (void); void (*to_terminal_inferior) (void); void (*to_terminal_ours_for_output) (void); @@ -1127,6 +1128,14 @@ extern const struct target_desc *target_read_description (struct target_ops *); +/* Returns non-zero if we were stopped by a trap or break instruction, + whether or not it is a software break planted by GDB. If size != 0, + sets *size to that of the instruction or 0 if it need not be skipped. */ + +#ifndef STOPPED_BY_TRAP_INSTRUCTION +#define STOPPED_BY_TRAP_INSTRUCTION(size) \ + (*current_target.to_stopped_by_trap_instruction) (size) +#endif #define target_get_ada_task_ptid(lwp, tid) \ (*current_target.to_get_ada_task_ptid) (lwp,tid) Index: gdb/target.c =================================================================== RCS file: /cvs/src/src/gdb/target.c,v retrieving revision 1.206 diff -u -r1.206 target.c --- gdb/target.c 14 Apr 2009 16:48:07 -0000 1.206 +++ gdb/target.c 21 Apr 2009 22:23:36 -0000 @@ -115,6 +115,8 @@ static int debug_to_remove_watchpoint (CORE_ADDR, int, int); +static int debug_to_stopped_by_trap_instruction (int *); + static int debug_to_stopped_by_watchpoint (void); static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *); @@ -435,6 +437,7 @@ INHERIT (to_insert_watchpoint, t); INHERIT (to_remove_watchpoint, t); INHERIT (to_stopped_data_address, t); + INHERIT (to_stopped_by_trap_instruction, t); INHERIT (to_have_steppable_watchpoint, t); INHERIT (to_have_continuable_watchpoint, t); INHERIT (to_stopped_by_watchpoint, t); @@ -551,6 +554,9 @@ de_fault (to_stopped_data_address, (int (*) (struct target_ops *, CORE_ADDR *)) return_zero); + de_fault (to_stopped_by_trap_instruction, + (int (*) (int*)) + return_zero); de_fault (to_watchpoint_addr_within_range, default_watchpoint_addr_within_range); de_fault (to_region_ok_for_hw_watchpoint, @@ -2994,6 +3000,19 @@ return retval; } +static int +debug_to_stopped_by_trap_instruction (int *size) +{ + int retval; + + retval = debug_target.to_stopped_by_trap_instruction (size); + + fprintf_unfiltered (gdb_stdlog, + "target_stopped_by_trap_instruction (%d) = %d\n", + *size, retval); + return retval; +} + static void debug_to_terminal_init (void) { @@ -3230,6 +3249,7 @@ current_target.to_remove_watchpoint = debug_to_remove_watchpoint; current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint; current_target.to_stopped_data_address = debug_to_stopped_data_address; + current_target.to_stopped_by_trap_instruction = debug_to_stopped_by_trap_instruction; current_target.to_watchpoint_addr_within_range = debug_to_watchpoint_addr_within_range; current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint; current_target.to_terminal_init = debug_to_terminal_init; Index: gdb/infcmd.c =================================================================== RCS file: /cvs/src/src/gdb/infcmd.c,v retrieving revision 1.238 diff -u -r1.238 infcmd.c --- gdb/infcmd.c 25 Mar 2009 21:42:34 -0000 1.238 +++ gdb/infcmd.c 21 Apr 2009 22:23:37 -0000 @@ -52,6 +52,7 @@ #include "cli/cli-decode.h" #include "gdbthread.h" #include "valprint.h" +#include "mi/mi-common.h" /* Functions exported for general use, in inferior.h: */ @@ -822,6 +823,39 @@ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); } + /* "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. */ + if (target_has_execution && !ptid_equal (inferior_ptid, null_ptid)) + { + struct thread_info *tp = inferior_thread (); + if (tp->program_breakpoint_hit && tp->program_breakpoint_size != 0 + && execution_direction != EXEC_REVERSE && read_pc () == stop_pc + && count > 0) + { + count--; + write_pc (read_pc () + tp->program_breakpoint_size); + if (count == 0) + { + reinit_frame_cache (); + 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); + } + } + } + /* In synchronous case, all is well; each step_once call will step once. */ if (!target_can_async_p ()) { Index: gdb/infrun.c =================================================================== RCS file: /cvs/src/src/gdb/infrun.c,v retrieving revision 1.369 diff -u -r1.369 infrun.c --- gdb/infrun.c 20 Apr 2009 21:11:06 -0000 1.369 +++ gdb/infrun.c 21 Apr 2009 22:23:39 -0000 @@ -1029,6 +1029,11 @@ a command like `return' or `jump' to continue execution.")); } + /* Skip a program breakpoint (unless PC changed without running inferior). */ + if (tp->program_breakpoint_hit && tp->program_breakpoint_size != 0 + && execution_direction != EXEC_REVERSE && read_pc () == stop_pc) + write_pc (read_pc () + tp->program_breakpoint_size); + /* If enabled, step over breakpoints by executing a copy of the instruction at a different address. @@ -1564,7 +1569,9 @@ /* Inferior received signal, and user asked to be notified. */ SIGNAL_RECEIVED, /* Reverse execution -- target ran out of history info. */ - NO_HISTORY + NO_HISTORY, + /* Inferior stopped because of program breakpoint. */ + PROGRAM_BREAKPOINT }; /* The PTID we'll do a target_wait on.*/ @@ -2937,6 +2944,13 @@ || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP || stop_soon == STOP_QUIETLY_REMOTE) { + /* If we hit a trap not inserted by GDB, it must be in the program. */ + ecs->event_thread->program_breakpoint_hit + = (STOPPED_BY_TRAP_INSTRUCTION (&ecs->event_thread->program_breakpoint_size) + && !software_breakpoint_inserted_here_p (stop_pc)); + if (debug_infrun && ecs->event_thread->program_breakpoint_hit) + fprintf_unfiltered (gdb_stdlog, "infrun: program breakpoint hit\n"); + if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap) { if (debug_infrun) @@ -3016,6 +3030,7 @@ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP) ecs->random_signal = !(bpstat_explains_signal (ecs->event_thread->stop_bpstat) + || ecs->event_thread->program_breakpoint_hit || ecs->event_thread->trap_expected || (ecs->event_thread->step_range_end && ecs->event_thread->step_resume_breakpoint == NULL)); @@ -3136,6 +3151,21 @@ return; } + /* Handle case of hitting a program breakpoint (break instruction + in target program, not planted by or known to GDB). */ + + if (ecs->event_thread->program_breakpoint_hit) + { + stop_print_frame = 1; + + /* We are about to nuke the step_resume_breakpoint and + through_sigtramp_breakpoint via the cleanup chain, so + no need to worry about it here. */ + + stop_stepping (ecs); + return; + } + /* Handle cases caused by hitting a breakpoint. */ { CORE_ADDR jmp_buf_pc; @@ -4232,6 +4262,17 @@ /* Reverse execution: target ran out of history info. */ ui_out_text (uiout, "\nNo more reverse-execution history.\n"); break; + case PROGRAM_BREAKPOINT: + /* The inferior was stopped by a break/trap inherent in the program. */ + { + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_PROGRAM_BREAKPOINT)); + ui_out_text (uiout, "\nProgram breakpoint, "); + /* to be followed by source location, as for planted breakpoint */ + } + break; default: internal_error (__FILE__, __LINE__, _("print_stop_reason: unrecognized enum value")); @@ -4370,45 +4411,54 @@ int do_frame_printing = 1; struct thread_info *tp = inferior_thread (); - bpstat_ret = bpstat_print (tp->stop_bpstat); - switch (bpstat_ret) + if (tp->program_breakpoint_hit) + { + /* Print program break stop reason and description. */ + print_stop_reason (PROGRAM_BREAKPOINT, 0); + source_flag = SRC_AND_LOC; /* print location and source line */ + } + else { - case PRINT_UNKNOWN: - /* If we had hit a shared library event breakpoint, - bpstat_print would print out this message. If we hit - an OS-level shared library event, do the same - thing. */ - if (last.kind == TARGET_WAITKIND_LOADED) + bpstat_ret = bpstat_print (tp->stop_bpstat); + switch (bpstat_ret) { - printf_filtered (_("Stopped due to shared library event\n")); + case PRINT_UNKNOWN: + /* If we had hit a shared library event breakpoint, + bpstat_print would print out this message. If we hit + an OS-level shared library event, do the same + thing. */ + if (last.kind == TARGET_WAITKIND_LOADED) + { + printf_filtered (_("Stopped due to shared library event\n")); + source_flag = SRC_LINE; /* something bogus */ + do_frame_printing = 0; + break; + } + + /* FIXME: cagney/2002-12-01: Given that a frame ID does + (or should) carry around the function and does (or + should) use that when doing a frame comparison. */ + if (tp->stop_step + && frame_id_eq (tp->step_frame_id, + get_frame_id (get_current_frame ())) + && step_start_function == find_pc_function (stop_pc)) + source_flag = SRC_LINE; /* finished step, print source line */ + else + source_flag = SRC_AND_LOC; /* print location and source line */ + break; + case PRINT_SRC_AND_LOC: + source_flag = SRC_AND_LOC; /* print location and source line */ + break; + case PRINT_SRC_ONLY: + source_flag = SRC_LINE; + break; + case PRINT_NOTHING: source_flag = SRC_LINE; /* something bogus */ do_frame_printing = 0; break; + default: + internal_error (__FILE__, __LINE__, _("Unknown value.")); } - - /* FIXME: cagney/2002-12-01: Given that a frame ID does - (or should) carry around the function and does (or - should) use that when doing a frame comparison. */ - if (tp->stop_step - && frame_id_eq (tp->step_frame_id, - get_frame_id (get_current_frame ())) - && step_start_function == find_pc_function (stop_pc)) - source_flag = SRC_LINE; /* finished step, just print source line */ - else - source_flag = SRC_AND_LOC; /* print location and source line */ - break; - case PRINT_SRC_AND_LOC: - source_flag = SRC_AND_LOC; /* print location and source line */ - break; - case PRINT_SRC_ONLY: - source_flag = SRC_LINE; - break; - case PRINT_NOTHING: - source_flag = SRC_LINE; /* something bogus */ - do_frame_printing = 0; - break; - default: - internal_error (__FILE__, __LINE__, _("Unknown value.")); } /* The behavior of this routine with respect to the source Index: gdb/mi/mi-common.h =================================================================== RCS file: /cvs/src/src/gdb/mi/mi-common.h,v retrieving revision 1.7 diff -u -r1.7 mi-common.h --- gdb/mi/mi-common.h 3 Jan 2009 05:57:57 -0000 1.7 +++ gdb/mi/mi-common.h 21 Apr 2009 22:23:41 -0000 @@ -35,6 +35,7 @@ EXEC_ASYNC_EXITED, EXEC_ASYNC_EXITED_NORMALLY, EXEC_ASYNC_SIGNAL_RECEIVED, + EXEC_ASYNC_PROGRAM_BREAKPOINT, /* This is here only to represent the number of enums. */ EXEC_ASYNC_LAST }; Index: gdb/mi/mi-common.c =================================================================== RCS file: /cvs/src/src/gdb/mi/mi-common.c,v retrieving revision 1.7 diff -u -r1.7 mi-common.c --- gdb/mi/mi-common.c 21 Feb 2009 16:14:50 -0000 1.7 +++ gdb/mi/mi-common.c 21 Apr 2009 22:23:44 -0000 @@ -33,6 +33,7 @@ "exited", "exited-normally", "signal-received", + "program-breakpoint", NULL }; Index: gdb/gdbserver/linux-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v retrieving revision 1.97 diff -u -r1.97 linux-low.c --- gdb/gdbserver/linux-low.c 3 Apr 2009 11:40:02 -0000 1.97 +++ gdb/gdbserver/linux-low.c 21 Apr 2009 22:23:45 -0000 @@ -2886,6 +2886,29 @@ return 0; } +static int +linux_stopped_by_trap_instruction (int *size) +{ + CORE_ADDR stop_pc = get_stop_pc(); + int trap_size = 0; + + if (the_low_target.trap_size_at != NULL) + trap_size = (*the_low_target.trap_size_at) (stop_pc); + else if (the_low_target.breakpoint_at != NULL + && (*the_low_target.breakpoint_at) (stop_pc)) + trap_size = the_low_target.breakpoint_len; + + if (trap_size != 0) + { + *size = (the_low_target.get_pc != NULL + && (*the_low_target.get_pc) () == stop_pc) + ? trap_size : 0; + return 1; + } + else + return 0; +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -2923,6 +2946,7 @@ linux_supports_non_stop, linux_async, linux_start_non_stop, + linux_stopped_by_trap_instruction, }; static void Index: gdb/gdbserver/linux-low.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v retrieving revision 1.28 diff -u -r1.28 linux-low.h --- gdb/gdbserver/linux-low.h 1 Apr 2009 22:50:24 -0000 1.28 +++ gdb/gdbserver/linux-low.h 21 Apr 2009 22:23:46 -0000 @@ -77,6 +77,9 @@ int decr_pc_after_break; + + /* Returns non-zero if there is a breakpoint at the PC (specifically, if + the target memory at PC matches the breakpoint field of this struct). */ int (*breakpoint_at) (CORE_ADDR pc); /* Watchpoint related functions. See target.h for comments. */ @@ -89,6 +92,11 @@ for registers smaller than an xfer unit). */ void (*collect_ptrace_register) (int regno, char *buf); void (*supply_ptrace_register) (int regno, const char *buf); + + /* Returns non-zero if there is any kind of trap instruction at the PC, + including but not limited to the instruction used for GDB breakpoints. + If so, the result is the size of the trap (PC increment to skip). */ + int (*trap_size_at) (CORE_ADDR pc); }; extern struct linux_target_ops the_low_target; Index: gdb/gdbserver/linux-xtensa-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-xtensa-low.c,v retrieving revision 1.4 diff -u -r1.4 linux-xtensa-low.c --- gdb/gdbserver/linux-xtensa-low.c 22 Mar 2009 23:57:10 -0000 1.4 +++ gdb/gdbserver/linux-xtensa-low.c 21 Apr 2009 22:23:47 -0000 @@ -140,6 +140,7 @@ { 0, 0, -1, -1, NULL, NULL } }; +/* Currently assumes the Xtensa 'density' option is configured: 'break.n 0'. */ #if XCHAL_HAVE_BE #define XTENSA_BREAKPOINT {0xd2,0x0f} #else @@ -175,12 +176,37 @@ return memcmp((char *)&insn, xtensa_breakpoint, xtensa_breakpoint_len) == 0; } +int +xtensa_trap_size_at (CORE_ADDR pc) +{ + unsigned char insn[3]; + + (*the_target->read_memory) (pc, insn, 3); + +#if XCHAL_HAVE_BE + if (insn[1] == 0xd2 && (insn[2] & 0x0f) == 0x0f) +#else + if (insn[0] == 0x2d && (insn[1] & 0xf0) == 0xf0) +#endif + /* break.n s (density) */ + return 2; +#if XCHAL_HAVE_BE + else if ((insn[2] & 0xf0) == 0x00 && (insn[1] & 0x0f) == 0x04 && insn[0] == 0x00) +#else + else if ((insn[0] & 0x0f) == 0x00 && (insn[1] & 0xf0) == 0x40 && insn[2] == 0x00) +#endif + /* break s, t */ + return 3; + else + return 0; +} + struct linux_target_ops the_low_target = { init_registers_xtensa, 0, - 0, - 0, - 0, + NULL, + NULL, + NULL, xtensa_get_pc, xtensa_set_pc, xtensa_breakpoint, @@ -188,4 +214,11 @@ NULL, 0, xtensa_breakpoint_at, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + xtensa_trap_size_at, }; Index: gdb/gdbserver/remote-utils.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v retrieving revision 1.66 diff -u -r1.66 remote-utils.c --- gdb/gdbserver/remote-utils.c 3 Apr 2009 14:38:38 -0000 1.66 +++ gdb/gdbserver/remote-utils.c 21 Apr 2009 22:23:49 -0000 @@ -1083,6 +1083,7 @@ { struct thread_info *saved_inferior; const char **regp; + int size; sprintf (buf, "T%02x", status->value.sig); buf += strlen (buf); @@ -1113,6 +1114,14 @@ *buf++ = ';'; } + else if (the_target->stopped_by_trap_instruction != NULL + && (*the_target->stopped_by_trap_instruction) (&size)) + { + sprintf (buf, "trap:%1x", size); + buf += 6; + *buf++ = ';'; + } + while (*regp) { buf = outreg (find_regno (*regp), buf); Index: gdb/gdbserver/target.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/target.h,v retrieving revision 1.36 diff -u -r1.36 target.h --- gdb/gdbserver/target.h 1 Apr 2009 22:50:24 -0000 1.36 +++ gdb/gdbserver/target.h 21 Apr 2009 22:23:50 -0000 @@ -275,6 +275,14 @@ /* Switch to non-stop (1) or all-stop (0) mode. Return 0 on success, -1 otherwise. */ int (*start_non_stop) (int); + + /* Returns non-zero if target was stopped by any trap instruction, else 0. + It may or may not have been a breakpoint planted by gdbserver or GDB. + If stopped by a trap and size != NULL, then *size is set to the size of + the trap instruction if the PC still points to it (for skipping), else 0. + This information is passed via the remote protocol to GDB. */ + + int (*stopped_by_trap_instruction) (int *size); }; extern struct target_ops *the_target; --------------000409040607070807000502--