Commit e592488c authored by Andi Kleen's avatar Andi Kleen Committed by Arnaldo Carvalho de Melo

perf annotate: Support source line numbers in annotate

With srcline key/sort'ing it's useful to have line numbers in the
annotate window. This patch implements this.

Use objdump -l to request the line numbers and save them in the line
structure. Then the browser displays them for source lines.

The line numbers are not displayed by default, but can be toggled on
with 'k'

There is one unfortunate problem with this setup. For lines not
containing source and which are outside functions objdump -l reports
line numbers off by a few: it always reports the first line number in
the next function even for lines that are outside the function.

I haven't found a nice way to detect/correct this. Probably objdump has
to be fixed.

See https://sourceware.org/bugzilla/show_bug.cgi?id=16433

The line numbers are still useful even with these problems, as most are
correct and the ones which are not are nearby.

v2: Fix help text. Handle (discriminator...) output in objdump.
Left align the line numbers.
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lkml.kernel.org/r/1415844328-4884-9-git-send-email-andi@firstfloor.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 2de21768
...@@ -27,6 +27,7 @@ static struct annotate_browser_opt { ...@@ -27,6 +27,7 @@ static struct annotate_browser_opt {
bool hide_src_code, bool hide_src_code,
use_offset, use_offset,
jump_arrows, jump_arrows,
show_linenr,
show_nr_jumps; show_nr_jumps;
} annotate_browser__opts = { } annotate_browser__opts = {
.use_offset = true, .use_offset = true,
...@@ -128,6 +129,10 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ...@@ -128,6 +129,10 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
if (!*dl->line) if (!*dl->line)
slsmg_write_nstring(" ", width - pcnt_width); slsmg_write_nstring(" ", width - pcnt_width);
else if (dl->offset == -1) { else if (dl->offset == -1) {
if (dl->line_nr && annotate_browser__opts.show_linenr)
printed = scnprintf(bf, sizeof(bf), "%-*d ",
ab->addr_width + 1, dl->line_nr);
else
printed = scnprintf(bf, sizeof(bf), "%*s ", printed = scnprintf(bf, sizeof(bf), "%*s ",
ab->addr_width, " "); ab->addr_width, " ");
slsmg_write_nstring(bf, printed); slsmg_write_nstring(bf, printed);
...@@ -733,6 +738,7 @@ static int annotate_browser__run(struct annotate_browser *browser, ...@@ -733,6 +738,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
"o Toggle disassembler output/simplified view\n" "o Toggle disassembler output/simplified view\n"
"s Toggle source code view\n" "s Toggle source code view\n"
"/ Search string\n" "/ Search string\n"
"k Toggle line numbers\n"
"r Run available scripts\n" "r Run available scripts\n"
"? Search string backwards\n"); "? Search string backwards\n");
continue; continue;
...@@ -741,6 +747,10 @@ static int annotate_browser__run(struct annotate_browser *browser, ...@@ -741,6 +747,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
script_browse(NULL); script_browse(NULL);
continue; continue;
} }
case 'k':
annotate_browser__opts.show_linenr =
!annotate_browser__opts.show_linenr;
break;
case 'H': case 'H':
nd = browser->curr_hot; nd = browser->curr_hot;
break; break;
...@@ -984,6 +994,7 @@ static struct annotate_config { ...@@ -984,6 +994,7 @@ static struct annotate_config {
} annotate__configs[] = { } annotate__configs[] = {
ANNOTATE_CFG(hide_src_code), ANNOTATE_CFG(hide_src_code),
ANNOTATE_CFG(jump_arrows), ANNOTATE_CFG(jump_arrows),
ANNOTATE_CFG(show_linenr),
ANNOTATE_CFG(show_nr_jumps), ANNOTATE_CFG(show_nr_jumps),
ANNOTATE_CFG(use_offset), ANNOTATE_CFG(use_offset),
}; };
......
...@@ -17,11 +17,13 @@ ...@@ -17,11 +17,13 @@
#include "debug.h" #include "debug.h"
#include "annotate.h" #include "annotate.h"
#include "evsel.h" #include "evsel.h"
#include <regex.h>
#include <pthread.h> #include <pthread.h>
#include <linux/bitops.h> #include <linux/bitops.h>
const char *disassembler_style; const char *disassembler_style;
const char *objdump_path; const char *objdump_path;
static regex_t file_lineno;
static struct ins *ins__find(const char *name); static struct ins *ins__find(const char *name);
static int disasm_line__parse(char *line, char **namep, char **rawp); static int disasm_line__parse(char *line, char **namep, char **rawp);
...@@ -570,13 +572,15 @@ static int disasm_line__parse(char *line, char **namep, char **rawp) ...@@ -570,13 +572,15 @@ static int disasm_line__parse(char *line, char **namep, char **rawp)
return -1; return -1;
} }
static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) static struct disasm_line *disasm_line__new(s64 offset, char *line,
size_t privsize, int line_nr)
{ {
struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
if (dl != NULL) { if (dl != NULL) {
dl->offset = offset; dl->offset = offset;
dl->line = strdup(line); dl->line = strdup(line);
dl->line_nr = line_nr;
if (dl->line == NULL) if (dl->line == NULL)
goto out_delete; goto out_delete;
...@@ -788,13 +792,15 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st ...@@ -788,13 +792,15 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
* The ops.raw part will be parsed further according to type of the instruction. * The ops.raw part will be parsed further according to type of the instruction.
*/ */
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
FILE *file, size_t privsize) FILE *file, size_t privsize,
int *line_nr)
{ {
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
struct disasm_line *dl; struct disasm_line *dl;
char *line = NULL, *parsed_line, *tmp, *tmp2, *c; char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
size_t line_len; size_t line_len;
s64 line_ip, offset = -1; s64 line_ip, offset = -1;
regmatch_t match[2];
if (getline(&line, &line_len, file) < 0) if (getline(&line, &line_len, file) < 0)
return -1; return -1;
...@@ -812,6 +818,12 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -812,6 +818,12 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
line_ip = -1; line_ip = -1;
parsed_line = line; parsed_line = line;
/* /filename:linenr ? Save line number and ignore. */
if (regexec(&file_lineno, line, 2, match, 0) == 0) {
*line_nr = atoi(line + match[1].rm_so);
return 0;
}
/* /*
* Strip leading spaces: * Strip leading spaces:
*/ */
...@@ -842,8 +854,9 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -842,8 +854,9 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
parsed_line = tmp2 + 1; parsed_line = tmp2 + 1;
} }
dl = disasm_line__new(offset, parsed_line, privsize); dl = disasm_line__new(offset, parsed_line, privsize, *line_nr);
free(line); free(line);
(*line_nr)++;
if (dl == NULL) if (dl == NULL)
return -1; return -1;
...@@ -869,6 +882,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -869,6 +882,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
return 0; return 0;
} }
static __attribute__((constructor)) void symbol__init_regexpr(void)
{
regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);
}
static void delete_last_nop(struct symbol *sym) static void delete_last_nop(struct symbol *sym)
{ {
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
...@@ -904,6 +922,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -904,6 +922,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
char symfs_filename[PATH_MAX]; char symfs_filename[PATH_MAX];
struct kcore_extract kce; struct kcore_extract kce;
bool delete_extract = false; bool delete_extract = false;
int lineno = 0;
if (filename) if (filename)
symbol__join_symfs(symfs_filename, filename); symbol__join_symfs(symfs_filename, filename);
...@@ -984,7 +1003,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -984,7 +1003,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
snprintf(command, sizeof(command), snprintf(command, sizeof(command),
"%s %s%s --start-address=0x%016" PRIx64 "%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64
" -d %s %s -C %s 2>/dev/null|grep -v %s|expand", " -l -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
objdump_path ? objdump_path : "objdump", objdump_path ? objdump_path : "objdump",
disassembler_style ? "-M " : "", disassembler_style ? "-M " : "",
disassembler_style ? disassembler_style : "", disassembler_style ? disassembler_style : "",
...@@ -1001,7 +1020,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -1001,7 +1020,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
goto out_free_filename; goto out_free_filename;
while (!feof(file)) while (!feof(file))
if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) if (symbol__parse_objdump_line(sym, map, file, privsize,
&lineno) < 0)
break; break;
/* /*
......
...@@ -58,6 +58,7 @@ struct disasm_line { ...@@ -58,6 +58,7 @@ struct disasm_line {
char *line; char *line;
char *name; char *name;
struct ins *ins; struct ins *ins;
int line_nr;
struct ins_operands ops; struct ins_operands ops;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment