Static tracepoints support, and UST integration.
[deliverable/binutils-gdb.git] / gdb / gdbserver / tracepoint.c
index dc71b205427a9da9291b3941eb0a35aa575100eb..c2d7da83937afac60caa2f2d183b9ebe7054c5b5 100644 (file)
@@ -132,6 +132,12 @@ trace_vdebug (const char *fmt, ...)
 # define traceframe_write_count gdb_agent_traceframe_write_count
 # define traceframes_created gdb_agent_traceframes_created
 # define trace_state_variables gdb_agent_trace_state_variables
+# define get_raw_reg gdb_agent_get_raw_reg
+# define get_trace_state_variable_value gdb_agent_get_trace_state_variable_value
+# define set_trace_state_variable_value gdb_agent_set_trace_state_variable_value
+# define ust_loaded gdb_agent_ust_loaded
+# define helper_thread_id gdb_agent_helper_thread_id
+# define cmd_buf gdb_agent_cmd_buf
 #endif
 
 #ifndef IN_PROCESS_AGENT
@@ -162,6 +168,12 @@ struct ipa_sym_addresses
   CORE_ADDR addr_traceframe_write_count;
   CORE_ADDR addr_traceframes_created;
   CORE_ADDR addr_trace_state_variables;
+  CORE_ADDR addr_get_raw_reg;
+  CORE_ADDR addr_get_trace_state_variable_value;
+  CORE_ADDR addr_set_trace_state_variable_value;
+  CORE_ADDR addr_ust_loaded;
+  CORE_ADDR addr_helper_thread_id;
+  CORE_ADDR addr_cmd_buf;
 };
 
 #define STRINGIZE_1(STR) #STR
@@ -200,6 +212,12 @@ static struct
   IPA_SYM(traceframe_write_count),
   IPA_SYM(traceframes_created),
   IPA_SYM(trace_state_variables),
+  IPA_SYM(get_raw_reg),
+  IPA_SYM(get_trace_state_variable_value),
+  IPA_SYM(set_trace_state_variable_value),
+  IPA_SYM(ust_loaded),
+  IPA_SYM(helper_thread_id),
+  IPA_SYM(cmd_buf),
 };
 
 struct ipa_sym_addresses ipa_sym_addrs;
@@ -214,14 +232,55 @@ in_process_agent_loaded (void)
 
 static int read_inferior_integer (CORE_ADDR symaddr, int *val);
 
+/* Returns true if both the in-process agent library and the static
+   tracepoints libraries are loaded in the inferior.  */
+
+static int
+in_process_agent_loaded_ust (void)
+{
+  int loaded = 0;
+
+  if (!in_process_agent_loaded ())
+    {
+      warning ("In-process agent not loaded");
+      return 0;
+    }
+
+  if (read_inferior_integer (ipa_sym_addrs.addr_ust_loaded, &loaded))
+    {
+      warning ("Error reading ust_loaded in lib");
+      return 0;
+    }
+
+  return loaded;
+}
+
 static void
 write_e_ipa_not_loaded (char *buffer)
 {
   sprintf (buffer,
           "E.In-process agent library not loaded in process.  "
-          "Dynamic tracepoints unavailable.");
+          "Fast and static tracepoints unavailable.");
+}
+
+/* Write an error to BUFFER indicating that UST isn't loaded in the
+   inferior.  */
+
+static void
+write_e_ust_not_loaded (char *buffer)
+{
+#ifdef HAVE_UST
+  sprintf (buffer,
+          "E.UST library not loaded in process.  "
+          "Static tracepoints unavailable.");
+#else
+  sprintf (buffer, "E.GDBserver was built without static tracepoints support");
+#endif
 }
 
+/* If the in-process agent library isn't loaded in the inferior, write
+   an error to BUFFER, and return 1.  Otherwise, return 0.  */
+
 static int
 maybe_write_ipa_not_loaded (char *buffer)
 {
@@ -233,6 +292,26 @@ maybe_write_ipa_not_loaded (char *buffer)
   return 0;
 }
 
+/* If the in-process agent library and the ust (static tracepoints)
+   library aren't loaded in the inferior, write an error to BUFFER,
+   and return 1.  Otherwise, return 0.  */
+
+static int
+maybe_write_ipa_ust_not_loaded (char *buffer)
+{
+  if (!in_process_agent_loaded ())
+    {
+      write_e_ipa_not_loaded (buffer);
+      return 1;
+    }
+  else if (!in_process_agent_loaded_ust ())
+    {
+      write_e_ust_not_loaded (buffer);
+      return 1;
+    }
+  return 0;
+}
+
 /* Cache all future symbols that the tracepoints module might request.
    We can not request symbols at arbitrary states in the remote
    protocol, only when the client tells us that new symbols are
@@ -338,6 +417,8 @@ static void download_tracepoints (void);
 static void download_trace_state_variables (void);
 static void upload_fast_traceframes (void);
 
+static int run_inferior_command (char *cmd);
+
 static int
 read_inferior_integer (CORE_ADDR symaddr, int *val)
 {
@@ -533,6 +614,12 @@ struct eval_expr_action
   struct agent_expr *expr;
 };
 
+/* An 'L' (collect static trace data) action.  */
+struct collect_static_trace_data_action
+{
+  struct tracepoint_action base;
+};
+
 /* This structure describes a piece of the source-level definition of
    the tracepoint.  The contents are not interpreted by the target,
    but preserved verbatim for uploading upon reconnection.  */
@@ -560,10 +647,17 @@ enum tracepoint_type
 
   /* A fast tracepoint implemented with a jump instead of a trap.  */
   fast_tracepoint,
+
+  /* A static tracepoint, implemented by a program call into a tracing
+     library.  */
+  static_tracepoint
 };
 
 struct tracepoint_hit_ctx;
 
+typedef enum eval_result_type (*condfn) (struct tracepoint_hit_ctx *,
+                                        ULONGEST *);
+
 /* The definition of a tracepoint.  */
 
 /* Tracepoints may have multiple locations, each at a different
@@ -612,6 +706,8 @@ struct tracepoint
      Note that while-stepping steps are not counted as "hits".  */
   long hit_count;
 
+  CORE_ADDR compiled_cond;
+
   /* Link to the next tracepoint in the list.  */
   struct tracepoint *next;
 
@@ -653,8 +749,8 @@ struct tracepoint
   char **step_actions_str;
 
   /* Handle returned by the breakpoint or tracepoint module when we
-     inserted the trap or jump.  NULL if we haven't inserted it
-     yet.  */
+     inserted the trap or jump, or hooked into a static tracepoint.
+     NULL if we haven't inserted it yet.  */
   void *handle;
 #endif
 
@@ -1143,6 +1239,35 @@ struct fast_tracepoint_ctx
   struct tracepoint *tpoint;
 };
 
+/* Static tracepoint specific data to be passed down to
+   collect_data_at_tracepoint.  */
+struct static_tracepoint_ctx
+{
+  struct tracepoint_hit_ctx base;
+
+  /* The regcache corresponding to the registers state at the time of
+     the tracepoint hit.  Initialized lazily, from REGS.  */
+  struct regcache regcache;
+  int regcache_initted;
+
+  /* The buffer space REGCACHE above uses.  We use a separate buffer
+     instead of letting the regcache malloc for both signal safety and
+     performance reasons; this is allocated on the stack instead.  */
+  unsigned char *regspace;
+
+  /* The register buffer as passed on by lttng/ust.  */
+  struct registers *regs;
+
+  /* The "printf" formatter and the args the user passed to the marker
+     call.  We use this to be able to collect "static trace data"
+     ($_sdata).  */
+  const char *fmt;
+  va_list *args;
+
+  /* The GDB tracepoint matching the probed marker that was "hit".  */
+  struct tracepoint *tpoint;
+};
+
 #else
 
 /* Static tracepoint specific data to be passed down to
@@ -1189,6 +1314,8 @@ static void collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
 static void collect_data_at_step (struct tracepoint_hit_ctx *ctx,
                                  CORE_ADDR stop_pc,
                                  struct tracepoint *tpoint, int current_step);
+static void compile_tracepoint_condition (struct tracepoint *tpoint,
+                                         CORE_ADDR *jump_entry);
 #endif
 static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
                                     CORE_ADDR stop_pc,
@@ -1212,6 +1339,10 @@ static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR);
 #define cmpxchg(mem, oldval, newval) \
   __sync_val_compare_and_swap (mem, oldval, newval)
 
+/* The size in bytes of the buffer used to talk to the IPA helper
+   thread.  */
+#define CMD_BUF_SIZE 1024
+
 /* Record that an error occurred during expression evaluation.  */
 
 static void
@@ -1610,6 +1741,7 @@ add_tracepoint (int num, CORE_ADDR addr)
   tpoint->type = trap_tracepoint;
   tpoint->orig_size = -1;
   tpoint->source_strings = NULL;
+  tpoint->compiled_cond = 0;
   tpoint->handle = NULL;
   tpoint->next = NULL;
 
@@ -1739,6 +1871,18 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet)
              ++act;
            break;
          }
+       case 'L':
+         {
+           struct collect_static_trace_data_action *raction;
+
+           raction = xmalloc (sizeof *raction);
+           raction->base.type = *act;
+           action = &raction->base;
+
+           trace_debug ("Want to collect static trace data");
+           ++act;
+           break;
+         }
        case 'S':
          trace_debug ("Unexpected step action, ignoring");
          ++act;
@@ -1854,7 +1998,7 @@ create_trace_state_variable (int num, int gdb)
   return tsv;
 }
 
-static LONGEST
+IP_AGENT_EXPORT LONGEST
 get_trace_state_variable_value (int num)
 {
   struct trace_state_variable *tsv;
@@ -1880,7 +2024,7 @@ get_trace_state_variable_value (int num)
   return tsv->value;
 }
 
-static void
+IP_AGENT_EXPORT void
 set_trace_state_variable_value (int num, LONGEST val)
 {
   struct trace_state_variable *tsv;
@@ -2130,6 +2274,17 @@ cmd_qtinit (char *packet)
   write_ok (packet);
 }
 
+/* Unprobe the UST marker at ADDRESS.  */
+
+static void
+unprobe_marker_at (CORE_ADDR address)
+{
+  char cmd[CMD_BUF_SIZE];
+
+  sprintf (cmd, "unprobe_marker_at:%s", paddress (address));
+  run_inferior_command (cmd);
+}
+
 /* Restore the program to its pre-tracing state.  This routine may be called
    in error situations, so it needs to be careful about only restoring
    from known-valid bits.  */
@@ -2169,6 +2324,19 @@ clear_installed_tracepoints (void)
        case fast_tracepoint:
          delete_fast_tracepoint_jump (tpoint->handle);
          break;
+       case static_tracepoint:
+         if (prev_stpoint != NULL
+             && prev_stpoint->address == tpoint->address)
+           /* Nothing to do.  We already unprobed a tracepoint set at
+              this marker address (and there can only be one probe
+              per marker).  */
+           ;
+         else
+           {
+             unprobe_marker_at (tpoint->address);
+             prev_stpoint = tpoint;
+           }
+         break;
        }
 
       tpoint->handle = NULL;
@@ -2241,6 +2409,11 @@ cmd_qtdp (char *own_buf)
              packet = unpack_varlen_hex (packet, &count);
              tpoint->orig_size = count;
            }
+         else if (*packet == 'S')
+           {
+             tpoint->type = static_tracepoint;
+             ++packet;
+           }
          else if (*packet == 'X')
            {
              actparm = (char *) packet;
@@ -2553,12 +2726,39 @@ sort_tracepoints (void)
       }
 }
 
+/* Ask the IPA to probe the marker at ADDRESS.  Returns -1 if running
+   the command fails, or 0 otherwise.  If the command ran
+   successfully, but probing the marker failed, ERROUT will be filled
+   with the error to reply to GDB, and -1 is also returned.  This
+   allows directly passing IPA errors to GDB.  */
+
+static int
+probe_marker_at (CORE_ADDR address, char *errout)
+{
+  char cmd[CMD_BUF_SIZE];
+  int err;
+
+  sprintf (cmd, "probe_marker_at:%s", paddress (address));
+  err = run_inferior_command (cmd);
+
+  if (err == 0)
+    {
+      if (*cmd == 'E')
+       {
+         strcpy (errout, cmd);
+         return -1;
+       }
+    }
+
+  return err;
+}
+
 #define MAX_JUMP_SIZE 20
 
 static void
 cmd_qtstart (char *packet)
 {
-  struct tracepoint *tpoint, *prev_ftpoint;
+  struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint;
   int slow_tracepoint_count, fast_count;
   CORE_ADDR jump_entry;
 
@@ -2597,6 +2797,9 @@ cmd_qtstart (char *packet)
   /* No previous fast tpoint yet.  */
   prev_ftpoint = NULL;
 
+  /* No previous static tpoint yet.  */
+  prev_stpoint = NULL;
+
   *packet = '\0';
 
   /* Install tracepoints.  */
@@ -2682,6 +2885,32 @@ cmd_qtstart (char *packet)
                }
            }
        }
+      else if (tpoint->type == static_tracepoint)
+       {
+         if (maybe_write_ipa_ust_not_loaded (packet))
+           {
+             trace_debug ("Requested a static tracepoint, but static "
+                          "tracepoints are not supported.");
+             break;
+           }
+
+         /* Can only probe a given marker once.  */
+         if (prev_stpoint != NULL && prev_stpoint->address == tpoint->address)
+           {
+             tpoint->handle = (void *) -1;
+           }
+         else
+           {
+             if (probe_marker_at (tpoint->address, packet) == 0)
+               {
+                 tpoint->handle = (void *) -1;
+
+                 /* So that we can handle multiple static tracepoints
+                    at the same address easily.  */
+                 prev_stpoint = tpoint;
+               }
+           }
+       }
 
       /* Any failure in the inner loop is sufficient cause to give
         up.  */
@@ -3022,6 +3251,8 @@ response_tracepoint (char *packet, struct tracepoint *tpoint)
           tpoint->pass_count);
   if (tpoint->type == fast_tracepoint)
     sprintf (packet + strlen (packet), ":F%x", tpoint->orig_size);
+  else if (tpoint->type == static_tracepoint)
+    sprintf (packet + strlen (packet), ":S");
 
   if (tpoint->cond)
     {
@@ -3196,6 +3427,36 @@ cmd_qtsv (char *packet)
     strcpy (packet, "l");
 }
 
+/* Return the first static tracepoint marker, and initialize the state
+   machine that will iterate through all the static tracepoints
+   markers.  */
+
+static void
+cmd_qtfstm (char *packet)
+{
+  if (!maybe_write_ipa_ust_not_loaded (packet))
+    run_inferior_command (packet);
+}
+
+/* Return additional static tracepoints markers.  */
+
+static void
+cmd_qtsstm (char *packet)
+{
+  if (!maybe_write_ipa_ust_not_loaded (packet))
+    run_inferior_command (packet);
+}
+
+/* Return the definition of the static tracepoint at a given address.
+   Result packet is the same as qTsST's.  */
+
+static void
+cmd_qtstmat (char *packet)
+{
+  if (!maybe_write_ipa_ust_not_loaded (packet))
+    run_inferior_command (packet);
+}
+
 /* Respond to qTBuffer packet with a block of raw data from the trace
    buffer.  GDB may ask for a lot, but we are allowed to reply with
    only as much as will fit within packet limits or whatever.  */
@@ -3367,6 +3628,21 @@ handle_tracepoint_query (char *packet)
       cmd_qtbuffer (packet);
       return 1;
     }
+  else if (strcmp ("qTfSTM", packet) == 0)
+    {
+      cmd_qtfstm (packet);
+      return 1;
+    }
+  else if (strcmp ("qTsSTM", packet) == 0)
+    {
+      cmd_qtsstm (packet);
+      return 1;
+    }
+  else if (strncmp ("qTSTMat:", packet, strlen ("qTSTMat:")) == 0)
+    {
+      cmd_qtstmat (packet);
+      return 1;
+    }
 
   return 0;
 }
@@ -3680,6 +3956,14 @@ tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc)
 
 #endif
 
+#if defined IN_PROCESS_AGENT && defined HAVE_UST
+struct ust_marker_data;
+static void collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
+                                           CORE_ADDR stop_pc,
+                                           struct tracepoint *tpoint,
+                                           struct traceframe *tframe);
+#endif
+
 /* Create a trace frame for the hit of the given tracepoint in the
    given thread.  */
 
@@ -3786,6 +4070,25 @@ get_context_regcache (struct tracepoint_hit_ctx *ctx)
        }
       regcache = &fctx->regcache;
     }
+#ifdef HAVE_UST
+  if (ctx->type == static_tracepoint)
+    {
+      struct static_tracepoint_ctx *sctx = (struct static_tracepoint_ctx *) ctx;
+      if (!sctx->regcache_initted)
+       {
+         sctx->regcache_initted = 1;
+         init_register_cache (&sctx->regcache, sctx->regspace);
+         supply_regblock (&sctx->regcache, NULL);
+         /* Pass down the tracepoint address, because REGS doesn't
+            include the PC, but we know what it must have been.  */
+         supply_static_tracepoint_registers (&sctx->regcache,
+                                             (const unsigned char *)
+                                             sctx->regs,
+                                             sctx->tpoint->address);
+       }
+      regcache = &sctx->regcache;
+    }
+#endif
 #else
   if (ctx->type == trap_tracepoint)
     {
@@ -3893,6 +4196,18 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
          }
       }
       break;
+    case 'L':
+      {
+#if defined IN_PROCESS_AGENT && defined HAVE_UST
+       trace_debug ("Want to collect static trace data");
+       collect_ust_data_at_tracepoint (ctx, stop_pc,
+                                       tpoint, tframe);
+#else
+       trace_debug ("warning: collecting static trace data, "
+                    "but static tracepoints are not supported");
+#endif
+      }
+      break;
     default:
       trace_debug ("unknown trace action '%c', ignoring", taction->type);
       break;
@@ -3906,7 +4221,26 @@ condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx,
   ULONGEST value = 0;
   enum eval_result_type err;
 
-  err = eval_agent_expr (ctx, NULL, tpoint->cond, &value);
+  /* Presently, gdbserver doesn't run compiled conditions, only the
+     IPA does.  If the program stops at a fast tracepoint's address
+     (e.g., due to a breakpoint, trap tracepoint, or stepping),
+     gdbserver preemptively collect the fast tracepoint.  Later, on
+     resume, gdbserver steps over the fast tracepoint like it steps
+     over breakpoints, so that the IPA doesn't see that fast
+     tracepoint.  This avoids double collects of fast tracepoints in
+     that stopping scenario.  Having gdbserver itself handle the fast
+     tracepoint gives the user a consistent view of when fast or trap
+     tracepoints are collected, compared to an alternative where only
+     trap tracepoints are collected on stop, and fast tracepoints on
+     resume.  When a fast tracepoint is being processed by gdbserver,
+     it is always the non-compiled condition expression that is
+     used.  */
+#ifdef IN_PROCESS_AGENT
+  if (tpoint->compiled_cond)
+    err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (ctx, &value);
+  else
+#endif
+    err = eval_agent_expr (ctx, NULL, tpoint->cond, &value);
 
   if (err != expr_eval_no_error)
     {
@@ -4458,6 +4792,11 @@ traceframe_find_block_type (unsigned char *database, unsigned int datasize,
          /* Skip over the TSV block.  */
          dataptr += (sizeof (int) + sizeof (LONGEST));
          break;
+       case 'S':
+         /* Skip over the static trace data block.  */
+         memcpy (&mlen, dataptr, sizeof (mlen));
+         dataptr += (sizeof (mlen) + mlen);
+         break;
        default:
          trace_debug ("traceframe %d has unknown block type 0x%x",
                       tfnum, blocktype);
@@ -4648,6 +4987,59 @@ traceframe_read_tsv (int tsvnum, LONGEST *val)
   return 1;
 }
 
+/* Read a requested block of static tracepoint data from a trace
+   frame.  */
+
+int
+traceframe_read_sdata (int tfnum, ULONGEST offset,
+                      unsigned char *buf, ULONGEST length,
+                      ULONGEST *nbytes)
+{
+  struct traceframe *tframe;
+  unsigned char *database, *dataptr;
+  unsigned int datasize;
+  unsigned short mlen;
+
+  trace_debug ("traceframe_read_sdata");
+
+  tframe = find_traceframe (tfnum);
+
+  if (!tframe)
+    {
+      trace_debug ("traceframe %d not found", tfnum);
+      return 1;
+    }
+
+  datasize = tframe->data_size;
+  database = &tframe->data[0];
+
+  /* Iterate through a traceframe's blocks, looking for static
+     tracepoint data.  */
+  dataptr = traceframe_find_block_type (database, datasize,
+                                       tfnum, 'S');
+  if (dataptr != NULL)
+    {
+      memcpy (&mlen, dataptr, sizeof (mlen));
+      dataptr += sizeof (mlen);
+      if (offset < mlen)
+       {
+         if (offset + length > mlen)
+           length = mlen - offset;
+
+         memcpy (buf, dataptr, length);
+         *nbytes = length;
+       }
+      else
+       *nbytes = 0;
+      return 0;
+    }
+
+  trace_debug ("traceframe %d has no static trace data", tfnum);
+
+  *nbytes = 0;
+  return 0;
+}
+
 /* Return the first fast tracepoint whose jump pad contains PC.  */
 
 static struct tracepoint *
@@ -4944,514 +5336,1998 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
 
 #ifndef IN_PROCESS_AGENT
 
-/* We'll need to adjust these when we consider bi-arch setups, and big
-   endian machines.  */
-
-static int
-write_inferior_data_ptr (CORE_ADDR where, CORE_ADDR ptr)
-{
-  return write_inferior_memory (where,
-                               (unsigned char *) &ptr, sizeof (void *));
-}
+/* Bytecode compilation.  */
 
-/* The base pointer of the IPA's heap.  This is the only memory the
-   IPA is allowed to use.  The IPA should _not_ call the inferior's
-   `malloc' during operation.  That'd be slow, and, most importantly,
-   it may not be safe.  We may be collecting a tracepoint in a signal
-   handler, for example.  */
-static CORE_ADDR target_tp_heap;
+CORE_ADDR current_insn_ptr;
 
-/* Allocate at least SIZE bytes of memory from the IPA heap, aligned
-   to 8 bytes.  */
+int emit_error;
 
-static CORE_ADDR
-target_malloc (ULONGEST size)
+struct bytecode_address
 {
-  CORE_ADDR ptr;
-
-  if (target_tp_heap == 0)
-    {
-      /* We have the pointer *address*, need what it points to.  */
-      if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_tp_heap_buffer,
-                                     &target_tp_heap))
-       fatal ("could get target heap head pointer");
-    }
-
-  ptr = target_tp_heap;
-  target_tp_heap += size;
-
-  /* Pad to 8-byte alignment.  */
-  target_tp_heap = ((target_tp_heap + 7) & ~0x7);
+  int pc;
+  CORE_ADDR address;
+  int goto_pc;
+  /* Offset and size of field to be modified in the goto block.  */
+  int from_offset, from_size;
+  struct bytecode_address *next;
+} *bytecode_address_table;
 
-  return ptr;
+CORE_ADDR
+get_raw_reg_func_addr (void)
+{
+  return ipa_sym_addrs.addr_get_raw_reg;
 }
 
-static CORE_ADDR
-download_agent_expr (struct agent_expr *expr)
+static void
+emit_prologue (void)
 {
-  CORE_ADDR expr_addr;
-  CORE_ADDR expr_bytes;
-
-  expr_addr = target_malloc (sizeof (*expr));
-  write_inferior_memory (expr_addr, (unsigned char *) expr, sizeof (*expr));
+  target_emit_ops ()->emit_prologue ();
+}
 
-  expr_bytes = target_malloc (expr->length);
-  write_inferior_data_ptr (expr_addr + offsetof (struct agent_expr, bytes),
-                          expr_bytes);
-  write_inferior_memory (expr_bytes, expr->bytes, expr->length);
+static void
+emit_epilogue (void)
+{
+  target_emit_ops ()->emit_epilogue ();
+}
 
