|
@@ -38,6 +38,8 @@ struct bpf_prog_priv {
|
|
struct perf_probe_event pev;
|
|
struct perf_probe_event pev;
|
|
bool need_prologue;
|
|
bool need_prologue;
|
|
struct bpf_insn *insns_buf;
|
|
struct bpf_insn *insns_buf;
|
|
|
|
+ int nr_types;
|
|
|
|
+ int *type_mapping;
|
|
};
|
|
};
|
|
|
|
|
|
static bool libbpf_initialized;
|
|
static bool libbpf_initialized;
|
|
@@ -113,6 +115,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
|
|
|
|
|
|
cleanup_perf_probe_events(&priv->pev, 1);
|
|
cleanup_perf_probe_events(&priv->pev, 1);
|
|
zfree(&priv->insns_buf);
|
|
zfree(&priv->insns_buf);
|
|
|
|
+ zfree(&priv->type_mapping);
|
|
free(priv);
|
|
free(priv);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -381,7 +384,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
|
|
struct bpf_prog_priv *priv;
|
|
struct bpf_prog_priv *priv;
|
|
struct bpf_insn *buf;
|
|
struct bpf_insn *buf;
|
|
size_t prologue_cnt = 0;
|
|
size_t prologue_cnt = 0;
|
|
- int err;
|
|
|
|
|
|
+ int i, err;
|
|
|
|
|
|
err = bpf_program__get_private(prog, (void **)&priv);
|
|
err = bpf_program__get_private(prog, (void **)&priv);
|
|
if (err || !priv)
|
|
if (err || !priv)
|
|
@@ -389,10 +392,21 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
|
|
|
|
|
|
pev = &priv->pev;
|
|
pev = &priv->pev;
|
|
|
|
|
|
- if (n < 0 || n >= pev->ntevs)
|
|
|
|
|
|
+ if (n < 0 || n >= priv->nr_types)
|
|
goto errout;
|
|
goto errout;
|
|
|
|
|
|
- tev = &pev->tevs[n];
|
|
|
|
|
|
+ /* Find a tev belongs to that type */
|
|
|
|
+ for (i = 0; i < pev->ntevs; i++) {
|
|
|
|
+ if (priv->type_mapping[i] == n)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (i >= pev->ntevs) {
|
|
|
|
+ pr_debug("Internal error: prologue type %d not found\n", n);
|
|
|
|
+ return -BPF_LOADER_ERRNO__PROLOGUE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tev = &pev->tevs[i];
|
|
|
|
|
|
buf = priv->insns_buf;
|
|
buf = priv->insns_buf;
|
|
err = bpf__gen_prologue(tev->args, tev->nargs,
|
|
err = bpf__gen_prologue(tev->args, tev->nargs,
|
|
@@ -423,6 +437,101 @@ errout:
|
|
return -BPF_LOADER_ERRNO__PROLOGUE;
|
|
return -BPF_LOADER_ERRNO__PROLOGUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * compare_tev_args is reflexive, transitive and antisymmetric.
|
|
|
|
+ * I can proof it but this margin is too narrow to contain.
|
|
|
|
+ */
|
|
|
|
+static int compare_tev_args(const void *ptev1, const void *ptev2)
|
|
|
|
+{
|
|
|
|
+ int i, ret;
|
|
|
|
+ const struct probe_trace_event *tev1 =
|
|
|
|
+ *(const struct probe_trace_event **)ptev1;
|
|
|
|
+ const struct probe_trace_event *tev2 =
|
|
|
|
+ *(const struct probe_trace_event **)ptev2;
|
|
|
|
+
|
|
|
|
+ ret = tev2->nargs - tev1->nargs;
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < tev1->nargs; i++) {
|
|
|
|
+ struct probe_trace_arg *arg1, *arg2;
|
|
|
|
+ struct probe_trace_arg_ref *ref1, *ref2;
|
|
|
|
+
|
|
|
|
+ arg1 = &tev1->args[i];
|
|
|
|
+ arg2 = &tev2->args[i];
|
|
|
|
+
|
|
|
|
+ ret = strcmp(arg1->value, arg2->value);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ ref1 = arg1->ref;
|
|
|
|
+ ref2 = arg2->ref;
|
|
|
|
+
|
|
|
|
+ while (ref1 && ref2) {
|
|
|
|
+ ret = ref2->offset - ref1->offset;
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ ref1 = ref1->next;
|
|
|
|
+ ref2 = ref2->next;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ref1 || ref2)
|
|
|
|
+ return ref2 ? 1 : -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Assign a type number to each tevs in a pev.
|
|
|
|
+ * mapping is an array with same slots as tevs in that pev.
|
|
|
|
+ * nr_types will be set to number of types.
|
|
|
|
+ */
|
|
|
|
+static int map_prologue(struct perf_probe_event *pev, int *mapping,
|
|
|
|
+ int *nr_types)
|
|
|
|
+{
|
|
|
|
+ int i, type = 0;
|
|
|
|
+ struct probe_trace_event **ptevs;
|
|
|
|
+
|
|
|
|
+ size_t array_sz = sizeof(*ptevs) * pev->ntevs;
|
|
|
|
+
|
|
|
|
+ ptevs = malloc(array_sz);
|
|
|
|
+ if (!ptevs) {
|
|
|
|
+ pr_debug("No ehough memory: alloc ptevs failed\n");
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
|
|
|
|
+ for (i = 0; i < pev->ntevs; i++)
|
|
|
|
+ ptevs[i] = &pev->tevs[i];
|
|
|
|
+
|
|
|
|
+ qsort(ptevs, pev->ntevs, sizeof(*ptevs),
|
|
|
|
+ compare_tev_args);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < pev->ntevs; i++) {
|
|
|
|
+ int n;
|
|
|
|
+
|
|
|
|
+ n = ptevs[i] - pev->tevs;
|
|
|
|
+ if (i == 0) {
|
|
|
|
+ mapping[n] = type;
|
|
|
|
+ pr_debug("mapping[%d]=%d\n", n, type);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (compare_tev_args(ptevs + i, ptevs + i - 1) == 0)
|
|
|
|
+ mapping[n] = type;
|
|
|
|
+ else
|
|
|
|
+ mapping[n] = ++type;
|
|
|
|
+
|
|
|
|
+ pr_debug("mapping[%d]=%d\n", n, mapping[n]);
|
|
|
|
+ }
|
|
|
|
+ free(ptevs);
|
|
|
|
+ *nr_types = type + 1;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int hook_load_preprocessor(struct bpf_program *prog)
|
|
static int hook_load_preprocessor(struct bpf_program *prog)
|
|
{
|
|
{
|
|
struct perf_probe_event *pev;
|
|
struct perf_probe_event *pev;
|
|
@@ -462,7 +571,19 @@ static int hook_load_preprocessor(struct bpf_program *prog)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- err = bpf_program__set_prep(prog, pev->ntevs,
|
|
|
|
|
|
+ priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
|
|
|
|
+ if (!priv->type_mapping) {
|
|
|
|
+ pr_debug("No enough memory: alloc type_mapping failed\n");
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+ memset(priv->type_mapping, -1,
|
|
|
|
+ sizeof(int) * pev->ntevs);
|
|
|
|
+
|
|
|
|
+ err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ err = bpf_program__set_prep(prog, priv->nr_types,
|
|
preproc_gen_prologue);
|
|
preproc_gen_prologue);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
@@ -596,10 +717,13 @@ int bpf__foreach_tev(struct bpf_object *obj,
|
|
for (i = 0; i < pev->ntevs; i++) {
|
|
for (i = 0; i < pev->ntevs; i++) {
|
|
tev = &pev->tevs[i];
|
|
tev = &pev->tevs[i];
|
|
|
|
|
|
- if (priv->need_prologue)
|
|
|
|
- fd = bpf_program__nth_fd(prog, i);
|
|
|
|
- else
|
|
|
|
|
|
+ if (priv->need_prologue) {
|
|
|
|
+ int type = priv->type_mapping[i];
|
|
|
|
+
|
|
|
|
+ fd = bpf_program__nth_fd(prog, type);
|
|
|
|
+ } else {
|
|
fd = bpf_program__fd(prog);
|
|
fd = bpf_program__fd(prog);
|
|
|
|
+ }
|
|
|
|
|
|
if (fd < 0) {
|
|
if (fd < 0) {
|
|
pr_debug("bpf: failed to get file descriptor\n");
|
|
pr_debug("bpf: failed to get file descriptor\n");
|