aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-probe.c2
-rw-r--r--tools/perf/util/probe-event.c151
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c1
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 */
176static 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
193static 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;
216out:
217 elf_end(elf);
218 return ret;
219}
220
175static int init_user_exec(void) 221static 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
235static 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
261out:
262 free(exec_copy);
263 return ret;
264}
265
189static int convert_to_perf_probe_point(struct probe_trace_point *tp, 266static 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
341static 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
264static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 375static 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;