aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-11-06 08:58:09 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-11-06 15:14:20 -0500
commitd3e0ce393057cfa907a0c4fe7b1ff56d5c30cca5 (patch)
treeabd8dc974a4323430790c78edfc917c4e0a330ad /tools/perf
parent07bc5c699a3d8fe5e26dbcd72e4103c7988055ba (diff)
perf bpf: Improve BPF related error messages
A series of bpf loader related error codes were introduced to help error reporting. Functions were improved to return these new error codes. Functions which return pointers were adjusted to encode error codes into return value using the ERR_PTR() interface. bpf_loader_strerror() was improved to convert these error messages to strings. It checks the error codes and calls libbpf_strerror() and strerror_r() accordingly, so caller don't need to consider checking the range of the error code. In bpf__strerror_load(), print kernel version of running kernel and the object's 'version' section to notify user how to fix his/her program. v1 -> v2: Use macro for error code. Fetch error message based on array index, eliminate for-loop. Print version strings. Before: # perf record -e ./test_kversion_nomatch_program.o sleep 1 event syntax error: './test_kversion_nomatch_program.o' \___ Failed to load program: Validate your program and check 'license'/'version' sections in your object SKIP After: # perf record -e ./test_kversion_nomatch_program.o ls event syntax error: './test_kversion_nomatch_program.o' \___ 'version' (4.4.0) doesn't match running kernel (4.3.0) SKIP Signed-off-by: Wang Nan <wangnan0@huawei.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1446818289-87444-1-git-send-email-wangnan0@huawei.com [ Add 'static inline' to bpf__strerror_prepare_load() when LIBBPF is disabled ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/bpf-loader.c88
-rw-r--r--tools/perf/util/bpf-loader.h23
-rw-r--r--tools/perf/util/parse-events.c7
-rw-r--r--tools/perf/util/util.h5
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
315static 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
311static int 323static int
312bpf_loader_strerror(int err, char *buf, size_t size) 324bpf_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
377int 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
354int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, 397int 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
365int bpf__strerror_load(struct bpf_object *obj __maybe_unused, 409int 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
15enum 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
14struct bpf_object; 26struct 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
21struct bpf_object *bpf__prepare_load(const char *filename, bool source); 33struct bpf_object *bpf__prepare_load(const char *filename, bool source);
34int bpf__strerror_prepare_load(const char *filename, bool source,
35 int err, char *buf, size_t size);
22 36
23void bpf__clear(void); 37void 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
84static inline
85int 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
70static inline int 93static inline int
71bpf__strerror_probe(struct bpf_object *obj __maybe_unused, 94bpf__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
353int fetch_kernel_version(unsigned int *puint, 353int 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 */