2011-04-06 11:00:36

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [GIT PULL 0/5] perf/urgent fixes

Hi Ingo,

Please consider pulling from:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 perf/urgent

Regards,

- Arnaldo


Masami Hiramatsu (5):
perf probe: Fix to ensure function declared file
perf probe: Fix to remove redundant close
perf probe: Fix multiple --vars options behavior
perf probe: Fix to find recursively inlined function
perf probe: Fix listing incorrect line number with inline function

tools/perf/util/probe-event.c | 19 ++---
tools/perf/util/probe-finder.c | 159 ++++++++++++++++++++++++++--------------
2 files changed, 113 insertions(+), 65 deletions(-)


2011-04-06 11:00:35

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 1/5] perf probe: Fix to ensure function declared file

From: Masami Hiramatsu <[email protected]>

Fix to ensure function declared file matches given file name. This fixes
a potential bug.

As I've commented on Lin Ming's fastpath enhancement, decl_file should
be checked on each probe point if user gives a probe point as func@file.

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

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 194f9e2..3bcd140 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1395,6 +1395,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
!die_compare_name(sp_die, pp->function))
return DWARF_CB_OK;

+ /* Check declared file */
+ if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die)))
+ return DWARF_CB_OK;
+
pf->fname = dwarf_decl_file(sp_die);
if (pp->line) { /* Function relative line */
dwarf_decl_line(sp_die, &pf->lno);
@@ -1840,6 +1844,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
struct line_finder *lf = param->data;
struct line_range *lr = lf->lr;

+ /* Check declared file */
+ if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die)))
+ return DWARF_CB_OK;
+
if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
die_compare_name(sp_die, lr->function)) {
lf->fname = dwarf_decl_file(sp_die);
--
1.6.2.5

2011-04-06 11:00:53

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 2/5] perf probe: Fix to remove redundant close

From: Masami Hiramatsu <[email protected]>

Since dwfl_end() closes given fd with dwfl, caller doesn't need to close its fd
when finishing process.

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

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 5ddee66..a372d74 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -234,7 +234,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,

/* Searching trace events corresponding to probe event */
ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
- close(fd);

if (ntevs > 0) { /* Succeeded to find trace events */
pr_debug("find %d probe_trace_events.\n", ntevs);
@@ -388,7 +387,6 @@ int show_line_range(struct line_range *lr, const char *module)
}

ret = find_line_range(fd, lr);
- close(fd);
if (ret == 0) {
pr_warning("Specified source line is not found.\n");
return -ENOENT;
@@ -524,7 +522,6 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
externs);

- close(fd);
return ret;
}

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3bcd140..5473f11 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1455,6 +1455,7 @@ static int find_probes(int fd, struct probe_finder *pf)
if (!dbg) {
pr_warning("No debug information found in the vmlinux - "
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
+ close(fd); /* Without dwfl_end(), fd isn't closed. */
return -EBADF;
}

@@ -1900,6 +1901,7 @@ int find_line_range(int fd, struct line_range *lr)
if (!dbg) {
pr_warning("No debug information found in the vmlinux - "
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
+ close(fd); /* Without dwfl_end(), fd isn't closed. */
return -EBADF;
}

--
1.6.2.5

2011-04-06 11:00:51

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 5/5] perf probe: Fix listing incorrect line number with inline function

From: Masami Hiramatsu <[email protected]>

Fix a bug showing incorrect line number when a probe is put on the head of an
inline function. This patch updates find_perf_probe_point() and introduces new
rules to get correct line number.

- If debuginfo doesn't have a correct file name, we shouldn't return line
number too, because, without file name, line number is meaningless.

- If the address is in a function, it stores the function name and the offset
from the function entry.

- If the address is on a line, it tries to get the relative line number from
the function entry line, except for the address is same as the entry
address of the function (in this case, the relative line number should
be 0).

- If the address is in an inline function entry (call-site), it uses the
inline function call line number as the line on which the address is.

- If the address is in an inline function body, it stores the inline
function name and offset from the inline function call site instead of the
(non-inlined) function.

Cc: [email protected]
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Lin Ming <[email protected]>
Cc: Peter Zijlstra <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Masami Hiramatsu <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/probe-finder.c | 134 ++++++++++++++++++++++++----------------
1 files changed, 81 insertions(+), 53 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 689ab46..b7c85ce 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -273,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
return dwarf_formstring(&attr);
}

