gdb/
[deliverable/binutils-gdb.git] / gdb / ctf.c
index de54051e90dafc130dba016e88d65a87fced440d..0985784ad40e939b301545e948a870978439deca 100644 (file)
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -24,6 +24,7 @@
 #include "tracepoint.h"
 #include "regcache.h"
 #include "gdb_stat.h"
+#include "exec.h"
 
 #include <ctype.h>
 
    1. The length (in bytes) of register cache.  Event "register" will
    be defined in metadata, which includes the length.
 
-   2. Trace status.  Not implemented yet in CTF writer.
+   2. Trace status.  Event "status" is defined in metadata, which
+   includes all aspects of trace status.
 
-   3. Uploaded trace variables and tracepoints.  Not implemented yet
-   in CTF writer.
+   3. Uploaded trace variables.  Event "tsv_def" is defined in
+   metadata, which is about all aspects of a uploaded trace variable.
+   Uploaded tracepoints.   Event "tp_def" is defined in meta, which
+   is about all aspects of an uploaded tracepoint.  Note that the
+   "sequence" (a CTF type, which is a dynamically-sized array.) is
+   used for "actions" "step_actions" and "cmd_strings".
 
    4. Trace frames.  Each trace frame is composed by several blocks
    of different types ('R', 'M', 'V').  One trace frame is saved in
@@ -65,6 +71,9 @@
 #define CTF_EVENT_ID_TSV 1
 #define CTF_EVENT_ID_MEMORY 2
 #define CTF_EVENT_ID_FRAME 3
+#define CTF_EVENT_ID_STATUS 4
+#define CTF_EVENT_ID_TSV_DEF 5
+#define CTF_EVENT_ID_TP_DEF 6
 
 /* The state kept while writing the CTF datastream file.  */
 
@@ -119,6 +128,12 @@ ctf_save_write (struct trace_write_handler *handler,
 #define ctf_save_write_uint32(HANDLER, U32) \
   ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
 
+/* Write a signed 32-bit integer to datastream file represented by
+   HANDLER.  */
+
+#define ctf_save_write_int32(HANDLER, INT32) \
+  ctf_save_write ((HANDLER), (gdb_byte *) &(INT32), 4)
+
 /* Set datastream file position.  Update HANDLER->content_size
    if WHENCE is SEEK_CUR.  */
 
@@ -217,6 +232,15 @@ ctf_save_metadata_header (struct trace_write_handler *handler)
                           "typealias integer { size = 64; align = 64;"
                           "signed = false; base = hex;}"
                           " := uint64_t;\n");
+  ctf_save_write_metadata (handler,
+                          "typealias integer { size = 32; align = 32;"
+                          "signed = true; } := int32_t;\n");
+  ctf_save_write_metadata (handler,
+                          "typealias integer { size = 64; align = 64;"
+                          "signed = true; } := int64_t;\n");
+  ctf_save_write_metadata (handler,
+                          "typealias string { encoding = ascii;"
+                          " } := chars;\n");
   ctf_save_write_metadata (handler, "\n");
 
   /* Get the byte order of the host and write CTF data in this byte
@@ -365,8 +389,50 @@ ctf_write_header (struct trace_file_writer *self)
                           "\t};\n"
                           "};\n", CTF_EVENT_ID_FRAME);
 
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+                         "event {\n\tname = \"tsv_def\";\n"
+                         "\tid = %u;\n\tfields := struct { \n"
+                         "\t\tint64_t initial_value;\n"
+                         "\t\tint32_t number;\n"
+                         "\t\tint32_t builtin;\n"
+                         "\t\tchars name;\n"
+                         "\t};\n"
+                         "};\n", CTF_EVENT_ID_TSV_DEF);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+                          "event {\n\tname = \"tp_def\";\n"
+                          "\tid = %u;\n\tfields := struct { \n"
+                          "\t\tuint64_t addr;\n"
+                          "\t\tuint64_t traceframe_usage;\n"
+                          "\t\tint32_t number;\n"
+                          "\t\tint32_t enabled;\n"
+                          "\t\tint32_t step;\n"
+                          "\t\tint32_t pass;\n"
+                          "\t\tint32_t hit_count;\n"
+                          "\t\tint32_t type;\n"
+                          "\t\tchars cond;\n"
+
+                         "\t\tuint32_t action_num;\n"
+                         "\t\tchars actions[action_num];\n"
+
+                         "\t\tuint32_t step_action_num;\n"
+                         "\t\tchars step_actions[step_action_num];\n"
+
+                         "\t\tchars at_string;\n"
+                         "\t\tchars cond_string;\n"
+
+                         "\t\tuint32_t cmd_num;\n"
+                         "\t\tchars cmd_strings[cmd_num];\n"
+                         "\t};\n"
+                         "};\n", CTF_EVENT_ID_TP_DEF);
+
   gdb_assert (writer->tcs.content_size == 0);
   gdb_assert (writer->tcs.packet_start == 0);
+
+  /* Create a new packet to contain this event.  */
+  self->ops->frame_ops->start (self, 0);
 }
 
 /* This is the implementation of trace_file_write_ops method
@@ -397,8 +463,39 @@ static void
 ctf_write_status (struct trace_file_writer *self,
                  struct trace_status *ts)
 {
-  /* It is not supported yet to write trace status into CTF trace
-     data.  */
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id;
+  int32_t int32;
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+                          "event {\n\tname = \"status\";\n\tid = %u;\n"
+                          "\tfields := struct { \n"
+                          "\t\tint32_t stop_reason;\n"
+                          "\t\tint32_t stopping_tracepoint;\n"
+                          "\t\tint32_t traceframe_count;\n"
+                          "\t\tint32_t traceframes_created;\n"
+                          "\t\tint32_t buffer_free;\n"
+                          "\t\tint32_t buffer_size;\n"
+                          "\t\tint32_t disconnected_tracing;\n"
+                          "\t\tint32_t circular_buffer;\n"
+                          "\t};\n"
+                          "};\n",
+                          CTF_EVENT_ID_STATUS);
+
+  id = CTF_EVENT_ID_STATUS;
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+  ctf_save_write_int32 (&writer->tcs, ts->stop_reason);
+  ctf_save_write_int32 (&writer->tcs, ts->stopping_tracepoint);
+  ctf_save_write_int32 (&writer->tcs, ts->traceframe_count);
+  ctf_save_write_int32 (&writer->tcs, ts->traceframes_created);
+  ctf_save_write_int32 (&writer->tcs, ts->buffer_free);
+  ctf_save_write_int32 (&writer->tcs, ts->buffer_size);
+  ctf_save_write_int32 (&writer->tcs, ts->disconnected_tracing);
+  ctf_save_write_int32 (&writer->tcs, ts->circular_buffer);
 }
 
 /* This is the implementation of trace_file_write_ops method
@@ -408,8 +505,31 @@ static void
 ctf_write_uploaded_tsv (struct trace_file_writer *self,
                        struct uploaded_tsv *tsv)
 {
-  /* It is not supported yet to write uploaded trace variables
-     into CTF trace data.  */
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  int32_t int32;
+  int64_t int64;
+  unsigned int len;
+  const gdb_byte zero = 0;
+
+  /* Event Id.  */
+  int32 = CTF_EVENT_ID_TSV_DEF;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+  /* initial_value */
+  int64 = tsv->initial_value;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+  /* number */
+  ctf_save_write_int32 (&writer->tcs, tsv->number);
+
+  /* builtin */
+  ctf_save_write_int32 (&writer->tcs, tsv->builtin);
+
+  /* name */
+  if (tsv->name != NULL)
+    ctf_save_write (&writer->tcs, tsv->name, strlen (tsv->name));
+  ctf_save_write (&writer->tcs, &zero, 1);
 }
 
 /* This is the implementation of trace_file_write_ops method
@@ -419,8 +539,80 @@ static void
 ctf_write_uploaded_tp (struct trace_file_writer *self,
                       struct uploaded_tp *tp)
 {
-  /* It is not supported yet to write uploaded tracepoints
-     into CTF trace data.  */
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  int32_t int32;
+  int64_t int64;
+  uint32_t u32;
+  const gdb_byte zero = 0;
+  int a;
+  char *act;
+
+  /* Event Id.  */
+  int32 = CTF_EVENT_ID_TP_DEF;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+  /* address */
+  int64 = tp->addr;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+  /* traceframe_usage */
+  int64 = tp->traceframe_usage;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+  /* number */
+  ctf_save_write_int32 (&writer->tcs, tp->number);
+
+  /* enabled */
+  ctf_save_write_int32 (&writer->tcs, tp->enabled);
+
+  /* step */
+  ctf_save_write_int32 (&writer->tcs, tp->step);
+
+  /* pass */
+  ctf_save_write_int32 (&writer->tcs, tp->pass);
+
+  /* hit_count */
+  ctf_save_write_int32 (&writer->tcs, tp->hit_count);
+
+  /* type */
+  ctf_save_write_int32 (&writer->tcs, tp->type);
+
+  /* condition  */
+  if (tp->cond != NULL)
+    ctf_save_write (&writer->tcs, tp->cond, strlen (tp->cond));
+  ctf_save_write (&writer->tcs, &zero, 1);
+
+  /* actions */
+  u32 = VEC_length (char_ptr, tp->actions);
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+  for (a = 0; VEC_iterate (char_ptr, tp->actions, a, act); ++a)
+    ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
+  /* step_actions */
+  u32 = VEC_length (char_ptr, tp->step_actions);
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+  for (a = 0; VEC_iterate (char_ptr, tp->step_actions, a, act); ++a)
+    ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
+  /* at_string */
+  if (tp->at_string != NULL)
+    ctf_save_write (&writer->tcs, tp->at_string,
+                   strlen (tp->at_string));
+  ctf_save_write (&writer->tcs, &zero, 1);
+
+  /* cond_string */
+  if (tp->cond_string != NULL)
+    ctf_save_write (&writer->tcs, tp->cond_string,
+                   strlen (tp->cond_string));
+  ctf_save_write (&writer->tcs, &zero, 1);
+
+  /* cmd_strings */
+  u32 = VEC_length (char_ptr, tp->cmd_strings);
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+  for (a = 0; VEC_iterate (char_ptr, tp->cmd_strings, a, act); ++a)
+    ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
 }
 
 /* This is the implementation of trace_file_write_ops method
@@ -429,7 +621,10 @@ ctf_write_uploaded_tp (struct trace_file_writer *self,
 static void
 ctf_write_definition_end (struct trace_file_writer *self)
 {
-  /* Nothing to do for CTF.  */
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+  self->ops->frame_ops->end (self);
 }
 
 /* The minimal file size of data stream.  It is required by
@@ -670,3 +865,984 @@ ctf_trace_file_writer_new (void)
 
   return (struct trace_file_writer *) writer;
 }
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data.  The libbabeltrace provides
+   iterator to iterate over each event in CTF data and APIs to get
+   details of event and packet, so it is very convenient to use
+   libbabeltrace to access events in CTF.  */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory.  */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The position of the first packet containing trace frame.  */
+static struct bt_iter_pos *start_pos;
+
+/* The name of CTF directory.  */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+/* Destroy ctf iterator and context.  */
+
+static void
+ctf_destroy (void)
+{
+  if (ctf_iter != NULL)
+    {
+      bt_ctf_iter_destroy (ctf_iter);
+      ctf_iter = NULL;
+    }
+  if (ctx != NULL)
+    {
+      bt_context_put (ctx);
+      ctx = NULL;
+    }
+}
+
+/* Open CTF trace data in DIRNAME.  */
+
+static void
+ctf_open_dir (char *dirname)
+{
+  int ret;
+  struct bt_iter_pos begin_pos;
+  struct bt_iter_pos *pos;
+
+  ctx = bt_context_create ();
+  if (ctx == NULL)
+    error (_("Unable to create bt_context"));
+  ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+  if (ret < 0)
+    {
+      ctf_destroy ();
+      error (_("Unable to use libbabeltrace on directory \"%s\""),
+            dirname);
+    }
+
+  begin_pos.type = BT_SEEK_BEGIN;
+  ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+  if (ctf_iter == NULL)
+    {
+      ctf_destroy ();
+      error (_("Unable to create bt_iterator"));
+    }
+
+  /* Iterate over events, and look for an event for register block
+     to set trace_regblock_size.  */
+
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (name == NULL)
+       break;
+      else if (strcmp (name, "register") == 0)
+       {
+         const struct bt_definition *scope
+           = bt_ctf_get_top_level_scope (event,
+                                         BT_EVENT_FIELDS);
+         const struct bt_definition *array
+           = bt_ctf_get_field (event, scope, "contents");
+
+         trace_regblock_size
+           = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+       }
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+}
+
+#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD)                      \
+  (VAR)->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT),    \
+                                                          (SCOPE),     \
+                                                          #FIELD))
+
+/* EVENT is the "status" event and TS is filled in.  */
+
+static void
+ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
+{
+  const struct bt_definition *scope
+    = bt_ctf_get_top_level_scope (event, BT_EVENT_FIELDS);
+
+  SET_INT32_FIELD (event, scope, ts, stop_reason);
+  SET_INT32_FIELD (event, scope, ts, stopping_tracepoint);
+  SET_INT32_FIELD (event, scope, ts, traceframe_count);
+  SET_INT32_FIELD (event, scope, ts, traceframes_created);
+  SET_INT32_FIELD (event, scope, ts, buffer_free);
+  SET_INT32_FIELD (event, scope, ts, buffer_size);
+  SET_INT32_FIELD (event, scope, ts, disconnected_tracing);
+  SET_INT32_FIELD (event, scope, ts, circular_buffer);
+
+  bt_iter_next (bt_ctf_get_iter (ctf_iter));
+}
+
+/* Read the events "tsv_def" one by one, extract its contents and fill
+   in the list UPLOADED_TSVS.  */
+
+static void
+ctf_read_tsv (struct uploaded_tsv **uploaded_tsvs)
+{
+  gdb_assert (ctf_iter != NULL);
+
+  while (1)
+    {
+      struct bt_ctf_event *event;
+      const struct bt_definition *scope;
+      const struct bt_definition *def;
+      uint32_t event_id;
+      struct uploaded_tsv *utsv = NULL;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+      scope = bt_ctf_get_top_level_scope (event,
+                                         BT_STREAM_EVENT_HEADER);
+      event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+                                                     "id"));
+      if (event_id != CTF_EVENT_ID_TSV_DEF)
+       break;
+
+      scope = bt_ctf_get_top_level_scope (event,
+                                         BT_EVENT_FIELDS);
+
+      def = bt_ctf_get_field (event, scope, "number");
+      utsv = get_uploaded_tsv ((int32_t) bt_ctf_get_int64 (def),
+                              uploaded_tsvs);
+
+      def = bt_ctf_get_field (event, scope, "builtin");
+      utsv->builtin = (int32_t) bt_ctf_get_int64 (def);
+      def = bt_ctf_get_field (event, scope, "initial_value");
+      utsv->initial_value = bt_ctf_get_int64 (def);
+
+      def = bt_ctf_get_field (event, scope, "name");
+      utsv->name =  xstrdup (bt_ctf_get_string (def));
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+
+}
+
+/* Read the value of element whose index is NUM from CTF and write it
+   to the corresponding VAR->ARRAY. */
+
+#define SET_ARRAY_FIELD(EVENT, SCOPE, VAR, NUM, ARRAY) \
+  do                                                   \
+    {                                                  \
+      uint32_t u32, i;                                         \
+      const struct bt_definition *def;                         \
+                                                               \
+      u32 = (uint32_t) bt_ctf_get_uint64 (bt_ctf_get_field ((EVENT),   \
+                                                           (SCOPE),    \
+                                                           #NUM));     \
+      def = bt_ctf_get_field ((EVENT), (SCOPE), #ARRAY);               \
+      for (i = 0; i < u32; i++)                                        \
+       {                                                               \
+         const struct bt_definition *element                           \
+           = bt_ctf_get_index ((EVENT), def, i);                       \
+                                                                       \
+         VEC_safe_push (char_ptr, (VAR)->ARRAY,                        \
+                        xstrdup (bt_ctf_get_string (element)));        \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+/* Read a string from CTF and set VAR->FIELD. If the length of string
+   is zero, set VAR->FIELD to NULL.  */
+
+#define SET_STRING_FIELD(EVENT, SCOPE, VAR, FIELD)                     \
+  do                                                                   \
+    {                                                                  \
+      const char *p = bt_ctf_get_string (bt_ctf_get_field ((EVENT),    \
+                                                          (SCOPE),     \
+                                                          #FIELD));    \
+                                                                       \
+      if (strlen (p) > 0)                                              \
+       (VAR)->FIELD = xstrdup (p);                                     \
+      else                                                             \
+       (VAR)->FIELD = NULL;                                            \
+    }                                                                  \
+  while (0)
+
+/* Read the events "tp_def" one by one, extract its contents and fill
+   in the list UPLOADED_TPS.  */
+
+static void
+ctf_read_tp (struct uploaded_tp **uploaded_tps)
+{
+  gdb_assert (ctf_iter != NULL);
+
+  while (1)
+    {
+      struct bt_ctf_event *event;
+      const struct bt_definition *scope;
+      uint32_t u32;
+      int32_t int32;
+      uint64_t u64;
+      struct uploaded_tp *utp = NULL;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+      scope = bt_ctf_get_top_level_scope (event,
+                                         BT_STREAM_EVENT_HEADER);
+      u32 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+                                                "id"));
+      if (u32 != CTF_EVENT_ID_TP_DEF)
+       break;
+
+      scope = bt_ctf_get_top_level_scope (event,
+                                         BT_EVENT_FIELDS);
+      int32 = (int32_t) bt_ctf_get_int64 (bt_ctf_get_field (event,
+                                                           scope,
+                                                           "number"));
+      u64 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+                                                "addr"));
+      utp = get_uploaded_tp (int32, u64,  uploaded_tps);
+
+      SET_INT32_FIELD (event, scope, utp, enabled);
+      SET_INT32_FIELD (event, scope, utp, step);
+      SET_INT32_FIELD (event, scope, utp, pass);
+      SET_INT32_FIELD (event, scope, utp, hit_count);
+      SET_INT32_FIELD (event, scope, utp, type);
+
+      /* Read 'cmd_strings'.  */
+      SET_ARRAY_FIELD (event, scope, utp, cmd_num, cmd_strings);
+      /* Read 'actions'.  */
+      SET_ARRAY_FIELD (event, scope, utp, action_num, actions);
+      /* Read 'step_actions'.  */
+      SET_ARRAY_FIELD (event, scope, utp, step_action_num,
+                      step_actions);
+
+      SET_STRING_FIELD(event, scope, utp, at_string);
+      SET_STRING_FIELD(event, scope, utp, cond_string);
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+}
+
+/* This is the implementation of target_ops method to_open.  Open CTF
+   trace data, read trace status, trace state variables and tracepoint
+   definitions from the first packet.  Set the start position at the
+   second packet which contains events on trace blocks.  */
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+  struct bt_ctf_event *event;
+  uint32_t event_id;
+  const struct bt_definition *scope;
+  struct uploaded_tsv *uploaded_tsvs = NULL;
+  struct uploaded_tp *uploaded_tps = NULL;
+
+  if (!dirname)
+    error (_("No CTF directory specified."));
+
+  ctf_open_dir (dirname);
+
+  target_preopen (from_tty);
+
+  /* Skip the first packet which about the trace status.  The first
+     event is "frame".  */
+  event = bt_ctf_iter_read_event (ctf_iter);
+  scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+  event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+  if (event_id != CTF_EVENT_ID_FRAME)
+    error (_("Wrong event id of the first event"));
+  /* The second event is "status".  */
+  bt_iter_next (bt_ctf_get_iter (ctf_iter));
+  event = bt_ctf_iter_read_event (ctf_iter);
+  scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+  event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+  if (event_id != CTF_EVENT_ID_STATUS)
+    error (_("Wrong event id of the second event"));
+  ctf_read_status (event, current_trace_status ());
+
+  ctf_read_tsv (&uploaded_tsvs);
+
+  ctf_read_tp (&uploaded_tps);
+
+  event = bt_ctf_iter_read_event (ctf_iter);
+  /* EVENT can be NULL if we've already gone to the end of stream of
+     events.  */
+  if (event != NULL)
+    {
+      scope = bt_ctf_get_top_level_scope (event,
+                                         BT_STREAM_EVENT_HEADER);
+      event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event,
+                                                     scope, "id"));
+      if (event_id != CTF_EVENT_ID_FRAME)
+       error (_("Wrong event id of the first event of the second packet"));
+    }
+
+  start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (start_pos->type == BT_SEEK_RESTORE);
+
+  trace_dirname = xstrdup (dirname);
+  push_target (&ctf_ops);
+
+  merge_uploaded_trace_state_variables (&uploaded_tsvs);
+  merge_uploaded_tracepoints (&uploaded_tps);
+}
+
+/* This is the implementation of target_ops method to_close.  Destroy
+   CTF iterator and context.  */
+
+static void
+ctf_close (void)
+{
+  ctf_destroy ();
+  xfree (trace_dirname);
+  trace_dirname = NULL;
+}
+
+/* This is the implementation of target_ops method to_files_info.
+   Print the directory name of CTF trace data.  */
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+  printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+   Iterate over events whose name is "register" in current frame,
+   extract contents from events, and set REGCACHE with the contents.
+   If no matched events are found, mark registers unavailable.  */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+                    struct regcache *regcache, int regno)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset, regn, regsize, pc_regno;
+  char *regs = NULL;
+  struct bt_ctf_event *event = NULL;
+  struct bt_iter_pos *pos;
+
+  /* An uninitialized reg size says we're not going to be
+     successful at getting register blocks.  */
+  if (trace_regblock_size == 0)
+    return;
+
+  gdb_assert (ctf_iter != NULL);
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event1;
+
+      event1 = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event1);
+
+      if (name == NULL || strcmp (name, "frame") == 0)
+       break;
+      else if (strcmp (name, "register") == 0)
+       {
+         event = event1;
+         break;
+       }
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  if (event != NULL)
+    {
+      const struct bt_definition *scope
+       = bt_ctf_get_top_level_scope (event,
+                                     BT_EVENT_FIELDS);
+      const struct bt_definition *array
+       = bt_ctf_get_field (event, scope, "contents");
+
+      regs = bt_ctf_get_char_array (array);
+      /* Assume the block is laid out in GDB register number order,
+        each register with the size that it has in GDB.  */
+      offset = 0;
+      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+       {
+         regsize = register_size (gdbarch, regn);
+         /* Make sure we stay within block bounds.  */
+         if (offset + regsize >= trace_regblock_size)
+           break;
+         if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+           {
+             if (regno == regn)
+               {
+                 regcache_raw_supply (regcache, regno, regs + offset);
+                 break;
+               }
+             else if (regno == -1)
+               {
+                 regcache_raw_supply (regcache, regn, regs + offset);
+               }
+           }
+         offset += regsize;
+       }
+      return;
+    }
+
+  regs = alloca (trace_regblock_size);
+
+  /* We get here if no register data has been found.  Mark registers
+     as unavailable.  */
+  for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+    regcache_raw_supply (regcache, regn, NULL);
+
+  /* We can often usefully guess that the PC is going to be the same
+     as the address of the tracepoint.  */
+  pc_regno = gdbarch_pc_regnum (gdbarch);
+  if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+    {
+      struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+      if (tp != NULL && tp->base.loc)
+       {
+         /* But don't try to guess if tracepoint is multi-location...  */
+         if (tp->base.loc->next != NULL)
+           {
+             warning (_("Tracepoint %d has multiple "
+                        "locations, cannot infer $pc"),
+                      tp->base.number);
+             return;
+           }
+         /* ... or does while-stepping.  */
+         if (tp->step_count > 0)
+           {
+             warning (_("Tracepoint %d does while-stepping, "
+                        "cannot infer $pc"),
+                      tp->base.number);
+             return;
+           }
+
+         store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+                                 gdbarch_byte_order (gdbarch),
+                                 tp->base.loc->address);
+         regcache_raw_supply (regcache, pc_regno, regs);
+       }
+    }
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+   Iterate over events whose name is "memory" in
+   current frame, extract the address and length from events.  If
+   OFFSET is within the range, read the contents from events to
+   READBUF.  */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+                 const char *annex, gdb_byte *readbuf,
+                 const gdb_byte *writebuf, ULONGEST offset,
+                 LONGEST len)
+{
+  /* We're only doing regular memory for now.  */
+  if (object != TARGET_OBJECT_MEMORY)
+    return -1;
+
+  if (readbuf == NULL)
+    error (_("ctf_xfer_partial: trace file is read-only"));
+
+  if (get_traceframe_number () != -1)
+    {
+      struct bt_iter_pos *pos;
+      int i = 0;
+
+      gdb_assert (ctf_iter != NULL);
+      /* Save the current position.  */
+      pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+      gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+      /* Iterate through the traceframe's blocks, looking for
+        memory.  */
+      while (1)
+       {
+         ULONGEST amt;
+         uint64_t maddr;
+         uint16_t mlen;
+         enum bfd_endian byte_order
+           = gdbarch_byte_order (target_gdbarch ());
+         const struct bt_definition *scope;
+         const struct bt_definition *def;
+         struct bt_ctf_event *event
+           = bt_ctf_iter_read_event (ctf_iter);
+         const char *name = bt_ctf_event_name (event);
+
+         if (strcmp (name, "frame") == 0)
+           break;
+         else if (strcmp (name, "memory") != 0)
+           {
+             if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+               break;
+
+             continue;
+           }
+
+         scope = bt_ctf_get_top_level_scope (event,
+                                             BT_EVENT_FIELDS);
+
+         def = bt_ctf_get_field (event, scope, "address");
+         maddr = bt_ctf_get_uint64 (def);
+         def = bt_ctf_get_field (event, scope, "length");
+         mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+         /* If the block includes the first part of the desired
+            range, return as much it has; GDB will re-request the
+            remainder, which might be in a different block of this
+            trace frame.  */
+         if (maddr <= offset && offset < (maddr + mlen))
+           {
+             const struct bt_definition *array
+               = bt_ctf_get_field (event, scope, "contents");
+             const struct bt_declaration *decl
+               = bt_ctf_get_decl_from_def (array);
+             gdb_byte *contents;
+             int k;
+
+             contents = xmalloc (mlen);
+
+             for (k = 0; k < mlen; k++)
+               {
+                 const struct bt_definition *element
+                   = bt_ctf_get_index (event, array, k);
+
+                 contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+               }
+
+             amt = (maddr + mlen) - offset;
+             if (amt > len)
+               amt = len;
+
+             memcpy (readbuf, &contents[offset - maddr], amt);
+
+             xfree (contents);
+
+             /* Restore the position.  */
+             bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+             return amt;
+           }
+
+         if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+           break;
+       }
+
+      /* Restore the position.  */
+      bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+    }
+
+  /* It's unduly pedantic to refuse to look at the executable for
+     read-only pieces; so do the equivalent of readonly regions aka
+     QTro packet.  */
+  if (exec_bfd != NULL)
+    {
+      asection *s;
+      bfd_size_type size;
+      bfd_vma vma;
+
+      for (s = exec_bfd->sections; s; s = s->next)
+       {
+         if ((s->flags & SEC_LOAD) == 0
+             || (s->flags & SEC_READONLY) == 0)
+           continue;
+
+         vma = s->vma;
+         size = bfd_get_section_size (s);
+         if (vma <= offset && offset < (vma + size))
+           {
+             ULONGEST amt;
+
+             amt = (vma + size) - offset;
+             if (amt > len)
+               amt = len;
+
+             amt = bfd_get_section_contents (exec_bfd, s,
+                                             readbuf, offset - vma, amt);
+             return amt;
+           }
+       }
+    }
+
+  /* Indicate failure to find the requested memory block.  */
+  return -1;
+}
+
+/* This is the implementation of target_ops method
+   to_get_trace_state_variable_value.
+   Iterate over events whose name is "tsv" in current frame.  When the
+   trace variable is found, set the value of it to *VAL and return
+   true, otherwise return false.  */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+  struct bt_iter_pos *pos;
+  int found = 0;
+
+  gdb_assert (ctf_iter != NULL);
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  /* Iterate through the traceframe's blocks, looking for 'V'
+     block.  */
+  while (1)
+    {
+      struct bt_ctf_event *event
+       = bt_ctf_iter_read_event (ctf_iter);
+      const char *name = bt_ctf_event_name (event);
+
+      if (name == NULL || strcmp (name, "frame") == 0)
+       break;
+      else if (strcmp (name, "tsv") == 0)
+       {
+         const struct bt_definition *scope;
+         const struct bt_definition *def;
+
+         scope = bt_ctf_get_top_level_scope (event,
+                                             BT_EVENT_FIELDS);
+
+         def = bt_ctf_get_field (event, scope, "num");
+         if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+           {
+             def = bt_ctf_get_field (event, scope, "val");
+             *val = bt_ctf_get_uint64 (def);
+
+             found = 1;
+           }
+       }
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  return found;
+}
+
+/* Return the tracepoint number in "frame" event.  */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+  /* The packet context of events has a field "tpnum".  */
+  const struct bt_definition *scope
+    = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+  uint64_t tpnum
+    = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+  return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected.  */
+
+static CORE_ADDR
+ctf_get_traceframe_address (void)
+{
+  struct bt_ctf_event *event = NULL;
+  struct bt_iter_pos *pos;
+  CORE_ADDR addr = 0;
+
+  gdb_assert (ctf_iter != NULL);
+  pos  = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event1;
+
+      event1 = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event1);
+
+      if (name == NULL)
+       break;
+      else if (strcmp (name, "frame") == 0)
+       {
+         event = event1;
+         break;
+       }
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+
+  if (event != NULL)
+    {
+      int tpnum = ctf_get_tpnum_from_frame_event (event);
+      struct tracepoint *tp
+       = get_tracepoint_by_number_on_target (tpnum);
+
+      if (tp && tp->base.loc)
+       addr = tp->base.loc->address;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+   Iterate the events whose name is "frame", extract the tracepoint
+   number in it.  Return traceframe number when matched.  */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+               CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+{
+  int ret = -1;
+  int tfnum = 0;
+  int found = 0;
+  struct bt_iter_pos pos;
+
+  if (num == -1)
+    {
+      if (tpp != NULL)
+       *tpp = -1;
+      return -1;
+    }
+
+  gdb_assert (ctf_iter != NULL);
+  /* Set iterator back to the start.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), start_pos);
+
+  while (1)
+    {
+      int id;
+      struct bt_ctf_event *event;
+      const char *name;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (event == NULL || name == NULL)
+       break;
+
+      if (strcmp (name, "frame") == 0)
+       {
+         CORE_ADDR tfaddr;
+
+         if (type == tfind_number)
+           {
+             /* Looking for a specific trace frame.  */
+             if (tfnum == num)
+               found = 1;
+           }
+         else
+           {
+             /* Start from the _next_ trace frame.  */
+             if (tfnum > get_traceframe_number ())
+               {
+                 switch (type)
+                   {
+                   case tfind_tp:
+                     {
+                       struct tracepoint *tp = get_tracepoint (num);
+
+                       if (tp != NULL
+                           && (tp->number_on_target
+                               == ctf_get_tpnum_from_frame_event (event)))
+                         found = 1;
+                       break;
+                     }
+                   case tfind_pc:
+                     tfaddr = ctf_get_traceframe_address ();
+                     if (tfaddr == addr1)
+                       found = 1;
+                     break;
+                   case tfind_range:
+                     tfaddr = ctf_get_traceframe_address ();
+                     if (addr1 <= tfaddr && tfaddr <= addr2)
+                       found = 1;
+                     break;
+                   case tfind_outside:
+                     tfaddr = ctf_get_traceframe_address ();
+                     if (!(addr1 <= tfaddr && tfaddr <= addr2))
+                       found = 1;
+                     break;
+                   default:
+                     internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+                   }
+               }
+           }
+         if (found)
+           {
+             if (tpp != NULL)
+               *tpp = ctf_get_tpnum_from_frame_event (event);
+
+             /* Skip the event "frame".  */
+             bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+             return tfnum;
+           }
+         tfnum++;
+       }
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+
+  return -1;
+}
+
+/* This is the implementation of target_ops method to_has_stack.
+   The target has a stack when GDB has already selected one trace
+   frame.  */
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+  return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_has_registers.
+   The target has registers when GDB has already selected one trace
+   frame.  */
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+  return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+   Iterate the events whose name is "memory", in current
+   frame, extract memory range information, and return them in
+   traceframe_info.  */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+  struct traceframe_info *info = XCNEW (struct traceframe_info);
+  const char *name;
+  struct bt_iter_pos *pos;
+
+  gdb_assert (ctf_iter != NULL);
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  do
+    {
+      struct bt_ctf_event *event
+       = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (name == NULL || strcmp (name, "register") == 0
+         || strcmp (name, "frame") == 0)
+       ;
+      else if (strcmp (name, "memory") == 0)
+       {
+         const struct bt_definition *scope
+           = bt_ctf_get_top_level_scope (event,
+                                         BT_EVENT_FIELDS);
+         const struct bt_definition *def;
+         struct mem_range *r;
+
+         r = VEC_safe_push (mem_range_s, info->memory, NULL);
+         def = bt_ctf_get_field (event, scope, "address");
+         r->start = bt_ctf_get_uint64 (def);
+
+         def = bt_ctf_get_field (event, scope, "length");
+         r->length = (uint16_t) bt_ctf_get_uint64 (def);
+       }
+      else
+       {
+         warning (_("Unhandled trace block type (%s) "
+                    "while building trace frame info."),
+                  name);
+       }
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+       break;
+    }
+  while (name != NULL && strcmp (name, "frame") != 0);
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  return info;
+}
+
+/* This is the implementation of target_ops method to_get_trace_status.
+   The trace status for a file is that tracing can never be run.  */
+
+static int
+ctf_get_trace_status (struct trace_status *ts)
+{
+  /* Other bits of trace status were collected as part of opening the
+     trace files, so nothing to do here.  */
+
+  return -1;
+}
+
+static void
+init_ctf_ops (void)
+{
+  memset (&ctf_ops, 0, sizeof (ctf_ops));
+
+  ctf_ops.to_shortname = "ctf";
+  ctf_ops.to_longname = "CTF file";
+  ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+  ctf_ops.to_open = ctf_open;
+  ctf_ops.to_close = ctf_close;
+  ctf_ops.to_fetch_registers = ctf_fetch_registers;
+  ctf_ops.to_xfer_partial = ctf_xfer_partial;
+  ctf_ops.to_files_info = ctf_files_info;
+  ctf_ops.to_get_trace_status = ctf_get_trace_status;
+  ctf_ops.to_trace_find = ctf_trace_find;
+  ctf_ops.to_get_trace_state_variable_value
+    = ctf_get_trace_state_variable_value;
+  ctf_ops.to_stratum = process_stratum;
+  ctf_ops.to_has_stack = ctf_has_stack;
+  ctf_ops.to_has_registers = ctf_has_registers;
+  ctf_ops.to_traceframe_info = ctf_traceframe_info;
+  ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+  init_ctf_ops ();
+
+  add_target (&ctf_ops);
+#endif
+}
This page took 0.08695 seconds and 4 git commands to generate.