]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2011-12-06 Pedro Alves <pedro@codesourcery.com>
authorPedro Alves <palves@redhat.com>
Tue, 6 Dec 2011 20:03:14 +0000 (20:03 +0000)
committerPedro Alves <palves@redhat.com>
Tue, 6 Dec 2011 20:03:14 +0000 (20:03 +0000)
gdb/
* breakpoint.c (breakpoint_restore_shadows): Rename to ...
(breakpoint_xfer_memory): ... this.  Change prototype.  Handle
memory writes too.
* breakpoint.h (breakpoint_restore_shadows): Delete.
(breakpoint_xfer_memory): Declare.
* mem-break.c (default_memory_insert_breakpoint)
(default_memory_remove_breakpoint): Use target_write_raw_memory.
(memory_xfer_partial): Rename to ...
(memory_xfer_partial_1): ... this.  Don't mask out breakpoints
here.
(memory_xfer_partial): New.
(target_write_raw_memory): New.
* target.h (target_write_raw_memory): New.

gdb/testsuite/
* gdb.base/break-always.exp: Test changing memory at addresses
with breakpoints inserted.

gdb/ChangeLog
gdb/breakpoint.c
gdb/breakpoint.h
gdb/mem-break.c
gdb/target.c
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/break-always.exp

index ffecf05594fdf819f89dff562f67ff9921b85c8c..cd9507a37d6fe379815dd75d1c2ca8ebffff5ed3 100644 (file)
@@ -1,3 +1,19 @@
+2011-12-06  Pedro Alves  <pedro@codesourcery.com>
+
+       * breakpoint.c (breakpoint_restore_shadows): Rename to ...
+       (breakpoint_xfer_memory): ... this.  Change prototype.  Handle
+       memory writes too.
+       * breakpoint.h (breakpoint_restore_shadows): Delete.
+       (breakpoint_xfer_memory): Declare.
+       * mem-break.c (default_memory_insert_breakpoint)
+       (default_memory_remove_breakpoint): Use target_write_raw_memory.
+       (memory_xfer_partial): Rename to ...
+       (memory_xfer_partial_1): ... this.  Don't mask out breakpoints
+       here.
+       (memory_xfer_partial): New.
+       (target_write_raw_memory): New.
+       * target.h (target_write_raw_memory): New.
+
 2011-12-06  Doug Evans  <dje@google.com>
 
        * linespec.c (decode_dollar): Avoid "may be used uninitialized" warning.
index bd0a0e329548714e801e6c9b66de11f1e4259517..d9d5bbe5928d427b59c5f24a4608cf63606eca85 100644 (file)
@@ -1049,7 +1049,9 @@ bp_location_has_shadow (struct bp_location *bl)
      bl->address + bp_location_shadow_len_after_address_max <= memaddr  */
 
 void
-breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, LONGEST len)
+breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
+                       const gdb_byte *writebuf_org,
+                       ULONGEST memaddr, LONGEST len)
 {
   /* Left boundary, right boundary and median element of our binary
      search.  */
@@ -1161,8 +1163,32 @@ breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, LONGEST len)
        bp_size -= (bp_addr + bp_size) - (memaddr + len);
       }
 
-    memcpy (buf + bp_addr - memaddr,
-           bl->target_info.shadow_contents + bptoffset, bp_size);
+    if (readbuf != NULL)
+      {
+       /* Update the read buffer with this inserted breakpoint's
+          shadow.  */
+       memcpy (readbuf + bp_addr - memaddr,
+               bl->target_info.shadow_contents + bptoffset, bp_size);
+      }
+    else
+      {
+       struct gdbarch *gdbarch = bl->gdbarch;
+       const unsigned char *bp;
+       CORE_ADDR placed_address = bl->target_info.placed_address;
+       unsigned placed_size = bl->target_info.placed_size;
+
+       /* Update the shadow with what we want to write to memory.  */
+       memcpy (bl->target_info.shadow_contents + bptoffset,
+               writebuf_org + bp_addr - memaddr, bp_size);
+
+       /* Determine appropriate breakpoint contents and size for this
+          address.  */
+       bp = gdbarch_breakpoint_from_pc (gdbarch, &placed_address, &placed_size);
+
+       /* Update the final write buffer with this inserted
+          breakpoint's INSN.  */
+       memcpy (writebuf + bp_addr - memaddr, bp + bptoffset, bp_size);
+      }
   }
 }
 \f
index ead3930e18f2f797853a30fa3ba53f3ecc03cacc..ddf1881011d15f0e0f0f9e4d5561882bd716c80e 100644 (file)
@@ -1296,10 +1296,17 @@ extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *);
    target.  */
 int watchpoints_triggered (struct target_waitstatus *);
 
-/* Update BUF, which is LEN bytes read from the target address MEMADDR,
-   by replacing any memory breakpoints with their shadowed contents.  */
-void breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, 
-                                LONGEST len);
+/* Helper for transparent breakpoint hiding for memory read and write
+   routines.
+
+   Update one of READBUF or WRITEBUF with either the shadows
+   (READBUF), or the breakpoint instructions (WRITEBUF) of inserted
+   breakpoints at the memory range defined by MEMADDR and extending
+   for LEN bytes.  If writing, then WRITEBUF is a copy of WRITEBUF_ORG
+   on entry.*/
+extern void breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
+                                   const gdb_byte *writebuf_org,
+                                   ULONGEST memaddr, LONGEST len);
 
 extern int breakpoints_always_inserted_mode (void);
 
index ba7dc242e5ea3dd56c10e3c1b66e1a245e945d9f..31ca45cdf696c49ae59391402f49b53aa411d2c5 100644 (file)
@@ -60,8 +60,8 @@ default_memory_insert_breakpoint (struct gdbarch *gdbarch,
 
   /* Write the breakpoint.  */
   if (val == 0)
-    val = target_write_memory (bp_tgt->placed_address, bp,
-                              bp_tgt->placed_size);
+    val = target_write_raw_memory (bp_tgt->placed_address, bp,
+                                  bp_tgt->placed_size);
 
   return val;
 }
@@ -71,8 +71,8 @@ int
 default_memory_remove_breakpoint (struct gdbarch *gdbarch,
                                  struct bp_target_info *bp_tgt)
 {
-  return target_write_memory (bp_tgt->placed_address, bp_tgt->shadow_contents,
-                             bp_tgt->placed_size);
+  return target_write_raw_memory (bp_tgt->placed_address, bp_tgt->shadow_contents,
+                                 bp_tgt->placed_size);
 }
 
 
index 6358b00f487e80f71ba7a9c1f8928d9516c8700a..5700066415fdfd986c7ac3a16429eb85b34e55fa 100644 (file)
@@ -1388,19 +1388,15 @@ memory_xfer_live_readonly_partial (struct target_ops *ops,
    For docs see target.h, to_xfer_partial.  */
 
 static LONGEST
-memory_xfer_partial (struct target_ops *ops, enum target_object object,
-                    void *readbuf, const void *writebuf, ULONGEST memaddr,
-                    LONGEST len)
+memory_xfer_partial_1 (struct target_ops *ops, enum target_object object,
+                      void *readbuf, const void *writebuf, ULONGEST memaddr,
+                      LONGEST len)
 {
   LONGEST res;
   int reg_len;
   struct mem_region *region;
   struct inferior *inf;
 
-  /* Zero length requests are ok and require no work.  */
-  if (len == 0)
-    return 0;
-
   /* For accesses to unmapped overlay sections, read directly from
      files.  Must do this first, as MEMADDR may need adjustment.  */
   if (readbuf != NULL && overlay_debugging)
@@ -1551,11 +1547,7 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
       if (res <= 0)
        return -1;
       else
-       {
-         if (readbuf && !show_memory_breakpoints)
-           breakpoint_restore_shadows (readbuf, memaddr, reg_len);
-         return res;
-       }
+       return res;
     }
 
   /* If none of those methods found the memory we wanted, fall back
@@ -1584,9 +1576,6 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
     }
   while (ops != NULL);
 
-  if (res > 0 && readbuf != NULL && !show_memory_breakpoints)
-    breakpoint_restore_shadows (readbuf, memaddr, reg_len);
-
   /* Make sure the cache gets updated no matter what - if we are writing
      to the stack.  Even if this write is not tagged as such, we still need
      to update the cache.  */
@@ -1606,6 +1595,48 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
   return res;
 }
 
+/* Perform a partial memory transfer.  For docs see target.h,
+   to_xfer_partial.  */
+
+static LONGEST
+memory_xfer_partial (struct target_ops *ops, enum target_object object,
+                    void *readbuf, const void *writebuf, ULONGEST memaddr,
+                    LONGEST len)
+{
+  int res;
+
+  /* Zero length requests are ok and require no work.  */
+  if (len == 0)
+    return 0;
+
+  /* Fill in READBUF with breakpoint shadows, or WRITEBUF with
+     breakpoint insns, thus hiding out from higher layers whether
+     there are software breakpoints inserted in the code stream.  */
+  if (readbuf != NULL)
+    {
+      res = memory_xfer_partial_1 (ops, object, readbuf, NULL, memaddr, len);
+
+      if (res > 0 && !show_memory_breakpoints)
+       breakpoint_xfer_memory (readbuf, NULL, NULL, memaddr, res);
+    }
+  else
+    {
+      void *buf;
+      struct cleanup *old_chain;
+
+      buf = xmalloc (len);
+      old_chain = make_cleanup (xfree, buf);
+      memcpy (buf, writebuf, len);
+
+      breakpoint_xfer_memory (NULL, buf, writebuf, memaddr, len);
+      res = memory_xfer_partial_1 (ops, object, NULL, buf, memaddr, len);
+
+      do_cleanups (old_chain);
+    }
+
+  return res;
+}
+
 static void
 restore_show_memory_breakpoints (void *arg)
 {
@@ -1761,6 +1792,25 @@ target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
     return EIO;
 }
 
+/* Write LEN bytes from MYADDR to target raw memory at address
+   MEMADDR.  Returns either 0 for success or an errno value if any
+   error occurs.  If an error occurs, no guarantee is made about how
+   much data got written.  Callers that can deal with partial writes
+   should call target_write.  */
+
+int
+target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+{
+  /* Dispatch to the topmost target, not the flattened current_target.
+     Memory accesses check target->to_has_(all_)memory, and the
+     flattened target doesn't inherit those.  */
+  if (target_write (current_target.beneath, TARGET_OBJECT_RAW_MEMORY, NULL,
+                   myaddr, memaddr, len) == len)
+    return 0;
+  else
+    return EIO;
+}
+
 /* Fetch the target's memory map.  */
 
 VEC(mem_region_s) *
index 1261d90e060424a1e7b17bcdc6c9d88a74613d6d..fd488d66f3c18a79ce87b7485b74c8f9259e1877 100644 (file)
@@ -941,6 +941,9 @@ extern int target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len);
 extern int target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr,
                                int len);
 
+extern int target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr,
+                                   int len);
+
 /* Fetches the target's memory map.  If one is found it is sorted
    and returned, after some consistency checking.  Otherwise, NULL
    is returned.  */
index 7626a06fd1ceeeb2a1fed78490cd2dcf68e53d25..ca83855a32f7043af17d53133476c6abbe7b0fa3 100644 (file)
@@ -1,3 +1,8 @@
+2011-12-06  Pedro Alves  <pedro@codesourcery.com>
+
+       * gdb.base/break-always.exp: Test changing memory at addresses
+       with breakpoints inserted.
+
 2011-12-06  Joel Brobecker  <brobecker@acacore.com>
 
         * gdb.ada/fullname_bp.exp: Add tests for other valid linespecs
index ce76af7c06076e35c35cb4d3f835e3745b0e974e..e20794e99d73ad6eff8e535aed5757ddaf056ae3 100644 (file)
@@ -49,7 +49,42 @@ gdb_test_no_output "enable 2" "enable 2.H"
 gdb_test_no_output "disable 2" "disable 2.I"
 gdb_test "info breakpoints" "keep n.*keep n.*keep y.*keep n.*keep n.*" "before re-enable check breakpoint state"
 gdb_test_no_output "enable" "re-enable all breakpoints"
-gdb_continue_to_breakpoint "bar" ".*break-always.c:$bar_location.*"
 
+set bp_address 0
+set test "set breakpoint on bar 2"
+gdb_test_multiple "break bar" $test {
+    -re "Breakpoint 6 at ($hex).*$gdb_prompt $" {
+       set bp_address $expect_out(1,string)
+       pass $test
+    }
+}
+
+# Save the original INSN under the breakpoint.
+gdb_test "p /x \$shadow = *(char *) $bp_address" \
+    " = $hex" \
+    "save shadow"
 
+# Overwrite memory where the breakpoint is planted.  GDB should update
+# its memory breakpoint's shadows, to account for the new contents,
+# and still leave the breakpoint insn planted.  Try twice with
+# different values, in case we happen to be writting exactly what was
+# there already.
+gdb_test "p /x *(char *) $bp_address = 0" \
+    " = 0x0" \
+    "write 0 to breakpoint's address"
+gdb_test "p /x *(char *) $bp_address" \
+    " = 0x0" \
+    "read back 0 from the breakpoint's address"
 
+gdb_test "p /x *(char *) $bp_address = 1" \
+    " = 0x1" \
+    "write 1 to breakpoint's address"
+gdb_test "p /x *(char *) $bp_address" \
+    " = 0x1" \
+    "read back 1 from the breakpoint's address"
+
+# Restore the original contents.
+gdb_test "p /x *(char *) $bp_address = \$shadow" ""
+
+# Run to breakpoint.
+gdb_continue_to_breakpoint "bar" ".*break-always.c:$bar_location.*"