2010-04-14 22:32:44

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 0/6] perf-probe bugfixes

Hi Arnaldo,

(Sorry, I've fixed to signed-off-by and send it again)
Could you pull these patches into your tree too?
These fixes several bugs on perf probe.

Thank you,

---

Masami Hiramatsu (6):
perf probe: Show function entry line as probe-able
perf probe: Support DW_OP_plus_uconst in DW_AT_data_member_location
perf probe: Fix line range to show end line
perf probe: Fix a bug that --line range can be overflow
perf probe: Fix mis-estimation for shortening filename
perf probe: Fix to use correct debugfs path finder


tools/perf/builtin-probe.c | 4 -
tools/perf/util/probe-event.c | 51 ++++++++++------
tools/perf/util/probe-event.h | 6 +-
tools/perf/util/probe-finder.c | 128 ++++++++++++++++++++++++++++++++--------
4 files changed, 139 insertions(+), 50 deletions(-)

--
Masami Hiramatsu
e-mail: [email protected]


2010-04-14 22:32:54

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 1/6] perf probe: Fix to use correct debugfs path finder

Instead of using debugfs_path, use debugfs_find_mountpoint()
to find actual debugfs path.

Signed-off-by: Masami Hiramatsu <[email protected]>
Reported-by: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
---

tools/perf/builtin-probe.c | 4 ----
tools/perf/util/probe-event.c | 12 ++++++++++--
2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 5259c5a..4b6dd84 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -40,7 +40,6 @@
#include "util/debug.h"
#include "util/debugfs.h"
#include "util/parse-options.h"
-#include "util/parse-events.h" /* For debugfs_path */
#include "util/probe-finder.h"
#include "util/probe-event.h"

@@ -205,9 +204,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
!params.show_lines))
usage_with_options(probe_usage, options);

