[PATCH v2 4/4] perf tools: Improve BPF related error messages output
A series of bpf loader related error code is introduced to help error delivering. Functions are improved to return those new error code. Functions which return pointers are adjusted to encode error code into return value using "ERR_PTR". bpf_loader_strerror() are introduced to convert those error message to string. It detected the value of error code and calls libbpf_strerror() and strerror_r() accordingly, so caller don't need to consider checking the range of error code. bpf__strerror_head() is updated so existing strerror functions can support these error code automatically. Signed-off-by: Wang Nan Cc: Arnaldo Carvalho de Melo Cc: Namhyung Kim --- tools/perf/util/bpf-loader.c | 98 +- tools/perf/util/bpf-loader.h | 18 tools/perf/util/parse-events.c | 7 +-- 3 files changed, 110 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 76f07ce..375f254 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -14,6 +14,10 @@ #include "probe-finder.h" // for MAX_PROBES #include "llvm-utils.h" +#if BPF_LOADER_ERRNO__END >= LIBBPF_ERRNO__START +# error Too many BPF loader error code +#endif + #define DEFINE_PRINT_FN(name, level) \ static int libbpf_##name(const char *fmt, ...) \ { \ @@ -53,7 +57,7 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) err = llvm__compile_bpf(filename, _buf, _buf_sz); if (err) - return ERR_PTR(err); + return ERR_PTR(-BPF_LOADER_ERRNO__ECOMPILE); obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); free(obj_buf); } else @@ -113,14 +117,14 @@ config_bpf_program(struct bpf_program *prog) if (err < 0) { pr_debug("bpf: '%s' is not a valid config string\n", config_str); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__ECONFIG; goto errout; } if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { pr_debug("bpf: '%s': group for event is set and not '%s'.\n", config_str, PERF_BPF_PROBE_GROUP); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__EGROUP; goto errout; } else if (!pev->group) pev->group = strdup(PERF_BPF_PROBE_GROUP); @@ -132,9 +136,9 @@ config_bpf_program(struct bpf_program *prog) } if (!pev->event) { - pr_debug("bpf: '%s': event name is missing\n", + pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n", config_str); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__EEVENTNAME; goto errout; } pr_debug("bpf: config '%s' is ok\n", config_str); @@ -285,7 +289,7 @@ int bpf__foreach_tev(struct bpf_object *obj, (void **)); if (err || !priv) { pr_debug("bpf: failed to get private field\n"); - return -EINVAL; + return -BPF_LOADER_ERRNO__EINTERNAL; } pev = >pev; @@ -308,13 +312,65 @@ int bpf__foreach_tev(struct bpf_object *obj, return 0; } +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +struct { + int code; + const char *msg; +} bpf_loader_strerror_table[] = { + {BPF_LOADER_ERRNO__ECONFIG, "Invalid config string"}, + {BPF_LOADER_ERRNO__EGROUP, "Invalid group name"}, + {BPF_LOADER_ERRNO__EEVENTNAME, "No event name found in config string"}, + {BPF_LOADER_ERRNO__EINTERNAL, "BPF loader internal error"}, + {BPF_LOADER_ERRNO__ECOMPILE, "Error when compiling BPF scriptlet"}, +}; + +static int +bpf_loader_strerror(int err, char *buf, size_t size) +{ + unsigned int i; + + if (!buf || !size) + return -1; + + err = err > 0 ? err : -err; + + if (err > LIBBPF_ERRNO__START) + return libbpf_strerror(err, buf, size); + + if (err < BPF_LOADER_ERRNO__START) { + char sbuf[STRERR_BUFSIZE], *msg; + + msg = strerror_r(err, sbuf, sizeof(sbuf)); + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(bpf_loader_strerror_table); i++) { + if (bpf_loader_strerror_table[i].code == err) { + const char *msg; + + msg = bpf_loader_strerror_table[i].msg; + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + } + + snprintf(buf, size, "Unknown bpf loader error %d",
[PATCH v2 4/4] perf tools: Improve BPF related error messages output
A series of bpf loader related error code is introduced to help error delivering. Functions are improved to return those new error code. Functions which return pointers are adjusted to encode error code into return value using "ERR_PTR". bpf_loader_strerror() are introduced to convert those error message to string. It detected the value of error code and calls libbpf_strerror() and strerror_r() accordingly, so caller don't need to consider checking the range of error code. bpf__strerror_head() is updated so existing strerror functions can support these error code automatically. Signed-off-by: Wang NanCc: Arnaldo Carvalho de Melo Cc: Namhyung Kim --- tools/perf/util/bpf-loader.c | 98 +- tools/perf/util/bpf-loader.h | 18 tools/perf/util/parse-events.c | 7 +-- 3 files changed, 110 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 76f07ce..375f254 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -14,6 +14,10 @@ #include "probe-finder.h" // for MAX_PROBES #include "llvm-utils.h" +#if BPF_LOADER_ERRNO__END >= LIBBPF_ERRNO__START +# error Too many BPF loader error code +#endif + #define DEFINE_PRINT_FN(name, level) \ static int libbpf_##name(const char *fmt, ...) \ { \ @@ -53,7 +57,7 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) err = llvm__compile_bpf(filename, _buf, _buf_sz); if (err) - return ERR_PTR(err); + return ERR_PTR(-BPF_LOADER_ERRNO__ECOMPILE); obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); free(obj_buf); } else @@ -113,14 +117,14 @@ config_bpf_program(struct bpf_program *prog) if (err < 0) { pr_debug("bpf: '%s' is not a valid config string\n", config_str); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__ECONFIG; goto errout; } if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { pr_debug("bpf: '%s': group for event is set and not '%s'.\n", config_str, PERF_BPF_PROBE_GROUP); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__EGROUP; goto errout; } else if (!pev->group) pev->group = strdup(PERF_BPF_PROBE_GROUP); @@ -132,9 +136,9 @@ config_bpf_program(struct bpf_program *prog) } if (!pev->event) { - pr_debug("bpf: '%s': event name is missing\n", + pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n", config_str); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__EEVENTNAME; goto errout; } pr_debug("bpf: config '%s' is ok\n", config_str); @@ -285,7 +289,7 @@ int bpf__foreach_tev(struct bpf_object *obj, (void **)); if (err || !priv) { pr_debug("bpf: failed to get private field\n"); - return -EINVAL; + return -BPF_LOADER_ERRNO__EINTERNAL; } pev = >pev; @@ -308,13 +312,65 @@ int bpf__foreach_tev(struct bpf_object *obj, return 0; } +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +struct { + int code; + const char *msg; +} bpf_loader_strerror_table[] = { + {BPF_LOADER_ERRNO__ECONFIG, "Invalid config string"}, + {BPF_LOADER_ERRNO__EGROUP, "Invalid group name"}, + {BPF_LOADER_ERRNO__EEVENTNAME, "No event name found in config string"}, + {BPF_LOADER_ERRNO__EINTERNAL, "BPF loader internal error"}, + {BPF_LOADER_ERRNO__ECOMPILE, "Error when compiling BPF scriptlet"}, +}; + +static int +bpf_loader_strerror(int err, char *buf, size_t size) +{ + unsigned int i; + + if (!buf || !size) + return -1; + + err = err > 0 ? err : -err; + + if (err > LIBBPF_ERRNO__START) + return libbpf_strerror(err, buf, size); + + if (err < BPF_LOADER_ERRNO__START) { + char sbuf[STRERR_BUFSIZE], *msg; + + msg = strerror_r(err, sbuf, sizeof(sbuf)); + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(bpf_loader_strerror_table); i++) { + if (bpf_loader_strerror_table[i].code == err) { + const char *msg; + + msg = bpf_loader_strerror_table[i].msg; + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + } +