Support disconnected tracing.
authorStan Shebs <shebs@codesourcery.com>
Wed, 6 Jan 2010 20:31:28 +0000 (20:31 +0000)
committerStan Shebs <shebs@codesourcery.com>
Wed, 6 Jan 2010 20:31:28 +0000 (20:31 +0000)
* 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.

gdb/ChangeLog
gdb/NEWS
gdb/breakpoint.c
gdb/breakpoint.h
gdb/cli/cli-cmds.c
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/infcmd.c
gdb/remote.c
gdb/tracepoint.c

index 3f12d0538387014d6f540855ae01ed97387a777d..b1dbb373835e9871903979fe999e2fe018303e5f 100644 (file)
@@ -1,3 +1,35 @@
+2010-01-06  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.
+
 2010-01-06  Tristan Gingold  <gingold@adacore.com>
 
        * symtab.c (lookup_global_symbol_from_objfile): Rename objfile
index 544a1aa510d07123efb1a2f122647806cc9ecab0..1f322b33611355e4ece06d45408e173cc42509fb 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -24,7 +24,11 @@ Renesas RX                   rx
   lists inferiors that are not running yet or that have exited
   already.  See also "New commands" and "New options" below.
 
-* Trace state variables
+* 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
@@ -37,7 +41,7 @@ Renesas RX                    rx
   command to create, and "info tvariables" to view; see "Trace State
   Variables" in the manual for more detail.
 
-* Fast tracepoints
+  ** Fast tracepoints
 
   GDB now includes an option for defining fast tracepoints, which
   targets may implement more efficiently, such as by installing a jump
@@ -49,6 +53,14 @@ Renesas RX                   rx
   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
@@ -130,6 +142,12 @@ show default-collect
    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
@@ -138,6 +156,12 @@ QTDV
 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 813080a7097eb18f8b3de4445f6edb4ff355dea0..0dc84747844e88465148bc940fb747f02a88d286 100644 (file)
@@ -9847,6 +9847,27 @@ ftrace_command (char *arg, int from_tty)
   set_tracepoint_count (breakpoint_count);
 }
 
+extern void create_tracepoint_from_upload (int num, enum bptype type,
+                                          ULONGEST addr);
+
+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.  */
 
@@ -9997,6 +10018,22 @@ get_tracepoint (int num)
   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 01fc0e96691fd013ec7b7c7ddae61cb6e6ecdf7b..6b373a3592cfe0ac4a7fca19948a032023ef40e9 100644 (file)
@@ -513,6 +513,9 @@ struct breakpoint
 
     /* 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;
@@ -985,6 +988,8 @@ extern void make_breakpoint_silent (struct breakpoint *);
 /* 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 33f8d4b70943f74fb5bd5e4cb972880ea1527976..483389848d86534ce4ab131bebebbfb06e9e45ee 100644 (file)
@@ -37,6 +37,7 @@
 #include "objfiles.h"
 #include "source.h"
 #include "disasm.h"
+extern void disconnect_or_stop_tracing (int from_tty);
 
 #include "ui-out.h"
 
@@ -317,6 +318,9 @@ quit_command (char *args, int from_tty)
 {
   if (!quit_confirm ())
     error (_("Not confirmed."));
+
+  disconnect_or_stop_tracing (from_tty);
+
   quit_force (args, from_tty);
 }
 
index 48d187bb02142f86371db9e8553fa9e09aeda2bb..0de9f247af26eb2cccd5d8d3354bae3e68edb500 100644 (file)
@@ -1,3 +1,9 @@
+2010-01-06  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Starting and Stopping Trace Experiments): Document
+       disconnected tracing.
+       (Tracepoint Packets): Document new protocol.
+
 2010-01-05  Stan Shebs  <stan@codesourcery.com>
 
        * gdb.texinfo (Create and Delete Tracepoints): Describe fast
index d23c67519c6cab8eeed8895e1d3e49b327ac92df..5b78f50722027d8dae4a19afefbe903db8d624ad 100644 (file)
@@ -9781,6 +9781,47 @@ Enter actions for tracepoint #1, one per line.
 (@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
@@ -29721,7 +29762,10 @@ encoded).  @value{GDBN} will continue to supply the values of symbols
 (if available), until the target ceases to request them.
 @end table
 
-@item QTDP
+@item QTDisconnected
+@itemx QTDP
+@itemx QTDV
+@itemx QTfP
 @itemx QTFrame
 @xref{Tracepoint Packets}.
 
@@ -29750,11 +29794,13 @@ the command by a @samp{,}, not a @samp{:}, contrary to the naming
 conventions above.  Please don't use this packet as a model for new
 packets.)
 
-@item QTStart    
+@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}
@@ -30152,6 +30198,12 @@ containing program code.  Since these areas never change, they should
 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.
 
@@ -30184,6 +30236,14 @@ if the user is examining a trace frame in which the requested variable
 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 4c4781f5ee594ae69ad7fa6dbe4f82d1221fec65..821ae5fb37b432238e5f461e2ff3191528564277 100644 (file)
@@ -55,6 +55,8 @@
 #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);
@@ -2505,6 +2507,8 @@ detach_command (char *args, int from_tty)
   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 cba9f5b81e70269273e0c4be82dc272167360b51..262b97ffcd3bd434bfa658af801f7b51246efcfe 100644 (file)
@@ -202,6 +202,9 @@ static void show_remote_protocol_packet_cmd (struct ui_file *file,
 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);
@@ -301,6 +304,10 @@ struct remote_state
   /* 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;
@@ -2922,6 +2929,13 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
        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 ())
@@ -3149,6 +3163,15 @@ remote_fast_tracepoint_feature (const struct protocol_feature *feature,
   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,
@@ -3179,6 +3202,8 @@ static struct protocol_feature remote_protocol_features[] = {
     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,
@@ -9130,6 +9155,184 @@ remote_new_objfile (struct objfile *objfile)
     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 8ec81a3a1d2289819c9b5b31da72788ff4a37ffe..1726d5eeebef8750dd94861c677c48a255265eb7 100644 (file)
@@ -61,6 +61,8 @@ extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
 #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
@@ -144,6 +146,8 @@ static struct cmd_list_element *tfindlist;
 /* 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;
   
@@ -172,6 +176,8 @@ static struct cleanup *make_cleanup_free_actions (struct breakpoint *t);
 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" */
