[gdbserver/lynx] spurious failure to write in inferior memory
authorJoel Brobecker <brobecker@adacore.com>
Fri, 19 Sep 2014 22:00:07 +0000 (18:00 -0400)
committerJoel Brobecker <brobecker@adacore.com>
Mon, 17 Nov 2014 03:23:27 +0000 (07:23 +0400)
We noticed the following error on ppc-lynx178, using just about
any program:

        (gdb) tar remote mytarget:4444
        Remote debugging using mytarget:4444
        0x000100c8 in _start ()
        (gdb) b try
        Breakpoint 1 at 0x10844: file try.adb, line 11.
        (gdb) cont
        Continuing.
 !!!->  Cannot remove breakpoints because program is no longer writable.
 !!!->  Further execution is probably impossible.

        Breakpoint 1, try () at try.adb:11
        11          Local : Integer := 18;

And, of course, trying to continue yielded the expected outcome:

       (gdb) c
       Continuing.
       warning: Error removing breakpoint 1
       Cannot remove breakpoints because program is no longer writable.
       Further execution is probably impossible.

It turns out that the problem is caused by an intentional test
against a variable with an undefined value. After GDB receives
notification of the inferior stopping, it tries to remove the
breakpoint by sending a memory-write packet ("X10844,4:9 ").
This leads us to lynx_write_memory, where it tries to split
the memory-write into chunks of 4 bytes. And, in order to handle
writes which are not aligned on word boundaries, we have the
following code:

      if (skip > 0 || truncate > 0)
        /* We need to read the memory at this address in order to preserve
           the data that we are not overwriting.  */
        lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
        if (errno)
          return errno;

(the comment explains what the code is about).

Unfortunately, the not-so-glaring error that we've made here is
that we're checking ERRNO regardless of whether we've called
lynx_read_memory. In our case, because we are writing 4 bytes
aligned on a word boundary, we do not call lynx_read_memory and
therefore test an ERRNO with an undefined value.

gdb/gdbserver/ChangeLog:

        * lynx-low.c (lynx_write_memory): Put lynx_read_memory and
        corresponding ERRNO check in same block.

gdb/gdbserver/ChangeLog
gdb/gdbserver/lynx-low.c

index 5a42642..0c25069 100644 (file)
@@ -1,3 +1,8 @@
+2014-11-17  Joel Brobecker  <brobecker@adacore.com>
+
+       * lynx-low.c (lynx_write_memory): Put lynx_read_memory and
+       corresponding ERRNO check in same block.
+
 2014-11-12  Pedro Alves  <palves@redhat.com>
 
        * server.c (cont_thread): Update comment.
index 96dea03..6178e03 100644 (file)
@@ -688,11 +688,13 @@ lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
       if (addr + xfer_size > memaddr + len)
         truncate = addr + xfer_size - memaddr - len;
       if (skip > 0 || truncate > 0)
-        /* We need to read the memory at this address in order to preserve
-           the data that we are not overwriting.  */
-        lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
-        if (errno)
-          return errno;
+       {
+         /* We need to read the memory at this address in order to preserve
+            the data that we are not overwriting.  */
+         lynx_read_memory (addr, (unsigned char *) &buf, xfer_size);
+         if (errno)
+           return errno;
+       }
       memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip,
               xfer_size - skip - truncate);
       errno = 0;