This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Disconnected tracing


This next patch realizes a long-anticipated advantage of tracepoints, namely that it should be possible to disconnect GDB from the target but leave the trace experiment running, then reconnect later to see if anything interesting turned up. While conceptually simple, there are a couple wrinkles; we need to tell the target what to do if GDB goes away without warning, and we also have to decide what should happen when we reconnect and find that the target's list of tracepoints is different from GDB's list.

The first is easily handled with a new boolean setshow, disconnected-tracing. The second is much more complicated, and basically requires uploading tracepoints from the target, and keeping track of tracepoint numbers that differ between host and target. I need to beg a little indulgence for this right now, because the code in this patch is very lame, and a later patch does it right; but that version depends heavily on the upcoming target vector changes. (In fact, the big target vector change will be my very next patch!)

Stan

2010-01-05 Stan Shebs <stan@codesourcery.com>

   Support disconnected tracing.
   * infcmd.c (detach_command): Ask whether to stop tracing.
   * cli/cli-cmds.c (quit_command): Ditto.
   * breakpoint.h (struct breakpoint): New field number_on_target.
   * breakpoint.c (create_tracepoint_from_upload): New function.
   (get_tracepoint_by_number_on_target): New function.
   * remote.c (struct remote): New field disconnected_tracing.
   (remote_disconnected_tracing_feature): New function.
   (remote_protocol_features): Add DisconnectedTracing.
   (struct uploaded_tp): New struct.
   (uploaded_tps): New global.
   (get_uploaded_tp): New function.
   (find_matching_tracepoint): New function.
   (remote_get_tracing_state): New function.
   (remote_start_remote): Call it.
   * tracepoint.c (disconnected_tracing): New global.
   (trace_start_command): Initialize number_on_target.
   (stop_tracing): New function, split out from...
   (trace_stop_command): Call stop_tracing.
   (get_trace_status): New function, split out from...
   (trace_status_command): Call get_trace_status, add info on
   disconnection behavior.
   (disconnect_or_stop_tracing): New function.
   (finish_tfind_command): Translate from number on target.
   (trace_find_tracepoint_command): Translate to number on target.
   (send_disconnected_tracing_value): New function.
   (set_disconnected_tracing): New function.
   (_initialize_tracepoint): Add disconnected-tracing variable.
   * NEWS: Mention disconnected tracing.

   * gdb.texinfo (Starting and Stopping Trace Experiments): Document
   disconnected tracing.
   (Tracepoint Packets): Document new protocol.

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.345
diff -p -r1.345 NEWS
*** NEWS	6 Jan 2010 04:20:26 -0000	1.345
--- NEWS	6 Jan 2010 04:55:19 -0000
*************** Renesas RX			rx
*** 24,30 ****
    lists inferiors that are not running yet or that have exited
    already.  See also "New commands" and "New options" below.
  
! * Trace state variables
  
    GDB tracepoints now include support for trace state variables, which
    are variables managed by the target agent during a tracing
--- 24,34 ----
    lists inferiors that are not running yet or that have exited
    already.  See also "New commands" and "New options" below.
  
! * New tracing features
! 
!   GDB's tracepoint facility now includes several new features:
! 
!   ** Trace state variables
  
    GDB tracepoints now include support for trace state variables, which
    are variables managed by the target agent during a tracing
*************** Renesas RX			rx
*** 37,43 ****
    command to create, and "info tvariables" to view; see "Trace State
    Variables" in the manual for more detail.
  
! * Fast tracepoints
  
    GDB now includes an option for defining fast tracepoints, which
    targets may implement more efficiently, such as by installing a jump
--- 41,47 ----
    command to create, and "info tvariables" to view; see "Trace State
    Variables" in the manual for more detail.
  
!   ** Fast tracepoints
  
    GDB now includes an option for defining fast tracepoints, which
    targets may implement more efficiently, such as by installing a jump
*************** Renesas RX			rx
*** 49,54 ****
--- 53,66 ----
    fast tracepoint, use the "ftrace" command, with syntax identical to
    the regular trace command.
  
+   ** Disconnected tracing
+ 
+   It is now possible to detach GDB from the target while it is running
+   a trace experiment, then reconnect later to see how the experiment
+   is going.  In addition, a new variable disconnected-tracing lets you
+   tell the target agent whether to continue running a trace if the
+   connection is lost unexpectedly.
+ 
  * Changed commands
  
  disassemble
*************** show default-collect
*** 130,135 ****
--- 142,153 ----
     This is a useful way to ensure essential items are not overlooked,
     such as registers or a critical global variable.
  
+ set disconnected-tracing
+ show disconnected-tracing
+    If set to 1, the target is instructed to continue tracing if it
+    loses its connection to GDB.  If 0, the target is to stop tracing
+    upon disconnection.
+ 
  * New remote packets
  
  QTDV
*************** QTDV
*** 138,143 ****
--- 156,167 ----
  qTV
     Get the current value of a trace state variable.
  
+ QTDisconnected
+    Set desired tracing behavior upon disconnection.
+ 
+ qTfP, qTsP
+    Get data about the tracepoints currently in use.
+ 
  * Bug fixes
  
  Process record now works correctly with hardware watchpoints.
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.106
diff -p -r1.106 breakpoint.h
*** breakpoint.h	6 Jan 2010 04:20:26 -0000	1.106
--- breakpoint.h	6 Jan 2010 04:55:19 -0000
*************** struct breakpoint
*** 513,518 ****
--- 513,521 ----
  
      /* Chain of action lines to execute when this tracepoint is hit.  */
      struct action_line *actions;
+ 
+     /* The number of the tracepoint on the target.  */
+     int number_on_target;
    };
  
  typedef struct breakpoint *breakpoint_p;
*************** extern void make_breakpoint_silent (stru
*** 985,990 ****
--- 988,995 ----
  /* Return a tracepoint with the given number if found.  */
  extern struct breakpoint *get_tracepoint (int num);
  
+ extern struct breakpoint *get_tracepoint_by_number_on_target (int num);
+ 
  /* Find a tracepoint by parsing a number in the supplied string.  */
  extern struct breakpoint *get_tracepoint_by_number (char **arg, int multi_p,
  						    int optional_p);
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.447
diff -p -r1.447 breakpoint.c
*** breakpoint.c	6 Jan 2010 04:20:26 -0000	1.447
--- breakpoint.c	6 Jan 2010 04:55:19 -0000
*************** ftrace_command (char *arg, int from_tty)
*** 9847,9852 ****
--- 9847,9873 ----
    set_tracepoint_count (breakpoint_count);
  }
  
+ extern void create_tracepoint_from_upload (int num, enum bptype type,
+ 					   ULONGEST addr);
+ 
+ extern void
+ create_tracepoint_from_upload (int num, enum bptype type, ULONGEST addr)
+ {
+   char buf[100];
+   struct breakpoint *tp;
+ 
+   sprintf (buf, "*0x%s", paddress (get_current_arch (), addr));
+   if (type == bp_fast_tracepoint)
+     ftrace_command (buf, 0);
+   else
+     trace_command (buf, 0);
+ 
+   /* Record that this tracepoint is numbered differently on host and
+      target.  */
+   tp = get_tracepoint (tracepoint_count);
+   tp->number_on_target = num;
+ }
+ 
  /* Print information on tracepoint number TPNUM_EXP, or all if
     omitted.  */
  
*************** get_tracepoint (int num)
*** 9997,10002 ****
--- 10018,10039 ----
    return NULL;
  }
  
+ /* Find the tracepoint with the given target-side number (which may be
+    different from the tracepoint number after disconnecting and
+    reconnecting).  */
+ 
+ struct breakpoint *
+ get_tracepoint_by_number_on_target (int num)
+ {
+   struct breakpoint *t;
+ 
+   ALL_TRACEPOINTS (t)
+     if (t->number_on_target == num)
+       return t;
+ 
+   return NULL;
+ }
+ 
  /* Utility: parse a tracepoint number and look it up in the list.
     If MULTI_P is true, there might be a range of tracepoints in ARG.
     if OPTIONAL_P is true, then if the argument is missing, the most
Index: infcmd.c
===================================================================
RCS file: /cvs/src/src/gdb/infcmd.c,v
retrieving revision 1.255
diff -p -r1.255 infcmd.c
*** infcmd.c	1 Jan 2010 07:31:36 -0000	1.255
--- infcmd.c	6 Jan 2010 04:55:19 -0000
***************
*** 55,60 ****
--- 55,62 ----
  #include "valprint.h"
  #include "inline-frame.h"
  
+ extern void disconnect_or_stop_tracing (int from_tty);
+ 
  /* Functions exported for general use, in inferior.h: */
  
  void all_registers_info (char *, int);
*************** detach_command (char *args, int from_tty
*** 2505,2510 ****
--- 2507,2514 ----
    if (ptid_equal (inferior_ptid, null_ptid))
      error (_("The program is not being run."));
  
+   disconnect_or_stop_tracing (from_tty);
+ 
    target_detach (args, from_tty);
  
    /* If the solist is global across inferiors, don't clear it when we
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.377
diff -p -r1.377 remote.c
*** remote.c	6 Jan 2010 04:20:26 -0000	1.377
--- remote.c	6 Jan 2010 04:55:19 -0000
*************** static void show_remote_protocol_packet_
*** 202,207 ****
--- 202,210 ----
  static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
  static ptid_t read_ptid (char *buf, char **obuf);
  
+ struct remote_state;
+ static void remote_get_tracing_state (struct remote_state *);
+ 
  static void remote_query_supported (void);
  
  static void remote_check_symbols (struct objfile *objfile);
*************** struct remote_state
*** 301,306 ****
--- 304,313 ----
    /* True if the stub reports support for fast tracepoints.  */
    int fast_tracepoints;
  
+   /* True if the stub can continue running a trace while GDB is
+      disconnected.  */
+   int disconnected_tracing;
+ 
    /* Nonzero if the user has pressed Ctrl-C, but the target hasn't
       responded to that.  */
    int ctrlc_pending_p;
*************** remote_start_remote (struct ui_out *uiou
*** 2922,2927 ****
--- 2929,2941 ----
  	remote_check_symbols (symfile_objfile);
      }
  
+   /* Possibly the target has been engaged in a trace run started
+      previously; find out where things are at.  */
+   if (rs->disconnected_tracing)
+     {
+       remote_get_tracing_state (rs);
+     }
+ 
    /* If breakpoints are global, insert them now.  */
    if (gdbarch_has_global_breakpoints (target_gdbarch)
        && breakpoints_always_inserted_mode ())
*************** remote_fast_tracepoint_feature (const st
*** 3149,3154 ****
--- 3163,3177 ----
    rs->fast_tracepoints = (support == PACKET_ENABLE);
  }
  
+ static void
+ remote_disconnected_tracing_feature (const struct protocol_feature *feature,
+ 				     enum packet_support support,
+ 				     const char *value)
+ {
+   struct remote_state *rs = get_remote_state ();
+   rs->disconnected_tracing = (support == PACKET_ENABLE);
+ }
+ 
  static struct protocol_feature remote_protocol_features[] = {
    { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
    { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
*************** static struct protocol_feature remote_pr
*** 3179,3184 ****
--- 3202,3209 ----
      PACKET_ConditionalTracepoints },
    { "FastTracepoints", PACKET_DISABLE, remote_fast_tracepoint_feature,
      PACKET_FastTracepoints },
+   { "DisconnectedTracing", PACKET_DISABLE, remote_disconnected_tracing_feature,
+     -1 },
    { "ReverseContinue", PACKET_DISABLE, remote_supported_packet,
      PACKET_bc },
    { "ReverseStep", PACKET_DISABLE, remote_supported_packet,
*************** remote_new_objfile (struct objfile *objf
*** 9130,9135 ****
--- 9155,9338 ----
      remote_check_symbols (objfile);
  }
  
+ /* Struct to collect random info about tracepoints on the target.  */
+ 
+ struct uploaded_tp {
+   int number;
+   enum bptype type;
+   ULONGEST addr;
+   int enabled;
+   int step;
+   int pass;
+   int orig_size;
+   char *cond;
+   int cond_len;
+   struct uploaded_tp *next;
+ };
+ 
+ struct uploaded_tp *uploaded_tps;
+ 
+ struct uploaded_tp *
+ get_uploaded_tp (int num)
+ {
+   struct uploaded_tp *utp;
+ 
+   for (utp = uploaded_tps; utp; utp = utp->next)
+     if (utp->number == num)
+       return utp;
+   utp = (struct uploaded_tp *) xmalloc (sizeof (struct uploaded_tp));
+   utp->number = num;
+   utp->next = uploaded_tps;
+   uploaded_tps = utp;
+   return utp;
+ }
+ 
+ /* Look for an existing tracepoint that seems similar enough to the
+    uploaded one.  Enablement isn't checked, because the user can
+    toggle that freely, and may have done so in anticipation of the
+    next trace run.  */
+ 
+ struct breakpoint *
+ find_matching_tracepoint (struct uploaded_tp *utp)
+ {
+   VEC(breakpoint_p) *tp_vec = all_tracepoints ();
+   int ix;
+   struct breakpoint *t;
+ 
+   for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+     {
+       if (t->type == utp->type
+ 	  && (t->loc && t->loc->address == utp->addr)
+ 	  && t->step_count == utp->step
+ 	  && t->pass_count == utp->pass
+ 	  /* FIXME also test conditionals and actions */
+ 	  )
+ 	return t;
+     }
+   return NULL;
+ }
+ 
+ /* Find out everything we can about the trace run that was already
+    happening on the target.  This includes both running/stopped, and
+    the tracepoints that were in use.  */
+ 
+ static void
+ remote_get_tracing_state (struct remote_state *rs)
+ {
+   char *p;
+   ULONGEST num, addr, step, pass, orig_size, xlen;
+   int enabled, i;
+   enum bptype type;
+   char *cond;
+   struct uploaded_tp *utp;
+   struct breakpoint *t;
+   extern void get_trace_status ();
+   extern unsigned long trace_running_p;
+ 
+   get_trace_status ();
+   if (trace_running_p)
+     printf_filtered (_("Trace is running on the target.\n"));
+ 
+   putpkt ("qTfP");
+   getpkt (&rs->buf, &rs->buf_size, 0);
+   p = rs->buf;
+   while (*p != '\0')
+     {
+       if (*p == 'T')
+ 	{
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &num);
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &addr);
+ 	  p++;
+ 	  enabled = (*p++ == 'E');
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &step);
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &pass);
+ 	  p++;
+ 	  type = bp_tracepoint;
+ 	  cond = NULL;
+ 	  while (*p)
+ 	    {
+ 	      if (*p == 'F')
+ 		{
+ 		  type = bp_fast_tracepoint;
+ 		  p++;
+ 		  p = unpack_varlen_hex (p, &orig_size);
+ 		}
+ 	      else if (*p == 'X')
+ 		{
+ 		  p++;
+ 		  p = unpack_varlen_hex (p, &xlen);
+ 		  p++;  /* skip the comma */
+ 		  cond = (char *) xmalloc (xlen);
+ 		  hex2bin (p, cond, xlen);
+ 		  p += 2 * xlen;
+ 		}
+ 	      else
+ 		/* Silently skip over anything else.  */
+ 		p++;
+ 	    }
+ 	  utp = get_uploaded_tp (num);
+ 	  utp->type = type;
+ 	  utp->addr = addr;
+ 	  utp->enabled = enabled;
+ 	  utp->step = step;
+ 	  utp->pass = pass;
+ 	  utp->cond = cond;
+ 	  utp->cond_len = xlen;
+ 	}
+       else if (*p == 'A')
+ 	{
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &num);
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &addr);
+ 	  p++;
+ 	  utp = get_uploaded_tp (num);
+ 	  /* FIXME save the action */
+ 	}
+       else if (*p == 'S')
+ 	{
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &num);
+ 	  p++;
+ 	  p = unpack_varlen_hex (p, &addr);
+ 	  p++;
+ 	  utp = get_uploaded_tp (num);
+ 	  /* FIXME save the action */
+ 	}
+       else if (*p == 'l')
+ 	{
+ 	  /* No more tracepoint info, get out of the loop.  */
+ 	  break;
+ 	}
+       putpkt ("qTsP");
+       getpkt (&rs->buf, &rs->buf_size, 0);
+       p = rs->buf;
+     }
+   /* Got all the tracepoint info, now look for matches among what we
+      already have in GDB.  */
+   for (utp = uploaded_tps; utp; utp = utp->next)
+     {
+       t = find_matching_tracepoint (utp);
+       if (t)
+ 	{
+ 	  printf_filtered (_("Assuming tracepoint %d is same as target's tracepoint %d.\n"),
+ 			   t->number, utp->number);
+ 	  t->number_on_target = utp->number;
+ 	}
+       else
+ 	{
+ 	  extern void create_tracepoint_from_upload (int num, ULONGEST addr);
+ 	  create_tracepoint_from_upload (utp->number, utp->addr);
+ 	}
+     }
+   /* FIXME free all the space */
+   uploaded_tps = NULL;
+ }
+ 
  void
  _initialize_remote (void)
  {
Index: tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.135
diff -p -r1.135 tracepoint.c
*** tracepoint.c	6 Jan 2010 04:20:26 -0000	1.135
--- tracepoint.c	6 Jan 2010 04:55:19 -0000
*************** extern char *unpack_varlen_hex (char *bu
*** 61,66 ****
--- 61,68 ----
  #include <unistd.h>
  #endif
  
+ extern void stop_tracing ();
+ 
  /* Maximum length of an agent aexpression.
     This accounts for the fact that packets are limited to 400 bytes
     (which includes everything -- including the checksum), and assumes
*************** static struct cmd_list_element *tfindlis
*** 144,149 ****
--- 146,153 ----
  /* List of expressions to collect by default at each tracepoint hit.  */
  static char *default_collect = "";
  
+ static int disconnected_tracing;
+ 
  static char *target_buf;
  static long target_buf_size;
    
*************** static struct cleanup *make_cleanup_free
*** 172,177 ****
--- 176,183 ----
  static void free_actions_list (char **actions_list);
  static void free_actions_list_cleanup_wrapper (void *);
  
+ extern void send_disconnected_tracing_value (int value);
+ 
  extern void _initialize_tracepoint (void);
  
  /* Utility: returns true if "target remote" */
*************** remote_set_transparent_ranges (void)
*** 1627,1633 ****
     to the target.  If no errors, 
     Tell target to start a new trace experiment.  */
  
! void download_tracepoint (struct breakpoint *t);
  
  static void
  trace_start_command (char *args, int from_tty)
--- 1633,1639 ----
     to the target.  If no errors, 
     Tell target to start a new trace experiment.  */
  
! int download_tracepoint (struct breakpoint *t);
  
  static void
  trace_start_command (char *args, int from_tty)
*************** trace_start_command (char *args, int fro
*** 1637,1642 ****
--- 1643,1649 ----
    int ix;
    struct breakpoint *t;
    struct trace_state_variable *tsv;
+   int any_downloaded = 0;
  
    dont_repeat ();	/* Like "run", dangerous to repeat accidentally.  */
  
*************** trace_start_command (char *args, int fro
*** 1650,1659 ****
        tp_vec = all_tracepoints ();
        for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
  	{
! 	  download_tracepoint (t);
  	}
        VEC_free (breakpoint_p, tp_vec);
  
        /* Init any trace state variables that start with nonzero values.  */
  
        for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
--- 1657,1675 ----
        tp_vec = all_tracepoints ();
        for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
  	{
! 	  t->number_on_target = 0;
! 	  if (download_tracepoint (t))
! 	    {
! 	      t->number_on_target = t->number;
! 	      any_downloaded = 1;
! 	    }
  	}
        VEC_free (breakpoint_p, tp_vec);
  
+       /* No point in tracing without any tracepoints... */
+       if (!any_downloaded)
+ 	error ("No tracepoints downloaded, not starting trace");
+ 
        /* Init any trace state variables that start with nonzero values.  */
  
        for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
*************** trace_start_command (char *args, int fro
*** 1686,1694 ****
      error (_("Trace can only be run on remote targets."));
  }
  
! /* Send the definition of a single tracepoint to the target.  */
  
! void
  download_tracepoint (struct breakpoint *t)
  {
    CORE_ADDR tpaddr;
--- 1702,1711 ----
      error (_("Trace can only be run on remote targets."));
  }
  
! /* Send the definition of a single tracepoint to the target.  Return 1
!    if successful, 0 if not.  */
  
! int
  download_tracepoint (struct breakpoint *t)
  {
    CORE_ADDR tpaddr;
*************** download_tracepoint (struct breakpoint *
*** 1759,1765 ****
      error (_("Target does not support tracepoints."));
  
    if (!t->actions && !*default_collect)
!     return;
  
    encode_actions (t, &tdp_actions, &stepping_actions);
    old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
--- 1776,1782 ----
      error (_("Target does not support tracepoints."));
  
    if (!t->actions && !*default_collect)
!     return 1;
  
    encode_actions (t, &tdp_actions, &stepping_actions);
    old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
*************** download_tracepoint (struct breakpoint *
*** 1802,1807 ****
--- 1819,1825 ----
  	}
      }
    do_cleanups (old_chain);
+   return 1;
  }
  
  /* tstop command */
*************** trace_stop_command (char *args, int from
*** 1810,1820 ****
  {
    if (target_is_remote ())
      {
!       putpkt ("QTStop");
!       remote_get_noisy_reply (&target_buf, &target_buf_size);
!       if (strcmp (target_buf, "OK"))
! 	error (_("Bogus reply from target: %s"), target_buf);
!       trace_running_p = 0;
        if (deprecated_trace_start_stop_hook)
  	deprecated_trace_start_stop_hook (0, from_tty);
      }
--- 1828,1834 ----
  {
    if (target_is_remote ())
      {
!       stop_tracing ();
        if (deprecated_trace_start_stop_hook)
  	deprecated_trace_start_stop_hook (0, from_tty);
      }
*************** trace_stop_command (char *args, int from
*** 1822,1847 ****
      error (_("Trace can only be run on remote targets."));
  }
  
  unsigned long trace_running_p;
  
  /* tstatus command */
  static void
  trace_status_command (char *args, int from_tty)
  {
    if (target_is_remote ())
      {
!       putpkt ("qTStatus");
!       remote_get_noisy_reply (&target_buf, &target_buf_size);
! 
!       if (target_buf[0] != 'T' ||
! 	  (target_buf[1] != '0' && target_buf[1] != '1'))
! 	error (_("Bogus reply from target: %s"), target_buf);
! 
!       /* exported for use by the GUI */
!       trace_running_p = (target_buf[1] == '1');
  
        if (trace_running_p)
! 	printf_filtered (_("Trace is running on the target.\n"));
        else
  	printf_filtered (_("Trace is not running on the target.\n"));
  
--- 1836,1883 ----
      error (_("Trace can only be run on remote targets."));
  }
  
+ void
+ stop_tracing ()
+ {
+   putpkt ("QTStop");
+   remote_get_noisy_reply (&target_buf, &target_buf_size);
+   if (strcmp (target_buf, "OK"))
+     error (_("Bogus reply from target: %s"), target_buf);
+   trace_running_p = 0;
+ }
+ 
  unsigned long trace_running_p;
  
+ void
+ get_trace_status ()
+ {
+   putpkt ("qTStatus");
+   remote_get_noisy_reply (&target_buf, &target_buf_size);
+ 
+   if (target_buf[0] != 'T' ||
+       (target_buf[1] != '0' && target_buf[1] != '1'))
+     error (_("Bogus trace status reply from target: %s"), target_buf);
+ 
+   /* exported for use by the GUI */
+   trace_running_p = (target_buf[1] == '1');
+ }
+ 
  /* tstatus command */
  static void
  trace_status_command (char *args, int from_tty)
  {
    if (target_is_remote ())
      {
!       get_trace_status ();
  
        if (trace_running_p)
! 	{
! 	  printf_filtered (_("Trace is running on the target.\n"));
! 	  if (disconnected_tracing)
! 	    printf_filtered (_("Trace will continue if GDB disconnects.\n"));
! 	  else
! 	    printf_filtered (_("Trace will stop if GDB disconnects.\n"));
! 	}
        else
  	printf_filtered (_("Trace is not running on the target.\n"));
  
*************** trace_status_command (char *args, int fr
*** 1856,1861 ****
--- 1892,1915 ----
      error (_("Trace can only be run on remote targets."));
  }
  
+ void
+ disconnect_or_stop_tracing (int from_tty)
+ {
+   if (trace_running_p && from_tty)
+     {
+       int cont = query (_("Trace is running.  Continue tracing after detach? "));
+       /* Note that we send the query result without affecting the
+ 	 user's setting of disconnected_tracing, so that the answer is
+ 	 a one-time-only.  */
+       send_disconnected_tracing_value (cont);
+ 
+       /* Also ensure that we do the equivalent of a tstop command if
+ 	 tracing is not to continue after the detach.  */
+       if (!cont)
+ 	stop_tracing ();
+     }
+ }
+ 
  /* Worker function for the various flavors of the tfind command.  */
  static void
  finish_tfind_command (char **msg,
*************** finish_tfind_command (char **msg,
*** 1865,1870 ****
--- 1919,1925 ----
    int target_frameno = -1, target_tracept = -1;
    struct frame_id old_frame_id;
    char *reply;
+   struct breakpoint *tp;
  
    old_frame_id = get_frame_id (get_current_frame ());
  
*************** finish_tfind_command (char **msg,
*** 1926,1935 ****
  	error (_("Bogus reply from target: %s"), reply);
        }
  
    reinit_frame_cache ();
    registers_changed ();
    set_traceframe_num (target_frameno);
!   set_tracepoint_num (target_tracept);
    if (target_frameno == -1)
      set_traceframe_context (NULL);
    else
--- 1981,1992 ----
  	error (_("Bogus reply from target: %s"), reply);
        }
  
+   tp = get_tracepoint_by_number_on_target (target_tracept);
+ 
    reinit_frame_cache ();
    registers_changed ();
    set_traceframe_num (target_frameno);
!   set_tracepoint_num (tp ? tp->number : target_tracept);
    if (target_frameno == -1)
      set_traceframe_context (NULL);
    else
*************** static void
*** 2064,2069 ****
--- 2121,2127 ----
  trace_find_tracepoint_command (char *args, int from_tty)
  {
    int tdp;
+   struct breakpoint *tp;
  
    if (target_is_remote ())
      {
*************** trace_find_tracepoint_command (char *arg
*** 2080,2085 ****
--- 2138,2150 ----
        else
  	tdp = parse_and_eval_long (args);
  
+       /* If we have the tracepoint on hand, use the number that the
+ 	 target knows about (which may be different if we disconnected
+ 	 and reconnected).  */
+       tp = get_tracepoint (tdp);
+       if (tp)
+ 	tdp = tp->number_on_target;
+ 
        sprintf (target_buf, "QTFrame:tdp:%x", tdp);
        finish_tfind_command (&target_buf, &target_buf_size, from_tty);
      }
*************** trace_dump_command (char *args, int from
*** 2550,2555 ****
--- 2615,2646 ----
    discard_cleanups (old_cleanups);
  }
  
+ /* Tell the target what to do with an ongoing tracing run if GDB
+    disconnects for some reason.  */
+ 
+ void
+ send_disconnected_tracing_value (int value)
+ {
+   char buf[30];
+ 
+   /* No need to do anything special if target not active.  */
+   if (!target_is_remote ())
+     return;
+ 
+   sprintf (buf, "QTDisconnected:%x", value);
+   putpkt (buf);
+   remote_get_noisy_reply (&target_buf, &target_buf_size);
+   if (strcmp (target_buf, "OK"))
+     error (_("Target does not support this command."));
+ }
+ 
+ static void
+ set_disconnected_tracing (char *args, int from_tty,
+ 			  struct cmd_list_element *c)
+ {
+   send_disconnected_tracing_value (disconnected_tracing);
+ }
+ 
  /* Convert the memory pointed to by mem into hex, placing result in buf.
   * Return a pointer to the last char put in buf (null)
   * "stolen" from sparc-stub.c
*************** get_traceframe_number (void)
*** 2581,2587 ****
    return traceframe_number;
  }
  
- 
  /* module initialization */
  void
  _initialize_tracepoint (void)
--- 2672,2677 ----
*************** Show the list of expressions to collect 
*** 2747,2752 ****
--- 2837,2854 ----
  			  NULL, NULL,
  			  &setlist, &showlist);
  
+   add_setshow_boolean_cmd ("disconnected-tracing", no_class,
+ 			   &disconnected_tracing, _("\
+ Set whether tracing continues after GDB disconnects."), _("\
+ Show whether tracing continues after GDB disconnects."), _("\
+ Use this to continue a tracing run even if GDB disconnects\n\
+ or detaches from the target.  You can reconnect later and look at\n\
+ trace data collected in the meantime."),
+ 			   set_disconnected_tracing,
+ 			   NULL,
+ 			   &setlist,
+ 			   &showlist);
+ 
    target_buf_size = 2048;
    target_buf = xmalloc (target_buf_size);
  }
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.655
diff -p -r1.655 gdb.texinfo
*** doc/gdb.texinfo	6 Jan 2010 04:20:27 -0000	1.655
--- doc/gdb.texinfo	6 Jan 2010 04:55:20 -0000
*************** Enter actions for tracepoint #1, one per
*** 9781,9786 ****
--- 9781,9827 ----
  (@value{GDBP}) @b{tstop}
  @end smallexample
  
+ @cindex disconnected tracing
+ You can choose to continue running the trace experiment even if
+ @value{GDBN} disconnects from the target, voluntarily or
+ involuntarily.  For commands such as @code{detach}, the debugger will
+ ask what you want to do with the trace. But for unexpected
+ terminations (@value{GDBN} crash, network outage), it would be
+ unfortunate to lose hard-won trace data, so the variable
+ @code{disconnected-tracing} lets you decide whether the trace should
+ continue running without @value{GDBN}.
+ 
+ @table @code
+ @item set disconnected-tracing on
+ @itemx set disconnected-tracing off
+ @kindex set disconnected-tracing
+ Choose whether a tracing run should continue to run if @value{GDBN}
+ has disconnected from the target.  Note that @code{detach} or
+ @code{quit} will ask you directly what to do about a running trace no
+ matter what this variable's setting, so the variable is mainly useful
+ for handling unexpected situations, such as loss of the network.
+ 
+ @item show disconnected-tracing
+ @kindex show disconnected-tracing
+ Show the current choice for disconnected tracing.
+ 
+ @end table
+ 
+ When you reconnect to the target, the trace experiment may or may not
+ still be running; it might have filled the trace buffer in the
+ meantime, or stopped for one of the other reasons.  If it is running,
+ it will continue after reconnection.
+ 
+ Upon reconnection, the target will upload information about the
+ tracepoints in effect.  @value{GDBN} will then compare that
+ information to the set of tracepoints currently defined, and attempt
+ to match them up, allowing for the possibility that the numbers may
+ have changed due to creation and deletion in the meantime.  If one of
+ the target's tracepoints does not match any in @value{GDBN}, the
+ debugger will create a new tracepoint, so that you have a number with
+ which to specify that tracepoint.  This matching-up process is
+ necessarily heuristic, and it may result in useless tracepoints being
+ created; you may simply delete them if they are of no use.
  
  @node Analyze Collected Data
  @section Using the Collected Data
*************** encoded).  @value{GDBN} will continue to
*** 29721,29727 ****
  (if available), until the target ceases to request them.
  @end table
  
! @item QTDP
  @itemx QTFrame
  @xref{Tracepoint Packets}.
  
--- 29762,29771 ----
  (if available), until the target ceases to request them.
  @end table
  
! @item QTDisconnected
! @itemx QTDP
! @itemx QTDV
! @itemx QTfP
  @itemx QTFrame
  @xref{Tracepoint Packets}.
  
*************** the command by a @samp{,}, not a @samp{:
*** 29750,29760 ****
  conventions above.  Please don't use this packet as a model for new
  packets.)
  
! @item QTStart    
  @itemx QTStop     
  @itemx QTinit     
  @itemx QTro       
  @itemx qTStatus   
  @xref{Tracepoint Packets}.
  
  @item qXfer:@var{object}:read:@var{annex}:@var{offset},@var{length}
--- 29794,29806 ----
  conventions above.  Please don't use this packet as a model for new
  packets.)
  
! @item QTsP
! @itemx QTStart    
  @itemx QTStop     
  @itemx QTinit     
  @itemx QTro       
  @itemx qTStatus   
+ @itemx qTV
  @xref{Tracepoint Packets}.
  
  @item qXfer:@var{object}:read:@var{annex}:@var{offset},@var{length}
*************** containing program code.  Since these ar
*** 30152,30157 ****
--- 30198,30209 ----
  still have the same contents they did when the tracepoint was hit, so
  there's no reason for the stub to refuse to provide their contents.
  
+ @item QTDisconnected:@var{value}
+ Set the choice to what to do with the tracing run when @value{GDBN}
+ disconnects from the target.  A @var{value} of 1 directs the target to
+ continue the tracing run, while 0 tells the target to stop tracing if
+ @value{GDBN} is no longer in the picture.
+ 
  @item qTStatus
  Ask the stub if there is a trace experiment running right now.
  
*************** if the user is examining a trace frame i
*** 30184,30189 ****
--- 30236,30249 ----
  was not collected.
  @end table
  
+ @item qTfP
+ @itemx qTsP
+ These packets request data about tracepoints that are being used by
+ the target.  @value{GDBN} sends @code{qTfP} to get the first piece
+ of data, and multiple @code{qTsP} to get additional pieces.  Replies
+ to these packets generally take the form of the @code{QTDP} packets
+ that define tracepoints. (FIXME add detailed syntax)
+ 
  @end table
  
  @node Host I/O Packets
Index: cli/cli-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v
retrieving revision 1.95
diff -p -r1.95 cli-cmds.c
*** cli/cli-cmds.c	1 Jan 2010 07:31:46 -0000	1.95
--- cli/cli-cmds.c	6 Jan 2010 04:55:20 -0000
***************
*** 37,42 ****
--- 37,43 ----
  #include "objfiles.h"
  #include "source.h"
  #include "disasm.h"
+ extern void disconnect_or_stop_tracing (int from_tty);
  
  #include "ui-out.h"
  
*************** quit_command (char *args, int from_tty)
*** 317,322 ****
--- 318,326 ----
  {
    if (!quit_confirm ())
      error (_("Not confirmed."));
+ 
+   disconnect_or_stop_tracing (from_tty);
+ 
    quit_force (args, from_tty);
  }
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]