- if (debugfs_valid_mountpoint(debugfs_path) < 0)
- die("Failed to find debugfs path.");
-
if (params.list_events) {
if (params.nevents != 0 || params.dellist) {
pr_err(" Error: Don't use --list with --add/--del.\n");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ca108b2..1c4a20a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -42,8 +42,8 @@
#include "color.h"
#include "symbol.h"
#include "thread.h"
+#include "debugfs.h"
#include "trace-event.h" /* For __unused */
-#include "parse-events.h" /* For debugfs_path */
#include "probe-event.h"
#include "probe-finder.h"

@@ -1075,10 +1075,18 @@ void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
static int open_kprobe_events(bool readwrite)
{
char buf[PATH_MAX];
+ const char *__debugfs;
int ret;

- ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
+ __debugfs = debugfs_find_mountpoint();
+ if (__debugfs == NULL) {
+ pr_warning("Debugfs is not mounted.\n");
+ return -ENOENT;
+ }
+
+ ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
if (ret >= 0) {
+ pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run)
ret = open(buf, O_RDWR, O_APPEND);
else


--
Masami Hiramatsu
e-mail: [email protected]

2010-04-14 22:33:01

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 2/6] perf probe: Fix mis-estimation for shortening filename

Fix mis-estimation size for making a short filename.
Since the buffer size is 32 bytes and there are '@' prefix and
'\0' termination, maximum shorten filename length should be
30. This means, before searching '/', it should be 31 bytes.

Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
---

tools/perf/util/probe-event.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1c4a20a..6d43839 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -806,12 +806,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
goto error;
}
if (pp->file) {
- len = strlen(pp->file) - 32;
+ len = strlen(pp->file) - 31;
if (len < 0)
len = 0;
tmp = strchr(pp->file + len, '/');
if (!tmp)
- tmp = pp->file + len - 1;
+ tmp = pp->file + len;
ret = e_snprintf(file, 32, "@%s", tmp + 1);
if (ret <= 0)
goto error;


--
Masami Hiramatsu
e-mail: [email protected]

2010-04-14 22:33:15

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 3/6] perf probe: Fix a bug that --line range can be overflow

Since line_finder.lno_s/e are signed int but line_range.start/end
are unsigned int, it is possible to be overflow when converting
line_range->start/end to line_finder->lno_s/e.
This changes line_range.start/end and line_list.line to signed int
and adds overflow checks when setting line_finder.lno_s/e.

Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
---

tools/perf/util/probe-event.c | 23 ++++++++++++-----------
tools/perf/util/probe-event.h | 6 +++---
tools/perf/util/probe-finder.c | 19 +++++++++----------
3 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6d43839..954ca21 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -189,7 +189,7 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
#define LINEBUF_SIZE 256
#define NR_ADDITIONAL_LINES 2

-static int show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
+static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
{
char buf[LINEBUF_SIZE];
const char *color = PERF_COLOR_BLUE;
@@ -198,7 +198,7 @@ static int show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
goto error;
if (!skip) {
if (show_num)
- fprintf(stdout, "%7u %s", l, buf);
+ fprintf(stdout, "%7d %s", l, buf);
else
color_fprintf(stdout, color, " %s", buf);
}
@@ -231,7 +231,7 @@ error:
*/
int show_line_range(struct line_range *lr)
{
- unsigned int l = 1;
+ int l = 1;
struct line_node *ln;
FILE *fp;
int fd, ret;
@@ -340,16 +340,15 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
*/
ptr = strchr(arg, ':');
if (ptr) {
- lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
+ lr->start = (int)strtoul(ptr + 1, &tmp, 0);
if (*tmp == '+')
- lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
- &tmp, 0);
+ lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
else if (*tmp == '-')
- lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
+ lr->end = (int)strtoul(tmp + 1, &tmp, 0);
else
- lr->end = 0;
- pr_debug("Line range is %u to %u\n", lr->start, lr->end);
- if (lr->end && lr->start > lr->end) {
+ lr->end = INT_MAX;
+ pr_debug("Line range is %d to %d\n", lr->start, lr->end);
+ if (lr->start > lr->end) {
semantic_error("Start line must be smaller"
" than end line.\n");
return -EINVAL;
@@ -360,8 +359,10 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
return -EINVAL;
}
tmp = strndup(arg, (ptr - arg));
- } else
+ } else {
tmp = strdup(arg);
+ lr->end = INT_MAX;
+ }

if (tmp == NULL)
return -ENOMEM;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index aee60e1..f0831bc 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -74,15 +74,15 @@ struct perf_probe_event {
/* Line number container */
struct line_node {
struct list_head list;
- unsigned int line;
+ int line;
};

/* Line range */
struct line_range {
char *file; /* File name */
char *function; /* Function name */
- unsigned int start; /* Start line number */
- unsigned int end; /* End line number */
+ int start; /* Start line number */
+ int end; /* End line number */
int offset; /* Start line offset */
char *path; /* Real path name */
struct list_head line_list; /* Visible lines */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e443e69..b4c9365 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -111,7 +111,7 @@ static int strtailcmp(const char *s1, const char *s2)
/* Line number list operations */

/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, unsigned int line)
+static int line_list__add_line(struct list_head *head, int line)
{
struct line_node *ln;
struct list_head *p;
@@ -138,7 +138,7 @@ found:
}

/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, unsigned int line)
+static int line_list__has_line(struct list_head *head, int line)
{
struct line_node *ln;

@@ -1146,7 +1146,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
if (lf->lr->path == NULL)
return -ENOMEM;
}
- line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
+ line_list__add_line(&lf->lr->line_list, lineno);
}
/* Update status */
if (!list_empty(&lf->lr->line_list))
@@ -1179,10 +1179,12 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
dwarf_decl_line(sp_die, &lr->offset);
pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
lf->lno_s = lr->offset + lr->start;
- if (!lr->end)
+ if (lf->lno_s < 0) /* Overflow */
+ lf->lno_s = INT_MAX;
+ lf->lno_e = lr->offset + lr->end;
+ if (lf->lno_e < 0) /* Overflow */
lf->lno_e = INT_MAX;
- else
- lf->lno_e = lr->offset + lr->end;
+ pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
lr->start = lf->lno_s;
lr->end = lf->lno_e;
if (dwarf_func_inline(sp_die)) {
@@ -1244,10 +1246,7 @@ int find_line_range(int fd, struct line_range *lr)
ret = find_line_range_by_func(&lf);
else {
lf.lno_s = lr->start;
- if (!lr->end)
- lf.lno_e = INT_MAX;
- else
- lf.lno_e = lr->end;
+ lf.lno_e = lr->end;
ret = find_line_range_by_line(NULL, &lf);
}
}


--
Masami Hiramatsu
e-mail: [email protected]

2010-04-14 22:33:23

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 4/6] perf probe: Fix line range to show end line

