[PATCH v2 4/4] perf tools: Improve BPF related error messages output

2015-11-03 Thread Wang Nan
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

2015-11-03 Thread Wang Nan
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;
+   }
+   }
+