@@ -1627,7 +1633,7 @@ remote_set_transparent_ranges (void)
    to the target.  If no errors, 
    Tell target to start a new trace experiment.  */
 
-void download_tracepoint (struct breakpoint *t);
+int download_tracepoint (struct breakpoint *t);
 
 static void
 trace_start_command (char *args, int from_tty)
@@ -1637,6 +1643,7 @@ trace_start_command (char *args, int from_tty)
   int ix;
   struct breakpoint *t;
   struct trace_state_variable *tsv;
+  int any_downloaded = 0;
 
   dont_repeat ();      /* Like "run", dangerous to repeat accidentally.  */
 
@@ -1650,10 +1657,19 @@ trace_start_command (char *args, int from_tty)
       tp_vec = all_tracepoints ();
       for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
        {
-         download_tracepoint (t);
+         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)
@@ -1686,9 +1702,10 @@ trace_start_command (char *args, int from_tty)
     error (_("Trace can only be run on remote targets."));
 }
 
-/* Send the definition of a single tracepoint to the target.  */
+/* Send the definition of a single tracepoint to the target.  Return 1
+   if successful, 0 if not.  */
 
-void
+int
 download_tracepoint (struct breakpoint *t)
 {
   CORE_ADDR tpaddr;
@@ -1759,7 +1776,7 @@ download_tracepoint (struct breakpoint *t)
     error (_("Target does not support tracepoints."));
 
   if (!t->actions && !*default_collect)
-    return;
+    return 1;
 
   encode_actions (t, &tdp_actions, &stepping_actions);
   old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
@@ -1802,6 +1819,7 @@ download_tracepoint (struct breakpoint *t)
        }
     }
   do_cleanups (old_chain);
+  return 1;
 }
 
 /* tstop command */
@@ -1810,11 +1828,7 @@ trace_stop_command (char *args, int from_tty)
 {
   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;
+      stop_tracing ();
       if (deprecated_trace_start_stop_hook)
        deprecated_trace_start_stop_hook (0, from_tty);
     }
@@ -1822,26 +1836,48 @@ trace_stop_command (char *args, int from_tty)
     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 ())
     {
-      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');
+      get_trace_status ();
 
       if (trace_running_p)
-       printf_filtered (_("Trace is running on the target.\n"));
+       {
+         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"));
 
@@ -1856,6 +1892,24 @@ trace_status_command (char *args, int from_tty)
     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,
@@ -1865,6 +1919,7 @@ finish_tfind_command (char **msg,
   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 ());
 
@@ -1926,10 +1981,12 @@ finish_tfind_command (char **msg,
        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 (target_tracept);
+  set_tracepoint_num (tp ? tp->number : target_tracept);
   if (target_frameno == -1)
     set_traceframe_context (NULL);
   else
@@ -2064,6 +2121,7 @@ static void
 trace_find_tracepoint_command (char *args, int from_tty)
 {
   int tdp;
+  struct breakpoint *tp;
 
   if (target_is_remote ())
     {
@@ -2080,6 +2138,13 @@ trace_find_tracepoint_command (char *args, int from_tty)
       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);
     }
@@ -2550,6 +2615,32 @@ trace_dump_command (char *args, int from_tty)
   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
@@ -2581,7 +2672,6 @@ get_traceframe_number (void)
   return traceframe_number;
 }
 
-
 /* module initialization */
 void
 _initialize_tracepoint (void)
@@ -2747,6 +2837,18 @@ Show the list of expressions to collect by default"), NULL,
                          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);
 }