Commit 469b9b88488e89114bb3e9ac5ee7906b7b96123f

Authored by Masami Hiramatsu
Committed by Arnaldo Carvalho de Melo
1 parent fb8c5a56c7

perf probe: Add basic module support

Add basic module probe support on perf probe. This introduces "--module
<MODNAME>" option to perf probe for putting probes and showing lines and
variables in the given module.

Currently, this supports only probing on running modules.  Supporting off-line
module probing is the next step.

e.g.)
[show lines]
 # ./perf probe --module drm -L drm_vblank_info
<drm_vblank_info:0>
      0  int drm_vblank_info(struct seq_file *m, void *data)
      1  {
                struct drm_info_node *node = (struct drm_info_node *) m->private
      3         struct drm_device *dev = node->minor->dev;
 ...
[show vars]
 # ./perf probe --module drm -V drm_vblank_info:3
Available variables at drm_vblank_info:3
        @<drm_vblank_info+20>
                (unknown_type)  data
                struct drm_info_node*   node
                struct seq_file*        m
[put a probe]
 # ./perf probe --module drm drm_vblank_info:3 node m
Add new event:
  probe:drm_vblank_info (on drm_vblank_info:3 with node m)

You can now use it on all perf tools, such as:

        perf record -e probe:drm_vblank_info -aR sleep 1
[list probes]
 # ./perf probe -l
probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ...

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20101021101341.3542.71638.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Showing 7 changed files with 239 additions and 69 deletions Side-by-side Diff

tools/perf/Documentation/perf-probe.txt
... ... @@ -16,9 +16,9 @@
16 16 or
17 17 'perf probe' --list
18 18 or
19   -'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
  19 +'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
20 20 or
21   -'perf probe' [--externs] --vars='PROBEPOINT'
  21 +'perf probe' [options] --vars='PROBEPOINT'
22 22  
23 23 DESCRIPTION
24 24 -----------
... ... @@ -32,6 +32,11 @@
32 32 -k::
33 33 --vmlinux=PATH::
34 34 Specify vmlinux path which has debuginfo (Dwarf binary).
  35 +
  36 +-m::
  37 +--module=MODNAME::
  38 + Specify module name in which perf-probe searches probe points
  39 + or lines.
35 40  
36 41 -s::
37 42 --source=PATH::
tools/perf/builtin-probe.c
... ... @@ -57,6 +57,7 @@
57 57 struct perf_probe_event events[MAX_PROBES];
58 58 struct strlist *dellist;
59 59 struct line_range line_range;
  60 + const char *target_module;
60 61 int max_probe_points;
61 62 } params;
62 63  
... ... @@ -162,8 +163,8 @@
162 163 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
163 164 "perf probe --list",
164 165 #ifdef DWARF_SUPPORT
165   - "perf probe --line 'LINEDESC'",
166   - "perf probe [--externs] --vars 'PROBEPOINT'",
  166 + "perf probe [<options>] --line 'LINEDESC'",
  167 + "perf probe [<options>] --vars 'PROBEPOINT'",
167 168 #endif
168 169 NULL
169 170 };
... ... @@ -214,6 +215,8 @@
214 215 "file", "vmlinux pathname"),
215 216 OPT_STRING('s', "source", &symbol_conf.source_prefix,
216 217 "directory", "path to kernel source"),
  218 + OPT_STRING('m', "module", &params.target_module,
  219 + "modname", "target module name"),
217 220 #endif
218 221 OPT__DRY_RUN(&probe_event_dry_run),
219 222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
... ... @@ -278,7 +281,7 @@
278 281 usage_with_options(probe_usage, options);
279 282 }
280 283  
281   - ret = show_line_range(&params.line_range);
  284 + ret = show_line_range(&params.line_range, params.target_module);
282 285 if (ret < 0)
283 286 pr_err(" Error: Failed to show lines. (%d)\n", ret);
284 287 return ret;
... ... @@ -291,6 +294,7 @@
291 294 }
292 295 ret = show_available_vars(params.events, params.nevents,
293 296 params.max_probe_points,
  297 + params.target_module,
294 298 params.show_ext_vars);
295 299 if (ret < 0)
296 300 pr_err(" Error: Failed to show vars. (%d)\n", ret);
... ... @@ -310,6 +314,7 @@
310 314 if (params.nevents) {
311 315 ret = add_perf_probe_events(params.events, params.nevents,
312 316 params.max_probe_points,
  317 + params.target_module,
313 318 params.force_add);
314 319 if (ret < 0) {
315 320 pr_err(" Error: Failed to add events. (%d)\n", ret);
tools/perf/util/map.h
... ... @@ -215,6 +215,16 @@
215 215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
216 216 }
217 217  
  218 +static inline
  219 +struct symbol *machine__find_kernel_function_by_name(struct machine *self,
  220 + const char *name,
  221 + struct map **mapp,
  222 + symbol_filter_t filter)
  223 +{
  224 + return map_groups__find_function_by_name(&self->kmaps, name, mapp,
  225 + filter);
  226 +}
  227 +
218 228 int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
219 229 int verbose, FILE *fp);
220 230  
tools/perf/util/probe-event.c
... ... @@ -74,10 +74,9 @@
74 74 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75 75 static struct machine machine;
76 76  
77   -/* Initialize symbol maps and path of vmlinux */
  77 +/* Initialize symbol maps and path of vmlinux/modules */
78 78 static int init_vmlinux(void)
79 79 {
80   - struct dso *kernel;
81 80 int ret;
82 81  
83 82 symbol_conf.sort_by_name = true;
84 83  
85 84  
86 85  
87 86  
88 87  
... ... @@ -91,33 +90,61 @@
91 90 goto out;
92 91 }
93 92  
94   - ret = machine__init(&machine, "/", 0);
  93 + ret = machine__init(&machine, "", HOST_KERNEL_ID);
95 94 if (ret < 0)
96 95 goto out;
97 96  
98   - kernel = dso__new_kernel(symbol_conf.vmlinux_name);
99   - if (kernel == NULL)
100   - die("Failed to create kernel dso.");
101   -
102   - ret = __machine__create_kernel_maps(&machine, kernel);
103   - if (ret < 0)
104   - pr_debug("Failed to create kernel maps.\n");
105   -
  97 + if (machine__create_kernel_maps(&machine) < 0) {
  98 + pr_debug("machine__create_kernel_maps ");
  99 + goto out;
  100 + }
106 101 out:
107 102 if (ret < 0)
108 103 pr_warning("Failed to init vmlinux path.\n");
109 104 return ret;
110 105 }
111 106  
  107 +static struct symbol *__find_kernel_function_by_name(const char *name,
  108 + struct map **mapp)
  109 +{
  110 + return machine__find_kernel_function_by_name(&machine, name, mapp,
  111 + NULL);
  112 +}
  113 +
  114 +const char *kernel_get_module_path(const char *module)
  115 +{
  116 + struct dso *dso;
  117 +
  118 + if (module) {
  119 + list_for_each_entry(dso, &machine.kernel_dsos, node) {
  120 + if (strncmp(dso->short_name + 1, module,
  121 + dso->short_name_len - 2) == 0)
  122 + goto found;
  123 + }
  124 + pr_debug("Failed to find module %s.\n", module);
  125 + return NULL;
  126 + } else {
  127 + dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
  128 + if (dso__load_vmlinux_path(dso,
  129 + machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
  130 + pr_debug("Failed to load kernel map.\n");
  131 + return NULL;
  132 + }
  133 + }
  134 +found:
  135 + return dso->long_name;
  136 +}
  137 +
112 138 #ifdef DWARF_SUPPORT
113   -static int open_vmlinux(void)
  139 +static int open_vmlinux(const char *module)
114 140 {
115   - if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
116   - pr_debug("Failed to load kernel map.\n");
117   - return -EINVAL;
  141 + const char *path = kernel_get_module_path(module);
  142 + if (!path) {
  143 + pr_err("Failed to find path of %s module", module ?: "kernel");
  144 + return -ENOENT;
118 145 }
119   - pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
120   - return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
  146 + pr_debug("Try to open %s\n", path);
  147 + return open(path, O_RDONLY);
121 148 }
122 149  
123 150 /*
124 151  
125 152  
126 153  
... ... @@ -125,20 +152,19 @@
125 152 * Currently only handles kprobes.
126 153 */
127 154 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
128   - struct perf_probe_point *pp)
  155 + struct perf_probe_point *pp)
