From: tip-bot for Masami Hiramatsu <mhiramat@redhat.com>
To: linux-tip-commits@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, paulus@samba.org, acme@redhat.com,
hpa@zytor.com, mingo@redhat.com, a.p.zijlstra@chello.nl,
efault@gmx.de, dle-develop@lists.sourceforge.net,
fweisbec@gmail.com, tglx@linutronix.de, mhiramat@redhat.com,
mingo@elte.hu, systemtap@sources.redhat.com
Subject: [tip:perf/core] perf probe: Add data structure member access support
Date: Wed, 17 Mar 2010 11:30:13 GMT [thread overview]
Message-ID: <tip-7df2f32956cf0f1a45df38cd0e0fe0c3467580e8@git.kernel.org> (raw)
In-Reply-To: <20100316220626.32050.57552.stgit@localhost6.localdomain6>
Commit-ID: 7df2f32956cf0f1a45df38cd0e0fe0c3467580e8
Gitweb: http://git.kernel.org/tip/7df2f32956cf0f1a45df38cd0e0fe0c3467580e8
Author: Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:06:26 -0400
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 12:11:15 +0100
perf probe: Add data structure member access support
Support accessing members in the data structures. With this,
perf-probe accepts data-structure members(IOW, it now accepts
dot '.' and arrow '->' operators) as probe arguemnts.
e.g.
./perf probe --add 'schedule:44 rq->curr'
./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
Note that '>' can be interpreted as redirection in command-line.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220626.32050.57552.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
tools/perf/util/probe-event.c | 90 ++++++++++++++++++++++++++++++++--
tools/perf/util/probe-event.h | 12 ++++-
tools/perf/util/probe-finder.c | 105 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 201 insertions(+), 6 deletions(-)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 4e3c1ae..64dea6c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -262,6 +262,49 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
pp->lazy_line);
}
+/* Parse perf-probe event argument */
+static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
+{
+ const char *tmp;
+ struct perf_probe_arg_field **fieldp;
+
+ pr_debug("parsing arg: %s into ", str);
+
+ tmp = strpbrk(str, "-.");
+ if (!is_c_varname(str) || !tmp) {
+ /* A variable, register, symbol or special value */
+ arg->name = xstrdup(str);
+ pr_debug("%s\n", arg->name);
+ return;
+ }
+
+ /* Structure fields */
+ arg->name = xstrndup(str, tmp - str);
+ pr_debug("%s, ", arg->name);
+ fieldp = &arg->field;
+
+ do {
+ *fieldp = xzalloc(sizeof(struct perf_probe_arg_field));
+ 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", str);
+
+ tmp = strpbrk(str, "-.");
+ if (tmp) {
+ (*fieldp)->name = xstrndup(str, tmp - str);
+ pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
+ fieldp = &(*fieldp)->next;
+ }
+ } while (tmp);
+ (*fieldp)->name = xstrdup(str);
+ pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
+}
+
/* Parse perf-probe event command */
void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
{
@@ -281,7 +324,7 @@ void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
pev->nargs = argc - 1;
pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
for (i = 0; i < pev->nargs; i++) {
- pev->args[i].name = xstrdup(argv[i + 1]);
+ parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
if (is_c_varname(pev->args[i].name) && pev->point.retprobe)
semantic_error("You can't specify local variable for"
" kretprobe");
@@ -353,6 +396,33 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
argv_free(argv);
}
+/* Compose only probe arg */
+int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
+{
+ struct perf_probe_arg_field *field = pa->field;
+ int ret;
+ char *tmp = buf;
+
+ ret = e_snprintf(tmp, len, "%s", pa->name);
+ if (ret <= 0)
+ goto error;
+ tmp += ret;
+ len -= ret;
+
+ while (field) {
+ ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
+ field->name);
+ if (ret <= 0)
+ goto error;
+ tmp += ret;
+ len -= ret;
+ field = field->next;
+ }
+ return tmp - buf;
+error:
+ die("Failed to synthesize perf probe argument: %s", strerror(-ret));
+}
+
/* Compose only probe point (not argument) */
static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
{
@@ -563,6 +633,7 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
void clear_perf_probe_event(struct perf_probe_event *pev)
{
struct perf_probe_point *pp = &pev->point;
+ struct perf_probe_arg_field *field, *next;
int i;
if (pev->event)
@@ -575,9 +646,18 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
free(pp->function);
if (pp->lazy_line)
free(pp->lazy_line);
- for (i = 0; i < pev->nargs; i++)
+ for (i = 0; i < pev->nargs; i++) {
if (pev->args[i].name)
free(pev->args[i].name);
+ field = pev->args[i].field;
+ while (field) {
+ next = field->next;
+ if (field->name)
+ free(field->name);
+ free(field);
+ field = next;
+ }
+ }
if (pev->args)
free(pev->args);
memset(pev, 0, sizeof(*pev));
@@ -682,8 +762,10 @@ static void show_perf_probe_event(struct perf_probe_event *pev)
if (pev->nargs > 0) {
printf(" with");
- for (i = 0; i < pev->nargs; i++)
- printf(" %s", pev->args[i].name);
+ for (i = 0; i < pev->nargs; i++) {
+ synthesize_perf_probe_arg(&pev->args[i], buf, 128);
+ printf(" %s", buf);
+ }
}
printf(")\n");
free(place);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 2a2f0a2..cd308b0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -45,9 +45,17 @@ struct perf_probe_point {
bool retprobe; /* Return probe flag */
};
+/* Perf probe probing argument field chain */
+struct perf_probe_arg_field {
+ struct perf_probe_arg_field *next; /* Next field */
+ char *name; /* Name of the field */
+ bool ref; /* Referencing flag */
+};
+
/* Perf probe probing argument */
struct perf_probe_arg {
- char *name; /* Argument name */
+ char *name; /* Argument name */
+ struct perf_probe_arg_field *field; /* Structure fields */
};
/* Perf probe probing event (point + arg) */
@@ -86,6 +94,8 @@ extern void parse_kprobe_trace_command(const char *cmd,
/* 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 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);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e02b607..db52ec2 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -206,6 +206,28 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
return epc;
}
+/* Get type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+ Dwarf_Attribute attr;
+ int tag;
+
+ do {
+ if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
+ dwarf_formref_die(&attr, die_mem) == NULL)
+ return NULL;
+
+ tag = dwarf_tag(die_mem);
+ vr_die = die_mem;
+ } while (tag == DW_TAG_const_type ||
+ tag == DW_TAG_restrict_type ||
+ tag == DW_TAG_volatile_type ||
+ tag == DW_TAG_shared_type ||
+ tag == DW_TAG_typedef);
+
+ return die_mem;
+}
+
/* Return values for die_find callbacks */
enum {
DIE_FIND_CB_FOUND = 0, /* End of Search */
@@ -314,6 +336,25 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
die_mem);
}
+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))
+ return DIE_FIND_CB_FOUND;
+
+ return DIE_FIND_CB_SIBLING;
+}
+
+/* Find a member called 'name' */
+static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
+ Dwarf_Die *die_mem)
+{
+ return die_find_child(st_die, __die_find_member_cb, (void *)name,
+ die_mem);
+}
+
/*
* Probe finder related functions
*/
@@ -363,6 +404,62 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
}
}
+static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
+ struct perf_probe_arg_field *field,
+ struct kprobe_trace_arg_ref **ref_ptr)
+{
+ struct kprobe_trace_arg_ref *ref = *ref_ptr;
+ Dwarf_Attribute attr;
+ Dwarf_Die member;
+ Dwarf_Die type;
+ Dwarf_Word offs;
+
+ pr_debug("converting %s in %s\n", field->name, varname);
+ if (die_get_real_type(vr_die, &type) == NULL)
+ die("Failed to get a type information of %s.", varname);
+
+ /* Check the pointer and dereference */
+ if (dwarf_tag(&type) == DW_TAG_pointer_type) {
+ if (!field->ref)
+ die("Semantic error: %s must be referred by '->'",
+ field->name);
+ /* Get the type pointed by this pointer */
+ if (die_get_real_type(&type, &type) == NULL)
+ die("Failed to get a type information of %s.", varname);
+
+ ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
+ if (*ref_ptr)
+ (*ref_ptr)->next = ref;
+ else
+ *ref_ptr = ref;
+ } else {
+ if (field->ref)
+ die("Semantic error: %s must be referred by '.'",
+ field->name);
+ if (!ref)
+ die("Structure on a register is not supported yet.");
+ }
+
+ /* Verify it is a data structure */
+ if (dwarf_tag(&type) != DW_TAG_structure_type)
+ die("%s is not a data structure.", varname);
+
+ if (die_find_member(&type, field->name, &member) == NULL)
+ die("%s(tyep:%s) has no member %s.", varname,
+ dwarf_diename(&type), field->name);
+
+ /* Get the offset of the field */
+ if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL ||
+ dwarf_formudata(&attr, &offs) != 0)
+ die("Failed to get the offset of %s.", field->name);
+ ref->offset += (long)offs;
+
+ /* Converting next field */
+ if (field->next)
+ convert_variable_fields(&member, field->name, field->next,
+ &ref);
+}
+
/* Show a variables in kprobe event format */
static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
{
@@ -379,6 +476,10 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
goto error;
convert_location(expr, pf);
+
+ if (pf->pvar->field)
+ convert_variable_fields(vr_die, pf->pvar->name,
+ pf->pvar->field, &pf->tvar->ref);
/* *expr will be cached in libdw. Don't free it. */
return ;
error:
@@ -391,13 +492,15 @@ error:
static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
{
Dwarf_Die vr_die;
+ char buf[128];
/* TODO: Support struct members and arrays */
if (!is_c_varname(pf->pvar->name)) {
/* Copy raw parameters */
pf->tvar->value = xstrdup(pf->pvar->name);
} else {
- pf->tvar->name = xstrdup(pf->pvar->name);
+ synthesize_perf_probe_arg(pf->pvar, buf, 128);
+ pf->tvar->name = xstrdup(buf);
pr_debug("Searching '%s' variable in context.\n",
pf->pvar->name);
/* Search child die for local variables and parameters. */
next prev parent reply other threads:[~2010-03-17 11:31 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory Masami Hiramatsu
2010-03-17 11:27 ` [tip:perf/core] perf tools: Introduce xzalloc() for detecting out of memory conditions tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 02/10] perf probe: Use wrapper functions Masami Hiramatsu
2010-03-17 11:27 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 03/10] perf probe: Move add-probe routine under util/ Masami Hiramatsu
2010-03-17 11:28 ` [tip:perf/core] perf probe: Move add-probe routine to util/ tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 04/10] perf probe: Rename session to param Masami Hiramatsu
2010-03-17 11:28 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 05/10] perf probe: Rename some die_get_* functions Masami Hiramatsu
2010-03-17 11:28 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 06/10] perf probe: Introduce die_find_child() function Masami Hiramatsu
2010-03-17 11:29 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 07/10] perf probe: Add --dry-run option Masami Hiramatsu
2010-03-17 11:29 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
2010-03-17 11:29 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-17 11:30 ` [tip:perf/core] perf probe: Fix !dwarf build tip-bot for Ingo Molnar
2010-03-17 14:14 ` Masami Hiramatsu
2010-03-18 17:38 ` [tip:perf/core] perf events: Fix false positive build warning with older GCC's tip-bot for Ingo Molnar
2010-03-18 20:03 ` Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 09/10] perf probe: List probes with line number and file name Masami Hiramatsu
2010-03-17 11:29 ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 10/10] perf probe: Accessing members in data structures Masami Hiramatsu
2010-03-17 10:25 ` Mark Wielaard
2010-03-17 19:14 ` Masami Hiramatsu
2010-03-18 3:28 ` Frederic Weisbecker
2010-03-20 4:20 ` Masami Hiramatsu
2010-03-23 15:55 ` Peter Zijlstra
2010-03-23 16:27 ` Arnaldo Carvalho de Melo
2010-03-17 11:30 ` tip-bot for Masami Hiramatsu [this message]
2010-03-17 10:34 ` [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Ingo Molnar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=tip-7df2f32956cf0f1a45df38cd0e0fe0c3467580e8@git.kernel.org \
--to=mhiramat@redhat.com \
--cc=a.p.zijlstra@chello.nl \
--cc=acme@redhat.com \
--cc=dle-develop@lists.sourceforge.net \
--cc=efault@gmx.de \
--cc=fweisbec@gmail.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tip-commits@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=mingo@redhat.com \
--cc=paulus@samba.org \
--cc=systemtap@sources.redhat.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.