gdb/
authorPedro Alves <palves@redhat.com>
Mon, 14 Feb 2011 11:22:29 +0000 (11:22 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 14 Feb 2011 11:22:29 +0000 (11:22 +0000)
* target.c (target_read_live_memory): New function.
(memory_xfer_live_readonly_partial): New.
(memory_xfer_partial): If reading from a traceframe, fallback to
reading unavailable read-only memory from read-only regions of
live target memory.
* tracepoint.c (disconnect_tracing): Adjust.
(set_current_traceframe): New, factored out from
set_traceframe_number.
(set_traceframe_number): Reimplement to only change the traceframe
number on the GDB side.
(do_restore_current_traceframe_cleanup): Adjust.
(make_cleanup_restore_traceframe_number): New.
(cur_traceframe_number): New global.
(tfile_open): Set cur_traceframe_number to no traceframe.
(set_tfile_traceframe): New function.
(tfile_trace_find): If looking up a traceframe using any method
other than by number, make sure the current tfile traceframe
matches gdb's current traceframe.  Update the current tfile
traceframe if the lookup succeeded.
(tfile_fetch_registers, tfile_xfer_partial)
(tfile_get_trace_state_variable_value): Make sure the remote
traceframe matches gdb's current traceframe.
* remote.c (remote_traceframe_number): New global.
(remote_open_1): Set it to -1.
(set_remote_traceframe): New function.
(remote_fetch_registers, remote_store_registers)
(remote_xfer_memory, remote_xfer_partial)
(remote_get_trace_state_variable_value): Make sure the remote
traceframe matches gdb's current traceframe.
(remote_trace_find): If looking up a traceframe using any method
other than by number, make sure the current remote traceframe
matches gdb's current traceframe.  Update the current remote
traceframe if the lookup succeeded.
* infrun.c (fetch_inferior_event): Adjust.
* tracepoint.h (set_current_traceframe): Declare.
(get_traceframe_number, set_traceframe_number): Add describing
comments.

gdb/ChangeLog
gdb/infrun.c
gdb/remote.c
gdb/target.c
gdb/tracepoint.c
gdb/tracepoint.h

index 1fd5b02..4440c09 100644 (file)
@@ -1,5 +1,45 @@
 2011-02-14  Pedro Alves  <pedro@codesourcery.com>
 
+       * target.c (target_read_live_memory): New function.
+       (memory_xfer_live_readonly_partial): New.
+       (memory_xfer_partial): If reading from a traceframe, fallback to
+       reading unavailable read-only memory from read-only regions of
+       live target memory.
+       * tracepoint.c (disconnect_tracing): Adjust.
+       (set_current_traceframe): New, factored out from
+       set_traceframe_number.
+       (set_traceframe_number): Reimplement to only change the traceframe
+       number on the GDB side.
+       (do_restore_current_traceframe_cleanup): Adjust.
+       (make_cleanup_restore_traceframe_number): New.
+       (cur_traceframe_number): New global.
+       (tfile_open): Set cur_traceframe_number to no traceframe.
+       (set_tfile_traceframe): New function.
+       (tfile_trace_find): If looking up a traceframe using any method
+       other than by number, make sure the current tfile traceframe
+       matches gdb's current traceframe.  Update the current tfile
+       traceframe if the lookup succeeded.
+       (tfile_fetch_registers, tfile_xfer_partial)
+       (tfile_get_trace_state_variable_value): Make sure the remote
+       traceframe matches gdb's current traceframe.
+       * remote.c (remote_traceframe_number): New global.
+       (remote_open_1): Set it to -1.
+       (set_remote_traceframe): New function.
+       (remote_fetch_registers, remote_store_registers)
+       (remote_xfer_memory, remote_xfer_partial)
+       (remote_get_trace_state_variable_value): Make sure the remote
+       traceframe matches gdb's current traceframe.
+       (remote_trace_find): If looking up a traceframe using any method
+       other than by number, make sure the current remote traceframe
+       matches gdb's current traceframe.  Update the current remote
+       traceframe if the lookup succeeded.
+       * infrun.c (fetch_inferior_event): Adjust.
+       * tracepoint.h (set_current_traceframe): Declare.
+       (get_traceframe_number, set_traceframe_number): Add describing
+       comments.
+
+2011-02-14  Pedro Alves  <pedro@codesourcery.com>
+
        Mark pieces of values as unavailable if the corresponding memory
        is unavailable.
 
index c894b32..dd26af3 100644 (file)
@@ -2631,7 +2631,7 @@ fetch_inferior_event (void *client_data)
   if (non_stop)
     {
       make_cleanup_restore_current_traceframe ();
-      set_traceframe_number (-1);
+      set_current_traceframe (-1);
     }
 
   if (non_stop)
index da04932..c0fd9a7 100644 (file)
@@ -1353,6 +1353,10 @@ static ptid_t any_thread_ptid;
 static ptid_t general_thread;
 static ptid_t continue_thread;
 
+/* This the traceframe which we last selected on the remote system.
+   It will be -1 if no traceframe is selected.  */
+static int remote_traceframe_number = -1;
+
 /* Find out if the stub attached to PID (and hence GDB should offer to
    detach instead of killing it when bailing out).  */
 
@@ -4002,6 +4006,7 @@ remote_open_1 (char *name, int from_tty,
 
   general_thread = not_sent_ptid;
   continue_thread = not_sent_ptid;
+  remote_traceframe_number = -1;
 
   /* Probe for ability to use "ThreadInfo" query, as required.  */
   use_threadinfo_query = 1;
@@ -5770,6 +5775,28 @@ fetch_registers_using_g (struct regcache *regcache)
   process_g_packet (regcache);
 }
 
+/* Make the remote selected traceframe match GDB's selected
+   traceframe.  */
+
+static void
+set_remote_traceframe (void)
+{
+  int newnum;
+
+  if (remote_traceframe_number == get_traceframe_number ())
+    return;
+
+  /* Avoid recursion, remote_trace_find calls us again.  */
+  remote_traceframe_number = get_traceframe_number ();
+
+  newnum = target_trace_find (tfind_number,
+                             get_traceframe_number (), 0, 0, NULL);
+
+  /* Should not happen.  If it does, all bets are off.  */
+  if (newnum != get_traceframe_number ())
+    warning (_("could not set remote traceframe"));
+}
+
 static void
 remote_fetch_registers (struct target_ops *ops,
                        struct regcache *regcache, int regnum)
@@ -5777,6 +5804,7 @@ remote_fetch_registers (struct target_ops *ops,
   struct remote_arch_state *rsa = get_remote_arch_state ();
   int i;
 
+  set_remote_traceframe ();
   set_general_thread (inferior_ptid);
 
   if (regnum >= 0)
@@ -5934,6 +5962,7 @@ remote_store_registers (struct target_ops *ops,
   struct remote_arch_state *rsa = get_remote_arch_state ();
   int i;
 
+  set_remote_traceframe ();
   set_general_thread (inferior_ptid);
 
   if (regnum >= 0)
@@ -6502,6 +6531,7 @@ remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len,
 {
   int res;
 
+  set_remote_traceframe ();
   set_general_thread (inferior_ptid);
 
   if (should_write)
@@ -8084,6 +8114,7 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
   char *p2;
   char query_type;
 
+  set_remote_traceframe ();
   set_general_thread (inferior_ptid);
 
   rs = get_remote_state ();
@@ -9972,6 +10003,12 @@ remote_trace_find (enum trace_find_type type, int num,
   char *p, *reply;
   int target_frameno = -1, target_tracept = -1;
 
+  /* Lookups other than by absolute frame number depend on the current
+     trace selected, so make sure it is correct on the remote end
+     first.  */
+  if (type != tfind_number)
+    set_remote_traceframe ();
+
   p = rs->buf;
   strcpy (p, "QTFrame:");
   p = strchr (p, '\0');
@@ -10009,6 +10046,8 @@ remote_trace_find (enum trace_find_type type, int num,
        target_frameno = (int) strtol (p, &reply, 16);
        if (reply == p)
          error (_("Unable to parse trace frame number"));
+       /* Don't update our remote traceframe number cache on failure
+          to select a remote traceframe.  */
        if (target_frameno == -1)
          return -1;
        break;
@@ -10029,6 +10068,8 @@ remote_trace_find (enum trace_find_type type, int num,
       }
   if (tpp)
     *tpp = target_tracept;
+
+  remote_traceframe_number = target_frameno;
   return target_frameno;
 }
 
@@ -10039,6 +10080,8 @@ remote_get_trace_state_variable_value (int tsvnum, LONGEST *val)
   char *reply;
   ULONGEST uval;
 
+  set_remote_traceframe ();
+
   sprintf (rs->buf, "qTV:%x", tsvnum);
   putpkt (rs->buf);
   reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
index edf03f1..214edb7 100644 (file)
@@ -1271,6 +1271,82 @@ target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
   return NULL;
 }
 
+/* Read memory from the live target, even if currently inspecting a
+   traceframe.  The return is the same as that of target_read.  */
+
+static LONGEST
+target_read_live_memory (enum target_object object,
+                        ULONGEST memaddr, gdb_byte *myaddr, LONGEST len)
+{
+  int 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_read (current_target.beneath, object, NULL,
+                    myaddr, memaddr, 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.  */
+
+static LONGEST
+memory_xfer_live_readonly_partial (struct target_ops *ops,
+                                  enum target_object object,
+                                  gdb_byte *readbuf, ULONGEST memaddr,
+                                  LONGEST 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->bfd, 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);
+               }
+             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);
+               }
+           }
+       }
+    }
+
+  return 0;
+}
+
 /* Perform a partial memory transfer.
    For docs see target.h, to_xfer_partial.  */
 