129 156 {
130 157 struct symbol *sym;
131   - int fd, ret = -ENOENT;
  158 + struct map *map;
  159 + u64 addr;
  160 + int ret = -ENOENT;
132 161  
133   - sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
134   - tp->symbol, NULL);
  162 + sym = __find_kernel_function_by_name(tp->symbol, &map);
135 163 if (sym) {
136   - fd = open_vmlinux();
137   - if (fd >= 0) {
138   - ret = find_perf_probe_point(fd,
139   - sym->start + tp->offset, pp);
140   - close(fd);
141   - }
  164 + addr = map->unmap_ip(map, sym->start + tp->offset);
  165 + pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
  166 + tp->offset, addr);
  167 + ret = find_perf_probe_point((unsigned long)addr, pp);
142 168 }
143 169 if (ret <= 0) {
144 170 pr_debug("Failed to find corresponding probes from "
145 171  
... ... @@ -156,12 +182,12 @@
156 182 /* Try to find perf_probe_event with debuginfo */
157 183 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
158 184 struct probe_trace_event **tevs,
159   - int max_tevs)
  185 + int max_tevs, const char *module)
160 186 {
161 187 bool need_dwarf = perf_probe_event_need_dwarf(pev);
162 188 int fd, ntevs;
163 189  
164   - fd = open_vmlinux();
  190 + fd = open_vmlinux(module);
165 191 if (fd < 0) {
166 192 if (need_dwarf) {
167 193 pr_warning("Failed to open debuginfo file.\n");
... ... @@ -300,7 +326,7 @@
300 326 * Show line-range always requires debuginfo to find source file and
301 327 * line number.
302 328 */
303   -int show_line_range(struct line_range *lr)
  329 +int show_line_range(struct line_range *lr, const char *module)
304 330 {
305 331 int l = 1;
306 332 struct line_node *ln;
... ... @@ -313,7 +339,7 @@
313 339 if (ret < 0)
314 340 return ret;
315 341  
316   - fd = open_vmlinux();
  342 + fd = open_vmlinux(module);
317 343 if (fd < 0) {
318 344 pr_warning("Failed to open debuginfo file.\n");
319 345 return fd;
... ... @@ -421,7 +447,7 @@
421 447  
422 448 /* Show available variables on given probe point */
423 449 int show_available_vars(struct perf_probe_event *pevs, int npevs,
424   - int max_vls, bool externs)
  450 + int max_vls, const char *module, bool externs)
425 451 {
426 452 int i, fd, ret = 0;
427 453  
... ... @@ -429,7 +455,7 @@
429 455 if (ret < 0)
430 456 return ret;
431 457  
432   - fd = open_vmlinux();
  458 + fd = open_vmlinux(module);
433 459 if (fd < 0) {
434 460 pr_warning("Failed to open debuginfo file.\n");
435 461 return fd;
436 462  
... ... @@ -447,8 +473,15 @@
447 473 #else /* !DWARF_SUPPORT */
448 474  
449 475 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
450   - struct perf_probe_point *pp)
  476 + struct perf_probe_point *pp)
451 477 {
  478 + struct symbol *sym;
  479 +
  480 + sym = __find_kernel_function_by_name(tp->symbol, NULL);
  481 + if (!sym) {
  482 + pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
  483 + return -ENOENT;
  484 + }
452 485 pp->function = strdup(tp->symbol);
453 486 if (pp->function == NULL)
454 487 return -ENOMEM;
... ... @@ -460,7 +493,7 @@
460 493  
461 494 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
462 495 struct probe_trace_event **tevs __unused,
463   - int max_tevs __unused)
  496 + int max_tevs __unused, const char *mod __unused)
464 497 {
465 498 if (perf_probe_event_need_dwarf(pev)) {
466 499 pr_warning("Debuginfo-analysis is not supported.\n");
467 500  
... ... @@ -469,14 +502,15 @@
469 502 return 0;
470 503 }
471 504  
472   -int show_line_range(struct line_range *lr __unused)
  505 +int show_line_range(struct line_range *lr __unused, const char *module __unused)
473 506 {
474 507 pr_warning("Debuginfo-analysis is not supported.\n");
475 508 return -ENOSYS;
476 509 }
477 510  
478 511 int show_available_vars(struct perf_probe_event *pevs __unused,
479   - int npevs __unused, int max_probe_points __unused)
  512 + int npevs __unused, int max_vls __unused,
  513 + const char *module __unused, bool externs __unused)
480 514 {
481 515 pr_warning("Debuginfo-analysis is not supported.\n");
482 516 return -ENOSYS;
... ... @@ -1159,7 +1193,7 @@
1159 1193 }
1160 1194  
1161 1195 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1162   - struct perf_probe_event *pev)
  1196 + struct perf_probe_event *pev)
1163 1197 {
1164 1198 char buf[64] = "";
1165 1199 int i, ret;
1166 1200  
... ... @@ -1588,14 +1622,14 @@
1588 1622  
1589 1623 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1590 1624 struct probe_trace_event **tevs,
1591   - int max_tevs)
  1625 + int max_tevs, const char *module)
