|
@@ -1136,12 +1136,78 @@ found:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+struct local_vars_finder {
|
|
|
+ struct probe_finder *pf;
|
|
|
+ struct perf_probe_arg *args;
|
|
|
+ int max_args;
|
|
|
+ int nargs;
|
|
|
+ int ret;
|
|
|
+};
|
|
|
+
|
|
|
+/* Collect available variables in this scope */
|
|
|
+static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
|
|
|
+{
|
|
|
+ struct local_vars_finder *vf = data;
|
|
|
+ int tag;
|
|
|
+
|
|
|
+ tag = dwarf_tag(die_mem);
|
|
|
+ if (tag == DW_TAG_formal_parameter ||
|
|
|
+ tag == DW_TAG_variable) {
|
|
|
+ if (convert_variable_location(die_mem, vf->pf->addr,
|
|
|
+ vf->pf->fb_ops, NULL) == 0) {
|
|
|
+ vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
|
|
|
+ if (vf->args[vf->nargs].var == NULL) {
|
|
|
+ vf->ret = -ENOMEM;
|
|
|
+ return DIE_FIND_CB_END;
|
|
|
+ }
|
|
|
+ pr_debug(" %s", vf->args[vf->nargs].var);
|
|
|
+ vf->nargs++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dwarf_haspc(die_mem, vf->pf->addr))
|
|
|
+ return DIE_FIND_CB_CONTINUE;
|
|
|
+ else
|
|
|
+ return DIE_FIND_CB_SIBLING;
|
|
|
+}
|
|
|
+
|
|
|
+static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
|
|
|
+ struct perf_probe_arg *args)
|
|
|
+{
|
|
|
+ Dwarf_Die die_mem;
|
|
|
+ int i;
|
|
|
+ int n = 0;
|
|
|
+ struct local_vars_finder vf = {.pf = pf, .args = args,
|
|
|
+ .max_args = MAX_PROBE_ARGS, .ret = 0};
|
|
|
+
|
|
|
+ for (i = 0; i < pf->pev->nargs; i++) {
|
|
|
+ /* var never be NULL */
|
|
|
+ if (strcmp(pf->pev->args[i].var, "$vars") == 0) {
|
|
|
+ pr_debug("Expanding $vars into:");
|
|
|
+ vf.nargs = n;
|
|
|
+ /* Special local variables */
|
|
|
+ die_find_child(sc_die, copy_variables_cb, (void *)&vf,
|
|
|
+ &die_mem);
|
|
|
+ pr_debug(" (%d)\n", vf.nargs - n);
|
|
|
+ if (vf.ret < 0)
|
|
|
+ return vf.ret;
|
|
|
+ n = vf.nargs;
|
|
|
+ } else {
|
|
|
+ /* Copy normal argument */
|
|
|
+ args[n] = pf->pev->args[i];
|
|
|
+ n++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return n;
|
|
|
+}
|
|
|
+
|
|
|
/* Add a found probe point into trace event list */
|
|
|
static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
|
|
|
{
|
|
|
struct trace_event_finder *tf =
|
|
|
container_of(pf, struct trace_event_finder, pf);
|
|
|
struct probe_trace_event *tev;
|
|
|
+ struct perf_probe_arg *args;
|
|
|
int ret, i;
|
|
|
|
|
|
/* Check number of tevs */
|
|
@@ -1161,21 +1227,35 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
|
|
|
pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
|
|
|
tev->point.offset);
|
|
|
|
|
|
- /* Find each argument */
|
|
|
- tev->nargs = pf->pev->nargs;
|
|
|
- tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
|
|
|
- if (tev->args == NULL)
|
|
|
+ /* Expand special probe argument if exist */
|
|
|
+ args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
|
|
|
+ if (args == NULL)
|
|
|
return -ENOMEM;
|
|
|
- for (i = 0; i < pf->pev->nargs; i++) {
|
|
|
- pf->pvar = &pf->pev->args[i];
|
|
|
+
|
|
|
+ ret = expand_probe_args(sc_die, pf, args);
|
|
|
+ if (ret < 0)
|
|
|
+ goto end;
|
|
|
+
|
|
|
+ tev->nargs = ret;
|
|
|
+ tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
|
|
|
+ if (tev->args == NULL) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto end;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Find each argument */
|
|
|
+ for (i = 0; i < tev->nargs; i++) {
|
|
|
+ pf->pvar = &args[i];
|
|
|
pf->tvar = &tev->args[i];
|
|
|
/* Variable should be found from scope DIE */
|
|
|
ret = find_variable(sc_die, pf);
|
|
|
if (ret != 0)
|
|
|
- return ret;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+end:
|
|
|
+ free(args);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* Find probe_trace_events specified by perf_probe_event from debuginfo */
|