diff options
| -rw-r--r-- | tools/perf/util/bpf-loader.c | 88 | ||||
| -rw-r--r-- | tools/perf/util/bpf-loader.h | 23 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 7 | ||||
| -rw-r--r-- | tools/perf/util/util.h | 5 |
4 files changed, 108 insertions, 15 deletions
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index c46256b1f5fd..e3afa1b60bb5 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
| @@ -53,7 +53,7 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) | |||
| 53 | 53 | ||
| 54 | err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); | 54 | err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); |
| 55 | if (err) | 55 | if (err) |
| 56 | return ERR_PTR(err); | 56 | return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); |
| 57 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); | 57 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); |
| 58 | free(obj_buf); | 58 | free(obj_buf); |
| 59 | } else | 59 | } else |
| @@ -113,14 +113,14 @@ config_bpf_program(struct bpf_program *prog) | |||
| 113 | if (err < 0) { | 113 | if (err < 0) { |
| 114 | pr_debug("bpf: '%s' is not a valid config string\n", | 114 | pr_debug("bpf: '%s' is not a valid config string\n", |
| 115 | config_str); | 115 | config_str); |
| 116 | err = -EINVAL; | 116 | err = -BPF_LOADER_ERRNO__CONFIG; |
| 117 | goto errout; | 117 | goto errout; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { | 120 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { |
| 121 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", | 121 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", |
| 122 | config_str, PERF_BPF_PROBE_GROUP); | 122 | config_str, PERF_BPF_PROBE_GROUP); |
| 123 | err = -EINVAL; | 123 | err = -BPF_LOADER_ERRNO__GROUP; |
| 124 | goto errout; | 124 | goto errout; |
| 125 | } else if (!pev->group) | 125 | } else if (!pev->group) |
| 126 | pev->group = strdup(PERF_BPF_PROBE_GROUP); | 126 | pev->group = strdup(PERF_BPF_PROBE_GROUP); |
| @@ -132,9 +132,9 @@ config_bpf_program(struct bpf_program *prog) | |||
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | if (!pev->event) { | 134 | if (!pev->event) { |
| 135 | pr_debug("bpf: '%s': event name is missing\n", | 135 | pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n", |
| 136 | config_str); | 136 | config_str); |
| 137 | err = -EINVAL; | 137 | err = -BPF_LOADER_ERRNO__EVENTNAME; |
| 138 | goto errout; | 138 | goto errout; |
| 139 | } | 139 | } |
| 140 | pr_debug("bpf: config '%s' is ok\n", config_str); | 140 | pr_debug("bpf: config '%s' is ok\n", config_str); |
| @@ -285,7 +285,7 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
| 285 | (void **)&priv); | 285 | (void **)&priv); |
| 286 | if (err || !priv) { | 286 | if (err || !priv) { |
| 287 | pr_debug("bpf: failed to get private field\n"); | 287 | pr_debug("bpf: failed to get private field\n"); |
| 288 | return -EINVAL; | 288 | return -BPF_LOADER_ERRNO__INTERNAL; |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | pev = &priv->pev; | 291 | pev = &priv->pev; |
| @@ -308,6 +308,18 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
| 308 | return 0; | 308 | return 0; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | ||
| 312 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) | ||
| 313 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) | ||
| 314 | |||
| 315 | static const char *bpf_loader_strerror_table[NR_ERRNO] = { | ||
| 316 | [ERRCODE_OFFSET(CONFIG)] = "Invalid config string", | ||
| 317 | [ERRCODE_OFFSET(GROUP)] = "Invalid group name", | ||
| 318 | [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", | ||
| 319 | [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", | ||
| 320 | [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", | ||
| 321 | }; | ||
| 322 | |||
| 311 | static int | 323 | static int |
| 312 | bpf_loader_strerror(int err, char *buf, size_t size) | 324 | bpf_loader_strerror(int err, char *buf, size_t size) |
| 313 | { | 325 | { |
| @@ -322,10 +334,21 @@ bpf_loader_strerror(int err, char *buf, size_t size) | |||
| 322 | if (err >= __LIBBPF_ERRNO__START) | 334 | if (err >= __LIBBPF_ERRNO__START) |
| 323 | return libbpf_strerror(err, buf, size); | 335 | return libbpf_strerror(err, buf, size); |
| 324 | 336 | ||
| 325 | msg = strerror_r(err, sbuf, sizeof(sbuf)); | 337 | if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) { |
| 326 | snprintf(buf, size, "%s", msg); | 338 | msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)]; |
| 339 | snprintf(buf, size, "%s", msg); | ||
| 340 | buf[size - 1] = '\0'; | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | if (err >= __BPF_LOADER_ERRNO__END) | ||
| 345 | snprintf(buf, size, "Unknown bpf loader error %d", err); | ||
| 346 | else | ||
| 347 | snprintf(buf, size, "%s", | ||
| 348 | strerror_r(err, sbuf, sizeof(sbuf))); | ||
| 349 | |||
| 327 | buf[size - 1] = '\0'; | 350 | buf[size - 1] = '\0'; |
| 328 | return 0; | 351 | return -1; |
| 329 | } | 352 | } |
| 330 | 353 | ||
| 331 | #define bpf__strerror_head(err, buf, size) \ | 354 | #define bpf__strerror_head(err, buf, size) \ |
| @@ -351,21 +374,62 @@ bpf_loader_strerror(int err, char *buf, size_t size) | |||
| 351 | }\ | 374 | }\ |
| 352 | buf[size - 1] = '\0'; | 375 | buf[size - 1] = '\0'; |
| 353 | 376 | ||
| 377 | int bpf__strerror_prepare_load(const char *filename, bool source, | ||
| 378 | int err, char *buf, size_t size) | ||
| 379 | { | ||
| 380 | size_t n; | ||
| 381 | int ret; | ||
| 382 | |||
| 383 | n = snprintf(buf, size, "Failed to load %s%s: ", | ||
| 384 | filename, source ? " from source" : ""); | ||
| 385 | if (n >= size) { | ||
| 386 | buf[size - 1] = '\0'; | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | buf += n; | ||
| 390 | size -= n; | ||
| 391 | |||
| 392 | ret = bpf_loader_strerror(err, buf, size); | ||
| 393 | buf[size - 1] = '\0'; | ||
| 394 | return ret; | ||
| 395 | } | ||
| 396 | |||
| 354 | int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | 397 | int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, |
| 355 | int err, char *buf, size_t size) | 398 | int err, char *buf, size_t size) |
| 356 | { | 399 | { |
| 357 | bpf__strerror_head(err, buf, size); | 400 | bpf__strerror_head(err, buf, size); |
| 358 | bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); | 401 | bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); |
| 359 | bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); | 402 | bpf__strerror_entry(EACCES, "You need to be root"); |
| 360 | bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); | 403 | bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0"); |
| 404 | bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file"); | ||
| 361 | bpf__strerror_end(buf, size); | 405 | bpf__strerror_end(buf, size); |
| 362 | return 0; | 406 | return 0; |
| 363 | } | 407 | } |
| 364 | 408 | ||
| 365 | int bpf__strerror_load(struct bpf_object *obj __maybe_unused, | 409 | int bpf__strerror_load(struct bpf_object *obj, |
| 366 | int err, char *buf, size_t size) | 410 | int err, char *buf, size_t size) |
| 367 | { | 411 | { |
| 368 | bpf__strerror_head(err, buf, size); | 412 | bpf__strerror_head(err, buf, size); |
| 413 | case LIBBPF_ERRNO__KVER: { | ||
| 414 | unsigned int obj_kver = bpf_object__get_kversion(obj); | ||
| 415 | unsigned int real_kver; | ||
| 416 | |||
| 417 | if (fetch_kernel_version(&real_kver, NULL, 0)) { | ||
| 418 | scnprintf(buf, size, "Unable to fetch kernel version"); | ||
| 419 | break; | ||
| 420 | } | ||
| 421 | |||
| 422 | if (obj_kver != real_kver) { | ||
| 423 | scnprintf(buf, size, | ||
| 424 | "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")", | ||
| 425 | KVER_PARAM(obj_kver), | ||
| 426 | KVER_PARAM(real_kver)); | ||
| 427 | break; | ||
| 428 | } | ||
| 429 | |||
| 430 | scnprintf(buf, size, "Failed to load program for unknown reason"); | ||
| 431 | break; | ||
| 432 | } | ||
| 369 | bpf__strerror_end(buf, size); | 433 | bpf__strerror_end(buf, size); |
| 370 | return 0; | 434 | return 0; |
| 371 | } | 435 | } |
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index ccd8d7fd79d3..5eb3629eed8b 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
| @@ -8,9 +8,21 @@ | |||
| 8 | #include <linux/compiler.h> | 8 | #include <linux/compiler.h> |
| 9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
| 10 | #include <string.h> | 10 | #include <string.h> |
| 11 | #include <bpf/libbpf.h> | ||
| 11 | #include "probe-event.h" | 12 | #include "probe-event.h" |
| 12 | #include "debug.h" | 13 | #include "debug.h" |
| 13 | 14 | ||
| 15 | enum bpf_loader_errno { | ||
| 16 | __BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100, | ||
| 17 | /* Invalid config string */ | ||
| 18 | BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START, | ||
| 19 | BPF_LOADER_ERRNO__GROUP, /* Invalid group name */ | ||
| 20 | BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ | ||
| 21 | BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ | ||
| 22 | BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ | ||
| 23 | __BPF_LOADER_ERRNO__END, | ||
| 24 | }; | ||
| 25 | |||
| 14 | struct bpf_object; | 26 | struct bpf_object; |
| 15 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" | 27 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" |
| 16 | 28 | ||
| @@ -19,6 +31,8 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, | |||
| 19 | 31 | ||
| 20 | #ifdef HAVE_LIBBPF_SUPPORT | 32 | #ifdef HAVE_LIBBPF_SUPPORT |
| 21 | struct bpf_object *bpf__prepare_load(const char *filename, bool source); | 33 | struct bpf_object *bpf__prepare_load(const char *filename, bool source); |
| 34 | int bpf__strerror_prepare_load(const char *filename, bool source, | ||
| 35 | int err, char *buf, size_t size); | ||
| 22 | 36 | ||
| 23 | void bpf__clear(void); | 37 | void bpf__clear(void); |
| 24 | 38 | ||
| @@ -67,6 +81,15 @@ __bpf_strerror(char *buf, size_t size) | |||
| 67 | return 0; | 81 | return 0; |
| 68 | } | 82 | } |
| 69 | 83 | ||
| 84 | static inline | ||
| 85 | int bpf__strerror_prepare_load(const char *filename __maybe_unused, | ||
| 86 | bool source __maybe_unused, | ||
| 87 | int err __maybe_unused, | ||
| 88 | char *buf, size_t size) | ||
| 89 | { | ||
| 90 | return __bpf_strerror(buf, size); | ||
| 91 | } | ||
| 92 | |||
| 70 | static inline int | 93 | static inline int |
| 71 | bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | 94 | bpf__strerror_probe(struct bpf_object *obj __maybe_unused, |
| 72 | int err __maybe_unused, | 95 | int err __maybe_unused, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c75b25d5e28c..e48d9da75707 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -642,9 +642,10 @@ int parse_events_load_bpf(struct parse_events_evlist *data, | |||
| 642 | snprintf(errbuf, sizeof(errbuf), | 642 | snprintf(errbuf, sizeof(errbuf), |
| 643 | "BPF support is not compiled"); | 643 | "BPF support is not compiled"); |
| 644 | else | 644 | else |
| 645 | snprintf(errbuf, sizeof(errbuf), | 645 | bpf__strerror_prepare_load(bpf_file_name, |
| 646 | "BPF object file '%s' is invalid", | 646 | source, |
| 647 | bpf_file_name); | 647 | -err, errbuf, |
| 648 | sizeof(errbuf)); | ||
| 648 | 649 | ||
| 649 | data->error->help = strdup("(add -v to see detail)"); | 650 | data->error->help = strdup("(add -v to see detail)"); |
| 650 | data->error->str = strdup(errbuf); | 651 | data->error->str = strdup(errbuf); |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 2665126267dc..dcc659017976 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
| @@ -352,5 +352,10 @@ int get_stack_size(const char *str, unsigned long *_size); | |||
| 352 | 352 | ||
| 353 | int fetch_kernel_version(unsigned int *puint, | 353 | int fetch_kernel_version(unsigned int *puint, |
| 354 | char *str, size_t str_sz); | 354 | char *str, size_t str_sz); |
| 355 | #define KVER_VERSION(x) (((x) >> 16) & 0xff) | ||
| 356 | #define KVER_PATCHLEVEL(x) (((x) >> 8) & 0xff) | ||
| 357 | #define KVER_SUBLEVEL(x) ((x) & 0xff) | ||
| 358 | #define KVER_FMT "%d.%d.%d" | ||
| 359 | #define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) | ||
| 355 | 360 | ||
| 356 | #endif /* GIT_COMPAT_UTIL_H */ | 361 | #endif /* GIT_COMPAT_UTIL_H */ |
