X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fnat%2Flinux-btrace.c;h=b87faf98b2c2db42979b9164d530a8ea2871fd8f;hb=1ee1a363454d88a87ad2ade7530b2a7fb670021e;hp=42f56f9ed30a2dfa4b8a72a87fa93d9d411670b3;hpb=de6242d3075700ec4b73bdee583dc216f3a0b046;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c index 42f56f9ed3..b87faf98b2 100644 --- a/gdb/nat/linux-btrace.c +++ b/gdb/nat/linux-btrace.c @@ -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. @@ -19,14 +19,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#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 @@ -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 * 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 = new std::vector; 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 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. */