+/* Get a line number and file name for given address */
+static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
+ const char **fname, int *lineno)
+{
+ Dwarf_Line *line;
+ Dwarf_Addr laddr;
+
+ line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr);
+ if (line && dwarf_lineaddr(line, &laddr) == 0 &&
+ addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
+ *fname = dwarf_linesrc(line, NULL, NULL);
+ if (!*fname)
+ /* line number is useless without filename */
+ *lineno = 0;
+ }
+
+ return *lineno ?: -ENOENT;
+}
+
/* Compare diename and tname */
static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
{
@@ -1704,11 +1723,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
Dwarf_Die cudie, spdie, indie;
Dwarf *dbg = NULL;
Dwfl *dwfl = NULL;
- Dwarf_Line *line;
- Dwarf_Addr laddr, eaddr, bias = 0;
- const char *tmp;
- int lineno, ret = 0;
- bool found = false;
+ Dwarf_Addr _addr, baseaddr, bias = 0;
+ const char *fname = NULL, *func = NULL, *tmp;
+ int baseline = 0, lineno = 0, ret = 0;

/* Open the live linux kernel */
dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
@@ -1729,68 +1746,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
goto end;
}

- /* Find a corresponding line */
- line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
- if (line) {
- if (dwarf_lineaddr(line, &laddr) == 0 &&
- (Dwarf_Addr)addr == laddr &&
- dwarf_lineno(line, &lineno) == 0) {
- tmp = dwarf_linesrc(line, NULL, NULL);
- if (tmp) {
- ppt->line = lineno;
- ppt->file = strdup(tmp);
- if (ppt->file == NULL) {
- ret = -ENOMEM;
- goto end;
- }
- found = true;
- }
- }
- }
+ /* Find a corresponding line (filename and lineno) */
+ cu_find_lineinfo(&cudie, addr, &fname, &lineno);
+ /* Don't care whether it failed or not */

- /* Find a corresponding function */
+ /* Find a corresponding function (name, baseline and baseaddr) */
if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
+ /* Get function entry information */
tmp = dwarf_diename(&spdie);
- if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
- goto end;
-
- if (ppt->line) {
- if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
- &indie)) {
- /* addr in an inline function */
+ if (!tmp ||
+ dwarf_entrypc(&spdie, &baseaddr) != 0 ||
+ dwarf_decl_line(&spdie, &baseline) != 0)
+ goto post;
+ func = tmp;
+
+ if (addr == (unsigned long)baseaddr)
+ /* Function entry - Relative line number is 0 */
+ lineno = baseline;
+ else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
+ &indie)) {
+ if (dwarf_entrypc(&indie, &_addr) == 0 &&
+ _addr == addr)
+ /*
+ * addr is at an inline function entry.
+ * In this case, lineno should be the call-site
+ * line number.
+ */
+ lineno = die_get_call_lineno(&indie);
+ else {
+ /*
+ * addr is in an inline function body.
+ * Since lineno points one of the lines
+ * of the inline function, baseline should
+ * be the entry line of the inline function.
+ */
tmp = dwarf_diename(&indie);
- if (!tmp)
- goto end;
- ret = dwarf_decl_line(&indie, &lineno);
- } else {
- if (eaddr == addr) { /* Function entry */
- lineno = ppt->line;
- ret = 0;
- } else
- ret = dwarf_decl_line(&spdie, &lineno);
- }
- if (ret == 0) {
- /* Make a relative line number */
- ppt->line -= lineno;
- goto found;
+ if (tmp &&
+ dwarf_decl_line(&spdie, &baseline) == 0)
+ func = tmp;
}
}
- /* We don't have a line number, let's use offset */
- ppt->offset = addr - (unsigned long)eaddr;
-found:
- ppt->function = strdup(tmp);
+ }
+
+post:
+ /* Make a relative line number or an offset */
+ if (lineno)
+ ppt->line = lineno - baseline;
+ else if (func)
+ ppt->offset = addr - (unsigned long)baseaddr;
+
+ /* Duplicate strings */
+ if (func) {
+ ppt->function = strdup(func);
if (ppt->function == NULL) {
ret = -ENOMEM;
goto end;
}
- found = true;
}
-
+ if (fname) {
+ ppt->file = strdup(fname);
+ if (ppt->file == NULL) {
+ if (ppt->function) {
+ free(ppt->function);
+ ppt->function = NULL;
+ }
+ ret = -ENOMEM;
+ goto end;
+ }
+ }
end:
if (dwfl)
dwfl_end(dwfl);
- if (ret >= 0)
- ret = found ? 1 : 0;
+ if (ret == 0 && (fname || func))
+ ret = 1; /* Found a point */
return ret;
}

