forked from Minki/linux
f6edb53c49
When doing a system-wide trace with Intel PT, the jump label set up as a result of probing CLOEXEC gets reset while the trace is running. That causes an Intel PT decoding error because the object code (obtained from /proc/kcore) does not match the running code at that point. While we can't expect there never to be jump label changes, we can avoid cases that the perf tool itself creates. The problem is avoided by first trying a cpu-wide event (pid = -1) for probing the PERF_FLAG_FD_CLOEXEC flag and falling back to an event for the current process (pid = 0). Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1407855871-15024-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
73 lines
1.4 KiB
C
73 lines
1.4 KiB
C
#include <sched.h>
|
|
#include "util.h"
|
|
#include "../perf.h"
|
|
#include "cloexec.h"
|
|
#include "asm/bug.h"
|
|
|
|
static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
|
|
|
|
static int perf_flag_probe(void)
|
|
{
|
|
/* use 'safest' configuration as used in perf_evsel__fallback() */
|
|
struct perf_event_attr attr = {
|
|
.type = PERF_TYPE_SOFTWARE,
|
|
.config = PERF_COUNT_SW_CPU_CLOCK,
|
|
.exclude_kernel = 1,
|
|
};
|
|
int fd;
|
|
int err;
|
|
int cpu;
|
|
pid_t pid = -1;
|
|
|
|
cpu = sched_getcpu();
|
|
if (cpu < 0)
|
|
cpu = 0;
|
|
|
|
while (1) {
|
|
/* check cloexec flag */
|
|
fd = sys_perf_event_open(&attr, pid, cpu, -1,
|
|
PERF_FLAG_FD_CLOEXEC);
|
|
if (fd < 0 && pid == -1 && errno == EACCES) {
|
|
pid = 0;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
err = errno;
|
|
|
|
if (fd >= 0) {
|
|
close(fd);
|
|
return 1;
|
|
}
|
|
|
|
WARN_ONCE(err != EINVAL && err != EBUSY,
|
|
"perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
|
|
err, strerror(err));
|
|
|
|
/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
|
|
fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
|
|
err = errno;
|
|
|
|
if (WARN_ONCE(fd < 0 && err != EBUSY,
|
|
"perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
|
|
err, strerror(err)))
|
|
return -1;
|
|
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned long perf_event_open_cloexec_flag(void)
|
|
{
|
|
static bool probed;
|
|
|
|
if (!probed) {
|
|
if (perf_flag_probe() <= 0)
|
|
flag = 0;
|
|
probed = true;
|
|
}
|
|
|
|
return flag;
|
|
}
|