This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH] breakpoint remove fail handle bug fix
On Thu, 12 Apr 2012 04:16:50 +0200, Hui Zhu wrote:
> But it didn't handle the issue when the target is remote.
[...]
> (gdb) c &
> Continuing.
> (gdb) d
> Delete all breakpoints? (y or n) y
> Cannot execute this command while the target is running.
This is because you did not turn on non-stop mode:
remote.c:
if (!non_stop && target_can_async_p () && rs->waiting_for_stop_reply)
error (_("Cannot execute this command while the target is running."));
It works then, gdbserver has this bug already fixed.
Just I find it a loss of time fixing linux-nat which should get obsoleted by
gdbserver anyway so posting this patch+testcase just FYI.
Regards,
Jan
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index ac1a0ea..299b3ca 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4494,9 +4494,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
}
/* Implement the to_xfer_partial interface for memory reads using the /proc
- filesystem. Because we can use a single read() call for /proc, this
- can be much more efficient than banging away at PTRACE_PEEKTEXT,
- but it doesn't support writes. */
+ filesystem. Because we can use a single read or write call for /proc, this
+ can be much more efficient than banging away at PTRACE_PEEKTEXT or
+ PTRACE_POKETEXT. */
static LONGEST
linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
@@ -4508,29 +4508,35 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
int fd;
char filename[64];
- if (object != TARGET_OBJECT_MEMORY || !readbuf)
- return 0;
-
- /* Don't bother for one word. */
- if (len < 3 * sizeof (long))
+ if (object != TARGET_OBJECT_MEMORY)
return 0;
/* We could keep this file open and cache it - possibly one per
thread. That requires some juggling, but is even faster. */
sprintf (filename, "/proc/%d/mem", PIDGET (inferior_ptid));
- fd = open (filename, O_RDONLY | O_LARGEFILE);
+ fd = open (filename, (readbuf ? O_RDONLY : O_WRONLY) | O_LARGEFILE);
if (fd == -1)
return 0;
- /* If pread64 is available, use it. It's faster if the kernel
+ /* If pread64 or pwrite64 is available, use it. It's faster if the kernel
supports it (only one syscall), and it's 64-bit safe even on
32-bit platforms (for instance, SPARC debugging a SPARC64
application). */
+ if ((readbuf != NULL
+#ifdef HAVE_PREAD64
+ && (pread64 (fd, readbuf, len, offset) != len)
+#else
+ && (lseek (fd, offset, SEEK_SET) == -1 || read (fd, readbuf, len) != len)
+#endif
+ )
+ || (writebuf != NULL
#ifdef HAVE_PREAD64
- if (pread64 (fd, readbuf, len, offset) != len)
+ && (pwrite64 (fd, writebuf, len, offset) != len)
#else
- if (lseek (fd, offset, SEEK_SET) == -1 || read (fd, readbuf, len) != len)
+ && (lseek (fd, offset, SEEK_SET) == -1
+ || write (fd, writebuf, len) != len)
#endif
+ ))
ret = 0;
else
ret = len;
@@ -4759,13 +4765,24 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
offset &= ((ULONGEST) 1 << addr_bit) - 1;
}
- xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
- offset, len);
+ /* Use more expensive linux_proc_xfer_partial only for larger transfers. */
+ if (len >= 3 * sizeof (long))
+ {
+ xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
+ offset, len);
+ if (xfer != 0)
+ return xfer;
+ }
+
+ xfer = super_xfer_partial (ops, object, annex, readbuf, writebuf,
+ offset, len);
if (xfer != 0)
return xfer;
- return super_xfer_partial (ops, object, annex, readbuf, writebuf,
- offset, len);
+ /* PTRACE_* of super_xfer_partial may not work if the inferior is running.
+ linux_proc_xfer_partial still may work in such case. */
+ return linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
+ offset, len);
}
static void
diff --git a/gdb/testsuite/gdb.base/async-breakpoint.c b/gdb/testsuite/gdb.base/async-breakpoint.c
new file mode 100644
index 0000000..3cdb0c1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/async-breakpoint.c
@@ -0,0 +1,37 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012 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 volatile v;
+
+static int
+func (void)
+{
+ return ++v;
+}
+
+static volatile int stopme;
+
+int
+main (void)
+{
+ int timeout = 60 * 10;
+
+ while (!stopme && timeout-- > 0)
+ usleep (1000000 / 10);
+
+ return func ();
+}
diff --git a/gdb/testsuite/gdb.base/async-breakpoint.exp b/gdb/testsuite/gdb.base/async-breakpoint.exp
new file mode 100644
index 0000000..d2469cf
--- /dev/null
+++ b/gdb/testsuite/gdb.base/async-breakpoint.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 2012 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/>.
+
+set testfile async-breakpoint
+
+# Required for non-stop.
+if ![support_displaced_stepping] {
+ unsupported "displaced stepping"
+ return -1
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile}] } {
+ return -1
+}
+
+gdb_test_no_output "set target-async on"
+
+# Required for remote targets due to:
+# Cannot execute this command while the target is running.
+# Required also for local mode as GDB does not insert breakpoints otherwise.
+gdb_test_no_output "set non-stop on"
+
+if ![runto_main] then {
+ return 0
+}
+
+delete_breakpoints
+
+gdb_breakpoint "main"
+
+gdb_test "continue &" {Continuing\.}
+
+# FAIL was: warning: Error removing breakpoint 1
+gdb_test_no_output {delete $bpnum}
+
+# FAIL was: Cannot access memory at address 0x40057c
+gdb_breakpoint "func"
+
+set test "set variable stopme=1"
+gdb_test_multiple $test $test {
+ -re "$gdb_prompt " {
+ exp_continue
+ }
+ -re "Breakpoint \[0-9\]+, func \\(\\) at " {
+ pass $test
+ }
+}
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
index ee66e48..557e86d 100644
--- a/gdb/testsuite/lib/gdbserver-support.exp
+++ b/gdb/testsuite/lib/gdbserver-support.exp
@@ -47,6 +47,9 @@
proc gdb_target_cmd { targetname serialport } {
global gdb_prompt
+ # Do not use ending anchor for "$gdb_prompt $" as in async mode we may get
+ # also notification of the stopped target.
+
set serialport_re [string_to_regexp $serialport]
for {set i 1} {$i <= 3} {incr i} {
send_gdb "target $targetname $serialport\n"
@@ -58,26 +61,26 @@ proc gdb_target_cmd { targetname serialport } {
-re "unknown host.*$gdb_prompt" {
verbose "Couldn't look up $serialport"
}
- -re "Couldn't establish connection to remote.*$gdb_prompt $" {
+ -re "Couldn't establish connection to remote.*$gdb_prompt " {
verbose "Connection failed"
}
-re "Remote MIPS debugging.*$gdb_prompt" {
verbose "Set target to $targetname"
return 0
}
- -re "Remote debugging using .*$serialport_re.*$gdb_prompt $" {
+ -re "Remote debugging using .*$serialport_re.*$gdb_prompt " {
verbose "Set target to $targetname"
return 0
}
- -re "Remote debugging using stdio.*$gdb_prompt $" {
+ -re "Remote debugging using stdio.*$gdb_prompt " {
verbose "Set target to $targetname"
return 0
}
- -re "Remote target $targetname connected to.*$gdb_prompt $" {
+ -re "Remote target $targetname connected to.*$gdb_prompt " {
verbose "Set target to $targetname"
return 0
}
- -re "Connected to.*$gdb_prompt $" {
+ -re "Connected to.*$gdb_prompt " {
verbose "Set target to $targetname"
return 0
}