···86868787DECLARE_EVENT_CLASS(softirq,88888989- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),8989+ TP_PROTO(unsigned int vec_nr),90909191- TP_ARGS(h, vec),9191+ TP_ARGS(vec_nr),92929393 TP_STRUCT__entry(9494- __field( int, vec )9494+ __field( unsigned int, vec )9595 ),96969797 TP_fast_assign(9898- if (vec)9999- __entry->vec = (int)(h - vec);100100- else101101- __entry->vec = (int)(long)h;9898+ __entry->vec = vec_nr;10299 ),103100104104- TP_printk("vec=%d [action=%s]", __entry->vec,101101+ TP_printk("vec=%u [action=%s]", __entry->vec,105102 show_softirq_name(__entry->vec))106103);107104108105/**109106 * softirq_entry - called immediately before the softirq handler110110- * @h: pointer to struct softirq_action111111- * @vec: pointer to first struct softirq_action in softirq_vec array107107+ * @vec_nr: softirq vector number112108 *113113- * The @h parameter, contains a pointer to the struct softirq_action114114- * which has a pointer to the action handler that is called. By subtracting115115- * the @vec pointer from the @h pointer, we can determine the softirq116116- * number. Also, when used in combination with the softirq_exit tracepoint117117- * we can determine the softirq latency.109109+ * When used in combination with the softirq_exit tracepoint110110+ * we can determine the softirq handler runtine.118111 */119112DEFINE_EVENT(softirq, softirq_entry,120113121121- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),114114+ TP_PROTO(unsigned int vec_nr),122115123123- TP_ARGS(h, vec)116116+ TP_ARGS(vec_nr)124117);125118126119/**127120 * softirq_exit - called immediately after the softirq handler returns128128- * @h: pointer to struct softirq_action129129- * @vec: pointer to first struct softirq_action in softirq_vec array121121+ * @vec_nr: softirq vector number130122 *131131- * The @h parameter contains a pointer to the struct softirq_action132132- * that has handled the softirq. By subtracting the @vec pointer from133133- * the @h pointer, we can determine the softirq number. Also, when used in134134- * combination with the softirq_entry tracepoint we can determine the softirq135135- * latency.123123+ * When used in combination with the softirq_entry tracepoint124124+ * we can determine the softirq handler runtine.136125 */137126DEFINE_EVENT(softirq, softirq_exit,138127139139- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),128128+ TP_PROTO(unsigned int vec_nr),140129141141- TP_ARGS(h, vec)130130+ TP_ARGS(vec_nr)142131);143132144133/**145134 * softirq_raise - called immediately when a softirq is raised146146- * @h: pointer to struct softirq_action147147- * @vec: pointer to first struct softirq_action in softirq_vec array135135+ * @vec_nr: softirq vector number148136 *149149- * The @h parameter contains a pointer to the softirq vector number which is150150- * raised. @vec is NULL and it means @h includes vector number not151151- * softirq_action. When used in combination with the softirq_entry tracepoint152152- * we can determine the softirq raise latency.137137+ * When used in combination with the softirq_entry tracepoint138138+ * we can determine the softirq raise to run latency.153139 */154140DEFINE_EVENT(softirq, softirq_raise,155141156156- TP_PROTO(struct softirq_action *h, struct softirq_action *vec),142142+ TP_PROTO(unsigned int vec_nr),157143158158- TP_ARGS(h, vec)144144+ TP_ARGS(vec_nr)159145);160146161147#endif /* _TRACE_IRQ_H */
+9-7
kernel/softirq.c
···229229230230 do {231231 if (pending & 1) {232232+ unsigned int vec_nr = h - softirq_vec;232233 int prev_count = preempt_count();233233- kstat_incr_softirqs_this_cpu(h - softirq_vec);234234235235- trace_softirq_entry(h, softirq_vec);235235+ kstat_incr_softirqs_this_cpu(vec_nr);236236+237237+ trace_softirq_entry(vec_nr);236238 h->action(h);237237- trace_softirq_exit(h, softirq_vec);239239+ trace_softirq_exit(vec_nr);238240 if (unlikely(prev_count != preempt_count())) {239239- printk(KERN_ERR "huh, entered softirq %td %s %p"241241+ printk(KERN_ERR "huh, entered softirq %u %s %p"240242 "with preempt_count %08x,"241241- " exited with %08x?\n", h - softirq_vec,242242- softirq_to_name[h - softirq_vec],243243- h->action, prev_count, preempt_count());243243+ " exited with %08x?\n", vec_nr,244244+ softirq_to_name[vec_nr], h->action,245245+ prev_count, preempt_count());244246 preempt_count() = prev_count;245247 }246248
+17-1
tools/perf/Documentation/perf-probe.txt
···1616or1717'perf probe' --list1818or1919-'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'1919+'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'2020+or2121+'perf probe' [options] --vars='PROBEPOINT'20222123DESCRIPTION2224-----------···3230-k::3331--vmlinux=PATH::3432 Specify vmlinux path which has debuginfo (Dwarf binary).3333+3434+-m::3535+--module=MODNAME::3636+ Specify module name in which perf-probe searches probe points3737+ or lines.35383639-s::3740--source=PATH::···6356--line=::6457 Show source code lines which can be probed. This needs an argument6558 which specifies a range of the source code. (see LINE SYNTAX for detail)5959+6060+-V::6161+--vars=::6262+ Show available local variables at given probe point. The argument6363+ syntax is same as PROBE SYNTAX, but NO ARGs.6464+6565+--externs::6666+ (Only for --vars) Show external defined variables in addition to local6767+ variables.66686769-f::6870--force::
+67-11
tools/perf/builtin-probe.c
···5050 bool list_events;5151 bool force_add;5252 bool show_lines;5353+ bool show_vars;5454+ bool show_ext_vars;5555+ bool mod_events;5356 int nevents;5457 struct perf_probe_event events[MAX_PROBES];5558 struct strlist *dellist;5659 struct line_range line_range;6060+ const char *target_module;5761 int max_probe_points;5862} params;5959-60636164/* Parse an event definition. Note that any error must die. */6265static int parse_probe_event(const char *str)···9592 len = 0;9693 for (i = 0; i < argc; i++)9794 len += sprintf(&buf[len], "%s ", argv[i]);9595+ params.mod_events = true;9896 ret = parse_probe_event(buf);9997 free(buf);10098 return ret;···104100static int opt_add_probe_event(const struct option *opt __used,105101 const char *str, int unset __used)106102{107107- if (str)103103+ if (str) {104104+ params.mod_events = true;108105 return parse_probe_event(str);109109- else106106+ } else110107 return 0;111108}112109···115110 const char *str, int unset __used)116111{117112 if (str) {113113+ params.mod_events = true;118114 if (!params.dellist)119115 params.dellist = strlist__new(true, NULL);120116 strlist__add(params.dellist, str);···136130137131 return ret;138132}133133+134134+static int opt_show_vars(const struct option *opt __used,135135+ const char *str, int unset __used)136136+{137137+ struct perf_probe_event *pev = ¶ms.events[params.nevents];138138+ int ret;139139+140140+ if (!str)141141+ return 0;142142+143143+ ret = parse_probe_event(str);144144+ if (!ret && pev->nargs != 0) {145145+ pr_err(" Error: '--vars' doesn't accept arguments.\n");146146+ return -EINVAL;147147+ }148148+ params.show_vars = true;149149+150150+ return ret;151151+}139152#endif140153141154static const char * const probe_usage[] = {···163138 "perf probe [<options>] --del '[GROUP:]EVENT' ...",164139 "perf probe --list",165140#ifdef DWARF_SUPPORT166166- "perf probe --line 'LINEDESC'",141141+ "perf probe [<options>] --line 'LINEDESC'",142142+ "perf probe [<options>] --vars 'PROBEPOINT'",167143#endif168144 NULL169145};···206180 OPT_CALLBACK('L', "line", NULL,207181 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",208182 "Show source code lines.", opt_show_lines),183183+ OPT_CALLBACK('V', "vars", NULL,184184+ "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",185185+ "Show accessible variables on PROBEDEF", opt_show_vars),186186+ OPT_BOOLEAN('\0', "externs", ¶ms.show_ext_vars,187187+ "Show external variables too (with --vars only)"),209188 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,210189 "file", "vmlinux pathname"),211190 OPT_STRING('s', "source", &symbol_conf.source_prefix,212191 "directory", "path to kernel source"),192192+ OPT_STRING('m', "module", ¶ms.target_module,193193+ "modname", "target module name"),213194#endif214195 OPT__DRY_RUN(&probe_event_dry_run),215196 OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points,···250217 usage_with_options(probe_usage, options);251218252219 if (params.list_events) {253253- if (params.nevents != 0 || params.dellist) {220220+ if (params.mod_events) {254221 pr_err(" Error: Don't use --list with --add/--del.\n");255222 usage_with_options(probe_usage, options);256223 }257224 if (params.show_lines) {258225 pr_err(" Error: Don't use --list with --line.\n");226226+ usage_with_options(probe_usage, options);227227+ }228228+ if (params.show_vars) {229229+ pr_err(" Error: Don't use --list with --vars.\n");259230 usage_with_options(probe_usage, options);260231 }261232 ret = show_perf_probe_events();···271234272235#ifdef DWARF_SUPPORT273236 if (params.show_lines) {274274- if (params.nevents != 0 || params.dellist) {275275- pr_warning(" Error: Don't use --line with"276276- " --add/--del.\n");237237+ if (params.mod_events) {238238+ pr_err(" Error: Don't use --line with"239239+ " --add/--del.\n");240240+ usage_with_options(probe_usage, options);241241+ }242242+ if (params.show_vars) {243243+ pr_err(" Error: Don't use --line with --vars.\n");277244 usage_with_options(probe_usage, options);278245 }279246280280- ret = show_line_range(¶ms.line_range);247247+ ret = show_line_range(¶ms.line_range, params.target_module);281248 if (ret < 0)282249 pr_err(" Error: Failed to show lines. (%d)\n", ret);250250+ return ret;251251+ }252252+ if (params.show_vars) {253253+ if (params.mod_events) {254254+ pr_err(" Error: Don't use --vars with"255255+ " --add/--del.\n");256256+ usage_with_options(probe_usage, options);257257+ }258258+ ret = show_available_vars(params.events, params.nevents,259259+ params.max_probe_points,260260+ params.target_module,261261+ params.show_ext_vars);262262+ if (ret < 0)263263+ pr_err(" Error: Failed to show vars. (%d)\n", ret);283264 return ret;284265 }285266#endif···313258314259 if (params.nevents) {315260 ret = add_perf_probe_events(params.events, params.nevents,316316- params.force_add,317317- params.max_probe_points);261261+ params.max_probe_points,262262+ params.target_module,263263+ params.force_add);318264 if (ret < 0) {319265 pr_err(" Error: Failed to add events. (%d)\n", ret);320266 return ret;
···7474static char *synthesize_perf_probe_point(struct perf_probe_point *pp);7575static struct machine machine;76767777-/* Initialize symbol maps and path of vmlinux */7777+/* Initialize symbol maps and path of vmlinux/modules */7878static int init_vmlinux(void)7979{8080- struct dso *kernel;8180 int ret;82818382 symbol_conf.sort_by_name = true;···9091 goto out;9192 }92939393- ret = machine__init(&machine, "/", 0);9494+ ret = machine__init(&machine, "", HOST_KERNEL_ID);9495 if (ret < 0)9596 goto out;96979797- kernel = dso__new_kernel(symbol_conf.vmlinux_name);9898- if (kernel == NULL)9999- die("Failed to create kernel dso.");100100-101101- ret = __machine__create_kernel_maps(&machine, kernel);102102- if (ret < 0)103103- pr_debug("Failed to create kernel maps.\n");104104-9898+ if (machine__create_kernel_maps(&machine) < 0) {9999+ pr_debug("machine__create_kernel_maps ");100100+ goto out;101101+ }105102out:106103 if (ret < 0)107104 pr_warning("Failed to init vmlinux path.\n");108105 return ret;109106}110107111111-#ifdef DWARF_SUPPORT112112-static int open_vmlinux(void)108108+static struct symbol *__find_kernel_function_by_name(const char *name,109109+ struct map **mapp)113110{114114- if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {115115- pr_debug("Failed to load kernel map.\n");116116- return -EINVAL;111111+ return machine__find_kernel_function_by_name(&machine, name, mapp,112112+ NULL);113113+}114114+115115+const char *kernel_get_module_path(const char *module)116116+{117117+ struct dso *dso;118118+119119+ if (module) {120120+ list_for_each_entry(dso, &machine.kernel_dsos, node) {121121+ if (strncmp(dso->short_name + 1, module,122122+ dso->short_name_len - 2) == 0)123123+ goto found;124124+ }125125+ pr_debug("Failed to find module %s.\n", module);126126+ return NULL;127127+ } else {128128+ dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;129129+ if (dso__load_vmlinux_path(dso,130130+ machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {131131+ pr_debug("Failed to load kernel map.\n");132132+ return NULL;133133+ }117134 }118118- pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);119119- return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);135135+found:136136+ return dso->long_name;137137+}138138+139139+#ifdef DWARF_SUPPORT140140+static int open_vmlinux(const char *module)141141+{142142+ const char *path = kernel_get_module_path(module);143143+ if (!path) {144144+ pr_err("Failed to find path of %s module", module ?: "kernel");145145+ return -ENOENT;146146+ }147147+ pr_debug("Try to open %s\n", path);148148+ return open(path, O_RDONLY);120149}121150122151/*···152125 * Currently only handles kprobes.153126 */154127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,155155- struct perf_probe_point *pp)128128+ struct perf_probe_point *pp)156129{157130 struct symbol *sym;158158- int fd, ret = -ENOENT;131131+ struct map *map;132132+ u64 addr;133133+ int ret = -ENOENT;159134160160- sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],161161- tp->symbol, NULL);135135+ sym = __find_kernel_function_by_name(tp->symbol, &map);162136 if (sym) {163163- fd = open_vmlinux();164164- if (fd >= 0) {165165- ret = find_perf_probe_point(fd,166166- sym->start + tp->offset, pp);167167- close(fd);168168- }137137+ addr = map->unmap_ip(map, sym->start + tp->offset);138138+ pr_debug("try to find %s+%ld@%llx\n", tp->symbol,139139+ tp->offset, addr);140140+ ret = find_perf_probe_point((unsigned long)addr, pp);169141 }170142 if (ret <= 0) {171143 pr_debug("Failed to find corresponding probes from "···182156/* Try to find perf_probe_event with debuginfo */183157static int try_to_find_probe_trace_events(struct perf_probe_event *pev,184158 struct probe_trace_event **tevs,185185- int max_tevs)159159+ int max_tevs, const char *module)186160{187161 bool need_dwarf = perf_probe_event_need_dwarf(pev);188162 int fd, ntevs;189163190190- fd = open_vmlinux();164164+ fd = open_vmlinux(module);191165 if (fd < 0) {192166 if (need_dwarf) {193167 pr_warning("Failed to open debuginfo file.\n");···326300 * Show line-range always requires debuginfo to find source file and327301 * line number.328302 */329329-int show_line_range(struct line_range *lr)303303+int show_line_range(struct line_range *lr, const char *module)330304{331305 int l = 1;332306 struct line_node *ln;···339313 if (ret < 0)340314 return ret;341315342342- fd = open_vmlinux();316316+ fd = open_vmlinux(module);343317 if (fd < 0) {344318 pr_warning("Failed to open debuginfo file.\n");345319 return fd;···404378 return ret;405379}406380381381+static int show_available_vars_at(int fd, struct perf_probe_event *pev,382382+ int max_vls, bool externs)383383+{384384+ char *buf;385385+ int ret, i;386386+ struct str_node *node;387387+ struct variable_list *vls = NULL, *vl;388388+389389+ buf = synthesize_perf_probe_point(&pev->point);390390+ if (!buf)391391+ return -EINVAL;392392+ pr_debug("Searching variables at %s\n", buf);393393+394394+ ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);395395+ if (ret > 0) {396396+ /* Some variables were found */397397+ fprintf(stdout, "Available variables at %s\n", buf);398398+ for (i = 0; i < ret; i++) {399399+ vl = &vls[i];400400+ /*401401+ * A probe point might be converted to402402+ * several trace points.403403+ */404404+ fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,405405+ vl->point.offset);406406+ free(vl->point.symbol);407407+ if (vl->vars) {408408+ strlist__for_each(node, vl->vars)409409+ fprintf(stdout, "\t\t%s\n", node->s);410410+ strlist__delete(vl->vars);411411+ } else412412+ fprintf(stdout, "(No variables)\n");413413+ }414414+ free(vls);415415+ } else416416+ pr_err("Failed to find variables at %s (%d)\n", buf, ret);417417+418418+ free(buf);419419+ return ret;420420+}421421+422422+/* Show available variables on given probe point */423423+int show_available_vars(struct perf_probe_event *pevs, int npevs,424424+ int max_vls, const char *module, bool externs)425425+{426426+ int i, fd, ret = 0;427427+428428+ ret = init_vmlinux();429429+ if (ret < 0)430430+ return ret;431431+432432+ fd = open_vmlinux(module);433433+ if (fd < 0) {434434+ pr_warning("Failed to open debuginfo file.\n");435435+ return fd;436436+ }437437+438438+ setup_pager();439439+440440+ for (i = 0; i < npevs && ret >= 0; i++)441441+ ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);442442+443443+ close(fd);444444+ return ret;445445+}446446+407447#else /* !DWARF_SUPPORT */408448409449static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,410410- struct perf_probe_point *pp)450450+ struct perf_probe_point *pp)411451{452452+ struct symbol *sym;453453+454454+ sym = __find_kernel_function_by_name(tp->symbol, NULL);455455+ if (!sym) {456456+ pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);457457+ return -ENOENT;458458+ }412459 pp->function = strdup(tp->symbol);413460 if (pp->function == NULL)414461 return -ENOMEM;···493394494395static int try_to_find_probe_trace_events(struct perf_probe_event *pev,495396 struct probe_trace_event **tevs __unused,496496- int max_tevs __unused)397397+ int max_tevs __unused, const char *mod __unused)497398{498399 if (perf_probe_event_need_dwarf(pev)) {499400 pr_warning("Debuginfo-analysis is not supported.\n");···502403 return 0;503404}504405505505-int show_line_range(struct line_range *lr __unused)406406+int show_line_range(struct line_range *lr __unused, const char *module __unused)506407{507408 pr_warning("Debuginfo-analysis is not supported.\n");508409 return -ENOSYS;509410}510411412412+int show_available_vars(struct perf_probe_event *pevs __unused,413413+ int npevs __unused, int max_vls __unused,414414+ const char *module __unused, bool externs __unused)415415+{416416+ pr_warning("Debuginfo-analysis is not supported.\n");417417+ return -ENOSYS;418418+}511419#endif512420513421int parse_line_range_desc(const char *arg, struct line_range *lr)···11931087}1194108811951089static int convert_to_perf_probe_event(struct probe_trace_event *tev,11961196- struct perf_probe_event *pev)10901090+ struct perf_probe_event *pev)11971091{11981092 char buf[64] = "";11991093 int i, ret;···1622151616231517static int convert_to_probe_trace_events(struct perf_probe_event *pev,16241518 struct probe_trace_event **tevs,16251625- int max_tevs)15191519+ int max_tevs, const char *module)16261520{16271521 struct symbol *sym;16281522 int ret = 0, i;16291523 struct probe_trace_event *tev;1630152416311525 /* Convert perf_probe_event with debuginfo */16321632- ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);15261526+ ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);16331527 if (ret != 0)16341528 return ret;16351529···16781572 }1679157316801574 /* Currently just checking function name from symbol map */16811681- sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],16821682- tev->point.symbol, NULL);15751575+ sym = __find_kernel_function_by_name(tev->point.symbol, NULL);16831576 if (!sym) {16841577 pr_warning("Kernel symbol \'%s\' not found.\n",16851578 tev->point.symbol);···17011596};1702159717031598int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,17041704- bool force_add, int max_tevs)15991599+ int max_tevs, const char *module, bool force_add)17051600{17061601 int i, j, ret;17071602 struct __event_package *pkgs;···17221617 pkgs[i].pev = &pevs[i];17231618 /* Convert with or without debuginfo */17241619 ret = convert_to_probe_trace_events(pkgs[i].pev,17251725- &pkgs[i].tevs, max_tevs);16201620+ &pkgs[i].tevs,16211621+ max_tevs,16221622+ module);17261623 if (ret < 0)17271624 goto end;17281625 pkgs[i].ntevs = ret;
+14-2
tools/perf/util/probe-event.h
···9090 struct list_head line_list; /* Visible lines */9191};92929393+/* List of variables */9494+struct variable_list {9595+ struct probe_trace_point point; /* Actual probepoint */9696+ struct strlist *vars; /* Available variables */9797+};9898+9399/* Command string to events */94100extern int parse_perf_probe_command(const char *cmd,95101 struct perf_probe_event *pev);···115109/* Command string to line-range */116110extern int parse_line_range_desc(const char *cmd, struct line_range *lr);117111112112+/* Internal use: Return kernel/module path */113113+extern const char *kernel_get_module_path(const char *module);118114119115extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,120120- bool force_add, int max_probe_points);116116+ int max_probe_points, const char *module,117117+ bool force_add);121118extern int del_perf_probe_events(struct strlist *dellist);122119extern int show_perf_probe_events(void);123123-extern int show_line_range(struct line_range *lr);120120+extern int show_line_range(struct line_range *lr, const char *module);121121+extern int show_available_vars(struct perf_probe_event *pevs, int npevs,122122+ int max_probe_points, const char *module,123123+ bool externs);124124125125126126/* Maximum index number of event-name postfix */
+510-134
tools/perf/util/probe-finder.c
···116116 }117117}118118119119+/* Dwarf FL wrappers */120120+121121+static int __linux_kernel_find_elf(Dwfl_Module *mod,122122+ void **userdata,123123+ const char *module_name,124124+ Dwarf_Addr base,125125+ char **file_name, Elf **elfp)126126+{127127+ int fd;128128+ const char *path = kernel_get_module_path(module_name);129129+130130+ if (path) {131131+ fd = open(path, O_RDONLY);132132+ if (fd >= 0) {133133+ *file_name = strdup(path);134134+ return fd;135135+ }136136+ }137137+ /* If failed, try to call standard method */138138+ return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,139139+ file_name, elfp);140140+}141141+142142+static char *debuginfo_path; /* Currently dummy */143143+144144+static const Dwfl_Callbacks offline_callbacks = {145145+ .find_debuginfo = dwfl_standard_find_debuginfo,146146+ .debuginfo_path = &debuginfo_path,147147+148148+ .section_address = dwfl_offline_section_address,149149+150150+ /* We use this table for core files too. */151151+ .find_elf = dwfl_build_id_find_elf,152152+};153153+154154+static const Dwfl_Callbacks kernel_callbacks = {155155+ .find_debuginfo = dwfl_standard_find_debuginfo,156156+ .debuginfo_path = &debuginfo_path,157157+158158+ .find_elf = __linux_kernel_find_elf,159159+ .section_address = dwfl_linux_kernel_module_section_address,160160+};161161+162162+/* Get a Dwarf from offline image */163163+static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)164164+{165165+ Dwfl_Module *mod;166166+ Dwarf *dbg = NULL;167167+168168+ if (!dwflp)169169+ return NULL;170170+171171+ *dwflp = dwfl_begin(&offline_callbacks);172172+ if (!*dwflp)173173+ return NULL;174174+175175+ mod = dwfl_report_offline(*dwflp, "", "", fd);176176+ if (!mod)177177+ goto error;178178+179179+ dbg = dwfl_module_getdwarf(mod, bias);180180+ if (!dbg) {181181+error:182182+ dwfl_end(*dwflp);183183+ *dwflp = NULL;184184+ }185185+ return dbg;186186+}187187+188188+/* Get a Dwarf from live kernel image */189189+static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,190190+ Dwarf_Addr *bias)191191+{192192+ Dwarf *dbg;193193+194194+ if (!dwflp)195195+ return NULL;196196+197197+ *dwflp = dwfl_begin(&kernel_callbacks);198198+ if (!*dwflp)199199+ return NULL;200200+201201+ /* Load the kernel dwarves: Don't care the result here */202202+ dwfl_linux_kernel_report_kernel(*dwflp);203203+ dwfl_linux_kernel_report_modules(*dwflp);204204+205205+ dbg = dwfl_addrdwarf(*dwflp, addr, bias);206206+ /* Here, check whether we could get a real dwarf */207207+ if (!dbg) {208208+ dwfl_end(*dwflp);209209+ *dwflp = NULL;210210+ }211211+ return dbg;212212+}213213+119214/* Dwarf wrappers */120215121216/* Find the realpath of the target file. */···255160 return name ? (strcmp(tname, name) == 0) : false;256161}257162258258-/* Get type die, but skip qualifiers and typedef */259259-static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)163163+/* Get type die */164164+static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)260165{261166 Dwarf_Attribute attr;167167+168168+ if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&169169+ dwarf_formref_die(&attr, die_mem))170170+ return die_mem;171171+ else172172+ return NULL;173173+}174174+175175+/* Get a type die, but skip qualifiers */176176+static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)177177+{262178 int tag;263179264180 do {265265- if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||266266- dwarf_formref_die(&attr, die_mem) == NULL)267267- return NULL;268268-269269- tag = dwarf_tag(die_mem);270270- vr_die = die_mem;181181+ vr_die = die_get_type(vr_die, die_mem);182182+ if (!vr_die)183183+ break;184184+ tag = dwarf_tag(vr_die);271185 } while (tag == DW_TAG_const_type ||272186 tag == DW_TAG_restrict_type ||273187 tag == DW_TAG_volatile_type ||274274- tag == DW_TAG_shared_type ||275275- tag == DW_TAG_typedef);188188+ tag == DW_TAG_shared_type);276189277277- return die_mem;190190+ return vr_die;191191+}192192+193193+/* Get a type die, but skip qualifiers and typedef */194194+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)195195+{196196+ do {197197+ vr_die = __die_get_real_type(vr_die, die_mem);198198+ } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);199199+200200+ return vr_die;278201}279202280203static bool die_is_signed_type(Dwarf_Die *tp_die)···433320 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);434321}435322323323+struct __find_variable_param {324324+ const char *name;325325+ Dwarf_Addr addr;326326+};327327+436328static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)437329{438438- const char *name = data;330330+ struct __find_variable_param *fvp = data;439331 int tag;440332441333 tag = dwarf_tag(die_mem);442334 if ((tag == DW_TAG_formal_parameter ||443335 tag == DW_TAG_variable) &&444444- die_compare_name(die_mem, name))336336+ die_compare_name(die_mem, fvp->name))445337 return DIE_FIND_CB_FOUND;446338447447- return DIE_FIND_CB_CONTINUE;339339+ if (dwarf_haspc(die_mem, fvp->addr))340340+ return DIE_FIND_CB_CONTINUE;341341+ else342342+ return DIE_FIND_CB_SIBLING;448343}449344450450-/* Find a variable called 'name' */451451-static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,452452- Dwarf_Die *die_mem)345345+/* Find a variable called 'name' at given address */346346+static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,347347+ Dwarf_Addr addr, Dwarf_Die *die_mem)453348{454454- return die_find_child(sp_die, __die_find_variable_cb, (void *)name,349349+ struct __find_variable_param fvp = { .name = name, .addr = addr};350350+351351+ return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,455352 die_mem);456353}457354···484361 die_mem);485362}486363364364+/* Get the name of given variable DIE */365365+static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)366366+{367367+ Dwarf_Die type;368368+ int tag, ret, ret2;369369+ const char *tmp = "";370370+371371+ if (__die_get_real_type(vr_die, &type) == NULL)372372+ return -ENOENT;373373+374374+ tag = dwarf_tag(&type);375375+ if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)376376+ tmp = "*";377377+ else if (tag == DW_TAG_subroutine_type) {378378+ /* Function pointer */379379+ ret = snprintf(buf, len, "(function_type)");380380+ return (ret >= len) ? -E2BIG : ret;381381+ } else {382382+ if (!dwarf_diename(&type))383383+ return -ENOENT;384384+ if (tag == DW_TAG_union_type)385385+ tmp = "union ";386386+ else if (tag == DW_TAG_structure_type)387387+ tmp = "struct ";388388+ /* Write a base name */389389+ ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));390390+ return (ret >= len) ? -E2BIG : ret;391391+ }392392+ ret = die_get_typename(&type, buf, len);393393+ if (ret > 0) {394394+ ret2 = snprintf(buf + ret, len - ret, "%s", tmp);395395+ ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;396396+ }397397+ return ret;398398+}399399+400400+/* Get the name and type of given variable DIE, stored as "type\tname" */401401+static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)402402+{403403+ int ret, ret2;404404+405405+ ret = die_get_typename(vr_die, buf, len);406406+ if (ret < 0) {407407+ pr_debug("Failed to get type, make it unknown.\n");408408+ ret = snprintf(buf, len, "(unknown_type)");409409+ }410410+ if (ret > 0) {411411+ ret2 = snprintf(buf + ret, len - ret, "\t%s",412412+ dwarf_diename(vr_die));413413+ ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;414414+ }415415+ return ret;416416+}417417+487418/*488419 * Probe finder related functions489420 */···551374 return ref;552375}553376554554-/* Show a location */555555-static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)377377+/*378378+ * Convert a location into trace_arg.379379+ * If tvar == NULL, this just checks variable can be converted.380380+ */381381+static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,382382+ Dwarf_Op *fb_ops,383383+ struct probe_trace_arg *tvar)556384{557385 Dwarf_Attribute attr;558386 Dwarf_Op *op;···566384 Dwarf_Word offs = 0;567385 bool ref = false;568386 const char *regs;569569- struct probe_trace_arg *tvar = pf->tvar;570387 int ret;388388+389389+ if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)390390+ goto static_var;571391572392 /* TODO: handle more than 1 exprs */573393 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||574574- dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||394394+ dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||575395 nops == 0) {576396 /* TODO: Support const_value */577577- pr_err("Failed to find the location of %s at this address.\n"578578- " Perhaps, it has been optimized out.\n", pf->pvar->var);579397 return -ENOENT;580398 }581399582400 if (op->atom == DW_OP_addr) {401401+static_var:402402+ if (!tvar)403403+ return 0;583404 /* Static variables on memory (not stack), make @varname */584405 ret = strlen(dwarf_diename(vr_die));585406 tvar->value = zalloc(ret + 2);···597412598413 /* If this is based on frame buffer, set the offset */599414 if (op->atom == DW_OP_fbreg) {600600- if (pf->fb_ops == NULL) {601601- pr_warning("The attribute of frame base is not "602602- "supported.\n");415415+ if (fb_ops == NULL)603416 return -ENOTSUP;604604- }605417 ref = true;606418 offs = op->number;607607- op = &pf->fb_ops[0];419419+ op = &fb_ops[0];608420 }609421610422 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {···617435 } else if (op->atom == DW_OP_regx) {618436 regn = op->number;619437 } else {620620- pr_warning("DW_OP %x is not supported.\n", op->atom);438438+ pr_debug("DW_OP %x is not supported.\n", op->atom);621439 return -ENOTSUP;622440 }623441442442+ if (!tvar)443443+ return 0;444444+624445 regs = get_arch_regstr(regn);625446 if (!regs) {626626- pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);447447+ /* This should be a bug in DWARF or this tool */448448+ pr_warning("Mapping for DWARF register number %u "449449+ "missing on this architecture.", regn);627450 return -ERANGE;628451 }629452···853666 pr_debug("Converting variable %s into trace event.\n",854667 dwarf_diename(vr_die));855668856856- ret = convert_variable_location(vr_die, pf);857857- if (ret == 0 && pf->pvar->field) {669669+ ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,670670+ pf->tvar);671671+ if (ret == -ENOENT)672672+ pr_err("Failed to find the location of %s at this address.\n"673673+ " Perhaps, it has been optimized out.\n", pf->pvar->var);674674+ else if (ret == -ENOTSUP)675675+ pr_err("Sorry, we don't support this variable location yet.\n");676676+ else if (pf->pvar->field) {858677 ret = convert_variable_fields(vr_die, pf->pvar->var,859678 pf->pvar->field, &pf->tvar->ref,860679 &die_mem);···915722 pr_debug("Searching '%s' variable in context.\n",916723 pf->pvar->var);917724 /* Search child die for local variables and parameters. */918918- if (die_find_variable(sp_die, pf->pvar->var, &vr_die))725725+ if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))919726 ret = convert_variable(&vr_die, pf);920727 else {921728 /* Search upper class */922729 nscopes = dwarf_getscopes_die(sp_die, &scopes);923923- if (nscopes > 0) {924924- ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,925925- 0, NULL, 0, 0, &vr_die);926926- if (ret >= 0)730730+ while (nscopes-- > 1) {731731+ pr_debug("Searching variables in %s\n",732732+ dwarf_diename(&scopes[nscopes]));733733+ /* We should check this scope, so give dummy address */734734+ if (die_find_variable_at(&scopes[nscopes],735735+ pf->pvar->var, 0,736736+ &vr_die)) {927737 ret = convert_variable(&vr_die, pf);928928- else929929- ret = -ENOENT;738738+ goto found;739739+ }740740+ }741741+ if (scopes)930742 free(scopes);931931- } else932932- ret = -ENOENT;743743+ ret = -ENOENT;933744 }745745+found:934746 if (ret < 0)935747 pr_warning("Failed to find '%s' in this function.\n",936748 pf->pvar->var);937749 return ret;938750}939751940940-/* Show a probe point to output buffer */941941-static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)752752+/* Convert subprogram DIE to trace point */753753+static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,754754+ bool retprobe, struct probe_trace_point *tp)942755{943943- struct probe_trace_event *tev;944756 Dwarf_Addr eaddr;945945- Dwarf_Die die_mem;946757 const char *name;947947- int ret, i;948948- Dwarf_Attribute fb_attr;949949- size_t nops;950950-951951- if (pf->ntevs == pf->max_tevs) {952952- pr_warning("Too many( > %d) probe point found.\n",953953- pf->max_tevs);954954- return -ERANGE;955955- }956956- tev = &pf->tevs[pf->ntevs++];957957-958958- /* If no real subprogram, find a real one */959959- if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {960960- sp_die = die_find_real_subprogram(&pf->cu_die,961961- pf->addr, &die_mem);962962- if (!sp_die) {963963- pr_warning("Failed to find probe point in any "964964- "functions.\n");965965- return -ENOENT;966966- }967967- }968758969759 /* Copy the name of probe point */970760 name = dwarf_diename(sp_die);···957781 dwarf_diename(sp_die));958782 return -ENOENT;959783 }960960- tev->point.symbol = strdup(name);961961- if (tev->point.symbol == NULL)784784+ tp->symbol = strdup(name);785785+ if (tp->symbol == NULL)962786 return -ENOMEM;963963- tev->point.offset = (unsigned long)(pf->addr - eaddr);787787+ tp->offset = (unsigned long)(paddr - eaddr);964788 } else965789 /* This function has no name. */966966- tev->point.offset = (unsigned long)pf->addr;790790+ tp->offset = (unsigned long)paddr;967791968792 /* Return probe must be on the head of a subprogram */969969- if (pf->pev->point.retprobe) {970970- if (tev->point.offset != 0) {793793+ if (retprobe) {794794+ if (eaddr != paddr) {971795 pr_warning("Return probe must be on the head of"972796 " a real function\n");973797 return -EINVAL;974798 }975975- tev->point.retprobe = true;799799+ tp->retprobe = true;976800 }977801978978- pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,979979- tev->point.offset);802802+ return 0;803803+}804804+805805+/* Call probe_finder callback with real subprogram DIE */806806+static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)807807+{808808+ Dwarf_Die die_mem;809809+ Dwarf_Attribute fb_attr;810810+ size_t nops;811811+ int ret;812812+813813+ /* If no real subprogram, find a real one */814814+ if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {815815+ sp_die = die_find_real_subprogram(&pf->cu_die,816816+ pf->addr, &die_mem);817817+ if (!sp_die) {818818+ pr_warning("Failed to find probe point in any "819819+ "functions.\n");820820+ return -ENOENT;821821+ }822822+ }980823981824 /* Get the frame base attribute/ops */982825 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);···1015820#endif1016821 }101782210181018- /* Find each argument */10191019- tev->nargs = pf->pev->nargs;10201020- tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);10211021- if (tev->args == NULL)10221022- return -ENOMEM;10231023- for (i = 0; i < pf->pev->nargs; i++) {10241024- pf->pvar = &pf->pev->args[i];10251025- pf->tvar = &tev->args[i];10261026- ret = find_variable(sp_die, pf);10271027- if (ret != 0)10281028- return ret;10291029- }823823+ /* Call finder's callback handler */824824+ ret = pf->callback(sp_die, pf);10308251031826 /* *pf->fb_ops will be cached in libdw. Don't free it. */1032827 pf->fb_ops = NULL;10331033- return 0;828828+829829+ return ret;1034830}10358311036832/* Find probe point from its line number */···1057871 (int)i, lineno, (uintmax_t)addr);1058872 pf->addr = addr;105987310601060- ret = convert_probe_point(NULL, pf);874874+ ret = call_probe_finder(NULL, pf);1061875 /* Continuing, because target line might be inlined. */1062876 }1063877 return ret;···1170984 (int)i, lineno, (unsigned long long)addr);1171985 pf->addr = addr;117298611731173- ret = convert_probe_point(sp_die, pf);987987+ ret = call_probe_finder(sp_die, pf);1174988 /* Continuing, because target line might be inlined. */1175989 }1176990 /* TODO: deallocate lines, but how? */···12051019 pr_debug("found inline addr: 0x%jx\n",12061020 (uintmax_t)pf->addr);1207102112081208- param->retval = convert_probe_point(in_die, pf);10221022+ param->retval = call_probe_finder(in_die, pf);12091023 if (param->retval < 0)12101024 return DWARF_CB_ABORT;12111025 }···12431057 }12441058 pf->addr += pp->offset;12451059 /* TODO: Check the address in this function */12461246- param->retval = convert_probe_point(sp_die, pf);10601060+ param->retval = call_probe_finder(sp_die, pf);12471061 }12481062 } else {12491063 struct dwarf_callback_param _param = {.data = (void *)pf,···12651079 return _param.retval;12661080}1267108112681268-/* Find probe_trace_events specified by perf_probe_event from debuginfo */12691269-int find_probe_trace_events(int fd, struct perf_probe_event *pev,12701270- struct probe_trace_event **tevs, int max_tevs)10821082+/* Find probe points from debuginfo */10831083+static int find_probes(int fd, struct probe_finder *pf)12711084{12721272- struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};12731273- struct perf_probe_point *pp = &pev->point;10851085+ struct perf_probe_point *pp = &pf->pev->point;12741086 Dwarf_Off off, noff;12751087 size_t cuhl;12761088 Dwarf_Die *diep;12771277- Dwarf *dbg;10891089+ Dwarf *dbg = NULL;10901090+ Dwfl *dwfl;10911091+ Dwarf_Addr bias; /* Currently ignored */12781092 int ret = 0;1279109312801280- pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);12811281- if (pf.tevs == NULL)12821282- return -ENOMEM;12831283- *tevs = pf.tevs;12841284- pf.ntevs = 0;12851285-12861286- dbg = dwarf_begin(fd, DWARF_C_READ);10941094+ dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);12871095 if (!dbg) {12881096 pr_warning("No dwarf info found in the vmlinux - "12891097 "please rebuild with CONFIG_DEBUG_INFO=y.\n");12901290- free(pf.tevs);12911291- *tevs = NULL;12921098 return -EBADF;12931099 }1294110012951101#if _ELFUTILS_PREREQ(0, 142)12961102 /* Get the call frame information from this dwarf */12971297- pf.cfi = dwarf_getcfi(dbg);11031103+ pf->cfi = dwarf_getcfi(dbg);12981104#endif1299110513001106 off = 0;13011301- line_list__init(&pf.lcache);11071107+ line_list__init(&pf->lcache);13021108 /* Loop on CUs (Compilation Unit) */13031109 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&13041110 ret >= 0) {13051111 /* Get the DIE(Debugging Information Entry) of this CU */13061306- diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);11121112+ diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);13071113 if (!diep)13081114 continue;1309111513101116 /* Check if target file is included. */13111117 if (pp->file)13121312- pf.fname = cu_find_realpath(&pf.cu_die, pp->file);11181118+ pf->fname = cu_find_realpath(&pf->cu_die, pp->file);13131119 else13141314- pf.fname = NULL;11201120+ pf->fname = NULL;1315112113161316- if (!pp->file || pf.fname) {11221122+ if (!pp->file || pf->fname) {13171123 if (pp->function)13181318- ret = find_probe_point_by_func(&pf);11241124+ ret = find_probe_point_by_func(pf);13191125 else if (pp->lazy_line)13201320- ret = find_probe_point_lazy(NULL, &pf);11261126+ ret = find_probe_point_lazy(NULL, pf);13211127 else {13221322- pf.lno = pp->line;13231323- ret = find_probe_point_by_line(&pf);11281128+ pf->lno = pp->line;11291129+ ret = find_probe_point_by_line(pf);13241130 }13251131 }13261132 off = noff;13271133 }13281328- line_list__free(&pf.lcache);13291329- dwarf_end(dbg);11341134+ line_list__free(&pf->lcache);11351135+ if (dwfl)11361136+ dwfl_end(dwfl);1330113713311331- return (ret < 0) ? ret : pf.ntevs;11381138+ return ret;11391139+}11401140+11411141+/* Add a found probe point into trace event list */11421142+static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)11431143+{11441144+ struct trace_event_finder *tf =11451145+ container_of(pf, struct trace_event_finder, pf);11461146+ struct probe_trace_event *tev;11471147+ int ret, i;11481148+11491149+ /* Check number of tevs */11501150+ if (tf->ntevs == tf->max_tevs) {11511151+ pr_warning("Too many( > %d) probe point found.\n",11521152+ tf->max_tevs);11531153+ return -ERANGE;11541154+ }11551155+ tev = &tf->tevs[tf->ntevs++];11561156+11571157+ ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,11581158+ &tev->point);11591159+ if (ret < 0)11601160+ return ret;11611161+11621162+ pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,11631163+ tev->point.offset);11641164+11651165+ /* Find each argument */11661166+ tev->nargs = pf->pev->nargs;11671167+ tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);11681168+ if (tev->args == NULL)11691169+ return -ENOMEM;11701170+ for (i = 0; i < pf->pev->nargs; i++) {11711171+ pf->pvar = &pf->pev->args[i];11721172+ pf->tvar = &tev->args[i];11731173+ ret = find_variable(sp_die, pf);11741174+ if (ret != 0)11751175+ return ret;11761176+ }11771177+11781178+ return 0;11791179+}11801180+11811181+/* Find probe_trace_events specified by perf_probe_event from debuginfo */11821182+int find_probe_trace_events(int fd, struct perf_probe_event *pev,11831183+ struct probe_trace_event **tevs, int max_tevs)11841184+{11851185+ struct trace_event_finder tf = {11861186+ .pf = {.pev = pev, .callback = add_probe_trace_event},11871187+ .max_tevs = max_tevs};11881188+ int ret;11891189+11901190+ /* Allocate result tevs array */11911191+ *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);11921192+ if (*tevs == NULL)11931193+ return -ENOMEM;11941194+11951195+ tf.tevs = *tevs;11961196+ tf.ntevs = 0;11971197+11981198+ ret = find_probes(fd, &tf.pf);11991199+ if (ret < 0) {12001200+ free(*tevs);12011201+ *tevs = NULL;12021202+ return ret;12031203+ }12041204+12051205+ return (ret < 0) ? ret : tf.ntevs;12061206+}12071207+12081208+#define MAX_VAR_LEN 6412091209+12101210+/* Collect available variables in this scope */12111211+static int collect_variables_cb(Dwarf_Die *die_mem, void *data)12121212+{12131213+ struct available_var_finder *af = data;12141214+ struct variable_list *vl;12151215+ char buf[MAX_VAR_LEN];12161216+ int tag, ret;12171217+12181218+ vl = &af->vls[af->nvls - 1];12191219+12201220+ tag = dwarf_tag(die_mem);12211221+ if (tag == DW_TAG_formal_parameter ||12221222+ tag == DW_TAG_variable) {12231223+ ret = convert_variable_location(die_mem, af->pf.addr,12241224+ af->pf.fb_ops, NULL);12251225+ if (ret == 0) {12261226+ ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);12271227+ pr_debug2("Add new var: %s\n", buf);12281228+ if (ret > 0)12291229+ strlist__add(vl->vars, buf);12301230+ }12311231+ }12321232+12331233+ if (af->child && dwarf_haspc(die_mem, af->pf.addr))12341234+ return DIE_FIND_CB_CONTINUE;12351235+ else12361236+ return DIE_FIND_CB_SIBLING;12371237+}12381238+12391239+/* Add a found vars into available variables list */12401240+static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)12411241+{12421242+ struct available_var_finder *af =12431243+ container_of(pf, struct available_var_finder, pf);12441244+ struct variable_list *vl;12451245+ Dwarf_Die die_mem, *scopes = NULL;12461246+ int ret, nscopes;12471247+12481248+ /* Check number of tevs */12491249+ if (af->nvls == af->max_vls) {12501250+ pr_warning("Too many( > %d) probe point found.\n", af->max_vls);12511251+ return -ERANGE;12521252+ }12531253+ vl = &af->vls[af->nvls++];12541254+12551255+ ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,12561256+ &vl->point);12571257+ if (ret < 0)12581258+ return ret;12591259+12601260+ pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,12611261+ vl->point.offset);12621262+12631263+ /* Find local variables */12641264+ vl->vars = strlist__new(true, NULL);12651265+ if (vl->vars == NULL)12661266+ return -ENOMEM;12671267+ af->child = true;12681268+ die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);12691269+12701270+ /* Find external variables */12711271+ if (!af->externs)12721272+ goto out;12731273+ /* Don't need to search child DIE for externs. */12741274+ af->child = false;12751275+ nscopes = dwarf_getscopes_die(sp_die, &scopes);12761276+ while (nscopes-- > 1)12771277+ die_find_child(&scopes[nscopes], collect_variables_cb,12781278+ (void *)af, &die_mem);12791279+ if (scopes)12801280+ free(scopes);12811281+12821282+out:12831283+ if (strlist__empty(vl->vars)) {12841284+ strlist__delete(vl->vars);12851285+ vl->vars = NULL;12861286+ }12871287+12881288+ return ret;12891289+}12901290+12911291+/* Find available variables at given probe point */12921292+int find_available_vars_at(int fd, struct perf_probe_event *pev,12931293+ struct variable_list **vls, int max_vls,12941294+ bool externs)12951295+{12961296+ struct available_var_finder af = {12971297+ .pf = {.pev = pev, .callback = add_available_vars},12981298+ .max_vls = max_vls, .externs = externs};12991299+ int ret;13001300+13011301+ /* Allocate result vls array */13021302+ *vls = zalloc(sizeof(struct variable_list) * max_vls);13031303+ if (*vls == NULL)13041304+ return -ENOMEM;13051305+13061306+ af.vls = *vls;13071307+ af.nvls = 0;13081308+13091309+ ret = find_probes(fd, &af.pf);13101310+ if (ret < 0) {13111311+ /* Free vlist for error */13121312+ while (af.nvls--) {13131313+ if (af.vls[af.nvls].point.symbol)13141314+ free(af.vls[af.nvls].point.symbol);13151315+ if (af.vls[af.nvls].vars)13161316+ strlist__delete(af.vls[af.nvls].vars);13171317+ }13181318+ free(af.vls);13191319+ *vls = NULL;13201320+ return ret;13211321+ }13221322+13231323+ return (ret < 0) ? ret : af.nvls;13321324}1333132513341326/* Reverse search */13351335-int find_perf_probe_point(int fd, unsigned long addr,13361336- struct perf_probe_point *ppt)13271327+int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)13371328{13381329 Dwarf_Die cudie, spdie, indie;13391339- Dwarf *dbg;13301330+ Dwarf *dbg = NULL;13311331+ Dwfl *dwfl = NULL;13401332 Dwarf_Line *line;13411341- Dwarf_Addr laddr, eaddr;13331333+ Dwarf_Addr laddr, eaddr, bias = 0;13421334 const char *tmp;13431335 int lineno, ret = 0;13441336 bool found = false;1345133713461346- dbg = dwarf_begin(fd, DWARF_C_READ);13471347- if (!dbg)13481348- return -EBADF;13381338+ /* Open the live linux kernel */13391339+ dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);13401340+ if (!dbg) {13411341+ pr_warning("No dwarf info found in the vmlinux - "13421342+ "please rebuild with CONFIG_DEBUG_INFO=y.\n");13431343+ ret = -EINVAL;13441344+ goto end;13451345+ }1349134613471347+ /* Adjust address with bias */13481348+ addr += bias;13501349 /* Find cu die */13511351- if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {13501350+ if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {13511351+ pr_warning("No CU DIE is found at %lx\n", addr);13521352 ret = -EINVAL;13531353 goto end;13541354 }···15971225 }1598122615991227end:16001600- dwarf_end(dbg);12281228+ if (dwfl)12291229+ dwfl_end(dwfl);16011230 if (ret >= 0)16021231 ret = found ? 1 : 0;16031232 return ret;···17311358 struct line_finder *lf = param->data;17321359 struct line_range *lr = lf->lr;1733136013611361+ pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die),13621362+ dwarf_diename(sp_die));17341363 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&17351364 die_compare_name(sp_die, lr->function)) {17361365 lf->fname = dwarf_decl_file(sp_die);···17761401 Dwarf_Off off = 0, noff;17771402 size_t cuhl;17781403 Dwarf_Die *diep;17791779- Dwarf *dbg;14041404+ Dwarf *dbg = NULL;14051405+ Dwfl *dwfl;14061406+ Dwarf_Addr bias; /* Currently ignored */17801407 const char *comp_dir;1781140817821782- dbg = dwarf_begin(fd, DWARF_C_READ);14091409+ dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);17831410 if (!dbg) {17841411 pr_warning("No dwarf info found in the vmlinux - "17851412 "please rebuild with CONFIG_DEBUG_INFO=y.\n");···18271450 }1828145118291452 pr_debug("path: %s\n", lr->path);18301830- dwarf_end(dbg);18311831-14531453+ dwfl_end(dwfl);18321454 return (ret < 0) ? ret : lf.found;18331455}18341456
+27-4
tools/perf/util/probe-finder.h
···2222 int max_tevs);23232424/* Find a perf_probe_point from debuginfo */2525-extern int find_perf_probe_point(int fd, unsigned long addr,2525+extern int find_perf_probe_point(unsigned long addr,2626 struct perf_probe_point *ppt);27272828+/* Find a line range */2829extern int find_line_range(int fd, struct line_range *lr);3030+3131+/* Find available variables */3232+extern int find_available_vars_at(int fd, struct perf_probe_event *pev,3333+ struct variable_list **vls, int max_points,3434+ bool externs);29353036#include <dwarf.h>3137#include <libdw.h>3838+#include <libdwfl.h>3239#include <version.h>33403441struct probe_finder {3542 struct perf_probe_event *pev; /* Target probe event */3636- struct probe_trace_event *tevs; /* Result trace events */3737- int ntevs; /* Number of trace events */3838- int max_tevs; /* Max number of trace events */4343+4444+ /* Callback when a probe point is found */4545+ int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);39464047 /* For function searching */4148 int lno; /* Line number */···5851 Dwarf_Op *fb_ops; /* Frame base attribute */5952 struct perf_probe_arg *pvar; /* Current target variable */6053 struct probe_trace_arg *tvar; /* Current result variable */5454+};5555+5656+struct trace_event_finder {5757+ struct probe_finder pf;5858+ struct probe_trace_event *tevs; /* Found trace events */5959+ int ntevs; /* Number of trace events */6060+ int max_tevs; /* Max number of trace events */6161+};6262+6363+struct available_var_finder {6464+ struct probe_finder pf;6565+ struct variable_list *vls; /* Found variable lists */6666+ int nvls; /* Number of variable lists */6767+ int max_vls; /* Max no. of variable lists */6868+ bool externs; /* Find external vars too */6969+ bool child; /* Search child scopes */6170};62716372struct line_finder {