Line range should reject the range if the number of lines is 0
(e.g. "sched.c:1024+0"), and it should show the lines include
the end of line number (e.g. "sched.c:1024-2048" should show
2048th line).

Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
---

tools/perf/util/probe-event.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 954ca21..5bf8ab0 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -290,7 +290,7 @@ int show_line_range(struct line_range *lr)

if (lr->end == INT_MAX)
lr->end = l + NR_ADDITIONAL_LINES;
- while (l < lr->end && !feof(fp) && ret >= 0)
+ while (l <= lr->end && !feof(fp) && ret >= 0)
ret = show_one_line(fp, (l++) - lr->offset, false, false);
end:
fclose(fp);
@@ -341,9 +341,15 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
ptr = strchr(arg, ':');
if (ptr) {
lr->start = (int)strtoul(ptr + 1, &tmp, 0);
- if (*tmp == '+')
+ if (*tmp == '+') {
lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
- else if (*tmp == '-')
+ lr->end--; /*
+ * Adjust the number of lines here.
+ * If the number of lines == 1, the
+ * the end of line should be equal to
+ * the start of line.
+ */
+ } else if (*tmp == '-')
lr->end = (int)strtoul(tmp + 1, &tmp, 0);
else
lr->end = INT_MAX;


--
Masami Hiramatsu
e-mail: [email protected]

2010-04-14 22:33:28

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 5/6] perf probe: Support DW_OP_plus_uconst in DW_AT_data_member_location

DW_OP_plus_uconst can be used for DW_AT_data_member_location.
This patch adds DW_OP_plus_uconst support when getting
structure member offset.

Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
---

tools/perf/util/probe-finder.c | 37 ++++++++++++++++++++++++++++++++-----
1 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index b4c9365..4f83121 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -249,6 +249,33 @@ static int die_get_byte_size(Dwarf_Die *tp_die)
return (int)ret;
}

+/* Get data_member_location offset */
+static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Op *expr;
+ size_t nexpr;
+ int ret;
+
+ if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
+ return -ENOENT;
+
+ if (dwarf_formudata(&attr, offs) != 0) {
+ /* DW_AT_data_member_location should be DW_OP_plus_uconst */
+ ret = dwarf_getlocation(&attr, &expr, &nexpr);
+ if (ret < 0 || nexpr == 0)
+ return -ENOENT;
+
+ if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
+ pr_debug("Unable to get offset:Unexpected OP %x (%d)\n",
+ expr[0].atom, nexpr);
+ return -ENOTSUP;
+ }
+ *offs = (Dwarf_Word)expr[0].number;
+ }
+ return 0;
+}
+
/* Return values for die_find callbacks */
enum {
DIE_FIND_CB_FOUND = 0, /* End of Search */
@@ -482,9 +509,9 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
Dwarf_Die *die_mem)
{
struct kprobe_trace_arg_ref *ref = *ref_ptr;
- Dwarf_Attribute attr;
Dwarf_Die type;
Dwarf_Word offs;
+ int ret;

pr_debug("converting %s in %s\n", field->name, varname);
if (die_get_real_type(vr_die, &type) == NULL) {
@@ -542,17 +569,17 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
}

/* Get the offset of the field */
- if (dwarf_attr(die_mem, DW_AT_data_member_location, &attr) == NULL ||
- dwarf_formudata(&attr, &offs) != 0) {
+ ret = die_get_data_member_location(die_mem, &offs);
+ if (ret < 0) {
pr_warning("Failed to get the offset of %s.\n", field->name);
- return -ENOENT;
+ return ret;
}
ref->offset += (long)offs;

/* Converting next field */
if (field->next)
return convert_variable_fields(die_mem, field->name,
- field->next, &ref, die_mem);
+ field->next, &ref, die_mem);
else
return 0;
}