--
1.6.2.5

2011-04-06 11:01:41

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 3/5] perf probe: Fix multiple --vars options behavior

From: Masami Hiramatsu <[email protected]>

Fix a bug that perf-probe fails to initialize libdwfl and shows incorrect error
when user gives multiple --vars options.

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

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a372d74..f022316 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -510,18 +510,18 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
if (ret < 0)
return ret;

- fd = open_vmlinux(module);
- if (fd < 0) {
- pr_warning("Failed to open debug information file.\n");
- return fd;
- }
-
setup_pager();

- for (i = 0; i < npevs && ret >= 0; i++)
+ for (i = 0; i < npevs && ret >= 0; i++) {
+ fd = open_vmlinux(module);
+ if (fd < 0) {
+ pr_warning("Failed to open debug information file.\n");
+ ret = fd;
+ break;
+ }
ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
externs);
-
+ }
return ret;
}

--
1.6.2.5

2011-04-06 11:01:40

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 4/5] perf probe: Fix to find recursively inlined function

From: Masami Hiramatsu <[email protected]>

Fix die_find_inlinefunc() to return correct innermost inlined function
at given address. Without this fix, it returns the outermost inlined
function.

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

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 5473f11..689ab46 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -497,7 +497,20 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
Dwarf_Die *die_mem)
{
- return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
+ Dwarf_Die tmp_die;
+
+ sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
+ if (!sp_die)
+ return NULL;
+
+ /* Inlined function could be recursive. Trace it until fail */
+ while (sp_die) {
+ memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
+ sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
+ &tmp_die);
+ }
+
+ return die_mem;
}

/* Walker on lines (Note: line number will not be sorted) */
--
1.6.2.5

2011-04-06 11:11:10

by Ingo Molnar

[permalink] [raw]
Subject: Re: [GIT PULL 0/5] perf/urgent fixes


* Arnaldo Carvalho de Melo <[email protected]> wrote:

> Hi Ingo,
>
> Please consider pulling from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 perf/urgent
>
> Regards,
>
> - Arnaldo
>
>
> Masami Hiramatsu (5):
> perf probe: Fix to ensure function declared file
> perf probe: Fix to remove redundant close
> perf probe: Fix multiple --vars options behavior
> perf probe: Fix to find recursively inlined function
> perf probe: Fix listing incorrect line number with inline function
>
> tools/perf/util/probe-event.c | 19 ++---
> tools/perf/util/probe-finder.c | 159 ++++++++++++++++++++++++++--------------
> 2 files changed, 113 insertions(+), 65 deletions(-)

Pulled, thanks a lot Arnaldo!

Ingo