* [RFA/7.8] user breakpoint not inserted if software-single-step at same location @ 2014-05-29 20:11 Joel Brobecker 2014-05-29 23:17 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Joel Brobecker @ 2014-05-29 20:11 UTC (permalink / raw) To: gdb-patches; +Cc: palves Hello, with the following code... 12 Nested; -- break #1 13 return I; -- break #2 14 end; (line 12 is a call to function Nested) ... we have noticed the following errorneous behavior on ppc-aix, where, after having inserted a breakpoint at line 12 and line 13, and continuing from the breakpoint at line 12, the program never stops at line 13, running away until the program terminates: % gdb -q func (gdb) b func.adb:12 Breakpoint 1 at 0x10000a24: file func.adb, line 12. (gdb) b func.adb:13 Breakpoint 2 at 0x10000a28: file func.adb, line 13. (gdb) run Starting program: /[...]/func Breakpoint 1, func () at func.adb:12 12 Nested; -- break #1 (gdb) c Continuing. [Inferior 1 (process 4128872) exited with code 02] When resuming from the first breakpoint, GDB first tries to step out of that first breakpoint. We rely on software single-stepping on this platform, and it just so happens that the address of the first software single-step breakpoint is the same as the user's breakpoint #2 (0x10000a28). So, with infrun and target traces turned on (but uninteresting traces snip'ed off), the "continue" operation looks like this: (gdb) c ### First, we insert the user breakpoints (the second one is an internal ### breakpoint on __pthread_init). The first user breakpoint is not ### inserted as we need to step out of it first. target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000d03f3800, xxx) = 0 ### Then we proceed with the step-out-of-breakpoint... infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [process 15335610] at 0x10000a24 ### That's when we insert the SSS breakpoints... target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000100009ac, xxx) = 0 ### ... then let the inferior resume... target_resume (15335610, continue, 0) infrun: wait_for_inferior () target_wait (-1, status, options={}) = 15335610, status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: target_wait (-1, status) = infrun: 15335610 [process 15335610], infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x100009ac ### At this point, we stopped at the second SSS breakpoint... target_stopped_by_watchpoint () = 0 ### We remove the SSS breakpoints... target_remove_breakpoint (0x0000000010000a28, xxx) = 0 target_remove_breakpoint (0x00000000100009ac, xxx) = 0 target_stopped_by_watchpoint () = 0 ### We find that we're not done, so we resume.... infrun: no stepping, continue ### And thus insert the user breakpoints again, except we're not ### inserting the second breakpoint?!? target_insert_breakpoint (0x0000000010000a24, xxx) = 0 infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [process 15335610] at 0x100009ac target_resume (-1, continue, 0) infrun: prepare_to_wait target_wait (-1, status, options={}) = 15335610, status->kind = exited, status = 2 What happens is that the removal of the software single-step breakpoints effectively removed the breakpoint instruction from inferior memory. But because such breakpoints are inserted directly as raw breakpoints rather than through the normal chain of breakpoints, we fail to notice that one of the user breakpoints points to the same address and that this user breakpoint is therefore effectively un-inserted. When resuming after the single-step, GDB thinks that the user breakpoint is still inserted and therefore does not need to insert it again. This patch fixes the problem by avoiding the creation of a raw breakpoint for any of the software single-step breakpoints when their address correspond to a user breakpoint which has already been inserted and whose address matches. The rest of the patch adjusts the code removing the software single-step breakpoints to take this possibility into account. As it happens, it simplifies the code a little bit. This patch does make one assumption, however, which is the fact that user breakpoints get inserted before software single-step breakpoints. I think this is a fair assumption, as software single-step breakpoints get created as part of the target-step operation (resume with step=1), which logically can only happen after we've inserted all breakpoints. For the record, this behavior started appearing after commit 31e77af205cf6564c2bf4c18400b4ca16bdf92cd (PR breakpoints/7143 - Watchpoint does not trigger when first set) was applied, but I have not checked whether it was really directly related to that commit, or a latent issue. gdb/ChangeLog: PR breakpoints/7143 * breakpoint.c (non_sss_software_breakpoint_inserted_here_p): New function, extracted from software_breakpoint_inserted_here_p. (software_breakpoint_inserted_here_p): Remove factored out code by call to non_sss_software_breakpoint_inserted_here_p. (insert_single_step_breakpoint): Do nothing if a non-software- single-step breakpoint was already inserted at the same address. (remove_single_step_breakpoints): Adjust to take into account the fact that the first software single-step may not have been inserted. Tested on ppc-aix with AdaCore's testsuite. Tested on x86_64-linux with the official testsuite. OK to commit? Also, due to the nature of the regression (compared to 7.7), I think we should wait for a resolution of this issue before creating the gdb 7.8 release branch. Thanks! -- Joel --- gdb/breakpoint.c | 56 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 676c7b8..f9dc413 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -4153,12 +4153,12 @@ breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc) return 0; } -/* This function returns non-zero iff there is a software breakpoint - inserted at PC. */ +/* Ignoring software single-step breakpoints, return non-zero iff + there is a software breakpoint inserted at PC. */ -int -software_breakpoint_inserted_here_p (struct address_space *aspace, - CORE_ADDR pc) +static int +non_sss_software_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) { struct bp_location *bl, **blp_tmp; @@ -4180,6 +4180,19 @@ software_breakpoint_inserted_here_p (struct address_space *aspace, } } + return 0; +} + +/* This function returns non-zero iff there is a software breakpoint + inserted at PC. */ + +int +software_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) +{ + if (non_sss_software_breakpoint_inserted_here_p (aspace, pc)) + return 1; + /* Also check for software single-step breakpoints. */ if (single_step_breakpoint_inserted_here_p (aspace, pc)) return 1; @@ -15149,6 +15162,13 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch, { void **bpt_p; + /* If a non-software-single-step breakpoint is inserted at the same + location as our next_pc, no need to insert an additional + raw breakpoint. */ + + if (non_sss_software_breakpoint_inserted_here_p (aspace, next_pc)) + return; + if (single_step_breakpoints[0] == NULL) { bpt_p = &single_step_breakpoints[0]; @@ -15189,22 +15209,18 @@ single_step_breakpoints_inserted (void) void remove_single_step_breakpoints (void) { - gdb_assert (single_step_breakpoints[0] != NULL); - - /* See insert_single_step_breakpoint for more about this deprecated - call. */ - deprecated_remove_raw_breakpoint (single_step_gdbarch[0], - single_step_breakpoints[0]); - single_step_gdbarch[0] = NULL; - single_step_breakpoints[0] = NULL; + int i; - if (single_step_breakpoints[1] != NULL) - { - deprecated_remove_raw_breakpoint (single_step_gdbarch[1], - single_step_breakpoints[1]); - single_step_gdbarch[1] = NULL; - single_step_breakpoints[1] = NULL; - } + for (i = 0; i < 2; i++) + if (single_step_breakpoints[i] != NULL) + { + /* See insert_single_step_breakpoint for more about + this deprecated call. */ + deprecated_remove_raw_breakpoint (single_step_gdbarch[i], + single_step_breakpoints[i]); + single_step_gdbarch[i] = NULL; + single_step_breakpoints[i] = NULL; + } } /* Delete software single step breakpoints without removing them from -- 1.9.1 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-29 20:11 [RFA/7.8] user breakpoint not inserted if software-single-step at same location Joel Brobecker @ 2014-05-29 23:17 ` Pedro Alves 2014-05-30 12:22 ` Joel Brobecker 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-05-29 23:17 UTC (permalink / raw) To: Joel Brobecker, gdb-patches On 05/29/2014 09:11 PM, Joel Brobecker wrote: > Hello, > > with the following code... > > 12 Nested; -- break #1 > 13 return I; -- break #2 > 14 end; > > (line 12 is a call to function Nested) > > ... we have noticed the following errorneous behavior on ppc-aix, "erroneous" > This patch does make one assumption, however, which is the fact > that user breakpoints get inserted before software single-step > breakpoints. I think this is a fair assumption, as software > single-step breakpoints get created as part of the target-step > operation (resume with step=1), which logically can only happen > after we've inserted all breakpoints. Async/background execution breaks that assumption though. E.g., say you do: (gdb) b *0xsame_addr_as_sss_bkpt (gdb) s & (gdb) del That "del" runs while the target is single-stepping. And it might just delete the breakpoint that was at the same address as a single-step breakpoint, before the single-step breakpoint traps or gdb collects the trap. If you try that on native GNU/Linux, it'll fail because then GDB can't poke at memory while the program is running. You can still trigger it with using two threads: (gdb) b *0xsame_addr_as_sss_bkpt (gdb) set scheduler-locking on (gdb) thread 1 (gdb) s & (gdb) thread 2 // this thread is stopped, so we can poke at memory. (gdb) del That's why I thought it'd be easier to do this in the "remove" path. We can still bypass actually inserting the sss breakpoint in the "insert" path if there's already another breakpoint there, but we'll need to create/clone the location and its shadow buffer, and then still handle the issue in the "remove" path. I'm now thinking that indeed we should implement that optimization, but not for efficiency (this being a corner case, it's doubtful it matters), but to cater for remote targets that might not handle duplicate Z0 packets well. They're supposed to be handled in an idempotent manner, but even GDBserver had related issues recently. Oh, _but_! If the target supports breakpoint evaluating breakpoint conditions itself (target_supports_evaluation_of_breakpoint_conditions), such as GDBserver, then we _need_ to send the duplicate software single-step Z0 breakpoint, in case the non-sss breakpoint that is already inserted at the same address was conditional, otherwise the target is only going to report the breakpoint hit if the non-sss breakpoint's condition evaluates true, while we need the sss breakpoint to be unconditional. (In this case we know for sure that the target knows what to do with the duplicate Z0 packets, it's a requirement of the feature.) In sum, in the "insert" path: - if !target_supports_evaluation_of_breakpoint_conditions; then optimize out the sss breakpoint if there's already a non-sss breakpoint inserted at the same address. else make sure to resend/reinsert the breakpoint sss breakpoint, even if there's already a non-sss in place, in case that other breakpoint was conditional. fi And in the "remove" path: - if there's still a non-sss breakpoint inserted at the same address, then don't actually remove the breakpoint off of the target, just wipe it from gdb's list. > Also, due to the nature of the regression (compared to 7.7), I think > we should wait for a resolution of this issue before creating the > gdb 7.8 release branch. I agree. Thanks, -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-29 23:17 ` Pedro Alves @ 2014-05-30 12:22 ` Joel Brobecker 2014-05-30 12:51 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Joel Brobecker @ 2014-05-30 12:22 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Hi Pedro, Thanks for the super quick review! > Async/background execution breaks that assumption though. Hmmm, you are right. I had a feeling that this assumption was going to come back to bite us one day. I didn't realize that it was going to be today! ;-) > We can still bypass actually inserting the sss breakpoint in > the "insert" path if there's already another breakpoint there, > but we'll need to create/clone the location and its shadow buffer, > and then still handle the issue in the "remove" path. [...] > In sum, in the "insert" path: > > - if !target_supports_evaluation_of_breakpoint_conditions; then > optimize out the sss breakpoint if there's already a > non-sss breakpoint inserted at the same address. > else > make sure to resend/reinsert the breakpoint sss breakpoint, > even if there's already a non-sss in place, in case that other > breakpoint was conditional. > fi > > And in the "remove" path: > > - if there's still a non-sss breakpoint inserted at the > same address, then don't actually remove the breakpoint > off of the target, just wipe it from gdb's list. It seems to me that we'd need to merge your initial recommendation into your summary above, right? Otherwise, wouldn't we fail in the async example you provided? Actually, wouldn't it fail regardless? Even if we inserted the SSS breakpoint, when the user deletes his breakpoints, since the breakpoint chain doesn't know about the SSS breakpoint, wouldn't it remove our SSS breakpoint insn? I am wondering whether the simpler approach that you initially suggested, which is to just handle the issue in the "remove" path for 7.8 wouldn't be a little safer, while we also look at actually enhancing SSS breakpoints via the normal breakpoint chain. I am wondering what's going to be needed for that... WDYT? Thanks! -- Joel ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 12:22 ` Joel Brobecker @ 2014-05-30 12:51 ` Pedro Alves 2014-05-30 13:27 ` Joel Brobecker 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-05-30 12:51 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 05/30/2014 01:22 PM, Joel Brobecker wrote: >> And in the "remove" path: >> >> - if there's still a non-sss breakpoint inserted at the >> same address, then don't actually remove the breakpoint >> off of the target, just wipe it from gdb's list. > > It seems to me that we'd need to merge your initial recommendation > into your summary above, right? I admit I don't know what recommendation you're referring to. :-) Otherwise, wouldn't we fail in > the async example you provided? Actually, wouldn't it fail > regardless? Even if we inserted the SSS breakpoint, when the user > deletes his breakpoints, since the breakpoint chain doesn't know > about the SSS breakpoint, wouldn't it remove our SSS breakpoint > insn? Ah, yes. We'd need the mirror treatment in bkpt_remove_location. > > I am wondering whether the simpler approach that you initially > suggested, which is to just handle the issue in the "remove" > path for 7.8 wouldn't be a little safer For 7.8, I'm thinking it's really safer to avoid resending duplicate Z0 packets to stubs that don't support conditional breakpoint evaluation on the target end. So I think we should handle the "insert" path too. BTW, did you try creating a test for the issue you discovered? I don't think we have anything that triggers this already in the tree, otherwise I think I'd have seen it with my software-single-step-on-x86 branch. > , while we also look > at actually enhancing SSS breakpoints via the normal breakpoint > chain. I am wondering what's going to be needed for that... I have done that at least two or three times before, and I was never that happy with the result. This was before the patch that led to this regression, and that one and the surrounding patches were actually result of exactly wanting to modernize software single-step. :-) The main issue is that SSS breakpoints and all other breakpoints need to be inserted/removed at different times, and that is surprisingly tricky to handle. But I'm hoping/assuming the codebase is a little bit more ready now for the next attempt. My main motivation is to be able to enable non-stop without forcing displaced-stepping for all single-steps (even those that don't step over a bkpt). -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 12:51 ` Pedro Alves @ 2014-05-30 13:27 ` Joel Brobecker 2014-05-30 15:57 ` Pedro Alves 2014-05-30 19:35 ` Joel Brobecker 0 siblings, 2 replies; 29+ messages in thread From: Joel Brobecker @ 2014-05-30 13:27 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > >> - if there's still a non-sss breakpoint inserted at the > >> same address, then don't actually remove the breakpoint > >> off of the target, just wipe it from gdb's list. > > > > It seems to me that we'd need to merge your initial recommendation > > into your summary above, right? > > I admit I don't know what recommendation you're referring to. :-) Sorry! This one: | but we'll need to create/clone the location and its shadow buffer, | and then still handle the issue in the "remove" path. > For 7.8, I'm thinking it's really safer to avoid resending > duplicate Z0 packets to stubs that don't support conditional > breakpoint evaluation on the target end. So I think we should > handle the "insert" path too. OK - I will take care of that. > BTW, did you try creating a test for the issue you discovered? > I don't think we have anything that triggers this already in > the tree, otherwise I think I'd have seen it with my > software-single-step-on-x86 branch. I am wondering how to create that test, because it would be a little tricky. We need to set ourselves into a situation where we single-step out of a breakpoint with the second SSS breakpoint being at the same address as one of the user breakpoints, that second SSS not being the one that gets hit during that first single-step-out-of-breakpoint. The only way I can see to achieve that, at the moment, is with a function call. The only reliable way to do that, I think, is with an assembly file, which means it'd be limited to a certain architecture. > I have done that at least two or three times before, and I was > never that happy with the result. This was before the patch > that led to this regression, and that one and the surrounding > patches were actually result of exactly wanting to modernize > software single-step. :-) The main issue is that SSS breakpoints > and all other breakpoints need to be inserted/removed at > different times, and that is surprisingly tricky to handle. > But I'm hoping/assuming the codebase is a little bit more > ready now for the next attempt. My main motivation is to > be able to enable non-stop without forcing displaced-stepping > for all single-steps (even those that don't step over a bkpt). Ugh! Much trickier than I thought! :-( So, to summarize, I'll start by working on a new patch, which I'll send here. I'll also try to put the new testcase on the list, but today is a little bit of a full day for me, so that part might have to wait until Monday depending on how well my day goes. Thanks, Pedro! -- Joel ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 13:27 ` Joel Brobecker @ 2014-05-30 15:57 ` Pedro Alves 2014-05-30 16:19 ` Joel Brobecker ` (2 more replies) 2014-05-30 19:35 ` Joel Brobecker 1 sibling, 3 replies; 29+ messages in thread From: Pedro Alves @ 2014-05-30 15:57 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 05/30/2014 02:26 PM, Joel Brobecker wrote: >>>> - if there's still a non-sss breakpoint inserted at the >>>> same address, then don't actually remove the breakpoint >>>> off of the target, just wipe it from gdb's list. >>> >>> It seems to me that we'd need to merge your initial recommendation >>> into your summary above, right? >> >> I admit I don't know what recommendation you're referring to. :-) > > Sorry! This one: > > | but we'll need to create/clone the location and its shadow buffer, > | and then still handle the issue in the "remove" path. Ah. Yes. > I am wondering how to create that test, because it would be > a little tricky. We need to set ourselves into a situation > where we single-step out of a breakpoint with the second SSS > breakpoint being at the same address as one of the user breakpoints, > that second SSS not being the one that gets hit during that > first single-step-out-of-breakpoint. Yeah. Hmmm. *thinks* I have a very simple idea, around "jump" + "always-inserted". E.g., with, where b+ indicates a user breakpoint: 00001 nop <- PC b+ 00002 nop - enable breakpoints always inserted mode - step to 00002 - gdb removes the sss breakpoint. - due to always inserted mode, gdb does not remove b+, but due to the bug, it's actually no longer planted. - the b+ breakpoint should be reported to the user. - now do "jump $pc". - expected: The breakpoint should trigger immediately again. - what we get on sss targets: GDB loses control, and program runs to end. Ah, I just went ahead and tried that against my by sss-on-x86 branch, and indeed it fails here, while it passes on pristine mainline / hardware stepping. 8<---------- From e13bf4d64bf299111193a1f27a0bbc194d9b34f4 Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Fri, 30 May 2014 16:52:36 +0100 Subject: [PATCH] test for sss breakpoints bug --- gdb/testsuite/gdb.base/sss-bp-on-user-bp.c | 30 ++++++++++++++++ gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp | 51 ++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 gdb/testsuite/gdb.base/sss-bp-on-user-bp.c create mode 100644 gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c new file mode 100644 index 0000000..ff82051 --- /dev/null +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <signal.h> +#include <unistd.h> + +int +main (void) +{ + /* Assume writes to integers compile to a single instruction. */ + volatile int i = 0; + + i = 1; /* set foo break here */ + i = 2; /* set bar break here */ + return 0; +} diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp new file mode 100644 index 0000000..bb63d3f --- /dev/null +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp @@ -0,0 +1,51 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that removing a single-step breakpoint that is placed at the +# same address as another regular breakpoint leaves the regular +# breakpoint inserted. + +standard_testfile +set executable ${testfile} + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +gdb_breakpoint [gdb_get_line_number "set foo break here"] +gdb_continue_to_breakpoint "first breakpoint" ".* set foo break here .*" + +gdb_breakpoint [gdb_get_line_number "set bar break here"] + +# So that GDB doesn't try to remove the regular breakpoint when the +# step finishes. +gdb_test_no_output "set breakpoint always-inserted on" + +# On software single-step targets, this step will want to momentarily +# place a single-step breakpoint over the bar breakpoint, and then +# remove it. But, a regular breakpoint it planted there already, and +# with always-inserted on, should remain planted when the step +# finishes. +gdb_test "si" "Breakpoint .* bar break .*" + +# If the breakpoint is still correctly inserted, then this jump should +# re-trigger it. Otherwise, GDB will lose control and the program +# will exit. +gdb_test "jump *\$pc" "Breakpoint .* bar break .*" -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 15:57 ` Pedro Alves @ 2014-05-30 16:19 ` Joel Brobecker 2014-05-30 16:23 ` Pedro Alves 2014-05-30 16:23 ` Pedro Alves 2014-06-03 11:55 ` Yao Qi 2 siblings, 1 reply; 29+ messages in thread From: Joel Brobecker @ 2014-05-30 16:19 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > I have a very simple idea, around "jump" + "always-inserted". > > E.g., with, where b+ indicates a user breakpoint: > > 00001 nop <- PC > b+ 00002 nop > > - enable breakpoints always inserted mode > - step to 00002 > - gdb removes the sss breakpoint. > - due to always inserted mode, gdb does not remove b+, but > due to the bug, it's actually no longer planted. > - the b+ breakpoint should be reported to the user. > - now do "jump $pc". > - expected: > The breakpoint should trigger immediately again. > - what we get on sss targets: > GDB loses control, and program runs to end. > > Ah, I just went ahead and tried that against my by sss-on-x86 > branch, and indeed it fails here, while it passes on > pristine mainline / hardware stepping. That is very clever! WDYT about pushing this new testcase now? -- Joel ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 16:19 ` Joel Brobecker @ 2014-05-30 16:23 ` Pedro Alves 0 siblings, 0 replies; 29+ messages in thread From: Pedro Alves @ 2014-05-30 16:23 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 05/30/2014 05:19 PM, Joel Brobecker wrote: > That is very clever! WDYT about pushing this new testcase now? Done. :-) -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 15:57 ` Pedro Alves 2014-05-30 16:19 ` Joel Brobecker @ 2014-05-30 16:23 ` Pedro Alves 2014-06-03 11:55 ` Yao Qi 2 siblings, 0 replies; 29+ messages in thread From: Pedro Alves @ 2014-05-30 16:23 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 05/30/2014 04:57 PM, Pedro Alves wrote: > Ah, I just went ahead and tried that against my by sss-on-x86 > branch, and indeed it fails here, while it passes on > pristine mainline / hardware stepping. I now filed bug 17000 for this , and went ahead and pushed the test in, kfailed. 8<-------------- Subject: [PATCH] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - test GDB gets confused when removing a software single-step breakpoint that is at the same address as another breakpoint. Add a kfailed test. gdb/testsuite/ 2014-05-30 Pedro Alves <palves@redhat.com> PR breakpoints/17000 * gdb.base/sss-bp-on-user-bp.c: New file. * gdb.base/sss-bp-on-user-bp.exp: New file. --- gdb/testsuite/ChangeLog | 6 ++++ gdb/testsuite/gdb.base/sss-bp-on-user-bp.c | 30 ++++++++++++++++ gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp | 52 ++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 gdb/testsuite/gdb.base/sss-bp-on-user-bp.c create mode 100644 gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index b09e86e..334fd83 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-05-30 Pedro Alves <palves@redhat.com> + + PR breakpoints/17000 + * gdb.base/sss-bp-on-user-bp.c: New file. + * gdb.base/sss-bp-on-user-bp.exp: New file. + 2014-05-30 David Blaikie <dblaikie@gmail.com> * gdb.opt/inline-break.c: Fix clang compatibility by specifying diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c new file mode 100644 index 0000000..ff82051 --- /dev/null +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <signal.h> +#include <unistd.h> + +int +main (void) +{ + /* Assume writes to integers compile to a single instruction. */ + volatile int i = 0; + + i = 1; /* set foo break here */ + i = 2; /* set bar break here */ + return 0; +} diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp new file mode 100644 index 0000000..62415e7 --- /dev/null +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp @@ -0,0 +1,52 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that removing a single-step breakpoint that is placed at the +# same address as another regular breakpoint leaves the regular +# breakpoint inserted. + +standard_testfile +set executable ${testfile} + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +gdb_breakpoint [gdb_get_line_number "set foo break here"] +gdb_continue_to_breakpoint "first breakpoint" ".* set foo break here .*" + +gdb_breakpoint [gdb_get_line_number "set bar break here"] + +# So that GDB doesn't try to remove the regular breakpoint when the +# step finishes. +gdb_test_no_output "set breakpoint always-inserted on" + +# On software single-step targets, this step will want to momentarily +# place a single-step breakpoint over the bar breakpoint, and then +# remove it. But, a regular breakpoint is planted there already, and +# with always-inserted on, should remain planted when the step +# finishes. +gdb_test "si" "Breakpoint .* bar break .*" + +# If the breakpoint is still correctly inserted, then this jump should +# re-trigger it. Otherwise, GDB will lose control and the program +# will exit. +setup_kfail "breakpoints/17000" "*-*-*" +gdb_test "jump *\$pc" "Breakpoint .* bar break .*" -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 15:57 ` Pedro Alves 2014-05-30 16:19 ` Joel Brobecker 2014-05-30 16:23 ` Pedro Alves @ 2014-06-03 11:55 ` Yao Qi 2014-06-03 12:00 ` Pedro Alves 2 siblings, 1 reply; 29+ messages in thread From: Yao Qi @ 2014-06-03 11:55 UTC (permalink / raw) To: Pedro Alves, Joel Brobecker; +Cc: gdb-patches On 05/30/2014 11:57 PM, Pedro Alves wrote: > +int > +main (void) > +{ > + /* Assume writes to integers compile to a single instruction. */ This assumption is wrong on arm at least. > + volatile int i = 0; > + > + i = 1; /* set foo break here */ > + i = 2; /* set bar break here */ > + return 0; > +} Each line is compiled to two instructions. 27 i = 1; /* set foo break here */ 0x0000025c <+20>: mov r3, #1 0x00000260 <+24>: str r3, [r11, #-8] 28 i = 2; /* set bar break here */ 0x00000264 <+28>: mov r3, #2 0x00000268 <+32>: str r3, [r11, #-8] > +# On software single-step targets, this step will want to momentarily > +# place a single-step breakpoint over the bar breakpoint, and then > +# remove it. But, a regular breakpoint it planted there already, and > +# with always-inserted on, should remain planted when the step > +# finishes. > +gdb_test "si" "Breakpoint .* bar break .*" this test will fail, because it still stops at "foo break". -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 11:55 ` Yao Qi @ 2014-06-03 12:00 ` Pedro Alves 2014-06-03 12:12 ` Andreas Schwab 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 12:00 UTC (permalink / raw) To: Yao Qi, Joel Brobecker; +Cc: gdb-patches On 06/03/2014 12:53 PM, Yao Qi wrote: > On 05/30/2014 11:57 PM, Pedro Alves wrote: >> +int >> +main (void) >> +{ >> + /* Assume writes to integers compile to a single instruction. */ > > This assumption is wrong on arm at least. Ah, thanks. We need to replace then with asm("nop") then. -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 12:00 ` Pedro Alves @ 2014-06-03 12:12 ` Andreas Schwab 2014-06-03 12:19 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Andreas Schwab @ 2014-06-03 12:12 UTC (permalink / raw) To: Pedro Alves; +Cc: Yao Qi, Joel Brobecker, gdb-patches Pedro Alves <palves@redhat.com> writes: > Ah, thanks. We need to replace then with asm("nop") then. nop isn't portable. Andreas. -- Andreas Schwab, SUSE Labs, schwab@suse.de GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7 "And now for something completely different." ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 12:12 ` Andreas Schwab @ 2014-06-03 12:19 ` Pedro Alves 2014-06-04 5:14 ` Yao Qi 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 12:19 UTC (permalink / raw) To: Andreas Schwab; +Cc: Yao Qi, Joel Brobecker, gdb-patches On 06/03/2014 01:12 PM, Andreas Schwab wrote: > Pedro Alves <palves@redhat.com> writes: > >> Ah, thanks. We need to replace then with asm("nop") then. > > nop isn't portable. Yes, but it doesn't matter what the instruction is as long as it's a single instruction that doesn't do much. For archs that don't have "nop" (like e.g., IA64), we can just use #ifdef to pick another insn. -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 12:19 ` Pedro Alves @ 2014-06-04 5:14 ` Yao Qi 2014-06-04 8:01 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Yao Qi @ 2014-06-04 5:14 UTC (permalink / raw) To: Pedro Alves, Andreas Schwab; +Cc: Joel Brobecker, gdb-patches On 06/03/2014 08:19 PM, Pedro Alves wrote: > On 06/03/2014 01:12 PM, Andreas Schwab wrote: >> Pedro Alves <palves@redhat.com> writes: >> >>> Ah, thanks. We need to replace then with asm("nop") then. >> >> nop isn't portable. > > Yes, but it doesn't matter what the instruction is as > long as it's a single instruction that doesn't do much. > For archs that don't have "nop" (like e.g., IA64), we can > just use #ifdef to pick another insn. > Pedro, here is the patch to tweak sss-bp-on-user-bp.exp. I give up on looking for a portable "nop" for various arch. In stead, we can use disassemble to get the next instruction address and set breakpoint there. See details in the commit log below. -- Yao (é½å°§) Subject: [PATCH] Tweak sss-bp-on-user-bp.exp sss-bp-on-user-bp.c has an assumption that write to integer can be compiled to a single instruction, which isn't true on some arch, such as arm. This test requires setting two breakpoints on two consecutive instructions, so this patch is to get the address of the next instruction via disassemble and set the 2nd breakpoint there. This approach is portable. This patch fixes the fails in sss-bp-on-user-bp.exp on arm-none-abi target. There is no change in x86 test results. I also revert the patch to PR breakpoints/17000, and verified that the patched sss-bp-on-user-bp.exp still triggers the fail on x86-with-software-single-step. gdb/testsuite: 2014-06-04 Yao Qi <yao@codesourcery.com> * gdb.base/sss-bp-on-user-bp.c (main): Remove comments. * gdb.base/sss-bp-on-user-bp.exp: Don't set breakpoint on "set bar break here". Get the next instruction address and set breakpoint there. Remove "bar break" from the regexp patterns. --- gdb/testsuite/gdb.base/sss-bp-on-user-bp.c | 4 ++-- gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c index ff82051..edc2e8c 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.c @@ -21,10 +21,10 @@ int main (void) { - /* Assume writes to integers compile to a single instruction. */ volatile int i = 0; i = 1; /* set foo break here */ - i = 2; /* set bar break here */ + i = 2; + return 0; } diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp index 2a12ad6..0b39fc1 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp @@ -32,7 +32,21 @@ if ![runto_main] then { gdb_breakpoint [gdb_get_line_number "set foo break here"] gdb_continue_to_breakpoint "first breakpoint" ".* set foo break here .*" -gdb_breakpoint [gdb_get_line_number "set bar break here"] +# Get the address of the next instruction and set a breakpoint there. +set next_insn_addr "" +set test "disassemble main" +gdb_test_multiple $test $test { + -re ".*=> $hex <\\+$decimal>:\[^\r\n\]+\r\n ($hex) .*$gdb_prompt $" { + set next_insn_addr $expect_out(1,string) + pass $test + } +} + +if { $next_insn_addr == "" } { + return -1 +} + +gdb_test "b *$next_insn_addr" "Breakpoint .*" # So that GDB doesn't try to remove the regular breakpoint when the # step finishes. @@ -43,9 +57,9 @@ gdb_test_no_output "set breakpoint always-inserted on" # remove it. But, a regular breakpoint is planted there already, and # with always-inserted on, should remain planted when the step # finishes. -gdb_test "si" "Breakpoint .* bar break .*" +gdb_test "si" "Breakpoint .*" # If the breakpoint is still correctly inserted, then this jump should # re-trigger it. Otherwise, GDB will lose control and the program # will exit. See PR breakpoints/17000. -gdb_test "jump *\$pc" "Breakpoint .* bar break .*" +gdb_test "jump *\$pc" "Breakpoint .*" -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-04 5:14 ` Yao Qi @ 2014-06-04 8:01 ` Pedro Alves 2014-06-04 12:58 ` Yao Qi 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-04 8:01 UTC (permalink / raw) To: Yao Qi, Andreas Schwab; +Cc: Joel Brobecker, gdb-patches On 06/04/2014 06:12 AM, Yao Qi wrote: > On 06/03/2014 08:19 PM, Pedro Alves wrote: >> On 06/03/2014 01:12 PM, Andreas Schwab wrote: >>> Pedro Alves <palves@redhat.com> writes: >>> >>>> Ah, thanks. We need to replace then with asm("nop") then. >>> >>> nop isn't portable. >> >> Yes, but it doesn't matter what the instruction is as >> long as it's a single instruction that doesn't do much. >> For archs that don't have "nop" (like e.g., IA64), we can >> just use #ifdef to pick another insn. >> > > Pedro, here is the patch to tweak sss-bp-on-user-bp.exp. > I give up on looking for a portable "nop" for various arch. In > stead, we can use disassemble to get the next instruction address > and set breakpoint there. See details in the commit log below. Good idea. Patch is OK. Thanks! -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-04 8:01 ` Pedro Alves @ 2014-06-04 12:58 ` Yao Qi 0 siblings, 0 replies; 29+ messages in thread From: Yao Qi @ 2014-06-04 12:58 UTC (permalink / raw) To: Pedro Alves, Andreas Schwab; +Cc: Joel Brobecker, gdb-patches On 06/04/2014 04:01 PM, Pedro Alves wrote: > Good idea. Patch is OK. Patch is pushed in, thanks for the review. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 13:27 ` Joel Brobecker 2014-05-30 15:57 ` Pedro Alves @ 2014-05-30 19:35 ` Joel Brobecker 2014-06-02 23:16 ` Pedro Alves 1 sibling, 1 reply; 29+ messages in thread From: Joel Brobecker @ 2014-05-30 19:35 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1573 bytes --] Hi Pedro, > > For 7.8, I'm thinking it's really safer to avoid resending > > duplicate Z0 packets to stubs that don't support conditional > > breakpoint evaluation on the target end. So I think we should > > handle the "insert" path too. > > OK - I will take care of that. New patch attached... gdb/ChangeLog: PR breakpoints/17000 * breakpoint.c (non_sss_software_breakpoint_inserted_here_p): New function, extracted from software_breakpoint_inserted_here_p. (software_breakpoint_inserted_here_p): Remove factored out code by call to non_sss_software_breakpoint_inserted_here_p. (insert_single_step_breakpoint): Do nothing if the target does not support target-side breakpoint condition evaluation, a a non-software- single-step breakpoint was already inserted at the same address. (remove_single_step_breakpoints): Adjust to take into account the fact that the first software single-step may not have been inserted. Do not remove the raw breakpoint is a user software breakpoint is still inserted at the same location. Tested on ppc-aix with AdaCore's testsuite. Tested on x86_64-linux with the official testsuite. Also tested on x86_64-linux through Pedro's branch enabling software single-stepping on that platform. Does it look better to you? One thing that we might have to consider is the fact that z0 and Z0 packets are no longer balanced; not sure if it would matter to any stubb in practice. I think we're into grey waters anyway... Thanks! -- Joel [-- Attachment #2: 0001-User-breakpoint-ignored-if-software-single-step-at-s.patch --] [-- Type: text/x-diff, Size: 9229 bytes --] From 0fdd06aff3439fb5769f485f465f15cc2c6f7841 Mon Sep 17 00:00:00 2001 From: Joel Brobecker <brobecker@adacore.com> Date: Fri, 30 May 2014 11:27:19 -0700 Subject: [PATCH] User breakpoint ignored if software-single-step at same location with the following code... 12 Nested; -- break #1 13 return I; -- break #2 14 end; (line 12 is a call to function Nested) ... we have noticed the following errorneous behavior on ppc-aix, where, after having inserted a breakpoint at line 12 and line 13, and continuing from the breakpoint at line 12, the program never stops at line 13, running away until the program terminates: % gdb -q func (gdb) b func.adb:12 Breakpoint 1 at 0x10000a24: file func.adb, line 12. (gdb) b func.adb:13 Breakpoint 2 at 0x10000a28: file func.adb, line 13. (gdb) run Starting program: /[...]/func Breakpoint 1, func () at func.adb:12 12 Nested; -- break #1 (gdb) c Continuing. [Inferior 1 (process 4128872) exited with code 02] When resuming from the first breakpoint, GDB first tries to step out of that first breakpoint. We rely on software single-stepping on this platform, and it just so happens that the address of the first software single-step breakpoint is the same as the user's breakpoint #2 (0x10000a28). So, with infrun and target traces turned on (but uninteresting traces snip'ed off), the "continue" operation looks like this: (gdb) c ### First, we insert the user breakpoints (the second one is an internal ### breakpoint on __pthread_init). The first user breakpoint is not ### inserted as we need to step out of it first. target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000d03f3800, xxx) = 0 ### Then we proceed with the step-out-of-breakpoint... infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [process 15335610] at 0x10000a24 ### That's when we insert the SSS breakpoints... target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000100009ac, xxx) = 0 ### ... then let the inferior resume... target_resume (15335610, continue, 0) infrun: wait_for_inferior () target_wait (-1, status, options={}) = 15335610, status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: target_wait (-1, status) = infrun: 15335610 [process 15335610], infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x100009ac ### At this point, we stopped at the second SSS breakpoint... target_stopped_by_watchpoint () = 0 ### We remove the SSS breakpoints... target_remove_breakpoint (0x0000000010000a28, xxx) = 0 target_remove_breakpoint (0x00000000100009ac, xxx) = 0 target_stopped_by_watchpoint () = 0 ### We find that we're not done, so we resume.... infrun: no stepping, continue ### And thus insert the user breakpoints again, except we're not ### inserting the second breakpoint?!? target_insert_breakpoint (0x0000000010000a24, xxx) = 0 infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [process 15335610] at 0x100009ac target_resume (-1, continue, 0) infrun: prepare_to_wait target_wait (-1, status, options={}) = 15335610, status->kind = exited, status = 2 What happens is that the removal of the software single-step breakpoints effectively removed the breakpoint instruction from inferior memory. But because such breakpoints are inserted directly as raw breakpoints rather than through the normal chain of breakpoints, we fail to notice that one of the user breakpoints points to the same address and that this user breakpoint is therefore effectively un-inserted. When resuming after the single-step, GDB thinks that the user breakpoint is still inserted and therefore does not need to insert it again. This patch fixes the problem by skipping the removal of the software single-step raw breakpoints if at least one non-software-single-step breakpoint is still inserted at that location. Additionally, this patch also avoids inserting the single-step breakpoint when possible, mostly to avoid issues with targets not supporting multiple breakpoints at same address. For instance, some remote stubs might not support multiple Z0 packets at the same address. gdb/ChangeLog: PR breakpoints/17000 * breakpoint.c (non_sss_software_breakpoint_inserted_here_p): New function, extracted from software_breakpoint_inserted_here_p. (software_breakpoint_inserted_here_p): Remove factored out code by call to non_sss_software_breakpoint_inserted_here_p. (insert_single_step_breakpoint): Do nothing if the target does not support target-side breakpoint condition evaluation, a a non-software- single-step breakpoint was already inserted at the same address. (remove_single_step_breakpoints): Adjust to take into account the fact that the first software single-step may not have been inserted. Do not remove the raw breakpoint is a user software breakpoint is still inserted at the same location. Tested on ppc-aix with AdaCore's testsuite. Tested on x86_64-linux with the official testsuite. Also tested on x86_64-linux through Pedro's branch enabling software single-stepping on that platform. --- gdb/breakpoint.c | 73 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 676c7b8..bddbca0 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -4153,12 +4153,12 @@ breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc) return 0; } -/* This function returns non-zero iff there is a software breakpoint - inserted at PC. */ +/* Ignoring software single-step breakpoints, return non-zero iff + there is a software breakpoint inserted at PC. */ -int -software_breakpoint_inserted_here_p (struct address_space *aspace, - CORE_ADDR pc) +static int +non_sss_software_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) { struct bp_location *bl, **blp_tmp; @@ -4180,6 +4180,19 @@ software_breakpoint_inserted_here_p (struct address_space *aspace, } } + return 0; +} + +/* This function returns non-zero iff there is a software breakpoint + inserted at PC. */ + +int +software_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) +{ + if (non_sss_software_breakpoint_inserted_here_p (aspace, pc)) + return 1; + /* Also check for software single-step breakpoints. */ if (single_step_breakpoint_inserted_here_p (aspace, pc)) return 1; @@ -15149,6 +15162,20 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch, { void **bpt_p; + /* Unless the target supports target-side evaluation of breakpoint + conditions, there is no need to insert an additional raw breakpoint + if a non-software-single-step breakpoint is already inserted + at that location. + + For targets supporting target-side evaluation of breakpoint + conditions, the issue is that those breakpoints cannot be + relied on to trigger during our software-single-step operation. + So we have to insert our own to make sure. */ + + if (!target_supports_evaluation_of_breakpoint_conditions () + && non_sss_software_breakpoint_inserted_here_p (aspace, next_pc)) + return; + if (single_step_breakpoints[0] == NULL) { bpt_p = &single_step_breakpoints[0]; @@ -15189,22 +15216,28 @@ single_step_breakpoints_inserted (void) void remove_single_step_breakpoints (void) { - gdb_assert (single_step_breakpoints[0] != NULL); - - /* See insert_single_step_breakpoint for more about this deprecated - call. */ - deprecated_remove_raw_breakpoint (single_step_gdbarch[0], - single_step_breakpoints[0]); - single_step_gdbarch[0] = NULL; - single_step_breakpoints[0] = NULL; + int i; - if (single_step_breakpoints[1] != NULL) - { - deprecated_remove_raw_breakpoint (single_step_gdbarch[1], - single_step_breakpoints[1]); - single_step_gdbarch[1] = NULL; - single_step_breakpoints[1] = NULL; - } + for (i = 0; i < 2; i++) + if (single_step_breakpoints[i] != NULL) + { + struct bp_target_info *bp_tgt = single_step_breakpoints[i]; + CORE_ADDR pc = bp_tgt->placed_address; + struct address_space *aspace = bp_tgt->placed_address_space; + + /* Only remove the raw breakpoint if there are no other + non-software-single-step breakpoints still inserted + at this location. Otherwise, we would be effectively + disabling those breakpoints. */ + if (!non_sss_software_breakpoint_inserted_here_p (aspace, pc)) + { + /* See insert_single_step_breakpoint for more about + this deprecated call. */ + deprecated_remove_raw_breakpoint (single_step_gdbarch[i], bp_tgt); + } + single_step_gdbarch[i] = NULL; + single_step_breakpoints[i] = NULL; + } } /* Delete software single step breakpoints without removing them from -- 1.9.1 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-05-30 19:35 ` Joel Brobecker @ 2014-06-02 23:16 ` Pedro Alves 2014-06-03 8:22 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-02 23:16 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 05/30/2014 08:35 PM, Joel Brobecker wrote: > Hi Pedro, > >>> For 7.8, I'm thinking it's really safer to avoid resending >>> duplicate Z0 packets to stubs that don't support conditional >>> breakpoint evaluation on the target end. So I think we should >>> handle the "insert" path too. >> >> OK - I will take care of that. > > New patch attached... > > gdb/ChangeLog: > > PR breakpoints/17000 > * breakpoint.c (non_sss_software_breakpoint_inserted_here_p): > New function, extracted from software_breakpoint_inserted_here_p. > (software_breakpoint_inserted_here_p): Remove factored out code > by call to non_sss_software_breakpoint_inserted_here_p. > (insert_single_step_breakpoint): Do nothing if the target > does not support target-side breakpoint condition evaluation, > a a non-software- single-step breakpoint was already inserted > at the same address. > (remove_single_step_breakpoints): Adjust to take into account > the fact that the first software single-step may not have been > inserted. Do not remove the raw breakpoint is a user software > breakpoint is still inserted at the same location. > > Tested on ppc-aix with AdaCore's testsuite. Tested on x86_64-linux > with the official testsuite. Also tested on x86_64-linux through > Pedro's branch enabling software single-stepping on that platform. > > Does it look better to you? Hmm, this doesn't handle the background execution cases we discussed earlier. That is, with: > @@ -15149,6 +15162,20 @@ insert_single_step_breakpoint (struct gdbarch *gdbarch, > { > void **bpt_p; > > + /* Unless the target supports target-side evaluation of breakpoint > + conditions, there is no need to insert an additional raw breakpoint > + if a non-software-single-step breakpoint is already inserted > + at that location. > + > + For targets supporting target-side evaluation of breakpoint > + conditions, the issue is that those breakpoints cannot be > + relied on to trigger during our software-single-step operation. > + So we have to insert our own to make sure. */ > + > + if (!target_supports_evaluation_of_breakpoint_conditions () > + && non_sss_software_breakpoint_inserted_here_p (aspace, next_pc)) > + return; ... when we hit this early return, the "b *0xaddr_where_sss_will_be_placed; s&; del" case may well result in removing the sss breakpoint from the target before the "step" actually finishes. So I think we should still create a bp_target_info for the single-step breakpoint, even though we don't actually insert it. I think it'd then be better if we do this in deprecated_insert_raw_breakpoint/deprecated_remove_raw_breakpoint instead, and to handle the mirror scenario you identified ("when the user deletes his breakpoints, since the breakpoint chain doesn't know about the SSS breakpoint, wouldn't it remove our SSS breakpoint insn?") in bkpt_insert_location/bkpt_remove_location. Note that with that early return as it is in the patch, single_step_breakpoints_inserted returns the wrong thing: int single_step_breakpoints_inserted (void) { return (single_step_breakpoints[0] != NULL || single_step_breakpoints[1] != NULL); } E.g., assume we only have inserted one sss breakpoint, and it happened to be on top of another breakpoint. Then single_step_breakpoints_inserted returns false, which confuses the callers. > One thing that we might have to consider > is the fact that z0 and Z0 packets are no longer balanced; not sure > if it would matter to any stubb in practice. I think we're into > grey waters anyway... About unbalanced: you're seeing that against gdbserver, right? If so, that's OK. However, we shouldn't see unbalanced Z0/z0 with "set remote conditional-breakpoints-packet off". If we do, that'd better be addressed. See also <https://sourceware.org/ml/gdb-patches/2014-04/msg00480.html>. > @@ -15189,22 +15216,28 @@ single_step_breakpoints_inserted (void) > void > remove_single_step_breakpoints (void) > { > - gdb_assert (single_step_breakpoints[0] != NULL); I think it's best if this assertion is preserved. > - > - /* See insert_single_step_breakpoint for more about this deprecated > - call. */ > - deprecated_remove_raw_breakpoint (single_step_gdbarch[0], > - single_step_breakpoints[0]); > - single_step_gdbarch[0] = NULL; > - single_step_breakpoints[0] = NULL; > + int i; > > - if (single_step_breakpoints[1] != NULL) > - { > - deprecated_remove_raw_breakpoint (single_step_gdbarch[1], > - single_step_breakpoints[1]); > - single_step_gdbarch[1] = NULL; > - single_step_breakpoints[1] = NULL; > - } > + for (i = 0; i < 2; i++) > + if (single_step_breakpoints[i] != NULL) > + { > + struct bp_target_info *bp_tgt = single_step_breakpoints[i]; > + CORE_ADDR pc = bp_tgt->placed_address; > + struct address_space *aspace = bp_tgt->placed_address_space; > + > + /* Only remove the raw breakpoint if there are no other > + non-software-single-step breakpoints still inserted > + at this location. Otherwise, we would be effectively > + disabling those breakpoints. */ > + if (!non_sss_software_breakpoint_inserted_here_p (aspace, pc)) > + { > + /* See insert_single_step_breakpoint for more about > + this deprecated call. */ > + deprecated_remove_raw_breakpoint (single_step_gdbarch[i], bp_tgt); > + } there should be an "else xfree" here, otherwise it's a leak. But, the patch below ends up not touching this function though. Let me know what you think, and feel free to push if it looks OK. Tested on all combinations of native|gdbserver X hardware-|software- stepping. At least, I think I did. If not this exact version, some other minor variation. :-) 8<-------- Subject: [PATCH] User breakpoint ignored if software-single-step at same location with the following code... 12 Nested; -- break #1 13 return I; -- break #2 14 end; (line 12 is a call to function Nested) ... we have noticed the following errorneous behavior on ppc-aix, where, after having inserted a breakpoint at line 12 and line 13, and continuing from the breakpoint at line 12, the program never stops at line 13, running away until the program terminates: % gdb -q func (gdb) b func.adb:12 Breakpoint 1 at 0x10000a24: file func.adb, line 12. (gdb) b func.adb:13 Breakpoint 2 at 0x10000a28: file func.adb, line 13. (gdb) run Starting program: /[...]/func Breakpoint 1, func () at func.adb:12 12 Nested; -- break #1 (gdb) c Continuing. [Inferior 1 (process 4128872) exited with code 02] When resuming from the first breakpoint, GDB first tries to step out of that first breakpoint. We rely on software single-stepping on this platform, and it just so happens that the address of the first software single-step breakpoint is the same as the user's breakpoint #2 (0x10000a28). So, with infrun and target traces turned on (but uninteresting traces snip'ed off), the "continue" operation looks like this: (gdb) c ### First, we insert the user breakpoints (the second one is an internal ### breakpoint on __pthread_init). The first user breakpoint is not ### inserted as we need to step out of it first. target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000d03f3800, xxx) = 0 ### Then we proceed with the step-out-of-breakpoint... infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [process 15335610] at 0x10000a24 ### That's when we insert the SSS breakpoints... target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000100009ac, xxx) = 0 ### ... then let the inferior resume... target_resume (15335610, continue, 0) infrun: wait_for_inferior () target_wait (-1, status, options={}) = 15335610, status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: target_wait (-1, status) = infrun: 15335610 [process 15335610], infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x100009ac ### At this point, we stopped at the second SSS breakpoint... target_stopped_by_watchpoint () = 0 ### We remove the SSS breakpoints... target_remove_breakpoint (0x0000000010000a28, xxx) = 0 target_remove_breakpoint (0x00000000100009ac, xxx) = 0 target_stopped_by_watchpoint () = 0 ### We find that we're not done, so we resume.... infrun: no stepping, continue ### And thus insert the user breakpoints again, except we're not ### inserting the second breakpoint?!? target_insert_breakpoint (0x0000000010000a24, xxx) = 0 infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [process 15335610] at 0x100009ac target_resume (-1, continue, 0) infrun: prepare_to_wait target_wait (-1, status, options={}) = 15335610, status->kind = exited, status = 2 What happens is that the removal of the software single-step breakpoints effectively removed the breakpoint instruction from inferior memory. But because such breakpoints are inserted directly as raw breakpoints rather than through the normal chain of breakpoints, we fail to notice that one of the user breakpoints points to the same address and that this user breakpoint is therefore effectively un-inserted. When resuming after the single-step, GDB thinks that the user breakpoint is still inserted and therefore does not need to insert it again. This patch teaches the insert and remove routines of both regular and raw breakpoints to be aware of each other. Special care needs to be applied in case the target supports evaluation of breakpoint conditions or commands. gdb/ChangeLog: PR breakpoints/17000 * breakpoint.c (find_non_raw_software_breakpoint_inserted_here): New function, extracted from software_breakpoint_inserted_here_p. (software_breakpoint_inserted_here_p): Replace factored out code by call to find_non_raw_software_breakpoint_inserted_here. (bkpt_insert_location): Handle the case of a single-step breakpoint already inserted at the same address. (bkpt_remove_location): Handle the case of a single-step breakpoint still inserted at the same address. (deprecated_insert_raw_breakpoint): Handle the case of non-raw breakpoint already inserted at the same address. (deprecated_remove_raw_breakpoint): Handle the case of a non-raw breakpoint still inserted at the same address. (single_step_breakpoint_inserted_here_p): (find_single_step_breakpoint_inserted_here): New function, fatored out from single_step_breakpoint_inserted_here_p. (single_step_breakpoint_inserted_here_p): Reimplement. gdb/testsuite/ChangeLog: PR breakpoints/17000 * gdb.base/sss-bp-on-user-bp.exp: Remove kfail. Tested on ppc-aix with AdaCore's testsuite. Tested on x86_64-linux, (native and gdbserver) with the official testsuite. Also tested on x86_64-linux through Pedro's branch enabling software single-stepping on that platform (native and gdbserver). --- gdb/breakpoint.c | 91 +++++++++++++++++++++++++--- gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp | 3 +- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 4e6c627..0043b06 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -4165,12 +4165,12 @@ breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc) return 0; } -/* This function returns non-zero iff there is a software breakpoint - inserted at PC. */ +/* Ignoring deprecated raw breakpoints, return non-zero iff there is a + software breakpoint inserted at PC. */ -int -software_breakpoint_inserted_here_p (struct address_space *aspace, - CORE_ADDR pc) +static struct bp_location * +find_non_raw_software_breakpoint_inserted_here (struct address_space *aspace, + CORE_ADDR pc) { struct bp_location *bl, **blp_tmp; @@ -4188,10 +4188,23 @@ software_breakpoint_inserted_here_p (struct address_space *aspace, && !section_is_mapped (bl->section)) continue; /* unmapped overlay -- can't be a match */ else - return 1; + return bl; } } + return NULL; +} + +/* This function returns non-zero iff there is a software breakpoint + inserted at PC. */ + +int +software_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) +{ + if (find_non_raw_software_breakpoint_inserted_here (aspace, pc) != NULL) + return 1; + /* Also check for software single-step breakpoints. */ if (single_step_breakpoint_inserted_here_p (aspace, pc)) return 1; @@ -13119,8 +13132,18 @@ bkpt_insert_location (struct bp_location *bl) return target_insert_hw_breakpoint (bl->gdbarch, &bl->target_info); else - return target_insert_breakpoint (bl->gdbarch, - &bl->target_info); + { + struct bp_target_info *bp_tgt = &bl->target_info; + int ret; + + /* There is no need to insert a breakpoint if an unconditional + raw/sss breakpoint is already inserted at that location. */ + if (single_step_breakpoint_inserted_here_p (bp_tgt->placed_address_space, + bp_tgt->placed_address)) + return 0; + + return target_insert_breakpoint (bl->gdbarch, bp_tgt); + } } static int @@ -13129,7 +13152,19 @@ bkpt_remove_location (struct bp_location *bl) if (bl->loc_type == bp_loc_hardware_breakpoint) return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info); else - return target_remove_breakpoint (bl->gdbarch, &bl->target_info); + { + struct bp_target_info *bp_tgt = &bl->target_info; + struct address_space *aspace = bp_tgt->placed_address_space; + CORE_ADDR address = bp_tgt->placed_address; + + /* Only remove the breakpoint if there is no raw/sss breakpoint + still inserted at this location. Otherwise, we would be + effectively disabling the raw/sss breakpoint. */ + if (single_step_breakpoint_inserted_here_p (aspace, address)) + return 0; + + return target_remove_breakpoint (bl->gdbarch, bp_tgt); + } } static int @@ -15138,12 +15173,27 @@ deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch, struct address_space *aspace, CORE_ADDR pc) { struct bp_target_info *bp_tgt; + struct bp_location *bl; bp_tgt = XCNEW (struct bp_target_info); bp_tgt->placed_address_space = aspace; bp_tgt->placed_address = pc; + /* If an unconditional non-raw breakpoint is already inserted at + that location, there's no need to insert another. However, with + target-side evaluation of breakpoint conditions, if the + breakpoint that is currently inserted on the target is + conditional, we need to make it unconditional. Note that a + breakpoint with target-side commands is not reported even if + unconditional, so we need to remove the commands from the target + as well. */ + bl = find_non_raw_software_breakpoint_inserted_here (aspace, pc); + if (bl != NULL + && VEC_empty (agent_expr_p, bl->target_info.conditions) + && VEC_empty (agent_expr_p, bl->target_info.tcommands)) + return bp_tgt; + if (target_insert_breakpoint (gdbarch, bp_tgt) != 0) { /* Could not insert the breakpoint. */ @@ -15161,9 +15211,30 @@ int deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp) { struct bp_target_info *bp_tgt = bp; + struct address_space *aspace = bp_tgt->placed_address_space; + CORE_ADDR address = bp_tgt->placed_address; + struct bp_location *bl; int ret; - ret = target_remove_breakpoint (gdbarch, bp_tgt); + bl = find_non_raw_software_breakpoint_inserted_here (aspace, address); + + /* Only remove the raw breakpoint if there are no other non-raw + breakpoints still inserted at this location. Otherwise, we would + be effectively disabling those breakpoints. */ + if (bl == NULL) + ret = target_remove_breakpoint (gdbarch, bp_tgt); + else if (!VEC_empty (agent_expr_p, bl->target_info.conditions) + || !VEC_empty (agent_expr_p, bl->target_info.tcommands)) + { + /* The target is evaluating conditions, and when we inserted the + software single-step breakpoint, we had made the breakpoint + unconditional and command-less on the target side. Reinsert + to restore the conditions/commands. */ + ret = target_insert_breakpoint (bl->gdbarch, &bl->target_info); + } + else + ret = 0; + xfree (bp_tgt); return ret; diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp index 62415e7..2a12ad6 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp @@ -47,6 +47,5 @@ gdb_test "si" "Breakpoint .* bar break .*" # If the breakpoint is still correctly inserted, then this jump should # re-trigger it. Otherwise, GDB will lose control and the program -# will exit. -setup_kfail "breakpoints/17000" "*-*-*" +# will exit. See PR breakpoints/17000. gdb_test "jump *\$pc" "Breakpoint .* bar break .*" -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-02 23:16 ` Pedro Alves @ 2014-06-03 8:22 ` Pedro Alves 2014-06-03 11:53 ` [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test Pedro Alves 2014-06-03 13:11 ` [RFA/7.8] user breakpoint not inserted if software-single-step at same location Pedro Alves 0 siblings, 2 replies; 29+ messages in thread From: Pedro Alves @ 2014-06-03 8:22 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 06/03/2014 12:16 AM, Pedro Alves wrote: > Let me know what you think, and feel free to push if it > looks OK. Tested on all combinations of > native|gdbserver X hardware-|software- stepping. At least, > I think I did. If not this exact version, some other minor > variation. :-) Bah, I woke up realizing that the version I posted forgets to clone the shadow buffer! Let me fix that and repost... -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test 2014-06-03 8:22 ` Pedro Alves @ 2014-06-03 11:53 ` Pedro Alves 2014-06-03 13:08 ` Pedro Alves 2014-06-03 13:11 ` [RFA/7.8] user breakpoint not inserted if software-single-step at same location Pedro Alves 1 sibling, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 11:53 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 06/03/2014 09:22 AM, Pedro Alves wrote: > On 06/03/2014 12:16 AM, Pedro Alves wrote: > >> Let me know what you think, and feel free to push if it >> looks OK. Tested on all combinations of >> native|gdbserver X hardware-|software- stepping. At least, >> I think I did. If not this exact version, some other minor >> variation. :-) > > Bah, I woke up realizing that the version I posted forgets to > clone the shadow buffer! Let me fix that and repost... > I managed to come up with a test that exposed this. Basically, it does: (gdb) disassemble test Dump of assembler code for function test: 0x0000000000400766 <+0>: push %rbp 0x0000000000400767 <+1>: mov %rsp,%rbp => 0x000000000040076a <+4>: nop 0x000000000040076b <+5>: nop 0x000000000040076c <+6>: pop %rbp 0x000000000040076d <+7>: retq End of assembler dump. (gdb) si& (gdb) del $bpnum (gdb) disassemble test Dump of assembler code for function test: 0x0000000000400766 <+0>: push %rbp 0x0000000000400767 <+1>: mov %rsp,%rbp 0x000000000040076a <+4>: nop => 0x000000000040076b <+5>: int3 0x000000000040076c <+6>: pop %rbp 0x000000000040076d <+7>: retq End of assembler dump. And note the bogus "int3" in the second disassemble output. The test actually fails in a different way currently against gdbserver: (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: define stepi_del_break stepi_del_break Cannot execute this command while the target is running. (gdb) FAIL: gdb.base/sss-bp-on-user-bp-2.exp: stepi_del_break The error is because GDB tried to remove the breakpoint from memory while the thread was running, and we can't talk to the server in the all-stop RSP until we get a stop reply, but in any case, GDB shouldn't even be attempting to remove the breakpoint, exactly because there was a sss breakpoint at the same address. I've added a kfail, and pushed it. 8<-------------- PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - test GDB gets confused when removing a software single-step breakpoint that is at the same address as another breakpoint. Add another kfailed test. gdb/testsuite/ 2014-06-03 Pedro Alves <palves@redhat.com> PR breakpoints/17000 * gdb.base/sss-bp-on-user-bp-2.c: New file. * gdb.base/sss-bp-on-user-bp-2.exp: New file. --- gdb/testsuite/ChangeLog | 6 ++ gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.c | 29 +++++++ gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp | 109 +++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.c create mode 100644 gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 9ded6eb..644f5ac 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-06-03 Pedro Alves <palves@redhat.com> + + PR breakpoints/17000 + * gdb.base/sss-bp-on-user-bp-2.c: New file. + * gdb.base/sss-bp-on-user-bp-2.exp: New file. + 2014-06-02 Doug Evans <xdje42@gmail.com> * gdb.guile/scm-parameter.exp: New file. diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.c b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.c new file mode 100644 index 0000000..c3c26fe --- /dev/null +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.c @@ -0,0 +1,29 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +static void +test (void) +{ + label: asm (" nop"); label2: asm (" nop"); /* must be a single line */ +} + +int +main (void) +{ + test (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp new file mode 100644 index 0000000..a129bb7 --- /dev/null +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp @@ -0,0 +1,109 @@ +# Copyright (C) 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that GDB doesn't get confused in the following scenario +# (PR breakpoints/17000). Say, we have this program: +# +# => 0xff000001 INSN1 +# 0xff000002 INSN2 +# +# The PC currently points at INSN1. +# +# 1 - User sets a breakpoint at 0xff000002 (INSN2). +# +# 2 - User steps. On software single-step archs, this sets a software +# single-step breakpoint at 0xff000002 (INSN2) too. +# +# 3 - User deletes breakpoint (INSN2) before the single-step finishes. +# +# 4 - The single-step finishes, and GDB removes the single-step +# breakpoint. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +if ![runto_main] { + fail "Can't run to main" + return 0 +} + +set line_re "\[^\r\n\]*" + +gdb_test "b test:label" "Breakpoint .*" +gdb_continue_to_breakpoint "run past setup" +delete_breakpoints + +# So we can precisely control breakpoint insertion order. +gdb_test_no_output "set breakpoint always-inserted on" + +# Capture disassembly output. PREFIX is used as test prefix. The +# current instruction indicator (=>) is stripped away. +proc disassemble { prefix } { + with_test_prefix "$prefix" { + set output [capture_command_output "disassemble test" ""] + return [string map {"=>" " "} $output] + } +} + +# Issue a stepi and immediately delete the user breakpoint that is set +# at the same address as the software single-step breakpoint. Do this +# in a user defined command, so that the stepi's trap doesn't have a +# chance to be handled before further input is processed. We then +# compare before/after disassembly. GDB should be able to handle +# deleting the user breakpoint before deleting the single-step +# breakpoint. E.g., we shouldn't see breakpoint instructions in the +# disassembly. + +set disasm_before [disassemble "before"] + +gdb_test "b test:label2" ".*" "set breakpoint where si will land" + +set test "define stepi_del_break" +gdb_test_multiple $test $test { + -re "Type commands for definition of \"stepi_del_break\".\r\nEnd with a line saying just \"end\".\r\n>$" { + gdb_test "si&\ndel \$bpnum\nend" "" $test + } +} + +set command "stepi_del_break" +set test $command +setup_kfail "breakpoints/17000" "*-*-*" +gdb_test_multiple $command $test { + -re "^$command\r\n$gdb_prompt " { + # Note no end anchor, because "si&" finishes and prints the + # current frame/line after the prompt is printed. + pass $test + } +} + +# Now consume the output of the finished "si&". +set test "si& finished" +gdb_test_multiple "" $test { + -re "must be a single line \\\*/\r\n" { + pass $test + } +} + +set disasm_after [disassemble "after"] + +set test "before/after disassembly matches" +if ![string compare $disasm_before $disasm_after] { + pass $test +} else { + fail $test +} -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test 2014-06-03 11:53 ` [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test Pedro Alves @ 2014-06-03 13:08 ` Pedro Alves 2014-06-06 19:05 ` [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux. (was: [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test) Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 13:08 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 06/03/2014 12:53 PM, Pedro Alves wrote: > (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: define stepi_del_break > stepi_del_break > Cannot execute this command while the target is running. > (gdb) FAIL: gdb.base/sss-bp-on-user-bp-2.exp: stepi_del_break > > The error is because GDB tried to remove the breakpoint from > memory while the thread was running, and we can't talk to the > server in the all-stop RSP until we get a stop reply, but in any > case, GDB shouldn't even be attempting to remove the breakpoint, > exactly because there was a sss breakpoint at the same address. > > I've added a kfail, and pushed it. Gosh, so many different mode combinations... So the fix for PR17000 doesn't fix that failure when testing against gdbserver _and_ hardware stepping. Well, of course it doesn't, because in that case GDB will really try to remove the breakpoint, because there's no overlapping software single-step breakpoint. I've pushed this to detect the scenario and skip the test. 8<--------------------- Subject: [PATCH] Skip sss-bp-on-user-bp-2.exp on remote hardware step targets. gdb/testsuite/ 2014-06-03 Pedro Alves <palves@redhat.com> * gdb.base/sss-bp-on-user-bp-2.exp: Skip if testing with a remote target that doesn't use software single-stepping. --- gdb/testsuite/ChangeLog | 5 ++++ gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp | 39 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 644f5ac..8217403 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2014-06-03 Pedro Alves <palves@redhat.com> + * gdb.base/sss-bp-on-user-bp-2.exp: Skip if testing with a remote + target that doesn't use software single-stepping. + +2014-06-03 Pedro Alves <palves@redhat.com> + PR breakpoints/17000 * gdb.base/sss-bp-on-user-bp-2.c: New file. * gdb.base/sss-bp-on-user-bp-2.exp: New file. diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp index a129bb7..b41f86e 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp @@ -42,6 +42,45 @@ if ![runto_main] { return 0 } +delete_breakpoints + +# With the all-stop RSP, we can't talk to the target while it's +# running, until we get back the stop reply. If not using single-step +# breakpoints, then the "del" in stepi_del_break below will try to +# delete the user breakpoint from the target, which will fail, with +# "Cannot execute this command while the target is running.". On +# software single-step targets, that del shouldn't trigger any RSP +# traffic. Just skip the test if testing against a remove target and +# not using software single-stepping. IOW, skip the test if we see a +# 'vCont;s' or 's' in the RSP traffic. + +gdb_test_no_output "set debug remote 1" + +set rsp_hardware_step 0 + +# Probe for software single-step breakpoint use. +set test "probe RSP hardware step" +gdb_test_multiple "si" $test { + -re "\\\$vCont;s.*$gdb_prompt $" { + set rsp_hardware_step 1 + pass $test + } + -re "\\\$s#.*$gdb_prompt $" { + set rsp_hardware_step 1 + pass $test + } + -re "$gdb_prompt $" { + pass $test + } +} + +if { $rsp_hardware_step } { + unsupported "remote target doesn't use software single-stepping" + return +} + +gdb_test_no_output "set debug remote 0" + set line_re "\[^\r\n\]*" gdb_test "b test:label" "Breakpoint .*" -- 1.9.0 -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux. (was: [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test) 2014-06-03 13:08 ` Pedro Alves @ 2014-06-06 19:05 ` Pedro Alves 2014-06-09 14:26 ` [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-06 19:05 UTC (permalink / raw) To: gdb-patches; +Cc: Joel Brobecker On 06/03/2014 02:08 PM, Pedro Alves wrote: > On 06/03/2014 12:53 PM, Pedro Alves wrote: > >> (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: define stepi_del_break >> stepi_del_break >> Cannot execute this command while the target is running. >> (gdb) FAIL: gdb.base/sss-bp-on-user-bp-2.exp: stepi_del_break >> >> The error is because GDB tried to remove the breakpoint from >> memory while the thread was running, and we can't talk to the >> server in the all-stop RSP until we get a stop reply, but in any >> case, GDB shouldn't even be attempting to remove the breakpoint, >> exactly because there was a sss breakpoint at the same address. >> >> I've added a kfail, and pushed it. > > Gosh, so many different mode combinations... So the fix for > PR17000 doesn't fix that failure when testing against gdbserver > _and_ hardware stepping. Well, of course it doesn't, because in > that case GDB will really try to remove the breakpoint, because > there's no overlapping software single-step breakpoint. > and ... > +# With the all-stop RSP, we can't talk to the target while it's > +# running, until we get back the stop reply. If not using single-step > +# breakpoints, then the "del" in stepi_del_break below will try to > +# delete the user breakpoint from the target, which will fail, with > +# "Cannot execute this command while the target is running.". On > +# software single-step targets, that del shouldn't trigger any RSP > +# traffic. Just skip the test if testing against a remove target and > +# not using software single-stepping. IOW, skip the test if we see a > +# 'vCont;s' or 's' in the RSP traffic. ... this is still not sufficient... I pushed the commit below to skip the test on native targets too. I was surprised the failure to remove the breakpoint mentioned below didn't cause a warning. That'll be the subject of a separate patch. 8<----------- From 829155c9adb5f3750c9c612702fdbf26fa7c558e Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Fri, 6 Jun 2014 19:59:21 +0100 Subject: [PATCH] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux. I noticed that sss-bp-on-user-bp-2.exp is racy on native GNU/Linux. I sometimes still see an int3 in the disassembly: (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: set debug target 0 disassemble test Dump of assembler code for function test: 0x0000000000400590 <+0>: push %rbp 0x0000000000400591 <+1>: mov %rsp,%rbp 0x0000000000400594 <+4>: nop => 0x0000000000400595 <+5>: int3 0x0000000000400596 <+6>: pop %rbp 0x0000000000400597 <+7>: retq End of assembler dump. (gdb) FAIL: gdb.base/sss-bp-on-user-bp-2.exp: before/after disassembly matches Enabling infrun/target debug logs, we can see the problem. Simplified, that's: (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: define stepi_del_break stepi_del_break infrun: clear_proceed_status_thread (process 25311) infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=0, current thread [process 25311] at 0x400594 LLR: PTRACE_SINGLESTEP process 25311, 0 (resume event thread) target_resume (25311, step, 0) native:target_xfer_partial (3, (null), 0x0, 0x32dce4c, 0x400595, 1) = 0, 0 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (gdb) linux_nat_wait: [process -1], [TARGET_WNOHANG] 0x400595 is the address of the breakpoint, and "= 0" is TARGET_XFER_EOF. That's default_memory_remove_breakpoint trying to remove the breakpoint, but failing. The problem is that we had just resumed the target and the native GNU/Linux target can't read memory off of a running thread. Most of the time, we get "lucky", because we manage to read memory before the kernel actually schedules the target to run. So just give up and skip the test on any target that uses hardware stepping, not just remote targets. gdb/testsuite/ 2014-06-06 Pedro Alves <palves@redhat.com> * gdb.base/sss-bp-on-user-bp-2.exp: Look for target_resume(step) in target debug output instead of looking at RSP packets, disabling the test on any target that uses hardware stepping. Update comments. --- gdb/testsuite/ChangeLog | 7 ++++++ gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp | 31 ++++++++++++-------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 933df0a..327e648 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2014-06-06 Pedro Alves <palves@redhat.com> + * gdb.base/sss-bp-on-user-bp-2.exp: Look for target_resume(step) + in target debug output instead of looking at RSP packets, + disabling the test on any target that uses hardware stepping. + Update comments. + +2014-06-06 Pedro Alves <palves@redhat.com> + * gdb.base/break-unload-file.exp: Fix typo. 2014-06-06 Yao Qi <yao@codesourcery.com> diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp index 87fa5f8..a196f68 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp @@ -50,23 +50,20 @@ delete_breakpoints # delete the user breakpoint from the target, which will fail, with # "Cannot execute this command while the target is running.". On # software single-step targets, that del shouldn't trigger any RSP -# traffic. Just skip the test if testing against a remove target and -# not using software single-stepping. IOW, skip the test if we see a -# 'vCont;s' or 's' in the RSP traffic. - -gdb_test_no_output "set debug remote 1" - -set rsp_hardware_step 0 +# traffic. Hardware-step targets that can't access memory while the +# target is running, either remote or native, are likewise affected. +# So we just skip the test if not using software single-stepping. We +# detect that by looking for 'target_resume (..., step)' in "debug +# target" output. # Probe for software single-step breakpoint use. -set test "probe RSP hardware step" + +gdb_test_no_output "set debug target 1" +set hardware_step 0 +set test "probe target hardware step" gdb_test_multiple "si" $test { - -re "\\\$vCont;s.*$gdb_prompt $" { - set rsp_hardware_step 1 - pass $test - } - -re "\\\$s#.*$gdb_prompt $" { - set rsp_hardware_step 1 + -re "target_resume \\(\[^\r\n\]+, step, .*$gdb_prompt $" { + set hardware_step 1 pass $test } -re "$gdb_prompt $" { @@ -74,12 +71,12 @@ gdb_test_multiple "si" $test { } } -if { $rsp_hardware_step } { - unsupported "remote target doesn't use software single-stepping" +if { $hardware_step } { + unsupported "target doesn't use software single-stepping" return } -gdb_test_no_output "set debug remote 0" +gdb_test_no_output "set debug target 0" set line_re "\[^\r\n\]*" -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux. 2014-06-06 19:05 ` [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux. (was: [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test) Pedro Alves @ 2014-06-09 14:26 ` Pedro Alves 0 siblings, 0 replies; 29+ messages in thread From: Pedro Alves @ 2014-06-09 14:26 UTC (permalink / raw) To: gdb-patches; +Cc: Joel Brobecker On 06/06/2014 08:05 PM, Pedro Alves wrote: > Enabling infrun/target debug logs, we can see the problem. > Simplified, that's: > > (gdb) PASS: gdb.base/sss-bp-on-user-bp-2.exp: define stepi_del_break > stepi_del_break > infrun: clear_proceed_status_thread (process 25311) > infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=0, current thread [process 25311] at 0x400594 > LLR: PTRACE_SINGLESTEP process 25311, 0 (resume event thread) > target_resume (25311, step, 0) > native:target_xfer_partial (3, (null), 0x0, 0x32dce4c, 0x400595, 1) = 0, 0 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > (gdb) linux_nat_wait: [process -1], [TARGET_WNOHANG] > > 0x400595 is the address of the breakpoint, and "= 0" is > TARGET_XFER_EOF. That's default_memory_remove_breakpoint trying to > remove the breakpoint, but failing. I was quite surprised this didn't result in a user visible warning. Turns out that's a regression compared to 7.7. This fixes it: https://sourceware.org/ml/gdb-patches/2014-06/msg00377.html -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 8:22 ` Pedro Alves 2014-06-03 11:53 ` [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test Pedro Alves @ 2014-06-03 13:11 ` Pedro Alves 2014-06-03 13:35 ` Joel Brobecker 1 sibling, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 13:11 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 06/03/2014 09:22 AM, Pedro Alves wrote: > On 06/03/2014 12:16 AM, Pedro Alves wrote: > >> Let me know what you think, and feel free to push if it >> looks OK. Tested on all combinations of >> native|gdbserver X hardware-|software- stepping. At least, >> I think I did. If not this exact version, some other minor >> variation. :-) > > Bah, I woke up realizing that the version I posted forgets to > clone the shadow buffer! Let me fix that and repost... > Here is the fixed version. Retested on all combinations of native|gdbserver X hardware-|software- stepping on x86_64 Fedora 20. Fixes both new tests. 8<------------ Subject: [PATCH] User breakpoint ignored if software-single-step at same location with the following code... 12 Nested; -- break #1 13 return I; -- break #2 14 end; (line 12 is a call to function Nested) ... we have noticed the following errorneous behavior on ppc-aix, where, after having inserted a breakpoint at line 12 and line 13, and continuing from the breakpoint at line 12, the program never stops at line 13, running away until the program terminates: % gdb -q func (gdb) b func.adb:12 Breakpoint 1 at 0x10000a24: file func.adb, line 12. (gdb) b func.adb:13 Breakpoint 2 at 0x10000a28: file func.adb, line 13. (gdb) run Starting program: /[...]/func Breakpoint 1, func () at func.adb:12 12 Nested; -- break #1 (gdb) c Continuing. [Inferior 1 (process 4128872) exited with code 02] When resuming from the first breakpoint, GDB first tries to step out of that first breakpoint. We rely on software single-stepping on this platform, and it just so happens that the address of the first software single-step breakpoint is the same as the user's breakpoint #2 (0x10000a28). So, with infrun and target traces turned on (but uninteresting traces snip'ed off), the "continue" operation looks like this: (gdb) c ### First, we insert the user breakpoints (the second one is an internal ### breakpoint on __pthread_init). The first user breakpoint is not ### inserted as we need to step out of it first. target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000d03f3800, xxx) = 0 ### Then we proceed with the step-out-of-breakpoint... infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=1, current thread [process 15335610] at 0x10000a24 ### That's when we insert the SSS breakpoints... target_insert_breakpoint (0x0000000010000a28, xxx) = 0 target_insert_breakpoint (0x00000000100009ac, xxx) = 0 ### ... then let the inferior resume... target_resume (15335610, continue, 0) infrun: wait_for_inferior () target_wait (-1, status, options={}) = 15335610, status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: target_wait (-1, status) = infrun: 15335610 [process 15335610], infrun: status->kind = stopped, signal = GDB_SIGNAL_TRAP infrun: infwait_normal_state infrun: TARGET_WAITKIND_STOPPED infrun: stop_pc = 0x100009ac ### At this point, we stopped at the second SSS breakpoint... target_stopped_by_watchpoint () = 0 ### We remove the SSS breakpoints... target_remove_breakpoint (0x0000000010000a28, xxx) = 0 target_remove_breakpoint (0x00000000100009ac, xxx) = 0 target_stopped_by_watchpoint () = 0 ### We find that we're not done, so we resume.... infrun: no stepping, continue ### And thus insert the user breakpoints again, except we're not ### inserting the second breakpoint?!? target_insert_breakpoint (0x0000000010000a24, xxx) = 0 infrun: resume (step=0, signal=GDB_SIGNAL_0), trap_expected=0, current thread [process 15335610] at 0x100009ac target_resume (-1, continue, 0) infrun: prepare_to_wait target_wait (-1, status, options={}) = 15335610, status->kind = exited, status = 2 What happens is that the removal of the software single-step breakpoints effectively removed the breakpoint instruction from inferior memory. But because such breakpoints are inserted directly as raw breakpoints rather than through the normal chain of breakpoints, we fail to notice that one of the user breakpoints points to the same address and that this user breakpoint is therefore effectively un-inserted. When resuming after the single-step, GDB thinks that the user breakpoint is still inserted and therefore does not need to insert it again. This patch teaches the insert and remove routines of both regular and raw breakpoints to be aware of each other. Special care needs to be applied in case the target supports evaluation of breakpoint conditions or commands. gdb/ChangeLog: PR breakpoints/17000 * breakpoint.c (find_non_raw_software_breakpoint_inserted_here): New function, extracted from software_breakpoint_inserted_here_p. (software_breakpoint_inserted_here_p): Replace factored out code by call to find_non_raw_software_breakpoint_inserted_here. (bp_target_info_copy_insertion_state): New function. (bkpt_insert_location): Handle the case of a single-step breakpoint already inserted at the same address. (bkpt_remove_location): Handle the case of a single-step breakpoint still inserted at the same address. (deprecated_insert_raw_breakpoint): Handle the case of non-raw breakpoint already inserted at the same address. (deprecated_remove_raw_breakpoint): Handle the case of a non-raw breakpoint still inserted at the same address. (find_single_step_breakpoint): New function, extracted from single_step_breakpoint_inserted_here_p. (find_single_step_breakpoint): New function, factored out from single_step_breakpoint_inserted_here_p. (single_step_breakpoint_inserted_here_p): Reimplement. gdb/testsuite/ChangeLog: PR breakpoints/17000 * gdb.base/sss-bp-on-user-bp.exp: Remove kfail. * gdb.base/sss-bp-on-user-bp-2.exp: Remove kfail. Tested on ppc-aix with AdaCore's testsuite. Tested on x86_64-linux, (native and gdbserver) with the official testsuite. Also tested on x86_64-linux through Pedro's branch enabling software single-stepping on that platform (native and gdbserver). --- gdb/breakpoint.c | 141 ++++++++++++++++++++++--- gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp | 1 - gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp | 3 +- 3 files changed, 125 insertions(+), 20 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 4e6c627..23c8895 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -229,6 +229,9 @@ static void tcatch_command (char *arg, int from_tty); static void detach_single_step_breakpoints (void); +static int find_single_step_breakpoint (struct address_space *aspace, + CORE_ADDR pc); + static void free_bp_location (struct bp_location *loc); static void incref_bp_location (struct bp_location *loc); static void decref_bp_location (struct bp_location **loc); @@ -4165,12 +4168,12 @@ breakpoint_inserted_here_p (struct address_space *aspace, CORE_ADDR pc) return 0; } -/* This function returns non-zero iff there is a software breakpoint - inserted at PC. */ +/* Ignoring deprecated raw breakpoints, return non-zero iff there is a + software breakpoint inserted at PC. */ -int -software_breakpoint_inserted_here_p (struct address_space *aspace, - CORE_ADDR pc) +static struct bp_location * +find_non_raw_software_breakpoint_inserted_here (struct address_space *aspace, + CORE_ADDR pc) { struct bp_location *bl, **blp_tmp; @@ -4188,10 +4191,23 @@ software_breakpoint_inserted_here_p (struct address_space *aspace, && !section_is_mapped (bl->section)) continue; /* unmapped overlay -- can't be a match */ else - return 1; + return bl; } } + return NULL; +} + +/* This function returns non-zero iff there is a software breakpoint + inserted at PC. */ + +int +software_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) +{ + if (find_non_raw_software_breakpoint_inserted_here (aspace, pc) != NULL) + return 1; + /* Also check for software single-step breakpoints. */ if (single_step_breakpoint_inserted_here_p (aspace, pc)) return 1; @@ -13112,6 +13128,19 @@ bkpt_re_set (struct breakpoint *b) breakpoint_re_set_default (b); } +/* Copy SRC's shadow buffer and whatever else we'd set if we actually + inserted DEST, so we can remove it later, in case SRC is removed + first. */ + +static void +bp_target_info_copy_insertion_state (struct bp_target_info *dest, + const struct bp_target_info *src) +{ + dest->shadow_len = src->shadow_len; + memcpy (dest->shadow_contents, src->shadow_contents, src->shadow_len); + dest->placed_size = src->placed_size; +} + static int bkpt_insert_location (struct bp_location *bl) { @@ -13119,8 +13148,25 @@ bkpt_insert_location (struct bp_location *bl) return target_insert_hw_breakpoint (bl->gdbarch, &bl->target_info); else - return target_insert_breakpoint (bl->gdbarch, - &bl->target_info); + { + struct bp_target_info *bp_tgt = &bl->target_info; + int ret; + int sss_slot; + + /* There is no need to insert a breakpoint if an unconditional + raw/sss breakpoint is already inserted at that location. */ + sss_slot = find_single_step_breakpoint (bp_tgt->placed_address_space, + bp_tgt->placed_address); + if (sss_slot >= 0) + { + struct bp_target_info *sss_bp_tgt = single_step_breakpoints[sss_slot]; + + bp_target_info_copy_insertion_state (bp_tgt, sss_bp_tgt); + return 0; + } + + return target_insert_breakpoint (bl->gdbarch, bp_tgt); + } } static int @@ -13129,7 +13175,19 @@ bkpt_remove_location (struct bp_location *bl) if (bl->loc_type == bp_loc_hardware_breakpoint) return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info); else - return target_remove_breakpoint (bl->gdbarch, &bl->target_info); + { + struct bp_target_info *bp_tgt = &bl->target_info; + struct address_space *aspace = bp_tgt->placed_address_space; + CORE_ADDR address = bp_tgt->placed_address; + + /* Only remove the breakpoint if there is no raw/sss breakpoint + still inserted at this location. Otherwise, we would be + effectively disabling the raw/sss breakpoint. */ + if (single_step_breakpoint_inserted_here_p (aspace, address)) + return 0; + + return target_remove_breakpoint (bl->gdbarch, bp_tgt); + } } static int @@ -15138,12 +15196,30 @@ deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch, struct address_space *aspace, CORE_ADDR pc) { struct bp_target_info *bp_tgt; + struct bp_location *bl; bp_tgt = XCNEW (struct bp_target_info); bp_tgt->placed_address_space = aspace; bp_tgt->placed_address = pc; + /* If an unconditional non-raw breakpoint is already inserted at + that location, there's no need to insert another. However, with + target-side evaluation of breakpoint conditions, if the + breakpoint that is currently inserted on the target is + conditional, we need to make it unconditional. Note that a + breakpoint with target-side commands is not reported even if + unconditional, so we need to remove the commands from the target + as well. */ + bl = find_non_raw_software_breakpoint_inserted_here (aspace, pc); + if (bl != NULL + && VEC_empty (agent_expr_p, bl->target_info.conditions) + && VEC_empty (agent_expr_p, bl->target_info.tcommands)) + { + bp_target_info_copy_insertion_state (bp_tgt, &bl->target_info); + return bp_tgt; + } + if (target_insert_breakpoint (gdbarch, bp_tgt) != 0) { /* Could not insert the breakpoint. */ @@ -15161,9 +15237,30 @@ int deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp) { struct bp_target_info *bp_tgt = bp; + struct address_space *aspace = bp_tgt->placed_address_space; + CORE_ADDR address = bp_tgt->placed_address; + struct bp_location *bl; int ret; - ret = target_remove_breakpoint (gdbarch, bp_tgt); + bl = find_non_raw_software_breakpoint_inserted_here (aspace, address); + + /* Only remove the raw breakpoint if there are no other non-raw + breakpoints still inserted at this location. Otherwise, we would + be effectively disabling those breakpoints. */ + if (bl == NULL) + ret = target_remove_breakpoint (gdbarch, bp_tgt); + else if (!VEC_empty (agent_expr_p, bl->target_info.conditions) + || !VEC_empty (agent_expr_p, bl->target_info.tcommands)) + { + /* The target is evaluating conditions, and when we inserted the + software single-step breakpoint, we had made the breakpoint + unconditional and command-less on the target side. Reinsert + to restore the conditions/commands. */ + ret = target_insert_breakpoint (bl->gdbarch, &bl->target_info); + } + else + ret = 0; + xfree (bp_tgt); return ret; @@ -15269,12 +15366,12 @@ detach_single_step_breakpoints (void) single_step_breakpoints[i]); } -/* Check whether a software single-step breakpoint is inserted at - PC. */ +/* Find the software single-step breakpoint that inserted at PC. + Returns its slot if found, and -1 if not found. */ -int -single_step_breakpoint_inserted_here_p (struct address_space *aspace, - CORE_ADDR pc) +static int +find_single_step_breakpoint (struct address_space *aspace, + CORE_ADDR pc) { int i; @@ -15285,10 +15382,20 @@ single_step_breakpoint_inserted_here_p (struct address_space *aspace, && breakpoint_address_match (bp_tgt->placed_address_space, bp_tgt->placed_address, aspace, pc)) - return 1; + return i; } - return 0; + return -1; +} + +/* Check whether a software single-step breakpoint is inserted at + PC. */ + +int +single_step_breakpoint_inserted_here_p (struct address_space *aspace, + CORE_ADDR pc) +{ + return find_single_step_breakpoint (aspace, pc) >= 0; } /* Returns 0 if 'bp' is NOT a syscall catchpoint, diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp index b41f86e..87fa5f8 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp-2.exp @@ -121,7 +121,6 @@ gdb_test_multiple $test $test { set command "stepi_del_break" set test $command -setup_kfail "breakpoints/17000" "*-*-*" gdb_test_multiple $command $test { -re "^$command\r\n$gdb_prompt " { # Note no end anchor, because "si&" finishes and prints the diff --git a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp index 62415e7..2a12ad6 100644 --- a/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp +++ b/gdb/testsuite/gdb.base/sss-bp-on-user-bp.exp @@ -47,6 +47,5 @@ gdb_test "si" "Breakpoint .* bar break .*" # If the breakpoint is still correctly inserted, then this jump should # re-trigger it. Otherwise, GDB will lose control and the program -# will exit. -setup_kfail "breakpoints/17000" "*-*-*" +# will exit. See PR breakpoints/17000. gdb_test "jump *\$pc" "Breakpoint .* bar break .*" -- 1.9.0 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 13:11 ` [RFA/7.8] user breakpoint not inserted if software-single-step at same location Pedro Alves @ 2014-06-03 13:35 ` Joel Brobecker 2014-06-03 15:41 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Joel Brobecker @ 2014-06-03 13:35 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Hi Pedro, > > Bah, I woke up realizing that the version I posted forgets to > > clone the shadow buffer! Let me fix that and repost... You are producing patches so fast, I am wondering if I will be able to keep up! :-) > gdb/ChangeLog: > > PR breakpoints/17000 > * breakpoint.c (find_non_raw_software_breakpoint_inserted_here): > New function, extracted from software_breakpoint_inserted_here_p. > (software_breakpoint_inserted_here_p): Replace factored out code > by call to find_non_raw_software_breakpoint_inserted_here. > (bp_target_info_copy_insertion_state): New function. > (bkpt_insert_location): Handle the case of a single-step > breakpoint already inserted at the same address. > (bkpt_remove_location): Handle the case of a single-step > breakpoint still inserted at the same address. > (deprecated_insert_raw_breakpoint): Handle the case of non-raw > breakpoint already inserted at the same address. > (deprecated_remove_raw_breakpoint): Handle the case of a > non-raw breakpoint still inserted at the same address. > (find_single_step_breakpoint): New function, extracted from > single_step_breakpoint_inserted_here_p. > (find_single_step_breakpoint): New function, > factored out from single_step_breakpoint_inserted_here_p. > (single_step_breakpoint_inserted_here_p): Reimplement. > > gdb/testsuite/ChangeLog: > > PR breakpoints/17000 > * gdb.base/sss-bp-on-user-bp.exp: Remove kfail. > * gdb.base/sss-bp-on-user-bp-2.exp: Remove kfail. You are making it us realize that the problem is more and more complex than we thought! :-(. And I think we'll need a small adjustment to your patch in order to account for something that may have been missed. See below: > @@ -15138,12 +15196,30 @@ deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch, > struct address_space *aspace, CORE_ADDR pc) > { > struct bp_target_info *bp_tgt; > + struct bp_location *bl; > > bp_tgt = XCNEW (struct bp_target_info); > > bp_tgt->placed_address_space = aspace; > bp_tgt->placed_address = pc; > > + /* If an unconditional non-raw breakpoint is already inserted at > + that location, there's no need to insert another. However, with > + target-side evaluation of breakpoint conditions, if the > + breakpoint that is currently inserted on the target is > + conditional, we need to make it unconditional. Note that a > + breakpoint with target-side commands is not reported even if > + unconditional, so we need to remove the commands from the target > + as well. */ > + bl = find_non_raw_software_breakpoint_inserted_here (aspace, pc); > + if (bl != NULL > + && VEC_empty (agent_expr_p, bl->target_info.conditions) > + && VEC_empty (agent_expr_p, bl->target_info.tcommands)) > + { > + bp_target_info_copy_insertion_state (bp_tgt, &bl->target_info); > + return bp_tgt; > + } > + ISTM that you are assuming that there would only be one other breakpoint inserted at this location. What if there were more? If I am right, I suggest the addition of an extra parameter to find_non_raw_software_breakpoint_inserted_here which would be a pointer to a filtering function. If NULL, no filtering is done, but if not NULL, the filter function must accept the bp_location for find_non_raw_software_breakpoint_inserted_here to return it. > deprecated_remove_raw_breakpoint (struct gdbarch *gdbarch, void *bp) > { > struct bp_target_info *bp_tgt = bp; > + struct address_space *aspace = bp_tgt->placed_address_space; > + CORE_ADDR address = bp_tgt->placed_address; > + struct bp_location *bl; > int ret; > > - ret = target_remove_breakpoint (gdbarch, bp_tgt); > + bl = find_non_raw_software_breakpoint_inserted_here (aspace, address); > + > + /* Only remove the raw breakpoint if there are no other non-raw > + breakpoints still inserted at this location. Otherwise, we would > + be effectively disabling those breakpoints. */ > + if (bl == NULL) > + ret = target_remove_breakpoint (gdbarch, bp_tgt); > + else if (!VEC_empty (agent_expr_p, bl->target_info.conditions) > + || !VEC_empty (agent_expr_p, bl->target_info.tcommands)) > + { > + /* The target is evaluating conditions, and when we inserted the > + software single-step breakpoint, we had made the breakpoint > + unconditional and command-less on the target side. Reinsert > + to restore the conditions/commands. */ > + ret = target_insert_breakpoint (bl->gdbarch, &bl->target_info); > + } > + else > + ret = 0; Same here, I think. -- Joel ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 13:35 ` Joel Brobecker @ 2014-06-03 15:41 ` Pedro Alves 2014-06-03 16:23 ` Joel Brobecker 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 15:41 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 06/03/2014 02:35 PM, Joel Brobecker wrote: > Hi Pedro, > >>> Bah, I woke up realizing that the version I posted forgets to >>> clone the shadow buffer! Let me fix that and repost... > > You are producing patches so fast, I am wondering if I will be able > to keep up! :-) :-) >> @@ -15138,12 +15196,30 @@ deprecated_insert_raw_breakpoint (struct gdbarch *gdbarch, >> struct address_space *aspace, CORE_ADDR pc) >> { >> struct bp_target_info *bp_tgt; >> + struct bp_location *bl; >> >> bp_tgt = XCNEW (struct bp_target_info); >> >> bp_tgt->placed_address_space = aspace; >> bp_tgt->placed_address = pc; >> >> + /* If an unconditional non-raw breakpoint is already inserted at >> + that location, there's no need to insert another. However, with >> + target-side evaluation of breakpoint conditions, if the >> + breakpoint that is currently inserted on the target is >> + conditional, we need to make it unconditional. Note that a >> + breakpoint with target-side commands is not reported even if >> + unconditional, so we need to remove the commands from the target >> + as well. */ >> + bl = find_non_raw_software_breakpoint_inserted_here (aspace, pc); >> + if (bl != NULL >> + && VEC_empty (agent_expr_p, bl->target_info.conditions) >> + && VEC_empty (agent_expr_p, bl->target_info.tcommands)) >> + { >> + bp_target_info_copy_insertion_state (bp_tgt, &bl->target_info); >> + return bp_tgt; >> + } >> + > > ISTM that you are assuming that there would only be one other breakpoint > inserted at this location. What if there were more? Yep, it's a valid assumption. Only one of those can be the one that is actually inserted in the target. All others breakpoints are considered duplicates, with bl->duplicate == 1 and bl->inserted == 0, and never reach the target. The duplicate location logic in the tail of update_global_location_list takes care of it: /* This and the above ensure the invariant that the first location is not duplicated, and is the inserted one. All following are marked as duplicated, and are not inserted. */ if (loc->inserted) swap_insertion (loc, *loc_first_p); loc->duplicate = 1; The one that is inserted will hold a merge of all the agent expressions (in target_info.conditions and target_info.tcommands) of the target-side conditions and commands of all breakpoints at that address. Those are computed just before that single breakpoint is inserted (build_target_condition_list, build_target_command_list). -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 15:41 ` Pedro Alves @ 2014-06-03 16:23 ` Joel Brobecker 2014-06-03 16:51 ` Pedro Alves 0 siblings, 1 reply; 29+ messages in thread From: Joel Brobecker @ 2014-06-03 16:23 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > Yep, it's a valid assumption. Only one of those can be the one that > is actually inserted in the target. All others breakpoints are considered > duplicates, with bl->duplicate == 1 and bl->inserted == 0, and never reach > the target. The duplicate location logic in the tail of update_global_location_list > takes care of it: > > /* This and the above ensure the invariant that the first location > is not duplicated, and is the inserted one. > All following are marked as duplicated, and are not inserted. */ > if (loc->inserted) > swap_insertion (loc, *loc_first_p); > loc->duplicate = 1; > > The one that is inserted will hold a merge of all the agent > expressions (in target_info.conditions and target_info.tcommands) of > the target-side conditions and commands of all breakpoints at that > address. Those are computed just before that single breakpoint > is inserted (build_target_condition_list, build_target_command_list). Indeed! Thanks for explaining it. I don't have any other comment on the patch. I ran it through our testsuite on ppc-aix, JIC, and as expected, found that it fixed the regression without introducing new ones. I think you can push that version! Thanks for your help, Pedro. -- Joel ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 16:23 ` Joel Brobecker @ 2014-06-03 16:51 ` Pedro Alves 2014-06-03 17:27 ` Joel Brobecker 0 siblings, 1 reply; 29+ messages in thread From: Pedro Alves @ 2014-06-03 16:51 UTC (permalink / raw) To: Joel Brobecker; +Cc: gdb-patches On 06/03/2014 05:23 PM, Joel Brobecker wrote: > I don't have any other comment on the patch. I ran it through our > testsuite on ppc-aix, JIC, and as expected, found that it fixed > the regression without introducing new ones. I think you can push > that version! Awesome, thank you! Now pushed. -- Pedro Alves ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFA/7.8] user breakpoint not inserted if software-single-step at same location 2014-06-03 16:51 ` Pedro Alves @ 2014-06-03 17:27 ` Joel Brobecker 0 siblings, 0 replies; 29+ messages in thread From: Joel Brobecker @ 2014-06-03 17:27 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > Awesome, thank you! Now pushed. Yeepee! I see that you marked the PR as fixed. I moved the AI in the wiki to Done. Thanks! -- Joel ^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2014-06-09 14:26 UTC | newest] Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-05-29 20:11 [RFA/7.8] user breakpoint not inserted if software-single-step at same location Joel Brobecker 2014-05-29 23:17 ` Pedro Alves 2014-05-30 12:22 ` Joel Brobecker 2014-05-30 12:51 ` Pedro Alves 2014-05-30 13:27 ` Joel Brobecker 2014-05-30 15:57 ` Pedro Alves 2014-05-30 16:19 ` Joel Brobecker 2014-05-30 16:23 ` Pedro Alves 2014-05-30 16:23 ` Pedro Alves 2014-06-03 11:55 ` Yao Qi 2014-06-03 12:00 ` Pedro Alves 2014-06-03 12:12 ` Andreas Schwab 2014-06-03 12:19 ` Pedro Alves 2014-06-04 5:14 ` Yao Qi 2014-06-04 8:01 ` Pedro Alves 2014-06-04 12:58 ` Yao Qi 2014-05-30 19:35 ` Joel Brobecker 2014-06-02 23:16 ` Pedro Alves 2014-06-03 8:22 ` Pedro Alves 2014-06-03 11:53 ` [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test Pedro Alves 2014-06-03 13:08 ` Pedro Alves 2014-06-06 19:05 ` [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux. (was: [pushed] PR breakpoints/17000: user breakpoint not inserted if software-single-step at same location - another test) Pedro Alves 2014-06-09 14:26 ` [pushed] sss-bp-on-user-bp-2.exp sometimes fails on native GNU/Linux Pedro Alves 2014-06-03 13:11 ` [RFA/7.8] user breakpoint not inserted if software-single-step at same location Pedro Alves 2014-06-03 13:35 ` Joel Brobecker 2014-06-03 15:41 ` Pedro Alves 2014-06-03 16:23 ` Joel Brobecker 2014-06-03 16:51 ` Pedro Alves 2014-06-03 17:27 ` Joel Brobecker
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).