--
Masami Hiramatsu
e-mail: [email protected]

2010-04-14 22:33:35

by Masami Hiramatsu

[permalink] [raw]
Subject: [PATCH -tip 6/6] perf probe: Show function entry line as probe-able

Function entry line should be shown as probe-able line,
because each function has declared line attribute.

Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
---

tools/perf/util/probe-finder.c | 74 ++++++++++++++++++++++++++++++++++------
1 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4f83121..aff8a04 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1127,6 +1127,45 @@ end:
return ret;
}

+/* Add a line and store the src path */
+static int line_range_add_line(const char *src, unsigned int lineno,
+ struct line_range *lr)
+{
+ /* Copy real path */
+ if (!lr->path) {
+ lr->path = strdup(src);
+ if (lr->path == NULL)
+ return -ENOMEM;
+ }
+ return line_list__add_line(&lr->line_list, lineno);
+}
+
+/* Search function declaration lines */
+static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
+{
+ struct dwarf_callback_param *param = data;
+ struct line_finder *lf = param->data;
+ const char *src;
+ int lineno;
+
+ src = dwarf_decl_file(sp_die);
+ if (src && strtailcmp(src, lf->fname) != 0)
+ return DWARF_CB_OK;
+
+ if (dwarf_decl_line(sp_die, &lineno) != 0 ||
+ (lf->lno_s > lineno || lf->lno_e < lineno))
+ return DWARF_CB_OK;
+
+ param->retval = line_range_add_line(src, lineno, lf->lr);
+ return DWARF_CB_OK;
+}
+
+static int find_line_range_func_decl_lines(struct line_finder *lf)
+{
+ struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
+ dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
+ return param.retval;
+}

/* Find line range from its line number */
static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
@@ -1135,7 +1174,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
Dwarf_Line *line;
size_t nlines, i;
Dwarf_Addr addr;
- int lineno;
+ int lineno, ret = 0;
const char *src;
Dwarf_Die die_mem;

@@ -1145,6 +1184,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
return -ENOENT;
}

+ /* Search probable lines on lines list */
for (i = 0; i < nlines; i++) {
line = dwarf_onesrcline(lines, i);
if (dwarf_lineno(line, &lineno) != 0 ||
@@ -1167,22 +1207,34 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
if (strtailcmp(src, lf->fname) != 0)
continue;

- /* Copy real path */
- if (!lf->lr->path) {
- lf->lr->path = strdup(src);
- if (lf->lr->path == NULL)
- return -ENOMEM;
- }
- line_list__add_line(&lf->lr->line_list, lineno);
+ ret = line_range_add_line(src, lineno, lf->lr);
+ if (ret < 0)
+ return ret;
}
+
+ /*
+ * Dwarf lines doesn't include function declarations. We have to
+ * check functions list or given function.
+ */
+ if (sp_die) {
+ src = dwarf_decl_file(sp_die);
+ if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
+ (lf->lno_s <= lineno && lf->lno_e >= lineno))
+ ret = line_range_add_line(src, lineno, lf->lr);
+ } else
+ ret = find_line_range_func_decl_lines(lf);
+
/* Update status */
- if (!list_empty(&lf->lr->line_list))
- lf->found = 1;
+ if (ret >= 0)
+ if (!list_empty(&lf->lr->line_list))
+ ret = lf->found = 1;
+ else
+ ret = 0; /* Lines are not found */
else {
free(lf->lr->path);
lf->lr->path = NULL;
}
- return lf->found;
+ return ret;
}

static int line_range_inline_cb(Dwarf_Die *in_die, void *data)


--
Masami Hiramatsu
e-mail: [email protected]

2010-04-14 23:29:18

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH -tip 0/6] perf-probe bugfixes

Em Wed, Apr 14, 2010 at 06:39:21PM -0400, Masami Hiramatsu escreveu:
> Hi Arnaldo,
>
> (Sorry, I've fixed to signed-off-by and send it again)
> Could you pull these patches into your tree too?
> These fixes several bugs on perf probe.
>
> Thank you,

Sure, I just applied your previous series and will now review this new
one and merge it after that.

2010-04-15 07:31:17

by Masami Hiramatsu

[permalink] [raw]
Subject: [tip:perf/core] perf probe: Fix to use correct debugfs path finder

Commit-ID: 7ca5989dd065cbc48a958666c273794686ea7525
Gitweb: http://git.kernel.org/tip/7ca5989dd065cbc48a958666c273794686ea7525
Author: Masami Hiramatsu <[email protected]>
AuthorDate: Wed, 14 Apr 2010 18:39:28 -0400
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 14 Apr 2010 17:41:06 -0300

perf probe: Fix to use correct debugfs path finder

Instead of using debugfs_path, use debugfs_find_mountpoint()
to find actual debugfs path.

LKML-Reference: <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Reported-by: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-probe.c | 4 ----
tools/perf/util/probe-event.c | 12 ++++++++++--
2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 64bc11a..c1e5403 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -40,7 +40,6 @@
#include "util/debug.h"
#include "util/debugfs.h"
#include "util/parse-options.h"
-#include "util/parse-events.h" /* For debugfs_path */
#include "util/probe-finder.h"
#include "util/probe-event.h"

@@ -205,9 +204,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
!params.show_lines))
usage_with_options(probe_usage, options);