-  return expr_addr;
+static void
+emit_add (void)
+{
+  target_emit_ops ()->emit_add ();
 }
 
-/* Align V up to N bits.  */
-#define UALIGN(V, N) (((V) + ((N) - 1)) & ~((N) - 1))
+static void
+emit_sub (void)
+{
+  target_emit_ops ()->emit_sub ();
+}
 
 static void
-download_tracepoints (void)
+emit_mul (void)
+{
+  target_emit_ops ()->emit_mul ();
+}
+
+static void
+emit_lsh (void)
+{
+  target_emit_ops ()->emit_lsh ();
+}
+
+static void
+emit_rsh_signed (void)
+{
+  target_emit_ops ()->emit_rsh_signed ();
+}
+
+static void
+emit_rsh_unsigned (void)
+{
+  target_emit_ops ()->emit_rsh_unsigned ();
+}
+
+static void
+emit_ext (int arg)
+{
+  target_emit_ops ()->emit_ext (arg);
+}
+
+static void
+emit_log_not (void)
+{
+  target_emit_ops ()->emit_log_not ();
+}
+
+static void
+emit_bit_and (void)
+{
+  target_emit_ops ()->emit_bit_and ();
+}
+
+static void
+emit_bit_or (void)
+{
+  target_emit_ops ()->emit_bit_or ();
+}
+
+static void
+emit_bit_xor (void)
+{
+  target_emit_ops ()->emit_bit_xor ();
+}
+
+static void
+emit_bit_not (void)
+{
+  target_emit_ops ()->emit_bit_not ();
+}
+
+static void
+emit_equal (void)
+{
+  target_emit_ops ()->emit_equal ();
+}
+
+static void
+emit_less_signed (void)
+{
+  target_emit_ops ()->emit_less_signed ();
+}
+
+static void
+emit_less_unsigned (void)
+{
+  target_emit_ops ()->emit_less_unsigned ();
+}
+
+static void
+emit_ref (int size)
+{
+  target_emit_ops ()->emit_ref (size);
+}
+
+static void
+emit_if_goto (int *offset_p, int *size_p)
+{
+  target_emit_ops ()->emit_if_goto (offset_p, size_p);
+}
+
+static void
+emit_goto (int *offset_p, int *size_p)
+{
+  target_emit_ops ()->emit_goto (offset_p, size_p);
+}
+
+static void
+write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
+{
+  target_emit_ops ()->write_goto_address (from, to, size);
+}
+
+static void
+emit_const (LONGEST num)
+{
+  target_emit_ops ()->emit_const (num);
+}
+
+static void
+emit_reg (int reg)
+{
+  target_emit_ops ()->emit_reg (reg);
+}
+
+static void
+emit_pop (void)
+{
+  target_emit_ops ()->emit_pop ();
+}
+
+static void
+emit_stack_flush (void)
+{
+  target_emit_ops ()->emit_stack_flush ();
+}
+
+static void
+emit_zero_ext (int arg)
+{
+  target_emit_ops ()->emit_zero_ext (arg);
+}
+
+static void
+emit_swap (void)
+{
+  target_emit_ops ()->emit_swap ();
+}
+
+static void
+emit_stack_adjust (int n)
+{
+  target_emit_ops ()->emit_stack_adjust (n);
+}
+
+/* FN's prototype is `LONGEST(*fn)(int)'.  */
+
+static void
+emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  target_emit_ops ()->emit_int_call_1 (fn, arg1);
+}
+
+/* FN's prototype is `void(*fn)(int,LONGEST)'.  */
+
+static void
+emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  target_emit_ops ()->emit_void_call_2 (fn, arg1);
+}
+
+static enum eval_result_type compile_bytecodes (struct agent_expr *aexpr);
+
+static void
+compile_tracepoint_condition (struct tracepoint *tpoint, CORE_ADDR *jump_entry)
+{
+  CORE_ADDR entry_point = *jump_entry;
+  enum eval_result_type err;
+
+  trace_debug ("Starting condition compilation for tracepoint %d\n",
+              tpoint->number);
+
+  /* Initialize the global pointer to the code being built.  */
+  current_insn_ptr = *jump_entry;
+
+  emit_prologue ();
+
+  err = compile_bytecodes (tpoint->cond);
+
+  if (err == expr_eval_no_error)
+    {
+      emit_epilogue ();
+
+      /* Record the beginning of the compiled code.  */
+      tpoint->compiled_cond = entry_point;
+
+      trace_debug ("Condition compilation for tracepoint %d complete\n",
+                  tpoint->number);
+    }
+  else
+    {
+      /* Leave the unfinished code in situ, but don't point to it.  */
+
+      tpoint->compiled_cond = 0;
+
+      trace_debug ("Condition compilation for tracepoint %d failed, "
+                  "error code %d",
+                  tpoint->number, err);
+    }
+
+  /* Update the code pointer passed in.  Note that we do this even if
+     the compile fails, so that we can look at the partial results
+     instead of letting them be overwritten.  */
+  *jump_entry = current_insn_ptr;
+
+  /* Leave a gap, to aid dump decipherment.  */
+  *jump_entry += 16;
+}
+
+/* Given an agent expression, turn it into native code.  */
+
+static enum eval_result_type
+compile_bytecodes (struct agent_expr *aexpr)
+{
+  int pc = 0;
+  int done = 0;
+  unsigned char op;
+  int arg;
+  /* This is only used to build 64-bit value for constants.  */
+  ULONGEST top;
+  struct bytecode_address *aentry, *aentry2;
+
+#define UNHANDLED                                      \
+  do                                                   \
+    {                                                  \
+      trace_debug ("Cannot compile op 0x%x\n", op);    \
+      return expr_eval_unhandled_opcode;               \
+    } while (0)
+
+  if (aexpr->length == 0)
+    {
+      trace_debug ("empty agent expression\n");
+      return expr_eval_empty_expression;
+    }
+
+  bytecode_address_table = NULL;
+
+  while (!done)
+    {
+      op = aexpr->bytes[pc];
+
+      trace_debug ("About to compile op 0x%x, pc=%d\n", op, pc);
+
+      /* Record the compiled-code address of the bytecode, for use by
+        jump instructions.  */
+      aentry = xmalloc (sizeof (struct bytecode_address));
+      aentry->pc = pc;
+      aentry->address = current_insn_ptr;
+      aentry->goto_pc = -1;
+      aentry->from_offset = aentry->from_size = 0;
+      aentry->next = bytecode_address_table;
+      bytecode_address_table = aentry;
+
+      ++pc;
+
+      emit_error = 0;
+
+      switch (op)
+       {
+       case gdb_agent_op_add:
+         emit_add ();
+         break;
+
+       case gdb_agent_op_sub:
+         emit_sub ();
+         break;
+
+       case gdb_agent_op_mul:
+         emit_mul ();
+         break;
+
+       case gdb_agent_op_div_signed:
+         UNHANDLED;
+         break;
+
+       case gdb_agent_op_div_unsigned:
+         UNHANDLED;
+         break;
+
+       case gdb_agent_op_rem_signed:
+         UNHANDLED;
+         break;
+
+       case gdb_agent_op_rem_unsigned:
+         UNHANDLED;
+         break;
+
+       case gdb_agent_op_lsh:
+         emit_lsh ();
+         break;
+
+       case gdb_agent_op_rsh_signed:
+         emit_rsh_signed ();
+         break;
+
+       case gdb_agent_op_rsh_unsigned:
+         emit_rsh_unsigned ();
+         break;
+
+       case gdb_agent_op_trace:
+         UNHANDLED;
+         break;
+
+       case gdb_agent_op_trace_quick:
+         UNHANDLED;
+         break;
+
+       case gdb_agent_op_log_not:
+         emit_log_not ();
+         break;
+
+       case gdb_agent_op_bit_and:
+         emit_bit_and ();
+         break;
+
+       case gdb_agent_op_bit_or:
+         emit_bit_or ();
+         break;
+
+       case gdb_agent_op_bit_xor:
+         emit_bit_xor ();
+         break;
+
+       case gdb_agent_op_bit_not:
+         emit_bit_not ();
+         break;
+
+       case gdb_agent_op_equal:
+         emit_equal ();
+         break;
+
+       case gdb_agent_op_less_signed:
+         emit_less_signed ();
+         break;
+
+       case gdb_agent_op_less_unsigned:
+         emit_less_unsigned ();
+         break;
+
+       case gdb_agent_op_ext:
+         arg = aexpr->bytes[pc++];
+         if (arg < (sizeof (LONGEST) * 8))
+           emit_ext (arg);
+         break;
+
+       case gdb_agent_op_ref8:
+         emit_ref (1);
+         break;
+
+       case gdb_agent_op_ref16:
+         emit_ref (2);
+         break;
+
+       case gdb_agent_op_ref32:
+         emit_ref (4);
+         break;
+
+       case gdb_agent_op_ref64:
+         emit_ref (8);
+         break;
+
+       case gdb_agent_op_if_goto:
+         arg = aexpr->bytes[pc++];
+         arg = (arg << 8) + aexpr->bytes[pc++];
+         aentry->goto_pc = arg;
+         emit_if_goto (&(aentry->from_offset), &(aentry->from_size));
+         break;
+
+       case gdb_agent_op_goto:
+         arg = aexpr->bytes[pc++];
+         arg = (arg << 8) + aexpr->bytes[pc++];
+         aentry->goto_pc = arg;
+         emit_goto (&(aentry->from_offset), &(aentry->from_size));
+         break;
+
+       case gdb_agent_op_const8:
+         emit_stack_flush ();
+         top = aexpr->bytes[pc++];
+         emit_const (top);
+         break;
+
+       case gdb_agent_op_const16:
+         emit_stack_flush ();
+         top = aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         emit_const (top);
+         break;
+
+       case gdb_agent_op_const32:
+         emit_stack_flush ();
+         top = aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         emit_const (top);
+         break;
+
+       case gdb_agent_op_const64:
+         emit_stack_flush ();
+         top = aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         top = (top << 8) + aexpr->bytes[pc++];
+         emit_const (top);
+         break;
+
+       case gdb_agent_op_reg:
+         emit_stack_flush ();
+         arg = aexpr->bytes[pc++];
+         arg = (arg << 8) + aexpr->bytes[pc++];
+         emit_reg (arg);
+         break;
+
+       case gdb_agent_op_end:
+         trace_debug ("At end of expression\n");
+
+         /* Assume there is one stack element left, and that it is
+            cached in "top" where emit_epilogue can get to it.  */
+         emit_stack_adjust (1);
+
+         done = 1;
+         break;
+
+       case gdb_agent_op_dup:
+         /* In our design, dup is equivalent to stack flushing.  */
+         emit_stack_flush ();
+         break;
+
+       case gdb_agent_op_pop:
+         emit_pop ();
+         break;
+
+       case gdb_agent_op_zero_ext:
+         arg = aexpr->bytes[pc++];
+         if (arg < (sizeof (LONGEST) * 8))
+           emit_zero_ext (arg);
+         break;
+
+       case gdb_agent_op_swap:
+         emit_swap ();
+         break;
+
+       case gdb_agent_op_getv:
+         emit_stack_flush ();
+         arg = aexpr->bytes[pc++];
+         arg = (arg << 8) + aexpr->bytes[pc++];
+         emit_int_call_1 (ipa_sym_addrs.addr_get_trace_state_variable_value,
+                          arg);
+         break;
+
+       case gdb_agent_op_setv:
+         arg = aexpr->bytes[pc++];
+         arg = (arg << 8) + aexpr->bytes[pc++];
+         emit_void_call_2 (ipa_sym_addrs.addr_set_trace_state_variable_value,
+                           arg);
+         break;
+
+       case gdb_agent_op_tracev:
+         UNHANDLED;
+         break;
+
+         /* GDB never (currently) generates any of these ops.  */
+       case gdb_agent_op_float:
+       case gdb_agent_op_ref_float:
+       case gdb_agent_op_ref_double:
+       case gdb_agent_op_ref_long_double:
+       case gdb_agent_op_l_to_d:
+       case gdb_agent_op_d_to_l:
+       case gdb_agent_op_trace16:
+         UNHANDLED;
+         break;
+
+       default:
+         trace_debug ("Agent expression op 0x%x not recognized\n", op);
+         /* Don't struggle on, things will just get worse.  */
+         return expr_eval_unrecognized_opcode;
+       }
+
+      /* This catches errors that occur in target-specific code
+        emission.  */
+      if (emit_error)
+       {
+         trace_debug ("Error %d while emitting code for %s\n",
+                      emit_error, gdb_agent_op_names[op]);
+         return expr_eval_unhandled_opcode;
+       }
+
+      trace_debug ("Op %s compiled\n", gdb_agent_op_names[op]);
+    }
+
+  /* Now fill in real addresses as goto destinations.  */
+  for (aentry = bytecode_address_table; aentry; aentry = aentry->next)
+    {
+      int written = 0;
+
+      if (aentry->goto_pc < 0)
+       continue;
+
+      /* Find the location that we are going to, and call back into
+        target-specific code to write the actual address or
+        displacement.  */
+      for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next)
+       {
+         if (aentry2->pc == aentry->goto_pc)
+           {
+             trace_debug ("Want to jump from %s to %s\n",
+                          paddress (aentry->address),
+                          paddress (aentry2->address));
+             write_goto_address (aentry->address + aentry->from_offset,
+                                 aentry2->address, aentry->from_size);
+             written = 1;
+             break;
+           }
+       }
+
+      /* Error out if we didn't find a destination.  */
+      if (!written)
+       {
+         trace_debug ("Destination of goto %d not found\n",
+                      aentry->goto_pc);
+         return expr_eval_invalid_goto;
+       }
+    }
+
+  return expr_eval_no_error;
+}
+
+/* We'll need to adjust these when we consider bi-arch setups, and big
+   endian machines.  */
+
+static int
+write_inferior_data_ptr (CORE_ADDR where, CORE_ADDR ptr)
+{
+  return write_inferior_memory (where,
+                               (unsigned char *) &ptr, sizeof (void *));
+}
+
+/* The base pointer of the IPA's heap.  This is the only memory the
+   IPA is allowed to use.  The IPA should _not_ call the inferior's
+   `malloc' during operation.  That'd be slow, and, most importantly,
+   it may not be safe.  We may be collecting a tracepoint in a signal
+   handler, for example.  */
+static CORE_ADDR target_tp_heap;
+
+/* Allocate at least SIZE bytes of memory from the IPA heap, aligned
+   to 8 bytes.  */
+
+static CORE_ADDR
+target_malloc (ULONGEST size)
+{
+  CORE_ADDR ptr;
+
+  if (target_tp_heap == 0)
+    {
+      /* We have the pointer *address*, need what it points to.  */
+      if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_tp_heap_buffer,
+                                     &target_tp_heap))
+       fatal ("could get target heap head pointer");
+    }
+
+  ptr = target_tp_heap;
+  target_tp_heap += size;
+
+  /* Pad to 8-byte alignment.  */
+  target_tp_heap = ((target_tp_heap + 7) & ~0x7);
+
+  return ptr;
+}
+
+static CORE_ADDR
+download_agent_expr (struct agent_expr *expr)
+{
+  CORE_ADDR expr_addr;
+  CORE_ADDR expr_bytes;
+
+  expr_addr = target_malloc (sizeof (*expr));
+  write_inferior_memory (expr_addr, (unsigned char *) expr, sizeof (*expr));
+
+  expr_bytes = target_malloc (expr->length);
+  write_inferior_data_ptr (expr_addr + offsetof (struct agent_expr, bytes),
+                          expr_bytes);
+  write_inferior_memory (expr_bytes, expr->bytes, expr->length);
+
+  return expr_addr;
+}
+
+/* Align V up to N bits.  */
+#define UALIGN(V, N) (((V) + ((N) - 1)) & ~((N) - 1))
+
+static void
+download_tracepoints (void)
 {
   CORE_ADDR tpptr = 0, prev_tpptr = 0;
   struct tracepoint *tpoint;
 
-  /* Start out empty.  */
-  write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0);
+  /* Start out empty.  */
+  write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0);
+
+  for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
+    {
+      struct tracepoint target_tracepoint;
+
+      if (tpoint->type != fast_tracepoint
+         && tpoint->type != static_tracepoint)
+       continue;
+
+      /* Maybe download a compiled condition.  */
+      if (tpoint->cond != NULL && target_emit_ops () != NULL)
+       {
+         CORE_ADDR jentry, jump_entry;
+
+         jentry = jump_entry = get_jump_space_head ();
+
+         if (tpoint->cond != NULL)
+           {
+             /* Pad to 8-byte alignment. (needed?)  */
+             /* Actually this should be left for the target to
+                decide.  */
+             jentry = UALIGN (jentry, 8);
+
+             compile_tracepoint_condition (tpoint, &jentry);
+           }
+
+         /* Pad to 8-byte alignment.  */
+         jentry = UALIGN (jentry, 8);
+         claim_jump_space (jentry - jump_entry);
+       }
+
+      target_tracepoint = *tpoint;
+
+      prev_tpptr = tpptr;
+      tpptr = target_malloc (sizeof (*tpoint));
+      tpoint->obj_addr_on_target = tpptr;
+
+      if (tpoint == tracepoints)
+       {
+         /* First object in list, set the head pointer in the
+            inferior.  */
+         write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr);
+       }
+      else
+       {
+         write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint,
+                                                         next),
+                                  tpptr);
+       }
+
+      /* Write the whole object.  We'll fix up its pointers in a bit.
+        Assume no next for now.  This is fixed up above on the next
+        iteration, if there's any.  */
+      target_tracepoint.next = NULL;
+      /* Need to clear this here too, since we're downloading the
+        tracepoints before clearing our own copy.  */
+      target_tracepoint.hit_count = 0;
+
+      write_inferior_memory (tpptr, (unsigned char *) &target_tracepoint,
+                            sizeof (target_tracepoint));
+
+      if (tpoint->cond)
+       write_inferior_data_ptr (tpptr + offsetof (struct tracepoint,
+                                                  cond),
+                                download_agent_expr (tpoint->cond));
+
+      if (tpoint->numactions)
+       {
+         int i;
+         CORE_ADDR actions_array;
+
+         /* The pointers array.  */
+         actions_array
+           = target_malloc (sizeof (*tpoint->actions) * tpoint->numactions);
+         write_inferior_data_ptr (tpptr + offsetof (struct tracepoint,
+                                                    actions),
+                                  actions_array);
+
+         /* Now for each pointer, download the action.  */
+         for (i = 0; i < tpoint->numactions; i++)
+           {
+             CORE_ADDR ipa_action = 0;
+             struct tracepoint_action *action = tpoint->actions[i];
+
+             switch (action->type)
+               {
+               case 'M':
+                 ipa_action
+                   = target_malloc (sizeof (struct collect_memory_action));
+                 write_inferior_memory (ipa_action,
+                                        (unsigned char *) action,
+                                        sizeof (struct collect_memory_action));
+                 break;
+               case 'R':
+                 ipa_action
+                   = target_malloc (sizeof (struct collect_registers_action));
+                 write_inferior_memory (ipa_action,
+                                        (unsigned char *) action,
+                                        sizeof (struct collect_registers_action));
+                 break;
+               case 'X':
+                 {
+                   CORE_ADDR expr;
+                   struct eval_expr_action *eaction
+                     = (struct eval_expr_action *) action;
+
+                   ipa_action = target_malloc (sizeof (*eaction));
+                   write_inferior_memory (ipa_action,
+                                          (unsigned char *) eaction,
+                                          sizeof (*eaction));
+
+                   expr = download_agent_expr (eaction->expr);
+                   write_inferior_data_ptr
+                     (ipa_action + offsetof (struct eval_expr_action, expr),
+                      expr);
+                   break;
+                 }
+               case 'L':
+                 ipa_action = target_malloc
+                   (sizeof (struct collect_static_trace_data_action));
+                 write_inferior_memory
+                   (ipa_action,
+                    (unsigned char *) action,
+                    sizeof (struct collect_static_trace_data_action));
+                 break;
+               default:
+                 trace_debug ("unknown trace action '%c', ignoring",
+                              action->type);
+                 break;
+               }
+
+             if (ipa_action != 0)
+               write_inferior_data_ptr
+                 (actions_array + i * sizeof (sizeof (*tpoint->actions)),
+                  ipa_action);
+           }
+       }
+    }
+}
+
+static void
+download_trace_state_variables (void)
+{
+  CORE_ADDR ptr = 0, prev_ptr = 0;
+  struct trace_state_variable *tsv;
+
+  /* Start out empty.  */
+  write_inferior_data_ptr (ipa_sym_addrs.addr_trace_state_variables, 0);
+
+  for (tsv = trace_state_variables; tsv != NULL; tsv = tsv->next)
+    {
+      struct trace_state_variable target_tsv;
+
+      /* TSV's with a getter have been initialized equally in both the
+        inferior and GDBserver.  Skip them.  */
+      if (tsv->getter != NULL)
+       continue;
+
+      target_tsv = *tsv;
+
+      prev_ptr = ptr;
+      ptr = target_malloc (sizeof (*tsv));
+
+      if (tsv == trace_state_variables)
+       {
+         /* First object in list, set the head pointer in the
+            inferior.  */
+
+         write_inferior_data_ptr (ipa_sym_addrs.addr_trace_state_variables,
+                                  ptr);
+       }
+      else
+       {
+         write_inferior_data_ptr (prev_ptr
+                                  + offsetof (struct trace_state_variable,
+                                              next),
+                                  ptr);
+       }
+
+      /* Write the whole object.  We'll fix up its pointers in a bit.
+        Assume no next, fixup when needed.  */
+      target_tsv.next = NULL;
+
+      write_inferior_memory (ptr, (unsigned char *) &target_tsv,
+                            sizeof (target_tsv));
+
+      if (tsv->name != NULL)
+       {
+         size_t size = strlen (tsv->name) + 1;
+         CORE_ADDR name_addr = target_malloc (size);
+         write_inferior_memory (name_addr,
+                                (unsigned char *) tsv->name, size);
+         write_inferior_data_ptr (ptr
+                                  + offsetof (struct trace_state_variable,
+                                              name),
+                                  name_addr);
+       }
+
+      if (tsv->getter != NULL)
+       {
+         fatal ("what to do with these?");
+       }
+    }
+
+  if (prev_ptr != 0)
+    {
+      /* Fixup the next pointer in the last item in the list.  */
+      write_inferior_data_ptr (prev_ptr + offsetof (struct trace_state_variable,
+                                                   next), 0);
+    }
+}
+
+/* Upload complete trace frames out of the IP Agent's trace buffer
+   into GDBserver's trace buffer.  This always uploads either all or
+   no trace frames.  This is the counter part of
+   `trace_alloc_trace_buffer'.  See its description of the atomic
+   synching mechanism.  */
+
+static void
+upload_fast_traceframes (void)
+{
+  unsigned int ipa_traceframe_read_count, ipa_traceframe_write_count;
+  unsigned int ipa_traceframe_read_count_racy, ipa_traceframe_write_count_racy;
+  CORE_ADDR tf;
+  struct ipa_trace_buffer_control ipa_trace_buffer_ctrl;
+  unsigned int curr_tbctrl_idx;
+  unsigned int ipa_trace_buffer_ctrl_curr;
+  unsigned int ipa_trace_buffer_ctrl_curr_old;
+  CORE_ADDR ipa_trace_buffer_ctrl_addr;
+  struct breakpoint *about_to_request_buffer_space_bkpt;
+  CORE_ADDR ipa_trace_buffer_lo;
+  CORE_ADDR ipa_trace_buffer_hi;
+
+  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
+                             &ipa_traceframe_read_count_racy))
+    {
+      /* This will happen in most targets if the current thread is
+        running.  */
+      return;
+    }
+
+  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count,
+                             &ipa_traceframe_write_count_racy))
+    return;
+
+  trace_debug ("ipa_traceframe_count (racy area): %d (w=%d, r=%d)",
+              ipa_traceframe_write_count_racy - ipa_traceframe_read_count_racy,
+              ipa_traceframe_write_count_racy, ipa_traceframe_read_count_racy);
+
+  if (ipa_traceframe_write_count_racy == ipa_traceframe_read_count_racy)
+    return;
+
+  about_to_request_buffer_space_bkpt
+    = set_breakpoint_at (ipa_sym_addrs.addr_about_to_request_buffer_space,
+                        NULL);
+
+  if (read_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
+                             &ipa_trace_buffer_ctrl_curr))
+    return;
+
+  ipa_trace_buffer_ctrl_curr_old = ipa_trace_buffer_ctrl_curr;
+
+  curr_tbctrl_idx = ipa_trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK;
+
+  {
+    unsigned int prev, counter;
+
+    /* Update the token, with new counters, and the GDBserver stamp
+       bit.  Alway reuse the current TBC index.  */
+    prev = ipa_trace_buffer_ctrl_curr & 0x0007ff00;
+    counter = (prev + 0x100) & 0x0007ff00;
+
+    ipa_trace_buffer_ctrl_curr = (0x80000000
+                                 | (prev << 12)
+                                 | counter
+                                 | curr_tbctrl_idx);
+  }
+
+  if (write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
+                              ipa_trace_buffer_ctrl_curr))
+    return;
+
+  trace_debug ("Lib: Committed %08x -> %08x",
+              ipa_trace_buffer_ctrl_curr_old,
+              ipa_trace_buffer_ctrl_curr);
+
+  /* Re-read these, now that we've installed the
+     `about_to_request_buffer_space' breakpoint/lock.  A thread could
+     have finished a traceframe between the last read of these
+     counters and setting the breakpoint above.  If we start
+     uploading, we never want to leave this function with
+     traceframe_read_count != 0, otherwise, GDBserver could end up
+     incrementing the counter tokens more than once (due to event loop
+     nesting), which would break the IP agent's "effective" detection
+     (see trace_alloc_trace_buffer).  */
+  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
+                             &ipa_traceframe_read_count))
+    return;
+  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count,
+                             &ipa_traceframe_write_count))
+    return;
+
+  if (debug_threads)
+    {
+      trace_debug ("ipa_traceframe_count (blocked area): %d (w=%d, r=%d)",
+                  ipa_traceframe_write_count - ipa_traceframe_read_count,
+                  ipa_traceframe_write_count, ipa_traceframe_read_count);
+
+      if (ipa_traceframe_write_count != ipa_traceframe_write_count_racy
+         || ipa_traceframe_read_count != ipa_traceframe_read_count_racy)
+       trace_debug ("note that ipa_traceframe_count's parts changed");
+    }
+
+  /* Get the address of the current TBC object (the IP agent has an
+     array of 3 such objects).  The index is stored in the TBC
+     token.  */
+  ipa_trace_buffer_ctrl_addr = ipa_sym_addrs.addr_trace_buffer_ctrl;
+  ipa_trace_buffer_ctrl_addr
+    += sizeof (struct ipa_trace_buffer_control) * curr_tbctrl_idx;
+
+  if (read_inferior_memory (ipa_trace_buffer_ctrl_addr,
+                           (unsigned char *) &ipa_trace_buffer_ctrl,
+                           sizeof (struct ipa_trace_buffer_control)))
+    return;
+
+  if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo,
+                                 &ipa_trace_buffer_lo))
+    return;
+  if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi,
+                                 &ipa_trace_buffer_hi))
+    return;
+
+  /* Offsets are easier to grok for debugging than raw addresses,
+     especially for the small trace buffer sizes that are useful for
+     testing.  */
+  trace_debug ("Lib: Trace buffer [%d] start=%d free=%d "
+              "endfree=%d wrap=%d hi=%d",
+              curr_tbctrl_idx,
+              (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo),
+              (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo),
+              (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo),
+              (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo),
+              (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
+
+  /* Note that the IPA's buffer is always circular.  */
+
+#define IPA_FIRST_TRACEFRAME() (ipa_trace_buffer_ctrl.start)
+
+#define IPA_NEXT_TRACEFRAME_1(TF, TFOBJ)               \
+  ((TF) + sizeof (struct traceframe) + (TFOBJ)->data_size)
+
+#define IPA_NEXT_TRACEFRAME(TF, TFOBJ)                                 \
+  (IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ)                                   \
+   - ((IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) >= ipa_trace_buffer_ctrl.wrap) \
+      ? (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo)             \
+      : 0))
+
+  tf = IPA_FIRST_TRACEFRAME ();
+
+  while (ipa_traceframe_write_count - ipa_traceframe_read_count)
+    {
+      struct tracepoint *tpoint;
+      struct traceframe *tframe;
+      unsigned char *block;
+      struct traceframe ipa_tframe;
+
+      if (read_inferior_memory (tf, (unsigned char *) &ipa_tframe,
+                               offsetof (struct traceframe, data)))
+       error ("Uploading: couldn't read traceframe at %s\n", paddress (tf));
+
+      if (ipa_tframe.tpnum == 0)
+       fatal ("Uploading: No (more) fast traceframes, but "
+              "ipa_traceframe_count == %u??\n",
+              ipa_traceframe_write_count - ipa_traceframe_read_count);
+
+      /* Note that this will be incorrect for multi-location
+        tracepoints...  */
+      tpoint = find_next_tracepoint_by_number (NULL, ipa_tframe.tpnum);
+
+      tframe = add_traceframe (tpoint);
+      if (tframe == NULL)
+       {
+         trace_buffer_is_full = 1;
+         trace_debug ("Uploading: trace buffer is full");
+       }
+      else
+       {
+         /* Copy the whole set of blocks in one go for now.  FIXME:
+            split this in smaller blocks.  */
+         block = add_traceframe_block (tframe, ipa_tframe.data_size);
+         if (block != NULL)
+           {
+             if (read_inferior_memory (tf + offsetof (struct traceframe, data),
+                                       block, ipa_tframe.data_size))
+               error ("Uploading: Couldn't read traceframe data at %s\n",
+                      paddress (tf + offsetof (struct traceframe, data)));
+           }
+
+         trace_debug ("Uploading: traceframe didn't fit");
+         finish_traceframe (tframe);
+       }
+
+      tf = IPA_NEXT_TRACEFRAME (tf, &ipa_tframe);
+
+      /* If we freed the traceframe that wrapped around, go back
+        to the non-wrap case.  */
+      if (tf < ipa_trace_buffer_ctrl.start)
+       {
+         trace_debug ("Lib: Discarding past the wraparound");
+         ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
+       }
+      ipa_trace_buffer_ctrl.start = tf;
+      ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_ctrl.start;
+      ++ipa_traceframe_read_count;
+
+      if (ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.free
+         && ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.end_free)
+       {
+         trace_debug ("Lib: buffer is fully empty.  "
+                      "Trace buffer [%d] start=%d free=%d endfree=%d",
+                      curr_tbctrl_idx,
+                      (int) (ipa_trace_buffer_ctrl.start
+                             - ipa_trace_buffer_lo),
+                      (int) (ipa_trace_buffer_ctrl.free
+                             - ipa_trace_buffer_lo),
+                      (int) (ipa_trace_buffer_ctrl.end_free
+                             - ipa_trace_buffer_lo));
+
+         ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo;
+         ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo;
+         ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi;
+         ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
+       }
+
+      trace_debug ("Uploaded a traceframe\n"
+                  "Lib: Trace buffer [%d] start=%d free=%d "
+                  "endfree=%d wrap=%d hi=%d",
+                  curr_tbctrl_idx,
+                  (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo),
+                  (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo),
+                  (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo),
+                  (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo),
+                  (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
+    }
+
+  if (write_inferior_memory (ipa_trace_buffer_ctrl_addr,
+                            (unsigned char *) &ipa_trace_buffer_ctrl,
+                            sizeof (struct ipa_trace_buffer_control)))
+    return;
+
+  write_inferior_integer (ipa_sym_addrs.addr_traceframe_read_count,
+                         ipa_traceframe_read_count);
+
+  trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx);
+
+  pause_all (1);
+  cancel_breakpoints ();
+
+  delete_breakpoint (about_to_request_buffer_space_bkpt);
+  about_to_request_buffer_space_bkpt = NULL;
+
+  unpause_all (1);
+
+  if (trace_buffer_is_full)
+    stop_tracing ();
+}
+#endif
+
+#ifdef IN_PROCESS_AGENT
+
+IP_AGENT_EXPORT int ust_loaded;
+IP_AGENT_EXPORT char cmd_buf[CMD_BUF_SIZE];
+
+#ifdef HAVE_UST
+
+/* Static tracepoints.  */
+
+/* UST puts a "struct tracepoint" in the global namespace, which
+   conflicts with our tracepoint.  Arguably, being a library, it
+   shouldn't take ownership of such a generic name.  We work around it
+   here.  */
+#define tracepoint ust_tracepoint
+#include <ust/ust.h>
+#undef tracepoint
+
+extern int serialize_to_text (char *outbuf, int bufsize,
+                             const char *fmt, va_list ap);
+
+#define GDB_PROBE_NAME "gdb"
+
+/* We dynamically search for the UST symbols instead of linking them
+   in.  This lets the user decide if the application uses static
+   tracepoints, instead of always pulling libust.so in.  This vector
+   holds pointers to all functions we care about.  */
+
+static struct
+{
+  int (*serialize_to_text) (char *outbuf, int bufsize,
+                           const char *fmt, va_list ap);
+
+  int (*ltt_probe_register) (struct ltt_available_probe *pdata);
+  int (*ltt_probe_unregister) (struct ltt_available_probe *pdata);
+
+  int (*ltt_marker_connect) (const char *channel, const char *mname,
+                            const char *pname);
+  int (*ltt_marker_disconnect) (const char *channel, const char *mname,
+                               const char *pname);
+
+  void (*marker_iter_start) (struct marker_iter *iter);
+  void (*marker_iter_next) (struct marker_iter *iter);
+  void (*marker_iter_stop) (struct marker_iter *iter);
+  void (*marker_iter_reset) (struct marker_iter *iter);
+} ust_ops;
+
+#include <dlfcn.h>
+
+/* Cast through typeof to catch incompatible API changes.  Since UST
+   only builds with gcc, we can freely use gcc extensions here
+   too.  */
+#define GET_UST_SYM(SYM)                                       \
+  do                                                           \
+    {                                                          \
+      if (ust_ops.SYM == NULL)                                 \
+       ust_ops.SYM = (typeof (&SYM)) dlsym (RTLD_DEFAULT, #SYM);       \
+      if (ust_ops.SYM == NULL)                                 \
+       return 0;                                               \
+    } while (0)
+
+#define USTF(SYM) ust_ops.SYM
+
+/* Get pointers to all libust.so functions we care about.  */
+
+static int
+dlsym_ust (void)
+{
+  GET_UST_SYM (serialize_to_text);
+
+  GET_UST_SYM (ltt_probe_register);
+  GET_UST_SYM (ltt_probe_unregister);
+  GET_UST_SYM (ltt_marker_connect);
+  GET_UST_SYM (ltt_marker_disconnect);
+
+  GET_UST_SYM (marker_iter_start);
+  GET_UST_SYM (marker_iter_next);
+  GET_UST_SYM (marker_iter_stop);
+  GET_UST_SYM (marker_iter_reset);
+
+  ust_loaded = 1;
+  return 1;
+}
+
+/* Given an UST marker, return the matching gdb static tracepoint.
+   The match is done by address.  */
+
+static struct tracepoint *
+ust_marker_to_static_tracepoint (const struct marker *mdata)
+{
+  struct tracepoint *tpoint;
+
+  for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
+    {
+      if (!tpoint->enabled || tpoint->type != static_tracepoint)
+       continue;
+
+      if (tpoint->address == (uintptr_t) mdata->location)
+       return tpoint;
+    }
+
+  return NULL;
+}
+
+/* The probe function we install on lttng/ust markers.  Whenever a
+   probed ust marker is hit, this function is called.  This is similar
+   to gdb_collect, only for static tracepoints, instead of fast
+   tracepoints.  */
+
+static void
+gdb_probe (const struct marker *mdata, void *probe_private,
+          struct registers *regs, void *call_private,
+          const char *fmt, va_list *args)
+{
+  struct tracepoint *tpoint;
+  struct static_tracepoint_ctx ctx;
+
+  /* Don't do anything until the trace run is completely set up.  */
+  if (!tracing)
+    {
+      trace_debug ("gdb_probe: not tracing\n");
+      return;
+    }
+
+  ctx.base.type = static_tracepoint;
+  ctx.regcache_initted = 0;
+  ctx.regs = regs;
+  ctx.fmt = fmt;
+  ctx.args = args;
+
+  /* Wrap the regblock in a register cache (in the stack, we don't
+     want to malloc here).  */
+  ctx.regspace = alloca (register_cache_size ());
+  if (ctx.regspace == NULL)
+    {
+      trace_debug ("Trace buffer block allocation failed, skipping");
+      return;
+    }
+
+  tpoint = ust_marker_to_static_tracepoint (mdata);
+  if (tpoint == NULL)
+    {
+      trace_debug ("gdb_probe: marker not known: "
+                  "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"",
+                  mdata->location, mdata->channel,
+                  mdata->name, mdata->format);
+      return;
+    }
+
+  ctx.tpoint = tpoint;
+
+  trace_debug ("gdb_probe: collecting marker: "
+              "loc:0x%p, ch:\"%s\",n:\"%s\",f:\"%s\"",
+              mdata->location, mdata->channel,
+              mdata->name, mdata->format);
+
+  /* Test the condition if present, and collect if true.  */
+  if (tpoint->cond == NULL
+      || condition_true_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
+                                      tpoint))
+    {
+      collect_data_at_tracepoint ((struct tracepoint_hit_ctx *) &ctx,
+                                 tpoint->address, tpoint);
+
+      if (stopping_tracepoint
+         || trace_buffer_is_full
+         || expr_eval_result != expr_eval_no_error)
+       stop_tracing ();
+    }
+  else
+    {
+      /* If there was a condition and it evaluated to false, the only
+        way we would stop tracing is if there was an error during
+        condition expression evaluation.  */
+      if (expr_eval_result != expr_eval_no_error)
+       stop_tracing ();
+    }
+}
+
+/* Called if the gdb static tracepoint requested collecting "$_sdata",
+   static tracepoint string data.  This is a string passed to the
+   tracing library by the user, at the time of the tracepoint marker
+   call.  E.g., in the UST marker call:
+
+     trace_mark (ust, bar33, "str %s", "FOOBAZ");
+
+   the collected data is "str FOOBAZ".
+*/
+
+static void
+collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
+                               CORE_ADDR stop_pc,
+                               struct tracepoint *tpoint,
+                               struct traceframe *tframe)
+{
+  struct static_tracepoint_ctx *umd = (struct static_tracepoint_ctx *) ctx;
+  unsigned char *bufspace;
+  int size;
+  va_list copy;
+  unsigned short blocklen;
+
+  if (umd == NULL)
+    {
+      trace_debug ("Wanted to collect static trace data, "
+                  "but there's no static trace data");
+      return;
+    }
+
+  va_copy (copy, *umd->args);
+  size = USTF(serialize_to_text) (NULL, 0, umd->fmt, copy);
+  va_end (copy);
+
+  trace_debug ("Want to collect ust data");
+
+  /* 'S' + size + string */
+  bufspace = add_traceframe_block (tframe,
+                                  1 + sizeof (blocklen) + size + 1);
+  if (bufspace == NULL)
+    {
+      trace_debug ("Trace buffer block allocation failed, skipping");
+      return;
+    }
+
+  /* Identify a static trace data block.  */
+  *bufspace = 'S';
+
+  blocklen = size + 1;
+  memcpy (bufspace + 1, &blocklen, sizeof (blocklen));
+
+  va_copy (copy, *umd->args);
+  USTF(serialize_to_text) ((char *) bufspace + 1 + sizeof (blocklen),
+                          size + 1, umd->fmt, copy);
+  va_end (copy);
+
+  trace_debug ("Storing static tracepoint data in regblock: %s",
+              bufspace + 1 + sizeof (blocklen));
+}
+
+/* The probe to register with lttng/ust.  */
+static struct ltt_available_probe gdb_ust_probe =
+  {
+    GDB_PROBE_NAME,
+    NULL,
+    gdb_probe,
+  };
+
+#endif /* HAVE_UST */
+#endif /* IN_PROCESS_AGENT */
+
+#ifdef HAVE_UST
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path)
+#endif
+
+/* Where we put the socked used for synchronization.  */
+#define SOCK_DIR P_tmpdir
+
+#endif /* HAVE_UST */
+
+#ifndef IN_PROCESS_AGENT
+
+#ifdef HAVE_UST
+
+static int
+gdb_ust_connect_sync_socket (int pid)
+{
+  struct sockaddr_un addr;
+  int res, fd;
+  char path[UNIX_PATH_MAX];
+
+  res = snprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", SOCK_DIR, pid);
+  if (res >= UNIX_PATH_MAX)
+    {
+      trace_debug ("string overflow allocating socket name");
+      return -1;
+    }
 
-  for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
+  res = fd = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (res == -1)
     {
-      struct tracepoint target_tracepoint;
+      warning ("error opening sync socket: %s\n", strerror (errno));
+      return -1;
+    }
 
-      if (tpoint->type != fast_tracepoint)
-       continue;
+  addr.sun_family = AF_UNIX;
 
-      target_tracepoint = *tpoint;
+  res = snprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path);
+  if (res >= UNIX_PATH_MAX)
+    {
+      warning ("string overflow allocating socket name\n");
+      close (fd);
+      return -1;
+    }
 
