diff options
-rw-r--r-- | tools/perf/util/dso.h | 10 | ||||
-rw-r--r-- | tools/perf/util/map.h | 10 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 378 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 11 |
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 | |||
105 | static inline void dso__set_loaded(struct dso *dso, enum map_type type) | 115 | static 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 | ||
91 | struct symbol; | 91 | struct 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 | |||
93 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | 103 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); |
94 | 104 | ||
95 | void map__init(struct map *map, enum map_type type, | 105 | void 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 | ||
72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
73 | static int convert_name_to_addr(struct perf_probe_event *pev, | ||
74 | const char *exec); | ||
75 | static void clear_probe_trace_event(struct probe_trace_event *tev); | 73 | static void clear_probe_trace_event(struct probe_trace_event *tev); |
76 | static struct machine *host_machine; | 74 | static struct machine *host_machine; |
77 | 75 | ||
@@ -249,6 +247,14 @@ out: | |||
249 | return ret; | 247 | return ret; |
250 | } | 248 | } |
251 | 249 | ||
250 | static 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 */ |
254 | static struct debuginfo *open_debuginfo(const char *module) | 260 | static 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 | ||
455 | static 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 */ |
464 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 455 | static 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 | ||
2153 | static int convert_to_probe_trace_events(struct perf_probe_event *pev, | 2151 | static char *looking_function_name; |
2154 | struct probe_trace_event **tevs, | 2152 | static int num_matched_functions; |
2155 | int max_tevs, const char *target) | 2153 | |
2154 | static 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 | */ | ||
2172 | static 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) | 2283 | out: |
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 */ | 2291 | nomem_out: |
2240 | sym = __find_kernel_function_by_name(tev->point.symbol, NULL); | 2292 | ret = -ENOMEM; |
2241 | if (!sym) { | 2293 | err_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 | ||
2299 | static 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 */ |
2255 | error: | 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 | ||
2262 | struct __event_package { | 2322 | struct __event_package { |
@@ -2461,7 +2521,7 @@ static struct strfilter *available_func_filter; | |||
2461 | static int filter_available_functions(struct map *map __maybe_unused, | 2521 | static 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 | */ | ||
2516 | static 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 | |||
2595 | out: | ||
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 { | |||
79 | void symbol__delete(struct symbol *sym); | 79 | void symbol__delete(struct symbol *sym); |
80 | void symbols__delete(struct rb_root *symbols); | 80 | void 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 | |||
82 | static inline size_t symbol__size(const struct symbol *sym) | 93 | static 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; |