aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/util/dso.h10
-rw-r--r--tools/perf/util/map.h10
-rw-r--r--tools/perf/util/probe-event.c378
-rw-r--r--tools/perf/util/symbol.h11
4 files changed, 204 insertions, 205 deletions
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index cd7d6f078cdd..ab06f1c03655 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -102,6 +102,16 @@ struct dso {
102 char name[0]; 102 char name[0];
103}; 103};
104 104
105/* dso__for_each_symbol - iterate over the symbols of given type
106 *
107 * @dso: the 'struct dso *' in which symbols itereated
108 * @pos: the 'struct symbol *' to use as a loop cursor
109 * @n: the 'struct rb_node *' to use as a temporary storage
110 * @type: the 'enum map_type' type of symbols
111 */
112#define dso__for_each_symbol(dso, pos, n, type) \
113 symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
114
105static inline void dso__set_loaded(struct dso *dso, enum map_type type) 115static inline void dso__set_loaded(struct dso *dso, enum map_type type)
106{ 116{
107 dso->loaded |= (1 << type); 117 dso->loaded |= (1 << type);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 257e513205ce..f00f058afb3b 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
90 90
91struct symbol; 91struct symbol;
92 92
93/* map__for_each_symbol - iterate over the symbols in the given map
94 *
95 * @map: the 'struct map *' in which symbols itereated
96 * @pos: the 'struct symbol *' to use as a loop cursor
97 * @n: the 'struct rb_node *' to use as a temporary storage
98 * Note: caller must ensure map->dso is not NULL (map is loaded).
99 */
100#define map__for_each_symbol(map, pos, n) \
101 dso__for_each_symbol(map->dso, pos, n, map->type)
102
93typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 103typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
94 104
95void map__init(struct map *map, enum map_type type, 105void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 3c35b7af2adb..42bec67aaa38 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,8 +70,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
70} 70}
71 71
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 72static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
73static int convert_name_to_addr(struct perf_probe_event *pev,
74 const char *exec);
75static void clear_probe_trace_event(struct probe_trace_event *tev); 73static void clear_probe_trace_event(struct probe_trace_event *tev);
76static struct machine *host_machine; 74static struct machine *host_machine;
77 75
@@ -249,6 +247,14 @@ out:
249 return ret; 247 return ret;
250} 248}
251 249
250static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
251{
252 int i;
253
254 for (i = 0; i < ntevs; i++)
255 clear_probe_trace_event(tevs + i);
256}
257
252#ifdef HAVE_DWARF_SUPPORT 258#ifdef HAVE_DWARF_SUPPORT
253/* Open new debuginfo of given module */ 259/* Open new debuginfo of given module */
254static struct debuginfo *open_debuginfo(const char *module) 260static struct debuginfo *open_debuginfo(const char *module)
@@ -353,8 +359,7 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
353 int ntevs, const char *exec) 359 int ntevs, const char *exec)
354{ 360{
355 int i, ret = 0; 361 int i, ret = 0;
356 unsigned long offset, stext = 0; 362 unsigned long stext = 0;
357 char buf[32];
358 363
359 if (!exec) 364 if (!exec)
360 return 0; 365 return 0;
@@ -365,15 +370,9 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
365 370
366 for (i = 0; i < ntevs && ret >= 0; i++) { 371 for (i = 0; i < ntevs && ret >= 0; i++) {
367 /* point.address is the addres of point.symbol + point.offset */ 372 /* point.address is the addres of point.symbol + point.offset */
368 offset = tevs[i].point.address - stext; 373 tevs[i].point.address -= stext;
369 tevs[i].point.offset = 0;
370 zfree(&tevs[i].point.symbol);
371 ret = e_snprintf(buf, 32, "0x%lx", offset);
372 if (ret < 0)
373 break;
374 tevs[i].point.module = strdup(exec); 374 tevs[i].point.module = strdup(exec);
375 tevs[i].point.symbol = strdup(buf); 375 if (!tevs[i].point.module) {
376 if (!tevs[i].point.symbol || !tevs[i].point.module) {
377 ret = -ENOMEM; 376 ret = -ENOMEM;
378 break; 377 break;
379 } 378 }
@@ -452,14 +451,6 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
452 return 0; 451 return 0;
453} 452}
454 453
455static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
456{
457 int i;
458
459 for (i = 0; i < ntevs; i++)
460 clear_probe_trace_event(tevs + i);
461}
462
463/* Try to find perf_probe_event with debuginfo */ 454/* Try to find perf_probe_event with debuginfo */
464static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 455static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
465 struct probe_trace_event **tevs, 456 struct probe_trace_event **tevs,
@@ -1586,20 +1577,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1586 if (buf == NULL) 1577 if (buf == NULL)
1587 return NULL; 1578 return NULL;
1588 1579
1580 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
1581 tev->group, tev->event);
1582 if (len <= 0)
1583 goto error;
1584
1585 /* Uprobes must have tp->address and tp->module */
1586 if (tev->uprobes && (!tp->address || !tp->module))
1587 goto error;
1588
1589 /* Use the tp->address for uprobes */
1589 if (tev->uprobes) 1590 if (tev->uprobes)
1590 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", 1591 ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
1591 tp->retprobe ? 'r' : 'p', 1592 tp->module, tp->address);
1592 tev->group, tev->event,
1593 tp->module, tp->symbol);
1594 else 1593 else
1595 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 1594 ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
1596 tp->retprobe ? 'r' : 'p',
1597 tev->group, tev->event,
1598 tp->module ?: "", tp->module ? ":" : "", 1595 tp->module ?: "", tp->module ? ":" : "",
1599 tp->symbol, tp->offset); 1596 tp->symbol, tp->offset);
1600 1597
1601 if (len <= 0) 1598 if (ret <= 0)
1602 goto error; 1599 goto error;
1600 len += ret;
1603 1601
1604 for (i = 0; i < tev->nargs; i++) { 1602 for (i = 0; i < tev->nargs; i++) {
1605 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 1603 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -2150,113 +2148,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
2150 return ret; 2148 return ret;
2151} 2149}
2152 2150
2153static int convert_to_probe_trace_events(struct perf_probe_event *pev, 2151static char *looking_function_name;
2154 struct probe_trace_event **tevs, 2152static int num_matched_functions;
2155 int max_tevs, const char *target) 2153
2154static int probe_function_filter(struct map *map __maybe_unused,
2155 struct symbol *sym)
2156{
2157 if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
2158 strcmp(looking_function_name, sym->name) == 0) {
2159 num_matched_functions++;
2160 return 0;
2161 }
2162 return 1;
2163}
2164
2165#define strdup_or_goto(str, label) \
2166 ({ char *__p = strdup(str); if (!__p) goto label; __p; })
2167
2168/*
2169 * Find probe function addresses from map.
2170 * Return an error or the number of found probe_trace_event
2171 */
2172static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2173 struct probe_trace_event **tevs,
2174 int max_tevs, const char *target)
2156{ 2175{
2176 struct map *map = NULL;
2177 struct kmap *kmap = NULL;
2178 struct ref_reloc_sym *reloc_sym = NULL;
2157 struct symbol *sym; 2179 struct symbol *sym;
2158 int ret, i; 2180 struct rb_node *nd;
2159 struct probe_trace_event *tev; 2181 struct probe_trace_event *tev;
2182 struct perf_probe_point *pp = &pev->point;
2183 struct probe_trace_point *tp;
2184 int ret, i;
2160 2185
2161 if (pev->uprobes && !pev->group) { 2186 /* Init maps of given executable or kernel */
2162 /* Replace group name if not given */ 2187 if (pev->uprobes)
2163 ret = convert_exec_to_group(target, &pev->group); 2188 map = dso__new_map(target);
2164 if (ret != 0) { 2189 else
2165 pr_warning("Failed to make a group name.\n"); 2190 map = kernel_get_module_map(target);
2166 return ret; 2191 if (!map) {
2167 } 2192 ret = -EINVAL;
2193 goto out;
2168 } 2194 }
2169 2195
2170 /* Convert perf_probe_event with debuginfo */ 2196 /*
2171 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2197 * Load matched symbols: Since the different local symbols may have
2172 if (ret != 0) 2198 * same name but different addresses, this lists all the symbols.
2173 return ret; /* Found in debuginfo or got an error */ 2199 */
2174 2200 num_matched_functions = 0;
2175 if (pev->uprobes) { 2201 looking_function_name = pp->function;
2176 ret = convert_name_to_addr(pev, target); 2202 ret = map__load(map, probe_function_filter);
2177 if (ret < 0) 2203 if (ret || num_matched_functions == 0) {
2178 return ret; 2204 pr_err("Failed to find symbol %s in %s\n", pp->function,
2205 target ? : "kernel");
2206 ret = -ENOENT;
2207 goto out;
2208 } else if (num_matched_functions > max_tevs) {
2209 pr_err("Too many functions matched in %s\n",
2210 target ? : "kernel");
2211 ret = -E2BIG;
2212 goto out;
2179 } 2213 }
2180 2214
2181 /* Allocate trace event buffer */ 2215 if (!pev->uprobes) {
2182 tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 2216 kmap = map__kmap(map);
2183 if (tev == NULL) 2217 reloc_sym = kmap->ref_reloc_sym;
2184 return -ENOMEM; 2218 if (!reloc_sym) {
2219 pr_warning("Relocated base symbol is not found!\n");
2220 ret = -EINVAL;
2221 goto out;
2222 }
2223 }
2185 2224
2186 /* Copy parameters */ 2225 /* Setup result trace-probe-events */
2187 tev->point.symbol = strdup(pev->point.function); 2226 *tevs = zalloc(sizeof(*tev) * num_matched_functions);
2188 if (tev->point.symbol == NULL) { 2227 if (!*tevs) {
2189 ret = -ENOMEM; 2228 ret = -ENOMEM;
2190 goto error; 2229 goto out;
2191 } 2230 }
2192 2231
2193 if (target) { 2232 ret = 0;
2194 tev->point.module = strdup(target); 2233 map__for_each_symbol(map, sym, nd) {
2195 if (tev->point.module == NULL) { 2234 tev = (*tevs) + ret;
2196 ret = -ENOMEM; 2235 tp = &tev->point;
2197 goto error; 2236 if (ret == num_matched_functions) {
2237 pr_warning("Too many symbols are listed. Skip it.\n");
2238 break;
2198 } 2239 }
2199 } 2240 ret++;
2200 2241
2201 tev->point.offset = pev->point.offset; 2242 if (pp->offset > sym->end - sym->start) {
2202 tev->point.retprobe = pev->point.retprobe; 2243 pr_warning("Offset %ld is bigger than the size of %s\n",
2203 tev->nargs = pev->nargs; 2244 pp->offset, sym->name);
2204 tev->uprobes = pev->uprobes; 2245 ret = -ENOENT;
2205 2246 goto err_out;
2206 if (tev->nargs) { 2247 }
2207 tev->args = zalloc(sizeof(struct probe_trace_arg) 2248 /* Add one probe point */
2208 * tev->nargs); 2249 tp->address = map->unmap_ip(map, sym->start) + pp->offset;
2209 if (tev->args == NULL) { 2250 if (reloc_sym) {
2210 ret = -ENOMEM; 2251 tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
2211 goto error; 2252 tp->offset = tp->address - reloc_sym->addr;
2253 } else {
2254 tp->symbol = strdup_or_goto(sym->name, nomem_out);
2255 tp->offset = pp->offset;
2256 }
2257 tp->retprobe = pp->retprobe;
2258 if (target)
2259 tev->point.module = strdup_or_goto(target, nomem_out);
2260 tev->uprobes = pev->uprobes;
2261 tev->nargs = pev->nargs;
2262 if (tev->nargs) {
2263 tev->args = zalloc(sizeof(struct probe_trace_arg) *
2264 tev->nargs);
2265 if (tev->args == NULL)
2266 goto nomem_out;
2212 } 2267 }
2213 for (i = 0; i < tev->nargs; i++) { 2268 for (i = 0; i < tev->nargs; i++) {
2214 if (pev->args[i].name) { 2269 if (pev->args[i].name)
2215 tev->args[i].name = strdup(pev->args[i].name); 2270 tev->args[i].name =
2216 if (tev->args[i].name == NULL) { 2271 strdup_or_goto(pev->args[i].name,
2217 ret = -ENOMEM; 2272 nomem_out);
2218 goto error; 2273
2219 } 2274 tev->args[i].value = strdup_or_goto(pev->args[i].var,
2220 } 2275 nomem_out);
2221 tev->args[i].value = strdup(pev->args[i].var); 2276 if (pev->args[i].type)
2222 if (tev->args[i].value == NULL) { 2277 tev->args[i].type =
2223 ret = -ENOMEM; 2278 strdup_or_goto(pev->args[i].type,
2224 goto error; 2279 nomem_out);
2225 }
2226 if (pev->args[i].type) {
2227 tev->args[i].type = strdup(pev->args[i].type);
2228 if (tev->args[i].type == NULL) {
2229 ret = -ENOMEM;
2230 goto error;
2231 }
2232 }
2233 } 2280 }
2234 } 2281 }
2235 2282
2236 if (pev->uprobes) 2283out:
2237 return 1; 2284 if (map && pev->uprobes) {
2285 /* Only when using uprobe(exec) map needs to be released */
2286 dso__delete(map->dso);
2287 map__delete(map);
2288 }
2289 return ret;
2238 2290
2239 /* Currently just checking function name from symbol map */ 2291nomem_out:
2240 sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 2292 ret = -ENOMEM;
2241 if (!sym) { 2293err_out:
2242 pr_warning("Kernel symbol \'%s\' not found.\n", 2294 clear_probe_trace_events(*tevs, num_matched_functions);
2243 tev->point.symbol); 2295 zfree(tevs);
2244 ret = -ENOENT; 2296 goto out;
2245 goto error; 2297}
2246 } else if (tev->point.offset > sym->end - sym->start) {
2247 pr_warning("Offset specified is greater than size of %s\n",
2248 tev->point.symbol);
2249 ret = -ENOENT;
2250 goto error;
2251 2298
2299static int convert_to_probe_trace_events(struct perf_probe_event *pev,
2300 struct probe_trace_event **tevs,
2301 int max_tevs, const char *target)
2302{
2303 int ret;
2304
2305 if (pev->uprobes && !pev->group) {
2306 /* Replace group name if not given */
2307 ret = convert_exec_to_group(target, &pev->group);
2308 if (ret != 0) {
2309 pr_warning("Failed to make a group name.\n");
2310 return ret;
2311 }
2252 } 2312 }
2253 2313
2254 return 1; 2314 /* Convert perf_probe_event with debuginfo */
2255error: 2315 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
2256 clear_probe_trace_event(tev); 2316 if (ret != 0)
2257 free(tev); 2317 return ret; /* Found in debuginfo or got an error */
2258 *tevs = NULL; 2318
2259 return ret; 2319 return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
2260} 2320}
2261 2321
2262struct __event_package { 2322struct __event_package {
@@ -2461,7 +2521,7 @@ static struct strfilter *available_func_filter;
2461static int filter_available_functions(struct map *map __maybe_unused, 2521static int filter_available_functions(struct map *map __maybe_unused,
2462 struct symbol *sym) 2522 struct symbol *sym)
2463{ 2523{
2464 if (sym->binding == STB_GLOBAL && 2524 if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
2465 strfilter__compare(available_func_filter, sym->name)) 2525 strfilter__compare(available_func_filter, sym->name))
2466 return 0; 2526 return 0;
2467 return 1; 2527 return 1;
@@ -2509,95 +2569,3 @@ end:
2509 return ret; 2569 return ret;
2510} 2570}
2511 2571
2512/*
2513 * uprobe_events only accepts address:
2514 * Convert function and any offset to address
2515 */
2516static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2517{
2518 struct perf_probe_point *pp = &pev->point;
2519 struct symbol *sym;
2520 struct map *map = NULL;
2521 char *function = NULL;
2522 int ret = -EINVAL;
2523 unsigned long long vaddr = 0;
2524
2525 if (!pp->function) {
2526 pr_warning("No function specified for uprobes");
2527 goto out;
2528 }
2529
2530 function = strdup(pp->function);
2531 if (!function) {
2532 pr_warning("Failed to allocate memory by strdup.\n");
2533 ret = -ENOMEM;
2534 goto out;
2535 }
2536
2537 map = dso__new_map(exec);
2538 if (!map) {
2539 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2540 goto out;
2541 }
2542 available_func_filter = strfilter__new(function, NULL);
2543 if (map__load(map, filter_available_functions)) {
2544 pr_err("Failed to load map.\n");
2545 goto out;
2546 }
2547
2548 sym = map__find_symbol_by_name(map, function, NULL);
2549 if (!sym) {
2550 pr_warning("Cannot find %s in DSO %s\n", function, exec);
2551 goto out;
2552 }
2553
2554 if (map->start > sym->start)
2555 vaddr = map->start;
2556 vaddr += sym->start + pp->offset + map->pgoff;
2557 pp->offset = 0;
2558
2559 if (!pev->event) {
2560 pev->event = function;
2561 function = NULL;
2562 }
2563 if (!pev->group) {
2564 char *ptr1, *ptr2, *exec_copy;
2565
2566 pev->group = zalloc(sizeof(char *) * 64);
2567 exec_copy = strdup(exec);
2568 if (!exec_copy) {
2569 ret = -ENOMEM;
2570 pr_warning("Failed to copy exec string.\n");
2571 goto out;
2572 }
2573
2574 ptr1 = strdup(basename(exec_copy));
2575 if (ptr1) {
2576 ptr2 = strpbrk(ptr1, "-._");
2577 if (ptr2)
2578 *ptr2 = '\0';
2579 e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2580 ptr1);
2581 free(ptr1);
2582 }
2583 free(exec_copy);
2584 }
2585 free(pp->function);
2586 pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2587 if (!pp->function) {
2588 ret = -ENOMEM;
2589 pr_warning("Failed to allocate memory by zalloc.\n");
2590 goto out;
2591 }
2592 e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
2593 ret = 0;
2594
2595out:
2596 if (map) {
2597 dso__delete(map->dso);
2598 map__delete(map);
2599 }
2600 if (function)
2601 free(function);
2602 return ret;
2603}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 538d484fa6c5..2553ae04b788 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -79,6 +79,17 @@ struct symbol {
79void symbol__delete(struct symbol *sym); 79void symbol__delete(struct symbol *sym);
80void symbols__delete(struct rb_root *symbols); 80void symbols__delete(struct rb_root *symbols);
81 81
82/* symbols__for_each_entry - iterate over symbols (rb_root)
83 *
84 * @symbols: the rb_root of symbols
85 * @pos: the 'struct symbol *' to use as a loop cursor
86 * @nd: the 'struct rb_node *' to use as a temporary storage
87 */
88#define symbols__for_each_entry(symbols, pos, nd) \
89 for (nd = rb_first(symbols); \
90 nd && (pos = rb_entry(nd, struct symbol, rb_node)); \
91 nd = rb_next(nd))
92
82static inline size_t symbol__size(const struct symbol *sym) 93static inline size_t symbol__size(const struct symbol *sym)
83{ 94{
84 return sym->end - sym->start + 1; 95 return sym->end - sym->start + 1;