1592 1626 {
1593 1627 struct symbol *sym;
1594 1628 int ret = 0, i;
1595 1629 struct probe_trace_event *tev;
1596 1630  
1597 1631 /* Convert perf_probe_event with debuginfo */
1598   - ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
  1632 + ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1599 1633 if (ret != 0)
1600 1634 return ret;
1601 1635  
... ... @@ -1644,8 +1678,7 @@
1644 1678 }
1645 1679  
1646 1680 /* Currently just checking function name from symbol map */
1647   - sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
1648   - tev->point.symbol, NULL);
  1681 + sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1649 1682 if (!sym) {
1650 1683 pr_warning("Kernel symbol \'%s\' not found.\n",
1651 1684 tev->point.symbol);
... ... @@ -1668,7 +1701,7 @@
1668 1701 };
1669 1702  
1670 1703 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1671   - int max_tevs, bool force_add)
  1704 + int max_tevs, const char *module, bool force_add)
1672 1705 {
1673 1706 int i, j, ret;
1674 1707 struct __event_package *pkgs;
... ... @@ -1689,7 +1722,9 @@
1689 1722 pkgs[i].pev = &pevs[i];
1690 1723 /* Convert with or without debuginfo */
1691 1724 ret = convert_to_probe_trace_events(pkgs[i].pev,
1692   - &pkgs[i].tevs, max_tevs);
  1725 + &pkgs[i].tevs,
  1726 + max_tevs,
  1727 + module);
1693 1728 if (ret < 0)
1694 1729 goto end;
1695 1730 pkgs[i].ntevs = ret;
tools/perf/util/probe-event.h
... ... @@ -115,14 +115,18 @@
115 115 /* Command string to line-range */
116 116 extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
117 117  
  118 +/* Internal use: Return kernel/module path */
  119 +extern const char *kernel_get_module_path(const char *module);
118 120  
119 121 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
120   - int max_probe_points, bool force_add);
  122 + int max_probe_points, const char *module,
  123 + bool force_add);
121 124 extern int del_perf_probe_events(struct strlist *dellist);
122 125 extern int show_perf_probe_events(void);
123   -extern int show_line_range(struct line_range *lr);
  126 +extern int show_line_range(struct line_range *lr, const char *module);
124 127 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
125   - int max_probe_points, bool externs);
  128 + int max_probe_points, const char *module,
  129 + bool externs);
126 130  
127 131  
128 132 /* Maximum index number of event-name postfix */
tools/perf/util/probe-finder.c
... ... @@ -116,6 +116,101 @@
116 116 }
117 117 }
118 118  
  119 +/* Dwarf FL wrappers */
  120 +
  121 +static int __linux_kernel_find_elf(Dwfl_Module *mod,
  122 + void **userdata,
  123 + const char *module_name,
  124 + Dwarf_Addr base,
  125 + char **file_name, Elf **elfp)
  126 +{
  127 + int fd;
  128 + const char *path = kernel_get_module_path(module_name);
  129 +
  130 + if (path) {
  131 + fd = open(path, O_RDONLY);
  132 + if (fd >= 0) {
  133 + *file_name = strdup(path);
  134 + return fd;
  135 + }
  136 + }
  137 + /* If failed, try to call standard method */
  138 + return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
  139 + file_name, elfp);
  140 +}
  141 +
  142 +static char *debuginfo_path; /* Currently dummy */
  143 +
  144 +static const Dwfl_Callbacks offline_callbacks = {
  145 + .find_debuginfo = dwfl_standard_find_debuginfo,
  146 + .debuginfo_path = &debuginfo_path,
  147 +
  148 + .section_address = dwfl_offline_section_address,
  149 +
  150 + /* We use this table for core files too. */
  151 + .find_elf = dwfl_build_id_find_elf,
  152 +};
  153 +
  154 +static const Dwfl_Callbacks kernel_callbacks = {
  155 + .find_debuginfo = dwfl_standard_find_debuginfo,
  156 + .debuginfo_path = &debuginfo_path,
  157 +
  158 + .find_elf = __linux_kernel_find_elf,
  159 + .section_address = dwfl_linux_kernel_module_section_address,
  160 +};
  161 +
  162 +/* Get a Dwarf from offline image */
  163 +static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
  164 +{
  165 + Dwfl_Module *mod;
  166 + Dwarf *dbg = NULL;
  167 +
  168 + if (!dwflp)
  169 + return NULL;
  170 +
  171 + *dwflp = dwfl_begin(&offline_callbacks);
  172 + if (!*dwflp)
  173 + return NULL;
  174 +
  175 + mod = dwfl_report_offline(*dwflp, "", "", fd);
  176 + if (!mod)
  177 + goto error;
  178 +
  179 + dbg = dwfl_module_getdwarf(mod, bias);
  180 + if (!dbg) {
  181 +error:
  182 + dwfl_end(*dwflp);
  183 + *dwflp = NULL;
  184 + }
  185 + return dbg;
  186 +}
  187 +
  188 +/* Get a Dwarf from live kernel image */
  189 +static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
  190 + Dwarf_Addr *bias)
  191 +{
  192 + Dwarf *dbg;
  193 +
  194 + if (!dwflp)
  195 + return NULL;
  196 +
  197 + *dwflp = dwfl_begin(&kernel_callbacks);
  198 + if (!*dwflp)
  199 + return NULL;
  200 +
  201 + /* Load the kernel dwarves: Don't care the result here */
  202 + dwfl_linux_kernel_report_kernel(*dwflp);
  203 + dwfl_linux_kernel_report_modules(*dwflp);
  204 +
  205 + dbg = dwfl_addrdwarf(*dwflp, addr, bias);
  206 + /* Here, check whether we could get a real dwarf */
  207 + if (!dbg) {
  208 + dwfl_end(*dwflp);
  209 + *dwflp = NULL;
  210 + }
  211 + return dbg;
  212 +}
  213 +
119 214 /* Dwarf wrappers */
120 215  
121 216 /* Find the realpath of the target file. */
122 217  
... ... @@ -1177,10 +1272,12 @@
1177 1272 Dwarf_Off off, noff;
1178 1273 size_t cuhl;
1179 1274 Dwarf_Die *diep;
1180   - Dwarf *dbg;
  1275 + Dwarf *dbg = NULL;
  1276 + Dwfl *dwfl;
  1277 + Dwarf_Addr bias; /* Currently ignored */
1181 1278 int ret = 0;
1182 1279  
1183   - dbg = dwarf_begin(fd, DWARF_C_READ);
  1280 + dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1184 1281 if (!dbg) {
1185 1282 pr_warning("No dwarf info found in the vmlinux - "
1186 1283 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
... ... @@ -1221,7 +1318,8 @@
1221 1318 off = noff;
1222 1319 }
1223 1320 line_list__free(&pf->lcache);
1224   - dwarf_end(dbg);
  1321 + if (dwfl)
  1322 + dwfl_end(dwfl);
1225 1323  
1226 1324 return ret;
1227 1325 }
1228 1326  
1229 1327  
1230 1328  
1231 1329  
1232 1330  
... ... @@ -1412,23 +1510,31 @@
1412 1510 }
1413 1511  
1414 1512 /* Reverse search */
1415   -int find_perf_probe_point(int fd, unsigned long addr,
1416   - struct perf_probe_point *ppt)
  1513 +int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1417 1514 {
1418 1515 Dwarf_Die cudie, spdie, indie;
1419   - Dwarf *dbg;
  1516 + Dwarf *dbg = NULL;
  1517 + Dwfl *dwfl = NULL;
1420 1518 Dwarf_Line *line;
1421   - Dwarf_Addr laddr, eaddr;
  1519 + Dwarf_Addr laddr, eaddr, bias = 0;
1422 1520 const char *tmp;
1423 1521 int lineno, ret = 0;
1424 1522 bool found = false;
1425 1523  
1426   - dbg = dwarf_begin(fd, DWARF_C_READ);
1427   - if (!dbg)
1428   - return -EBADF;
  1524 + /* Open the live linux kernel */
  1525 + dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
  1526 + if (!dbg) {
  1527 + pr_warning("No dwarf info found in the vmlinux - "
  1528 + "please rebuild with CONFIG_DEBUG_INFO=y.\n");
  1529 + ret = -EINVAL;
  1530 + goto end;
  1531 + }
1429 1532  
  1533 + /* Adjust address with bias */
  1534 + addr += bias;
1430 1535 /* Find cu die */
1431   - if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
  1536 + if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
  1537 + pr_warning("No CU DIE is found at %lx\n", addr);
1432 1538 ret = -EINVAL;
1433 1539 goto end;
1434 1540 }
... ... @@ -1491,7 +1597,8 @@
1491 1597 }
1492 1598  
1493 1599 end:
1494   - dwarf_end(dbg);
  1600 + if (dwfl)
  1601 + dwfl_end(dwfl);
1495 1602 if (ret >= 0)
1496 1603 ret = found ? 1 : 0;
1497 1604 return ret;
... ... @@ -1624,6 +1731,8 @@
1624 1731 struct line_finder *lf = param->data;
1625 1732 struct line_range *lr = lf->lr;
1626 1733  
  1734 + pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die),
  1735 + dwarf_diename(sp_die));
1627 1736 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1628 1737 die_compare_name(sp_die, lr->function)) {
1629 1738 lf->fname = dwarf_decl_file(sp_die);
1630 1739  
... ... @@ -1667,10 +1776,12 @@
1667 1776 Dwarf_Off off = 0, noff;
1668 1777 size_t cuhl;
1669 1778 Dwarf_Die *diep;
1670   - Dwarf *dbg;
  1779 + Dwarf *dbg = NULL;
  1780 + Dwfl *dwfl;
  1781 + Dwarf_Addr bias; /* Currently ignored */
1671 1782 const char *comp_dir;
1672 1783  
1673   - dbg = dwarf_begin(fd, DWARF_C_READ);
  1784 + dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1674 1785 if (!dbg) {
1675 1786 pr_warning("No dwarf info found in the vmlinux - "
1676 1787 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
... ... @@ -1716,8 +1827,7 @@
1716 1827 }
1717 1828  
1718 1829 pr_debug("path: %s\n", lr->path);
1719   - dwarf_end(dbg);
1720   -
  1830 + dwfl_end(dwfl);
1721 1831 return (ret < 0) ? ret : lf.found;
1722 1832 }
tools/perf/util/probe-finder.h
... ... @@ -22,7 +22,7 @@
22 22 int max_tevs);
23 23  
24 24 /* Find a perf_probe_point from debuginfo */
25   -extern int find_perf_probe_point(int fd, unsigned long addr,
  25 +extern int find_perf_probe_point(unsigned long addr,
26 26 struct perf_probe_point *ppt);
27 27  
28 28 /* Find a line range */
... ... @@ -35,6 +35,7 @@
35 35  
36 36 #include <dwarf.h>
37 37 #include <libdw.h>
  38 +#include <libdwfl.h>
38 39 #include <version.h>
39 40  
40 41 struct probe_finder {