diff options
-rw-r--r-- | tools/perf/builtin-probe.c | 2 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 151 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 1 |
4 files changed, 138 insertions, 17 deletions
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 1792a3f1f4ce..43ff33d0007b 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -424,7 +424,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
424 | } | 424 | } |
425 | 425 | ||
426 | #ifdef HAVE_DWARF_SUPPORT | 426 | #ifdef HAVE_DWARF_SUPPORT |
427 | if (params.show_lines && !params.uprobes) { | 427 | if (params.show_lines) { |
428 | if (params.mod_events) { | 428 | if (params.mod_events) { |
429 | pr_err(" Error: Don't use --line with" | 429 | pr_err(" Error: Don't use --line with" |
430 | " --add/--del.\n"); | 430 | " --add/--del.\n"); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 68013b91377c..72b56aef105e 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -172,6 +172,52 @@ const char *kernel_get_module_path(const char *module) | |||
172 | return (dso) ? dso->long_name : NULL; | 172 | return (dso) ? dso->long_name : NULL; |
173 | } | 173 | } |
174 | 174 | ||
175 | /* Copied from unwind.c */ | ||
176 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
177 | GElf_Shdr *shp, const char *name) | ||
178 | { | ||
179 | Elf_Scn *sec = NULL; | ||
180 | |||
181 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
182 | char *str; | ||
183 | |||
184 | gelf_getshdr(sec, shp); | ||
185 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
186 | if (!strcmp(name, str)) | ||
187 | break; | ||
188 | } | ||
189 | |||
190 | return sec; | ||
191 | } | ||
192 | |||
193 | static int get_text_start_address(const char *exec, unsigned long *address) | ||
194 | { | ||
195 | Elf *elf; | ||
196 | GElf_Ehdr ehdr; | ||
197 | GElf_Shdr shdr; | ||
198 | int fd, ret = -ENOENT; | ||
199 | |||
200 | fd = open(exec, O_RDONLY); | ||
201 | if (fd < 0) | ||
202 | return -errno; | ||
203 | |||
204 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
205 | if (elf == NULL) | ||
206 | return -EINVAL; | ||
207 | |||
208 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
209 | goto out; | ||
210 | |||
211 | if (!elf_section_by_name(elf, &ehdr, &shdr, ".text")) | ||
212 | goto out; | ||
213 | |||
214 | *address = shdr.sh_addr - shdr.sh_offset; | ||
215 | ret = 0; | ||
216 | out: | ||
217 | elf_end(elf); | ||
218 | return ret; | ||
219 | } | ||
220 | |||
175 | static int init_user_exec(void) | 221 | static int init_user_exec(void) |
176 | { | 222 | { |
177 | int ret = 0; | 223 | int ret = 0; |
@@ -186,6 +232,37 @@ static int init_user_exec(void) | |||
186 | return ret; | 232 | return ret; |
187 | } | 233 | } |
188 | 234 | ||
235 | static int convert_exec_to_group(const char *exec, char **result) | ||
236 | { | ||
237 | char *ptr1, *ptr2, *exec_copy; | ||
238 | char buf[64]; | ||
239 | int ret; | ||
240 | |||
241 | exec_copy = strdup(exec); | ||
242 | if (!exec_copy) | ||
243 | return -ENOMEM; | ||
244 | |||
245 | ptr1 = basename(exec_copy); | ||
246 | if (!ptr1) { | ||
247 | ret = -EINVAL; | ||
248 | goto out; | ||
249 | } | ||
250 | |||
251 | ptr2 = strpbrk(ptr1, "-._"); | ||
252 | if (ptr2) | ||
253 | *ptr2 = '\0'; | ||
254 | ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); | ||
255 | if (ret < 0) | ||
256 | goto out; | ||
257 | |||
258 | *result = strdup(buf); | ||
259 | ret = *result ? 0 : -ENOMEM; | ||
260 | |||
261 | out: | ||
262 | free(exec_copy); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
189 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | 266 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, |
190 | struct perf_probe_point *pp) | 267 | struct perf_probe_point *pp) |
191 | { | 268 | { |
@@ -261,6 +338,40 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
261 | return 0; | 338 | return 0; |
262 | } | 339 | } |
263 | 340 | ||
341 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | ||
342 | int ntevs, const char *exec) | ||
343 | { | ||
344 | int i, ret = 0; | ||
345 | unsigned long offset, stext = 0; | ||
346 | char buf[32]; | ||
347 | |||
348 | if (!exec) | ||
349 | return 0; | ||
350 | |||
351 | ret = get_text_start_address(exec, &stext); | ||
352 | if (ret < 0) | ||
353 | return ret; | ||
354 | |||
355 | for (i = 0; i < ntevs && ret >= 0; i++) { | ||
356 | offset = tevs[i].point.address - stext; | ||
357 | offset += tevs[i].point.offset; | ||
358 | tevs[i].point.offset = 0; | ||
359 | free(tevs[i].point.symbol); | ||
360 | ret = e_snprintf(buf, 32, "0x%lx", offset); | ||
361 | if (ret < 0) | ||
362 | break; | ||
363 | tevs[i].point.module = strdup(exec); | ||
364 | tevs[i].point.symbol = strdup(buf); | ||
365 | if (!tevs[i].point.symbol || !tevs[i].point.module) { | ||
366 | ret = -ENOMEM; | ||
367 | break; | ||
368 | } | ||
369 | tevs[i].uprobes = true; | ||
370 | } | ||
371 | |||
372 | return ret; | ||
373 | } | ||
374 | |||
264 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 375 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, |
265 | int ntevs, const char *module) | 376 | int ntevs, const char *module) |
266 | { | 377 | { |
@@ -305,15 +416,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
305 | struct debuginfo *dinfo; | 416 | struct debuginfo *dinfo; |
306 | int ntevs, ret = 0; | 417 | int ntevs, ret = 0; |
307 | 418 | ||
308 | if (pev->uprobes) { | ||
309 | if (need_dwarf) { | ||
310 | pr_warning("Debuginfo-analysis is not yet supported" | ||
311 | " with -x/--exec option.\n"); | ||
312 | return -ENOSYS; | ||
313 | } | ||
314 | return convert_name_to_addr(pev, target); | ||
315 | } | ||
316 | |||
317 | dinfo = open_debuginfo(target); | 419 | dinfo = open_debuginfo(target); |
318 | 420 | ||
319 | if (!dinfo) { | 421 | if (!dinfo) { |
@@ -332,9 +434,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
332 | 434 | ||
333 | if (ntevs > 0) { /* Succeeded to find trace events */ | 435 | if (ntevs > 0) { /* Succeeded to find trace events */ |
334 | pr_debug("find %d probe_trace_events.\n", ntevs); | 436 | pr_debug("find %d probe_trace_events.\n", ntevs); |
335 | if (target) | 437 | if (target) { |
336 | ret = add_module_to_probe_trace_events(*tevs, ntevs, | 438 | if (pev->uprobes) |
337 | target); | 439 | ret = add_exec_to_probe_trace_events(*tevs, |
440 | ntevs, target); | ||
441 | else | ||
442 | ret = add_module_to_probe_trace_events(*tevs, | ||
443 | ntevs, target); | ||
444 | } | ||
338 | return ret < 0 ? ret : ntevs; | 445 | return ret < 0 ? ret : ntevs; |
339 | } | 446 | } |
340 | 447 | ||
@@ -654,9 +761,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
654 | return -ENOSYS; | 761 | return -ENOSYS; |
655 | } | 762 | } |
656 | 763 | ||
657 | if (pev->uprobes) | ||
658 | return convert_name_to_addr(pev, target); | ||
659 | |||
660 | return 0; | 764 | return 0; |
661 | } | 765 | } |
662 | 766 | ||
@@ -1913,14 +2017,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1913 | int max_tevs, const char *target) | 2017 | int max_tevs, const char *target) |
1914 | { | 2018 | { |
1915 | struct symbol *sym; | 2019 | struct symbol *sym; |
1916 | int ret = 0, i; | 2020 | int ret, i; |
1917 | struct probe_trace_event *tev; | 2021 | struct probe_trace_event *tev; |
1918 | 2022 | ||
2023 | if (pev->uprobes && !pev->group) { | ||
2024 | /* Replace group name if not given */ | ||
2025 | ret = convert_exec_to_group(target, &pev->group); | ||
2026 | if (ret != 0) { | ||
2027 | pr_warning("Failed to make a group name.\n"); | ||
2028 | return ret; | ||
2029 | } | ||
2030 | } | ||
2031 | |||
1919 | /* Convert perf_probe_event with debuginfo */ | 2032 | /* Convert perf_probe_event with debuginfo */ |
1920 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); | 2033 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); |
1921 | if (ret != 0) | 2034 | if (ret != 0) |
1922 | return ret; /* Found in debuginfo or got an error */ | 2035 | return ret; /* Found in debuginfo or got an error */ |
1923 | 2036 | ||
2037 | if (pev->uprobes) { | ||
2038 | ret = convert_name_to_addr(pev, target); | ||
2039 | if (ret < 0) | ||
2040 | return ret; | ||
2041 | } | ||
2042 | |||
1924 | /* Allocate trace event buffer */ | 2043 | /* Allocate trace event buffer */ |
1925 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); | 2044 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); |
1926 | if (tev == NULL) | 2045 | if (tev == NULL) |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f9f3de8b4220..d481c46e0796 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -12,6 +12,7 @@ struct probe_trace_point { | |||
12 | char *symbol; /* Base symbol */ | 12 | char *symbol; /* Base symbol */ |
13 | char *module; /* Module name */ | 13 | char *module; /* Module name */ |
14 | unsigned long offset; /* Offset from symbol */ | 14 | unsigned long offset; /* Offset from symbol */ |
15 | unsigned long address; /* Actual address of the trace point */ | ||
15 | bool retprobe; /* Return probe flag */ | 16 | bool retprobe; /* Return probe flag */ |
16 | }; | 17 | }; |
17 | 18 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ffb657ffd327..7db7e05ccb89 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -729,6 +729,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, | |||
729 | return -ENOENT; | 729 | return -ENOENT; |
730 | } | 730 | } |
731 | tp->offset = (unsigned long)(paddr - sym.st_value); | 731 | tp->offset = (unsigned long)(paddr - sym.st_value); |
732 | tp->address = (unsigned long)paddr; | ||
732 | tp->symbol = strdup(symbol); | 733 | tp->symbol = strdup(symbol); |
733 | if (!tp->symbol) | 734 | if (!tp->symbol) |
734 | return -ENOMEM; | 735 | return -ENOMEM; |