perf probe: Cleanup debuginfo related code
Cleanup debuginfo related code to eliminate fragile code which pointed by Ingo (Thanks!). 1) Invert logic of NO_DWARF_SUPPORT to DWARF_SUPPORT. 2) For removing assymetric/local variable ifdefs, introduce more helper functions. 3) Change options order to reduce the number of ifdefs. Reported-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1269274229-20442-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
f3a1f0ea94
commit
4b4da7f766
@ -506,9 +506,8 @@ endif
|
|||||||
|
|
||||||
ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
|
||||||
msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
|
msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
|
||||||
BASIC_CFLAGS += -DNO_DWARF_SUPPORT
|
|
||||||
else
|
else
|
||||||
BASIC_CFLAGS += -I/usr/include/elfutils
|
BASIC_CFLAGS += -I/usr/include/elfutils -DDWARF_SUPPORT
|
||||||
EXTLIBS += -lelf -ldw
|
EXTLIBS += -lelf -ldw
|
||||||
LIB_OBJS += util/probe-finder.o
|
LIB_OBJS += util/probe-finder.o
|
||||||
endif
|
endif
|
||||||
|
@ -109,7 +109,7 @@ static int opt_del_probe_event(const struct option *opt __used,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
static int opt_show_lines(const struct option *opt __used,
|
static int opt_show_lines(const struct option *opt __used,
|
||||||
const char *str, int unset __used)
|
const char *str, int unset __used)
|
||||||
{
|
{
|
||||||
@ -126,7 +126,7 @@ static const char * const probe_usage[] = {
|
|||||||
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
|
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
|
||||||
"perf probe [<options>] --del '[GROUP:]EVENT' ...",
|
"perf probe [<options>] --del '[GROUP:]EVENT' ...",
|
||||||
"perf probe --list",
|
"perf probe --list",
|
||||||
#ifndef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
"perf probe --line 'LINEDESC'",
|
"perf probe --line 'LINEDESC'",
|
||||||
#endif
|
#endif
|
||||||
NULL
|
NULL
|
||||||
@ -135,20 +135,16 @@ static const char * const probe_usage[] = {
|
|||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
OPT_BOOLEAN('v', "verbose", &verbose,
|
OPT_BOOLEAN('v', "verbose", &verbose,
|
||||||
"be more verbose (show parsed arguments, etc)"),
|
"be more verbose (show parsed arguments, etc)"),
|
||||||
#ifndef NO_DWARF_SUPPORT
|
|
||||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
|
||||||
"file", "vmlinux pathname"),
|
|
||||||
#endif
|
|
||||||
OPT_BOOLEAN('l', "list", ¶ms.list_events,
|
OPT_BOOLEAN('l', "list", ¶ms.list_events,
|
||||||
"list up current probe events"),
|
"list up current probe events"),
|
||||||
OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
|
OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
|
||||||
opt_del_probe_event),
|
opt_del_probe_event),
|
||||||
OPT_CALLBACK('a', "add", NULL,
|
OPT_CALLBACK('a', "add", NULL,
|
||||||
#ifdef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
"[EVENT=]FUNC[+OFF|%return] [ARG ...]",
|
|
||||||
#else
|
|
||||||
"[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
|
"[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
|
||||||
" [ARG ...]",
|
" [ARG ...]",
|
||||||
|
#else
|
||||||
|
"[EVENT=]FUNC[+OFF|%return] [ARG ...]",
|
||||||
#endif
|
#endif
|
||||||
"probe point definition, where\n"
|
"probe point definition, where\n"
|
||||||
"\t\tGROUP:\tGroup name (optional)\n"
|
"\t\tGROUP:\tGroup name (optional)\n"
|
||||||
@ -156,23 +152,25 @@ static const struct option options[] = {
|
|||||||
"\t\tFUNC:\tFunction name\n"
|
"\t\tFUNC:\tFunction name\n"
|
||||||
"\t\tOFF:\tOffset from function entry (in byte)\n"
|
"\t\tOFF:\tOffset from function entry (in byte)\n"
|
||||||
"\t\t%return:\tPut the probe at function return\n"
|
"\t\t%return:\tPut the probe at function return\n"
|
||||||
#ifdef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
"\t\tARG:\tProbe argument (only \n"
|
|
||||||
#else
|
|
||||||
"\t\tSRC:\tSource code path\n"
|
"\t\tSRC:\tSource code path\n"
|
||||||
"\t\tRL:\tRelative line number from function entry.\n"
|
"\t\tRL:\tRelative line number from function entry.\n"
|
||||||
"\t\tAL:\tAbsolute line number in file.\n"
|
"\t\tAL:\tAbsolute line number in file.\n"
|
||||||
"\t\tPT:\tLazy expression of line code.\n"
|
"\t\tPT:\tLazy expression of line code.\n"
|
||||||
"\t\tARG:\tProbe argument (local variable name or\n"
|
"\t\tARG:\tProbe argument (local variable name or\n"
|
||||||
#endif
|
|
||||||
"\t\t\tkprobe-tracer argument format.)\n",
|
"\t\t\tkprobe-tracer argument format.)\n",
|
||||||
|
#else
|
||||||
|
"\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
|
||||||
|
#endif
|
||||||
opt_add_probe_event),
|
opt_add_probe_event),
|
||||||
OPT_BOOLEAN('f', "force", ¶ms.force_add, "forcibly add events"
|
OPT_BOOLEAN('f', "force", ¶ms.force_add, "forcibly add events"
|
||||||
" with existing name"),
|
" with existing name"),
|
||||||
#ifndef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
OPT_CALLBACK('L', "line", NULL,
|
OPT_CALLBACK('L', "line", NULL,
|
||||||
"FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
|
"FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
|
||||||
"Show source code lines.", opt_show_lines),
|
"Show source code lines.", opt_show_lines),
|
||||||
|
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||||
|
"file", "vmlinux pathname"),
|
||||||
#endif
|
#endif
|
||||||
OPT__DRY_RUN(&probe_event_dry_run),
|
OPT__DRY_RUN(&probe_event_dry_run),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
@ -211,7 +209,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
if (params.show_lines) {
|
if (params.show_lines) {
|
||||||
if (params.nevents != 0 || params.dellist) {
|
if (params.nevents != 0 || params.dellist) {
|
||||||
pr_warning(" Error: Don't use --line with"
|
pr_warning(" Error: Don't use --line with"
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "parse-events.h" /* For debugfs_path */
|
#include "trace-event.h" /* For __unused */
|
||||||
|
#include "parse-events.h" /* For debugfs_path */
|
||||||
#include "probe-event.h"
|
#include "probe-event.h"
|
||||||
#include "probe-finder.h"
|
#include "probe-finder.h"
|
||||||
|
|
||||||
@ -70,10 +71,11 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
|
||||||
static struct map_groups kmap_groups;
|
static struct map_groups kmap_groups;
|
||||||
static struct map *kmaps[MAP__NR_TYPES];
|
static struct map *kmaps[MAP__NR_TYPES];
|
||||||
|
|
||||||
/* Initialize symbol maps for vmlinux */
|
/* Initialize symbol maps and path of vmlinux */
|
||||||
static void init_vmlinux(void)
|
static void init_vmlinux(void)
|
||||||
{
|
{
|
||||||
symbol_conf.sort_by_name = true;
|
symbol_conf.sort_by_name = true;
|
||||||
@ -89,7 +91,7 @@ static void init_vmlinux(void)
|
|||||||
die("Failed to create kernel maps.");
|
die("Failed to create kernel maps.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
static int open_vmlinux(void)
|
static int open_vmlinux(void)
|
||||||
{
|
{
|
||||||
if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
|
if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
|
||||||
@ -99,6 +101,176 @@ static int open_vmlinux(void)
|
|||||||
pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
|
pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
|
||||||
return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
|
return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void convert_to_perf_probe_point(struct kprobe_trace_point *tp,
|
||||||
|
struct perf_probe_point *pp)
|
||||||
|
{
|
||||||
|
struct symbol *sym;
|
||||||
|
int fd, ret = 0;
|
||||||
|
|
||||||
|
sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
|
||||||
|
tp->symbol, NULL);
|
||||||
|
if (sym) {
|
||||||
|
fd = open_vmlinux();
|
||||||
|
ret = find_perf_probe_point(fd, sym->start + tp->offset, pp);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
if (ret <= 0) {
|
||||||
|
pp->function = xstrdup(tp->symbol);
|
||||||
|
pp->offset = tp->offset;
|
||||||
|
}
|
||||||
|
pp->retprobe = tp->retprobe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
bool need_dwarf = perf_probe_event_need_dwarf(pev);
|
||||||
|
int fd, ntevs;
|
||||||
|
|
||||||
|
fd = open_vmlinux();
|
||||||
|
if (fd < 0) {
|
||||||
|
if (need_dwarf)
|
||||||
|
die("Could not open debuginfo file.");
|
||||||
|
|
||||||
|
pr_debug("Could not open vmlinux. Try to use symbols.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Searching trace events corresponding to probe event */
|
||||||
|
ntevs = find_kprobe_trace_events(fd, pev, tevs);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (ntevs > 0) /* Succeeded to find trace events */
|
||||||
|
return ntevs;
|
||||||
|
|
||||||
|
if (ntevs == 0) /* No error but failed to find probe point. */
|
||||||
|
die("Probe point '%s' not found. - probe not added.",
|
||||||
|
synthesize_perf_probe_point(&pev->point));
|
||||||
|
|
||||||
|
/* Error path */
|
||||||
|
if (need_dwarf) {
|
||||||
|
if (ntevs == -ENOENT)
|
||||||
|
pr_warning("No dwarf info found in the vmlinux - "
|
||||||
|
"please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
||||||
|
die("Could not analyze debuginfo.");
|
||||||
|
}
|
||||||
|
pr_debug("An error occurred in debuginfo analysis."
|
||||||
|
" Try to use symbols.\n");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LINEBUF_SIZE 256
|
||||||
|
#define NR_ADDITIONAL_LINES 2
|
||||||
|
|
||||||
|
static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
|
||||||
|
{
|
||||||
|
char buf[LINEBUF_SIZE];
|
||||||
|
const char *color = PERF_COLOR_BLUE;
|
||||||
|
|
||||||
|
if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
|
||||||
|
goto error;
|
||||||
|
if (!skip) {
|
||||||
|
if (show_num)
|
||||||
|
fprintf(stdout, "%7u %s", l, buf);
|
||||||
|
else
|
||||||
|
color_fprintf(stdout, color, " %s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (strlen(buf) == LINEBUF_SIZE - 1 &&
|
||||||
|
buf[LINEBUF_SIZE - 2] != '\n') {
|
||||||
|
if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
|
||||||
|
goto error;
|
||||||
|
if (!skip) {
|
||||||
|
if (show_num)
|
||||||
|
fprintf(stdout, "%s", buf);
|
||||||
|
else
|
||||||
|
color_fprintf(stdout, color, "%s", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
error:
|
||||||
|
if (feof(fp))
|
||||||
|
die("Source file is shorter than expected.");
|
||||||
|
else
|
||||||
|
die("File read error: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show line-range always requires debuginfo to find source file and
|
||||||
|
* line number.
|
||||||
|
*/
|
||||||
|
void show_line_range(struct line_range *lr)
|
||||||
|
{
|
||||||
|
unsigned int l = 1;
|
||||||
|
struct line_node *ln;
|
||||||
|
FILE *fp;
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
/* Search a line range */
|
||||||
|
init_vmlinux();
|
||||||
|
fd = open_vmlinux();
|
||||||
|
if (fd < 0)
|
||||||
|
die("Could not open debuginfo file.");
|
||||||
|
ret = find_line_range(fd, lr);
|
||||||
|
if (ret <= 0)
|
||||||
|
die("Source line is not found.\n");
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
setup_pager();
|
||||||
|
|
||||||
|
if (lr->function)
|
||||||
|
fprintf(stdout, "<%s:%d>\n", lr->function,
|
||||||
|
lr->start - lr->offset);
|
||||||
|
else
|
||||||
|
fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
|
||||||
|
|
||||||
|
fp = fopen(lr->path, "r");
|
||||||
|
if (fp == NULL)
|
||||||
|
die("Failed to open %s: %s", lr->path, strerror(errno));
|
||||||
|
/* Skip to starting line number */
|
||||||
|
while (l < lr->start)
|
||||||
|
show_one_line(fp, l++, true, false);
|
||||||
|
|
||||||
|
list_for_each_entry(ln, &lr->line_list, list) {
|
||||||
|
while (ln->line > l)
|
||||||
|
show_one_line(fp, (l++) - lr->offset, false, false);
|
||||||
|
show_one_line(fp, (l++) - lr->offset, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lr->end == INT_MAX)
|
||||||
|
lr->end = l + NR_ADDITIONAL_LINES;
|
||||||
|
while (l < lr->end && !feof(fp))
|
||||||
|
show_one_line(fp, (l++) - lr->offset, false, false);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !DWARF_SUPPORT */
|
||||||
|
|
||||||
|
static void convert_to_perf_probe_point(struct kprobe_trace_point *tp,
|
||||||
|
struct perf_probe_point *pp)
|
||||||
|
{
|
||||||
|
pp->function = xstrdup(tp->symbol);
|
||||||
|
pp->offset = tp->offset;
|
||||||
|
pp->retprobe = tp->retprobe;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
|
||||||
|
struct kprobe_trace_event **tevs __unused)
|
||||||
|
{
|
||||||
|
if (perf_probe_event_need_dwarf(pev))
|
||||||
|
die("Debuginfo-analysis is not supported");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_line_range(struct line_range *lr __unused)
|
||||||
|
{
|
||||||
|
die("Debuginfo-analysis is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void parse_line_range_desc(const char *arg, struct line_range *lr)
|
void parse_line_range_desc(const char *arg, struct line_range *lr)
|
||||||
@ -592,32 +764,14 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
|
|||||||
{
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int i;
|
int i;
|
||||||
#ifndef NO_DWARF_SUPPORT
|
|
||||||
struct symbol *sym;
|
|
||||||
int fd, ret = 0;
|
|
||||||
|
|
||||||
sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
|
|
||||||
tev->point.symbol, NULL);
|
|
||||||
if (sym) {
|
|
||||||
fd = open_vmlinux();
|
|
||||||
ret = find_perf_probe_point(fd, sym->start + tev->point.offset,
|
|
||||||
&pev->point);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
if (ret <= 0) {
|
|
||||||
pev->point.function = xstrdup(tev->point.symbol);
|
|
||||||
pev->point.offset = tev->point.offset;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Convert trace_point to probe_point */
|
|
||||||
pev->point.function = xstrdup(tev->point.symbol);
|
|
||||||
pev->point.offset = tev->point.offset;
|
|
||||||
#endif
|
|
||||||
pev->point.retprobe = tev->point.retprobe;
|
|
||||||
|
|
||||||
|
/* Convert event/group name */
|
||||||
pev->event = xstrdup(tev->event);
|
pev->event = xstrdup(tev->event);
|
||||||
pev->group = xstrdup(tev->group);
|
pev->group = xstrdup(tev->group);
|
||||||
|
|
||||||
|
/* Convert trace_point to probe_point */
|
||||||
|
convert_to_perf_probe_point(&tev->point, &pev->point);
|
||||||
|
|
||||||
/* Convert trace_arg to probe_arg */
|
/* Convert trace_arg to probe_arg */
|
||||||
pev->nargs = tev->nargs;
|
pev->nargs = tev->nargs;
|
||||||
pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
|
pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
|
||||||
@ -944,52 +1098,13 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
|
|||||||
struct kprobe_trace_event **tevs)
|
struct kprobe_trace_event **tevs)
|
||||||
{
|
{
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
bool need_dwarf;
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
int ntevs = 0, i;
|
int ntevs = 0, i;
|
||||||
struct kprobe_trace_event *tev;
|
struct kprobe_trace_event *tev;
|
||||||
|
|
||||||
need_dwarf = perf_probe_event_need_dwarf(pev);
|
/* Convert perf_probe_event with debuginfo */
|
||||||
|
ntevs = try_to_find_kprobe_trace_events(pev, tevs);
|
||||||
if (need_dwarf)
|
if (ntevs > 0)
|
||||||
#ifdef NO_DWARF_SUPPORT
|
return ntevs;
|
||||||
die("Debuginfo-analysis is not supported");
|
|
||||||
#else /* !NO_DWARF_SUPPORT */
|
|
||||||
pr_debug("Some probes require debuginfo.\n");
|
|
||||||
|
|
||||||
fd = open_vmlinux();
|
|
||||||
if (fd < 0) {
|
|
||||||
if (need_dwarf)
|
|
||||||
die("Could not open debuginfo file.");
|
|
||||||
|
|
||||||
pr_debug("Could not open vmlinux/module file."
|
|
||||||
" Try to use symbols.\n");
|
|
||||||
goto end_dwarf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Searching probe points */
|
|
||||||
ntevs = find_kprobe_trace_events(fd, pev, tevs);
|
|
||||||
|
|
||||||
if (ntevs > 0) /* Found */
|
|
||||||
goto found;
|
|
||||||
|
|
||||||
if (ntevs == 0) /* No error but failed to find probe point. */
|
|
||||||
die("Probe point '%s' not found. - probe not added.",
|
|
||||||
synthesize_perf_probe_point(&pev->point));
|
|
||||||
|
|
||||||
/* Error path */
|
|
||||||
if (need_dwarf) {
|
|
||||||
if (ntevs == -ENOENT)
|
|
||||||
pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
|
|
||||||
die("Could not analyze debuginfo.");
|
|
||||||
}
|
|
||||||
pr_debug("An error occurred in debuginfo analysis."
|
|
||||||
" Try to use symbols.\n");
|
|
||||||
|
|
||||||
end_dwarf:
|
|
||||||
#endif /* !NO_DWARF_SUPPORT */
|
|
||||||
|
|
||||||
/* Allocate trace event buffer */
|
/* Allocate trace event buffer */
|
||||||
ntevs = 1;
|
ntevs = 1;
|
||||||
@ -1012,10 +1127,7 @@ end_dwarf:
|
|||||||
if (!sym)
|
if (!sym)
|
||||||
die("Kernel symbol \'%s\' not found - probe not added.",
|
die("Kernel symbol \'%s\' not found - probe not added.",
|
||||||
tev->point.symbol);
|
tev->point.symbol);
|
||||||
#ifndef NO_DWARF_SUPPORT
|
|
||||||
found:
|
|
||||||
close(fd);
|
|
||||||
#endif
|
|
||||||
return ntevs;
|
return ntevs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,90 +1245,3 @@ void del_perf_probe_events(struct strlist *dellist)
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LINEBUF_SIZE 256
|
|
||||||
#define NR_ADDITIONAL_LINES 2
|
|
||||||
|
|
||||||
static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
|
|
||||||
{
|
|
||||||
char buf[LINEBUF_SIZE];
|
|
||||||
const char *color = PERF_COLOR_BLUE;
|
|
||||||
|
|
||||||
if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
|
|
||||||
goto error;
|
|
||||||
if (!skip) {
|
|
||||||
if (show_num)
|
|
||||||
fprintf(stdout, "%7u %s", l, buf);
|
|
||||||
else
|
|
||||||
color_fprintf(stdout, color, " %s", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (strlen(buf) == LINEBUF_SIZE - 1 &&
|
|
||||||
buf[LINEBUF_SIZE - 2] != '\n') {
|
|
||||||
if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
|
|
||||||
goto error;
|
|
||||||
if (!skip) {
|
|
||||||
if (show_num)
|
|
||||||
fprintf(stdout, "%s", buf);
|
|
||||||
else
|
|
||||||
color_fprintf(stdout, color, "%s", buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
error:
|
|
||||||
if (feof(fp))
|
|
||||||
die("Source file is shorter than expected.");
|
|
||||||
else
|
|
||||||
die("File read error: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_line_range(struct line_range *lr)
|
|
||||||
{
|
|
||||||
unsigned int l = 1;
|
|
||||||
struct line_node *ln;
|
|
||||||
FILE *fp;
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
|
||||||
int fd, ret;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Search a line range */
|
|
||||||
init_vmlinux();
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
|
||||||
fd = open_vmlinux();
|
|
||||||
if (fd < 0)
|
|
||||||
die("Could not open debuginfo file.");
|
|
||||||
ret = find_line_range(fd, lr);
|
|
||||||
if (ret <= 0)
|
|
||||||
die("Source line is not found.\n");
|
|
||||||
close(fd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setup_pager();
|
|
||||||
|
|
||||||
if (lr->function)
|
|
||||||
fprintf(stdout, "<%s:%d>\n", lr->function,
|
|
||||||
lr->start - lr->offset);
|
|
||||||
else
|
|
||||||
fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
|
|
||||||
|
|
||||||
fp = fopen(lr->path, "r");
|
|
||||||
if (fp == NULL)
|
|
||||||
die("Failed to open %s: %s", lr->path, strerror(errno));
|
|
||||||
/* Skip to starting line number */
|
|
||||||
while (l < lr->start)
|
|
||||||
show_one_line(fp, l++, true, false);
|
|
||||||
|
|
||||||
list_for_each_entry(ln, &lr->line_list, list) {
|
|
||||||
while (ln->line > l)
|
|
||||||
show_one_line(fp, (l++) - lr->offset, false, false);
|
|
||||||
show_one_line(fp, (l++) - lr->offset, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lr->end == INT_MAX)
|
|
||||||
lr->end = l + NR_ADDITIONAL_LINES;
|
|
||||||
while (l < lr->end && !feof(fp))
|
|
||||||
show_one_line(fp, (l++) - lr->offset, false, false);
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ static inline int is_c_varname(const char *name)
|
|||||||
return isalpha(name[0]) || name[0] == '_';
|
return isalpha(name[0]) || name[0] == '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
|
/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
|
||||||
extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
|
extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
|
||||||
struct kprobe_trace_event **tevs);
|
struct kprobe_trace_event **tevs);
|
||||||
@ -57,6 +57,6 @@ struct line_finder {
|
|||||||
int found;
|
int found;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* NO_DWARF_SUPPORT */
|
#endif /* DWARF_SUPPORT */
|
||||||
|
|
||||||
#endif /*_PROBE_FINDER_H */
|
#endif /*_PROBE_FINDER_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user