Move the traceframe_available_memory code from memory_xfer_partial_1 down to the...
[deliverable/binutils-gdb.git] / gdb / remote.c
index e03d3bf988a01e8308c09e9c128a4cc4a49506cb..dcee6e1a4f48940aacb0716ef874440af2eaea7e 100644 (file)
@@ -6824,6 +6824,87 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ULONGEST len,
                                 packet_format[0], 1);
 }
 
+/* Read memory from the live target, even if currently inspecting a
+   traceframe.  The return is the same as that of target_read.  */
+
+static enum target_xfer_status
+target_read_live_memory (enum target_object object,
+                        ULONGEST memaddr, gdb_byte *myaddr, ULONGEST len,
+                        ULONGEST *xfered_len)
+{
+  enum target_xfer_status ret;
+  struct cleanup *cleanup;
+
+  /* Switch momentarily out of tfind mode so to access live memory.
+     Note that this must not clear global state, such as the frame
+     cache, which must still remain valid for the previous traceframe.
+     We may be _building_ the frame cache at this point.  */
+  cleanup = make_cleanup_restore_traceframe_number ();
+  set_traceframe_number (-1);
+
+  ret = target_xfer_partial (current_target.beneath, object, NULL,
+                            myaddr, NULL, memaddr, len, xfered_len);
+
+  do_cleanups (cleanup);
+  return ret;
+}
+
+/* Using the set of read-only target sections of OPS, read live
+   read-only memory.  Note that the actual reads start from the
+   top-most target again.
+
+   For interface/parameters/return description see target.h,
+   to_xfer_partial.  */
+
+static enum target_xfer_status
+memory_xfer_live_readonly_partial (struct target_ops *ops,
+                                  enum target_object object,
+                                  gdb_byte *readbuf, ULONGEST memaddr,
+                                  ULONGEST len, ULONGEST *xfered_len)
+{
+  struct target_section *secp;
+  struct target_section_table *table;
+
+  secp = target_section_by_addr (ops, memaddr);
+  if (secp != NULL
+      && (bfd_get_section_flags (secp->the_bfd_section->owner,
+                                secp->the_bfd_section)
+         & SEC_READONLY))
+    {
+      struct target_section *p;
+      ULONGEST memend = memaddr + len;
+
+      table = target_get_section_table (ops);
+
+      for (p = table->sections; p < table->sections_end; p++)
+       {
+         if (memaddr >= p->addr)
+           {
+             if (memend <= p->endaddr)
+               {
+                 /* Entire transfer is within this section.  */
+                 return target_read_live_memory (object, memaddr,
+                                                 readbuf, len, xfered_len);
+               }
+             else if (memaddr >= p->endaddr)
+               {
+                 /* This section ends before the transfer starts.  */
+                 continue;
+               }
+             else
+               {
+                 /* This section overlaps the transfer.  Just do half.  */
+                 len = p->endaddr - memaddr;
+                 return target_read_live_memory (object, memaddr,
+                                                 readbuf, len, xfered_len);
+               }
+           }
+       }
+    }
+
+  return TARGET_XFER_EOF;
+}
+
 /* Read memory data directly from the remote machine.
    This does not use the data cache; the data cache uses this.
    MEMADDR is the address in the remote memory space.
@@ -6835,8 +6916,8 @@ remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ULONGEST len,
    transferred in *XFERED_LEN.  */
 
 static enum target_xfer_status
-remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, ULONGEST len,
-                  ULONGEST *xfered_len)
+remote_read_bytes (struct target_ops *ops, CORE_ADDR memaddr,
+                  gdb_byte *myaddr, ULONGEST len, ULONGEST *xfered_len)
 {
   struct remote_state *rs = get_remote_state ();
   int max_buf_size;            /* Max size of packet output buffer.  */
@@ -6847,6 +6928,63 @@ remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, ULONGEST len,
   if (len == 0)
     return 0;
 
+  if (get_traceframe_number () != -1)
+    {
+      VEC(mem_range_s) *available;
+
+      /* If we fail to get the set of available memory, then the
+        target does not support querying traceframe info, and so we
+        attempt reading from the traceframe anyway (assuming the
+        target implements the old QTro packet then).  */
+      if (traceframe_available_memory (&available, memaddr, len))
+       {
+         struct cleanup *old_chain;
+
+         old_chain = make_cleanup (VEC_cleanup(mem_range_s), &available);
+
+         if (VEC_empty (mem_range_s, available)
+             || VEC_index (mem_range_s, available, 0)->start != memaddr)
+           {
+             enum target_xfer_status res;
+
+             /* Don't read into the traceframe's available
+                memory.  */
+             if (!VEC_empty (mem_range_s, available))
+               {
+                 LONGEST oldlen = len;
+
+                 len = VEC_index (mem_range_s, available, 0)->start - memaddr;
+                 gdb_assert (len <= oldlen);
+               }
+
+             do_cleanups (old_chain);
+
+             /* This goes through the topmost target again.  */
+             res = memory_xfer_live_readonly_partial (ops,
+                                                      TARGET_OBJECT_MEMORY,
+                                                      myaddr, memaddr,
+                                                      len, xfered_len);
+             if (res == TARGET_XFER_OK)
+               return TARGET_XFER_OK;
+             else
+               {
+                 /* No use trying further, we know some memory starting
+                    at MEMADDR isn't available.  */
+                 *xfered_len = len;
+                 return TARGET_XFER_UNAVAILABLE;
+               }
+           }
+
+         /* Don't try to read more than how much is available, in
+            case the target implements the deprecated QTro packet to
+            cater for older GDBs (the target's knowledge of read-only
+            sections may be outdated by now).  */
+         len = VEC_index (mem_range_s, available, 0)->length;
+
+         do_cleanups (old_chain);
+       }
+    }
+
   max_buf_size = get_memory_read_packet_size ();
   /* The packet buffer will be large enough for the payload;
      get_memory_packet_size ensures this.  */
@@ -8698,7 +8836,7 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
       if (writebuf != NULL)
        return remote_write_bytes (offset, writebuf, len, xfered_len);
       else
-       return remote_read_bytes (offset, readbuf, len, xfered_len);
+       return remote_read_bytes (ops, offset, readbuf, len, xfered_len);
     }
 
   /* Handle SPU memory using qxfer packets.  */
This page took 0.025339 seconds and 4 git commands to generate.