|
@@ -53,7 +53,7 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
|
|
|
|
|
|
err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
|
|
|
if (err)
|
|
|
- return ERR_PTR(err);
|
|
|
+ return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
|
|
|
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
|
|
|
free(obj_buf);
|
|
|
} else
|
|
@@ -113,14 +113,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__CONFIG;
|
|
|
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__GROUP;
|
|
|
goto errout;
|
|
|
} else if (!pev->group)
|
|
|
pev->group = strdup(PERF_BPF_PROBE_GROUP);
|
|
@@ -132,9 +132,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__EVENTNAME;
|
|
|
goto errout;
|
|
|
}
|
|
|
pr_debug("bpf: config '%s' is ok\n", config_str);
|
|
@@ -285,7 +285,7 @@ int bpf__foreach_tev(struct bpf_object *obj,
|
|
|
(void **)&priv);
|
|
|
if (err || !priv) {
|
|
|
pr_debug("bpf: failed to get private field\n");
|
|
|
- return -EINVAL;
|
|
|
+ return -BPF_LOADER_ERRNO__INTERNAL;
|
|
|
}
|
|
|
|
|
|
pev = &priv->pev;
|
|
@@ -308,6 +308,18 @@ int bpf__foreach_tev(struct bpf_object *obj,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
|
|
|
+#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
|
|
|
+#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
|
|
|
+
|
|
|
+static const char *bpf_loader_strerror_table[NR_ERRNO] = {
|
|
|
+ [ERRCODE_OFFSET(CONFIG)] = "Invalid config string",
|
|
|
+ [ERRCODE_OFFSET(GROUP)] = "Invalid group name",
|
|
|
+ [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string",
|
|
|
+ [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error",
|
|
|
+ [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet",
|
|
|
+};
|
|
|
+
|
|
|
static int
|
|
|
bpf_loader_strerror(int err, char *buf, size_t size)
|
|
|
{
|
|
@@ -322,10 +334,21 @@ bpf_loader_strerror(int err, char *buf, size_t size)
|
|
|
if (err >= __LIBBPF_ERRNO__START)
|
|
|
return libbpf_strerror(err, buf, size);
|
|
|
|
|
|
- msg = strerror_r(err, sbuf, sizeof(sbuf));
|
|
|
- snprintf(buf, size, "%s", msg);
|
|
|
+ if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) {
|
|
|
+ msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)];
|
|
|
+ snprintf(buf, size, "%s", msg);
|
|
|
+ buf[size - 1] = '\0';
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (err >= __BPF_LOADER_ERRNO__END)
|
|
|
+ snprintf(buf, size, "Unknown bpf loader error %d", err);
|
|
|
+ else
|
|
|
+ snprintf(buf, size, "%s",
|
|
|
+ strerror_r(err, sbuf, sizeof(sbuf)));
|
|
|
+
|
|
|
buf[size - 1] = '\0';
|
|
|
- return 0;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
#define bpf__strerror_head(err, buf, size) \
|
|
@@ -351,21 +374,62 @@ bpf_loader_strerror(int err, char *buf, size_t size)
|
|
|
}\
|
|
|
buf[size - 1] = '\0';
|
|
|
|
|
|
+int bpf__strerror_prepare_load(const char *filename, bool source,
|
|
|
+ int err, char *buf, size_t size)
|
|
|
+{
|
|
|
+ size_t n;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ n = snprintf(buf, size, "Failed to load %s%s: ",
|
|
|
+ filename, source ? " from source" : "");
|
|
|
+ if (n >= size) {
|
|
|
+ buf[size - 1] = '\0';
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ buf += n;
|
|
|
+ size -= n;
|
|
|
+
|
|
|
+ ret = bpf_loader_strerror(err, buf, size);
|
|
|
+ buf[size - 1] = '\0';
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
|
|
|
int err, char *buf, size_t size)
|
|
|
{
|
|
|
bpf__strerror_head(err, buf, size);
|
|
|
bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
|
|
|
- bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n");
|
|
|
- bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n");
|
|
|
+ bpf__strerror_entry(EACCES, "You need to be root");
|
|
|
+ bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
|
|
|
+ bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
|
|
|
bpf__strerror_end(buf, size);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
|
|
|
+int bpf__strerror_load(struct bpf_object *obj,
|
|
|
int err, char *buf, size_t size)
|
|
|
{
|
|
|
bpf__strerror_head(err, buf, size);
|
|
|
+ case LIBBPF_ERRNO__KVER: {
|
|
|
+ unsigned int obj_kver = bpf_object__get_kversion(obj);
|
|
|
+ unsigned int real_kver;
|
|
|
+
|
|
|
+ if (fetch_kernel_version(&real_kver, NULL, 0)) {
|
|
|
+ scnprintf(buf, size, "Unable to fetch kernel version");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (obj_kver != real_kver) {
|
|
|
+ scnprintf(buf, size,
|
|
|
+ "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")",
|
|
|
+ KVER_PARAM(obj_kver),
|
|
|
+ KVER_PARAM(real_kver));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ scnprintf(buf, size, "Failed to load program for unknown reason");
|
|
|
+ break;
|
|
|
+ }
|
|
|
bpf__strerror_end(buf, size);
|
|
|
return 0;
|
|
|
}
|