* [RFC] stepping over permanent breakpoint
@ 2009-03-16 17:41 Aleksandar Ristovski
2009-03-16 18:22 ` Pedro Alves
` (2 more replies)
0 siblings, 3 replies; 17+ messages in thread
From: Aleksandar Ristovski @ 2009-03-16 17:41 UTC (permalink / raw)
To: gdb
[-- Attachment #1: Type: text/plain, Size: 1348 bytes --]
Hello,
When there is a hard-coded breakpoint in code, like in this
example (for x86):
#include <stdio.h>
int main()
{
__asm(" int $0x03\n");
printf("Hello World\n");
return 0;
}
gdb on linux will appear to work correctly.
However, on systems that do not need pc adjustment after
break (like QNX) gdb will not be able to step over that
breakpoint unless user explicitly sets a breakpoint on top
of it.
I think that in case of linux it is actually working by
accident - because kernel does not back-up instruction
pointer after hard-coded breakpoint instruction was
executed. Gdb will receive SIGTRAP but will not really know why.
Attached patch fixes this for systems where
gdbarch_decr_pc_after_break (gdbarch) == 0
I am still not sure this is the final fix. Wouldn't it be
better if we recognized a hard-coded breakpoint as a
breakpoint? There would be an issue since it is not in the
breakpoint list, but maybe we should either automatically
add it when we encounter it, or perhaps print with some
"special" number (to make it clear to the user it is not one
of the user-generated breakpoints).
Thanks,
Aleksandar Ristovski
QNX Software Systems
ChangeLog for your reference:
* infrun.c (adjust_pc_after_break): On systems with adjusted
PC after break, make sure hard-coded breakpoint is stepped-over.
[-- Attachment #2: infrun.c-adjust_pc_after_break-permanent-breakpoints-20090316.diff --]
[-- Type: text/x-patch, Size: 1309 bytes --]
Index: gdb/infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.361
diff -u -p -r1.361 infrun.c
--- gdb/infrun.c 1 Mar 2009 23:18:36 -0000 1.361
+++ gdb/infrun.c 16 Mar 2009 17:33:22 -0000
@@ -2089,14 +2089,29 @@ adjust_pc_after_break (struct execution_
we have nothing to do. */
regcache = get_thread_regcache (ecs->ptid);
gdbarch = get_regcache_arch (regcache);
- if (gdbarch_decr_pc_after_break (gdbarch) == 0)
- return;
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
- gdbarch_decr_pc_after_break (gdbarch);
+ if (gdbarch_decr_pc_after_break (gdbarch) == 0)
+ {
+ /* Check if we have stopped at a permanent breakpoint. */
+ int len;
+ const gdb_byte *brk;
+ gdb_byte *target_mem = alloca(32);
+
+ brk = gdbarch_breakpoint_from_pc (gdbarch, &breakpoint_pc, &len);
+ if (!target_read_memory (breakpoint_pc, target_mem, len)
+ && memcmp (target_mem, brk, len) == 0)
+ {
+ breakpoint_pc += len;
+ regcache_write_pc (regcache, breakpoint_pc);
+ }
+ return;
+ }
+
/* Check whether there actually is a software breakpoint inserted at
that location.
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [RFC] stepping over permanent breakpoint 2009-03-16 17:41 [RFC] stepping over permanent breakpoint Aleksandar Ristovski @ 2009-03-16 18:22 ` Pedro Alves 2009-03-16 18:55 ` Aleksandar Ristovski 2009-03-16 18:50 ` Mark Kettenis 2009-03-23 16:50 ` RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) Ross Morley 2 siblings, 1 reply; 17+ messages in thread From: Pedro Alves @ 2009-03-16 18:22 UTC (permalink / raw) To: gdb; +Cc: Aleksandar Ristovski On Monday 16 March 2009 17:40:49, Aleksandar Ristovski wrote: > Hello, > > When there is a hard-coded breakpoint in code, like in this > example (for x86): > > #include <stdio.h> > > int main() > { > __asm(" int $0x03\n"); > printf("Hello World\n"); > return 0; > } > > gdb on linux will appear to work correctly. > > However, on systems that do not need pc adjustment after > break (like QNX) gdb will not be able to step over that > breakpoint (...) > (...) unless user explicitly sets a breakpoint on top > of it. Which I think your patch breaks? :-) > > I think that in case of linux it is actually working by > accident - because kernel does not back-up instruction > pointer after hard-coded breakpoint instruction was > executed. Gdb will receive SIGTRAP but will not really know why. > > Attached patch fixes this for systems where > gdbarch_decr_pc_after_break (gdbarch) == 0 > > I am still not sure this is the final fix. Wouldn't it be > better if we recognized a hard-coded breakpoint as a > breakpoint? There would be an issue since it is not in the > breakpoint list, but maybe we should either automatically > add it when we encounter it, or perhaps print with some > "special" number (to make it clear to the user it is not one > of the user-generated breakpoints). How about if you do the detection on resume instead? (please forgive my manual-patch-writing-in-email skills) infrun.c:resume: /* Normally, by the time we reach `resume', the breakpoints are either removed or inserted, as appropriate. The exception is if we're sitting at a permanent breakpoint; we need to step over it, but permanent breakpoints can't be removed. So we have to test for it here. */ - if (breakpoint_here_p (pc) == permanent_breakpoint_here) + if (pc == stop_pc + && gdbarch_decr_pc_after_break (gdbarch) == 0 + && (breakpoint_here_p (pc) == permanent_breakpoint_here + || hardcoded_breakpoint_inserted_here_p (pc))) { if (gdbarch_skip_permanent_breakpoint_p (gdbarch)) gdbarch_skip_permanent_breakpoint (gdbarch, regcache); else error (_("\ The program is stopped at a permanent breakpoint, but GDB does not know\n\ how to step past a permanent breakpoint on this architecture. Try using\n\ a command like `return' or `jump' to continue execution.")); } Then, have to make sure all decr_pc_after_break == 0 archs implement gdbarch_skip_permanent_breakpoint. Maybe change the default to just skip the breakpoint op, like i386_skip_permanent_breakpoint. I wonder why that isn't the case today? Hmmm, actually, why isn't this done on `proceed' instead of on `resume': infrun.c:proceed (): (...) if (addr == (CORE_ADDR) -1) { + if (pc == stop_pc + && gdbarch_decr_pc_after_break (gdbarch) == 0 + && execution_direction != EXEC_REVERSE + && (breakpoint_here_p (pc) == permanent_breakpoint_here + || hardcoded_breakpoint_inserted_here_p (pc))) + gdbarch_skip_permanent_breakpoint (gdbarch, regcache); - if (pc == stop_pc && breakpoint_here_p (pc) + else if (pc == stop_pc && breakpoint_here_p (pc) && execution_direction != EXEC_REVERSE) ? What do you think? What do others think? One thing this changes if that on decr_pc_after_break == 0 targets, if you single-step into a hardcoded breakpoint trap, and then issue a "continue", you'll not get a SIGTRAP reported, instead it is silently skipped. Not sure if that's a problem, and if it is, if it is worth tackling. I can't see how easily to fix it without having a "had been stepping before" thread flag, that isn't cleared by clear_proceed_status. -- Pedro Alves ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC] stepping over permanent breakpoint 2009-03-16 18:22 ` Pedro Alves @ 2009-03-16 18:55 ` Aleksandar Ristovski 2009-03-16 19:38 ` Pedro Alves 0 siblings, 1 reply; 17+ messages in thread From: Aleksandar Ristovski @ 2009-03-16 18:55 UTC (permalink / raw) To: gdb [-- Attachment #1: Type: text/plain, Size: 4429 bytes --] Pedro Alves wrote: > On Monday 16 March 2009 17:40:49, Aleksandar Ristovski wrote: >> Hello, >> >> When there is a hard-coded breakpoint in code, like in this >> example (for x86): >> >> #include <stdio.h> >> >> int main() >> { >> __asm(" int $0x03\n"); >> printf("Hello World\n"); >> return 0; >> } >> >> gdb on linux will appear to work correctly. >> >> However, on systems that do not need pc adjustment after >> break (like QNX) gdb will not be able to step over that >> breakpoint (...) > >> (...) unless user explicitly sets a breakpoint on top >> of it. > > Which I think your patch breaks? :-) No, it doesn't, it will behave as before. Observe where is the code I added, it is inside if (gdbarch_decr_pc_after_break (gdbarch) == 0) so for linux, it won't even be executed. > >> I think that in case of linux it is actually working by >> accident - because kernel does not back-up instruction >> pointer after hard-coded breakpoint instruction was >> executed. Gdb will receive SIGTRAP but will not really know why. >> >> Attached patch fixes this for systems where >> gdbarch_decr_pc_after_break (gdbarch) == 0 >> >> I am still not sure this is the final fix. Wouldn't it be >> better if we recognized a hard-coded breakpoint as a >> breakpoint? There would be an issue since it is not in the >> breakpoint list, but maybe we should either automatically >> add it when we encounter it, or perhaps print with some >> "special" number (to make it clear to the user it is not one >> of the user-generated breakpoints). > > How about if you do the detection on resume instead? > (please forgive my manual-patch-writing-in-email skills) > > infrun.c:resume: > > /* Normally, by the time we reach `resume', the breakpoints are either > removed or inserted, as appropriate. The exception is if we're sitting > at a permanent breakpoint; we need to step over it, but permanent > breakpoints can't be removed. So we have to test for it here. */ > - if (breakpoint_here_p (pc) == permanent_breakpoint_here) > + if (pc == stop_pc > + && gdbarch_decr_pc_after_break (gdbarch) == 0 > + && (breakpoint_here_p (pc) == permanent_breakpoint_here > + || hardcoded_breakpoint_inserted_here_p (pc))) > { > if (gdbarch_skip_permanent_breakpoint_p (gdbarch)) > gdbarch_skip_permanent_breakpoint (gdbarch, regcache); > else > error (_("\ > The program is stopped at a permanent breakpoint, but GDB does not know\n\ > how to step past a permanent breakpoint on this architecture. Try using\n\ > a command like `return' or `jump' to continue execution.")); > } > > Then, have to make sure all decr_pc_after_break == 0 archs implement > gdbarch_skip_permanent_breakpoint. Maybe change the default to just > skip the breakpoint op, like i386_skip_permanent_breakpoint. I wonder > why that isn't the case today? > > Hmmm, actually, why isn't this done on `proceed' instead of on `resume': > > infrun.c:proceed (): > (...) > if (addr == (CORE_ADDR) -1) > { > + if (pc == stop_pc > + && gdbarch_decr_pc_after_break (gdbarch) == 0 > + && execution_direction != EXEC_REVERSE > + && (breakpoint_here_p (pc) == permanent_breakpoint_here > + || hardcoded_breakpoint_inserted_here_p (pc))) > + gdbarch_skip_permanent_breakpoint (gdbarch, regcache); > - if (pc == stop_pc && breakpoint_here_p (pc) > + else if (pc == stop_pc && breakpoint_here_p (pc) > && execution_direction != EXEC_REVERSE) > > ? > > What do you think? What do others think? > > One thing this changes if that on decr_pc_after_break == 0 targets, if > you single-step into a hardcoded breakpoint trap, and then issue > a "continue", you'll not get a SIGTRAP reported, instead it is > silently skipped. Not sure if that's a problem, and if it is, if it is > worth tackling. I can't see how easily to fix it without having a > "had been stepping before" thread flag, that isn't cleared by > clear_proceed_status. > I have tried path similar to what you suggest. It seems more correct, but I would think that in addition to what you are doing, it would also need a change in adjust_pc_after_break to still decrement PC (to point to just-hit hardcoded breakpoint). Normally, adjust_pc_after_break will (on linux) miss this case and leave pc to point to instruction following breakpoint instruction. [-- Attachment #2: infrun.c.diff --] [-- Type: text/x-patch, Size: 606 bytes --] @@ -2106,7 +2121,8 @@ adjust_pc_after_break (struct execution_ SIGTRAPs, we keep a list of such breakpoint locations for a bit, and retire them after a number of stop events are reported. */ if (software_breakpoint_inserted_here_p (breakpoint_pc) - || (non_stop && moribund_breakpoint_here_p (breakpoint_pc))) + || (non_stop && moribund_breakpoint_here_p (breakpoint_pc)) + || hardcoded_breakpoint_inserted_here_p (breakpoint_pc)) { /* When using hardware single-step, a SIGTRAP is reported for both a completed single-step and a software breakpoint. Need to ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC] stepping over permanent breakpoint 2009-03-16 18:55 ` Aleksandar Ristovski @ 2009-03-16 19:38 ` Pedro Alves 2009-03-16 20:37 ` Aleksandar Ristovski 0 siblings, 1 reply; 17+ messages in thread From: Pedro Alves @ 2009-03-16 19:38 UTC (permalink / raw) To: gdb; +Cc: Aleksandar Ristovski On Monday 16 March 2009 18:55:27, Aleksandar Ristovski wrote: > Pedro Alves wrote: > > On Monday 16 March 2009 17:40:49, Aleksandar Ristovski wrote: > >> However, on systems that do not need pc adjustment after > >> break (like QNX) gdb will not be able to step over that > >> breakpoint (...) > > > >> (...) unless user explicitly sets a breakpoint on top > >> of it. > > > > Which I think your patch breaks? :-) > > No, it doesn't, it will behave as before. Observe where is > the code I added, it is inside > if (gdbarch_decr_pc_after_break (gdbarch) == 0) > so for linux, it won't even be executed. Not all architectures that run linux need PC adjustment. You're thinking x86-linux. Anyway, I meant that you're breaking setting a user breakpoint on top of a permanent breakpoint. Try setting a breakpoint with "break *int3_addr", on top of that int3, and running to it. When it is hit, you're moving the PC passed it, so later calls to bpstat_stop_status like: /* See if there is a breakpoint at the current PC. */ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ... will not see the permanent breakpoint, right? > I have tried path similar to what you suggest. It seems more > correct, but I would think that in addition to what you are > doing, it would also need a change in adjust_pc_after_break > to still decrement PC (to point to just-hit hardcoded > breakpoint). Normally, adjust_pc_after_break will (on linux) > miss this case and leave pc to point to instruction > following breakpoint instruction. Yeah, I considered that, but I think that it is legitimate to want to pass SIGTRAPs to the inferior, and have a SIGTRAP handler see whatever it would see if GDB wasn't there. This may be useful for debugging programs that embed a gdb stub in process, for example. So, on decr_pc_after_break != 0 targets, I'd leave things as they are. Mark's point about considering a trap instruction as a normal instruction is valid, so I'm not sure if we'd want to do this skipping by default or not. I'll let you guys fight over it. :-) -- Pedro Alves ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC] stepping over permanent breakpoint 2009-03-16 19:38 ` Pedro Alves @ 2009-03-16 20:37 ` Aleksandar Ristovski 0 siblings, 0 replies; 17+ messages in thread From: Aleksandar Ristovski @ 2009-03-16 20:37 UTC (permalink / raw) To: gdb Pedro Alves wrote: > > Not all architectures that run linux need PC adjustment. You're > thinking x86-linux. Anyway, I meant that you're breaking setting > a user breakpoint on top of a permanent breakpoint. Try > setting a breakpoint with "break *int3_addr", on top > of that int3, and running to it. When it is hit, you're moving > the PC passed it, so later calls to bpstat_stop_status like: > > /* See if there is a breakpoint at the current PC. */ > ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); > > ... will not see the permanent breakpoint, right? Hmm... very interesting. I am not seeing what you suggest (it works for me) but by looking at the code, I don't understand why - I agree it should be broken as you say, but for some reason it isn't. I will have to look into this a bit more (I am working in gdb 6.7). > > Mark's point about considering a trap instruction as a normal > instruction is valid, so I'm not sure if we'd want to do this > skipping by default or not. I'll let you guys fight > over it. :-) > Other than wanting to make gdb on qnx work, I have no strong feelings about one way or the other... It was a thought. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC] stepping over permanent breakpoint 2009-03-16 17:41 [RFC] stepping over permanent breakpoint Aleksandar Ristovski 2009-03-16 18:22 ` Pedro Alves @ 2009-03-16 18:50 ` Mark Kettenis 2009-03-16 19:04 ` Aleksandar Ristovski 2009-03-23 16:50 ` RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) Ross Morley 2 siblings, 1 reply; 17+ messages in thread From: Mark Kettenis @ 2009-03-16 18:50 UTC (permalink / raw) To: aristovski; +Cc: gdb > From: Aleksandar Ristovski <aristovski@qnx.com> > Date: Mon, 16 Mar 2009 13:40:49 -0400 > > Hello, > > When there is a hard-coded breakpoint in code, like in this > example (for x86): > > #include <stdio.h> > > int main() > { > __asm(" int $0x03\n"); > printf("Hello World\n"); > return 0; > } > > gdb on linux will appear to work correctly. Well, on Linux, that instruction will not be interpreted as a permanent breakpoint, just like on QNX. > However, on systems that do not need pc adjustment after > break (like QNX) gdb will not be able to step over that > breakpoint unless user explicitly sets a breakpoint on top > of it. The big question here is whether a breakpoint trap instruction should always be interpreted as a permanent breakpoint in GDB or that it only gets interpreted as such if you actually tell GDB about it. Up until now, we've always done the latter. If you don't tell GDB, random breakpoint trap instructions are handled as normal instructions and you get to see whatever the architecture/OS does for these instructions. > I think that in case of linux it is actually working by > accident - because kernel does not back-up instruction > pointer after hard-coded breakpoint instruction was > executed. Gdb will receive SIGTRAP but will not really know why. > > Attached patch fixes this for systems where > gdbarch_decr_pc_after_break (gdbarch) == 0 If you want to fix things, it should be fixed for *all* systems. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [RFC] stepping over permanent breakpoint 2009-03-16 18:50 ` Mark Kettenis @ 2009-03-16 19:04 ` Aleksandar Ristovski 0 siblings, 0 replies; 17+ messages in thread From: Aleksandar Ristovski @ 2009-03-16 19:04 UTC (permalink / raw) To: gdb Mark Kettenis wrote: >> From: Aleksandar Ristovski <aristovski@qnx.com> >> Date: Mon, 16 Mar 2009 13:40:49 -0400 >> >> Hello, >> >> When there is a hard-coded breakpoint in code, like in this >> example (for x86): >> >> #include <stdio.h> >> >> int main() >> { >> __asm(" int $0x03\n"); >> printf("Hello World\n"); >> return 0; >> } >> >> gdb on linux will appear to work correctly. > > Well, on Linux, that instruction will not be interpreted as a > permanent breakpoint, just like on QNX. Except on QNX gdb will not be able to continue or step over that instruction. > >> However, on systems that do not need pc adjustment after >> break (like QNX) gdb will not be able to step over that >> breakpoint unless user explicitly sets a breakpoint on top >> of it. > > The big question here is whether a breakpoint trap instruction should > always be interpreted as a permanent breakpoint in GDB or that it only > gets interpreted as such if you actually tell GDB about it. Up until > now, we've always done the latter. If you don't tell GDB, random > breakpoint trap instructions are handled as normal instructions and > you get to see whatever the architecture/OS does for these > instructions. Yes, this is my dilemma. I think we could print more informative message, but I am not sure. > >> I think that in case of linux it is actually working by >> accident - because kernel does not back-up instruction >> pointer after hard-coded breakpoint instruction was >> executed. Gdb will receive SIGTRAP but will not really know why. >> >> Attached patch fixes this for systems where >> gdbarch_decr_pc_after_break (gdbarch) == 0 > > If you want to fix things, it should be fixed for *all* systems. > What I proposed only brings in line those systems and makes them able to continue after hitting a permanent breakpoint (so on systems that normally do not need adjustment, I added advancing over the hardcoded breakpoint). ^ permalink raw reply [flat|nested] 17+ messages in thread
* RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) 2009-03-16 17:41 [RFC] stepping over permanent breakpoint Aleksandar Ristovski 2009-03-16 18:22 ` Pedro Alves 2009-03-16 18:50 ` Mark Kettenis @ 2009-03-23 16:50 ` Ross Morley 2009-03-24 16:57 ` Daniel Jacobowitz 2009-03-31 0:44 ` Ross Morley 2 siblings, 2 replies; 17+ messages in thread From: Ross Morley @ 2009-03-23 16:50 UTC (permalink / raw) To: gdb [-- Attachment #1: Type: text/plain, Size: 11959 bytes --] It was interesting to see the matter of skipping permanent breakpoints come up on this list. This is very similar to an issue we dealt with a couple of years ago with Xtensa and remote targets. Our solution has been stable for at least two years, but has not yet been prepared for submission because I've had higher priorities (and at that time we were way out of sync with mainline GDB). The issue is actually more complicated than the forgoing discussion suggests. I'd like to discuss it here and present our solution. I'll attach a patch for our current solution relative to GDB 6.8, but I do propose to revise it to improve some areas based on our experience (in the next few weeks) - I'll discuss that toward the end of this post. 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. Terminology ----------- I use the term "program breakpoint" to denote a break instruction that is part of the program, that GDB did not plant nor know about. There is a feature called "permanent breakpoint" that is a little different in that GDB knows about it (it's in the breakpoint table). I didn't want to use the same term for something different (this is open to discussion). As far as I can tell, only the HPPA arch uses permanent breakpoints. It would be good to reconcile the two, but I haven't attempted that. 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. Note that the instruction that represents a program break is entirely arch-specific, and need not be the same one GDB plants for breakpoints. There might be several instructions or variations. One solution we rejected was to have GDB probe the code at the PC (if not at a known planted breakpoint). There are two problems: 1. GDB has to know which instructions to look for. 2. GDB has to probe memory every instruction when stepping, which can seriously hurt performance when there are s/w watchpoints (especially with remote targets). We decided it was best to have the target agent communicate that it is signalling a breakpoint. Note that the target agent might have no idea whether the break was planted by GDB, so it's up to GDB to distinguish by looking up the PC in its breakpoint table. Currently only a SIGTRAP is communicated, and GDB then looks up the PC in its breakpoint table to see if it hit a planted breakpoint. Otherwise, if stepping then GDB assumes it's a single-step trap, else GDB gives up and stops without explanation. For Xtensa we use only the remote protocol. The target signals a "T" stop-reply packet with a trap signal number. It does this whether it hit a break or was stepping. I needed to distinguish the cases. There are already extensions to the "T" packet (eg. "watch", "awatch", "rwatch", "thread"). I added another: TAApbreak:kind where the suffix "kind" is a number that gives arch-specific info about the type of breakpoint, including its size (for skipping). A target interface function and macro is defined so the higher levels of GDB can find out whether it was stopped by a program breakpoint (as opposed to a normal GDB planted breakpoint). STOPPED_BY_PROGRAM_BREAKPOINT(k) returns true or false, and writes the "kind" argument into (int *) k. Some questions arise which I'm sure are hitting your neurons about now. I'll address some of them before I go on. - What about target agents that don't (yet) implement the extension? Behavior is exactly as before: GDB will just treat the SIGTRAP as either a step or an unknown event. - Why "pbreak"? Any extension that starts with letters a-f requires a special case in the parser in remote.c which thinks it's a hex number. There is already a special case to handle "awatch". I wanted to avoid that (it turns out the parser also treats "p" special for currthread, so I will propose using "TAAtrap" - later). - What about non-remote targets? The target agent would have to communicate the information another way. If not, GDB behavior is exactly as before. I'm not sure whether this problem even exists for non-remote targets since I haven't looked into that. We define a target interface function and macro STOPPED_BY_PROGRAM_BREAKPOINT(k) which currently returns 0 (false) for non-remote targets. - Why not use a special signal instead of a remote protocol extension? There is no clear signal that is safe to use. GDB uses just SIGTRAP and SIGINT, and already overloads SIGTRAP for most things. The use of a remote protocol extension to disambiguate is well precedented. - Isn't the size of a breakpoint constant for a given arch? No. There can be several kinds used for different reasons. There can be several encodings on a single break instruction (Xtensa has the normal 3 byte and a "density" 2 byte encoding). - Can't GDB figure out the size of the break by itself? Of course GDB could disassemble the instruction. But that needs another remote protocol exchange to get the code. Why not have the debug agent just pass it along with the signal? 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! Problems with Current Implementation and Proposed Simplification ---------------------------------------------------------------- 1. "TAApbreak" requires a special case in the remote stop-reply packet parser to differentiate it from {S,T}AA:p<currthread>. This is really a parser issue, but I'd rather avoid the need to rewrite it or add another special case. I propose "TAAtrap". 2. The "kind" argument of "TAApbreak:kind" can encode some more information the user might be interested in, but the cost is adding two gdbarch functions. Yet the user can figure out the meaning from a disassembly. The only information GDB itself really needs is the size, so it can skip the breakpoint. 3. Non-remote targets aren't handled. However that should be just a matter of adding an implementation to the target interface, and nothing breaks meanwhile. 4. There are cases in which a target OS or debug agent uses a break to trigger an exception of some kind, and then unwinds the stack to before the exception (eg. in the Xtensa ISS). Then when GDB tries to skip the break, it skips real code. 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 Aleksandar Ristovski wrote: > Hello, > > When there is a hard-coded breakpoint in code, like in this example > (for x86): > > #include <stdio.h> > > int main() > { > __asm(" int $0x03\n"); > printf("Hello World\n"); > return 0; > } > > gdb on linux will appear to work correctly. > > However, on systems that do not need pc adjustment after break (like > QNX) gdb will not be able to step over that breakpoint unless user > explicitly sets a breakpoint on top of it. > > I think that in case of linux it is actually working by accident - > because kernel does not back-up instruction pointer after hard-coded > breakpoint instruction was executed. Gdb will receive SIGTRAP but will > not really know why. > > Attached patch fixes this for systems where > gdbarch_decr_pc_after_break (gdbarch) == 0 > > I am still not sure this is the final fix. Wouldn't it be better if we > recognized a hard-coded breakpoint as a breakpoint? There would be an > issue since it is not in the breakpoint list, but maybe we should > either automatically add it when we encounter it, or perhaps print > with some "special" number (to make it clear to the user it is not one > of the user-generated breakpoints). > > > Thanks, > > Aleksandar Ristovski > QNX Software Systems > > > > ChangeLog for your reference: > > * infrun.c (adjust_pc_after_break): On systems with adjusted PC after > break, make sure hard-coded breakpoint is stepped-over. > >------------------------------------------------------------------------ > >Index: gdb/infrun.c >=================================================================== >RCS file: /cvs/src/src/gdb/infrun.c,v >retrieving revision 1.361 >diff -u -p -r1.361 infrun.c >--- gdb/infrun.c 1 Mar 2009 23:18:36 -0000 1.361 >+++ gdb/infrun.c 16 Mar 2009 17:33:22 -0000 >@@ -2089,14 +2089,29 @@ adjust_pc_after_break (struct execution_ > we have nothing to do. */ > regcache = get_thread_regcache (ecs->ptid); > gdbarch = get_regcache_arch (regcache); >- if (gdbarch_decr_pc_after_break (gdbarch) == 0) >- return; > > /* Find the location where (if we've hit a breakpoint) the > breakpoint would be. */ > breakpoint_pc = regcache_read_pc (regcache) > - gdbarch_decr_pc_after_break (gdbarch); > >+ if (gdbarch_decr_pc_after_break (gdbarch) == 0) >+ { >+ /* Check if we have stopped at a permanent breakpoint. */ >+ int len; >+ const gdb_byte *brk; >+ gdb_byte *target_mem = alloca(32); >+ >+ brk = gdbarch_breakpoint_from_pc (gdbarch, &breakpoint_pc, &len); >+ if (!target_read_memory (breakpoint_pc, target_mem, len) >+ && memcmp (target_mem, brk, len) == 0) >+ { >+ breakpoint_pc += len; >+ regcache_write_pc (regcache, breakpoint_pc); >+ } >+ return; >+ } >+ > /* Check whether there actually is a software breakpoint inserted at > that location. > > > [-- Attachment #2: xtensa_program_bp.patch --] [-- Type: text/x-patch, Size: 23862 bytes --] diff -urN gdb-6.8-orig/gdb/gdbarch.c gdb-6.8-new/gdb/gdbarch.c --- gdb-6.8-orig/gdb/gdbarch.c 2009-03-19 17:29:47.000000000 -0700 +++ gdb-6.8-new/gdb/gdbarch.c 2009-03-20 11:29:29.000000000 -0700 @@ -190,6 +190,8 @@ gdbarch_memory_insert_breakpoint_ftype *memory_insert_breakpoint; gdbarch_memory_remove_breakpoint_ftype *memory_remove_breakpoint; CORE_ADDR decr_pc_after_break; + gdbarch_skip_program_breakpoint_ftype *skip_program_breakpoint; + gdbarch_describe_program_breakpoint_ftype *describe_program_breakpoint; CORE_ADDR deprecated_function_start_offset; gdbarch_remote_register_number_ftype *remote_register_number; gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address; @@ -312,6 +314,8 @@ default_memory_insert_breakpoint, /* memory_insert_breakpoint */ default_memory_remove_breakpoint, /* memory_remove_breakpoint */ 0, /* decr_pc_after_break */ + 0, /* skip_program_breakpoint */ + 0, /* describe_program_breakpoint */ 0, /* deprecated_function_start_offset */ default_remote_register_number, /* remote_register_number */ 0, /* fetch_tls_load_module_address */ @@ -550,6 +554,10 @@ /* Skip verify of memory_insert_breakpoint, invalid_p == 0 */ /* Skip verify of memory_remove_breakpoint, invalid_p == 0 */ /* Skip verify of decr_pc_after_break, invalid_p == 0 */ + if (gdbarch->skip_program_breakpoint == 0) + gdbarch->skip_program_breakpoint = default_skip_program_breakpoint; + if (gdbarch->describe_program_breakpoint == 0) + gdbarch->describe_program_breakpoint = default_describe_program_breakpoint; /* Skip verify of deprecated_function_start_offset, invalid_p == 0 */ /* Skip verify of remote_register_number, invalid_p == 0 */ /* Skip verify of fetch_tls_load_module_address, has predicate */ @@ -709,6 +717,9 @@ "gdbarch_dump: deprecated_function_start_offset = 0x%s\n", paddr_nz (gdbarch->deprecated_function_start_offset)); fprintf_unfiltered (file, + "gdbarch_dump: describe_program_breakpoint = <0x%lx>\n", + (long) gdbarch->describe_program_breakpoint); + fprintf_unfiltered (file, "gdbarch_dump: double_bit = %s\n", paddr_d (gdbarch->double_bit)); fprintf_unfiltered (file, @@ -940,6 +951,9 @@ "gdbarch_dump: skip_permanent_breakpoint = <0x%lx>\n", (long) gdbarch->skip_permanent_breakpoint); fprintf_unfiltered (file, + "gdbarch_dump: skip_program_breakpoint = <0x%lx>\n", + (long) gdbarch->skip_program_breakpoint); + fprintf_unfiltered (file, "gdbarch_dump: skip_prologue = <0x%lx>\n", (long) gdbarch->skip_prologue); fprintf_unfiltered (file, @@ -2183,6 +2197,40 @@ gdbarch->decr_pc_after_break = decr_pc_after_break; } +void +gdbarch_skip_program_breakpoint (struct gdbarch *gdbarch, int kind) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->skip_program_breakpoint != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_program_breakpoint called\n"); + gdbarch->skip_program_breakpoint (kind); +} + +void +set_gdbarch_skip_program_breakpoint (struct gdbarch *gdbarch, + gdbarch_skip_program_breakpoint_ftype skip_program_breakpoint) +{ + gdbarch->skip_program_breakpoint = skip_program_breakpoint; +} + +const char * +gdbarch_describe_program_breakpoint (struct gdbarch *gdbarch, int kind) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->describe_program_breakpoint != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_describe_program_breakpoint called\n"); + return gdbarch->describe_program_breakpoint (kind); +} + +void +set_gdbarch_describe_program_breakpoint (struct gdbarch *gdbarch, + gdbarch_describe_program_breakpoint_ftype describe_program_breakpoint) +{ + gdbarch->describe_program_breakpoint = describe_program_breakpoint; +} + CORE_ADDR gdbarch_deprecated_function_start_offset (struct gdbarch *gdbarch) { diff -urN gdb-6.8-orig/gdb/gdbarch.h gdb-6.8-new/gdb/gdbarch.h --- gdb-6.8-orig/gdb/gdbarch.h 2009-03-19 17:29:47.000000000 -0700 +++ gdb-6.8-new/gdb/gdbarch.h 2009-03-20 11:29:24.000000000 -0700 @@ -399,6 +399,21 @@ extern CORE_ADDR gdbarch_decr_pc_after_break (struct gdbarch *gdbarch); extern void set_gdbarch_decr_pc_after_break (struct gdbarch *gdbarch, CORE_ADDR decr_pc_after_break); +/* TENSILICA_LOCAL + Program breakpoints. These are break instructions in the target code, + not planted by GDB. Define this to skip program breakpoints: */ + +typedef void (gdbarch_skip_program_breakpoint_ftype) (int kind); +extern void gdbarch_skip_program_breakpoint (struct gdbarch *gdbarch, int kind); +extern void set_gdbarch_skip_program_breakpoint (struct gdbarch *gdbarch, gdbarch_skip_program_breakpoint_ftype *skip_program_breakpoint); + +/* TENSILICA_LOCAL + Define this to describe program breakpoints: */ + +typedef const char * (gdbarch_describe_program_breakpoint_ftype) (int kind); +extern const char * gdbarch_describe_program_breakpoint (struct gdbarch *gdbarch, int kind); +extern void set_gdbarch_describe_program_breakpoint (struct gdbarch *gdbarch, gdbarch_describe_program_breakpoint_ftype *describe_program_breakpoint); + /* A function can be addressed by either it's "pointer" (possibly a descriptor address) or "entry point" (first executable instruction). The method "convert_from_func_ptr_addr" converting the former to the diff -urN gdb-6.8-orig/gdb/gdbarch.sh gdb-6.8-new/gdb/gdbarch.sh --- gdb-6.8-orig/gdb/gdbarch.sh 2009-03-19 17:29:47.000000000 -0700 +++ gdb-6.8-new/gdb/gdbarch.sh 2009-03-20 11:29:09.000000000 -0700 @@ -484,6 +484,14 @@ m:int:memory_remove_breakpoint:struct bp_target_info *bp_tgt:bp_tgt:0:default_memory_remove_breakpoint::0 v:CORE_ADDR:decr_pc_after_break:::0:::0 +# TENSILICA_LOCAL +# Program breakpoints. These are break instructions in the target code, +# not planted by GDB. Define this to skip program breakpoints: +f:void:skip_program_breakpoint:int kind:kind:::default_skip_program_breakpoint::0 +# TENSILICA_LOCAL +# Define this to describe program breakpoints: +f:const char *:describe_program_breakpoint:int kind:kind:::default_describe_program_breakpoint::0 + # A function can be addressed by either it's "pointer" (possibly a # descriptor address) or "entry point" (first executable instruction). # The method "convert_from_func_ptr_addr" converting the former to the 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 */ /* In synchronous case, all is well, just use the regular for loop. */ if (!target_can_async_p ()) diff -urN gdb-6.8-orig/gdb/infrun.c gdb-6.8-new/gdb/infrun.c --- gdb-6.8-orig/gdb/infrun.c 2009-03-19 17:29:48.000000000 -0700 +++ gdb-6.8-new/gdb/infrun.c 2009-03-20 11:36:37.000000000 -0700 @@ -511,6 +511,9 @@ resume (int step, enum target_signal sig) { int should_resume = 1; +/* TENSILICA_LOCAL */ + int program_break_kind; +/* END TENSILICA_LOCAL */ struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); QUIT; @@ -549,6 +552,18 @@ a command like `return' or `jump' to continue execution.")); } +/* TENSILICA_LOCAL */ + /* Skip a program breakpoint, unless PC changed without running inferior. + This is the same as skipping a permanent breakpoint, except that + the preceding macro does not provide an argument to differentiate + varieties of break instructions to skip, requiring the implementation + to probe and decode the target code. Also the SKIP_PERMANENT_BREAKPOINT + macro is used only by HPPA and is not in gdbarch.h. */ + if (STOPPED_BY_PROGRAM_BREAKPOINT (&program_break_kind) && + read_pc() == stop_pc) + gdbarch_skip_program_breakpoint (current_gdbarch, program_break_kind); +/* END TENSILICA_LOCAL */ + if (step && gdbarch_software_single_step_p (current_gdbarch)) { /* Do it the hard way, w/temp breakpoints */ @@ -928,7 +943,11 @@ /* Inferior exited. */ EXITED, /* Inferior received signal, and user asked to be notified. */ - SIGNAL_RECEIVED + SIGNAL_RECEIVED, +/* TENSILICA_LOCAL */ + /* Inferior stopped because of program breakpoint. */ + PROGRAM_BREAK +/* END TENSILICA_LOCAL */ }; /* This structure contains what used to be local variables in @@ -2007,6 +2026,9 @@ ecs->random_signal = !(bpstat_explains_signal (stop_bpstat) || stepping_over_breakpoint +/* TENSILICA_LOCAL */ + || STOPPED_BY_PROGRAM_BREAKPOINT (NULL) +/* END TENSILICA_LOCAL */ || (step_range_end && step_resume_breakpoint == NULL)); else { @@ -2329,6 +2351,23 @@ } } +/* TENSILICA_LOCAL */ + /* Handle case of hitting a program breakpoint (break instruction + in target program, not planted by or known to GDB). */ + + if (STOPPED_BY_PROGRAM_BREAKPOINT (NULL)) + { + 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; + } +/* END TENSILICA_LOCAL */ + /* We come here if we hit a breakpoint but should not stop for it. Possibly we also were stepping and should stop for that. So fall through and @@ -3023,6 +3062,20 @@ (uiout, "reason", async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); break; +/* TENSILICA_LOCAL */ + case PROGRAM_BREAK: + /* This stop reason is used only for program breaks, never planted. */ + { + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string (uiout, "reason", "program-breakpoint"); + ui_out_text (uiout, "\nProgram breakpoint \""); + ui_out_field_fmt (uiout, "break-insn", "%s", + gdbarch_describe_program_breakpoint (current_gdbarch, stop_info)); + ui_out_text (uiout, "\", "); + /* to be followed by source location, as for planted breakpoint */ + } + break; +/* END TENSILICA_LOCAL */ case SIGNAL_EXITED: /* The inferior was terminated by a signal. */ annotate_signalled (); @@ -3208,10 +3261,21 @@ int source_flag; int do_frame_printing = 1; - bpstat_ret = bpstat_print (stop_bpstat); - switch (bpstat_ret) +/* TENSILICA_LOCAL */ + /* Print program break stop reason and description. */ + + if (STOPPED_BY_PROGRAM_BREAKPOINT (&bpstat_ret)) + { + print_stop_reason (PROGRAM_BREAK, bpstat_ret); + source_flag = SRC_AND_LOC; /* print location and source line */ + } + else { - case PRINT_UNKNOWN: +/* END TENSILICA_LOCAL */ + bpstat_ret = bpstat_print (stop_bpstat); + switch (bpstat_ret) + { + 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 @@ -3224,30 +3288,34 @@ 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 (stop_step - && frame_id_eq (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.")); + /* 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 (stop_step + && frame_id_eq (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.")); + } +/* TENSILICA_LOCAL */ } +/* END TENSILICA_LOCAL */ + if (ui_out_is_mi_like_p (uiout)) ui_out_field_int (uiout, "thread-id", diff -urN gdb-6.8-orig/gdb/remote.c gdb-6.8-new/gdb/remote.c --- gdb-6.8-orig/gdb/remote.c 2009-03-19 17:29:48.000000000 -0700 +++ gdb-6.8-new/gdb/remote.c 2009-03-20 11:41:52.000000000 -0700 @@ -473,6 +473,15 @@ /* This is non-zero if target stopped for a watchpoint. */ static int remote_stopped_by_watchpoint_p; +/* TENSILICA_LOCAL */ +/* This is non-zero if target stopped for a program breakpoint. */ +static int remote_stopped_by_program_breakpoint_p = 0; + +/* This is set to a architecture-specific representation of the kind of + program breakpoint if remote_stopped_by_program_breakpoint_p != 0. */ +static int remote_program_breakpoint_kind = 0; +/* END TENSILICA_LOCAL */ + static struct target_ops remote_ops; static struct target_ops extended_remote_ops; @@ -3399,6 +3408,9 @@ (*deprecated_target_wait_loop_hook) (); remote_stopped_by_watchpoint_p = 0; +/* TENSILICA_LOCAL */ + remote_stopped_by_program_breakpoint_p = 0; +/* END TENSILICA_LOCAL */ switch (buf[0]) { @@ -3474,6 +3486,19 @@ solibs_changed = 1; p = p_temp; } +/* TENSILICA_LOCAL */ + else if ((strncmp (p, "pbreak", p1 - p) == 0)) + { + /* Protocol extension for program break 'TAApbreak:kind' + where kind is an arch-specific integer encoding info + about the break instruction (eg. size, type, args). */ + ULONGEST kind; + + remote_stopped_by_program_breakpoint_p = 1; + p = unpack_varlen_hex (++p1, &kind); + remote_program_breakpoint_kind = (int)kind; + } +/* END TENSILICA_LOCAL */ else { /* Silently skip unknown optional info. */ @@ -3592,6 +3617,11 @@ remote_stopped_by_watchpoint_p = 0; +/* TENSILICA_LOCAL */ + remote_stopped_by_program_breakpoint_p = 0; + sigint_interrupt_flag = 0; +/* END TENSILICA_LOCAL PR */ + while (1) { char *buf, *p; @@ -3702,6 +3732,18 @@ solibs_changed = 1; p = p_temp; } +/* TENSILICA_LOCAL */ + else if ((strncmp (p, "pbreak", p1 - p) == 0)) + { + /* Protocol extension for program break 'TAApbreak:kind' + where kind is an arch-specific integer. */ + ULONGEST kind; + + remote_stopped_by_program_breakpoint_p = 1; + p = unpack_varlen_hex (++p1, &kind); + remote_program_breakpoint_kind = (int)kind; + } +/* END TENSILICA_LOCAL */ else { /* Silently skip unknown optional info. */ @@ -5720,6 +5762,19 @@ return rc; } +/* TENSILICA_LOCAL */ +/* Return non-zero if target was stopped by a program breakpoint. + If so and kind != NULL, set *kind to an architecture-specific value. */ + +static int +remote_stopped_by_program_breakpoint (int *kind) +{ + if (remote_stopped_by_program_breakpoint_p && kind != NULL) + *kind = remote_program_breakpoint_kind; + return remote_stopped_by_program_breakpoint_p; +} +/* END TENSILICA_LOCAL */ + static int remote_insert_hw_breakpoint (struct bp_target_info *bp_tgt) @@ -7229,6 +7284,10 @@ 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; +/* TENSILICA_LOCAL */ + remote_ops.to_stopped_by_program_breakpoint = + remote_stopped_by_program_breakpoint; +/* END TENSILICA_LOCAL */ 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; @@ -7365,6 +7424,10 @@ remote_async_ops.to_remove_watchpoint = remote_remove_watchpoint; remote_async_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint; remote_async_ops.to_stopped_data_address = remote_stopped_data_address; +/* TENSILICA_LOCAL */ + remote_async_ops.to_stopped_by_program_breakpoint = + remote_stopped_by_program_breakpoint; +/* END TENSILICA_LOCAL */ remote_async_ops.to_terminal_inferior = remote_async_terminal_inferior; remote_async_ops.to_terminal_ours = remote_async_terminal_ours; remote_async_ops.to_kill = remote_async_kill; diff -urN gdb-6.8-orig/gdb/target.c gdb-6.8-new/gdb/target.c --- gdb-6.8-orig/gdb/target.c 2009-03-19 17:29:49.000000000 -0700 +++ gdb-6.8-new/gdb/target.c 2009-03-20 11:44:22.000000000 -0700 @@ -410,6 +410,9 @@ INHERIT (to_insert_watchpoint, t); INHERIT (to_remove_watchpoint, t); INHERIT (to_stopped_data_address, t); +/* TENSILICA_LOCAL */ + INHERIT (to_stopped_by_program_breakpoint, t); +/* END TENSILICA_LOCAL */ INHERIT (to_stopped_by_watchpoint, t); INHERIT (to_have_steppable_watchpoint, t); INHERIT (to_have_continuable_watchpoint, t); @@ -539,6 +542,11 @@ de_fault (to_stopped_data_address, (int (*) (struct target_ops *, CORE_ADDR *)) return_zero); +/* TENSILICA_LOCAL -- Program breakpoint. */ + de_fault (to_stopped_by_program_breakpoint, + (int (*) (int*)) + return_zero); +/* END TENSILICA_LOCAL */ de_fault (to_region_ok_for_hw_watchpoint, default_region_ok_for_hw_watchpoint); de_fault (to_terminal_init, @@ -2400,6 +2408,22 @@ return retval; } +/* TENSILICA_LOCAL */ +static int +debug_to_stopped_by_program_breakpoint (int *kind) +{ + int retval; + + retval = debug_target.to_stopped_by_program_breakpoint (kind); + + fprintf_unfiltered (gdb_stdlog, + "target_stopped_by_program_breakpoint (%ld) = %ld\n", + (unsigned long) *kind, + (unsigned long) retval); + return retval; +} +/* END TENSILICA_LOCAL */ + static void debug_to_terminal_init (void) { @@ -2703,6 +2727,9 @@ 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; +/* TENSILICA_LOCAL */ + current_target.to_stopped_by_program_breakpoint = debug_to_stopped_by_program_breakpoint; +/* END TENSILICA_LOCAL */ current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint; current_target.to_terminal_init = debug_to_terminal_init; current_target.to_terminal_inferior = debug_to_terminal_inferior; diff -urN gdb-6.8-orig/gdb/target.h gdb-6.8-new/gdb/target.h --- gdb-6.8-orig/gdb/target.h 2009-03-19 17:29:49.000000000 -0700 +++ gdb-6.8-new/gdb/target.h 2009-03-20 11:45:20.000000000 -0700 @@ -369,6 +369,9 @@ int to_have_continuable_watchpoint; int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *); int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int); +/* TENSILICA_LOCAL -- Program breakpoints */ + int (*to_stopped_by_program_breakpoint) (int *); +/* END TENSILICA_LOCAL */ void (*to_terminal_init) (void); void (*to_terminal_inferior) (void); void (*to_terminal_ours_for_output) (void); @@ -1107,6 +1110,18 @@ extern const struct target_desc *target_read_description (struct target_ops *); +/* TENSILICA_LOCAL */ +/* Returns non-zero if we were stopped by a program breakpoint (break instr + embedded in the target code, not planted by GDB). If k != 0, sets *k to + an arch-specific integer indicating the kind of break instruction. */ + +#ifndef STOPPED_BY_PROGRAM_BREAKPOINT +#define STOPPED_BY_PROGRAM_BREAKPOINT(k) \ + (*current_target.to_stopped_by_program_breakpoint) (k) +#endif +/* END TENSILICA_LOCAL */ + + /* Command logging facility. */ #define target_log_command(p) \ diff -urN gdb-6.8-orig/gdb/xtensa-tdep.c gdb-6.8-new/gdb/xtensa-tdep.c --- gdb-6.8-orig/gdb/xtensa-tdep.c 2009-03-19 17:29:49.000000000 -0700 +++ gdb-6.8-new/gdb/xtensa-tdep.c 2009-03-20 11:52:50.000000000 -0700 @@ -2454,6 +2454,34 @@ return body_pc != 0 ? body_pc : start_pc; } +/* TENSILICA_LOCAL */ +static void +xtensa_skip_program_breakpoint (int kind) +{ + DEBUGTRACE ("xtensa_skip_program_breakpoint (pc = 0x%08x, kind = 0x%03x)\n", + (unsigned)read_pc (), kind); + + write_pc (read_pc () + 2 + ((kind >> 8) & 1)); + return; +} + +/* Provide a string description of a program breakpoint of a given kind. */ + +static const char * +xtensa_describe_program_breakpoint (int kind) +{ +/* Keep an eye: potential conflict with concurrent instances of this arch. */ + static char descr[16]; + int len; + + len = sprintf (descr, "break%s %u,%u", + (kind & 0xf00) ? "" : ".n", + (kind & 0x0f0) >> 4, + (kind & 0x00f)); + gdb_assert (len < 16); + return descr; +} + /* Verify the current configuration. */ static void xtensa_verify_config (struct gdbarch *gdbarch) @@ -2632,6 +2660,14 @@ /* Advance PC across any prologue instructions to reach "real" code. */ set_gdbarch_skip_prologue (gdbarch, xtensa_skip_prologue); +/* TENSILICA_LOCAL */ + /* Handle program breakpoints not planted by GDB. + It's Xtensa-specific, although we want to submit it. */ + set_gdbarch_skip_program_breakpoint (gdbarch, xtensa_skip_program_breakpoint); + set_gdbarch_describe_program_breakpoint (gdbarch, + xtensa_describe_program_breakpoint); +/* END TENSILICA_LOCAL */ + /* Stack grows downward. */ set_gdbarch_inner_than (gdbarch, core_addr_lessthan); ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) 2009-03-23 16:50 ` RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) Ross Morley @ 2009-03-24 16:57 ` Daniel Jacobowitz 2009-03-24 20:33 ` RFC: Program Breakpoints Ross Morley 2009-03-31 0:44 ` Ross Morley 1 sibling, 1 reply; 17+ messages in thread From: Daniel Jacobowitz @ 2009-03-24 16:57 UTC (permalink / raw) To: Ross Morley; +Cc: gdb On Mon, Mar 23, 2009 at 09:50:30AM -0700, Ross Morley wrote: > It was interesting to see the matter of skipping permanent breakpoints > come up on this list. This is very similar to an issue we dealt with > a couple of years ago with Xtensa and remote targets. Our solution > has been stable for at least two years, but has not yet been prepared > for submission because I've had higher priorities (and at that time we > were way out of sync with mainline GDB). The issue is actually more > complicated than the forgoing discussion suggests. > > I'd like to discuss it here and present our solution. I'll attach a > patch for our current solution relative to GDB 6.8, but I do propose > to revise it to improve some areas based on our experience (in the > next few weeks) - I'll discuss that toward the end of this post. I read through this; overall, it looks sane. On some targets implementing this would require the remote stub to read from pc anyway; that's faster than GDB doing it, but not necessarily much faster. But on some other targets the stub has to do this anyway, or can pipeline it with other necessary operations, so it's not a big loss. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-24 16:57 ` Daniel Jacobowitz @ 2009-03-24 20:33 ` Ross Morley 2009-03-24 20:40 ` Daniel Jacobowitz 0 siblings, 1 reply; 17+ messages in thread From: Ross Morley @ 2009-03-24 20:33 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb Daniel Jacobowitz wrote: >On Mon, Mar 23, 2009 at 09:50:30AM -0700, Ross Morley wrote: > > >>It was interesting to see the matter of skipping permanent breakpoints >>come up on this list. This is very similar to an issue we dealt with >>a couple of years ago with Xtensa and remote targets. Our solution >>has been stable for at least two years, but has not yet been prepared >>for submission because I've had higher priorities (and at that time we >>were way out of sync with mainline GDB). The issue is actually more >>complicated than the forgoing discussion suggests. >> >>I'd like to discuss it here and present our solution. I'll attach a >>patch for our current solution relative to GDB 6.8, but I do propose >>to revise it to improve some areas based on our experience (in the >>next few weeks) - I'll discuss that toward the end of this post. >> >> > >I read through this; overall, it looks sane. On some targets >implementing this would require the remote stub to read from pc >anyway; that's faster than GDB doing it, but not necessarily much >faster. But on some other targets the stub has to do this anyway, >or can pipeline it with other necessary operations, so it's not a big >loss. > > I think you're saying it's not a big deal performance-wise to do this without a remote protocol extension. Is that correct? I think it's quite possible to implement the target-specific macro STOPPED_BY_PROGRAM_BREAKPOINT(size) without any help from the remote protocol. That is certainly an option, and might be the method of choice for non-remote targets and some remote targets. Having the remote stub do the break detection has other benefits. It removes the burden of parsing the set of possible instructions that *might* cause a stop, from GDB, and lets the stub (which has already decided to signal a stop) simply tell GDB why it stopped. It also handles cases where the stub decides whether to stop or not based on factors beyond the instruction itself. Seems cleaner and more robust. In general I think SIGTRAP is too overloaded in GDB which has to jump through hoops to figure out why it stopped. What I'm hoping to get from this RFC is whether the community would accept this method, or whether it would rather take another approach (before I put in more effort to simplify our solution and submit it). We'd like to have a solution that we don't have to keep merging. :-) I'll wait a few more days in case others have something to say. Thanks, Ross ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-24 20:33 ` RFC: Program Breakpoints Ross Morley @ 2009-03-24 20:40 ` Daniel Jacobowitz 2009-03-24 23:48 ` Pedro Alves 2009-03-24 23:59 ` Ross Morley 0 siblings, 2 replies; 17+ messages in thread From: Daniel Jacobowitz @ 2009-03-24 20:40 UTC (permalink / raw) To: Ross Morley; +Cc: gdb On Tue, Mar 24, 2009 at 01:32:57PM -0700, Ross Morley wrote: >> I read through this; overall, it looks sane. On some targets >> implementing this would require the remote stub to read from pc >> anyway; that's faster than GDB doing it, but not necessarily much >> faster. But on some other targets the stub has to do this anyway, >> or can pipeline it with other necessary operations, so it's not a big >> loss. >> >> > > I think you're saying it's not a big deal performance-wise to do this > without a remote protocol extension. Is that correct? No, I was saying the opposite. Sometimes it will still be expensive to implement the protocol extension. I'm interested in whether anyone sees an approach that does not require instruction scanning. GDB has the option to cheat - it can consult the program (ELF file), separately from the target's view of memory. This would not work for stray breakpoints inserted in the program at runtime, though. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-24 20:40 ` Daniel Jacobowitz @ 2009-03-24 23:48 ` Pedro Alves 2009-03-25 7:58 ` Mark Kettenis 2009-03-24 23:59 ` Ross Morley 1 sibling, 1 reply; 17+ messages in thread From: Pedro Alves @ 2009-03-24 23:48 UTC (permalink / raw) To: gdb; +Cc: Daniel Jacobowitz, Ross Morley On Tuesday 24 March 2009 20:39:53, Daniel Jacobowitz wrote: > No, I was saying the opposite. Sometimes it will still be expensive > to implement the protocol extension. I'm interested in whether anyone > sees an approach that does not require instruction scanning. [ For the record, since I was curious about the win32 bits below ] Several OSs already export that info on their debug APIs, but we just discard it. Some linux archs expose it in the SIGTRAP siginfo, in the si_code field, in the form of TRAP_BRKPT, TRAP_TRACE. E.g., I think ppc does expose TRAP_BRKPT, but x86/x86_64 doesn't, at least not yet. I believe mac/darwin also distinguishes breakpoint traps from single-stepping traps at the debug api level. At least include/gdb/signals.h mentions TARGET_EXC_BREAKPOINT as being a Mach exception. This could mean that GNU/Hurd also distinguishes them. Windows distinguishes breakpoints from singlesteps at the debug API level too. We have EXCEPTION_SINGLE_STEP and EXCEPTION_BREAKPOINT. You'll see that windows-nat.c converts both to SIGTRAP. I've just confirmed this, by enabling "set debugexceptions on" on a Cygwin GDB. Probably other os/archs/targets have similar means to distinguish a breakpoint trap from a singlestep. Either through a different trap vector for each case, or looking at the trace flag and at the intruction stream themselves, etc. -- Pedro Alves ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-24 23:48 ` Pedro Alves @ 2009-03-25 7:58 ` Mark Kettenis 2009-03-25 13:17 ` Pedro Alves 0 siblings, 1 reply; 17+ messages in thread From: Mark Kettenis @ 2009-03-25 7:58 UTC (permalink / raw) To: pedro; +Cc: gdb, drow, ross [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 1712 bytes --] > From: Pedro Alves <pedro@codesourcery.com> > Date: Tue, 24 Mar 2009 23:48:21 +0000 > > On Tuesday 24 March 2009 20:39:53, Daniel Jacobowitz wrote: > > No, I was saying the opposite. Sometimes it will still be expensive > > to implement the protocol extension. I'm interested in whether anyone > > sees an approach that does not require instruction scanning. > > [ For the record, since I was curious about the win32 bits below ] > > Several OSs already export that info on their debug APIs, but we > just discard it. > > Some linux archs expose it in the SIGTRAP siginfo, in > the si_code field, in the form of TRAP_BRKPT, TRAP_TRACE. E.g., I think > ppc does expose TRAP_BRKPT, but x86/x86_64 doesn't, at least not yet. > > I believe mac/darwin also distinguishes breakpoint traps from > single-stepping traps at the debug api level. At least include/gdb/signals.h > mentions TARGET_EXC_BREAKPOINT as being a Mach exception. This could > mean that GNU/Hurd also distinguishes them. > > Windows distinguishes breakpoints from singlesteps at the debug API level > too. We have EXCEPTION_SINGLE_STEP and EXCEPTION_BREAKPOINT. You'll > see that windows-nat.c converts both to SIGTRAP. I've just confirmed this, > by enabling "set debugexceptions on" on a Cygwin GDB. > > Probably other os/archs/targets have similar means to distinguish a > breakpoint trap from a singlestep. Either through a different trap > vector for each case, or looking at the trace flag and at the intruction > stream themselves, etc. These statements are all rather i386-centric. Especially on targets that emulate single-stepping it may be impossible to distinguish. GDB should not depend on the ability to do so. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-25 7:58 ` Mark Kettenis @ 2009-03-25 13:17 ` Pedro Alves 0 siblings, 0 replies; 17+ messages in thread From: Pedro Alves @ 2009-03-25 13:17 UTC (permalink / raw) To: Mark Kettenis; +Cc: gdb, drow, ross On Wednesday 25 March 2009 07:57:26, Mark Kettenis wrote: > These statements are all rather i386-centric. These were examples, not statements of all-truth. I mentioned ppc-linux, and darwin; you meant hardware-single-stepping-centric. > Especially on targets > that emulate single-stepping it may be impossible to distinguish. GDB > should not depend on the ability to do so. If it's impossible to distinguish for some reason, then the target would still report SIGTRAP-means-all, like today. When the distinction on the debug api side is buggy and inconsistent, then GDB is better off without it. -- Pedro Alves ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-24 20:40 ` Daniel Jacobowitz 2009-03-24 23:48 ` Pedro Alves @ 2009-03-24 23:59 ` Ross Morley 1 sibling, 0 replies; 17+ messages in thread From: Ross Morley @ 2009-03-24 23:59 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb Daniel Jacobowitz wrote: >On Tue, Mar 24, 2009 at 01:32:57PM -0700, Ross Morley wrote: > > >>>I read through this; overall, it looks sane. On some targets >>>implementing this would require the remote stub to read from pc >>>anyway; that's faster than GDB doing it, but not necessarily much >>>faster. But on some other targets the stub has to do this anyway, >>>or can pipeline it with other necessary operations, so it's not a big >>>loss. >>> >>> >>> >>> >>I think you're saying it's not a big deal performance-wise to do this >>without a remote protocol extension. Is that correct? >> >> > >No, I was saying the opposite. > Sorry for the misunderstanding. >Sometimes it will still be expensive >to implement the protocol extension. > I would think that in most cases the stub already knows something about what's going on, be it a single-step trap, a data watchpoint match, or a breakpoint. It already has to distinguish some of those cases. In many if not most cases the stub gets an exception directed to a certain vector, an indication in a status register, or some other clue as to the nature of the stop. It doesn't need to distinguish types of break instruction except for size (if there's more than one). It also needn't distinguish GDB planted breaks from program breaks. If a target finds it's too expensive to implement the remote protocol extension, then that target can have GDB probe the instruction. >I'm interested in whether anyone >sees an approach that does not require instruction scanning. > > I suspect it's going to be very target and arch specific. >GDB has the option to cheat - it can consult the program (ELF file), >separately from the target's view of memory. This would not work for >stray breakpoints inserted in the program at runtime, though. > > Not always. Program breaks are often very useful in situations where you have code embedded in a ROM and no ELF file available. We put them in exception handlers to allow a debugger to get control when certain exceptions happen. I do agree it would be good to hear if anyone has any other ideas. Thanks, Ross ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-23 16:50 ` RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) Ross Morley 2009-03-24 16:57 ` Daniel Jacobowitz @ 2009-03-31 0:44 ` Ross Morley 2009-03-31 3:17 ` Daniel Jacobowitz 1 sibling, 1 reply; 17+ messages in thread From: Ross Morley @ 2009-03-31 0:44 UTC (permalink / raw) Cc: gdb 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. > <stuff deleted> > 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. > <stuff deleted> > 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! > <stuff deleted> > 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 */ > > > > ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: RFC: Program Breakpoints 2009-03-31 0:44 ` Ross Morley @ 2009-03-31 3:17 ` Daniel Jacobowitz 0 siblings, 0 replies; 17+ messages in thread From: Daniel Jacobowitz @ 2009-03-31 3:17 UTC (permalink / raw) To: Ross Morley; +Cc: gdb On Mon, Mar 30, 2009 at 05:44:20PM -0700, Ross Morley wrote: > What is the proper way to update the frame without the call to > deprecated_update_frame_pc_hack (get_current_frame (), read_pc ()); If write_pc doesn't automatically, then flush the frame chain yourself after write_pc. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2009-03-31 3:17 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-03-16 17:41 [RFC] stepping over permanent breakpoint Aleksandar Ristovski 2009-03-16 18:22 ` Pedro Alves 2009-03-16 18:55 ` Aleksandar Ristovski 2009-03-16 19:38 ` Pedro Alves 2009-03-16 20:37 ` Aleksandar Ristovski 2009-03-16 18:50 ` Mark Kettenis 2009-03-16 19:04 ` Aleksandar Ristovski 2009-03-23 16:50 ` RFC: Program Breakpoints (was: [RFC] stepping over permanent breakpoint) Ross Morley 2009-03-24 16:57 ` Daniel Jacobowitz 2009-03-24 20:33 ` RFC: Program Breakpoints Ross Morley 2009-03-24 20:40 ` Daniel Jacobowitz 2009-03-24 23:48 ` Pedro Alves 2009-03-25 7:58 ` Mark Kettenis 2009-03-25 13:17 ` Pedro Alves 2009-03-24 23:59 ` Ross Morley 2009-03-31 0:44 ` Ross Morley 2009-03-31 3:17 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox