perf/core improvements and fixes:
New features: - Allow passing C language eBPF scriptlets via --event in all tools, so that it gets built using clang and then pass it to the kernel via sys_bpf() (Wang Nan) - Wire up the loaded ebpf object file with associated kprobes, so that it can determine if the kprobes will be filtered or not (Wang Nan) User visible: - Add cmd string table to decode sys_bpf first arg in 'trace' (Arnaldo Carvalho de Melo) - Enable printing of branch stack in 'perf script' (Stephane Eranian) - Pass the right file with debug info to libunwind (Rabin Vincent) Build Fixes: - Make sure fixdep is built before libbpf, fixing a race (Jiri Olsa) - Fix libiberty feature detection (Rabin Vincent) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWMqXLAAoJENZQFvNTUqpAheYP/0uYHUyYI9cNjF6/85cTotHS V+qXWxHAoYzBoTXmDVBEz25sA7yC1M4h+xPqQjI8ZnAe2ChJcqLZSsqkViMDZRV7 LZhC5WIZ6EN0AaP/KUkTdDEm/bblm0mN1LX6v8BKFD5F8T5K8ur6Ml8w0vN27bbA WFb8SXjP3prt1xedR2UDilZqkB712ycOVH9LdePWlzHwsLt6ZyX2S85zwZVZkHnU tNHx6d3lG30imFNmq8fp7ShruD+yTmCY7fNdMFgv0t/XfVtyNaZeF/GswQGSRAIm osWmB0N23NqmhcQ239pNGlJGggWfemhCWOGxsZx0L1GLTnqA8OxBI1RMtFqjyNzn Mqu4WjQuXEGeHo9ZFwwieqa2z0d8j4IE7C/+L9DZiJZiZ+Dfn9v4NQ/3kK6kSNLX xvN54Td3flGz0vcHik4tnvU3R1Xocl10nOE0tXwJGns6w9TjteKCwdW5biTX3BCh zkbuASVAWrSTQ6/VSQ90UMdhwhgBFvTvVCxhsp37JX94beuA/D7HqwxNTecdS+/D ilTXTpLn9e6oeYryvMjlHMgpEh+q9gZEWyuhU8dowAl88UCR26O9SqCu/EgbpMSL cJGRbuYIb+IX1yUQmHRLT5JUxDgpXPwWaBoscSyElaAHdLE1dwcyoi/LcogxbdbQ OdLCmN2MvBoJzyOrCEPA =7aUd -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: New features: - Allow passing C language eBPF scriptlets via --event in all tools, so that it gets built using clang and then pass it to the kernel via sys_bpf(). (Wang Nan) - Wire up the loaded ebpf object file with associated kprobes, so that it can determine if the kprobes will be filtered or not. (Wang Nan) User visible changes: - Add cmd string table to decode sys_bpf first arg in 'trace'. (Arnaldo Carvalho de Melo) - Enable printing of branch stack in 'perf script'. (Stephane Eranian) - Pass the right file with debug info to libunwind. (Rabin Vincent) Build Fixes: - Make sure fixdep is built before libbpf, fixing a race. (Jiri Olsa) - Fix libiberty feature detection. (Rabin Vincent) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Коммит
bebd23a2ed
|
@ -132,10 +132,10 @@ test-libbfd.bin:
|
|||
$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
|
||||
|
||||
test-liberty.bin:
|
||||
$(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
|
||||
$(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
|
||||
|
||||
test-liberty-z.bin:
|
||||
$(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
|
||||
$(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
|
||||
|
||||
test-cplus-demangle.bin:
|
||||
$(BUILD) -liberty
|
||||
|
|
|
@ -314,6 +314,12 @@ This option sets the time out limit. The default value is 500 ms.
|
|||
Record context switch events i.e. events of type PERF_RECORD_SWITCH or
|
||||
PERF_RECORD_SWITCH_CPU_WIDE.
|
||||
|
||||
--clang-path::
|
||||
Path to clang binary to use for compiling BPF scriptlets.
|
||||
|
||||
--clang-opt::
|
||||
Options passed to clang when compiling BPF scriptlets.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-stat[1], linkperf:perf-list[1]
|
||||
|
|
|
@ -112,11 +112,11 @@ OPTIONS
|
|||
--debug-mode::
|
||||
Do various checks like samples ordering and lost events.
|
||||
|
||||
-f::
|
||||
-F::
|
||||
--fields::
|
||||
Comma separated list of fields to print. Options are:
|
||||
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
|
||||
srcline, period, iregs, flags.
|
||||
srcline, period, iregs, brstack, brstacksym, flags.
|
||||
Field list can be prepended with the type, trace, sw or hw,
|
||||
to indicate to which event type the field list applies.
|
||||
e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
|
||||
|
@ -175,6 +175,16 @@ OPTIONS
|
|||
Finally, a user may not set fields to none for all event types.
|
||||
i.e., -f "" is not allowed.
|
||||
|
||||
The brstack output includes branch related information with raw addresses using the
|
||||
/v/v/v/v/ syntax in the following order:
|
||||
FROM: branch source instruction
|
||||
TO : branch target instruction
|
||||
M/P/-: M=branch target mispredicted or branch direction was mispredicted, P=target predicted or direction predicted, -=not supported
|
||||
X/- : X=branch inside a transactional region, -=not in transaction region or not supported
|
||||
A/- : A=TSX abort entry, -=not aborted region or not supported
|
||||
|
||||
The brstacksym is identical to brstack, except that the FROM and TO addresses are printed in a symbolic form if possible.
|
||||
|
||||
-k::
|
||||
--vmlinux=<file>::
|
||||
vmlinux pathname
|
||||
|
|
|
@ -430,7 +430,7 @@ $(LIBAPI)-clean:
|
|||
$(call QUIET_CLEAN, libapi)
|
||||
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
|
||||
$(LIBBPF): FORCE
|
||||
$(LIBBPF): fixdep FORCE
|
||||
$(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a
|
||||
|
||||
$(LIBBPF)-clean:
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "util/auxtrace.h"
|
||||
#include "util/parse-branch-options.h"
|
||||
#include "util/parse-regs-options.h"
|
||||
#include "util/llvm-utils.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
|
@ -1112,6 +1113,12 @@ struct option __record_options[] = {
|
|||
"per thread proc mmap processing timeout in ms"),
|
||||
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
|
||||
"Record context switch events"),
|
||||
#ifdef HAVE_LIBBPF_SUPPORT
|
||||
OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
|
||||
"clang binary to use for compiling BPF scriptlets"),
|
||||
OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
|
||||
"options passed to clang when compiling BPF scriptlets"),
|
||||
#endif
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ enum perf_output_field {
|
|||
PERF_OUTPUT_SRCLINE = 1U << 12,
|
||||
PERF_OUTPUT_PERIOD = 1U << 13,
|
||||
PERF_OUTPUT_IREGS = 1U << 14,
|
||||
PERF_OUTPUT_BRSTACK = 1U << 15,
|
||||
PERF_OUTPUT_BRSTACKSYM = 1U << 16,
|
||||
};
|
||||
|
||||
struct output_option {
|
||||
|
@ -72,6 +74,8 @@ struct output_option {
|
|||
{.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
|
||||
{.str = "period", .field = PERF_OUTPUT_PERIOD},
|
||||
{.str = "iregs", .field = PERF_OUTPUT_IREGS},
|
||||
{.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
|
||||
{.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
|
||||
};
|
||||
|
||||
/* default set to maintain compatibility with current format */
|
||||
|
@ -425,6 +429,77 @@ static void print_sample_start(struct perf_sample *sample,
|
|||
}
|
||||
}
|
||||
|
||||
static inline char
|
||||
mispred_str(struct branch_entry *br)
|
||||
{
|
||||
if (!(br->flags.mispred || br->flags.predicted))
|
||||
return '-';
|
||||
|
||||
return br->flags.predicted ? 'P' : 'M';
|
||||
}
|
||||
|
||||
static void print_sample_brstack(union perf_event *event __maybe_unused,
|
||||
struct perf_sample *sample,
|
||||
struct thread *thread __maybe_unused,
|
||||
struct perf_event_attr *attr __maybe_unused)
|
||||
{
|
||||
struct branch_stack *br = sample->branch_stack;
|
||||
u64 i;
|
||||
|
||||
if (!(br && br->nr))
|
||||
return;
|
||||
|
||||
for (i = 0; i < br->nr; i++) {
|
||||
printf(" 0x%"PRIx64"/0x%"PRIx64"/%c/%c/%c/%d ",
|
||||
br->entries[i].from,
|
||||
br->entries[i].to,
|
||||
mispred_str( br->entries + i),
|
||||
br->entries[i].flags.in_tx? 'X' : '-',
|
||||
br->entries[i].flags.abort? 'A' : '-',
|
||||
br->entries[i].flags.cycles);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_sample_brstacksym(union perf_event *event __maybe_unused,
|
||||
struct perf_sample *sample,
|
||||
struct thread *thread __maybe_unused,
|
||||
struct perf_event_attr *attr __maybe_unused)
|
||||
{
|
||||
struct branch_stack *br = sample->branch_stack;
|
||||
struct addr_location alf, alt;
|
||||
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
u64 i, from, to;
|
||||
|
||||
if (!(br && br->nr))
|
||||
return;
|
||||
|
||||
for (i = 0; i < br->nr; i++) {
|
||||
|
||||
memset(&alf, 0, sizeof(alf));
|
||||
memset(&alt, 0, sizeof(alt));
|
||||
from = br->entries[i].from;
|
||||
to = br->entries[i].to;
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, from, &alf);
|
||||
if (alf.map)
|
||||
alf.sym = map__find_symbol(alf.map, alf.addr, NULL);
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, to, &alt);
|
||||
if (alt.map)
|
||||
alt.sym = map__find_symbol(alt.map, alt.addr, NULL);
|
||||
|
||||
symbol__fprintf_symname_offs(alf.sym, &alf, stdout);
|
||||
putchar('/');
|
||||
symbol__fprintf_symname_offs(alt.sym, &alt, stdout);
|
||||
printf("/%c/%c/%c/%d ",
|
||||
mispred_str( br->entries + i),
|
||||
br->entries[i].flags.in_tx? 'X' : '-',
|
||||
br->entries[i].flags.abort? 'A' : '-',
|
||||
br->entries[i].flags.cycles);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void print_sample_addr(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct thread *thread,
|
||||
|
@ -560,6 +635,11 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
|
|||
if (PRINT_FIELD(IREGS))
|
||||
print_sample_iregs(event, sample, thread, attr);
|
||||
|
||||
if (PRINT_FIELD(BRSTACK))
|
||||
print_sample_brstack(event, sample, thread, attr);
|
||||
else if (PRINT_FIELD(BRSTACKSYM))
|
||||
print_sample_brstacksym(event, sample, thread, attr);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
@ -1681,7 +1761,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
"comma separated output fields prepend with 'type:'. "
|
||||
"Valid types: hw,sw,trace,raw. "
|
||||
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
|
||||
"addr,symoff,period,iregs,flags", parse_output_fields),
|
||||
"addr,symoff,period,iregs,brstack,brstacksym,flags", parse_output_fields),
|
||||
OPT_BOOLEAN('a', "all-cpus", &system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
|
||||
|
|
|
@ -585,6 +585,12 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct sysc
|
|||
|
||||
#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
|
||||
|
||||
static const char *bpf_cmd[] = {
|
||||
"MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
|
||||
"MAP_GET_NEXT_KEY", "PROG_LOAD",
|
||||
};
|
||||
static DEFINE_STRARRAY(bpf_cmd);
|
||||
|
||||
static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
|
||||
static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
|
||||
|
||||
|
@ -1011,6 +1017,7 @@ static struct syscall_fmt {
|
|||
.arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
|
||||
[1] = SCA_ACCMODE, /* mode */ }, },
|
||||
{ .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
|
||||
{ .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
|
||||
{ .name = "brk", .hexret = true,
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
|
||||
{ .name = "chdir", .errmsg = true,
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef LINUX_VERSION_CODE
|
||||
# error Need LINUX_VERSION_CODE
|
||||
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
|
||||
#endif
|
||||
#define BPF_ANY 0
|
||||
#define BPF_MAP_TYPE_ARRAY 2
|
||||
#define BPF_FUNC_map_lookup_elem 1
|
||||
#define BPF_FUNC_map_update_elem 2
|
||||
|
||||
static void *(*bpf_map_lookup_elem)(void *map, void *key) =
|
||||
(void *) BPF_FUNC_map_lookup_elem;
|
||||
static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
|
||||
(void *) BPF_FUNC_map_update_elem;
|
||||
|
||||
struct bpf_map_def {
|
||||
unsigned int type;
|
||||
unsigned int key_size;
|
||||
unsigned int value_size;
|
||||
unsigned int max_entries;
|
||||
};
|
||||
|
||||
#define SEC(NAME) __attribute__((section(NAME), used))
|
||||
struct bpf_map_def SEC("maps") flip_table = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(int),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
SEC("func=sys_epoll_pwait")
|
||||
int bpf_func__sys_epoll_pwait(void *ctx)
|
||||
{
|
||||
int ind =0;
|
||||
int *flag = bpf_map_lookup_elem(&flip_table, &ind);
|
||||
int new_flag;
|
||||
if (!flag)
|
||||
return 0;
|
||||
/* flip flag and store back */
|
||||
new_flag = !*flag;
|
||||
bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY);
|
||||
return new_flag;
|
||||
}
|
||||
char _license[] SEC("license") = "GPL";
|
||||
int _version SEC("version") = LINUX_VERSION_CODE;
|
|
@ -12,6 +12,7 @@
|
|||
#include "bpf-loader.h"
|
||||
#include "probe-event.h"
|
||||
#include "probe-finder.h" // for MAX_PROBES
|
||||
#include "llvm-utils.h"
|
||||
|
||||
#define DEFINE_PRINT_FN(name, level) \
|
||||
static int libbpf_##name(const char *fmt, ...) \
|
||||
|
@ -33,7 +34,7 @@ struct bpf_prog_priv {
|
|||
struct perf_probe_event pev;
|
||||
};
|
||||
|
||||
struct bpf_object *bpf__prepare_load(const char *filename)
|
||||
struct bpf_object *bpf__prepare_load(const char *filename, bool source)
|
||||
{
|
||||
struct bpf_object *obj;
|
||||
static bool libbpf_initialized;
|
||||
|
@ -45,7 +46,19 @@ struct bpf_object *bpf__prepare_load(const char *filename)
|
|||
libbpf_initialized = true;
|
||||
}
|
||||
|
||||
obj = bpf_object__open(filename);
|
||||
if (source) {
|
||||
int err;
|
||||
void *obj_buf;
|
||||
size_t obj_buf_sz;
|
||||
|
||||
err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
|
||||
free(obj_buf);
|
||||
} else
|
||||
obj = bpf_object__open(filename);
|
||||
|
||||
if (!obj) {
|
||||
pr_debug("bpf: failed to load %s\n", filename);
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
@ -18,7 +18,7 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
|
|||
int fd, void *arg);
|
||||
|
||||
#ifdef HAVE_LIBBPF_SUPPORT
|
||||
struct bpf_object *bpf__prepare_load(const char *filename);
|
||||
struct bpf_object *bpf__prepare_load(const char *filename, bool source);
|
||||
|
||||
void bpf__clear(void);
|
||||
|
||||
|
@ -34,7 +34,8 @@ int bpf__foreach_tev(struct bpf_object *obj,
|
|||
bpf_prog_iter_callback_t func, void *arg);
|
||||
#else
|
||||
static inline struct bpf_object *
|
||||
bpf__prepare_load(const char *filename __maybe_unused)
|
||||
bpf__prepare_load(const char *filename __maybe_unused,
|
||||
bool source __maybe_unused)
|
||||
{
|
||||
pr_debug("ERROR: eBPF object loading is disabled during compiling.\n");
|
||||
return ERR_PTR(-ENOTSUP);
|
||||
|
|
|
@ -208,6 +208,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
|
|||
evsel->unit = "";
|
||||
evsel->scale = 1.0;
|
||||
evsel->evlist = NULL;
|
||||
evsel->bpf_fd = -1;
|
||||
INIT_LIST_HEAD(&evsel->node);
|
||||
INIT_LIST_HEAD(&evsel->config_terms);
|
||||
perf_evsel__object.init(evsel);
|
||||
|
@ -1356,6 +1357,22 @@ retry_open:
|
|||
err);
|
||||
goto try_fallback;
|
||||
}
|
||||
|
||||
if (evsel->bpf_fd >= 0) {
|
||||
int evt_fd = FD(evsel, cpu, thread);
|
||||
int bpf_fd = evsel->bpf_fd;
|
||||
|
||||
err = ioctl(evt_fd,
|
||||
PERF_EVENT_IOC_SET_BPF,
|
||||
bpf_fd);
|
||||
if (err && errno != EEXIST) {
|
||||
pr_err("failed to attach bpf fd %d: %s\n",
|
||||
bpf_fd, strerror(errno));
|
||||
err = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
}
|
||||
|
||||
set_rlimit = NO_CHANGE;
|
||||
|
||||
/*
|
||||
|
|
|
@ -123,6 +123,7 @@ struct perf_evsel {
|
|||
char *group_name;
|
||||
bool cmdline_group_boundary;
|
||||
struct list_head config_terms;
|
||||
int bpf_fd;
|
||||
};
|
||||
|
||||
union u64_swap {
|
||||
|
|
|
@ -542,6 +542,7 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
|
|||
struct __add_bpf_event_param *param = _param;
|
||||
struct parse_events_evlist *evlist = param->data;
|
||||
struct list_head *list = param->list;
|
||||
struct perf_evsel *pos;
|
||||
int err;
|
||||
|
||||
pr_debug("add bpf event %s:%s and attach bpf program %d\n",
|
||||
|
@ -562,6 +563,11 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
|
|||
}
|
||||
pr_debug("adding %s:%s\n", tev->group, tev->event);
|
||||
|
||||
list_for_each_entry(pos, &new_evsels, node) {
|
||||
pr_debug("adding %s:%s to %p\n",
|
||||
tev->group, tev->event, pos);
|
||||
pos->bpf_fd = fd;
|
||||
}
|
||||
list_splice(&new_evsels, list);
|
||||
return 0;
|
||||
}
|
||||
|
@ -620,11 +626,12 @@ errout:
|
|||
|
||||
int parse_events_load_bpf(struct parse_events_evlist *data,
|
||||
struct list_head *list,
|
||||
char *bpf_file_name)
|
||||
char *bpf_file_name,
|
||||
bool source)
|
||||
{
|
||||
struct bpf_object *obj;
|
||||
|
||||
obj = bpf__prepare_load(bpf_file_name);
|
||||
obj = bpf__prepare_load(bpf_file_name, source);
|
||||
if (IS_ERR(obj) || !obj) {
|
||||
char errbuf[BUFSIZ];
|
||||
int err;
|
||||
|
|
|
@ -125,7 +125,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
|
|||
struct list_head *head_config);
|
||||
int parse_events_load_bpf(struct parse_events_evlist *data,
|
||||
struct list_head *list,
|
||||
char *bpf_file_name);
|
||||
char *bpf_file_name,
|
||||
bool source);
|
||||
/* Provide this function for perf test */
|
||||
struct bpf_object;
|
||||
int parse_events_load_bpf_obj(struct parse_events_evlist *data,
|
||||
|
|
|
@ -116,6 +116,7 @@ group [^,{}/]*[{][^}]*[}][^,{}/]*
|
|||
event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
|
||||
event [^,{}/]+
|
||||
bpf_object .*\.(o|bpf)
|
||||
bpf_source .*\.c
|
||||
|
||||
num_dec [0-9]+
|
||||
num_hex 0x[a-fA-F0-9]+
|
||||
|
@ -161,6 +162,7 @@ modifier_bp [rwx]{1,3}
|
|||
|
||||
{event_pmu} |
|
||||
{bpf_object} |
|
||||
{bpf_source} |
|
||||
{event} {
|
||||
BEGIN(INITIAL);
|
||||
REWIND(1);
|
||||
|
@ -269,6 +271,7 @@ r{num_raw_hex} { return raw(yyscanner); }
|
|||
|
||||
{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
|
||||
{bpf_object} { return str(yyscanner, PE_BPF_OBJECT); }
|
||||
{bpf_source} { return str(yyscanner, PE_BPF_SOURCE); }
|
||||
{name} { return pmu_str_check(yyscanner); }
|
||||
"/" { BEGIN(config); return '/'; }
|
||||
- { return '-'; }
|
||||
|
|
|
@ -42,7 +42,7 @@ static inc_group_count(struct list_head *list,
|
|||
%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
|
||||
%token PE_EVENT_NAME
|
||||
%token PE_NAME
|
||||
%token PE_BPF_OBJECT
|
||||
%token PE_BPF_OBJECT PE_BPF_SOURCE
|
||||
%token PE_MODIFIER_EVENT PE_MODIFIER_BP
|
||||
%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
|
||||
%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
|
||||
|
@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list,
|
|||
%type <num> PE_TERM
|
||||
%type <str> PE_NAME
|
||||
%type <str> PE_BPF_OBJECT
|
||||
%type <str> PE_BPF_SOURCE
|
||||
%type <str> PE_NAME_CACHE_TYPE
|
||||
%type <str> PE_NAME_CACHE_OP_RESULT
|
||||
%type <str> PE_MODIFIER_EVENT
|
||||
|
@ -461,7 +462,17 @@ PE_BPF_OBJECT
|
|||
struct list_head *list;
|
||||
|
||||
ALLOC_LIST(list);
|
||||
ABORT_ON(parse_events_load_bpf(data, list, $1));
|
||||
ABORT_ON(parse_events_load_bpf(data, list, $1, false));
|
||||
$$ = list;
|
||||
}
|
||||
|
|
||||
PE_BPF_SOURCE
|
||||
{
|
||||
struct parse_events_evlist *data = _data;
|
||||
struct list_head *list;
|
||||
|
||||
ALLOC_LIST(list);
|
||||
ABORT_ON(parse_events_load_bpf(data, list, $1, true));
|
||||
$$ = list;
|
||||
}
|
||||
|
||||
|
|
|
@ -360,12 +360,15 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
|
|||
int fd = dso__data_get_fd(map->dso, ui->machine);
|
||||
int is_exec = elf_is_exec(fd, map->dso->name);
|
||||
unw_word_t base = is_exec ? 0 : map->start;
|
||||
const char *symfile;
|
||||
|
||||
if (fd >= 0)
|
||||
dso__data_put_fd(map->dso);
|
||||
|
||||
symfile = map->dso->symsrc_filename ?: map->dso->name;
|
||||
|
||||
memset(&di, 0, sizeof(di));
|
||||
if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name,
|
||||
if (dwarf_find_debug_frame(0, &di, ip, base, symfile,
|
||||
map->start, map->end))
|
||||
return dwarf_search_unwind_table(as, ip, &di, pi,
|
||||
need_unwind_info, arg);
|
||||
|
|
Загрузка…
Ссылка в новой задаче