2011-01-05 Michael Snyder <msnyder@msnyder-server.eng.vmware.com>
[deliverable/binutils-gdb.git] / gdb / gdbserver / tracepoint.c
index 6557749273393aabb6d27603bee142382e5335d4..c9e9ead3271ab1498b320e55bfd5a5e57fd3869e 100644 (file)
@@ -1,5 +1,5 @@
 /* Tracepoint code for remote server for GDB.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -22,9 +22,6 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <stddef.h>
-#if HAVE_MALLOC_H
-#include <malloc.h>
-#endif
 #if HAVE_STDINT_H
 #include <stdint.h>
 #endif
@@ -133,8 +130,13 @@ trace_vdebug (const char *fmt, ...)
 # 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 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
@@ -168,11 +170,14 @@ struct ipa_sym_addresses
   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
 #define STRINGIZE(STR) STRINGIZE_1(STR)
-#define IPA_SYM(SYM)                           \
+#define IPA_SYM(SYM)                                   \
   {                                                    \
     STRINGIZE (gdb_agent_ ## SYM),                     \
     offsetof (struct ipa_sym_addresses, addr_ ## SYM)  \
@@ -209,6 +214,9 @@ static struct
   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;
@@ -223,14 +231,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)
 {
@@ -242,6 +291,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
@@ -347,6 +416,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)
 {
@@ -542,6 +613,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.  */
@@ -569,6 +646,10 @@ 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;
@@ -667,8 +748,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
 
@@ -1157,6 +1238,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
@@ -1228,6 +1338,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
@@ -1756,6 +1870,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;
@@ -2147,6 +2273,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.  */
@@ -2186,6 +2323,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;
@@ -2258,6 +2408,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;
@@ -2570,12 +2725,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;
 
@@ -2614,6 +2796,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.  */
@@ -2699,6 +2884,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.  */
@@ -3039,6 +3250,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)
     {
@@ -3213,6 +3426,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.  */
@@ -3384,6 +3627,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;
 }
@@ -3697,6 +3955,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.  */
 
@@ -3803,6 +4069,27 @@ 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)
     {
@@ -3843,13 +4130,10 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
       }
     case 'R':
       {
-       struct collect_registers_action *raction;
-
        unsigned char *regspace;
        struct regcache tregcache;
        struct regcache *context_regcache;
 
-       raction = (struct collect_registers_action *) taction;
 
        trace_debug ("Want to collect registers");
 
@@ -3910,6 +4194,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;
@@ -4494,6 +4790,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);
@@ -4598,7 +4899,8 @@ traceframe_read_mem (int tfnum, CORE_ADDR addr,
 
   /* Iterate through a traceframe's blocks, looking for memory.  */
   while ((dataptr = traceframe_find_block_type (dataptr,
-                                               datasize - (dataptr - database),
+                                               datasize
+                                               - (dataptr - database),
                                                tfnum, 'M')) != NULL)
     {
       memcpy (&maddr, dataptr, sizeof (maddr));
@@ -4660,7 +4962,8 @@ traceframe_read_tsv (int tsvnum, LONGEST *val)
 
   /* Iterate through a traceframe's blocks, looking for the tsv.  */
   while ((dataptr = traceframe_find_block_type (dataptr,
-                                               datasize - (dataptr - database),
+                                               datasize
+                                               - (dataptr - database),
                                                tfnum, 'V')) != NULL)
     {
       memcpy (&vnum, dataptr, sizeof (vnum));
@@ -4684,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 *
@@ -4799,7 +5155,8 @@ fast_tracepoint_collecting (CORE_ADDR thread_area,
                                  &ipa_gdb_jump_pad_buffer_end))
     fatal ("error extracting `gdb_jump_pad_buffer_end'");
 
-  if (ipa_gdb_jump_pad_buffer <= stop_pc && stop_pc < ipa_gdb_jump_pad_buffer_end)
+  if (ipa_gdb_jump_pad_buffer <= stop_pc
+      && stop_pc < ipa_gdb_jump_pad_buffer_end)
     {
       /* We can tell which tracepoint(s) the thread is collecting by
         matching the jump pad address back to the tracepoint.  */
@@ -5189,7 +5546,8 @@ emit_void_call_2 (CORE_ADDR fn, int arg1)
 static enum eval_result_type compile_bytecodes (struct agent_expr *aexpr);
 
 static void
-compile_tracepoint_condition (struct tracepoint *tpoint, CORE_ADDR *jump_entry)
+compile_tracepoint_condition (struct tracepoint *tpoint,
+                             CORE_ADDR *jump_entry)
 {
   CORE_ADDR entry_point = *jump_entry;
   enum eval_result_type err;
@@ -5631,7 +5989,8 @@ download_tracepoints (void)
     {
       struct tracepoint target_tracepoint;
 
-      if (tpoint->type != fast_tracepoint)
+      if (tpoint->type != fast_tracepoint
+         && tpoint->type != static_tracepoint)
        continue;
 
       /* Maybe download a compiled condition.  */
@@ -5742,6 +6101,14 @@ download_tracepoints (void)
                       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);
@@ -5824,8 +6191,9 @@ download_trace_state_variables (void)
   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);
+      write_inferior_data_ptr (prev_ptr
+                              + offsetof (struct trace_state_variable,
+                                          next), 0);
     }
 }
 
@@ -5863,8 +6231,10 @@ upload_fast_traceframes (void)
     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);
+              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;
@@ -6009,7 +6379,8 @@ upload_fast_traceframes (void)
          block = add_traceframe_block (tframe, ipa_tframe.data_size);
          if (block != NULL)
            {
-             if (read_inferior_memory (tf + offsetof (struct traceframe, data),
+             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)));
@@ -6057,7 +6428,8 @@ upload_fast_traceframes (void)
                   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.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));
     }
@@ -6087,20 +6459,902 @@ upload_fast_traceframes (void)
 
 #ifdef IN_PROCESS_AGENT
 
-#include <sys/mman.h>
-#include <fcntl.h>
+IP_AGENT_EXPORT int ust_loaded;
+IP_AGENT_EXPORT char cmd_buf[CMD_BUF_SIZE];
 
-IP_AGENT_EXPORT char *gdb_tp_heap_buffer;
-IP_AGENT_EXPORT char *gdb_jump_pad_buffer;
-IP_AGENT_EXPORT char *gdb_jump_pad_buffer_end;
+#ifdef HAVE_UST
 
-static void __attribute__ ((constructor))
-initialize_tracepoint_ftlib (void)
+/* 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
 {
-  initialize_tracepoint ();
+  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;
 }
 
-#endif
+/* 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 = xsnprintf (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;
+    }
+
+  res = fd = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (res == -1)
+    {
+      warning ("error opening sync socket: %s\n", strerror (errno));
+      return -1;
+    }
+
+  addr.sun_family = AF_UNIX;
+
+  res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path);
+  if (res >= UNIX_PATH_MAX)
+    {
+      warning ("string overflow allocating socket name\n");
+      close (fd);
+      return -1;
+    }
+
+  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;
+    }
+
+  return fd;
+}
+
+/* Resume thread PTID.  */
+
+static void
+resume_thread (ptid_t ptid)
+{
+  struct thread_resume resume_info;
+
+  resume_info.thread = ptid;
+  resume_info.kind = resume_continue;
+  resume_info.sig = TARGET_SIGNAL_0;
+  (*the_target->resume) (&resume_info, 1);
+}
+
+/* Stop thread PTID.  */
+
+static void
+stop_thread (ptid_t ptid)
+{
+  struct thread_resume resume_info;
+
+  resume_info.thread = ptid;
+  resume_info.kind = resume_stop;
+  resume_info.sig = TARGET_SIGNAL_0;
+  (*the_target->resume) (&resume_info, 1);
+}
+
+/* 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.  */
+
+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;
+
+  trace_debug ("run_inferior_command: running: %s", cmd);
+
+  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;
+    }
+
+  if (tid == 0)
+    {
+      warning ("helper thread not initialized yet");
+      goto out;
+    }
+
+  if (write_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
+                            (unsigned char *) cmd, strlen (cmd) + 1))
+    {
+      warning ("Error writing command");
+      goto out;
+    }
+
+  ptid = ptid_build (pid, tid, 0);
+
+  resume_thread (ptid);
+
+  fd = gdb_ust_connect_sync_socket (pid);
+  if (fd >= 0)
+    {
+      char buf[1] = "";
+      int ret;
+
+      trace_debug ("signalling helper thread");
+
+      do
+       {
+         ret = write (fd, buf, 1);
+       } while (ret == -1 && errno == EINTR);
+
+      trace_debug ("waiting for helper thread's response");
+
+      do
+       {
+         ret = read (fd, buf, 1);
+       } while (ret == -1 && errno == EINTR);
+
+      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
+       {
+         err = 0;
+         trace_debug ("run_inferior_command: response: %s", cmd);
+       }
+    }
+
+  reinsert_all_breakpoints ();
+  unpause_all (0);
+
+  return err;
+}
+
+#else /* HAVE_UST */
+
+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)
+       {
+         warning ("unlink failed: %s", strerror (errno));
+         close (fd);
+         return -1;
+       }
+      warning ("socket %s already exists; overwriting", name);
+    }
+
+  result = bind (fd, (struct sockaddr *) &addr, sizeof (addr));
+  if (result == -1)
+    {
+      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;
+}
+
+static int
+gdb_ust_socket_init (void)
+{
+  int result, fd;
+  char name[UNIX_PATH_MAX];
+
+  result = xsnprintf (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
+response_ust_marker (char *packet, const struct marker *st)
+{
+  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.  */
+
+static void
+cmd_qtfstm (char *packet)
+{
+  trace_debug ("Returning first trace state variable definition");
+
+  if (first_marker ())
+    response_ust_marker (packet, first_marker ());
+  else
+    strcpy (packet, "l");
+}
+
+/* Return additional trace state variable definitions. */
+
+static void
+cmd_qtsstm (char *packet)
+{
+  trace_debug ("Returning static tracepoint");
+
+  if (next_st)
+    response_ust_marker (packet, next_st);
+  else
+    strcpy (packet, "l");
+}
+
+/* Disconnect the GDB probe from a marker at a given address.  */
+
+static void
+unprobe_marker_at (char *packet)
+{
+  char *p = packet;
+  ULONGEST address;
+  struct marker_iter iter;
+
+  p += sizeof ("unprobe_marker_at:") - 1;
+
+  p = unpack_varlen_hex (p, &address);
+
+  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;
+      }
+}
+
+/* Connect the GDB probe to a marker at a given address.  */
+
+static int
+probe_marker_at (char *packet)
+{
+  char *p = packet;
+  ULONGEST address;
+  struct marker_iter iter;
+  struct marker *m;
+
+  p += sizeof ("probe_marker_at:") - 1;
+
+  p = unpack_varlen_hex (p, &address);
+
+  USTF(marker_iter_reset) (&iter);
+
+  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;
+
+       trace_debug ("found marker for address.  "
+                    "ltt_marker_connect (marker = %s/%s)",
+                    m->channel, m->name);
+
+       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 (result < 0)
+         {
+           sprintf (packet, "E.could not connect marker: channel=%s, name=%s",
+                    m->channel, m->name);
+           return -1;
+         }
+
+       strcpy (packet, "OK");
+       return 0;
+      }
+
+  sprintf (packet, "E.no marker found at 0x%s", paddress (address));
+  return -1;
+}
+
+static int
+cmd_qtstmat (char *packet)
+{
+  char *p = packet;
+  ULONGEST address;
+  struct marker_iter iter;
+  struct marker *m;
+
+  p += sizeof ("qTSTMat:") - 1;
+
+  p = unpack_varlen_hex (p, &address);
+
+  USTF(marker_iter_reset) (&iter);
+
+  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;
+      }
+
+  strcpy (packet, "l");
+  return -1;
+}
+
+static void *
+gdb_ust_thread (void *arg)
+{
+  int listen_fd;
+
+  while (1)
+    {
+      listen_fd = gdb_ust_socket_init ();
+
+#ifdef SYS_gettid
+      if (helper_thread_id == 0)
+       helper_thread_id = syscall (SYS_gettid);
+#endif
+
+      if (listen_fd == -1)
+       {
+         warning ("could not create sync socket\n");
+         break;
+       }
+
+      while (1)
+       {
+         socklen_t tmp;
+         struct sockaddr_un sockaddr;
+         int fd;
+         char buf[1];
+         int ret;
+
+         tmp = sizeof (sockaddr);
+
+         do
+           {
+             fd = accept (listen_fd, &sockaddr, &tmp);
+           }
+         /* It seems an ERESTARTSYS can escape out of accept.  */
+         while (fd == -512 || (fd == -1 && errno == EINTR));
+
+         if (fd < 0)
+           {
+             warning ("Accept returned %d, error: %s\n",
+                      fd, strerror (errno));
+             break;
+           }
+
+         do
+           {
+             ret = read (fd, buf, 1);
+           } while (ret == -1 && errno == EINTR);
+
+         if (ret == -1)
+           {
+             warning ("reading socket (fd=%d) failed with %s",
+                      fd, strerror (errno));
+             close (fd);
+             break;
+           }
+
+         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, "");
+           }
+
+         write (fd, buf, 1);
+         close (fd);
+       }
+    }
+
+  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;
+
+  /* We want the helper thread to be as transparent as possible, so
+     have it inherit an all-signals-blocked mask.  */
+
+  sigfillset (&new_mask);
+  res = pthread_sigmask (SIG_SETMASK, &new_mask, &orig_mask);
+  if (res)
+    fatal ("pthread_sigmask (1) failed: %s", strerror (res));
+
+  res = pthread_create (&thread,
+                       NULL,
+                       gdb_ust_thread,
+                       NULL);
+
+  res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL);
+  if (res)
+    fatal ("pthread_sigmask (2) failed: %s", strerror (res));
+
+  while (helper_thread_id == 0)
+    usleep (1);
+
+  USTF(ltt_probe_register) (&gdb_ust_probe);
+}
+
+#endif /* HAVE_UST */
+
+#include <sys/mman.h>
+#include <fcntl.h>
+
+IP_AGENT_EXPORT char *gdb_tp_heap_buffer;
+IP_AGENT_EXPORT char *gdb_jump_pad_buffer;
+IP_AGENT_EXPORT char *gdb_jump_pad_buffer_end;
+
+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.053296 seconds and 4 git commands to generate.