@@ -1329,6 +1405,59 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object,
        }
     }
 
+  /* If reading unavailable memory in the context of traceframes, and
+     this address falls within a read-only section, fallback to
+     reading from live memory.  */
+  if (readbuf != NULL && 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)
+           {
+             /* 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, object,
+                                                      readbuf, memaddr, len);
+             if (res > 0)
+               return res;
+
+             /* No use trying further, we know some memory starting
+                at MEMADDR isn't available.  */
+             return -1;
+           }
+
+         /* 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);
+       }
+    }
+
   /* Try GDB's internal data cache.  */
   region = lookup_mem_region (memaddr);
   /* region->hi == 0 means there's no upper bound.  */
index 18f3c7f..498f47c 100644 (file)
@@ -1927,7 +1927,7 @@ disconnect_tracing (int from_tty)
      confusing upon reconnection.  Just use these calls instead of
      full tfind_1 behavior because we're in the middle of detaching,
      and there's no point to updating current stack frame etc.  */
-  set_traceframe_number (-1);
+  set_current_traceframe (-1);
   set_traceframe_context (NULL);
 }
 
@@ -2935,7 +2935,7 @@ get_traceframe_number (void)
    if NUM is already current.  */
 
 void
-set_traceframe_number (int num)
+set_current_traceframe (int num)
 {
   int newnum;
 
@@ -2959,6 +2959,15 @@ set_traceframe_number (int num)
   clear_traceframe_info ();
 }
 