-      prev_tpptr = tpptr;
-      tpptr = target_malloc (sizeof (*tpoint));
-      tpoint->obj_addr_on_target = tpptr;
+  res = connect (fd, (struct sockaddr *) &addr, sizeof (addr));
+  if (res == -1)
+    {
+      warning ("error connecting sync socket (%s): %s. "
+              "Make sure the directory exists and that it is writable.",
+              path, strerror (errno));
+      close (fd);
+      return -1;
+    }
 
-      if (tpoint == tracepoints)
-       {
-         /* First object in list, set the head pointer in the
-            inferior.  */
-         write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr);
-       }
-      else
-       {
-         write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint,
-                                                         next),
-                                  tpptr);
-       }
+  return fd;
+}
 
-      /* Write the whole object.  We'll fix up its pointers in a bit.
-        Assume no next for now.  This is fixed up above on the next
-        iteration, if there's any.  */
-      target_tracepoint.next = NULL;
-      /* Need to clear this here too, since we're downloading the
-        tracepoints before clearing our own copy.  */
-      target_tracepoint.hit_count = 0;
+/* Resume thread PTID.  */
 
-      write_inferior_memory (tpptr, (unsigned char *) &target_tracepoint,
-                            sizeof (target_tracepoint));
+static void
+resume_thread (ptid_t ptid)
+{
+  struct thread_resume resume_info;
 
-      if (tpoint->cond)
-       write_inferior_data_ptr (tpptr + offsetof (struct tracepoint,
-                                                  cond),
-                                download_agent_expr (tpoint->cond));
+  resume_info.thread = ptid;
+  resume_info.kind = resume_continue;
+  resume_info.sig = TARGET_SIGNAL_0;
+  (*the_target->resume) (&resume_info, 1);
+}
 
-      if (tpoint->numactions)
-       {
-         int i;
-         CORE_ADDR actions_array;
+/* Stop thread PTID.  */
 
-         /* The pointers array.  */
-         actions_array
-           = target_malloc (sizeof (*tpoint->actions) * tpoint->numactions);
-         write_inferior_data_ptr (tpptr + offsetof (struct tracepoint,
-                                                    actions),
-                                  actions_array);
+static void
+stop_thread (ptid_t ptid)
+{
+  struct thread_resume resume_info;
 
-         /* Now for each pointer, download the action.  */
-         for (i = 0; i < tpoint->numactions; i++)
-           {
-             CORE_ADDR ipa_action = 0;
-             struct tracepoint_action *action = tpoint->actions[i];
+  resume_info.thread = ptid;
+  resume_info.kind = resume_stop;
+  resume_info.sig = TARGET_SIGNAL_0;
+  (*the_target->resume) (&resume_info, 1);
+}
 
-             switch (action->type)
-               {
-               case 'M':
-                 ipa_action
-                   = target_malloc (sizeof (struct collect_memory_action));
-                 write_inferior_memory (ipa_action,
-                                        (unsigned char *) action,
-                                        sizeof (struct collect_memory_action));
-                 break;
-               case 'R':
-                 ipa_action
-                   = target_malloc (sizeof (struct collect_registers_action));
-                 write_inferior_memory (ipa_action,
-                                        (unsigned char *) action,
-                                        sizeof (struct collect_registers_action));
-                 break;
-               case 'X':
-                 {
-                   CORE_ADDR expr;
-                   struct eval_expr_action *eaction
-                     = (struct eval_expr_action *) action;
+/* Ask the in-process agent to run a command.  Since we don't want to
+   have to handle the IPA hitting breakpoints while running the
+   command, we pause all threads, remove all breakpoints, and then set
+   the helper thread re-running.  We communicate with the helper
+   thread by means of direct memory xfering, and a socket for
+   synchronization.  */
 
-                   ipa_action = target_malloc (sizeof (*eaction));
-                   write_inferior_memory (ipa_action,
-                                          (unsigned char *) eaction,
-                                          sizeof (*eaction));
+static int
+run_inferior_command (char *cmd)
+{
+  int err = -1;
+  int fd = -1;
+  int pid = ptid_get_pid (current_inferior->entry.id);
+  int tid;
+  ptid_t ptid = null_ptid;
 
-                   expr = download_agent_expr (eaction->expr);
-                   write_inferior_data_ptr
-                     (ipa_action + offsetof (struct eval_expr_action, expr),
-                      expr);
-                   break;
-                 }
-               default:
-                 trace_debug ("unknown trace action '%c', ignoring",
-                              action->type);
-                 break;
-               }
+  trace_debug ("run_inferior_command: running: %s", cmd);
 
-             if (ipa_action != 0)
-               write_inferior_data_ptr
-                 (actions_array + i * sizeof (sizeof (*tpoint->actions)),
-                  ipa_action);
-           }
-       }
+  pause_all (0);
+  uninsert_all_breakpoints ();
+
+  if (read_inferior_integer (ipa_sym_addrs.addr_helper_thread_id, &tid))
+    {
+      warning ("Error reading helper thread's id in lib");
+      goto out;
     }
-}
 
-static void
-download_trace_state_variables (void)
-{
-  CORE_ADDR ptr = 0, prev_ptr = 0;
-  struct trace_state_variable *tsv;
+  if (tid == 0)
+    {
+      warning ("helper thread not initialized yet");
+      goto out;
+    }
 
-  /* Start out empty.  */
-  write_inferior_data_ptr (ipa_sym_addrs.addr_trace_state_variables, 0);
+  if (write_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
+                            (unsigned char *) cmd, strlen (cmd) + 1))
+    {
+      warning ("Error writing command");
+      goto out;
+    }
 
-  for (tsv = trace_state_variables; tsv != NULL; tsv = tsv->next)
+  ptid = ptid_build (pid, tid, 0);
+
+  resume_thread (ptid);
+
+  fd = gdb_ust_connect_sync_socket (pid);
+  if (fd >= 0)
     {
-      struct trace_state_variable target_tsv;
+      char buf[1] = "";
+      int ret;
 
-      /* TSV's with a getter have been initialized equally in both the
-        inferior and GDBserver.  Skip them.  */
-      if (tsv->getter != NULL)
-       continue;
+      trace_debug ("signalling helper thread");
 
-      target_tsv = *tsv;
+      do
+       {
+         ret = write (fd, buf, 1);
+       } while (ret == -1 && errno == EINTR);
 
-      prev_ptr = ptr;
-      ptr = target_malloc (sizeof (*tsv));
+      trace_debug ("waiting for helper thread's response");
 
-      if (tsv == trace_state_variables)
+      do
        {
-         /* First object in list, set the head pointer in the
-            inferior.  */
+         ret = read (fd, buf, 1);
+       } while (ret == -1 && errno == EINTR);
 
-         write_inferior_data_ptr (ipa_sym_addrs.addr_trace_state_variables,
-                                  ptr);
+      close (fd);
+
+      trace_debug ("helper thread's response received");
+    }
+
+ out:
+
+  /* Need to read response with the inferior stopped.  */
+  if (!ptid_equal (ptid, null_ptid))
+    {
+      int was_non_stop = non_stop;
+      struct target_waitstatus status;
+
+      stop_thread (ptid);
+      non_stop = 1;
+      mywait (ptid, &status, 0, 0);
+      non_stop = was_non_stop;
+    }
+
+  if (fd >= 0)
+    {
+      if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
+                               (unsigned char *) cmd, CMD_BUF_SIZE))
+       {
+         warning ("Error reading command response");
        }
       else
        {
-         write_inferior_data_ptr (prev_ptr
-                                  + offsetof (struct trace_state_variable,
-                                              next),
-                                  ptr);
+         err = 0;
+         trace_debug ("run_inferior_command: response: %s", cmd);
        }
+    }
 
-      /* Write the whole object.  We'll fix up its pointers in a bit.
-        Assume no next, fixup when needed.  */
-      target_tsv.next = NULL;
+  reinsert_all_breakpoints ();
+  unpause_all (0);
 
-      write_inferior_memory (ptr, (unsigned char *) &target_tsv,
-                            sizeof (target_tsv));
+  return err;
+}
 
-      if (tsv->name != NULL)
-       {
-         size_t size = strlen (tsv->name) + 1;
-         CORE_ADDR name_addr = target_malloc (size);
-         write_inferior_memory (name_addr,
-                                (unsigned char *) tsv->name, size);
-         write_inferior_data_ptr (ptr
-                                  + offsetof (struct trace_state_variable,
-                                              name),
-                                  name_addr);
-       }
+#else /* HAVE_UST */
 
-      if (tsv->getter != NULL)
+static int
+run_inferior_command (char *cmd)
+{
+  return -1;
+}
+
+#endif /* HAVE_UST */
+
+#else /* !IN_PROCESS_AGENT */
+
+/* Thread ID of the helper thread.  GDBserver reads this to know which
+   is the help thread.  This is an LWP id on Linux.  */
+int helper_thread_id;
+
+#ifdef HAVE_UST
+
+static int
+init_named_socket (const char *name)
+{
+  int result, fd;
+  struct sockaddr_un addr;
+
+  result = fd = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (result == -1)
+    {
+      warning ("socket creation failed: %s", strerror (errno));
+      return -1;
+    }
+
+  addr.sun_family = AF_UNIX;
+
+  strncpy (addr.sun_path, name, UNIX_PATH_MAX);
+  addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
+
+  result = access (name, F_OK);
+  if (result == 0)
+    {
+      /* File exists.  */
+      result = unlink (name);
+      if (result == -1)
        {
-         fatal ("what to do with these?");
+         warning ("unlink failed: %s", strerror (errno));
+         close (fd);
+         return -1;
        }
+      warning ("socket %s already exists; overwriting", name);
     }
 
-  if (prev_ptr != 0)
+  result = bind (fd, (struct sockaddr *) &addr, sizeof (addr));
+  if (result == -1)
     {
-      /* Fixup the next pointer in the last item in the list.  */
-      write_inferior_data_ptr (prev_ptr + offsetof (struct trace_state_variable,
-                                                   next), 0);
+      warning ("bind failed: %s", strerror (errno));
+      close (fd);
+      return -1;
+    }
+
+  result = listen (fd, 1);
+  if (result == -1)
+    {
+      warning ("listen: %s", strerror (errno));
+      close (fd);
+      return -1;
     }
+
+  return fd;
 }
 
-/* Upload complete trace frames out of the IP Agent's trace buffer
-   into GDBserver's trace buffer.  This always uploads either all or
-   no trace frames.  This is the counter part of
-   `trace_alloc_trace_buffer'.  See its description of the atomic
-   synching mechanism.  */
+static int
+gdb_ust_socket_init (void)
+{
+  int result, fd;
+  char name[UNIX_PATH_MAX];
+
+  result = snprintf (name, UNIX_PATH_MAX, "%s/gdb_ust%d",
+                    SOCK_DIR, getpid ());
+  if (result >= UNIX_PATH_MAX)
+    {
+      trace_debug ("string overflow allocating socket name");
+      return -1;
+    }
+
+  fd = init_named_socket (name);
+  if (fd < 0)
+    warning ("Error initializing named socket (%s) for communication with the "
+            "ust helper thread. Check that directory exists and that it "
+            "is writable.", name);
+
+  return fd;
+}
+
+/* Return an hexstr version of the STR C string, fit for sending to
+   GDB.  */
+
+static char *
+cstr_to_hexstr (const char *str)
+{
+  int len = strlen (str);
+  char *hexstr = xmalloc (len * 2 + 1);
+  convert_int_to_ascii ((gdb_byte *) str, hexstr, len);
+  return hexstr;
+}
+
+/* The next marker to be returned on a qTsSTM command.  */
+static const struct marker *next_st;
+
+/* Returns the first known marker.  */
+
+struct marker *
+first_marker (void)
+{
+  struct marker_iter iter;
+
+  USTF(marker_iter_reset) (&iter);
+  USTF(marker_iter_start) (&iter);
+
+  return iter.marker;
+}
+
+/* Returns the marker following M.  */
+
+const struct marker *
+next_marker (const struct marker *m)
+{
+  struct marker_iter iter;
+
+  USTF(marker_iter_reset) (&iter);
+  USTF(marker_iter_start) (&iter);
+
+  for (; iter.marker != NULL; USTF(marker_iter_next) (&iter))
+    {
+      if (iter.marker == m)
+       {
+         USTF(marker_iter_next) (&iter);
+         return iter.marker;
+       }
+    }
+
+  return NULL;
+}
+
+/* Compose packet that is the response to the qTsSTM/qTfSTM/qTSTMat
+   packets.  */
 
 static void
-upload_fast_traceframes (void)
+response_ust_marker (char *packet, const struct marker *st)
 {
-  unsigned int ipa_traceframe_read_count, ipa_traceframe_write_count;
-  unsigned int ipa_traceframe_read_count_racy, ipa_traceframe_write_count_racy;
-  CORE_ADDR tf;
-  struct ipa_trace_buffer_control ipa_trace_buffer_ctrl;
-  unsigned int curr_tbctrl_idx;
-  unsigned int ipa_trace_buffer_ctrl_curr;
-  unsigned int ipa_trace_buffer_ctrl_curr_old;
-  CORE_ADDR ipa_trace_buffer_ctrl_addr;
-  struct breakpoint *about_to_request_buffer_space_bkpt;
-  CORE_ADDR ipa_trace_buffer_lo;
-  CORE_ADDR ipa_trace_buffer_hi;
+  char *strid, *format, *tmp;
+
+  next_st = next_marker (st);
+
+  tmp = xmalloc (strlen (st->channel) + 1 +
+                strlen (st->name) + 1);
+  sprintf (tmp, "%s/%s", st->channel, st->name);
+
+  strid = cstr_to_hexstr (tmp);
+  free (tmp);
+
+  format = cstr_to_hexstr (st->format);
+
+  sprintf (packet, "m%s:%s:%s",
+          paddress ((uintptr_t) st->location),
+          strid,
+          format);
+
+  free (strid);
+  free (format);
+}
+
+/* Return the first static tracepoint, and initialize the state
+   machine that will iterate through all the static tracepoints.  */
 
-  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
-                             &ipa_traceframe_read_count_racy))
-    {
-      /* This will happen in most targets if the current thread is
-        running.  */
-      return;
-    }
+static void
+cmd_qtfstm (char *packet)
+{
+  trace_debug ("Returning first trace state variable definition");
 
-  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count,
-                             &ipa_traceframe_write_count_racy))
-    return;
+  if (first_marker ())
+    response_ust_marker (packet, first_marker ());
+  else
+    strcpy (packet, "l");
+}
 
-  trace_debug ("ipa_traceframe_count (racy area): %d (w=%d, r=%d)",
-              ipa_traceframe_write_count_racy - ipa_traceframe_read_count_racy,
-              ipa_traceframe_write_count_racy, ipa_traceframe_read_count_racy);
+/* Return additional trace state variable definitions. */
 
-  if (ipa_traceframe_write_count_racy == ipa_traceframe_read_count_racy)
-    return;
+static void
+cmd_qtsstm (char *packet)
+{
+  trace_debug ("Returning static tracepoint");
 
-  about_to_request_buffer_space_bkpt
-    = set_breakpoint_at (ipa_sym_addrs.addr_about_to_request_buffer_space,
-                        NULL);
+  if (next_st)
+    response_ust_marker (packet, next_st);
+  else
+    strcpy (packet, "l");
+}
 
-  if (read_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
-                             &ipa_trace_buffer_ctrl_curr))
-    return;
+/* Disconnect the GDB probe from a marker at a given address.  */
 
-  ipa_trace_buffer_ctrl_curr_old = ipa_trace_buffer_ctrl_curr;
+static void
+unprobe_marker_at (char *packet)
+{
+  char *p = packet;
+  ULONGEST address;
+  struct marker_iter iter;
 
-  curr_tbctrl_idx = ipa_trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK;
+  p += sizeof ("unprobe_marker_at:") - 1;
 
-  {
-    unsigned int prev, counter;
+  p = unpack_varlen_hex (p, &address);
 
-    /* Update the token, with new counters, and the GDBserver stamp
-       bit.  Alway reuse the current TBC index.  */
-    prev = ipa_trace_buffer_ctrl_curr & 0x0007ff00;
-    counter = (prev + 0x100) & 0x0007ff00;
+  USTF(marker_iter_reset) (&iter);
+  USTF(marker_iter_start) (&iter);
+  for (; iter.marker != NULL; USTF(marker_iter_next) (&iter))
+    if ((uintptr_t ) iter.marker->location == address)
+      {
+       int result;
+
+       result = USTF(ltt_marker_disconnect) (iter.marker->channel,
+                                             iter.marker->name,
+                                             GDB_PROBE_NAME);
+       if (result < 0)
+         warning ("could not disable marker %s/%s",
+                  iter.marker->channel, iter.marker->name);
+       break;
+      }
+}
 
-    ipa_trace_buffer_ctrl_curr = (0x80000000
-                                 | (prev << 12)
-                                 | counter
-                                 | curr_tbctrl_idx);
-  }
+/* Connect the GDB probe to a marker at a given address.  */
 
-  if (write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr,
-                              ipa_trace_buffer_ctrl_curr))
-    return;
+static int
+probe_marker_at (char *packet)
+{
+  char *p = packet;
+  ULONGEST address;
+  struct marker_iter iter;
+  struct marker *m;
 
-  trace_debug ("Lib: Committed %08x -> %08x",
-              ipa_trace_buffer_ctrl_curr_old,
-              ipa_trace_buffer_ctrl_curr);
+  p += sizeof ("probe_marker_at:") - 1;
 
-  /* Re-read these, now that we've installed the
-     `about_to_request_buffer_space' breakpoint/lock.  A thread could
-     have finished a traceframe between the last read of these
-     counters and setting the breakpoint above.  If we start
-     uploading, we never want to leave this function with
-     traceframe_read_count != 0, otherwise, GDBserver could end up
-     incrementing the counter tokens more than once (due to event loop
-     nesting), which would break the IP agent's "effective" detection
-     (see trace_alloc_trace_buffer).  */
-  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_read_count,
-                             &ipa_traceframe_read_count))
-    return;
-  if (read_inferior_uinteger (ipa_sym_addrs.addr_traceframe_write_count,
-                             &ipa_traceframe_write_count))
-    return;
+  p = unpack_varlen_hex (p, &address);
 
-  if (debug_threads)
-    {
-      trace_debug ("ipa_traceframe_count (blocked area): %d (w=%d, r=%d)",
-                  ipa_traceframe_write_count - ipa_traceframe_read_count,
-                  ipa_traceframe_write_count, ipa_traceframe_read_count);
+  USTF(marker_iter_reset) (&iter);
 
-      if (ipa_traceframe_write_count != ipa_traceframe_write_count_racy
-         || ipa_traceframe_read_count != ipa_traceframe_read_count_racy)
-       trace_debug ("note that ipa_traceframe_count's parts changed");
-    }
+  for (USTF(marker_iter_start) (&iter), m = iter.marker;
+       m != NULL;
+       USTF(marker_iter_next) (&iter), m = iter.marker)
+    if ((uintptr_t ) m->location == address)
+      {
+       int result;
 
-  /* Get the address of the current TBC object (the IP agent has an
-     array of 3 such objects).  The index is stored in the TBC
-     token.  */
-  ipa_trace_buffer_ctrl_addr = ipa_sym_addrs.addr_trace_buffer_ctrl;
-  ipa_trace_buffer_ctrl_addr
-    += sizeof (struct ipa_trace_buffer_control) * curr_tbctrl_idx;
+       trace_debug ("found marker for address.  "
+                    "ltt_marker_connect (marker = %s/%s)",
+                    m->channel, m->name);
 
-  if (read_inferior_memory (ipa_trace_buffer_ctrl_addr,
-                           (unsigned char *) &ipa_trace_buffer_ctrl,
-                           sizeof (struct ipa_trace_buffer_control)))
-    return;
+       result = USTF(ltt_marker_connect) (m->channel, m->name, GDB_PROBE_NAME);
+       if (result && result != -EEXIST)
+         trace_debug ("ltt_marker_connect (marker = %s/%s, errno = %d)",
+                      m->channel, m->name, -result);
 
-  if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_lo,
-                                 &ipa_trace_buffer_lo))
-    return;
-  if (read_inferior_data_pointer (ipa_sym_addrs.addr_trace_buffer_hi,
-                                 &ipa_trace_buffer_hi))
-    return;
+       if (result < 0)
+         {
+           sprintf (packet, "E.could not connect marker: channel=%s, name=%s",
+                    m->channel, m->name);
+           return -1;
+         }
 
-  /* Offsets are easier to grok for debugging than raw addresses,
-     especially for the small trace buffer sizes that are useful for
-     testing.  */
-  trace_debug ("Lib: Trace buffer [%d] start=%d free=%d "
-              "endfree=%d wrap=%d hi=%d",
-              curr_tbctrl_idx,
-              (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo),
-              (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo),
-              (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo),
-              (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo),
-              (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
+       strcpy (packet, "OK");
+       return 0;
+      }
 
-  /* Note that the IPA's buffer is always circular.  */
+  sprintf (packet, "E.no marker found at 0x%s", paddress (address));
+  return -1;
+}
 
-#define IPA_FIRST_TRACEFRAME() (ipa_trace_buffer_ctrl.start)
+static int
+cmd_qtstmat (char *packet)
+{
+  char *p = packet;
+  ULONGEST address;
+  struct marker_iter iter;
+  struct marker *m;
 
-#define IPA_NEXT_TRACEFRAME_1(TF, TFOBJ)               \
-  ((TF) + sizeof (struct traceframe) + (TFOBJ)->data_size)
+  p += sizeof ("qTSTMat:") - 1;
 
-#define IPA_NEXT_TRACEFRAME(TF, TFOBJ)                                 \
-  (IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ)                                   \
-   - ((IPA_NEXT_TRACEFRAME_1 (TF, TFOBJ) >= ipa_trace_buffer_ctrl.wrap) \
-      ? (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo)             \
-      : 0))
+  p = unpack_varlen_hex (p, &address);
 
-  tf = IPA_FIRST_TRACEFRAME ();
+  USTF(marker_iter_reset) (&iter);
 
-  while (ipa_traceframe_write_count - ipa_traceframe_read_count)
-    {
-      struct tracepoint *tpoint;
-      struct traceframe *tframe;
-      unsigned char *block;
-      struct traceframe ipa_tframe;
+  for (USTF(marker_iter_start) (&iter), m = iter.marker;
+       m != NULL;
+       USTF(marker_iter_next) (&iter), m = iter.marker)
+    if ((uintptr_t ) m->location == address)
+      {
+       response_ust_marker (packet, m);
+       return 0;
+      }
 
-      if (read_inferior_memory (tf, (unsigned char *) &ipa_tframe,
-                               offsetof (struct traceframe, data)))
-       error ("Uploading: couldn't read traceframe at %s\n", paddress (tf));
+  strcpy (packet, "l");
+  return -1;
+}
 
-      if (ipa_tframe.tpnum == 0)
-       fatal ("Uploading: No (more) fast traceframes, but "
-              "ipa_traceframe_count == %u??\n",
-              ipa_traceframe_write_count - ipa_traceframe_read_count);
+static void *
+gdb_ust_thread (void *arg)
+{
+  int listen_fd;
 
-      /* Note that this will be incorrect for multi-location
-        tracepoints...  */
-      tpoint = find_next_tracepoint_by_number (NULL, ipa_tframe.tpnum);
+  while (1)
+    {
+      listen_fd = gdb_ust_socket_init ();
 
-      tframe = add_traceframe (tpoint);
-      if (tframe == NULL)
+#ifdef SYS_gettid
+      if (helper_thread_id == 0)
+       helper_thread_id = syscall (SYS_gettid);
+#endif
+
+      if (listen_fd == -1)
        {
-         trace_buffer_is_full = 1;
-         trace_debug ("Uploading: trace buffer is full");
+         warning ("could not create sync socket\n");
+         break;
        }
-      else
+
+      while (1)
        {
-         /* Copy the whole set of blocks in one go for now.  FIXME:
-            split this in smaller blocks.  */
-         block = add_traceframe_block (tframe, ipa_tframe.data_size);
-         if (block != NULL)
+         socklen_t tmp;
+         struct sockaddr_un sockaddr;
+         int fd;
+         char buf[1];
+         int ret;
+
+         tmp = sizeof (sockaddr);
+
+         do
            {
-             if (read_inferior_memory (tf + offsetof (struct traceframe, data),
-                                       block, ipa_tframe.data_size))
-               error ("Uploading: Couldn't read traceframe data at %s\n",
-                      paddress (tf + offsetof (struct traceframe, data)));
+             fd = accept (listen_fd, &sockaddr, &tmp);
            }
+         /* It seems an ERESTARTSYS can escape out of accept.  */
+         while (fd == -512 || (fd == -1 && errno == EINTR));
 
-         trace_debug ("Uploading: traceframe didn't fit");
-         finish_traceframe (tframe);
-       }
+         if (fd < 0)
+           {
+             warning ("Accept returned %d, error: %s\n",
+                      fd, strerror (errno));
+             break;
+           }
 
-      tf = IPA_NEXT_TRACEFRAME (tf, &ipa_tframe);
+         do
+           {
+             ret = read (fd, buf, 1);
+           } while (ret == -1 && errno == EINTR);
 
-      /* If we freed the traceframe that wrapped around, go back
-        to the non-wrap case.  */
-      if (tf < ipa_trace_buffer_ctrl.start)
-       {
-         trace_debug ("Lib: Discarding past the wraparound");
-         ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
-       }
-      ipa_trace_buffer_ctrl.start = tf;
-      ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_ctrl.start;
-      ++ipa_traceframe_read_count;
+         if (ret == -1)
+           {
+             warning ("reading socket (fd=%d) failed with %s",
+                      fd, strerror (errno));
+             close (fd);
+             break;
+           }
 
-      if (ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.free
-         && ipa_trace_buffer_ctrl.start == ipa_trace_buffer_ctrl.end_free)
-       {
-         trace_debug ("Lib: buffer is fully empty.  "
-                      "Trace buffer [%d] start=%d free=%d endfree=%d",
-                      curr_tbctrl_idx,
-                      (int) (ipa_trace_buffer_ctrl.start
-                             - ipa_trace_buffer_lo),
-                      (int) (ipa_trace_buffer_ctrl.free
-                             - ipa_trace_buffer_lo),
-                      (int) (ipa_trace_buffer_ctrl.end_free
-                             - ipa_trace_buffer_lo));
+         if (cmd_buf[0])
+           {
+             if (strcmp ("qTfSTM", cmd_buf) == 0)
+               {
+                 cmd_qtfstm (cmd_buf);
+               }
+             else if (strcmp ("qTsSTM", cmd_buf) == 0)
+               {
+                 cmd_qtsstm (cmd_buf);
+               }
+             else if (strncmp ("unprobe_marker_at:",
+                               cmd_buf,
+                               sizeof ("unprobe_marker_at:") - 1) == 0)
+               {
+                 unprobe_marker_at (cmd_buf);
+               }
+             else if (strncmp ("probe_marker_at:",
+                               cmd_buf,
+                               sizeof ("probe_marker_at:") - 1) == 0)
+               {
+                 probe_marker_at (cmd_buf);
+               }
+             else if (strncmp ("qTSTMat:",
+                               cmd_buf,
+                               sizeof ("qTSTMat:") - 1) == 0)
+               {
+                 cmd_qtstmat (cmd_buf);
+               }
+             else if (strcmp (cmd_buf, "help") == 0)
+               {
+                 strcpy (cmd_buf, "for help, press F1\n");
+               }
+             else
+               strcpy (cmd_buf, "");
+           }
 
-         ipa_trace_buffer_ctrl.start = ipa_trace_buffer_lo;
-         ipa_trace_buffer_ctrl.free = ipa_trace_buffer_lo;
-         ipa_trace_buffer_ctrl.end_free = ipa_trace_buffer_hi;
-         ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
+         write (fd, buf, 1);
+         close (fd);
        }
-
-      trace_debug ("Uploaded a traceframe\n"
-                  "Lib: Trace buffer [%d] start=%d free=%d "
-                  "endfree=%d wrap=%d hi=%d",
-                  curr_tbctrl_idx,
-                  (int) (ipa_trace_buffer_ctrl.start - ipa_trace_buffer_lo),
-                  (int) (ipa_trace_buffer_ctrl.free - ipa_trace_buffer_lo),
-                  (int) (ipa_trace_buffer_ctrl.end_free - ipa_trace_buffer_lo),
-                  (int) (ipa_trace_buffer_ctrl.wrap - ipa_trace_buffer_lo),
-                  (int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
     }
 
-  if (write_inferior_memory (ipa_trace_buffer_ctrl_addr,
-                            (unsigned char *) &ipa_trace_buffer_ctrl,
-                            sizeof (struct ipa_trace_buffer_control)))
+  return NULL;
+}
+
+#include <signal.h>
+
+static void
+gdb_ust_init (void)
+{
+  int res;
+  pthread_t thread;
+  sigset_t new_mask;
+  sigset_t orig_mask;
+
+  if (!dlsym_ust ())
     return;
 
-  write_inferior_integer (ipa_sym_addrs.addr_traceframe_read_count,
-                         ipa_traceframe_read_count);
+  /* We want the helper thread to be as transparent as possible, so
+     have it inherit an all-signals-blocked mask.  */
 
-  trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx);
+  sigfillset (&new_mask);
+  res = pthread_sigmask (SIG_SETMASK, &new_mask, &orig_mask);
+  if (res)
+    fatal ("pthread_sigmask (1) failed: %s", strerror (res));
 
-  pause_all (1);
-  cancel_breakpoints ();
+  res = pthread_create (&thread,
+                       NULL,
+                       gdb_ust_thread,
+                       NULL);
 
-  delete_breakpoint (about_to_request_buffer_space_bkpt);
-  about_to_request_buffer_space_bkpt = NULL;
+  res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL);
+  if (res)
+    fatal ("pthread_sigmask (2) failed: %s", strerror (res));
 
-  unpause_all (1);
+  while (helper_thread_id == 0)
+    usleep (1);
 
-  if (trace_buffer_is_full)
-    stop_tracing ();
+  USTF(ltt_probe_register) (&gdb_ust_probe);
 }
-#endif
 
-#ifdef IN_PROCESS_AGENT
+#endif /* HAVE_UST */
 
 #include <sys/mman.h>
 #include <fcntl.h>
@@ -5464,9 +7340,13 @@ static void __attribute__ ((constructor))
 initialize_tracepoint_ftlib (void)
 {
   initialize_tracepoint ();
-}
 
+#ifdef HAVE_UST
+  gdb_ust_init ();
 #endif
+}
+
+#endif /* IN_PROCESS_AGENT */
 
 static LONGEST
 tsv_get_timestamp (void)
This page took 0.052074 seconds and 4 git commands to generate.