|
@@ -42,7 +42,8 @@
|
|
|
#include "color.h"
|
|
|
#include "symbol.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-finder.h"
|
|
|
|
|
@@ -70,10 +71,11 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
|
|
|
static struct map_groups kmap_groups;
|
|
|
static struct map *kmaps[MAP__NR_TYPES];
|
|
|
|
|
|
-/* Initialize symbol maps for vmlinux */
|
|
|
+/* Initialize symbol maps and path of vmlinux */
|
|
|
static void init_vmlinux(void)
|
|
|
{
|
|
|
symbol_conf.sort_by_name = true;
|
|
@@ -89,7 +91,7 @@ static void init_vmlinux(void)
|
|
|
die("Failed to create kernel maps.");
|
|
|
}
|
|
|
|
|
|
-#ifndef NO_DWARF_SUPPORT
|
|
|
+#ifdef DWARF_SUPPORT
|
|
|
static int open_vmlinux(void)
|
|
|
{
|
|
|
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);
|
|
|
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
|
|
|
|
|
|
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];
|
|
|
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->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 */
|
|
|
pev->nargs = tev->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 symbol *sym;
|
|
|
- bool need_dwarf;
|
|
|
-#ifndef NO_DWARF_SUPPORT
|
|
|
- int fd;
|
|
|
-#endif
|
|
|
int ntevs = 0, i;
|
|
|
struct kprobe_trace_event *tev;
|
|
|
|
|
|
- need_dwarf = perf_probe_event_need_dwarf(pev);
|
|
|
-
|
|
|
- if (need_dwarf)
|
|
|
-#ifdef NO_DWARF_SUPPORT
|
|
|
- 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 */
|
|
|
+ /* Convert perf_probe_event with debuginfo */
|
|
|
+ ntevs = try_to_find_kprobe_trace_events(pev, tevs);
|
|
|
+ if (ntevs > 0)
|
|
|
+ return ntevs;
|
|
|
|
|
|
/* Allocate trace event buffer */
|
|
|
ntevs = 1;
|
|
@@ -1012,10 +1127,7 @@ end_dwarf:
|
|
|
if (!sym)
|
|
|
die("Kernel symbol \'%s\' not found - probe not added.",
|
|
|
tev->point.symbol);
|
|
|
-#ifndef NO_DWARF_SUPPORT
|
|
|
-found:
|
|
|
- close(fd);
|
|
|
-#endif
|
|
|
+
|
|
|
return ntevs;
|
|
|
}
|
|
|
|
|
@@ -1133,90 +1245,3 @@ void del_perf_probe_events(struct strlist *dellist)
|
|
|
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);
|
|
|
-}
|
|
|
-
|
|
|
-
|