Fix cast of xml_find_attribute's return value
[deliverable/binutils-gdb.git] / gdb / btrace.c
index 5436ee9e8fbb29fcb3d2c0782a13146a774d2c9a..2bf71771bb5ded9520a6ac0a983745df76187d3f 100644 (file)
 #include "filenames.h"
 #include "xml-support.h"
 #include "regcache.h"
+#include "rsp-low.h"
+#include "gdbcmd.h"
+#include "cli/cli-utils.h"
+
+#include <inttypes.h>
+#include <ctype.h>
+
+/* Command lists for btrace maintenance commands.  */
+static struct cmd_list_element *maint_btrace_cmdlist;
+static struct cmd_list_element *maint_btrace_set_cmdlist;
+static struct cmd_list_element *maint_btrace_show_cmdlist;
+static struct cmd_list_element *maint_btrace_pt_set_cmdlist;
+static struct cmd_list_element *maint_btrace_pt_show_cmdlist;
+
+/* Control whether to skip PAD packets when computing the packet history.  */
+static int maint_btrace_pt_skip_pad = 1;
+
+static void btrace_add_pc (struct thread_info *tp);
 
 /* Print a record debug message.  Use do ... while (0) to avoid ambiguities
    when used in if statements.  */
@@ -175,7 +193,7 @@ ftrace_new_function (struct btrace_function *prev,
 {
   struct btrace_function *bfun;
 
-  bfun = xzalloc (sizeof (*bfun));
+  bfun = XCNEW (struct btrace_function);
 
   bfun->msym = mfun;
   bfun->sym = fun;
@@ -549,11 +567,10 @@ ftrace_update_insns (struct btrace_function *bfun,
 static enum btrace_insn_class
 ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
-  volatile struct gdb_exception error;
   enum btrace_insn_class iclass;
 
   iclass = BTRACE_INSN_OTHER;
-  TRY_CATCH (error, RETURN_MASK_ERROR)
+  TRY
     {
       if (gdbarch_insn_is_call (gdbarch, pc))
        iclass = BTRACE_INSN_CALL;
@@ -562,6 +579,10 @@ ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
       else if (gdbarch_insn_is_jump (gdbarch, pc))
        iclass = BTRACE_INSN_JUMP;
     }
+  CATCH (error, RETURN_MASK_ERROR)
+    {
+    }
+  END_CATCH
 
   return iclass;
 }
@@ -598,7 +619,6 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 
       for (;;)
        {
-         volatile struct gdb_exception error;
          struct btrace_insn insn;
          int size;
 
@@ -628,12 +648,19 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
            level = min (level, end->level);
 
          size = 0;
-         TRY_CATCH (error, RETURN_MASK_ERROR)
-           size = gdb_insn_length (gdbarch, pc);
+         TRY
+           {
+             size = gdb_insn_length (gdbarch, pc);
+           }
+         CATCH (error, RETURN_MASK_ERROR)
+           {
+           }
+         END_CATCH
 
          insn.pc = pc;
          insn.size = size;
          insn.iclass = ftrace_classify_insn (gdbarch, pc);
+         insn.flags = 0;
 
          ftrace_update_insns (end, &insn);
 
@@ -678,6 +705,274 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
   btinfo->level = -level;
 }
 
+#if defined (HAVE_LIBIPT)
+
+static enum btrace_insn_class
+pt_reclassify_insn (enum pt_insn_class iclass)
+{
+  switch (iclass)
+    {
+    case ptic_call:
+      return BTRACE_INSN_CALL;
+
+    case ptic_return:
+      return BTRACE_INSN_RETURN;
+
+    case ptic_jump:
+      return BTRACE_INSN_JUMP;
+
+    default:
+      return BTRACE_INSN_OTHER;
+    }
+}
+
+/* Return the btrace instruction flags for INSN.  */
+
+static enum btrace_insn_flag
+pt_btrace_insn_flags (const struct pt_insn *insn)
+{
+  enum btrace_insn_flag flags = 0;
+
+  if (insn->speculative)
+    flags |= BTRACE_INSN_FLAG_SPECULATIVE;
+
+  return flags;
+}
+
+/* Add function branch trace using DECODER.  */
+
+static void
+ftrace_add_pt (struct pt_insn_decoder *decoder,
+              struct btrace_function **pbegin,
+              struct btrace_function **pend, int *plevel,
+              unsigned int *ngaps)
+{
+  struct btrace_function *begin, *end, *upd;
+  uint64_t offset;
+  int errcode, nerrors;
+
+  begin = *pbegin;
+  end = *pend;
+  nerrors = 0;
+  for (;;)
+    {
+      struct btrace_insn btinsn;
+      struct pt_insn insn;
+
+      errcode = pt_insn_sync_forward (decoder);
+      if (errcode < 0)
+       {
+         if (errcode != -pte_eos)
+           warning (_("Failed to synchronize onto the Intel(R) Processor "
+                      "Trace stream: %s."), pt_errstr (pt_errcode (errcode)));
+         break;
+       }
+
+      memset (&btinsn, 0, sizeof (btinsn));
+      for (;;)
+       {
+         errcode = pt_insn_next (decoder, &insn, sizeof(insn));
+         if (errcode < 0)
+           break;
+
+         /* Look for gaps in the trace - unless we're at the beginning.  */
+         if (begin != NULL)
+           {
+             /* Tracing is disabled and re-enabled each time we enter the
+                kernel.  Most times, we continue from the same instruction we
+                stopped before.  This is indicated via the RESUMED instruction
+                flag.  The ENABLED instruction flag means that we continued
+                from some other instruction.  Indicate this as a trace gap.  */
+             if (insn.enabled)
+               *pend = end = ftrace_new_gap (end, BDE_PT_DISABLED);
+
+             /* Indicate trace overflows.  */
+             if (insn.resynced)
+               *pend = end = ftrace_new_gap (end, BDE_PT_OVERFLOW);
+           }
+
+         upd = ftrace_update_function (end, insn.ip);
+         if (upd != end)
+           {
+             *pend = end = upd;
+
+             if (begin == NULL)
+               *pbegin = begin = upd;
+           }
+
+         /* Maintain the function level offset.  */
+         *plevel = min (*plevel, end->level);
+
+         btinsn.pc = (CORE_ADDR) insn.ip;
+         btinsn.size = (gdb_byte) insn.size;
+         btinsn.iclass = pt_reclassify_insn (insn.iclass);
+         btinsn.flags = pt_btrace_insn_flags (&insn);
+
+         ftrace_update_insns (end, &btinsn);
+       }
+
+      if (errcode == -pte_eos)
+       break;
+
+      /* If the gap is at the very beginning, we ignore it - we will have
+        less trace, but we won't have any holes in the trace.  */
+      if (begin == NULL)
+       continue;
+
+      pt_insn_get_offset (decoder, &offset);
+
+      warning (_("Failed to decode Intel(R) Processor Trace near trace "
+                "offset 0x%" PRIx64 " near recorded PC 0x%" PRIx64 ": %s."),
+              offset, insn.ip, pt_errstr (pt_errcode (errcode)));
+
+      /* Indicate the gap in the trace.  */
+      *pend = end = ftrace_new_gap (end, errcode);
+      *ngaps += 1;
+    }
+
+  if (nerrors > 0)
+    warning (_("The recorded execution trace may have gaps."));
+}
+
+/* A callback function to allow the trace decoder to read the inferior's
+   memory.  */
+
+static int
+btrace_pt_readmem_callback (gdb_byte *buffer, size_t size,
+                           const struct pt_asid *asid, uint64_t pc,
+                           void *context)
+{
+  int errcode;
+
+  TRY
+    {
+      errcode = target_read_code ((CORE_ADDR) pc, buffer, size);
+      if (errcode != 0)
+       return -pte_nomap;
+    }
+  CATCH (error, RETURN_MASK_ERROR)
+    {
+      return -pte_nomap;
+    }
+  END_CATCH
+
+  return size;
+}
+
+/* Translate the vendor from one enum to another.  */
+
+static enum pt_cpu_vendor
+pt_translate_cpu_vendor (enum btrace_cpu_vendor vendor)
+{
+  switch (vendor)
+    {
+    default:
+      return pcv_unknown;
+
+    case CV_INTEL:
+      return pcv_intel;
+    }
+}
+
+/* Finalize the function branch trace after decode.  */
+
+static void btrace_finalize_ftrace_pt (struct pt_insn_decoder *decoder,
+                                      struct thread_info *tp, int level)
+{
+  pt_insn_free_decoder (decoder);
+
+  /* LEVEL is the minimal function level of all btrace function segments.
+     Define the global level offset to -LEVEL so all function levels are
+     normalized to start at zero.  */
+  tp->btrace.level = -level;
+
+  /* Add a single last instruction entry for the current PC.
+     This allows us to compute the backtrace at the current PC using both
+     standard unwind and btrace unwind.
+     This extra entry is ignored by all record commands.  */
+  btrace_add_pc (tp);
+}
+
+/* Compute the function branch trace from Intel(R) Processor Trace.  */
+
+static void
+btrace_compute_ftrace_pt (struct thread_info *tp,
+                         const struct btrace_data_pt *btrace)
+{
+  struct btrace_thread_info *btinfo;
+  struct pt_insn_decoder *decoder;
+  struct pt_config config;
+  int level, errcode;
+
+  if (btrace->size == 0)
+    return;
+
+  btinfo = &tp->btrace;
+  level = btinfo->begin != NULL ? -btinfo->level : INT_MAX;
+
+  pt_config_init(&config);
+  config.begin = btrace->data;
+  config.end = btrace->data + btrace->size;
+
+  config.cpu.vendor = pt_translate_cpu_vendor (btrace->config.cpu.vendor);
+  config.cpu.family = btrace->config.cpu.family;
+  config.cpu.model = btrace->config.cpu.model;
+  config.cpu.stepping = btrace->config.cpu.stepping;
+
+  errcode = pt_cpu_errata (&config.errata, &config.cpu);
+  if (errcode < 0)
+    error (_("Failed to configure the Intel(R) Processor Trace decoder: %s."),
+          pt_errstr (pt_errcode (errcode)));
+
+  decoder = pt_insn_alloc_decoder (&config);
+  if (decoder == NULL)
+    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
+
+  TRY
+    {
+      struct pt_image *image;
+
+      image = pt_insn_get_image(decoder);
+      if (image == NULL)
+       error (_("Failed to configure the Intel(R) Processor Trace decoder."));
+
+      errcode = pt_image_set_callback(image, btrace_pt_readmem_callback, NULL);
+      if (errcode < 0)
+       error (_("Failed to configure the Intel(R) Processor Trace decoder: "
+                "%s."), pt_errstr (pt_errcode (errcode)));
+
+      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
+                    &btinfo->ngaps);
+    }
+  CATCH (error, RETURN_MASK_ALL)
+    {
+      /* Indicate a gap in the trace if we quit trace processing.  */
+      if (error.reason == RETURN_QUIT && btinfo->end != NULL)
+       {
+         btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
+         btinfo->ngaps++;
+       }
+
+      btrace_finalize_ftrace_pt (decoder, tp, level);
+
+      throw_exception (error);
+    }
+  END_CATCH
+
+  btrace_finalize_ftrace_pt (decoder, tp, level);
+}
+
+#else /* defined (HAVE_LIBIPT)  */
+
+static void
+btrace_compute_ftrace_pt (struct thread_info *tp,
+                         const struct btrace_data_pt *btrace)
+{
+  internal_error (__FILE__, __LINE__, _("Unexpected branch trace format."));
+}
+
+#endif /* defined (HAVE_LIBIPT)  */
+
 /* Compute the function branch trace from a block branch trace BTRACE for
    a thread given by BTINFO.  */
 
@@ -694,6 +989,10 @@ btrace_compute_ftrace (struct thread_info *tp, struct btrace_data *btrace)
     case BTRACE_FORMAT_BTS:
       btrace_compute_ftrace_bts (tp, &btrace->variant.bts);
       return;
+
+    case BTRACE_FORMAT_PT:
+      btrace_compute_ftrace_pt (tp, &btrace->variant.pt);
+      return;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -903,6 +1202,10 @@ btrace_stitch_trace (struct btrace_data *btrace, struct thread_info *tp)
 
     case BTRACE_FORMAT_BTS:
       return btrace_stitch_bts (&btrace->variant.bts, tp);
+
+    case BTRACE_FORMAT_PT:
+      /* Delta reads are not supported.  */
+      return -1;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -922,6 +1225,33 @@ btrace_clear_history (struct btrace_thread_info *btinfo)
   btinfo->replay = NULL;
 }
 
+/* Clear the branch trace maintenance histories in BTINFO.  */
+
+static void
+btrace_maint_clear (struct btrace_thread_info *btinfo)
+{
+  switch (btinfo->data.format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      btinfo->maint.variant.bts.packet_history.begin = 0;
+      btinfo->maint.variant.bts.packet_history.end = 0;
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      xfree (btinfo->maint.variant.pt.packets);
+
+      btinfo->maint.variant.pt.packets = NULL;
+      btinfo->maint.variant.pt.packet_history.begin = 0;
+      btinfo->maint.variant.pt.packet_history.end = 0;
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
 /* See btrace.h.  */
 
 void
@@ -985,6 +1315,11 @@ btrace_fetch (struct thread_info *tp)
   /* Compute the trace, provided we have any.  */
   if (!btrace_data_empty (&btrace))
     {
+      /* Store the raw trace data.  The stored data will be cleared in
+        btrace_clear, so we always append the new trace.  */
+      btrace_data_append (&btinfo->data, &btrace);
+      btrace_maint_clear (btinfo);
+
       btrace_clear_history (btinfo);
       btrace_compute_ftrace (tp, &btrace);
     }
@@ -1021,6 +1356,9 @@ btrace_clear (struct thread_info *tp)
   btinfo->end = NULL;
   btinfo->ngaps = 0;
 
+  /* Must clear the maint data before - it depends on BTINFO->DATA.  */
+  btrace_maint_clear (btinfo);
+  btrace_data_clear (&btinfo->data);
   btrace_clear_history (btinfo);
 }
 
@@ -1046,7 +1384,8 @@ check_xml_btrace_version (struct gdb_xml_parser *parser,
                          const struct gdb_xml_element *element,
                          void *user_data, VEC (gdb_xml_value_s) *attributes)
 {
-  const char *version = xml_find_attribute (attributes, "version")->value;
+  const char *version
+    = (const char *) xml_find_attribute (attributes, "version")->value;
 
   if (strcmp (version, "1.0") != 0)
     gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version);
@@ -1063,7 +1402,7 @@ parse_xml_btrace_block (struct gdb_xml_parser *parser,
   struct btrace_block *block;
   ULONGEST *begin, *end;
 
-  btrace = user_data;
+  btrace = (struct btrace_data *) user_data;
 
   switch (btrace->format)
     {
@@ -1079,20 +1418,138 @@ parse_xml_btrace_block (struct gdb_xml_parser *parser,
       gdb_xml_error (parser, _("Btrace format error."));
     }
 
-  begin = xml_find_attribute (attributes, "begin")->value;
-  end = xml_find_attribute (attributes, "end")->value;
+  begin = (ULONGEST *) xml_find_attribute (attributes, "begin")->value;
+  end = (ULONGEST *) xml_find_attribute (attributes, "end")->value;
 
   block = VEC_safe_push (btrace_block_s, btrace->variant.bts.blocks, NULL);
   block->begin = *begin;
   block->end = *end;
 }
 
+/* Parse a "raw" xml record.  */
+
+static void
+parse_xml_raw (struct gdb_xml_parser *parser, const char *body_text,
+              gdb_byte **pdata, size_t *psize)
+{
+  struct cleanup *cleanup;
+  gdb_byte *data, *bin;
+  size_t len, size;
+
+  len = strlen (body_text);
+  if (len % 2 != 0)
+    gdb_xml_error (parser, _("Bad raw data size."));
+
+  size = len / 2;
+
+  bin = data = (gdb_byte *) xmalloc (size);
+  cleanup = make_cleanup (xfree, data);
+
+  /* We use hex encoding - see common/rsp-low.h.  */
+  while (len > 0)
+    {
+      char hi, lo;
+
+      hi = *body_text++;
+      lo = *body_text++;
+
+      if (hi == 0 || lo == 0)
+       gdb_xml_error (parser, _("Bad hex encoding."));
+
+      *bin++ = fromhex (hi) * 16 + fromhex (lo);
+      len -= 2;
+    }
+
+  discard_cleanups (cleanup);
+
+  *pdata = data;
+  *psize = size;
+}
+
+/* Parse a btrace pt-config "cpu" xml record.  */
+
+static void
+parse_xml_btrace_pt_config_cpu (struct gdb_xml_parser *parser,
+                               const struct gdb_xml_element *element,
+                               void *user_data,
+                               VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_data *btrace;
+  const char *vendor;
+  ULONGEST *family, *model, *stepping;
+
+  vendor = (const char *) xml_find_attribute (attributes, "vendor")->value;
+  family = (ULONGEST *) xml_find_attribute (attributes, "family")->value;
+  model = (ULONGEST *) xml_find_attribute (attributes, "model")->value;
+  stepping = (ULONGEST *) xml_find_attribute (attributes, "stepping")->value;
+
+  btrace = (struct btrace_data *) user_data;
+
+  if (strcmp (vendor, "GenuineIntel") == 0)
+    btrace->variant.pt.config.cpu.vendor = CV_INTEL;
+
+  btrace->variant.pt.config.cpu.family = *family;
+  btrace->variant.pt.config.cpu.model = *model;
+  btrace->variant.pt.config.cpu.stepping = *stepping;
+}
+
+/* Parse a btrace pt "raw" xml record.  */
+
+static void
+parse_xml_btrace_pt_raw (struct gdb_xml_parser *parser,
+                        const struct gdb_xml_element *element,
+                        void *user_data, const char *body_text)
+{
+  struct btrace_data *btrace;
+
+  btrace = (struct btrace_data *) user_data;
+  parse_xml_raw (parser, body_text, &btrace->variant.pt.data,
+                &btrace->variant.pt.size);
+}
+
+/* Parse a btrace "pt" xml record.  */
+
+static void
+parse_xml_btrace_pt (struct gdb_xml_parser *parser,
+                    const struct gdb_xml_element *element,
+                    void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_data *btrace;
+
+  btrace = (struct btrace_data *) user_data;
+  btrace->format = BTRACE_FORMAT_PT;
+  btrace->variant.pt.config.cpu.vendor = CV_UNKNOWN;
+  btrace->variant.pt.data = NULL;
+  btrace->variant.pt.size = 0;
+}
+
 static const struct gdb_xml_attribute block_attributes[] = {
   { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
+static const struct gdb_xml_attribute btrace_pt_config_cpu_attributes[] = {
+  { "vendor", GDB_XML_AF_NONE, NULL, NULL },
+  { "family", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "model", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "stepping", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_pt_config_children[] = {
+  { "cpu", btrace_pt_config_cpu_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_pt_config_cpu, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_pt_children[] = {
+  { "pt-config", NULL, btrace_pt_config_children, GDB_XML_EF_OPTIONAL, NULL,
+    NULL },
+  { "raw", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL, parse_xml_btrace_pt_raw },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute btrace_attributes[] = {
   { "version", GDB_XML_AF_NONE, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -1101,6 +1558,8 @@ static const struct gdb_xml_attribute btrace_attributes[] = {
 static const struct gdb_xml_element btrace_children[] = {
   { "block", block_attributes, NULL,
     GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL },
+  { "pt", NULL, btrace_pt_children, GDB_XML_EF_OPTIONAL, parse_xml_btrace_pt,
+    NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
@@ -1152,15 +1611,39 @@ parse_xml_btrace_conf_bts (struct gdb_xml_parser *parser,
   struct btrace_config *conf;
   struct gdb_xml_value *size;
 
-  conf = user_data;
+  conf = (struct btrace_config *) user_data;
   conf->format = BTRACE_FORMAT_BTS;
   conf->bts.size = 0;
 
   size = xml_find_attribute (attributes, "size");
   if (size != NULL)
-    conf->bts.size = (unsigned int) * (ULONGEST *) size->value;
+    conf->bts.size = (unsigned int) *(ULONGEST *) size->value;
+}
+
+/* Parse a btrace-conf "pt" xml record.  */
+
+static void
+parse_xml_btrace_conf_pt (struct gdb_xml_parser *parser,
+                         const struct gdb_xml_element *element,
+                         void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_config *conf;
+  struct gdb_xml_value *size;
+
+  conf = (struct btrace_config *) user_data;
+  conf->format = BTRACE_FORMAT_PT;
+  conf->pt.size = 0;
+
+  size = xml_find_attribute (attributes, "size");
+  if (size != NULL)
+    conf->pt.size = (unsigned int) *(ULONGEST *) size->value;
 }
 
+static const struct gdb_xml_attribute btrace_conf_pt_attributes[] = {
+  { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
   { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -1169,6 +1652,8 @@ static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
 static const struct gdb_xml_element btrace_conf_children[] = {
   { "bts", btrace_conf_bts_attributes, NULL, GDB_XML_EF_OPTIONAL,
     parse_xml_btrace_conf_bts, NULL },
+  { "pt", btrace_conf_pt_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_conf_pt, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
@@ -1712,7 +2197,7 @@ btrace_set_insn_history (struct btrace_thread_info *btinfo,
                         const struct btrace_insn_iterator *end)
 {
   if (btinfo->insn_history == NULL)
-    btinfo->insn_history = xzalloc (sizeof (*btinfo->insn_history));
+    btinfo->insn_history = XCNEW (struct btrace_insn_history);
 
   btinfo->insn_history->begin = *begin;
   btinfo->insn_history->end = *end;
@@ -1728,7 +2213,7 @@ btrace_set_call_history (struct btrace_thread_info *btinfo,
   gdb_assert (begin->btinfo == end->btinfo);
 
   if (btinfo->call_history == NULL)
-    btinfo->call_history = xzalloc (sizeof (*btinfo->call_history));
+    btinfo->call_history = XCNEW (struct btrace_call_history);
 
   btinfo->call_history->begin = *begin;
   btinfo->call_history->end = *end;
@@ -1766,7 +2251,7 @@ btrace_is_empty (struct thread_info *tp)
 static void
 do_btrace_data_cleanup (void *arg)
 {
-  btrace_data_fini (arg);
+  btrace_data_fini ((struct btrace_data *) arg);
 }
 
 /* See btrace.h.  */
@@ -1776,3 +2261,718 @@ make_cleanup_btrace_data (struct btrace_data *data)
 {
   return make_cleanup (do_btrace_data_cleanup, data);
 }
+
+#if defined (HAVE_LIBIPT)
+
+/* Print a single packet.  */
+
+static void
+pt_print_packet (const struct pt_packet *packet)
+{
+  switch (packet->type)
+    {
+    default:
+      printf_unfiltered (("[??: %x]"), packet->type);
+      break;
+
+    case ppt_psb:
+      printf_unfiltered (("psb"));
+      break;
+
+    case ppt_psbend:
+      printf_unfiltered (("psbend"));
+      break;
+
+    case ppt_pad:
+      printf_unfiltered (("pad"));
+      break;
+
+    case ppt_tip:
+      printf_unfiltered (("tip %u: 0x%" PRIx64 ""),
+                        packet->payload.ip.ipc,
+                        packet->payload.ip.ip);
+      break;
+
+    case ppt_tip_pge:
+      printf_unfiltered (("tip.pge %u: 0x%" PRIx64 ""),
+                        packet->payload.ip.ipc,
+                        packet->payload.ip.ip);
+      break;
+
+    case ppt_tip_pgd:
+      printf_unfiltered (("tip.pgd %u: 0x%" PRIx64 ""),
+                        packet->payload.ip.ipc,
+                        packet->payload.ip.ip);
+      break;
+
+    case ppt_fup:
+      printf_unfiltered (("fup %u: 0x%" PRIx64 ""),
+                        packet->payload.ip.ipc,
+                        packet->payload.ip.ip);
+      break;
+
+    case ppt_tnt_8:
+      printf_unfiltered (("tnt-8 %u: 0x%" PRIx64 ""),
+                        packet->payload.tnt.bit_size,
+                        packet->payload.tnt.payload);
+      break;
+
+    case ppt_tnt_64:
+      printf_unfiltered (("tnt-64 %u: 0x%" PRIx64 ""),
+                        packet->payload.tnt.bit_size,
+                        packet->payload.tnt.payload);
+      break;
+
+    case ppt_pip:
+      printf_unfiltered (("pip %" PRIx64 "%s"), packet->payload.pip.cr3,
+                        packet->payload.pip.nr ? (" nr") : (""));
+      break;
+
+    case ppt_tsc:
+      printf_unfiltered (("tsc %" PRIx64 ""), packet->payload.tsc.tsc);
+      break;
+
+    case ppt_cbr:
+      printf_unfiltered (("cbr %u"), packet->payload.cbr.ratio);
+      break;
+
+    case ppt_mode:
+      switch (packet->payload.mode.leaf)
+       {
+       default:
+         printf_unfiltered (("mode %u"), packet->payload.mode.leaf);
+         break;
+
+       case pt_mol_exec:
+         printf_unfiltered (("mode.exec%s%s"),
+                            packet->payload.mode.bits.exec.csl
+                            ? (" cs.l") : (""),
+                            packet->payload.mode.bits.exec.csd
+                            ? (" cs.d") : (""));
+         break;
+
+       case pt_mol_tsx:
+         printf_unfiltered (("mode.tsx%s%s"),
+                            packet->payload.mode.bits.tsx.intx
+                            ? (" intx") : (""),
+                            packet->payload.mode.bits.tsx.abrt
+                            ? (" abrt") : (""));
+         break;
+       }
+      break;
+
+    case ppt_ovf:
+      printf_unfiltered (("ovf"));
+      break;
+
+    case ppt_stop:
+      printf_unfiltered (("stop"));
+      break;
+
+    case ppt_vmcs:
+      printf_unfiltered (("vmcs %" PRIx64 ""), packet->payload.vmcs.base);
+      break;
+
+    case ppt_tma:
+      printf_unfiltered (("tma %x %x"), packet->payload.tma.ctc,
+                        packet->payload.tma.fc);
+      break;
+
+    case ppt_mtc:
+      printf_unfiltered (("mtc %x"), packet->payload.mtc.ctc);
+      break;
+
+    case ppt_cyc:
+      printf_unfiltered (("cyc %" PRIx64 ""), packet->payload.cyc.value);
+      break;
+
+    case ppt_mnt:
+      printf_unfiltered (("mnt %" PRIx64 ""), packet->payload.mnt.payload);
+      break;
+    }
+}
+
+/* Decode packets into MAINT using DECODER.  */
+
+static void
+btrace_maint_decode_pt (struct btrace_maint_info *maint,
+                       struct pt_packet_decoder *decoder)
+{
+  int errcode;
+
+  for (;;)
+    {
+      struct btrace_pt_packet packet;
+
+      errcode = pt_pkt_sync_forward (decoder);
+      if (errcode < 0)
+       break;
+
+      for (;;)
+       {
+         pt_pkt_get_offset (decoder, &packet.offset);
+
+         errcode = pt_pkt_next (decoder, &packet.packet,
+                                sizeof(packet.packet));
+         if (errcode < 0)
+           break;
+
+         if (maint_btrace_pt_skip_pad == 0 || packet.packet.type != ppt_pad)
+           {
+             packet.errcode = pt_errcode (errcode);
+             VEC_safe_push (btrace_pt_packet_s, maint->variant.pt.packets,
+                            &packet);
+           }
+       }
+
+      if (errcode == -pte_eos)
+       break;
+
+      packet.errcode = pt_errcode (errcode);
+      VEC_safe_push (btrace_pt_packet_s, maint->variant.pt.packets,
+                    &packet);
+
+      warning (_("Error at trace offset 0x%" PRIx64 ": %s."),
+              packet.offset, pt_errstr (packet.errcode));
+    }
+
+  if (errcode != -pte_eos)
+    warning (_("Failed to synchronize onto the Intel(R) Processor Trace "
+              "stream: %s."), pt_errstr (pt_errcode (errcode)));
+}
+
+/* Update the packet history in BTINFO.  */
+
+static void
+btrace_maint_update_pt_packets (struct btrace_thread_info *btinfo)
+{
+  volatile struct gdb_exception except;
+  struct pt_packet_decoder *decoder;
+  struct btrace_data_pt *pt;
+  struct pt_config config;
+  int errcode;
+
+  pt = &btinfo->data.variant.pt;
+
+  /* Nothing to do if there is no trace.  */
+  if (pt->size == 0)
+    return;
+
+  memset (&config, 0, sizeof(config));
+
+  config.size = sizeof (config);
+  config.begin = pt->data;
+  config.end = pt->data + pt->size;
+
+  config.cpu.vendor = pt_translate_cpu_vendor (pt->config.cpu.vendor);
+  config.cpu.family = pt->config.cpu.family;
+  config.cpu.model = pt->config.cpu.model;
+  config.cpu.stepping = pt->config.cpu.stepping;
+
+  errcode = pt_cpu_errata (&config.errata, &config.cpu);
+  if (errcode < 0)
+    error (_("Failed to configure the Intel(R) Processor Trace decoder: %s."),
+          pt_errstr (pt_errcode (errcode)));
+
+  decoder = pt_pkt_alloc_decoder (&config);
+  if (decoder == NULL)
+    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
+
+  TRY
+    {
+      btrace_maint_decode_pt (&btinfo->maint, decoder);
+    }
+  CATCH (except, RETURN_MASK_ALL)
+    {
+      pt_pkt_free_decoder (decoder);
+
+      if (except.reason < 0)
+       throw_exception (except);
+    }
+  END_CATCH
+
+  pt_pkt_free_decoder (decoder);
+}
+
+#endif /* !defined (HAVE_LIBIPT)  */
+
+/* Update the packet maintenance information for BTINFO and store the
+   low and high bounds into BEGIN and END, respectively.
+   Store the current iterator state into FROM and TO.  */
+
+static void
+btrace_maint_update_packets (struct btrace_thread_info *btinfo,
+                            unsigned int *begin, unsigned int *end,
+                            unsigned int *from, unsigned int *to)
+{
+  switch (btinfo->data.format)
+    {
+    default:
+      *begin = 0;
+      *end = 0;
+      *from = 0;
+      *to = 0;
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      /* Nothing to do - we operate directly on BTINFO->DATA.  */
+      *begin = 0;
+      *end = VEC_length (btrace_block_s, btinfo->data.variant.bts.blocks);
+      *from = btinfo->maint.variant.bts.packet_history.begin;
+      *to = btinfo->maint.variant.bts.packet_history.end;
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      if (VEC_empty (btrace_pt_packet_s, btinfo->maint.variant.pt.packets))
+       btrace_maint_update_pt_packets (btinfo);
+
+      *begin = 0;
+      *end = VEC_length (btrace_pt_packet_s, btinfo->maint.variant.pt.packets);
+      *from = btinfo->maint.variant.pt.packet_history.begin;
+      *to = btinfo->maint.variant.pt.packet_history.end;
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
+/* Print packets in BTINFO from BEGIN (inclusive) until END (exclusive) and
+   update the current iterator position.  */
+
+static void
+btrace_maint_print_packets (struct btrace_thread_info *btinfo,
+                           unsigned int begin, unsigned int end)
+{
+  switch (btinfo->data.format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      {
+       VEC (btrace_block_s) *blocks;
+       unsigned int blk;
+
+       blocks = btinfo->data.variant.bts.blocks;
+       for (blk = begin; blk < end; ++blk)
+         {
+           const btrace_block_s *block;
+
+           block = VEC_index (btrace_block_s, blocks, blk);
+
+           printf_unfiltered ("%u\tbegin: %s, end: %s\n", blk,
+                              core_addr_to_string_nz (block->begin),
+                              core_addr_to_string_nz (block->end));
+         }
+
+       btinfo->maint.variant.bts.packet_history.begin = begin;
+       btinfo->maint.variant.bts.packet_history.end = end;
+      }
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      {
+       VEC (btrace_pt_packet_s) *packets;
+       unsigned int pkt;
+
+       packets = btinfo->maint.variant.pt.packets;
+       for (pkt = begin; pkt < end; ++pkt)
+         {
+           const struct btrace_pt_packet *packet;
+
+           packet = VEC_index (btrace_pt_packet_s, packets, pkt);
+
+           printf_unfiltered ("%u\t", pkt);
+           printf_unfiltered ("0x%" PRIx64 "\t", packet->offset);
+
+           if (packet->errcode == pte_ok)
+             pt_print_packet (&packet->packet);
+           else
+             printf_unfiltered ("[error: %s]", pt_errstr (packet->errcode));
+
+           printf_unfiltered ("\n");
+         }
+
+       btinfo->maint.variant.pt.packet_history.begin = begin;
+       btinfo->maint.variant.pt.packet_history.end = end;
+      }
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
+/* Read a number from an argument string.  */
+
+static unsigned int
+get_uint (char **arg)
+{
+  char *begin, *end, *pos;
+  unsigned long number;
+
+  begin = *arg;
+  pos = skip_spaces (begin);
+
+  if (!isdigit (*pos))
+    error (_("Expected positive number, got: %s."), pos);
+
+  number = strtoul (pos, &end, 10);
+  if (number > UINT_MAX)
+    error (_("Number too big."));
+
+  *arg += (end - begin);
+
+  return (unsigned int) number;
+}
+
+/* Read a context size from an argument string.  */
+
+static int
+get_context_size (char **arg)
+{
+  char *pos;
+  int number;
+
+  pos = skip_spaces (*arg);
+
+  if (!isdigit (*pos))
+    error (_("Expected positive number, got: %s."), pos);
+
+  return strtol (pos, arg, 10);
+}
+
+/* Complain about junk at the end of an argument string.  */
+
+static void
+no_chunk (char *arg)
+{
+  if (*arg != 0)
+    error (_("Junk after argument: %s."), arg);
+}
+
+/* The "maintenance btrace packet-history" command.  */
+
+static void
+maint_btrace_packet_history_cmd (char *arg, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+  unsigned int size, begin, end, from, to;
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  size = 10;
+  btinfo = &tp->btrace;
+
+  btrace_maint_update_packets (btinfo, &begin, &end, &from, &to);
+  if (begin == end)
+    {
+      printf_unfiltered (_("No trace.\n"));
+      return;
+    }
+
+  if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
+    {
+      from = to;
+
+      if (end - from < size)
+       size = end - from;
+      to = from + size;
+    }
+  else if (strcmp (arg, "-") == 0)
+    {
+      to = from;
+
+      if (to - begin < size)
+       size = to - begin;
+      from = to - size;
+    }
+  else
+    {
+      from = get_uint (&arg);
+      if (end <= from)
+       error (_("'%u' is out of range."), from);
+
+      arg = skip_spaces (arg);
+      if (*arg == ',')
+       {
+         arg = skip_spaces (++arg);
+
+         if (*arg == '+')
+           {
+             arg += 1;
+             size = get_context_size (&arg);
+
+             no_chunk (arg);
+
+             if (end - from < size)
+               size = end - from;
+             to = from + size;
+           }
+         else if (*arg == '-')
+           {
+             arg += 1;
+             size = get_context_size (&arg);
+
+             no_chunk (arg);
+
+             /* Include the packet given as first argument.  */
+             from += 1;
+             to = from;
+
+             if (to - begin < size)
+               size = to - begin;
+             from = to - size;
+           }
+         else
+           {
+             to = get_uint (&arg);
+
+             /* Include the packet at the second argument and silently
+                truncate the range.  */
+             if (to < end)
+               to += 1;
+             else
+               to = end;
+
+             no_chunk (arg);
+           }
+       }
+      else
+       {
+         no_chunk (arg);
+
+         if (end - from < size)
+           size = end - from;
+         to = from + size;
+       }
+
+      dont_repeat ();
+    }
+
+  btrace_maint_print_packets (btinfo, from, to);
+}
+
+/* The "maintenance btrace clear-packet-history" command.  */
+
+static void
+maint_btrace_clear_packet_history_cmd (char *args, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  btinfo = &tp->btrace;
+
+  /* Must clear the maint data before - it depends on BTINFO->DATA.  */
+  btrace_maint_clear (btinfo);
+  btrace_data_clear (&btinfo->data);
+}
+
+/* The "maintenance btrace clear" command.  */
+
+static void
+maint_btrace_clear_cmd (char *args, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  btrace_clear (tp);
+}
+
+/* The "maintenance btrace" command.  */
+
+static void
+maint_btrace_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_cmdlist, "maintenance btrace ", all_commands,
+            gdb_stdout);
+}
+
+/* The "maintenance set btrace" command.  */
+
+static void
+maint_btrace_set_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_set_cmdlist, "maintenance set btrace ", all_commands,
+            gdb_stdout);
+}
+
+/* The "maintenance show btrace" command.  */
+
+static void
+maint_btrace_show_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_show_cmdlist, "maintenance show btrace ",
+            all_commands, gdb_stdout);
+}
+
+/* The "maintenance set btrace pt" command.  */
+
+static void
+maint_btrace_pt_set_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_pt_set_cmdlist, "maintenance set btrace pt ",
+            all_commands, gdb_stdout);
+}
+
+/* The "maintenance show btrace pt" command.  */
+
+static void
+maint_btrace_pt_show_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_pt_show_cmdlist, "maintenance show btrace pt ",
+            all_commands, gdb_stdout);
+}
+
+/* The "maintenance info btrace" command.  */
+
+static void
+maint_info_btrace_cmd (char *args, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+  const struct btrace_config *conf;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  btinfo = &tp->btrace;
+
+  conf = btrace_conf (btinfo);
+  if (conf == NULL)
+    error (_("No btrace configuration."));
+
+  printf_unfiltered (_("Format: %s.\n"),
+                    btrace_format_string (conf->format));
+
+  switch (conf->format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      printf_unfiltered (_("Number of packets: %u.\n"),
+                        VEC_length (btrace_block_s,
+                                    btinfo->data.variant.bts.blocks));
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      {
+       struct pt_version version;
+
+       version = pt_library_version ();
+       printf_unfiltered (_("Version: %u.%u.%u%s.\n"), version.major,
+                          version.minor, version.build,
+                          version.ext != NULL ? version.ext : "");
+
+       btrace_maint_update_pt_packets (btinfo);
+       printf_unfiltered (_("Number of packets: %u.\n"),
+                          VEC_length (btrace_pt_packet_s,
+                                      btinfo->maint.variant.pt.packets));
+      }
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
+/* The "maint show btrace pt skip-pad" show value function. */
+
+static void
+show_maint_btrace_pt_skip_pad  (struct ui_file *file, int from_tty,
+                                 struct cmd_list_element *c,
+                                 const char *value)
+{
+  fprintf_filtered (file, _("Skip PAD packets is %s.\n"), value);
+}
+
+
+/* Initialize btrace maintenance commands.  */
+
+void _initialize_btrace (void);
+void
+_initialize_btrace (void)
+{
+  add_cmd ("btrace", class_maintenance, maint_info_btrace_cmd,
+          _("Info about branch tracing data."), &maintenanceinfolist);
+
+  add_prefix_cmd ("btrace", class_maintenance, maint_btrace_cmd,
+                 _("Branch tracing maintenance commands."),
+                 &maint_btrace_cmdlist, "maintenance btrace ",
+                 0, &maintenancelist);
+
+  add_prefix_cmd ("btrace", class_maintenance, maint_btrace_set_cmd, _("\
+Set branch tracing specific variables."),
+                  &maint_btrace_set_cmdlist, "maintenance set btrace ",
+                  0, &maintenance_set_cmdlist);
+
+  add_prefix_cmd ("pt", class_maintenance, maint_btrace_pt_set_cmd, _("\
+Set Intel(R) Processor Trace specific variables."),
+                  &maint_btrace_pt_set_cmdlist, "maintenance set btrace pt ",
+                  0, &maint_btrace_set_cmdlist);
+
+  add_prefix_cmd ("btrace", class_maintenance, maint_btrace_show_cmd, _("\
+Show branch tracing specific variables."),
+                  &maint_btrace_show_cmdlist, "maintenance show btrace ",
+                  0, &maintenance_show_cmdlist);
+
+  add_prefix_cmd ("pt", class_maintenance, maint_btrace_pt_show_cmd, _("\
+Show Intel(R) Processor Trace specific variables."),
+                  &maint_btrace_pt_show_cmdlist, "maintenance show btrace pt ",
+                  0, &maint_btrace_show_cmdlist);
+
+  add_setshow_boolean_cmd ("skip-pad", class_maintenance,
+                          &maint_btrace_pt_skip_pad, _("\
+Set whether PAD packets should be skipped in the btrace packet history."), _("\
+Show whether PAD packets should be skipped in the btrace packet history."),_("\
+When enabled, PAD packets are ignored in the btrace packet history."),
+                          NULL, show_maint_btrace_pt_skip_pad,
+                          &maint_btrace_pt_set_cmdlist,
+                          &maint_btrace_pt_show_cmdlist);
+
+  add_cmd ("packet-history", class_maintenance, maint_btrace_packet_history_cmd,
+          _("Print the raw branch tracing data.\n\
+With no argument, print ten more packets after the previous ten-line print.\n\
+With '-' as argument print ten packets before a previous ten-line print.\n\
+One argument specifies the starting packet of a ten-line print.\n\
+Two arguments with comma between specify starting and ending packets to \
+print.\n\
+Preceded with '+'/'-' the second argument specifies the distance from the \
+first.\n"),
+          &maint_btrace_cmdlist);
+
+  add_cmd ("clear-packet-history", class_maintenance,
+          maint_btrace_clear_packet_history_cmd,
+          _("Clears the branch tracing packet history.\n\
+Discards the raw branch tracing data but not the execution history data.\n\
+"),
+          &maint_btrace_cmdlist);
+
+  add_cmd ("clear", class_maintenance, maint_btrace_clear_cmd,
+          _("Clears the branch tracing data.\n\
+Discards the raw branch tracing data and the execution history data.\n\
+The next 'record' command will fetch the branch tracing data anew.\n\
+"),
+          &maint_btrace_cmdlist);
+
+}
This page took 0.036378 seconds and 4 git commands to generate.