From 9ed7e1b85cd55dc46cb9410a23086bdaa2ff3eb9 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Mon, 14 Jun 2010 15:26:30 -0400 Subject: perf probe: Add kernel source path option The probe plugin requires access to the source code for some operations. The source code must be in the exact same location as specified by the DWARF tags, but sometimes the location is an absolute path that cannot be replicated by a normal user. This change adds the -s|--source option to allow the user to specify the root of the kernel source tree. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Masami Hiramatsu LKML-Reference: <1276543590-10486-1-git-send-email-chase.douglas@canonical.com> Signed-off-by: Chase Douglas Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 58 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index d964cb199c6..baf66538349 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -37,6 +37,7 @@ #include "event.h" #include "debug.h" #include "util.h" +#include "symbol.h" #include "probe-finder.h" /* Kprobe tracer basic type is up to u64 */ @@ -57,6 +58,55 @@ static int strtailcmp(const char *s1, const char *s2) return 0; } +/* + * Find a src file from a DWARF tag path. Prepend optional source path prefix + * and chop off leading directories that do not exist. Result is passed back as + * a newly allocated path on success. + * Return 0 if file was found and readable, -errno otherwise. + */ +static int get_real_path(const char *raw_path, char **new_path) +{ + if (!symbol_conf.source_prefix) { + if (access(raw_path, R_OK) == 0) { + *new_path = strdup(raw_path); + return 0; + } else + return -errno; + } + + *new_path = malloc((strlen(symbol_conf.source_prefix) + + strlen(raw_path) + 2)); + if (!*new_path) + return -ENOMEM; + + for (;;) { + sprintf(*new_path, "%s/%s", symbol_conf.source_prefix, + raw_path); + + if (access(*new_path, R_OK) == 0) + return 0; + + switch (errno) { + case ENAMETOOLONG: + case ENOENT: + case EROFS: + case EFAULT: + raw_path = strchr(++raw_path, '/'); + if (!raw_path) { + free(*new_path); + *new_path = NULL; + return -ENOENT; + } + continue; + + default: + free(*new_path); + *new_path = NULL; + return -errno; + } + } +} + /* Line number list operations */ /* Add a line to line number list */ @@ -1096,11 +1146,13 @@ end: static int line_range_add_line(const char *src, unsigned int lineno, struct line_range *lr) { + int ret; + /* Copy real path */ if (!lr->path) { - lr->path = strdup(src); - if (lr->path == NULL) - return -ENOMEM; + ret = get_real_path(src, &lr->path); + if (ret != 0) + return ret; } return line_list__add_line(&lr->line_list, lineno); } -- cgit v1.2.3-70-g09d2 From 73317b954041031249e8968d2e9023ff4e960d99 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 19 May 2010 15:57:35 -0400 Subject: perf probe: Support "string" type Support string type casting to event argument. If perf-probe finds an argument casted as string, it ensures the target variable is "(unsigned/signed) char *(or []). perf-probe also adds dereference if the target is a pointer. So, both of 'char buf[10];' and 'char *buf;' can be accessed by 'buf:string' Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Frederic Weisbecker LKML-Reference: <20100519195734.2885.1666.stgit@localhost6.localdomain6> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-probe.txt | 2 +- tools/perf/util/probe-finder.c | 59 +++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 12 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index ea531d9d975..394016d33ce 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -95,7 +95,7 @@ Each probe argument follows below syntax. [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) -'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. +'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type. LINE SYNTAX ----------- diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index baf66538349..aaea16b1c60 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -464,18 +464,61 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf) } static int convert_variable_type(Dwarf_Die *vr_die, - struct kprobe_trace_arg *targ) + struct kprobe_trace_arg *tvar, + const char *cast) { + struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref; Dwarf_Die type; char buf[16]; int ret; + /* TODO: check all types */ + if (cast && strcmp(cast, "string") != 0) { + /* Non string type is OK */ + tvar->type = strdup(cast); + return (tvar->type == NULL) ? -ENOMEM : 0; + } + if (die_get_real_type(vr_die, &type) == NULL) { pr_warning("Failed to get a type information of %s.\n", dwarf_diename(vr_die)); return -ENOENT; } + if (cast && strcmp(cast, "string") == 0) { /* String type */ + ret = dwarf_tag(&type); + if (ret != DW_TAG_pointer_type && + ret != DW_TAG_array_type) { + pr_warning("Failed to cast into string: " + "%s(%s) is not a pointer nor array.", + dwarf_diename(vr_die), dwarf_diename(&type)); + return -EINVAL; + } + if (ret == DW_TAG_pointer_type) { + if (die_get_real_type(&type, &type) == NULL) { + pr_warning("Failed to get a type information."); + return -ENOENT; + } + while (*ref_ptr) + ref_ptr = &(*ref_ptr)->next; + /* Add new reference with offset +0 */ + *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref)); + if (*ref_ptr == NULL) { + pr_warning("Out of memory error\n"); + return -ENOMEM; + } + } + if (die_compare_name(&type, "char") != 0 && + die_compare_name(&type, "unsigned char") != 0) { + pr_warning("Failed to cast into string: " + "%s is not (unsigned) char *.", + dwarf_diename(vr_die)); + return -EINVAL; + } + tvar->type = strdup(cast); + return (tvar->type == NULL) ? -ENOMEM : 0; + } + ret = die_get_byte_size(&type) * 8; if (ret) { /* Check the bitwidth */ @@ -495,8 +538,8 @@ static int convert_variable_type(Dwarf_Die *vr_die, strerror(-ret)); return ret; } - targ->type = strdup(buf); - if (targ->type == NULL) + tvar->type = strdup(buf); + if (tvar->type == NULL) return -ENOMEM; } return 0; @@ -606,14 +649,8 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) &die_mem); vr_die = &die_mem; } - if (ret == 0) { - if (pf->pvar->type) { - pf->tvar->type = strdup(pf->pvar->type); - if (pf->tvar->type == NULL) - ret = -ENOMEM; - } else - ret = convert_variable_type(vr_die, pf->tvar); - } + if (ret == 0) + ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); /* *expr will be cached in libdw. Don't free it. */ return ret; error: -- cgit v1.2.3-70-g09d2 From b2a3c12b7442247c440f7083d48ef05716753ec1 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 19 May 2010 15:57:42 -0400 Subject: perf probe: Support tracing an entry of array Add array-entry tracing support to perf probe. This enables to trace an entry of array which is indexed by constant value, e.g. array[0]. For example: $ perf probe -a 'bio_split bi->bi_io_vec[0]' Cc: Paul Mackerras Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Frederic Weisbecker LKML-Reference: <20100519195742.2885.5344.stgit@localhost6.localdomain6> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-probe.txt | 2 +- tools/perf/util/probe-event.c | 56 +++++++++++++++++++++++---------- tools/perf/util/probe-event.h | 1 + tools/perf/util/probe-finder.c | 48 ++++++++++++++++++++++++---- 4 files changed, 83 insertions(+), 24 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 394016d33ce..27d52dae5a4 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt @@ -94,7 +94,7 @@ Each probe argument follows below syntax. [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] -'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) +'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type. LINE SYNTAX diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 914c67095d9..351baa9a369 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -557,7 +557,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) /* Parse perf-probe event argument */ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) { - char *tmp; + char *tmp, *goodname; struct perf_probe_arg_field **fieldp; pr_debug("parsing arg: %s into ", str); @@ -580,7 +580,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) pr_debug("type:%s ", arg->type); } - tmp = strpbrk(str, "-."); + tmp = strpbrk(str, "-.["); if (!is_c_varname(str) || !tmp) { /* A variable, register, symbol or special value */ arg->var = strdup(str); @@ -590,10 +590,11 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) return 0; } - /* Structure fields */ + /* Structure fields or array element */ arg->var = strndup(str, tmp - str); if (arg->var == NULL) return -ENOMEM; + goodname = arg->var; pr_debug("%s, ", arg->var); fieldp = &arg->field; @@ -601,22 +602,38 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); if (*fieldp == NULL) return -ENOMEM; - if (*tmp == '.') { - str = tmp + 1; - (*fieldp)->ref = false; - } else if (tmp[1] == '>') { - str = tmp + 2; + if (*tmp == '[') { /* Array */ + str = tmp; + (*fieldp)->index = strtol(str + 1, &tmp, 0); (*fieldp)->ref = true; - } else { - semantic_error("Argument parse error: %s\n", str); - return -EINVAL; + if (*tmp != ']' || tmp == str + 1) { + semantic_error("Array index must be a" + " number.\n"); + return -EINVAL; + } + tmp++; + if (*tmp == '\0') + tmp = NULL; + } else { /* Structure */ + if (*tmp == '.') { + str = tmp + 1; + (*fieldp)->ref = false; + } else if (tmp[1] == '>') { + str = tmp + 2; + (*fieldp)->ref = true; + } else { + semantic_error("Argument parse error: %s\n", + str); + return -EINVAL; + } + tmp = strpbrk(str, "-.["); } - - tmp = strpbrk(str, "-."); if (tmp) { (*fieldp)->name = strndup(str, tmp - str); if ((*fieldp)->name == NULL) return -ENOMEM; + if (*str != '[') + goodname = (*fieldp)->name; pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); fieldp = &(*fieldp)->next; } @@ -624,11 +641,13 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) (*fieldp)->name = strdup(str); if ((*fieldp)->name == NULL) return -ENOMEM; + if (*str != '[') + goodname = (*fieldp)->name; pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); - /* If no name is specified, set the last field name */ + /* If no name is specified, set the last field name (not array index)*/ if (!arg->name) { - arg->name = strdup((*fieldp)->name); + arg->name = strdup(goodname); if (arg->name == NULL) return -ENOMEM; } @@ -776,8 +795,11 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) len -= ret; while (field) { - ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".", - field->name); + if (field->name[0] == '[') + ret = e_snprintf(tmp, len, "%s", field->name); + else + ret = e_snprintf(tmp, len, "%s%s", + field->ref ? "->" : ".", field->name); if (ret <= 0) goto error; tmp += ret; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index e9db1a214ca..bc06d3e8baf 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -50,6 +50,7 @@ struct perf_probe_point { struct perf_probe_arg_field { struct perf_probe_arg_field *next; /* Next field */ char *name; /* Name of the field */ + long index; /* Array index number */ bool ref; /* Referencing flag */ }; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index aaea16b1c60..308664deb85 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -485,6 +485,9 @@ static int convert_variable_type(Dwarf_Die *vr_die, return -ENOENT; } + pr_debug("%s type is %s.\n", + dwarf_diename(vr_die), dwarf_diename(&type)); + if (cast && strcmp(cast, "string") == 0) { /* String type */ ret = dwarf_tag(&type); if (ret != DW_TAG_pointer_type && @@ -553,16 +556,44 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, struct kprobe_trace_arg_ref *ref = *ref_ptr; Dwarf_Die type; Dwarf_Word offs; - int ret; + int ret, tag; pr_debug("converting %s in %s\n", field->name, varname); if (die_get_real_type(vr_die, &type) == NULL) { pr_warning("Failed to get the type of %s.\n", varname); return -ENOENT; } - - /* Check the pointer and dereference */ - if (dwarf_tag(&type) == DW_TAG_pointer_type) { + pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); + tag = dwarf_tag(&type); + + if (field->name[0] == '[' && + (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { + if (field->next) + /* Save original type for next field */ + memcpy(die_mem, &type, sizeof(*die_mem)); + /* Get the type of this array */ + if (die_get_real_type(&type, &type) == NULL) { + pr_warning("Failed to get the type of %s.\n", varname); + return -ENOENT; + } + pr_debug2("Array real type: (%x)\n", + (unsigned)dwarf_dieoffset(&type)); + if (tag == DW_TAG_pointer_type) { + ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); + if (ref == NULL) + return -ENOMEM; + if (*ref_ptr) + (*ref_ptr)->next = ref; + else + *ref_ptr = ref; + } + ref->offset += die_get_byte_size(&type) * field->index; + if (!field->next) + /* Save vr_die for converting types */ + memcpy(die_mem, vr_die, sizeof(*die_mem)); + goto next; + } else if (tag == DW_TAG_pointer_type) { + /* Check the pointer and dereference */ if (!field->ref) { pr_err("Semantic error: %s must be referred by '->'\n", field->name); @@ -588,10 +619,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, *ref_ptr = ref; } else { /* Verify it is a data structure */ - if (dwarf_tag(&type) != DW_TAG_structure_type) { + if (tag != DW_TAG_structure_type) { pr_warning("%s is not a data structure.\n", varname); return -EINVAL; } + if (field->name[0] == '[') { + pr_err("Semantic error: %s is not a pointor nor array.", + varname); + return -EINVAL; + } if (field->ref) { pr_err("Semantic error: %s must be referred by '.'\n", field->name); @@ -618,6 +654,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, } ref->offset += (long)offs; +next: /* Converting next field */ if (field->next) return convert_variable_fields(die_mem, field->name, @@ -667,7 +704,6 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) char buf[32], *ptr; int ret; - /* TODO: Support arrays */ if (pf->pvar->name) pf->tvar->name = strdup(pf->pvar->name); else { -- cgit v1.2.3-70-g09d2 From b7dcb857cc3eb89136111fefe89780129c1af1d7 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 19 May 2010 15:57:49 -0400 Subject: perf probe: Support static and global variables Add static and global variables support to perf probe. This allows user to trace non-local variables (and structure members) at probe points. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Frederic Weisbecker LKML-Reference: <20100519195749.2885.17451.stgit@localhost6.localdomain6> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 15 ++++++-- tools/perf/util/probe-finder.c | 85 ++++++++++++++++++++++++++++++------------ 2 files changed, 73 insertions(+), 27 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 351baa9a369..09cf5465e10 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -926,6 +926,7 @@ out: static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, char *buf, size_t buflen) { + struct kprobe_trace_arg_ref *ref = arg->ref; int ret, depth = 0; char *tmp = buf; @@ -939,16 +940,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, buf += ret; buflen -= ret; + /* Special case: @XXX */ + if (arg->value[0] == '@' && arg->ref) + ref = ref->next; + /* Dereferencing arguments */ - if (arg->ref) { - depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf, + if (ref) { + depth = __synthesize_kprobe_trace_arg_ref(ref, &buf, &buflen, 1); if (depth < 0) return depth; } /* Print argument value */ - ret = e_snprintf(buf, buflen, "%s", arg->value); + if (arg->value[0] == '@' && arg->ref) + ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, + arg->ref->offset); + else + ret = e_snprintf(buf, buflen, "%s", arg->value); if (ret < 0) return ret; buf += ret; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 308664deb85..3e64e1fa105 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -406,14 +406,50 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, * Probe finder related functions */ +static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs) +{ + struct kprobe_trace_arg_ref *ref; + ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); + if (ref != NULL) + ref->offset = offs; + return ref; +} + /* Show a location */ -static int convert_location(Dwarf_Op *op, struct probe_finder *pf) +static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) { + Dwarf_Attribute attr; + Dwarf_Op *op; + size_t nops; unsigned int regn; Dwarf_Word offs = 0; bool ref = false; const char *regs; struct kprobe_trace_arg *tvar = pf->tvar; + int ret; + + /* TODO: handle more than 1 exprs */ + if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || + dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 || + nops == 0) { + /* TODO: Support const_value */ + pr_err("Failed to find the location of %s at this address.\n" + " Perhaps, it has been optimized out.\n", pf->pvar->var); + return -ENOENT; + } + + if (op->atom == DW_OP_addr) { + /* Static variables on memory (not stack), make @varname */ + ret = strlen(dwarf_diename(vr_die)); + tvar->value = zalloc(ret + 2); + if (tvar->value == NULL) + return -ENOMEM; + snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); + tvar->ref = alloc_trace_arg_ref((long)offs); + if (tvar->ref == NULL) + return -ENOMEM; + return 0; + } /* If this is based on frame buffer, set the offset */ if (op->atom == DW_OP_fbreg) { @@ -455,10 +491,9 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf) return -ENOMEM; if (ref) { - tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); + tvar->ref = alloc_trace_arg_ref((long)offs); if (tvar->ref == NULL) return -ENOMEM; - tvar->ref->offset = (long)offs; } return 0; } @@ -666,20 +701,13 @@ next: /* Show a variables in kprobe event format */ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) { - Dwarf_Attribute attr; Dwarf_Die die_mem; - Dwarf_Op *expr; - size_t nexpr; int ret; - if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) - goto error; - /* TODO: handle more than 1 exprs */ - ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1); - if (ret <= 0 || nexpr == 0) - goto error; + pr_debug("Converting variable %s into trace event.\n", + dwarf_diename(vr_die)); - ret = convert_location(expr, pf); + ret = convert_variable_location(vr_die, pf); if (ret == 0 && pf->pvar->field) { ret = convert_variable_fields(vr_die, pf->pvar->var, pf->pvar->field, &pf->tvar->ref, @@ -690,19 +718,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); /* *expr will be cached in libdw. Don't free it. */ return ret; -error: - /* TODO: Support const_value */ - pr_err("Failed to find the location of %s at this address.\n" - " Perhaps, it has been optimized out.\n", pf->pvar->var); - return -ENOENT; } /* Find a variable in a subprogram die */ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) { - Dwarf_Die vr_die; + Dwarf_Die vr_die, *scopes; char buf[32], *ptr; - int ret; + int ret, nscopes; if (pf->pvar->name) pf->tvar->name = strdup(pf->pvar->name); @@ -730,12 +753,26 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); /* Search child die for local variables and parameters. */ - if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { + if (die_find_variable(sp_die, pf->pvar->var, &vr_die)) + ret = convert_variable(&vr_die, pf); + else { + /* Search upper class */ + nscopes = dwarf_getscopes_die(sp_die, &scopes); + if (nscopes > 0) { + ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var, + 0, NULL, 0, 0, &vr_die); + if (ret >= 0) + ret = convert_variable(&vr_die, pf); + else + ret = -ENOENT; + free(scopes); + } else + ret = -ENOENT; + } + if (ret < 0) pr_warning("Failed to find '%s' in this function.\n", pf->pvar->var); - return -ENOENT; - } - return convert_variable(&vr_die, pf); + return ret; } /* Show a probe point to output buffer */ -- cgit v1.2.3-70-g09d2 From 7cf0b79e6ffd04bba5d4e625a0fe2e30a5b383e5 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 9 Jul 2010 18:28:59 +0900 Subject: perf probe: Fix error message if get_real_path() failed Perf probe -L shows incorrect error message (Dwarf error) if it fails to find source file. This can confuse users. # ./perf probe -s /nowhere -L vfs_read Debuginfo analysis failed. (-2) Error: Failed to show lines. (-2) With this patch, it shows correct message. # ./perf probe -s /nowhere -L vfs_read Failed to find source file. (-2) Error: Failed to show lines. (-2) LKML-Reference: <4C36EBDB.4020308@hitachi.com> Cc: Chase Douglas Cc: Arnaldo Carvalho de Melo Cc: Ingo Molnar Acked-by: Chase Douglas Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 59 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/probe-finder.c | 61 ++++-------------------------------------- 2 files changed, 64 insertions(+), 56 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 09cf5465e10..8d08e75b2dd 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -195,6 +195,55 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, return ntevs; } +/* + * Find a src file from a DWARF tag path. Prepend optional source path prefix + * and chop off leading directories that do not exist. Result is passed back as + * a newly allocated path on success. + * Return 0 if file was found and readable, -errno otherwise. + */ +static int get_real_path(const char *raw_path, char **new_path) +{ + if (!symbol_conf.source_prefix) { + if (access(raw_path, R_OK) == 0) { + *new_path = strdup(raw_path); + return 0; + } else + return -errno; + } + + *new_path = malloc((strlen(symbol_conf.source_prefix) + + strlen(raw_path) + 2)); + if (!*new_path) + return -ENOMEM; + + for (;;) { + sprintf(*new_path, "%s/%s", symbol_conf.source_prefix, + raw_path); + + if (access(*new_path, R_OK) == 0) + return 0; + + switch (errno) { + case ENAMETOOLONG: + case ENOENT: + case EROFS: + case EFAULT: + raw_path = strchr(++raw_path, '/'); + if (!raw_path) { + free(*new_path); + *new_path = NULL; + return -ENOENT; + } + continue; + + default: + free(*new_path); + *new_path = NULL; + return -errno; + } + } +} + #define LINEBUF_SIZE 256 #define NR_ADDITIONAL_LINES 2 @@ -244,6 +293,7 @@ int show_line_range(struct line_range *lr) struct line_node *ln; FILE *fp; int fd, ret; + char *tmp; /* Search a line range */ ret = init_vmlinux(); @@ -266,6 +316,15 @@ int show_line_range(struct line_range *lr) return ret; } + /* Convert source file path */ + tmp = lr->path; + ret = get_real_path(tmp, &lr->path); + free(tmp); /* Free old path */ + if (ret < 0) { + pr_warning("Failed to find source file. (%d)\n", ret); + return ret; + } + setup_pager(); if (lr->function) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3e64e1fa105..a934a364c30 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -58,55 +58,6 @@ static int strtailcmp(const char *s1, const char *s2) return 0; } -/* - * Find a src file from a DWARF tag path. Prepend optional source path prefix - * and chop off leading directories that do not exist. Result is passed back as - * a newly allocated path on success. - * Return 0 if file was found and readable, -errno otherwise. - */ -static int get_real_path(const char *raw_path, char **new_path) -{ - if (!symbol_conf.source_prefix) { - if (access(raw_path, R_OK) == 0) { - *new_path = strdup(raw_path); - return 0; - } else - return -errno; - } - - *new_path = malloc((strlen(symbol_conf.source_prefix) + - strlen(raw_path) + 2)); - if (!*new_path) - return -ENOMEM; - - for (;;) { - sprintf(*new_path, "%s/%s", symbol_conf.source_prefix, - raw_path); - - if (access(*new_path, R_OK) == 0) - return 0; - - switch (errno) { - case ENAMETOOLONG: - case ENOENT: - case EROFS: - case EFAULT: - raw_path = strchr(++raw_path, '/'); - if (!raw_path) { - free(*new_path); - *new_path = NULL; - return -ENOENT; - } - continue; - - default: - free(*new_path); - *new_path = NULL; - return -errno; - } - } -} - /* Line number list operations */ /* Add a line to line number list */ @@ -1256,13 +1207,11 @@ end: static int line_range_add_line(const char *src, unsigned int lineno, struct line_range *lr) { - int ret; - - /* Copy real path */ + /* Copy source path */ if (!lr->path) { - ret = get_real_path(src, &lr->path); - if (ret != 0) - return ret; + lr->path = strdup(src); + if (lr->path == NULL) + return -ENOMEM; } return line_list__add_line(&lr->line_list, lineno); } @@ -1460,7 +1409,7 @@ int find_line_range(int fd, struct line_range *lr) } off = noff; } - pr_debug("path: %lx\n", (unsigned long)lr->path); + pr_debug("path: %s\n", lr->path); dwarf_end(dbg); return (ret < 0) ? ret : lf.found; -- cgit v1.2.3-70-g09d2 From 6a330a3c8a648916b3c6bda79a78c38ac093af17 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 9 Jul 2010 18:29:11 +0900 Subject: perf probe: Support comp_dir to find an absolute source path Gcc generates DW_AT_comp_dir and stores relative source path if building kernel without O= option. In that case, perf probe --line sometimes doesn't work without --source option, because it tries to access relative source path. This adds DW_AT_comp_dir support to perf probe for finding an absolute source path when no --source option. LKML-Reference: <4C36EBE7.3060802@hitachi.com> Cc: Ingo Molnar Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 34 ++++++++++++++++++++++------------ tools/perf/util/probe-event.h | 1 + tools/perf/util/probe-finder.c | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+), 12 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8d08e75b2dd..4445a1e7052 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -201,28 +201,38 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, * a newly allocated path on success. * Return 0 if file was found and readable, -errno otherwise. */ -static int get_real_path(const char *raw_path, char **new_path) +static int get_real_path(const char *raw_path, const char *comp_dir, + char **new_path) { - if (!symbol_conf.source_prefix) { - if (access(raw_path, R_OK) == 0) { - *new_path = strdup(raw_path); - return 0; - } else - return -errno; + const char *prefix = symbol_conf.source_prefix; + + if (!prefix) { + if (raw_path[0] != '/' && comp_dir) + /* If not an absolute path, try to use comp_dir */ + prefix = comp_dir; + else { + if (access(raw_path, R_OK) == 0) { + *new_path = strdup(raw_path); + return 0; + } else + return -errno; + } } - *new_path = malloc((strlen(symbol_conf.source_prefix) + - strlen(raw_path) + 2)); + *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); if (!*new_path) return -ENOMEM; for (;;) { - sprintf(*new_path, "%s/%s", symbol_conf.source_prefix, - raw_path); + sprintf(*new_path, "%s/%s", prefix, raw_path); if (access(*new_path, R_OK) == 0) return 0; + if (!symbol_conf.source_prefix) + /* In case of searching comp_dir, don't retry */ + return -errno; + switch (errno) { case ENAMETOOLONG: case ENOENT: @@ -318,7 +328,7 @@ int show_line_range(struct line_range *lr) /* Convert source file path */ tmp = lr->path; - ret = get_real_path(tmp, &lr->path); + ret = get_real_path(tmp, lr->comp_dir, &lr->path); free(tmp); /* Free old path */ if (ret < 0) { pr_warning("Failed to find source file. (%d)\n", ret); diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index bc06d3e8baf..ed362acff4b 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -86,6 +86,7 @@ struct line_range { int end; /* End line number */ int offset; /* Start line offset */ char *path; /* Real path name */ + char *comp_dir; /* Compile directory */ struct list_head line_list; /* Visible lines */ }; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index a934a364c30..37dcdb651a6 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -144,6 +144,15 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) return src; } +/* Get DW_AT_comp_dir (should be NULL with older gcc) */ +static const char *cu_get_comp_dir(Dwarf_Die *cu_die) +{ + Dwarf_Attribute attr; + if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) + return NULL; + return dwarf_formstring(&attr); +} + /* Compare diename and tname */ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) { @@ -1374,6 +1383,7 @@ int find_line_range(int fd, struct line_range *lr) size_t cuhl; Dwarf_Die *diep; Dwarf *dbg; + const char *comp_dir; dbg = dwarf_begin(fd, DWARF_C_READ); if (!dbg) { @@ -1409,6 +1419,17 @@ int find_line_range(int fd, struct line_range *lr) } off = noff; } + + /* Store comp_dir */ + if (lf.found) { + comp_dir = cu_get_comp_dir(&lf.cu_die); + if (comp_dir) { + lr->comp_dir = strdup(comp_dir); + if (!lr->comp_dir) + ret = -ENOMEM; + } + } + pr_debug("path: %s\n", lr->path); dwarf_end(dbg); -- cgit v1.2.3-70-g09d2 From 8217563359878d11ef03cc76bc935ada89d73efd Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 9 Jul 2010 18:29:17 +0900 Subject: perf probe: Fix the logic of die_compare_name Invert the return value of die_compare_name(), because it returns a 'bool' result which should be expeced true if the die's name is same as compared string. LKML-Reference: <4C36EBED.1000006@hitachi.com> Cc: Arnaldo Carvalho de Melo Cc: Ingo Molnar Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 37dcdb651a6..f88070ea5b9 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -158,7 +158,7 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) { const char *name; name = dwarf_diename(dw_die); - return name ? strcmp(tname, name) : -1; + return name ? (strcmp(tname, name) == 0) : false; } /* Get type die, but skip qualifiers and typedef */ @@ -329,7 +329,7 @@ static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) tag = dwarf_tag(die_mem); if ((tag == DW_TAG_formal_parameter || tag == DW_TAG_variable) && - (die_compare_name(die_mem, name) == 0)) + die_compare_name(die_mem, name)) return DIE_FIND_CB_FOUND; return DIE_FIND_CB_CONTINUE; @@ -348,7 +348,7 @@ static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) const char *name = data; if ((dwarf_tag(die_mem) == DW_TAG_member) && - (die_compare_name(die_mem, name) == 0)) + die_compare_name(die_mem, name)) return DIE_FIND_CB_FOUND; return DIE_FIND_CB_SIBLING; @@ -506,8 +506,8 @@ static int convert_variable_type(Dwarf_Die *vr_die, return -ENOMEM; } } - if (die_compare_name(&type, "char") != 0 && - die_compare_name(&type, "unsigned char") != 0) { + if (!die_compare_name(&type, "char") && + !die_compare_name(&type, "unsigned char")) { pr_warning("Failed to cast into string: " "%s is not (unsigned) char *.", dwarf_diename(vr_die)); @@ -1017,7 +1017,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) /* Check tag and diename */ if (dwarf_tag(sp_die) != DW_TAG_subprogram || - die_compare_name(sp_die, pp->function) != 0) + !die_compare_name(sp_die, pp->function)) return DWARF_CB_OK; pf->fname = dwarf_decl_file(sp_die); @@ -1340,7 +1340,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) struct line_range *lr = lf->lr; if (dwarf_tag(sp_die) == DW_TAG_subprogram && - die_compare_name(sp_die, lr->function) == 0) { + die_compare_name(sp_die, lr->function)) { lf->fname = dwarf_decl_file(sp_die); dwarf_decl_line(sp_die, &lr->offset); pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); -- cgit v1.2.3-70-g09d2 From 0e60836bbd392300198c5c2d918c18845428a1fe Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Thu, 29 Jul 2010 19:43:51 +0530 Subject: perf probe: Rename common fields/functions from kprobe to probe. As a precursor for perf to support uprobes, rename fields/functions that had kprobe in their name but can be shared across perf-kprobes and perf-uprobes to probe. Cc: Ananth N Mavinakayanahalli Cc: Andrew Morton Cc: Christoph Hellwig Cc: "Frank Ch. Eigler" Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jim Keniston Cc: Linus Torvalds Cc: Mark Wielaard Cc: Mathieu Desnoyers Cc: Naren A Devaiah Cc: Oleg Nesterov Cc: "Paul E. McKenney" Cc: Peter Zijlstra Cc: Randy Dunlap Cc: Steven Rostedt LKML-Reference: <20100729141351.GG21723@linux.vnet.ibm.com> Signed-off-by: Srikar Dronamraju Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 1 - tools/perf/util/probe-event.c | 135 +++++++++++++++++++++-------------------- tools/perf/util/probe-event.h | 27 +++------ tools/perf/util/probe-finder.c | 34 +++++------ tools/perf/util/probe-finder.h | 10 +-- 5 files changed, 101 insertions(+), 106 deletions(-) (limited to 'tools/perf/util/probe-finder.c') diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 54551867e7e..199d5e19554 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -267,4 +267,3 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) } return 0; } - diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4445a1e7052..2e665cb8405 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1,5 +1,5 @@ /* - * probe-event.c : perf-probe definition to kprobe_events format converter + * probe-event.c : perf-probe definition to probe_events format converter * * Written by Masami Hiramatsu * @@ -120,8 +120,11 @@ static int open_vmlinux(void) return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); } -/* Convert trace point to probe point with debuginfo */ -static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, +/* + * Convert trace point to probe point with debuginfo + * Currently only handles kprobes. + */ +static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, struct perf_probe_point *pp) { struct symbol *sym; @@ -151,8 +154,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, } /* Try to find perf_probe_event with debuginfo */ -static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event **tevs, +static int try_to_find_probe_trace_events(struct perf_probe_event *pev, + struct probe_trace_event **tevs, int max_tevs) { bool need_dwarf = perf_probe_event_need_dwarf(pev); @@ -169,11 +172,11 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, } /* Searching trace events corresponding to probe event */ - ntevs = find_kprobe_trace_events(fd, pev, tevs, max_tevs); + ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); close(fd); if (ntevs > 0) { /* Succeeded to find trace events */ - pr_debug("find %d kprobe_trace_events.\n", ntevs); + pr_debug("find %d probe_trace_events.\n", ntevs); return ntevs; } @@ -377,8 +380,8 @@ end: #else /* !DWARF_SUPPORT */ -static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, - struct perf_probe_point *pp) +static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, + struct perf_probe_point *pp) { pp->function = strdup(tp->symbol); if (pp->function == NULL) @@ -389,8 +392,8 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, return 0; } -static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event **tevs __unused, +static int try_to_find_probe_trace_events(struct perf_probe_event *pev, + struct probe_trace_event **tevs __unused, int max_tevs __unused) { if (perf_probe_event_need_dwarf(pev)) { @@ -781,16 +784,17 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) return false; } -/* Parse kprobe_events event into struct probe_point */ -int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) +/* Parse probe_events event into struct probe_point */ +static int parse_probe_trace_command(const char *cmd, + struct probe_trace_event *tev) { - struct kprobe_trace_point *tp = &tev->point; + struct probe_trace_point *tp = &tev->point; char pr; char *p; int ret, i, argc; char **argv; - pr_debug("Parsing kprobe_events: %s\n", cmd); + pr_debug("Parsing probe_events: %s\n", cmd); argv = argv_split(cmd, &argc); if (!argv) { pr_debug("Failed to split arguments.\n"); @@ -822,7 +826,7 @@ int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) tp->offset = 0; tev->nargs = argc - 2; - tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); + tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); if (tev->args == NULL) { ret = -ENOMEM; goto out; @@ -968,13 +972,13 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev) } #endif -static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref, +static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, char **buf, size_t *buflen, int depth) { int ret; if (ref->next) { - depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf, + depth = __synthesize_probe_trace_arg_ref(ref->next, buf, buflen, depth + 1); if (depth < 0) goto out; @@ -992,10 +996,10 @@ out: } -static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, +static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, char *buf, size_t buflen) { - struct kprobe_trace_arg_ref *ref = arg->ref; + struct probe_trace_arg_ref *ref = arg->ref; int ret, depth = 0; char *tmp = buf; @@ -1015,7 +1019,7 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, /* Dereferencing arguments */ if (ref) { - depth = __synthesize_kprobe_trace_arg_ref(ref, &buf, + depth = __synthesize_probe_trace_arg_ref(ref, &buf, &buflen, 1); if (depth < 0) return depth; @@ -1051,9 +1055,9 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, return buf - tmp; } -char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) +char *synthesize_probe_trace_command(struct probe_trace_event *tev) { - struct kprobe_trace_point *tp = &tev->point; + struct probe_trace_point *tp = &tev->point; char *buf; int i, len, ret; @@ -1069,7 +1073,7 @@ char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) goto error; for (i = 0; i < tev->nargs; i++) { - ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len, + ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, MAX_CMDLEN - len); if (ret <= 0) goto error; @@ -1082,7 +1086,7 @@ error: return NULL; } -int convert_to_perf_probe_event(struct kprobe_trace_event *tev, +static int convert_to_perf_probe_event(struct probe_trace_event *tev, struct perf_probe_event *pev) { char buf[64] = ""; @@ -1095,7 +1099,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev, return -ENOMEM; /* Convert trace_point to probe_point */ - ret = convert_to_perf_probe_point(&tev->point, &pev->point); + ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); if (ret < 0) return ret; @@ -1108,7 +1112,7 @@ int convert_to_perf_probe_event(struct kprobe_trace_event *tev, if (tev->args[i].name) pev->args[i].name = strdup(tev->args[i].name); else { - ret = synthesize_kprobe_trace_arg(&tev->args[i], + ret = synthesize_probe_trace_arg(&tev->args[i], buf, 64); pev->args[i].name = strdup(buf); } @@ -1159,9 +1163,9 @@ void clear_perf_probe_event(struct perf_probe_event *pev) memset(pev, 0, sizeof(*pev)); } -void clear_kprobe_trace_event(struct kprobe_trace_event *tev) +static void clear_probe_trace_event(struct probe_trace_event *tev) { - struct kprobe_trace_arg_ref *ref, *next; + struct probe_trace_arg_ref *ref, *next; int i; if (tev->event) @@ -1222,7 +1226,7 @@ static int open_kprobe_events(bool readwrite) } /* Get raw string list of current kprobe_events */ -static struct strlist *get_kprobe_trace_command_rawlist(int fd) +static struct strlist *get_probe_trace_command_rawlist(int fd) { int ret, idx; FILE *fp; @@ -1290,7 +1294,7 @@ static int show_perf_probe_event(struct perf_probe_event *pev) int show_perf_probe_events(void) { int fd, ret; - struct kprobe_trace_event tev; + struct probe_trace_event tev; struct perf_probe_event pev; struct strlist *rawlist; struct str_node *ent; @@ -1307,20 +1311,20 @@ int show_perf_probe_events(void) if (fd < 0) return fd; - rawlist = get_kprobe_trace_command_rawlist(fd); + rawlist = get_probe_trace_command_rawlist(fd); close(fd); if (!rawlist) return -ENOENT; strlist__for_each(ent, rawlist) { - ret = parse_kprobe_trace_command(ent->s, &tev); + ret = parse_probe_trace_command(ent->s, &tev); if (ret >= 0) { ret = convert_to_perf_probe_event(&tev, &pev); if (ret >= 0) ret = show_perf_probe_event(&pev); } clear_perf_probe_event(&pev); - clear_kprobe_trace_event(&tev); + clear_probe_trace_event(&tev); if (ret < 0) break; } @@ -1330,20 +1334,19 @@ int show_perf_probe_events(void) } /* Get current perf-probe event names */ -static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) +static struct strlist *get_probe_trace_event_names(int fd, bool include_group) { char buf[128]; struct strlist *sl, *rawlist; struct str_node *ent; - struct kprobe_trace_event tev; + struct probe_trace_event tev; int ret = 0; memset(&tev, 0, sizeof(tev)); - - rawlist = get_kprobe_trace_command_rawlist(fd); + rawlist = get_probe_trace_command_rawlist(fd); sl = strlist__new(true, NULL); strlist__for_each(ent, rawlist) { - ret = parse_kprobe_trace_command(ent->s, &tev); + ret = parse_probe_trace_command(ent->s, &tev); if (ret < 0) break; if (include_group) { @@ -1353,7 +1356,7 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) ret = strlist__add(sl, buf); } else ret = strlist__add(sl, tev.event); - clear_kprobe_trace_event(&tev); + clear_probe_trace_event(&tev); if (ret < 0) break; } @@ -1366,13 +1369,13 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) return sl; } -static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) +static int write_probe_trace_event(int fd, struct probe_trace_event *tev) { int ret = 0; - char *buf = synthesize_kprobe_trace_command(tev); + char *buf = synthesize_probe_trace_command(tev); if (!buf) { - pr_debug("Failed to synthesize kprobe trace event.\n"); + pr_debug("Failed to synthesize probe trace event.\n"); return -EINVAL; } @@ -1425,12 +1428,12 @@ static int get_new_event_name(char *buf, size_t len, const char *base, return ret; } -static int __add_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event *tevs, +static int __add_probe_trace_events(struct perf_probe_event *pev, + struct probe_trace_event *tevs, int ntevs, bool allow_suffix) { int i, fd, ret; - struct kprobe_trace_event *tev = NULL; + struct probe_trace_event *tev = NULL; char buf[64]; const char *event, *group; struct strlist *namelist; @@ -1439,7 +1442,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev, if (fd < 0) return fd; /* Get current event names */ - namelist = get_kprobe_trace_event_names(fd, false); + namelist = get_probe_trace_event_names(fd, false); if (!namelist) { pr_debug("Failed to get current event list.\n"); return -EIO; @@ -1474,7 +1477,7 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev, ret = -ENOMEM; break; } - ret = write_kprobe_trace_event(fd, tev); + ret = write_probe_trace_event(fd, tev); if (ret < 0) break; /* Add added event name to namelist */ @@ -1511,21 +1514,21 @@ static int __add_kprobe_trace_events(struct perf_probe_event *pev, return ret; } -static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, - struct kprobe_trace_event **tevs, +static int convert_to_probe_trace_events(struct perf_probe_event *pev, + struct probe_trace_event **tevs, int max_tevs) { struct symbol *sym; int ret = 0, i; - struct kprobe_trace_event *tev; + struct probe_trace_event *tev; /* Convert perf_probe_event with debuginfo */ - ret = try_to_find_kprobe_trace_events(pev, tevs, max_tevs); + ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); if (ret != 0) return ret; /* Allocate trace event buffer */ - tev = *tevs = zalloc(sizeof(struct kprobe_trace_event)); + tev = *tevs = zalloc(sizeof(struct probe_trace_event)); if (tev == NULL) return -ENOMEM; @@ -1538,7 +1541,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, tev->point.offset = pev->point.offset; tev->nargs = pev->nargs; if (tev->nargs) { - tev->args = zalloc(sizeof(struct kprobe_trace_arg) + tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); if (tev->args == NULL) { ret = -ENOMEM; @@ -1579,7 +1582,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, return 1; error: - clear_kprobe_trace_event(tev); + clear_probe_trace_event(tev); free(tev); *tevs = NULL; return ret; @@ -1587,7 +1590,7 @@ error: struct __event_package { struct perf_probe_event *pev; - struct kprobe_trace_event *tevs; + struct probe_trace_event *tevs; int ntevs; }; @@ -1610,7 +1613,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, for (i = 0; i < npevs; i++) { pkgs[i].pev = &pevs[i]; /* Convert with or without debuginfo */ - ret = convert_to_kprobe_trace_events(pkgs[i].pev, + ret = convert_to_probe_trace_events(pkgs[i].pev, &pkgs[i].tevs, max_tevs); if (ret < 0) goto end; @@ -1619,24 +1622,24 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, /* Loop 2: add all events */ for (i = 0; i < npevs && ret >= 0; i++) - ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, + ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, pkgs[i].ntevs, force_add); end: /* Loop 3: cleanup trace events */ for (i = 0; i < npevs; i++) for (j = 0; j < pkgs[i].ntevs; j++) - clear_kprobe_trace_event(&pkgs[i].tevs[j]); + clear_probe_trace_event(&pkgs[i].tevs[j]); return ret; } -static int __del_trace_kprobe_event(int fd, struct str_node *ent) +static int __del_trace_probe_event(int fd, struct str_node *ent) { char *p; char buf[128]; int ret; - /* Convert from perf-probe event to trace-kprobe event */ + /* Convert from perf-probe event to trace-probe event */ ret = e_snprintf(buf, 128, "-:%s", ent->s); if (ret < 0) goto error; @@ -1662,7 +1665,7 @@ error: return ret; } -static int del_trace_kprobe_event(int fd, const char *group, +static int del_trace_probe_event(int fd, const char *group, const char *event, struct strlist *namelist) { char buf[128]; @@ -1679,7 +1682,7 @@ static int del_trace_kprobe_event(int fd, const char *group, strlist__for_each_safe(ent, n, namelist) if (strglobmatch(ent->s, buf)) { found++; - ret = __del_trace_kprobe_event(fd, ent); + ret = __del_trace_probe_event(fd, ent); if (ret < 0) break; strlist__remove(namelist, ent); @@ -1688,7 +1691,7 @@ static int del_trace_kprobe_event(int fd, const char *group, ent = strlist__find(namelist, buf); if (ent) { found++; - ret = __del_trace_kprobe_event(fd, ent); + ret = __del_trace_probe_event(fd, ent); if (ret >= 0) strlist__remove(namelist, ent); } @@ -1712,7 +1715,7 @@ int del_perf_probe_events(struct strlist *dellist) return fd; /* Get current event names */ - namelist = get_kprobe_trace_event_names(fd, true); + namelist = get_probe_trace_event_names(fd, true); if (namelist == NULL) return -EINVAL; @@ -1733,7 +1736,7 @@ int del_perf_probe_events(struct strlist *dellist) event = str; } pr_debug("Group: %s, Event: %s\n", group, event); - ret = del_trace_kprobe_event(fd, group, event, namelist); + ret = del_trace_probe_event(fd, group, event, namelist); free(str); if (ret < 0) break; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index ed362acff4b..5af39243a25 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -7,33 +7,33 @@ extern bool probe_event_dry_run; /* kprobe-tracer tracing point */ -struct kprobe_trace_point { +struct probe_trace_point { char *symbol; /* Base symbol */ unsigned long offset; /* Offset from symbol */ bool retprobe; /* Return probe flag */ }; -/* kprobe-tracer tracing argument referencing offset */ -struct kprobe_trace_arg_ref { - struct kprobe_trace_arg_ref *next; /* Next reference */ +/* probe-tracer tracing argument referencing offset */ +struct probe_trace_arg_ref { + struct probe_trace_arg_ref *next; /* Next reference */ long offset; /* Offset value */ }; /* kprobe-tracer tracing argument */ -struct kprobe_trace_arg { +struct probe_trace_arg { char *name; /* Argument name */ char *value; /* Base value */ char *type; /* Type name */ - struct kprobe_trace_arg_ref *ref; /* Referencing offset */ + struct probe_trace_arg_ref *ref; /* Referencing offset */ }; /* kprobe-tracer tracing event (point + arg) */ -struct kprobe_trace_event { +struct probe_trace_event { char *event; /* Event name */ char *group; /* Group name */ - struct kprobe_trace_point point; /* Trace point */ + struct probe_trace_point point; /* Trace point */ int nargs; /* Number of args */ - struct kprobe_trace_arg *args; /* Arguments */ + struct probe_trace_arg *args; /* Arguments */ }; /* Perf probe probing point */ @@ -93,25 +93,18 @@ struct line_range { /* Command string to events */ extern int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev); -extern int parse_kprobe_trace_command(const char *cmd, - struct kprobe_trace_event *tev); /* Events to command string */ extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); -extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev); +extern char *synthesize_probe_trace_command(struct probe_trace_event *tev); extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len); /* Check the perf_probe_event needs debuginfo */ extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); -/* Convert from kprobe_trace_event to perf_probe_event */ -extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev, - struct perf_probe_event *pev); - /* Release event contents */ extern void clear_perf_probe_event(struct perf_probe_event *pev); -extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev); /* Command string to line-range */ extern int parse_line_range_desc(const char *cmd, struct line_range *lr); diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index f88070ea5b9..840f1aabbb7 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -366,10 +366,10 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, * Probe finder related functions */ -static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs) +static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) { - struct kprobe_trace_arg_ref *ref; - ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); + struct probe_trace_arg_ref *ref; + ref = zalloc(sizeof(struct probe_trace_arg_ref)); if (ref != NULL) ref->offset = offs; return ref; @@ -385,7 +385,7 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) Dwarf_Word offs = 0; bool ref = false; const char *regs; - struct kprobe_trace_arg *tvar = pf->tvar; + struct probe_trace_arg *tvar = pf->tvar; int ret; /* TODO: handle more than 1 exprs */ @@ -459,10 +459,10 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) } static int convert_variable_type(Dwarf_Die *vr_die, - struct kprobe_trace_arg *tvar, + struct probe_trace_arg *tvar, const char *cast) { - struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref; + struct probe_trace_arg_ref **ref_ptr = &tvar->ref; Dwarf_Die type; char buf[16]; int ret; @@ -500,7 +500,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, while (*ref_ptr) ref_ptr = &(*ref_ptr)->next; /* Add new reference with offset +0 */ - *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref)); + *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); if (*ref_ptr == NULL) { pr_warning("Out of memory error\n"); return -ENOMEM; @@ -545,10 +545,10 @@ static int convert_variable_type(Dwarf_Die *vr_die, static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, struct perf_probe_arg_field *field, - struct kprobe_trace_arg_ref **ref_ptr, + struct probe_trace_arg_ref **ref_ptr, Dwarf_Die *die_mem) { - struct kprobe_trace_arg_ref *ref = *ref_ptr; + struct probe_trace_arg_ref *ref = *ref_ptr; Dwarf_Die type; Dwarf_Word offs; int ret, tag; @@ -574,7 +574,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, pr_debug2("Array real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); if (tag == DW_TAG_pointer_type) { - ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); + ref = zalloc(sizeof(struct probe_trace_arg_ref)); if (ref == NULL) return -ENOMEM; if (*ref_ptr) @@ -605,7 +605,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, return -EINVAL; } - ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); + ref = zalloc(sizeof(struct probe_trace_arg_ref)); if (ref == NULL) return -ENOMEM; if (*ref_ptr) @@ -738,7 +738,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) /* Show a probe point to output buffer */ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) { - struct kprobe_trace_event *tev; + struct probe_trace_event *tev; Dwarf_Addr eaddr; Dwarf_Die die_mem; const char *name; @@ -803,7 +803,7 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) /* Find each argument */ tev->nargs = pf->pev->nargs; - tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); + tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); if (tev->args == NULL) return -ENOMEM; for (i = 0; i < pf->pev->nargs; i++) { @@ -1060,9 +1060,9 @@ static int find_probe_point_by_func(struct probe_finder *pf) return _param.retval; } -/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ -int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, - struct kprobe_trace_event **tevs, int max_tevs) +/* Find probe_trace_events specified by perf_probe_event from debuginfo */ +int find_probe_trace_events(int fd, struct perf_probe_event *pev, + struct probe_trace_event **tevs, int max_tevs) { struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; struct perf_probe_point *pp = &pev->point; @@ -1072,7 +1072,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, Dwarf *dbg; int ret = 0; - pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * max_tevs); + pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); if (pf.tevs == NULL) return -ENOMEM; *tevs = pf.tevs; diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index e1f61dcd18f..4507d519f18 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -16,9 +16,9 @@ static inline int is_c_varname(const char *name) } #ifdef DWARF_SUPPORT -/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ -extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, - struct kprobe_trace_event **tevs, +/* Find probe_trace_events specified by perf_probe_event from debuginfo */ +extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, + struct probe_trace_event **tevs, int max_tevs); /* Find a perf_probe_point from debuginfo */ @@ -33,7 +33,7 @@ extern int find_line_range(int fd, struct line_range *lr); struct probe_finder { struct perf_probe_event *pev; /* Target probe event */ - struct kprobe_trace_event *tevs; /* Result trace events */ + struct probe_trace_event *tevs; /* Result trace events */ int ntevs; /* Number of trace events */ int max_tevs; /* Max number of trace events */ @@ -50,7 +50,7 @@ struct probe_finder { #endif Dwarf_Op *fb_ops; /* Frame base attribute */ struct perf_probe_arg *pvar; /* Current target variable */ - struct kprobe_trace_arg *tvar; /* Current result variable */ + struct probe_trace_arg *tvar; /* Current result variable */ }; struct line_finder { -- cgit v1.2.3-70-g09d2