Don't write to inferior_ptid in go32-nat.c
[deliverable/binutils-gdb.git] / gdb / nat / linux-btrace.c
index 42f56f9ed30a2dfa4b8a72a87fa93d9d411670b3..b87faf98b2c2db42979b9164d530a8ea2871fd8f 100644 (file)
@@ -1,6 +1,6 @@
 /* Linux-dependent part of branch trace support for GDB, and GDBserver.
 
-   Copyright (C) 2013-2018 Free Software Foundation, Inc.
+   Copyright (C) 2013-2020 Free Software Foundation, Inc.
 
    Contributed by Intel Corp. <markus.t.metzger@intel.com>
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include "common-defs.h"
+#include "gdbsupport/common-defs.h"
 #include "linux-btrace.h"
-#include "common-regcache.h"
-#include "gdb_wait.h"
+#include "gdbsupport/common-regcache.h"
+#include "gdbsupport/gdb_wait.h"
 #include "x86-cpuid.h"
-#include "filestuff.h"
-#include "common/scoped_fd.h"
-#include "common/scoped_mmap.h"
+#include "gdbsupport/filestuff.h"
+#include "gdbsupport/scoped_fd.h"
+#include "gdbsupport/scoped_mmap.h"
 
 #include <inttypes.h>
 
@@ -90,6 +90,9 @@ btrace_this_cpu (void)
                cpu.model += (cpuid >> 12) & 0xf0;
            }
        }
+      else if (ebx == signature_AMD_ebx && ecx == signature_AMD_ecx
+              && edx == signature_AMD_edx)
+       cpu.vendor = CV_AMD;
     }
 
   return cpu;
@@ -271,11 +274,11 @@ perf_event_sample_ok (const struct perf_event_sample *sample)
    In case the buffer overflows during sampling, one sample may have its lower
    part at the end and its upper part at the beginning of the buffer.  */
 
-static VEC (btrace_block_s) *
+static std::vector<btrace_block> *
 perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
                     const uint8_t *end, const uint8_t *start, size_t size)
 {
-  VEC (btrace_block_s) *btrace = NULL;
+  std::vector<btrace_block> *btrace = new std::vector<btrace_block>;
   struct perf_event_sample sample;
   size_t read = 0;
   struct btrace_block block = { 0, 0 };
@@ -343,7 +346,7 @@ perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
       /* We found a valid sample, so we can complete the current block.  */
       block.begin = psample->bts.to;
 
-      VEC_safe_push (btrace_block_s, btrace, &block);
+      btrace->push_back (block);
 
       /* Start the next block.  */
       block.end = psample->bts.from;
@@ -354,7 +357,7 @@ perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
      reading delta trace, we can fill in the start address later on.
      Otherwise we will prune it.  */
   block.begin = 0;
-  VEC_safe_push (btrace_block_s, btrace, &block);
+  btrace->push_back (block);
 
   return btrace;
 }
@@ -406,9 +409,40 @@ cpu_supports_bts (void)
 
     case CV_INTEL:
       return intel_supports_bts (&cpu);
+
+    case CV_AMD:
+      return 0;
     }
 }
 
+/* The perf_event_open syscall failed.  Try to print a helpful error
+   message.  */
+
+static void
+diagnose_perf_event_open_fail ()
+{
+  switch (errno)
+    {
+    case EPERM:
+    case EACCES:
+      {
+       static const char filename[] = "/proc/sys/kernel/perf_event_paranoid";
+       gdb_file_up file = gdb_fopen_cloexec (filename, "r");
+       if (file.get () == nullptr)
+         break;
+
+       int level, found = fscanf (file.get (), "%d", &level);
+       if (found == 1 && level > 2)
+         error (_("You do not have permission to record the process.  "
+                  "Try setting %s to 2 or less."), filename);
+      }
+
+      break;
+    }
+
+  error (_("Failed to start recording: %s"), safe_strerror (errno));
+}
+
 /* Enable branch tracing in BTS format.  */
 
 static struct btrace_target_info *
@@ -441,14 +475,14 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   bts->attr.exclude_hv = 1;
   bts->attr.exclude_idle = 1;
 
-  pid = ptid_get_lwp (ptid);
+  pid = ptid.lwp ();
   if (pid == 0)
-    pid = ptid_get_pid (ptid);
+    pid = ptid.pid ();
 
   errno = 0;
   scoped_fd fd (syscall (SYS_perf_event_open, &bts->attr, pid, -1, -1, 0));
   if (fd.get () < 0)
-    return nullptr;
+    diagnose_perf_event_open_fail ();
 
   /* Convert the requested size in bytes to pages (rounding up).  */
   pages = ((size_t) conf->size / PAGE_SIZE
@@ -484,6 +518,7 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
       if ((__u64) length != data_size + PAGE_SIZE)
        continue;
 
+      errno = 0;
       /* The number of pages we request needs to be a power of two.  */
       data.reset (nullptr, length, PROT_READ, MAP_SHARED, fd.get (), 0);
       if (data.get () != MAP_FAILED)
@@ -491,7 +526,7 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
     }
 
   if (pages == 0)
-    return nullptr;
+    error (_("Failed to map trace buffer: %s."), safe_strerror (errno));
 
   struct perf_event_mmap_page *header = (struct perf_event_mmap_page *)
     data.get ();
@@ -509,40 +544,40 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
 
       /* Check for overflows.  */
       if ((__u64) size != data_size)
-       return nullptr;
+       error (_("Failed to determine trace buffer size."));
     }
 #endif /* defined (PERF_ATTR_SIZE_VER5) */
 
   bts->bts.size = size;
   bts->bts.data_head = &header->data_head;
-  bts->bts.mem = (const uint8_t *) data.get () + data_offset;
+  bts->bts.mem = (const uint8_t *) data.release () + data_offset;
   bts->bts.last_head = 0ull;
   bts->header = header;
   bts->file = fd.release ();
 
-  data.release ();
-
   tinfo->conf.bts.size = (unsigned int) size;
   return tinfo.release ();
 }
 
 #if defined (PERF_ATTR_SIZE_VER5)
 
-/* Determine the event type.
-   Returns zero on success and fills in TYPE; returns -1 otherwise.  */
+/* Determine the event type.  */
 
 static int
-perf_event_pt_event_type (int *type)
+perf_event_pt_event_type ()
 {
-  gdb_file_up file =
-    gdb_fopen_cloexec ("/sys/bus/event_source/devices/intel_pt/type", "r");
+  static const char filename[] = "/sys/bus/event_source/devices/intel_pt/type";
+
+  errno = 0;
+  gdb_file_up file = gdb_fopen_cloexec (filename, "r");
   if (file.get () == nullptr)
-    return -1;
+    error (_("Failed to open %s: %s."), filename, safe_strerror (errno));
 
-  int found = fscanf (file.get (), "%d", type);
-  if (found == 1)
-    return 0;
-  return -1;
+  int type, found = fscanf (file.get (), "%d", &type);
+  if (found != 1)
+    error (_("Failed to read the PT event type from %s."), filename);
+
+  return type;
 }
 
 /* Enable branch tracing in Intel Processor Trace format.  */
@@ -552,18 +587,11 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
 {
   struct btrace_tinfo_pt *pt;
   size_t pages;
-  int pid, pg, errcode, type;
-
-  if (conf->size == 0)
-    return NULL;
-
-  errcode = perf_event_pt_event_type (&type);
-  if (errcode != 0)
-    return NULL;
+  int pid, pg;
 
-  pid = ptid_get_lwp (ptid);
+  pid = ptid.lwp ();
   if (pid == 0)
-    pid = ptid_get_pid (ptid);
+    pid = ptid.pid ();
 
   gdb::unique_xmalloc_ptr<btrace_target_info> tinfo
     (XCNEW (btrace_target_info));
@@ -573,7 +601,7 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
   pt = &tinfo->variant.pt;
 
   pt->attr.size = sizeof (pt->attr);
-  pt->attr.type = type;
+  pt->attr.type = perf_event_pt_event_type ();
 
   pt->attr.exclude_kernel = 1;
   pt->attr.exclude_hv = 1;
@@ -582,13 +610,13 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
   errno = 0;
   scoped_fd fd (syscall (SYS_perf_event_open, &pt->attr, pid, -1, -1, 0));
   if (fd.get () < 0)
-    return nullptr;
+    diagnose_perf_event_open_fail ();
 
   /* Allocate the configuration page. */
   scoped_mmap data (nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd.get (), 0);
   if (data.get () == MAP_FAILED)
-    return nullptr;
+    error (_("Failed to map trace user page: %s."), safe_strerror (errno));
 
   struct perf_event_mmap_page *header = (struct perf_event_mmap_page *)
     data.get ();
@@ -630,6 +658,7 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
 
       header->aux_size = data_size;
 
+      errno = 0;
       aux.reset (nullptr, length, PROT_READ, MAP_SHARED, fd.get (),
                 header->aux_offset);
       if (aux.get () != MAP_FAILED)
@@ -637,16 +666,15 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
     }
 
   if (pages == 0)
-    return nullptr;
+    error (_("Failed to map trace buffer: %s."), safe_strerror (errno));
 
   pt->pt.size = aux.size ();
   pt->pt.mem = (const uint8_t *) aux.release ();
   pt->pt.data_head = &header->aux_head;
-  pt->header = header;
+  pt->header = (struct perf_event_mmap_page *) data.release ();
+  gdb_assert (pt->header == header);
   pt->file = fd.release ();
 
-  data.release ();
-
   tinfo->conf.pt.size = (unsigned int) pt->pt.size;
   return tinfo.release ();
 }
@@ -656,8 +684,7 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
 static struct btrace_target_info *
 linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
 {
-  errno = EOPNOTSUPP;
-  return NULL;
+  error (_("Intel Processor Trace support was disabled at compile time."));
 }
 
 #endif /* !defined (PERF_ATTR_SIZE_VER5) */
@@ -667,27 +694,20 @@ linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
 struct btrace_target_info *
 linux_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
 {
-  struct btrace_target_info *tinfo;
-
-  tinfo = NULL;
   switch (conf->format)
     {
     case BTRACE_FORMAT_NONE:
-      break;
+      error (_("Bad branch trace format."));
+
+    default:
+      error (_("Unknown branch trace format."));
 
     case BTRACE_FORMAT_BTS:
-      tinfo = linux_enable_bts (ptid, &conf->bts);
-      break;
+      return linux_enable_bts (ptid, &conf->bts);
 
     case BTRACE_FORMAT_PT:
-      tinfo = linux_enable_pt (ptid, &conf->pt);
-      break;
+      return linux_enable_pt (ptid, &conf->pt);
     }
-
-  if (tinfo == NULL)
-    error (_("Unknown error."));
-
-  return tinfo;
 }
 
 /* Disable BTS tracing.  */
@@ -771,7 +791,8 @@ linux_read_bts (struct btrace_data_bts *btrace,
       data_head = *pevent->data_head;
 
       /* Delete any leftover trace from the previous iteration.  */
-      VEC_free (btrace_block_s, btrace->blocks);
+      delete btrace->blocks;
+      btrace->blocks = nullptr;
 
       if (type == BTRACE_READ_DELTA)
        {
@@ -829,9 +850,8 @@ linux_read_bts (struct btrace_data_bts *btrace,
   /* Prune the incomplete last block (i.e. the first one of inferior execution)
      if we're not doing a delta read.  There is no way of filling in its zeroed
      BEGIN element.  */
-  if (!VEC_empty (btrace_block_s, btrace->blocks)
-      && type != BTRACE_READ_DELTA)
-    VEC_pop (btrace_block_s, btrace->blocks);
+  if (!btrace->blocks->empty () && type != BTRACE_READ_DELTA)
+    btrace->blocks->pop_back ();
 
   return BTRACE_ERR_NONE;
 }
@@ -875,7 +895,7 @@ linux_read_pt (struct btrace_data_pt *btrace,
       return BTRACE_ERR_NONE;
     }
 
-  internal_error (__FILE__, __LINE__, _("Unkown btrace read type."));
+  internal_error (__FILE__, __LINE__, _("Unknown btrace read type."));
 }
 
 /* See linux-btrace.h.  */
This page took 0.029024 seconds and 4 git commands to generate.