+/* Make the traceframe NUM be the current trace frame, and do nothing
+   more.  */
+
+void
+set_traceframe_number (int num)
+{
+  traceframe_number = num;
+}
+
 /* A cleanup used when switching away and back from tfind mode.  */
 
 struct current_traceframe_cleanup
@@ -2972,7 +2981,7 @@ do_restore_current_traceframe_cleanup (void *arg)
 {
   struct current_traceframe_cleanup *old = arg;
 
-  set_traceframe_number (old->traceframe_number);
+  set_current_traceframe (old->traceframe_number);
 }
 
 static void
@@ -2995,6 +3004,12 @@ make_cleanup_restore_current_traceframe (void)
                            restore_current_traceframe_cleanup_dtor);
 }
 
+struct cleanup *
+make_cleanup_restore_traceframe_number (void)
+{
+  return make_cleanup_restore_integer (&traceframe_number);
+}
+
 /* Given a number and address, return an uploaded tracepoint with that
    number, creating if necessary.  */
 
@@ -3247,6 +3262,7 @@ char *trace_filename;
 int trace_fd = -1;
 off_t trace_frames_offset;
 off_t cur_offset;
+int cur_traceframe_number;
 int cur_data_size;
 int trace_regblock_size;
 
@@ -3338,6 +3354,8 @@ tfile_open (char *filename, int from_tty)
   ts->disconnected_tracing = 0;
   ts->circular_buffer = 0;
 
+  cur_traceframe_number = -1;
+
   /* Read through a section of newline-terminated lines that
      define things like tracepoints.  */
   i = 0;
@@ -3752,6 +3770,28 @@ tfile_get_traceframe_address (off_t tframe_offset)
   return addr;
 }
 
+/* Make tfile's selected traceframe match GDB's selected
+   traceframe.  */
+
+static void
+set_tfile_traceframe (void)
+{
+  int newnum;
+
+  if (cur_traceframe_number == get_traceframe_number ())
+    return;
+
+  /* Avoid recursion, tfile_trace_find calls us again.  */
+  cur_traceframe_number = get_traceframe_number ();
+
+  newnum = target_trace_find (tfind_number,
+                             get_traceframe_number (), 0, 0, NULL);
+
+  /* Should not happen.  If it does, all bets are off.  */
+  if (newnum != get_traceframe_number ())
+    warning (_("could not set tfile's traceframe"));
+}
+
 /* Given a type of search and some parameters, scan the collection of
    traceframes in the file looking for a match.  When found, return
    both the traceframe and tracepoint number, otherwise -1 for
@@ -3768,6 +3808,12 @@ tfile_trace_find (enum trace_find_type type, int num,
   off_t offset, tframe_offset;
   ULONGEST tfaddr;
 
+  /* Lookups other than by absolute frame number depend on the current
+     trace selected, so make sure it is correct on the tfile end
+     first.  */
+  if (type != tfind_number)
+    set_tfile_traceframe ();
+
   lseek (trace_fd, trace_frames_offset, SEEK_SET);
   offset = trace_frames_offset;
   while (1)
@@ -3820,6 +3866,7 @@ tfile_trace_find (enum trace_find_type type, int num,
            *tpp = tpnum;
          cur_offset = offset;
          cur_data_size = data_size;
+         cur_traceframe_number = tfnum;
          return tfnum;
        }
       /* Skip past the traceframe's data.  */
@@ -3936,6 +3983,8 @@ tfile_fetch_registers (struct target_ops *ops,
   if (!trace_regblock_size)
     return;
 
+  set_tfile_traceframe ();
+
   regs = alloca (trace_regblock_size);
 
   if (traceframe_find_block_type ('R', 0) >= 0)
@@ -4019,7 +4068,9 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
   if (readbuf == NULL)
     error (_("tfile_xfer_partial: trace file is read-only"));
 
-  if (traceframe_number != -1)
+  set_tfile_traceframe ();
+
+ if (traceframe_number != -1)
     {
       int pos = 0;
 
@@ -4102,6 +4153,8 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val)
 {
   int pos;
 
+  set_tfile_traceframe ();
+
   pos = 0;
   while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
     {
index ee15e94..b94537c 100644 (file)
@@ -192,9 +192,24 @@ extern void release_static_tracepoint_marker (struct static_tracepoint_marker *)
 extern void (*deprecated_trace_find_hook) (char *arg, int from_tty);
 extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
 
-int get_traceframe_number (void);
-void set_traceframe_number (int);
+/* Returns the current traceframe number.  */
+extern int get_traceframe_number (void);
+
+/* Make the traceframe NUM be the current GDB trace frame number, and
+   do nothing more.  In particular, this does not flush the
+   register/frame caches or notify the target about the trace frame
+   change, so that is can be used when we need to momentarily access
+   live memory.  Targets lazily switch their current traceframe to
+   match GDB's traceframe number, at the appropriate times.  */
+extern void set_traceframe_number (int);
+
+/* Make the traceframe NUM be the current trace frame, all the way to
+   the target, and flushes all global state (register/frame caches,
+   etc.).  */
+extern void set_current_traceframe (int num);
+
 struct cleanup *make_cleanup_restore_current_traceframe (void);
+struct cleanup *make_cleanup_restore_traceframe_number (void);
 
 void free_actions (struct breakpoint *);
 extern void validate_actionline (char **, struct breakpoint *);