- if (debugfs_valid_mountpoint(debugfs_path) < 0)
- die("Failed to find debugfs path.");
-
if (params.list_events) {
if (params.nevents != 0 || params.dellist) {
pr_err(" Error: Don't use --list with --add/--del.\n");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ca108b2..1c4a20a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -42,8 +42,8 @@
#include "color.h"
#include "symbol.h"
#include "thread.h"
+#include "debugfs.h"
#include "trace-event.h" /* For __unused */
-#include "parse-events.h" /* For debugfs_path */
#include "probe-event.h"
#include "probe-finder.h"

@@ -1075,10 +1075,18 @@ void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
static int open_kprobe_events(bool readwrite)
{
char buf[PATH_MAX];
+ const char *__debugfs;
int ret;

- ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
+ __debugfs = debugfs_find_mountpoint();
+ if (__debugfs == NULL) {
+ pr_warning("Debugfs is not mounted.\n");
+ return -ENOENT;
+ }
+
+ ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
if (ret >= 0) {
+ pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run)
ret = open(buf, O_RDWR, O_APPEND);
else

2010-04-15 07:31:56

by Masami Hiramatsu

[permalink] [raw]
Subject: [tip:perf/core] perf probe: Fix mis-estimation for shortening filename

Commit-ID: dd259c5db26ccda46409dbf6efc79d5a2b259e38
Gitweb: http://git.kernel.org/tip/dd259c5db26ccda46409dbf6efc79d5a2b259e38
Author: Masami Hiramatsu <[email protected]>
AuthorDate: Wed, 14 Apr 2010 18:39:35 -0400
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 14 Apr 2010 17:41:14 -0300

perf probe: Fix mis-estimation for shortening filename

Fix mis-estimation size for making a short filename.
Since the buffer size is 32 bytes and there are '@' prefix and
'\0' termination, maximum shorten filename length should be
30. This means, before searching '/', it should be 31 bytes.

LKML-Reference: <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/probe-event.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1c4a20a..6d43839 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -806,12 +806,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
goto error;
}
if (pp->file) {
- len = strlen(pp->file) - 32;
+ len = strlen(pp->file) - 31;
if (len < 0)
len = 0;
tmp = strchr(pp->file + len, '/');
if (!tmp)
- tmp = pp->file + len - 1;
+ tmp = pp->file + len;
ret = e_snprintf(file, 32, "@%s", tmp + 1);
if (ret <= 0)
goto error;

2010-04-15 07:32:08

by Masami Hiramatsu

[permalink] [raw]
Subject: [tip:perf/core] perf probe: Fix line range to show end line

Commit-ID: dda4ab34fe1905d3d590572b776dd92aa0866558
Gitweb: http://git.kernel.org/tip/dda4ab34fe1905d3d590572b776dd92aa0866558
Author: Masami Hiramatsu <[email protected]>
AuthorDate: Wed, 14 Apr 2010 18:39:50 -0400
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 14 Apr 2010 17:41:30 -0300

perf probe: Fix line range to show end line

Line range should reject the range if the number of lines is 0
(e.g. "sched.c:1024+0"), and it should show the lines include
the end of line number (e.g. "sched.c:1024-2048" should show
2048th line).

LKML-Reference: <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/probe-event.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 954ca21..5bf8ab0 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -290,7 +290,7 @@ int show_line_range(struct line_range *lr)

if (lr->end == INT_MAX)
lr->end = l + NR_ADDITIONAL_LINES;
- while (l < lr->end && !feof(fp) && ret >= 0)
+ while (l <= lr->end && !feof(fp) && ret >= 0)
ret = show_one_line(fp, (l++) - lr->offset, false, false);
end:
fclose(fp);
@@ -341,9 +341,15 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
ptr = strchr(arg, ':');
if (ptr) {
lr->start = (int)strtoul(ptr + 1, &tmp, 0);
- if (*tmp == '+')
+ if (*tmp == '+') {
lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
- else if (*tmp == '-')
+ lr->end--; /*
+ * Adjust the number of lines here.
+ * If the number of lines == 1, the
+ * the end of line should be equal to
+ * the start of line.
+ */
+ } else if (*tmp == '-')
lr->end = (int)strtoul(tmp + 1, &tmp, 0);
else
lr->end = INT_MAX;

2010-04-15 07:31:53

by Masami Hiramatsu

[permalink] [raw]
Subject: [tip:perf/core] perf probe: Fix a bug that --line range can be overflow

Commit-ID: d3b63d7ae04879a817bac5c0bf09749f73629d32
Gitweb: http://git.kernel.org/tip/d3b63d7ae04879a817bac5c0bf09749f73629d32
Author: Masami Hiramatsu <[email protected]>
AuthorDate: Wed, 14 Apr 2010 18:39:42 -0400
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 14 Apr 2010 17:41:21 -0300

perf probe: Fix a bug that --line range can be overflow

Since line_finder.lno_s/e are signed int but line_range.start/end
are unsigned int, it is possible to be overflow when converting
line_range->start/end to line_finder->lno_s/e.
This changes line_range.start/end and line_list.line to signed int
and adds overflow checks when setting line_finder.lno_s/e.

LKML-Reference: <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/probe-event.c | 23 ++++++++++++-----------
tools/perf/util/probe-event.h | 6 +++---
tools/perf/util/probe-finder.c | 19 +++++++++----------
3 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 6d43839..954ca21 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -189,7 +189,7 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
#define LINEBUF_SIZE 256
#define NR_ADDITIONAL_LINES 2

-static int show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
+static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
{
char buf[LINEBUF_SIZE];
const char *color = PERF_COLOR_BLUE;
@@ -198,7 +198,7 @@ static int show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
goto error;
if (!skip) {
if (show_num)
- fprintf(stdout, "%7u %s", l, buf);
+ fprintf(stdout, "%7d %s", l, buf);
else
color_fprintf(stdout, color, " %s", buf);
}
@@ -231,7 +231,7 @@ error:
*/
int show_line_range(struct line_range *lr)
{
- unsigned int l = 1;
+ int l = 1;
struct line_node *ln;
FILE *fp;
int fd, ret;
@@ -340,16 +340,15 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
*/
ptr = strchr(arg, ':');
if (ptr) {
- lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
+ lr->start = (int)strtoul(ptr + 1, &tmp, 0);
if (*tmp == '+')
- lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
- &tmp, 0);
+ lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
else if (*tmp == '-')
- lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
+ lr->end = (int)strtoul(tmp + 1, &tmp, 0);
else
- lr->end = 0;
- pr_debug("Line range is %u to %u\n", lr->start, lr->end);
- if (lr->end && lr->start > lr->end) {
+ lr->end = INT_MAX;
+ pr_debug("Line range is %d to %d\n", lr->start, lr->end);
+ if (lr->start > lr->end) {
semantic_error("Start line must be smaller"
" than end line.\n");
return -EINVAL;
@@ -360,8 +359,10 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
return -EINVAL;
}
tmp = strndup(arg, (ptr - arg));
- } else
+ } else {
tmp = strdup(arg);
+ lr->end = INT_MAX;
+ }

if (tmp == NULL)
return -ENOMEM;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index ab54929..e7ff0d0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -74,15 +74,15 @@ struct perf_probe_event {
/* Line number container */
struct line_node {
struct list_head list;
- unsigned int line;
+ int line;
};

/* Line range */
struct line_range {
char *file; /* File name */
char *function; /* Function name */
- unsigned int start; /* Start line number */
- unsigned int end; /* End line number */
+ int start; /* Start line number */
+ int end; /* End line number */
int offset; /* Start line offset */
char *path; /* Real path name */
struct list_head line_list; /* Visible lines */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e443e69..b4c9365 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -111,7 +111,7 @@ static int strtailcmp(const char *s1, const char *s2)
/* Line number list operations */

/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, unsigned int line)
+static int line_list__add_line(struct list_head *head, int line)
{
struct line_node *ln;
struct list_head *p;
@@ -138,7 +138,7 @@ found:
}

/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, unsigned int line)
+static int line_list__has_line(struct list_head *head, int line)
{
struct line_node *ln;

@@ -1146,7 +1146,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
if (lf->lr->path == NULL)
return -ENOMEM;
}
- line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
+ line_list__add_line(&lf->lr->line_list, lineno);
}
/* Update status */
if (!list_empty(&lf->lr->line_list))
@@ -1179,10 +1179,12 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
dwarf_decl_line(sp_die, &lr->offset);
pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
lf->lno_s = lr->offset + lr->start;
- if (!lr->end)
+ if (lf->lno_s < 0) /* Overflow */
+ lf->lno_s = INT_MAX;
+ lf->lno_e = lr->offset + lr->end;
+ if (lf->lno_e < 0) /* Overflow */
lf->lno_e = INT_MAX;
- else
- lf->lno_e = lr->offset + lr->end;
+ pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
lr->start = lf->lno_s;
lr->end = lf->lno_e;
if (dwarf_func_inline(sp_die)) {
@@ -1244,10 +1246,7 @@ int find_line_range(int fd, struct line_range *lr)
ret = find_line_range_by_func(&lf);
else {
lf.lno_s = lr->start;
- if (!lr->end)
- lf.lno_e = INT_MAX;
- else
- lf.lno_e = lr->end;
+ lf.lno_e = lr->end;
ret = find_line_range_by_line(NULL, &lf);
}
}

2010-04-15 07:32:37

by Masami Hiramatsu

[permalink] [raw]
Subject: [tip:perf/core] perf probe: Show function entry line as probe-able

Commit-ID: f6c903f5856ffa75ae19dcee4dbb5093e320d45c
Gitweb: http://git.kernel.org/tip/f6c903f5856ffa75ae19dcee4dbb5093e320d45c
Author: Masami Hiramatsu <[email protected]>
AuthorDate: Wed, 14 Apr 2010 18:40:07 -0400
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 14 Apr 2010 17:45:39 -0300

perf probe: Show function entry line as probe-able

Function entry line should be shown as probe-able line,
because each function has declared line attribute.

LKML-Reference: <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/probe-finder.c | 74 ++++++++++++++++++++++++++++++++++------
1 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 03b4691..3e79775 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1127,6 +1127,45 @@ end:
return ret;
}

+/* Add a line and store the src path */
+static int line_range_add_line(const char *src, unsigned int lineno,
+ struct line_range *lr)
+{
+ /* Copy real path */
+ if (!lr->path) {
+ lr->path = strdup(src);
+ if (lr->path == NULL)
+ return -ENOMEM;
+ }
+ return line_list__add_line(&lr->line_list, lineno);
+}
+
+/* Search function declaration lines */
+static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
+{
+ struct dwarf_callback_param *param = data;
+ struct line_finder *lf = param->data;
+ const char *src;
+ int lineno;
+
+ src = dwarf_decl_file(sp_die);
+ if (src && strtailcmp(src, lf->fname) != 0)
+ return DWARF_CB_OK;
+
+ if (dwarf_decl_line(sp_die, &lineno) != 0 ||
+ (lf->lno_s > lineno || lf->lno_e < lineno))
+ return DWARF_CB_OK;
+
+ param->retval = line_range_add_line(src, lineno, lf->lr);
+ return DWARF_CB_OK;
+}
+
+static int find_line_range_func_decl_lines(struct line_finder *lf)
+{
+ struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
+ dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
+ return param.retval;
+}

/* Find line range from its line number */
static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
@@ -1135,7 +1174,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
Dwarf_Line *line;
size_t nlines, i;
Dwarf_Addr addr;
- int lineno;
+ int lineno, ret = 0;
const char *src;
Dwarf_Die die_mem;

@@ -1145,6 +1184,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
return -ENOENT;
}

+ /* Search probable lines on lines list */
for (i = 0; i < nlines; i++) {
line = dwarf_onesrcline(lines, i);
if (dwarf_lineno(line, &lineno) != 0 ||
@@ -1167,22 +1207,34 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
if (strtailcmp(src, lf->fname) != 0)
continue;

- /* Copy real path */
- if (!lf->lr->path) {
- lf->lr->path = strdup(src);
- if (lf->lr->path == NULL)
- return -ENOMEM;
- }
- line_list__add_line(&lf->lr->line_list, lineno);
+ ret = line_range_add_line(src, lineno, lf->lr);
+ if (ret < 0)
+ return ret;
}
+
+ /*
+ * Dwarf lines doesn't include function declarations. We have to
+ * check functions list or given function.
+ */
+ if (sp_die) {
+ src = dwarf_decl_file(sp_die);
+ if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
+ (lf->lno_s <= lineno && lf->lno_e >= lineno))
+ ret = line_range_add_line(src, lineno, lf->lr);
+ } else
+ ret = find_line_range_func_decl_lines(lf);
+
/* Update status */
- if (!list_empty(&lf->lr->line_list))
- lf->found = 1;
+ if (ret >= 0)
+ if (!list_empty(&lf->lr->line_list))
+ ret = lf->found = 1;
+ else
+ ret = 0; /* Lines are not found */
else {
free(lf->lr->path);
lf->lr->path = NULL;
}
- return lf->found;
+ return ret;
}

static int line_range_inline_cb(Dwarf_Die *in_die, void *data)