diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 177 |
1 files changed, 98 insertions, 79 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index abf5845a2acc..a2d8cefc597c 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -51,6 +51,7 @@ #define PERFPROBE_GROUP "probe" bool probe_event_dry_run; /* Dry run flag */ +struct probe_conf probe_conf; #define semantic_error(msg ...) pr_err("Semantic error :" msg) @@ -344,15 +345,14 @@ out: static int get_alternative_probe_event(struct debuginfo *dinfo, struct perf_probe_event *pev, - struct perf_probe_point *tmp, - const char *target) + struct perf_probe_point *tmp) { int ret; memcpy(tmp, &pev->point, sizeof(*tmp)); memset(&pev->point, 0, sizeof(pev->point)); ret = find_alternative_probe_point(dinfo, tmp, &pev->point, - target, pev->uprobes); + pev->target, pev->uprobes); if (ret < 0) memcpy(&pev->point, tmp, sizeof(*tmp)); @@ -557,8 +557,9 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, bool uprobe) { struct ref_reloc_sym *reloc_sym; + u64 etext_addr; char *tmp; - int i; + int i, skipped = 0; if (uprobe) return add_exec_to_probe_trace_events(tevs, ntevs, module); @@ -572,33 +573,45 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, pr_warning("Relocated base symbol is not found!\n"); return -EINVAL; } + /* Get the address of _etext for checking non-probable text symbol */ + etext_addr = kernel_get_symbol_address_by_name("_etext", false); for (i = 0; i < ntevs; i++) { if (tevs[i].point.address && !tevs[i].point.retprobe) { - tmp = strdup(reloc_sym->name); - if (!tmp) - return -ENOMEM; - free(tevs[i].point.symbol); + /* If we found a wrong one, mark it by NULL symbol */ + if (etext_addr < tevs[i].point.address) { + pr_warning("%s+%lu is out of .text, skip it.\n", + tevs[i].point.symbol, tevs[i].point.offset); + tmp = NULL; + skipped++; + } else { + tmp = strdup(reloc_sym->name); + if (!tmp) + return -ENOMEM; + } + /* If we have no realname, use symbol for it */ + if (!tevs[i].point.realname) + tevs[i].point.realname = tevs[i].point.symbol; + else + free(tevs[i].point.symbol); tevs[i].point.symbol = tmp; tevs[i].point.offset = tevs[i].point.address - reloc_sym->unrelocated_addr; } } - return 0; + return skipped; } /* Try to find perf_probe_event with debuginfo */ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event **tevs, - int max_tevs, const char *target) + struct probe_trace_event **tevs) { bool need_dwarf = perf_probe_event_need_dwarf(pev); struct perf_probe_point tmp; struct debuginfo *dinfo; int ntevs, ret = 0; - dinfo = open_debuginfo(target, !need_dwarf); - + dinfo = open_debuginfo(pev->target, !need_dwarf); if (!dinfo) { if (need_dwarf) return -ENOENT; @@ -608,13 +621,12 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, pr_debug("Try to find probe point from debuginfo.\n"); /* Searching trace events corresponding to a probe event */ - ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); + ntevs = debuginfo__find_trace_events(dinfo, pev, tevs); if (ntevs == 0) { /* Not found, retry with an alternative */ - ret = get_alternative_probe_event(dinfo, pev, &tmp, target); + ret = get_alternative_probe_event(dinfo, pev, &tmp); if (!ret) { - ntevs = debuginfo__find_trace_events(dinfo, pev, - tevs, max_tevs); + ntevs = debuginfo__find_trace_events(dinfo, pev, tevs); /* * Write back to the original probe_event for * setting appropriate (user given) event name @@ -629,12 +641,15 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, if (ntevs > 0) { /* Succeeded to find trace events */ pr_debug("Found %d probe_trace_events.\n", ntevs); ret = post_process_probe_trace_events(*tevs, ntevs, - target, pev->uprobes); - if (ret < 0) { + pev->target, pev->uprobes); + if (ret < 0 || ret == ntevs) { clear_probe_trace_events(*tevs, ntevs); zfree(tevs); } - return ret < 0 ? ret : ntevs; + if (ret != ntevs) + return ret < 0 ? ret : ntevs; + ntevs = 0; + /* Fall through */ } if (ntevs == 0) { /* No error but failed to find probe point. */ @@ -809,8 +824,7 @@ int show_line_range(struct line_range *lr, const char *module, bool user) static int show_available_vars_at(struct debuginfo *dinfo, struct perf_probe_event *pev, - int max_vls, struct strfilter *_filter, - bool externs, const char *target) + struct strfilter *_filter) { char *buf; int ret, i, nvars; @@ -824,13 +838,12 @@ static int show_available_vars_at(struct debuginfo *dinfo, return -EINVAL; pr_debug("Searching variables at %s\n", buf); - ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, - max_vls, externs); + ret = debuginfo__find_available_vars_at(dinfo, pev, &vls); if (!ret) { /* Not found, retry with an alternative */ - ret = get_alternative_probe_event(dinfo, pev, &tmp, target); + ret = get_alternative_probe_event(dinfo, pev, &tmp); if (!ret) { ret = debuginfo__find_available_vars_at(dinfo, pev, - &vls, max_vls, externs); + &vls); /* Release the old probe_point */ clear_perf_probe_point(&tmp); } @@ -877,8 +890,7 @@ end: /* Show available variables on given probe point */ int show_available_vars(struct perf_probe_event *pevs, int npevs, - int max_vls, const char *module, - struct strfilter *_filter, bool externs) + struct strfilter *_filter) { int i, ret = 0; struct debuginfo *dinfo; @@ -887,7 +899,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, if (ret < 0) return ret; - dinfo = open_debuginfo(module, false); + dinfo = open_debuginfo(pevs->target, false); if (!dinfo) { ret = -ENOENT; goto out; @@ -896,8 +908,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, setup_pager(); for (i = 0; i < npevs && ret >= 0; i++) - ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, - externs, module); + ret = show_available_vars_at(dinfo, &pevs[i], _filter); debuginfo__delete(dinfo); out: @@ -916,9 +927,7 @@ find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, } static int try_to_find_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event **tevs __maybe_unused, - int max_tevs __maybe_unused, - const char *target __maybe_unused) + struct probe_trace_event **tevs __maybe_unused) { if (perf_probe_event_need_dwarf(pev)) { pr_warning("Debuginfo-analysis is not supported.\n"); @@ -937,10 +946,8 @@ int show_line_range(struct line_range *lr __maybe_unused, } int show_available_vars(struct perf_probe_event *pevs __maybe_unused, - int npevs __maybe_unused, int max_vls __maybe_unused, - const char *module __maybe_unused, - struct strfilter *filter __maybe_unused, - bool externs __maybe_unused) + int npevs __maybe_unused, + struct strfilter *filter __maybe_unused) { pr_warning("Debuginfo-analysis is not supported.\n"); return -ENOSYS; @@ -980,6 +987,18 @@ static int parse_line_num(char **ptr, int *val, const char *what) return 0; } +/* Check the name is good for event, group or function */ +static bool is_c_func_name(const char *name) +{ + if (!isalpha(*name) && *name != '_') + return false; + while (*++name != '\0') { + if (!isalpha(*name) && !isdigit(*name) && *name != '_') + return false; + } + return true; +} + /* * Stuff 'lr' according to the line range described by 'arg'. * The line range syntax is described by: @@ -1048,10 +1067,15 @@ int parse_line_range_desc(const char *arg, struct line_range *lr) goto err; } lr->function = name; - } else if (strchr(name, '.')) + } else if (strchr(name, '/') || strchr(name, '.')) lr->file = name; - else + else if (is_c_func_name(name))/* We reuse it for checking funcname */ lr->function = name; + else { /* Invalid name */ + semantic_error("'%s' is not a valid function name.\n", name); + err = -EINVAL; + goto err; + } return 0; err: @@ -1059,18 +1083,6 @@ err: return err; } -/* Check the name is good for event/group */ -static bool check_event_name(const char *name) -{ - if (!isalpha(*name) && *name != '_') - return false; - while (*++name != '\0') { - if (!isalpha(*name) && !isdigit(*name) && *name != '_') - return false; - } - return true; -} - /* Parse probepoint definition. */ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) { @@ -1094,7 +1106,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) semantic_error("Group name is not supported yet.\n"); return -ENOTSUP; } - if (!check_event_name(arg)) { + if (!is_c_func_name(arg)) { semantic_error("%s is bad for event name -it must " "follow C symbol-naming rule.\n", arg); return -EINVAL; @@ -1892,6 +1904,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) free(tev->event); free(tev->group); free(tev->point.symbol); + free(tev->point.realname); free(tev->point.module); for (i = 0; i < tev->nargs; i++) { free(tev->args[i].name); @@ -1969,7 +1982,7 @@ static int open_probe_events(const char *trace_file, bool readwrite) if (ret >= 0) { pr_debug("Opening %s write=%d\n", buf, readwrite); if (readwrite && !probe_event_dry_run) - ret = open(buf, O_RDWR, O_APPEND); + ret = open(buf, O_RDWR | O_APPEND, 0); else ret = open(buf, O_RDONLY, 0); @@ -2369,6 +2382,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, struct strlist *namelist; LIST_HEAD(blacklist); struct kprobe_blacklist_node *node; + bool safename; if (pev->uprobes) fd = open_uprobe_events(true); @@ -2384,7 +2398,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, namelist = get_probe_trace_event_names(fd, false); if (!namelist) { pr_debug("Failed to get current event list.\n"); - return -EIO; + ret = -ENOMEM; + goto close_out; } /* Get kprobe blacklist if exists */ if (!pev->uprobes) { @@ -2393,10 +2408,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, pr_debug("No kprobe blacklist support, ignored\n"); } + safename = (pev->point.function && !strisglob(pev->point.function)); ret = 0; pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); for (i = 0; i < ntevs; i++) { tev = &tevs[i]; + /* Skip if the symbol is out of .text (marked previously) */ + if (!tev->point.symbol) + continue; /* Ensure that the address is NOT blacklisted */ node = kprobe_blacklist__find_by_address(&blacklist, tev->point.address); @@ -2408,10 +2427,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, if (pev->event) event = pev->event; else - if (pev->point.function) + if (safename) event = pev->point.function; else - event = tev->point.symbol; + event = tev->point.realname; if (pev->group) group = pev->group; else @@ -2467,6 +2486,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, kprobe_blacklist__delete(&blacklist); strlist__delete(namelist); +close_out: close(fd); return ret; } @@ -2475,9 +2495,11 @@ static int find_probe_functions(struct map *map, char *name) { int found = 0; struct symbol *sym; + struct rb_node *tmp; - map__for_each_symbol_by_name(map, name, sym) { - found++; + map__for_each_symbol(map, sym, tmp) { + if (strglobmatch(sym->name, name)) + found++; } return found; @@ -2495,8 +2517,7 @@ void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, * Return an error or the number of found probe_trace_event */ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, - struct probe_trace_event **tevs, - int max_tevs, const char *target) + struct probe_trace_event **tevs) { struct map *map = NULL; struct ref_reloc_sym *reloc_sym = NULL; @@ -2507,7 +2528,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, int num_matched_functions; int ret, i; - map = get_target_map(target, pev->uprobes); + map = get_target_map(pev->target, pev->uprobes); if (!map) { ret = -EINVAL; goto out; @@ -2520,12 +2541,12 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, num_matched_functions = find_probe_functions(map, pp->function); if (num_matched_functions == 0) { pr_err("Failed to find symbol %s in %s\n", pp->function, - target ? : "kernel"); + pev->target ? : "kernel"); ret = -ENOENT; goto out; - } else if (num_matched_functions > max_tevs) { + } else if (num_matched_functions > probe_conf.max_probes) { pr_err("Too many functions matched in %s\n", - target ? : "kernel"); + pev->target ? : "kernel"); ret = -E2BIG; goto out; } @@ -2573,8 +2594,9 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, tp->offset = pp->offset; } tp->retprobe = pp->retprobe; - if (target) - tev->point.module = strdup_or_goto(target, nomem_out); + if (pev->target) + tev->point.module = strdup_or_goto(pev->target, + nomem_out); tev->uprobes = pev->uprobes; tev->nargs = pev->nargs; if (tev->nargs) { @@ -2614,14 +2636,13 @@ err_out: bool __weak arch__prefers_symtab(void) { return false; } static int convert_to_probe_trace_events(struct perf_probe_event *pev, - struct probe_trace_event **tevs, - int max_tevs, const char *target) + struct probe_trace_event **tevs) { int ret; if (pev->uprobes && !pev->group) { /* Replace group name if not given */ - ret = convert_exec_to_group(target, &pev->group); + ret = convert_exec_to_group(pev->target, &pev->group); if (ret != 0) { pr_warning("Failed to make a group name.\n"); return ret; @@ -2629,17 +2650,17 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, } if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { - ret = find_probe_trace_events_from_map(pev, tevs, max_tevs, target); + ret = find_probe_trace_events_from_map(pev, tevs); if (ret > 0) return ret; /* Found in symbol table */ } /* Convert perf_probe_event with debuginfo */ - ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); + ret = try_to_find_probe_trace_events(pev, tevs); if (ret != 0) return ret; /* Found in debuginfo or got an error */ - return find_probe_trace_events_from_map(pev, tevs, max_tevs, target); + return find_probe_trace_events_from_map(pev, tevs); } struct __event_package { @@ -2648,8 +2669,7 @@ struct __event_package { int ntevs; }; -int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, - int max_tevs, bool force_add) +int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, j, ret; struct __event_package *pkgs; @@ -2671,9 +2691,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, pkgs[i].pev = &pevs[i]; /* Convert with or without debuginfo */ ret = convert_to_probe_trace_events(pkgs[i].pev, - &pkgs[i].tevs, - max_tevs, - pkgs[i].pev->target); + &pkgs[i].tevs); if (ret < 0) goto end; pkgs[i].ntevs = ret; @@ -2682,7 +2700,8 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, /* Loop 2: add all events */ for (i = 0; i < npevs; i++) { ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, - pkgs[i].ntevs, force_add); + pkgs[i].ntevs, + probe_conf.force_add); if (ret < 0) break; } |