Commit ac675d0d authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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:

User visible changes:

  - Fix 'perf list' segfault due to lack of support for PERF_CONF_SW_BPF_OUTPUT
    in an array used just for printing available events, robustify the code
    involved (Arnaldo Carvalho de Melo)

  - 'perf test unwind' should create kernel maps, now that entry works and the
    test passes (Jiri Olsa)

  - Fix showing the running kernel build id in 'perf buildid-list' (Michael Petlan)

  - Fix command line symbol filtering in 'perf report' (Namhyung Kim)

Infrastructure changes:

  - Extract and collect map info from BPF object files in libbpf (Wang Nan)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 3f3b1a46 0bb93490
...@@ -163,22 +163,25 @@ struct bpf_program { ...@@ -163,22 +163,25 @@ struct bpf_program {
bpf_program_clear_priv_t clear_priv; bpf_program_clear_priv_t clear_priv;
}; };
struct bpf_map {
int fd;
char *name;
struct bpf_map_def def;
void *priv;
bpf_map_clear_priv_t clear_priv;
};
static LIST_HEAD(bpf_objects_list); static LIST_HEAD(bpf_objects_list);
struct bpf_object { struct bpf_object {
char license[64]; char license[64];
u32 kern_version; u32 kern_version;
void *maps_buf;
size_t maps_buf_sz;
struct bpf_program *programs; struct bpf_program *programs;
size_t nr_programs; size_t nr_programs;
int *map_fds; struct bpf_map *maps;
/* size_t nr_maps;
* This field is required because maps_buf will be freed and
* maps_buf_sz will be set to 0 after loaded.
*/
size_t nr_map_fds;
bool loaded; bool loaded;
/* /*
...@@ -489,30 +492,81 @@ static int ...@@ -489,30 +492,81 @@ static int
bpf_object__init_maps(struct bpf_object *obj, void *data, bpf_object__init_maps(struct bpf_object *obj, void *data,
size_t size) size_t size)
{ {
if (size == 0) { size_t nr_maps;
int i;
nr_maps = size / sizeof(struct bpf_map_def);
if (!data || !nr_maps) {
pr_debug("%s doesn't need map definition\n", pr_debug("%s doesn't need map definition\n",
obj->path); obj->path);
return 0; return 0;
} }
obj->maps_buf = malloc(size); pr_debug("maps in %s: %zd bytes\n", obj->path, size);
if (!obj->maps_buf) {
pr_warning("malloc maps failed: %s\n", obj->path); obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
if (!obj->maps) {
pr_warning("alloc maps for object failed\n");
return -ENOMEM; return -ENOMEM;
} }
obj->nr_maps = nr_maps;
obj->maps_buf_sz = size; for (i = 0; i < nr_maps; i++) {
memcpy(obj->maps_buf, data, size); struct bpf_map_def *def = &obj->maps[i].def;
pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size);
/*
* fill all fd with -1 so won't close incorrect
* fd (fd=0 is stdin) when failure (zclose won't close
* negative fd)).
*/
obj->maps[i].fd = -1;
/* Save map definition into obj->maps */
*def = ((struct bpf_map_def *)data)[i];
}
return 0; return 0;
} }
static void
bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
{
int i;
Elf_Data *symbols = obj->efile.symbols;
if (!symbols || maps_shndx < 0)
return;
for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
GElf_Sym sym;
size_t map_idx;
const char *map_name;
if (!gelf_getsym(symbols, i, &sym))
continue;
if (sym.st_shndx != maps_shndx)
continue;
map_name = elf_strptr(obj->efile.elf,
obj->efile.ehdr.e_shstrndx,
sym.st_name);
map_idx = sym.st_value / sizeof(struct bpf_map_def);
if (map_idx >= obj->nr_maps) {
pr_warning("index of map \"%s\" is buggy: %zu > %zu\n",
map_name, map_idx, obj->nr_maps);
continue;
}
obj->maps[map_idx].name = strdup(map_name);
pr_debug("map %zu is \"%s\"\n", map_idx,
obj->maps[map_idx].name);
}
}
static int bpf_object__elf_collect(struct bpf_object *obj) static int bpf_object__elf_collect(struct bpf_object *obj)
{ {
Elf *elf = obj->efile.elf; Elf *elf = obj->efile.elf;
GElf_Ehdr *ep = &obj->efile.ehdr; GElf_Ehdr *ep = &obj->efile.ehdr;
Elf_Scn *scn = NULL; Elf_Scn *scn = NULL;
int idx = 0, err = 0; int idx = 0, err = 0, maps_shndx = -1;
/* Elf is corrupted/truncated, avoid calling elf_strptr. */ /* Elf is corrupted/truncated, avoid calling elf_strptr. */
if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
...@@ -562,10 +616,11 @@ static int bpf_object__elf_collect(struct bpf_object *obj) ...@@ -562,10 +616,11 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
err = bpf_object__init_kversion(obj, err = bpf_object__init_kversion(obj,
data->d_buf, data->d_buf,
data->d_size); data->d_size);
else if (strcmp(name, "maps") == 0) else if (strcmp(name, "maps") == 0) {
err = bpf_object__init_maps(obj, data->d_buf, err = bpf_object__init_maps(obj, data->d_buf,
data->d_size); data->d_size);
else if (sh.sh_type == SHT_SYMTAB) { maps_shndx = idx;
} else if (sh.sh_type == SHT_SYMTAB) {
if (obj->efile.symbols) { if (obj->efile.symbols) {
pr_warning("bpf: multiple SYMTAB in %s\n", pr_warning("bpf: multiple SYMTAB in %s\n",
obj->path); obj->path);
...@@ -606,6 +661,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj) ...@@ -606,6 +661,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
if (err) if (err)
goto out; goto out;
} }
if (maps_shndx >= 0)
bpf_object__init_maps_name(obj, maps_shndx);
out: out:
return err; return err;
} }
...@@ -688,37 +746,15 @@ static int ...@@ -688,37 +746,15 @@ static int
bpf_object__create_maps(struct bpf_object *obj) bpf_object__create_maps(struct bpf_object *obj)
{ {
unsigned int i; unsigned int i;
size_t nr_maps;
int *pfd;
nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); for (i = 0; i < obj->nr_maps; i++) {
if (!obj->maps_buf || !nr_maps) { struct bpf_map_def *def = &obj->maps[i].def;
pr_debug("don't need create maps for %s\n", int *pfd = &obj->maps[i].fd;
obj->path);
return 0;
}
obj->map_fds = malloc(sizeof(int) * nr_maps);
if (!obj->map_fds) {
pr_warning("realloc perf_bpf_map_fds failed\n");
return -ENOMEM;
}
obj->nr_map_fds = nr_maps;
/* fill all fd with -1 */ *pfd = bpf_create_map(def->type,
memset(obj->map_fds, -1, sizeof(int) * nr_maps); def->key_size,
def->value_size,
pfd = obj->map_fds; def->max_entries);
for (i = 0; i < nr_maps; i++) {
struct bpf_map_def def;
def = *(struct bpf_map_def *)(obj->maps_buf +
i * sizeof(struct bpf_map_def));
*pfd = bpf_create_map(def.type,
def.key_size,
def.value_size,
def.max_entries);
if (*pfd < 0) { if (*pfd < 0) {
size_t j; size_t j;
int err = *pfd; int err = *pfd;
...@@ -726,22 +762,17 @@ bpf_object__create_maps(struct bpf_object *obj) ...@@ -726,22 +762,17 @@ bpf_object__create_maps(struct bpf_object *obj)
pr_warning("failed to create map: %s\n", pr_warning("failed to create map: %s\n",
strerror(errno)); strerror(errno));
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
zclose(obj->map_fds[j]); zclose(obj->maps[j].fd);
obj->nr_map_fds = 0;
zfree(&obj->map_fds);
return err; return err;
} }
pr_debug("create map: fd=%d\n", *pfd); pr_debug("create map: fd=%d\n", *pfd);
pfd++;
} }
zfree(&obj->maps_buf);
obj->maps_buf_sz = 0;
return 0; return 0;
} }
static int static int
bpf_program__relocate(struct bpf_program *prog, int *map_fds) bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
{ {
int i; int i;
...@@ -761,7 +792,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds) ...@@ -761,7 +792,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds)
return -LIBBPF_ERRNO__RELOC; return -LIBBPF_ERRNO__RELOC;
} }
insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
insns[insn_idx].imm = map_fds[map_idx]; insns[insn_idx].imm = obj->maps[map_idx].fd;
} }
zfree(&prog->reloc_desc); zfree(&prog->reloc_desc);
...@@ -780,7 +811,7 @@ bpf_object__relocate(struct bpf_object *obj) ...@@ -780,7 +811,7 @@ bpf_object__relocate(struct bpf_object *obj)
for (i = 0; i < obj->nr_programs; i++) { for (i = 0; i < obj->nr_programs; i++) {
prog = &obj->programs[i]; prog = &obj->programs[i];
err = bpf_program__relocate(prog, obj->map_fds); err = bpf_program__relocate(prog, obj);
if (err) { if (err) {
pr_warning("failed to relocate '%s'\n", pr_warning("failed to relocate '%s'\n",
prog->section_name); prog->section_name);
...@@ -804,8 +835,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) ...@@ -804,8 +835,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
Elf_Data *data = obj->efile.reloc[i].data; Elf_Data *data = obj->efile.reloc[i].data;
int idx = shdr->sh_info; int idx = shdr->sh_info;
struct bpf_program *prog; struct bpf_program *prog;
size_t nr_maps = obj->maps_buf_sz / size_t nr_maps = obj->nr_maps;
sizeof(struct bpf_map_def);
if (shdr->sh_type != SHT_REL) { if (shdr->sh_type != SHT_REL) {
pr_warning("internal error at %d\n", __LINE__); pr_warning("internal error at %d\n", __LINE__);
...@@ -1050,10 +1080,8 @@ int bpf_object__unload(struct bpf_object *obj) ...@@ -1050,10 +1080,8 @@ int bpf_object__unload(struct bpf_object *obj)
if (!obj) if (!obj)
return -EINVAL; return -EINVAL;
for (i = 0; i < obj->nr_map_fds; i++) for (i = 0; i < obj->nr_maps; i++)
zclose(obj->map_fds[i]); zclose(obj->maps[i].fd);
zfree(&obj->map_fds);
obj->nr_map_fds = 0;
for (i = 0; i < obj->nr_programs; i++) for (i = 0; i < obj->nr_programs; i++)
bpf_program__unload(&obj->programs[i]); bpf_program__unload(&obj->programs[i]);
...@@ -1096,7 +1124,16 @@ void bpf_object__close(struct bpf_object *obj) ...@@ -1096,7 +1124,16 @@ void bpf_object__close(struct bpf_object *obj)
bpf_object__elf_finish(obj); bpf_object__elf_finish(obj);
bpf_object__unload(obj); bpf_object__unload(obj);
zfree(&obj->maps_buf); for (i = 0; i < obj->nr_maps; i++) {
zfree(&obj->maps[i].name);
if (obj->maps[i].clear_priv)
obj->maps[i].clear_priv(&obj->maps[i],
obj->maps[i].priv);
obj->maps[i].priv = NULL;
obj->maps[i].clear_priv = NULL;
}
zfree(&obj->maps);
obj->nr_maps = 0;
if (obj->programs && obj->nr_programs) { if (obj->programs && obj->nr_programs) {
for (i = 0; i < obj->nr_programs; i++) for (i = 0; i < obj->nr_programs; i++)
...@@ -1251,3 +1288,92 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n) ...@@ -1251,3 +1288,92 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n)
return fd; return fd;
} }
int bpf_map__get_fd(struct bpf_map *map)
{
if (!map)
return -EINVAL;
return map->fd;
}
int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef)
{
if (!map || !pdef)
return -EINVAL;
*pdef = map->def;
return 0;
}
const char *bpf_map__get_name(struct bpf_map *map)
{
if (!map)
return NULL;
return map->name;
}
int bpf_map__set_private(struct bpf_map *map, void *priv,
bpf_map_clear_priv_t clear_priv)
{
if (!map)
return -EINVAL;
if (map->priv) {
if (map->clear_priv)
map->clear_priv(map, map->priv);
}
map->priv = priv;
map->clear_priv = clear_priv;
return 0;
}
int bpf_map__get_private(struct bpf_map *map, void **ppriv)
{
if (!map)
return -EINVAL;
if (ppriv)
*ppriv = map->priv;
return 0;
}
struct bpf_map *
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
{
size_t idx;
struct bpf_map *s, *e;
if (!obj || !obj->maps)
return NULL;
s = obj->maps;
e = obj->maps + obj->nr_maps;
if (prev == NULL)
return s;
if ((prev < s) || (prev >= e)) {
pr_warning("error in %s: map handler doesn't belong to object\n",
__func__);
return NULL;
}
idx = (prev - obj->maps) + 1;
if (idx >= obj->nr_maps)
return NULL;
return &obj->maps[idx];
}
struct bpf_map *
bpf_object__get_map_by_name(struct bpf_object *obj, const char *name)
{
struct bpf_map *pos;
bpf_map__for_each(pos, obj) {
if (strcmp(pos->name, name) == 0)
return pos;
}
return NULL;
}
...@@ -165,4 +165,28 @@ struct bpf_map_def { ...@@ -165,4 +165,28 @@ struct bpf_map_def {
unsigned int max_entries; unsigned int max_entries;
}; };
/*
* There is another 'struct bpf_map' in include/linux/map.h. However,
* it is not a uapi header so no need to consider name clash.
*/
struct bpf_map;
struct bpf_map *
bpf_object__get_map_by_name(struct bpf_object *obj, const char *name);
struct bpf_map *
bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
#define bpf_map__for_each(pos, obj) \
for ((pos) = bpf_map__next(NULL, (obj)); \
(pos) != NULL; \
(pos) = bpf_map__next((pos), (obj)))
int bpf_map__get_fd(struct bpf_map *map);
int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef);
const char *bpf_map__get_name(struct bpf_map *map);
typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
int bpf_map__set_private(struct bpf_map *map, void *priv,
bpf_map_clear_priv_t clear_priv);
int bpf_map__get_private(struct bpf_map *map, void **ppriv);
#endif #endif
...@@ -513,20 +513,26 @@ static int __cmd_report(struct report *rep) ...@@ -513,20 +513,26 @@ static int __cmd_report(struct report *rep)
if (rep->cpu_list) { if (rep->cpu_list) {
ret = perf_session__cpu_bitmap(session, rep->cpu_list, ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap); rep->cpu_bitmap);
if (ret) if (ret) {
ui__error("failed to set cpu bitmap\n");
return ret; return ret;
}
} }
if (rep->show_threads) if (rep->show_threads)
perf_read_values_init(&rep->show_threads_values); perf_read_values_init(&rep->show_threads_values);
ret = report__setup_sample_type(rep); ret = report__setup_sample_type(rep);
if (ret) if (ret) {
/* report__setup_sample_type() already showed error message */
return ret; return ret;
}
ret = perf_session__process_events(session); ret = perf_session__process_events(session);
if (ret) if (ret) {
ui__error("failed to process sample\n");
return ret; return ret;
}
report__warn_kptr_restrict(rep); report__warn_kptr_restrict(rep);
......
...@@ -173,6 +173,11 @@ int test__dwarf_unwind(int subtest __maybe_unused) ...@@ -173,6 +173,11 @@ int test__dwarf_unwind(int subtest __maybe_unused)
return -1; return -1;
} }
if (machine__create_kernel_maps(machine)) {
pr_err("Failed to create kernel maps\n");
return -1;
}
callchain_param.record_mode = CALLCHAIN_DWARF; callchain_param.record_mode = CALLCHAIN_DWARF;
if (init_live_machine(machine)) { if (init_live_machine(machine)) {
......
...@@ -2055,10 +2055,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -2055,10 +2055,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
SLang_reset_tty(); SLang_reset_tty();
SLang_init_tty(0, 0, 0); SLang_init_tty(0, 0, 0);
if (min_pcnt) { if (min_pcnt)
browser->min_pcnt = min_pcnt; browser->min_pcnt = min_pcnt;
hist_browser__update_nr_entries(browser); hist_browser__update_nr_entries(browser);
}
browser->pstack = pstack__new(3); browser->pstack = pstack__new(3);
if (browser->pstack == NULL) if (browser->pstack == NULL)
......
...@@ -120,7 +120,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, ...@@ -120,7 +120,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
} }
static int static int
config__exec(const char *value, struct perf_probe_event *pev) prog_config__exec(const char *value, struct perf_probe_event *pev)
{ {
pev->uprobes = true; pev->uprobes = true;
pev->target = strdup(value); pev->target = strdup(value);
...@@ -130,7 +130,7 @@ config__exec(const char *value, struct perf_probe_event *pev) ...@@ -130,7 +130,7 @@ config__exec(const char *value, struct perf_probe_event *pev)
} }
static int static int
config__module(const char *value, struct perf_probe_event *pev) prog_config__module(const char *value, struct perf_probe_event *pev)
{ {
pev->uprobes = false; pev->uprobes = false;
pev->target = strdup(value); pev->target = strdup(value);
...@@ -140,8 +140,7 @@ config__module(const char *value, struct perf_probe_event *pev) ...@@ -140,8 +140,7 @@ config__module(const char *value, struct perf_probe_event *pev)
} }
static int static int
config__bool(const char *value, prog_config__bool(const char *value, bool *pbool, bool invert)
bool *pbool, bool invert)
{ {
int err; int err;
bool bool_value; bool bool_value;
...@@ -158,17 +157,17 @@ config__bool(const char *value, ...@@ -158,17 +157,17 @@ config__bool(const char *value,
} }
static int static int
config__inlines(const char *value, prog_config__inlines(const char *value,
struct perf_probe_event *pev __maybe_unused) struct perf_probe_event *pev __maybe_unused)
{ {
return config__bool(value, &probe_conf.no_inlines, true); return prog_config__bool(value, &probe_conf.no_inlines, true);
} }
static int static int
config__force(const char *value, prog_config__force(const char *value,
struct perf_probe_event *pev __maybe_unused) struct perf_probe_event *pev __maybe_unused)
{ {
return config__bool(value, &probe_conf.force_add, false); return prog_config__bool(value, &probe_conf.force_add, false);
} }
static struct { static struct {
...@@ -176,58 +175,58 @@ static struct { ...@@ -176,58 +175,58 @@ static struct {
const char *usage; const char *usage;
const char *desc; const char *desc;
int (*func)(const char *, struct perf_probe_event *); int (*func)(const char *, struct perf_probe_event *);
} bpf_config_terms[] = { } bpf_prog_config_terms[] = {
{ {
.key = "exec", .key = "exec",
.usage = "exec=<full path of file>", .usage = "exec=<full path of file>",
.desc = "Set uprobe target", .desc = "Set uprobe target",
.func = config__exec, .func = prog_config__exec,
}, },
{ {
.key = "module", .key = "module",
.usage = "module=<module name> ", .usage = "module=<module name> ",
.desc = "Set kprobe module", .desc = "Set kprobe module",
.func = config__module, .func = prog_config__module,
}, },
{ {
.key = "inlines", .key = "inlines",
.usage = "inlines=[yes|no] ", .usage = "inlines=[yes|no] ",
.desc = "Probe at inline symbol", .desc = "Probe at inline symbol",
.func = config__inlines, .func = prog_config__inlines,
}, },
{ {
.key = "force", .key = "force",
.usage = "force=[yes|no] ", .usage = "force=[yes|no] ",
.desc = "Forcibly add events with existing name", .desc = "Forcibly add events with existing name",
.func = config__force, .func = prog_config__force,
}, },
}; };
static int static int
do_config(const char *key, const char *value, do_prog_config(const char *key, const char *value,
struct perf_probe_event *pev) struct perf_probe_event *pev)
{ {
unsigned int i; unsigned int i;
pr_debug("config bpf program: %s=%s\n", key, value); pr_debug("config bpf program: %s=%s\n", key, value);
for (i = 0; i < ARRAY_SIZE(bpf_config_terms); i++) for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
if (strcmp(key, bpf_config_terms[i].key) == 0) if (strcmp(key, bpf_prog_config_terms[i].key) == 0)
return bpf_config_terms[i].func(value, pev); return bpf_prog_config_terms[i].func(value, pev);
pr_debug("BPF: ERROR: invalid config option in object: %s=%s\n", pr_debug("BPF: ERROR: invalid program config option: %s=%s\n",
key, value); key, value);
pr_debug("\nHint: Currently valid options are:\n"); pr_debug("\nHint: Valid options are:\n");
for (i = 0; i < ARRAY_SIZE(bpf_config_terms); i++) for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
pr_debug("\t%s:\t%s\n", bpf_config_terms[i].usage, pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage,
bpf_config_terms[i].desc); bpf_prog_config_terms[i].desc);
pr_debug("\n"); pr_debug("\n");
return -BPF_LOADER_ERRNO__CONFIG_TERM; return -BPF_LOADER_ERRNO__PROGCONF_TERM;
} }
static const char * static const char *
parse_config_kvpair(const char *config_str, struct perf_probe_event *pev) parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
{ {
char *text = strdup(config_str); char *text = strdup(config_str);
char *sep, *line; char *sep, *line;
...@@ -253,7 +252,7 @@ parse_config_kvpair(const char *config_str, struct perf_probe_event *pev) ...@@ -253,7 +252,7 @@ parse_config_kvpair(const char *config_str, struct perf_probe_event *pev)
} }
*equ = '\0'; *equ = '\0';
err = do_config(line, equ + 1, pev); err = do_prog_config(line, equ + 1, pev);
if (err) if (err)
break; break;
nextline: nextline:
...@@ -268,10 +267,10 @@ parse_config_kvpair(const char *config_str, struct perf_probe_event *pev) ...@@ -268,10 +267,10 @@ parse_config_kvpair(const char *config_str, struct perf_probe_event *pev)
} }
static int static int
parse_config(const char *config_str, struct perf_probe_event *pev) parse_prog_config(const char *config_str, struct perf_probe_event *pev)
{ {
int err; int err;
const char *main_str = parse_config_kvpair(config_str, pev); const char *main_str = parse_prog_config_kvpair(config_str, pev);
if (IS_ERR(main_str)) if (IS_ERR(main_str))
return PTR_ERR(main_str); return PTR_ERR(main_str);
...@@ -312,7 +311,7 @@ config_bpf_program(struct bpf_program *prog) ...@@ -312,7 +311,7 @@ config_bpf_program(struct bpf_program *prog)
pev = &priv->pev; pev = &priv->pev;
pr_debug("bpf: config program '%s'\n", config_str); pr_debug("bpf: config program '%s'\n", config_str);
err = parse_config(config_str, pev); err = parse_prog_config(config_str, pev);
if (err) if (err)
goto errout; goto errout;
...@@ -750,7 +749,7 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = { ...@@ -750,7 +749,7 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {
[ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string",
[ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error",
[ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet",
[ERRCODE_OFFSET(CONFIG_TERM)] = "Invalid config term in config string", [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string",
[ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue",
[ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program",
[ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue",
...@@ -834,7 +833,7 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, ...@@ -834,7 +833,7 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
int err, char *buf, size_t size) int err, char *buf, size_t size)
{ {
bpf__strerror_head(err, buf, size); bpf__strerror_head(err, buf, size);
case BPF_LOADER_ERRNO__CONFIG_TERM: { case BPF_LOADER_ERRNO__PROGCONF_TERM: {
scnprintf(buf, size, "%s (add -v to see detail)", emsg); scnprintf(buf, size, "%s (add -v to see detail)", emsg);
break; break;
} }
......
...@@ -20,7 +20,7 @@ enum bpf_loader_errno { ...@@ -20,7 +20,7 @@ enum bpf_loader_errno {
BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */
BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */
BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */
BPF_LOADER_ERRNO__CONFIG_TERM, /* Invalid config term in config term */ BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */
BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
......
...@@ -91,7 +91,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf) ...@@ -91,7 +91,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
bid += 2; bid += 2;
} }
return raw - build_id; return (bid - bf) + 1;
} }
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
......
...@@ -924,9 +924,6 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -924,9 +924,6 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
int64_t cmp = 0; int64_t cmp = 0;
perf_hpp__for_each_sort_list(fmt) { perf_hpp__for_each_sort_list(fmt) {
if (perf_hpp__should_skip(fmt))
continue;
cmp = fmt->cmp(fmt, left, right); cmp = fmt->cmp(fmt, left, right);
if (cmp) if (cmp)
break; break;
...@@ -942,9 +939,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) ...@@ -942,9 +939,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
int64_t cmp = 0; int64_t cmp = 0;
perf_hpp__for_each_sort_list(fmt) { perf_hpp__for_each_sort_list(fmt) {
if (perf_hpp__should_skip(fmt))
continue;
cmp = fmt->collapse(fmt, left, right); cmp = fmt->collapse(fmt, left, right);
if (cmp) if (cmp)
break; break;
......
...@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { ...@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
.symbol = "dummy", .symbol = "dummy",
.alias = "", .alias = "",
}, },
[PERF_COUNT_SW_BPF_OUTPUT] = {
.symbol = "bpf-output",
.alias = "",
},
}; };
#define __PERF_EVENT_FIELD(config, name) \ #define __PERF_EVENT_FIELD(config, name) \
...@@ -1879,7 +1883,7 @@ void print_symbol_events(const char *event_glob, unsigned type, ...@@ -1879,7 +1883,7 @@ void print_symbol_events(const char *event_glob, unsigned type,
for (i = 0; i < max; i++, syms++) { for (i = 0; i < max; i++, syms++) {
if (event_glob != NULL && if (event_glob != NULL && syms->symbol != NULL &&
!(strglobmatch(syms->symbol, event_glob) || !(strglobmatch(syms->symbol, event_glob) ||
(syms->alias && strglobmatch(syms->alias, event_glob)))) (syms->alias && strglobmatch(syms->alias, event_glob))))
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment