Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/urgent

+824 -237
+1 -1
include/linux/interrupt.h
··· 410 410 extern void softirq_init(void); 411 411 static inline void __raise_softirq_irqoff(unsigned int nr) 412 412 { 413 - trace_softirq_raise((struct softirq_action *)(unsigned long)nr, NULL); 413 + trace_softirq_raise(nr); 414 414 or_softirq_pending(1UL << nr); 415 415 } 416 416
+20 -34
include/trace/events/irq.h
··· 86 86 87 87 DECLARE_EVENT_CLASS(softirq, 88 88 89 - TP_PROTO(struct softirq_action *h, struct softirq_action *vec), 89 + TP_PROTO(unsigned int vec_nr), 90 90 91 - TP_ARGS(h, vec), 91 + TP_ARGS(vec_nr), 92 92 93 93 TP_STRUCT__entry( 94 - __field( int, vec ) 94 + __field( unsigned int, vec ) 95 95 ), 96 96 97 97 TP_fast_assign( 98 - if (vec) 99 - __entry->vec = (int)(h - vec); 100 - else 101 - __entry->vec = (int)(long)h; 98 + __entry->vec = vec_nr; 102 99 ), 103 100 104 - TP_printk("vec=%d [action=%s]", __entry->vec, 101 + TP_printk("vec=%u [action=%s]", __entry->vec, 105 102 show_softirq_name(__entry->vec)) 106 103 ); 107 104 108 105 /** 109 106 * softirq_entry - called immediately before the softirq handler 110 - * @h: pointer to struct softirq_action 111 - * @vec: pointer to first struct softirq_action in softirq_vec array 107 + * @vec_nr: softirq vector number 112 108 * 113 - * The @h parameter, contains a pointer to the struct softirq_action 114 - * which has a pointer to the action handler that is called. By subtracting 115 - * the @vec pointer from the @h pointer, we can determine the softirq 116 - * number. Also, when used in combination with the softirq_exit tracepoint 117 - * we can determine the softirq latency. 109 + * When used in combination with the softirq_exit tracepoint 110 + * we can determine the softirq handler runtine. 118 111 */ 119 112 DEFINE_EVENT(softirq, softirq_entry, 120 113 121 - TP_PROTO(struct softirq_action *h, struct softirq_action *vec), 114 + TP_PROTO(unsigned int vec_nr), 122 115 123 - TP_ARGS(h, vec) 116 + TP_ARGS(vec_nr) 124 117 ); 125 118 126 119 /** 127 120 * softirq_exit - called immediately after the softirq handler returns 128 - * @h: pointer to struct softirq_action 129 - * @vec: pointer to first struct softirq_action in softirq_vec array 121 + * @vec_nr: softirq vector number 130 122 * 131 - * The @h parameter contains a pointer to the struct softirq_action 132 - * that has handled the softirq. By subtracting the @vec pointer from 133 - * the @h pointer, we can determine the softirq number. Also, when used in 134 - * combination with the softirq_entry tracepoint we can determine the softirq 135 - * latency. 123 + * When used in combination with the softirq_entry tracepoint 124 + * we can determine the softirq handler runtine. 136 125 */ 137 126 DEFINE_EVENT(softirq, softirq_exit, 138 127 139 - TP_PROTO(struct softirq_action *h, struct softirq_action *vec), 128 + TP_PROTO(unsigned int vec_nr), 140 129 141 - TP_ARGS(h, vec) 130 + TP_ARGS(vec_nr) 142 131 ); 143 132 144 133 /** 145 134 * softirq_raise - called immediately when a softirq is raised 146 - * @h: pointer to struct softirq_action 147 - * @vec: pointer to first struct softirq_action in softirq_vec array 135 + * @vec_nr: softirq vector number 148 136 * 149 - * The @h parameter contains a pointer to the softirq vector number which is 150 - * raised. @vec is NULL and it means @h includes vector number not 151 - * softirq_action. When used in combination with the softirq_entry tracepoint 152 - * we can determine the softirq raise latency. 137 + * When used in combination with the softirq_entry tracepoint 138 + * we can determine the softirq raise to run latency. 153 139 */ 154 140 DEFINE_EVENT(softirq, softirq_raise, 155 141 156 - TP_PROTO(struct softirq_action *h, struct softirq_action *vec), 142 + TP_PROTO(unsigned int vec_nr), 157 143 158 - TP_ARGS(h, vec) 144 + TP_ARGS(vec_nr) 159 145 ); 160 146 161 147 #endif /* _TRACE_IRQ_H */
+9 -7
kernel/softirq.c
··· 229 229 230 230 do { 231 231 if (pending & 1) { 232 + unsigned int vec_nr = h - softirq_vec; 232 233 int prev_count = preempt_count(); 233 - kstat_incr_softirqs_this_cpu(h - softirq_vec); 234 234 235 - trace_softirq_entry(h, softirq_vec); 235 + kstat_incr_softirqs_this_cpu(vec_nr); 236 + 237 + trace_softirq_entry(vec_nr); 236 238 h->action(h); 237 - trace_softirq_exit(h, softirq_vec); 239 + trace_softirq_exit(vec_nr); 238 240 if (unlikely(prev_count != preempt_count())) { 239 - printk(KERN_ERR "huh, entered softirq %td %s %p" 241 + printk(KERN_ERR "huh, entered softirq %u %s %p" 240 242 "with preempt_count %08x," 241 - " exited with %08x?\n", h - softirq_vec, 242 - softirq_to_name[h - softirq_vec], 243 - h->action, prev_count, preempt_count()); 243 + " exited with %08x?\n", vec_nr, 244 + softirq_to_name[vec_nr], h->action, 245 + prev_count, preempt_count()); 244 246 preempt_count() = prev_count; 245 247 } 246 248
+17 -1
tools/perf/Documentation/perf-probe.txt
··· 16 16 or 17 17 'perf probe' --list 18 18 or 19 - 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 19 + 'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 20 + or 21 + 'perf probe' [options] --vars='PROBEPOINT' 20 22 21 23 DESCRIPTION 22 24 ----------- ··· 32 30 -k:: 33 31 --vmlinux=PATH:: 34 32 Specify vmlinux path which has debuginfo (Dwarf binary). 33 + 34 + -m:: 35 + --module=MODNAME:: 36 + Specify module name in which perf-probe searches probe points 37 + or lines. 35 38 36 39 -s:: 37 40 --source=PATH:: ··· 63 56 --line=:: 64 57 Show source code lines which can be probed. This needs an argument 65 58 which specifies a range of the source code. (see LINE SYNTAX for detail) 59 + 60 + -V:: 61 + --vars=:: 62 + Show available local variables at given probe point. The argument 63 + syntax is same as PROBE SYNTAX, but NO ARGs. 64 + 65 + --externs:: 66 + (Only for --vars) Show external defined variables in addition to local 67 + variables. 66 68 67 69 -f:: 68 70 --force::
+67 -11
tools/perf/builtin-probe.c
··· 50 50 bool list_events; 51 51 bool force_add; 52 52 bool show_lines; 53 + bool show_vars; 54 + bool show_ext_vars; 55 + bool mod_events; 53 56 int nevents; 54 57 struct perf_probe_event events[MAX_PROBES]; 55 58 struct strlist *dellist; 56 59 struct line_range line_range; 60 + const char *target_module; 57 61 int max_probe_points; 58 62 } params; 59 - 60 63 61 64 /* Parse an event definition. Note that any error must die. */ 62 65 static int parse_probe_event(const char *str) ··· 95 92 len = 0; 96 93 for (i = 0; i < argc; i++) 97 94 len += sprintf(&buf[len], "%s ", argv[i]); 95 + params.mod_events = true; 98 96 ret = parse_probe_event(buf); 99 97 free(buf); 100 98 return ret; ··· 104 100 static int opt_add_probe_event(const struct option *opt __used, 105 101 const char *str, int unset __used) 106 102 { 107 - if (str) 103 + if (str) { 104 + params.mod_events = true; 108 105 return parse_probe_event(str); 109 - else 106 + } else 110 107 return 0; 111 108 } 112 109 ··· 115 110 const char *str, int unset __used) 116 111 { 117 112 if (str) { 113 + params.mod_events = true; 118 114 if (!params.dellist) 119 115 params.dellist = strlist__new(true, NULL); 120 116 strlist__add(params.dellist, str); ··· 136 130 137 131 return ret; 138 132 } 133 + 134 + static int opt_show_vars(const struct option *opt __used, 135 + const char *str, int unset __used) 136 + { 137 + struct perf_probe_event *pev = &params.events[params.nevents]; 138 + int ret; 139 + 140 + if (!str) 141 + return 0; 142 + 143 + ret = parse_probe_event(str); 144 + if (!ret && pev->nargs != 0) { 145 + pr_err(" Error: '--vars' doesn't accept arguments.\n"); 146 + return -EINVAL; 147 + } 148 + params.show_vars = true; 149 + 150 + return ret; 151 + } 139 152 #endif 140 153 141 154 static const char * const probe_usage[] = { ··· 163 138 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 164 139 "perf probe --list", 165 140 #ifdef DWARF_SUPPORT 166 - "perf probe --line 'LINEDESC'", 141 + "perf probe [<options>] --line 'LINEDESC'", 142 + "perf probe [<options>] --vars 'PROBEPOINT'", 167 143 #endif 168 144 NULL 169 145 }; ··· 206 180 OPT_CALLBACK('L', "line", NULL, 207 181 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 208 182 "Show source code lines.", opt_show_lines), 183 + OPT_CALLBACK('V', "vars", NULL, 184 + "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", 185 + "Show accessible variables on PROBEDEF", opt_show_vars), 186 + OPT_BOOLEAN('\0', "externs", &params.show_ext_vars, 187 + "Show external variables too (with --vars only)"), 209 188 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 210 189 "file", "vmlinux pathname"), 211 190 OPT_STRING('s', "source", &symbol_conf.source_prefix, 212 191 "directory", "path to kernel source"), 192 + OPT_STRING('m', "module", &params.target_module, 193 + "modname", "target module name"), 213 194 #endif 214 195 OPT__DRY_RUN(&probe_event_dry_run), 215 196 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, ··· 250 217 usage_with_options(probe_usage, options); 251 218 252 219 if (params.list_events) { 253 - if (params.nevents != 0 || params.dellist) { 220 + if (params.mod_events) { 254 221 pr_err(" Error: Don't use --list with --add/--del.\n"); 255 222 usage_with_options(probe_usage, options); 256 223 } 257 224 if (params.show_lines) { 258 225 pr_err(" Error: Don't use --list with --line.\n"); 226 + usage_with_options(probe_usage, options); 227 + } 228 + if (params.show_vars) { 229 + pr_err(" Error: Don't use --list with --vars.\n"); 259 230 usage_with_options(probe_usage, options); 260 231 } 261 232 ret = show_perf_probe_events(); ··· 271 234 272 235 #ifdef DWARF_SUPPORT 273 236 if (params.show_lines) { 274 - if (params.nevents != 0 || params.dellist) { 275 - pr_warning(" Error: Don't use --line with" 276 - " --add/--del.\n"); 237 + if (params.mod_events) { 238 + pr_err(" Error: Don't use --line with" 239 + " --add/--del.\n"); 240 + usage_with_options(probe_usage, options); 241 + } 242 + if (params.show_vars) { 243 + pr_err(" Error: Don't use --line with --vars.\n"); 277 244 usage_with_options(probe_usage, options); 278 245 } 279 246 280 - ret = show_line_range(&params.line_range); 247 + ret = show_line_range(&params.line_range, params.target_module); 281 248 if (ret < 0) 282 249 pr_err(" Error: Failed to show lines. (%d)\n", ret); 250 + return ret; 251 + } 252 + if (params.show_vars) { 253 + if (params.mod_events) { 254 + pr_err(" Error: Don't use --vars with" 255 + " --add/--del.\n"); 256 + usage_with_options(probe_usage, options); 257 + } 258 + ret = show_available_vars(params.events, params.nevents, 259 + params.max_probe_points, 260 + params.target_module, 261 + params.show_ext_vars); 262 + if (ret < 0) 263 + pr_err(" Error: Failed to show vars. (%d)\n", ret); 283 264 return ret; 284 265 } 285 266 #endif ··· 313 258 314 259 if (params.nevents) { 315 260 ret = add_perf_probe_events(params.events, params.nevents, 316 - params.force_add, 317 - params.max_probe_points); 261 + params.max_probe_points, 262 + params.target_module, 263 + params.force_add); 318 264 if (ret < 0) { 319 265 pr_err(" Error: Failed to add events. (%d)\n", ret); 320 266 return ret;
+10
tools/perf/util/map.h
··· 215 215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); 216 216 } 217 217 218 + static inline 219 + struct symbol *machine__find_kernel_function_by_name(struct machine *self, 220 + const char *name, 221 + struct map **mapp, 222 + symbol_filter_t filter) 223 + { 224 + return map_groups__find_function_by_name(&self->kmaps, name, mapp, 225 + filter); 226 + } 227 + 218 228 int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, 219 229 int verbose, FILE *fp); 220 230
+149 -42
tools/perf/util/probe-event.c
··· 74 74 static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 75 75 static struct machine machine; 76 76 77 - /* Initialize symbol maps and path of vmlinux */ 77 + /* Initialize symbol maps and path of vmlinux/modules */ 78 78 static int init_vmlinux(void) 79 79 { 80 - struct dso *kernel; 81 80 int ret; 82 81 83 82 symbol_conf.sort_by_name = true; ··· 90 91 goto out; 91 92 } 92 93 93 - ret = machine__init(&machine, "/", 0); 94 + ret = machine__init(&machine, "", HOST_KERNEL_ID); 94 95 if (ret < 0) 95 96 goto out; 96 97 97 - kernel = dso__new_kernel(symbol_conf.vmlinux_name); 98 - if (kernel == NULL) 99 - die("Failed to create kernel dso."); 100 - 101 - ret = __machine__create_kernel_maps(&machine, kernel); 102 - if (ret < 0) 103 - pr_debug("Failed to create kernel maps.\n"); 104 - 98 + if (machine__create_kernel_maps(&machine) < 0) { 99 + pr_debug("machine__create_kernel_maps "); 100 + goto out; 101 + } 105 102 out: 106 103 if (ret < 0) 107 104 pr_warning("Failed to init vmlinux path.\n"); 108 105 return ret; 109 106 } 110 107 111 - #ifdef DWARF_SUPPORT 112 - static int open_vmlinux(void) 108 + static struct symbol *__find_kernel_function_by_name(const char *name, 109 + struct map **mapp) 113 110 { 114 - if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { 115 - pr_debug("Failed to load kernel map.\n"); 116 - return -EINVAL; 111 + return machine__find_kernel_function_by_name(&machine, name, mapp, 112 + NULL); 113 + } 114 + 115 + const char *kernel_get_module_path(const char *module) 116 + { 117 + struct dso *dso; 118 + 119 + if (module) { 120 + list_for_each_entry(dso, &machine.kernel_dsos, node) { 121 + if (strncmp(dso->short_name + 1, module, 122 + dso->short_name_len - 2) == 0) 123 + goto found; 124 + } 125 + pr_debug("Failed to find module %s.\n", module); 126 + return NULL; 127 + } else { 128 + dso = machine.vmlinux_maps[MAP__FUNCTION]->dso; 129 + if (dso__load_vmlinux_path(dso, 130 + machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { 131 + pr_debug("Failed to load kernel map.\n"); 132 + return NULL; 133 + } 117 134 } 118 - pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name); 119 - return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 135 + found: 136 + return dso->long_name; 137 + } 138 + 139 + #ifdef DWARF_SUPPORT 140 + static int open_vmlinux(const char *module) 141 + { 142 + const char *path = kernel_get_module_path(module); 143 + if (!path) { 144 + pr_err("Failed to find path of %s module", module ?: "kernel"); 145 + return -ENOENT; 146 + } 147 + pr_debug("Try to open %s\n", path); 148 + return open(path, O_RDONLY); 120 149 } 121 150 122 151 /* ··· 152 125 * Currently only handles kprobes. 153 126 */ 154 127 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 155 - struct perf_probe_point *pp) 128 + struct perf_probe_point *pp) 156 129 { 157 130 struct symbol *sym; 158 - int fd, ret = -ENOENT; 131 + struct map *map; 132 + u64 addr; 133 + int ret = -ENOENT; 159 134 160 - sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 161 - tp->symbol, NULL); 135 + sym = __find_kernel_function_by_name(tp->symbol, &map); 162 136 if (sym) { 163 - fd = open_vmlinux(); 164 - if (fd >= 0) { 165 - ret = find_perf_probe_point(fd, 166 - sym->start + tp->offset, pp); 167 - close(fd); 168 - } 137 + addr = map->unmap_ip(map, sym->start + tp->offset); 138 + pr_debug("try to find %s+%ld@%llx\n", tp->symbol, 139 + tp->offset, addr); 140 + ret = find_perf_probe_point((unsigned long)addr, pp); 169 141 } 170 142 if (ret <= 0) { 171 143 pr_debug("Failed to find corresponding probes from " ··· 182 156 /* Try to find perf_probe_event with debuginfo */ 183 157 static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 184 158 struct probe_trace_event **tevs, 185 - int max_tevs) 159 + int max_tevs, const char *module) 186 160 { 187 161 bool need_dwarf = perf_probe_event_need_dwarf(pev); 188 162 int fd, ntevs; 189 163 190 - fd = open_vmlinux(); 164 + fd = open_vmlinux(module); 191 165 if (fd < 0) { 192 166 if (need_dwarf) { 193 167 pr_warning("Failed to open debuginfo file.\n"); ··· 326 300 * Show line-range always requires debuginfo to find source file and 327 301 * line number. 328 302 */ 329 - int show_line_range(struct line_range *lr) 303 + int show_line_range(struct line_range *lr, const char *module) 330 304 { 331 305 int l = 1; 332 306 struct line_node *ln; ··· 339 313 if (ret < 0) 340 314 return ret; 341 315 342 - fd = open_vmlinux(); 316 + fd = open_vmlinux(module); 343 317 if (fd < 0) { 344 318 pr_warning("Failed to open debuginfo file.\n"); 345 319 return fd; ··· 404 378 return ret; 405 379 } 406 380 381 + static int show_available_vars_at(int fd, struct perf_probe_event *pev, 382 + int max_vls, bool externs) 383 + { 384 + char *buf; 385 + int ret, i; 386 + struct str_node *node; 387 + struct variable_list *vls = NULL, *vl; 388 + 389 + buf = synthesize_perf_probe_point(&pev->point); 390 + if (!buf) 391 + return -EINVAL; 392 + pr_debug("Searching variables at %s\n", buf); 393 + 394 + ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); 395 + if (ret > 0) { 396 + /* Some variables were found */ 397 + fprintf(stdout, "Available variables at %s\n", buf); 398 + for (i = 0; i < ret; i++) { 399 + vl = &vls[i]; 400 + /* 401 + * A probe point might be converted to 402 + * several trace points. 403 + */ 404 + fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 405 + vl->point.offset); 406 + free(vl->point.symbol); 407 + if (vl->vars) { 408 + strlist__for_each(node, vl->vars) 409 + fprintf(stdout, "\t\t%s\n", node->s); 410 + strlist__delete(vl->vars); 411 + } else 412 + fprintf(stdout, "(No variables)\n"); 413 + } 414 + free(vls); 415 + } else 416 + pr_err("Failed to find variables at %s (%d)\n", buf, ret); 417 + 418 + free(buf); 419 + return ret; 420 + } 421 + 422 + /* Show available variables on given probe point */ 423 + int show_available_vars(struct perf_probe_event *pevs, int npevs, 424 + int max_vls, const char *module, bool externs) 425 + { 426 + int i, fd, ret = 0; 427 + 428 + ret = init_vmlinux(); 429 + if (ret < 0) 430 + return ret; 431 + 432 + fd = open_vmlinux(module); 433 + if (fd < 0) { 434 + pr_warning("Failed to open debuginfo file.\n"); 435 + return fd; 436 + } 437 + 438 + setup_pager(); 439 + 440 + for (i = 0; i < npevs && ret >= 0; i++) 441 + ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); 442 + 443 + close(fd); 444 + return ret; 445 + } 446 + 407 447 #else /* !DWARF_SUPPORT */ 408 448 409 449 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 410 - struct perf_probe_point *pp) 450 + struct perf_probe_point *pp) 411 451 { 452 + struct symbol *sym; 453 + 454 + sym = __find_kernel_function_by_name(tp->symbol, NULL); 455 + if (!sym) { 456 + pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 457 + return -ENOENT; 458 + } 412 459 pp->function = strdup(tp->symbol); 413 460 if (pp->function == NULL) 414 461 return -ENOMEM; ··· 493 394 494 395 static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 495 396 struct probe_trace_event **tevs __unused, 496 - int max_tevs __unused) 397 + int max_tevs __unused, const char *mod __unused) 497 398 { 498 399 if (perf_probe_event_need_dwarf(pev)) { 499 400 pr_warning("Debuginfo-analysis is not supported.\n"); ··· 502 403 return 0; 503 404 } 504 405 505 - int show_line_range(struct line_range *lr __unused) 406 + int show_line_range(struct line_range *lr __unused, const char *module __unused) 506 407 { 507 408 pr_warning("Debuginfo-analysis is not supported.\n"); 508 409 return -ENOSYS; 509 410 } 510 411 412 + int show_available_vars(struct perf_probe_event *pevs __unused, 413 + int npevs __unused, int max_vls __unused, 414 + const char *module __unused, bool externs __unused) 415 + { 416 + pr_warning("Debuginfo-analysis is not supported.\n"); 417 + return -ENOSYS; 418 + } 511 419 #endif 512 420 513 421 int parse_line_range_desc(const char *arg, struct line_range *lr) ··· 1193 1087 } 1194 1088 1195 1089 static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1196 - struct perf_probe_event *pev) 1090 + struct perf_probe_event *pev) 1197 1091 { 1198 1092 char buf[64] = ""; 1199 1093 int i, ret; ··· 1622 1516 1623 1517 static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1624 1518 struct probe_trace_event **tevs, 1625 - int max_tevs) 1519 + int max_tevs, const char *module) 1626 1520 { 1627 1521 struct symbol *sym; 1628 1522 int ret = 0, i; 1629 1523 struct probe_trace_event *tev; 1630 1524 1631 1525 /* Convert perf_probe_event with debuginfo */ 1632 - ret = try_to_find_probe_trace_events(pev, tevs, max_tevs); 1526 + ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); 1633 1527 if (ret != 0) 1634 1528 return ret; 1635 1529 ··· 1678 1572 } 1679 1573 1680 1574 /* Currently just checking function name from symbol map */ 1681 - sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION], 1682 - tev->point.symbol, NULL); 1575 + sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1683 1576 if (!sym) { 1684 1577 pr_warning("Kernel symbol \'%s\' not found.\n", 1685 1578 tev->point.symbol); ··· 1701 1596 }; 1702 1597 1703 1598 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1704 - bool force_add, int max_tevs) 1599 + int max_tevs, const char *module, bool force_add) 1705 1600 { 1706 1601 int i, j, ret; 1707 1602 struct __event_package *pkgs; ··· 1722 1617 pkgs[i].pev = &pevs[i]; 1723 1618 /* Convert with or without debuginfo */ 1724 1619 ret = convert_to_probe_trace_events(pkgs[i].pev, 1725 - &pkgs[i].tevs, max_tevs); 1620 + &pkgs[i].tevs, 1621 + max_tevs, 1622 + module); 1726 1623 if (ret < 0) 1727 1624 goto end; 1728 1625 pkgs[i].ntevs = ret;
+14 -2
tools/perf/util/probe-event.h
··· 90 90 struct list_head line_list; /* Visible lines */ 91 91 }; 92 92 93 + /* List of variables */ 94 + struct variable_list { 95 + struct probe_trace_point point; /* Actual probepoint */ 96 + struct strlist *vars; /* Available variables */ 97 + }; 98 + 93 99 /* Command string to events */ 94 100 extern int parse_perf_probe_command(const char *cmd, 95 101 struct perf_probe_event *pev); ··· 115 109 /* Command string to line-range */ 116 110 extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 117 111 112 + /* Internal use: Return kernel/module path */ 113 + extern const char *kernel_get_module_path(const char *module); 118 114 119 115 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 120 - bool force_add, int max_probe_points); 116 + int max_probe_points, const char *module, 117 + bool force_add); 121 118 extern int del_perf_probe_events(struct strlist *dellist); 122 119 extern int show_perf_probe_events(void); 123 - extern int show_line_range(struct line_range *lr); 120 + extern int show_line_range(struct line_range *lr, const char *module); 121 + extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 122 + int max_probe_points, const char *module, 123 + bool externs); 124 124 125 125 126 126 /* Maximum index number of event-name postfix */
+510 -134
tools/perf/util/probe-finder.c
··· 116 116 } 117 117 } 118 118 119 + /* Dwarf FL wrappers */ 120 + 121 + static int __linux_kernel_find_elf(Dwfl_Module *mod, 122 + void **userdata, 123 + const char *module_name, 124 + Dwarf_Addr base, 125 + char **file_name, Elf **elfp) 126 + { 127 + int fd; 128 + const char *path = kernel_get_module_path(module_name); 129 + 130 + if (path) { 131 + fd = open(path, O_RDONLY); 132 + if (fd >= 0) { 133 + *file_name = strdup(path); 134 + return fd; 135 + } 136 + } 137 + /* If failed, try to call standard method */ 138 + return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, 139 + file_name, elfp); 140 + } 141 + 142 + static char *debuginfo_path; /* Currently dummy */ 143 + 144 + static const Dwfl_Callbacks offline_callbacks = { 145 + .find_debuginfo = dwfl_standard_find_debuginfo, 146 + .debuginfo_path = &debuginfo_path, 147 + 148 + .section_address = dwfl_offline_section_address, 149 + 150 + /* We use this table for core files too. */ 151 + .find_elf = dwfl_build_id_find_elf, 152 + }; 153 + 154 + static const Dwfl_Callbacks kernel_callbacks = { 155 + .find_debuginfo = dwfl_standard_find_debuginfo, 156 + .debuginfo_path = &debuginfo_path, 157 + 158 + .find_elf = __linux_kernel_find_elf, 159 + .section_address = dwfl_linux_kernel_module_section_address, 160 + }; 161 + 162 + /* Get a Dwarf from offline image */ 163 + static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) 164 + { 165 + Dwfl_Module *mod; 166 + Dwarf *dbg = NULL; 167 + 168 + if (!dwflp) 169 + return NULL; 170 + 171 + *dwflp = dwfl_begin(&offline_callbacks); 172 + if (!*dwflp) 173 + return NULL; 174 + 175 + mod = dwfl_report_offline(*dwflp, "", "", fd); 176 + if (!mod) 177 + goto error; 178 + 179 + dbg = dwfl_module_getdwarf(mod, bias); 180 + if (!dbg) { 181 + error: 182 + dwfl_end(*dwflp); 183 + *dwflp = NULL; 184 + } 185 + return dbg; 186 + } 187 + 188 + /* Get a Dwarf from live kernel image */ 189 + static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, 190 + Dwarf_Addr *bias) 191 + { 192 + Dwarf *dbg; 193 + 194 + if (!dwflp) 195 + return NULL; 196 + 197 + *dwflp = dwfl_begin(&kernel_callbacks); 198 + if (!*dwflp) 199 + return NULL; 200 + 201 + /* Load the kernel dwarves: Don't care the result here */ 202 + dwfl_linux_kernel_report_kernel(*dwflp); 203 + dwfl_linux_kernel_report_modules(*dwflp); 204 + 205 + dbg = dwfl_addrdwarf(*dwflp, addr, bias); 206 + /* Here, check whether we could get a real dwarf */ 207 + if (!dbg) { 208 + dwfl_end(*dwflp); 209 + *dwflp = NULL; 210 + } 211 + return dbg; 212 + } 213 + 119 214 /* Dwarf wrappers */ 120 215 121 216 /* Find the realpath of the target file. */ ··· 255 160 return name ? (strcmp(tname, name) == 0) : false; 256 161 } 257 162 258 - /* Get type die, but skip qualifiers and typedef */ 259 - static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 163 + /* Get type die */ 164 + static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 260 165 { 261 166 Dwarf_Attribute attr; 167 + 168 + if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && 169 + dwarf_formref_die(&attr, die_mem)) 170 + return die_mem; 171 + else 172 + return NULL; 173 + } 174 + 175 + /* Get a type die, but skip qualifiers */ 176 + static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 177 + { 262 178 int tag; 263 179 264 180 do { 265 - if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || 266 - dwarf_formref_die(&attr, die_mem) == NULL) 267 - return NULL; 268 - 269 - tag = dwarf_tag(die_mem); 270 - vr_die = die_mem; 181 + vr_die = die_get_type(vr_die, die_mem); 182 + if (!vr_die) 183 + break; 184 + tag = dwarf_tag(vr_die); 271 185 } while (tag == DW_TAG_const_type || 272 186 tag == DW_TAG_restrict_type || 273 187 tag == DW_TAG_volatile_type || 274 - tag == DW_TAG_shared_type || 275 - tag == DW_TAG_typedef); 188 + tag == DW_TAG_shared_type); 276 189 277 - return die_mem; 190 + return vr_die; 191 + } 192 + 193 + /* Get a type die, but skip qualifiers and typedef */ 194 + static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 195 + { 196 + do { 197 + vr_die = __die_get_real_type(vr_die, die_mem); 198 + } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); 199 + 200 + return vr_die; 278 201 } 279 202 280 203 static bool die_is_signed_type(Dwarf_Die *tp_die) ··· 433 320 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); 434 321 } 435 322 323 + struct __find_variable_param { 324 + const char *name; 325 + Dwarf_Addr addr; 326 + }; 327 + 436 328 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 437 329 { 438 - const char *name = data; 330 + struct __find_variable_param *fvp = data; 439 331 int tag; 440 332 441 333 tag = dwarf_tag(die_mem); 442 334 if ((tag == DW_TAG_formal_parameter || 443 335 tag == DW_TAG_variable) && 444 - die_compare_name(die_mem, name)) 336 + die_compare_name(die_mem, fvp->name)) 445 337 return DIE_FIND_CB_FOUND; 446 338 447 - return DIE_FIND_CB_CONTINUE; 339 + if (dwarf_haspc(die_mem, fvp->addr)) 340 + return DIE_FIND_CB_CONTINUE; 341 + else 342 + return DIE_FIND_CB_SIBLING; 448 343 } 449 344 450 - /* Find a variable called 'name' */ 451 - static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, 452 - Dwarf_Die *die_mem) 345 + /* Find a variable called 'name' at given address */ 346 + static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, 347 + Dwarf_Addr addr, Dwarf_Die *die_mem) 453 348 { 454 - return die_find_child(sp_die, __die_find_variable_cb, (void *)name, 349 + struct __find_variable_param fvp = { .name = name, .addr = addr}; 350 + 351 + return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, 455 352 die_mem); 456 353 } 457 354 ··· 484 361 die_mem); 485 362 } 486 363 364 + /* Get the name of given variable DIE */ 365 + static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) 366 + { 367 + Dwarf_Die type; 368 + int tag, ret, ret2; 369 + const char *tmp = ""; 370 + 371 + if (__die_get_real_type(vr_die, &type) == NULL) 372 + return -ENOENT; 373 + 374 + tag = dwarf_tag(&type); 375 + if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) 376 + tmp = "*"; 377 + else if (tag == DW_TAG_subroutine_type) { 378 + /* Function pointer */ 379 + ret = snprintf(buf, len, "(function_type)"); 380 + return (ret >= len) ? -E2BIG : ret; 381 + } else { 382 + if (!dwarf_diename(&type)) 383 + return -ENOENT; 384 + if (tag == DW_TAG_union_type) 385 + tmp = "union "; 386 + else if (tag == DW_TAG_structure_type) 387 + tmp = "struct "; 388 + /* Write a base name */ 389 + ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); 390 + return (ret >= len) ? -E2BIG : ret; 391 + } 392 + ret = die_get_typename(&type, buf, len); 393 + if (ret > 0) { 394 + ret2 = snprintf(buf + ret, len - ret, "%s", tmp); 395 + ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; 396 + } 397 + return ret; 398 + } 399 + 400 + /* Get the name and type of given variable DIE, stored as "type\tname" */ 401 + static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) 402 + { 403 + int ret, ret2; 404 + 405 + ret = die_get_typename(vr_die, buf, len); 406 + if (ret < 0) { 407 + pr_debug("Failed to get type, make it unknown.\n"); 408 + ret = snprintf(buf, len, "(unknown_type)"); 409 + } 410 + if (ret > 0) { 411 + ret2 = snprintf(buf + ret, len - ret, "\t%s", 412 + dwarf_diename(vr_die)); 413 + ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; 414 + } 415 + return ret; 416 + } 417 + 487 418 /* 488 419 * Probe finder related functions 489 420 */ ··· 551 374 return ref; 552 375 } 553 376 554 - /* Show a location */ 555 - static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) 377 + /* 378 + * Convert a location into trace_arg. 379 + * If tvar == NULL, this just checks variable can be converted. 380 + */ 381 + static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 382 + Dwarf_Op *fb_ops, 383 + struct probe_trace_arg *tvar) 556 384 { 557 385 Dwarf_Attribute attr; 558 386 Dwarf_Op *op; ··· 566 384 Dwarf_Word offs = 0; 567 385 bool ref = false; 568 386 const char *regs; 569 - struct probe_trace_arg *tvar = pf->tvar; 570 387 int ret; 388 + 389 + if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 390 + goto static_var; 571 391 572 392 /* TODO: handle more than 1 exprs */ 573 393 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 574 - dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 || 394 + dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 575 395 nops == 0) { 576 396 /* TODO: Support const_value */ 577 - pr_err("Failed to find the location of %s at this address.\n" 578 - " Perhaps, it has been optimized out.\n", pf->pvar->var); 579 397 return -ENOENT; 580 398 } 581 399 582 400 if (op->atom == DW_OP_addr) { 401 + static_var: 402 + if (!tvar) 403 + return 0; 583 404 /* Static variables on memory (not stack), make @varname */ 584 405 ret = strlen(dwarf_diename(vr_die)); 585 406 tvar->value = zalloc(ret + 2); ··· 597 412 598 413 /* If this is based on frame buffer, set the offset */ 599 414 if (op->atom == DW_OP_fbreg) { 600 - if (pf->fb_ops == NULL) { 601 - pr_warning("The attribute of frame base is not " 602 - "supported.\n"); 415 + if (fb_ops == NULL) 603 416 return -ENOTSUP; 604 - } 605 417 ref = true; 606 418 offs = op->number; 607 - op = &pf->fb_ops[0]; 419 + op = &fb_ops[0]; 608 420 } 609 421 610 422 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { ··· 617 435 } else if (op->atom == DW_OP_regx) { 618 436 regn = op->number; 619 437 } else { 620 - pr_warning("DW_OP %x is not supported.\n", op->atom); 438 + pr_debug("DW_OP %x is not supported.\n", op->atom); 621 439 return -ENOTSUP; 622 440 } 623 441 442 + if (!tvar) 443 + return 0; 444 + 624 445 regs = get_arch_regstr(regn); 625 446 if (!regs) { 626 - pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn); 447 + /* This should be a bug in DWARF or this tool */ 448 + pr_warning("Mapping for DWARF register number %u " 449 + "missing on this architecture.", regn); 627 450 return -ERANGE; 628 451 } 629 452 ··· 853 666 pr_debug("Converting variable %s into trace event.\n", 854 667 dwarf_diename(vr_die)); 855 668 856 - ret = convert_variable_location(vr_die, pf); 857 - if (ret == 0 && pf->pvar->field) { 669 + ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 670 + pf->tvar); 671 + if (ret == -ENOENT) 672 + pr_err("Failed to find the location of %s at this address.\n" 673 + " Perhaps, it has been optimized out.\n", pf->pvar->var); 674 + else if (ret == -ENOTSUP) 675 + pr_err("Sorry, we don't support this variable location yet.\n"); 676 + else if (pf->pvar->field) { 858 677 ret = convert_variable_fields(vr_die, pf->pvar->var, 859 678 pf->pvar->field, &pf->tvar->ref, 860 679 &die_mem); ··· 915 722 pr_debug("Searching '%s' variable in context.\n", 916 723 pf->pvar->var); 917 724 /* Search child die for local variables and parameters. */ 918 - if (die_find_variable(sp_die, pf->pvar->var, &vr_die)) 725 + if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) 919 726 ret = convert_variable(&vr_die, pf); 920 727 else { 921 728 /* Search upper class */ 922 729 nscopes = dwarf_getscopes_die(sp_die, &scopes); 923 - if (nscopes > 0) { 924 - ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var, 925 - 0, NULL, 0, 0, &vr_die); 926 - if (ret >= 0) 730 + while (nscopes-- > 1) { 731 + pr_debug("Searching variables in %s\n", 732 + dwarf_diename(&scopes[nscopes])); 733 + /* We should check this scope, so give dummy address */ 734 + if (die_find_variable_at(&scopes[nscopes], 735 + pf->pvar->var, 0, 736 + &vr_die)) { 927 737 ret = convert_variable(&vr_die, pf); 928 - else 929 - ret = -ENOENT; 738 + goto found; 739 + } 740 + } 741 + if (scopes) 930 742 free(scopes); 931 - } else 932 - ret = -ENOENT; 743 + ret = -ENOENT; 933 744 } 745 + found: 934 746 if (ret < 0) 935 747 pr_warning("Failed to find '%s' in this function.\n", 936 748 pf->pvar->var); 937 749 return ret; 938 750 } 939 751 940 - /* Show a probe point to output buffer */ 941 - static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 752 + /* Convert subprogram DIE to trace point */ 753 + static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 754 + bool retprobe, struct probe_trace_point *tp) 942 755 { 943 - struct probe_trace_event *tev; 944 756 Dwarf_Addr eaddr; 945 - Dwarf_Die die_mem; 946 757 const char *name; 947 - int ret, i; 948 - Dwarf_Attribute fb_attr; 949 - size_t nops; 950 - 951 - if (pf->ntevs == pf->max_tevs) { 952 - pr_warning("Too many( > %d) probe point found.\n", 953 - pf->max_tevs); 954 - return -ERANGE; 955 - } 956 - tev = &pf->tevs[pf->ntevs++]; 957 - 958 - /* If no real subprogram, find a real one */ 959 - if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 960 - sp_die = die_find_real_subprogram(&pf->cu_die, 961 - pf->addr, &die_mem); 962 - if (!sp_die) { 963 - pr_warning("Failed to find probe point in any " 964 - "functions.\n"); 965 - return -ENOENT; 966 - } 967 - } 968 758 969 759 /* Copy the name of probe point */ 970 760 name = dwarf_diename(sp_die); ··· 957 781 dwarf_diename(sp_die)); 958 782 return -ENOENT; 959 783 } 960 - tev->point.symbol = strdup(name); 961 - if (tev->point.symbol == NULL) 784 + tp->symbol = strdup(name); 785 + if (tp->symbol == NULL) 962 786 return -ENOMEM; 963 - tev->point.offset = (unsigned long)(pf->addr - eaddr); 787 + tp->offset = (unsigned long)(paddr - eaddr); 964 788 } else 965 789 /* This function has no name. */ 966 - tev->point.offset = (unsigned long)pf->addr; 790 + tp->offset = (unsigned long)paddr; 967 791 968 792 /* Return probe must be on the head of a subprogram */ 969 - if (pf->pev->point.retprobe) { 970 - if (tev->point.offset != 0) { 793 + if (retprobe) { 794 + if (eaddr != paddr) { 971 795 pr_warning("Return probe must be on the head of" 972 796 " a real function\n"); 973 797 return -EINVAL; 974 798 } 975 - tev->point.retprobe = true; 799 + tp->retprobe = true; 976 800 } 977 801 978 - pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 979 - tev->point.offset); 802 + return 0; 803 + } 804 + 805 + /* Call probe_finder callback with real subprogram DIE */ 806 + static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) 807 + { 808 + Dwarf_Die die_mem; 809 + Dwarf_Attribute fb_attr; 810 + size_t nops; 811 + int ret; 812 + 813 + /* If no real subprogram, find a real one */ 814 + if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 815 + sp_die = die_find_real_subprogram(&pf->cu_die, 816 + pf->addr, &die_mem); 817 + if (!sp_die) { 818 + pr_warning("Failed to find probe point in any " 819 + "functions.\n"); 820 + return -ENOENT; 821 + } 822 + } 980 823 981 824 /* Get the frame base attribute/ops */ 982 825 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); ··· 1015 820 #endif 1016 821 } 1017 822 1018 - /* Find each argument */ 1019 - tev->nargs = pf->pev->nargs; 1020 - tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1021 - if (tev->args == NULL) 1022 - return -ENOMEM; 1023 - for (i = 0; i < pf->pev->nargs; i++) { 1024 - pf->pvar = &pf->pev->args[i]; 1025 - pf->tvar = &tev->args[i]; 1026 - ret = find_variable(sp_die, pf); 1027 - if (ret != 0) 1028 - return ret; 1029 - } 823 + /* Call finder's callback handler */ 824 + ret = pf->callback(sp_die, pf); 1030 825 1031 826 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 1032 827 pf->fb_ops = NULL; 1033 - return 0; 828 + 829 + return ret; 1034 830 } 1035 831 1036 832 /* Find probe point from its line number */ ··· 1057 871 (int)i, lineno, (uintmax_t)addr); 1058 872 pf->addr = addr; 1059 873 1060 - ret = convert_probe_point(NULL, pf); 874 + ret = call_probe_finder(NULL, pf); 1061 875 /* Continuing, because target line might be inlined. */ 1062 876 } 1063 877 return ret; ··· 1170 984 (int)i, lineno, (unsigned long long)addr); 1171 985 pf->addr = addr; 1172 986 1173 - ret = convert_probe_point(sp_die, pf); 987 + ret = call_probe_finder(sp_die, pf); 1174 988 /* Continuing, because target line might be inlined. */ 1175 989 } 1176 990 /* TODO: deallocate lines, but how? */ ··· 1205 1019 pr_debug("found inline addr: 0x%jx\n", 1206 1020 (uintmax_t)pf->addr); 1207 1021 1208 - param->retval = convert_probe_point(in_die, pf); 1022 + param->retval = call_probe_finder(in_die, pf); 1209 1023 if (param->retval < 0) 1210 1024 return DWARF_CB_ABORT; 1211 1025 } ··· 1243 1057 } 1244 1058 pf->addr += pp->offset; 1245 1059 /* TODO: Check the address in this function */ 1246 - param->retval = convert_probe_point(sp_die, pf); 1060 + param->retval = call_probe_finder(sp_die, pf); 1247 1061 } 1248 1062 } else { 1249 1063 struct dwarf_callback_param _param = {.data = (void *)pf, ··· 1265 1079 return _param.retval; 1266 1080 } 1267 1081 1268 - /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1269 - int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1270 - struct probe_trace_event **tevs, int max_tevs) 1082 + /* Find probe points from debuginfo */ 1083 + static int find_probes(int fd, struct probe_finder *pf) 1271 1084 { 1272 - struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; 1273 - struct perf_probe_point *pp = &pev->point; 1085 + struct perf_probe_point *pp = &pf->pev->point; 1274 1086 Dwarf_Off off, noff; 1275 1087 size_t cuhl; 1276 1088 Dwarf_Die *diep; 1277 - Dwarf *dbg; 1089 + Dwarf *dbg = NULL; 1090 + Dwfl *dwfl; 1091 + Dwarf_Addr bias; /* Currently ignored */ 1278 1092 int ret = 0; 1279 1093 1280 - pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1281 - if (pf.tevs == NULL) 1282 - return -ENOMEM; 1283 - *tevs = pf.tevs; 1284 - pf.ntevs = 0; 1285 - 1286 - dbg = dwarf_begin(fd, DWARF_C_READ); 1094 + dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1287 1095 if (!dbg) { 1288 1096 pr_warning("No dwarf info found in the vmlinux - " 1289 1097 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1290 - free(pf.tevs); 1291 - *tevs = NULL; 1292 1098 return -EBADF; 1293 1099 } 1294 1100 1295 1101 #if _ELFUTILS_PREREQ(0, 142) 1296 1102 /* Get the call frame information from this dwarf */ 1297 - pf.cfi = dwarf_getcfi(dbg); 1103 + pf->cfi = dwarf_getcfi(dbg); 1298 1104 #endif 1299 1105 1300 1106 off = 0; 1301 - line_list__init(&pf.lcache); 1107 + line_list__init(&pf->lcache); 1302 1108 /* Loop on CUs (Compilation Unit) */ 1303 1109 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1304 1110 ret >= 0) { 1305 1111 /* Get the DIE(Debugging Information Entry) of this CU */ 1306 - diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 1112 + diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); 1307 1113 if (!diep) 1308 1114 continue; 1309 1115 1310 1116 /* Check if target file is included. */ 1311 1117 if (pp->file) 1312 - pf.fname = cu_find_realpath(&pf.cu_die, pp->file); 1118 + pf->fname = cu_find_realpath(&pf->cu_die, pp->file); 1313 1119 else 1314 - pf.fname = NULL; 1120 + pf->fname = NULL; 1315 1121 1316 - if (!pp->file || pf.fname) { 1122 + if (!pp->file || pf->fname) { 1317 1123 if (pp->function) 1318 - ret = find_probe_point_by_func(&pf); 1124 + ret = find_probe_point_by_func(pf); 1319 1125 else if (pp->lazy_line) 1320 - ret = find_probe_point_lazy(NULL, &pf); 1126 + ret = find_probe_point_lazy(NULL, pf); 1321 1127 else { 1322 - pf.lno = pp->line; 1323 - ret = find_probe_point_by_line(&pf); 1128 + pf->lno = pp->line; 1129 + ret = find_probe_point_by_line(pf); 1324 1130 } 1325 1131 } 1326 1132 off = noff; 1327 1133 } 1328 - line_list__free(&pf.lcache); 1329 - dwarf_end(dbg); 1134 + line_list__free(&pf->lcache); 1135 + if (dwfl) 1136 + dwfl_end(dwfl); 1330 1137 1331 - return (ret < 0) ? ret : pf.ntevs; 1138 + return ret; 1139 + } 1140 + 1141 + /* Add a found probe point into trace event list */ 1142 + static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) 1143 + { 1144 + struct trace_event_finder *tf = 1145 + container_of(pf, struct trace_event_finder, pf); 1146 + struct probe_trace_event *tev; 1147 + int ret, i; 1148 + 1149 + /* Check number of tevs */ 1150 + if (tf->ntevs == tf->max_tevs) { 1151 + pr_warning("Too many( > %d) probe point found.\n", 1152 + tf->max_tevs); 1153 + return -ERANGE; 1154 + } 1155 + tev = &tf->tevs[tf->ntevs++]; 1156 + 1157 + ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1158 + &tev->point); 1159 + if (ret < 0) 1160 + return ret; 1161 + 1162 + pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1163 + tev->point.offset); 1164 + 1165 + /* Find each argument */ 1166 + tev->nargs = pf->pev->nargs; 1167 + tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1168 + if (tev->args == NULL) 1169 + return -ENOMEM; 1170 + for (i = 0; i < pf->pev->nargs; i++) { 1171 + pf->pvar = &pf->pev->args[i]; 1172 + pf->tvar = &tev->args[i]; 1173 + ret = find_variable(sp_die, pf); 1174 + if (ret != 0) 1175 + return ret; 1176 + } 1177 + 1178 + return 0; 1179 + } 1180 + 1181 + /* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1182 + int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1183 + struct probe_trace_event **tevs, int max_tevs) 1184 + { 1185 + struct trace_event_finder tf = { 1186 + .pf = {.pev = pev, .callback = add_probe_trace_event}, 1187 + .max_tevs = max_tevs}; 1188 + int ret; 1189 + 1190 + /* Allocate result tevs array */ 1191 + *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); 1192 + if (*tevs == NULL) 1193 + return -ENOMEM; 1194 + 1195 + tf.tevs = *tevs; 1196 + tf.ntevs = 0; 1197 + 1198 + ret = find_probes(fd, &tf.pf); 1199 + if (ret < 0) { 1200 + free(*tevs); 1201 + *tevs = NULL; 1202 + return ret; 1203 + } 1204 + 1205 + return (ret < 0) ? ret : tf.ntevs; 1206 + } 1207 + 1208 + #define MAX_VAR_LEN 64 1209 + 1210 + /* Collect available variables in this scope */ 1211 + static int collect_variables_cb(Dwarf_Die *die_mem, void *data) 1212 + { 1213 + struct available_var_finder *af = data; 1214 + struct variable_list *vl; 1215 + char buf[MAX_VAR_LEN]; 1216 + int tag, ret; 1217 + 1218 + vl = &af->vls[af->nvls - 1]; 1219 + 1220 + tag = dwarf_tag(die_mem); 1221 + if (tag == DW_TAG_formal_parameter || 1222 + tag == DW_TAG_variable) { 1223 + ret = convert_variable_location(die_mem, af->pf.addr, 1224 + af->pf.fb_ops, NULL); 1225 + if (ret == 0) { 1226 + ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1227 + pr_debug2("Add new var: %s\n", buf); 1228 + if (ret > 0) 1229 + strlist__add(vl->vars, buf); 1230 + } 1231 + } 1232 + 1233 + if (af->child && dwarf_haspc(die_mem, af->pf.addr)) 1234 + return DIE_FIND_CB_CONTINUE; 1235 + else 1236 + return DIE_FIND_CB_SIBLING; 1237 + } 1238 + 1239 + /* Add a found vars into available variables list */ 1240 + static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) 1241 + { 1242 + struct available_var_finder *af = 1243 + container_of(pf, struct available_var_finder, pf); 1244 + struct variable_list *vl; 1245 + Dwarf_Die die_mem, *scopes = NULL; 1246 + int ret, nscopes; 1247 + 1248 + /* Check number of tevs */ 1249 + if (af->nvls == af->max_vls) { 1250 + pr_warning("Too many( > %d) probe point found.\n", af->max_vls); 1251 + return -ERANGE; 1252 + } 1253 + vl = &af->vls[af->nvls++]; 1254 + 1255 + ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1256 + &vl->point); 1257 + if (ret < 0) 1258 + return ret; 1259 + 1260 + pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, 1261 + vl->point.offset); 1262 + 1263 + /* Find local variables */ 1264 + vl->vars = strlist__new(true, NULL); 1265 + if (vl->vars == NULL) 1266 + return -ENOMEM; 1267 + af->child = true; 1268 + die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); 1269 + 1270 + /* Find external variables */ 1271 + if (!af->externs) 1272 + goto out; 1273 + /* Don't need to search child DIE for externs. */ 1274 + af->child = false; 1275 + nscopes = dwarf_getscopes_die(sp_die, &scopes); 1276 + while (nscopes-- > 1) 1277 + die_find_child(&scopes[nscopes], collect_variables_cb, 1278 + (void *)af, &die_mem); 1279 + if (scopes) 1280 + free(scopes); 1281 + 1282 + out: 1283 + if (strlist__empty(vl->vars)) { 1284 + strlist__delete(vl->vars); 1285 + vl->vars = NULL; 1286 + } 1287 + 1288 + return ret; 1289 + } 1290 + 1291 + /* Find available variables at given probe point */ 1292 + int find_available_vars_at(int fd, struct perf_probe_event *pev, 1293 + struct variable_list **vls, int max_vls, 1294 + bool externs) 1295 + { 1296 + struct available_var_finder af = { 1297 + .pf = {.pev = pev, .callback = add_available_vars}, 1298 + .max_vls = max_vls, .externs = externs}; 1299 + int ret; 1300 + 1301 + /* Allocate result vls array */ 1302 + *vls = zalloc(sizeof(struct variable_list) * max_vls); 1303 + if (*vls == NULL) 1304 + return -ENOMEM; 1305 + 1306 + af.vls = *vls; 1307 + af.nvls = 0; 1308 + 1309 + ret = find_probes(fd, &af.pf); 1310 + if (ret < 0) { 1311 + /* Free vlist for error */ 1312 + while (af.nvls--) { 1313 + if (af.vls[af.nvls].point.symbol) 1314 + free(af.vls[af.nvls].point.symbol); 1315 + if (af.vls[af.nvls].vars) 1316 + strlist__delete(af.vls[af.nvls].vars); 1317 + } 1318 + free(af.vls); 1319 + *vls = NULL; 1320 + return ret; 1321 + } 1322 + 1323 + return (ret < 0) ? ret : af.nvls; 1332 1324 } 1333 1325 1334 1326 /* Reverse search */ 1335 - int find_perf_probe_point(int fd, unsigned long addr, 1336 - struct perf_probe_point *ppt) 1327 + int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) 1337 1328 { 1338 1329 Dwarf_Die cudie, spdie, indie; 1339 - Dwarf *dbg; 1330 + Dwarf *dbg = NULL; 1331 + Dwfl *dwfl = NULL; 1340 1332 Dwarf_Line *line; 1341 - Dwarf_Addr laddr, eaddr; 1333 + Dwarf_Addr laddr, eaddr, bias = 0; 1342 1334 const char *tmp; 1343 1335 int lineno, ret = 0; 1344 1336 bool found = false; 1345 1337 1346 - dbg = dwarf_begin(fd, DWARF_C_READ); 1347 - if (!dbg) 1348 - return -EBADF; 1338 + /* Open the live linux kernel */ 1339 + dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); 1340 + if (!dbg) { 1341 + pr_warning("No dwarf info found in the vmlinux - " 1342 + "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1343 + ret = -EINVAL; 1344 + goto end; 1345 + } 1349 1346 1347 + /* Adjust address with bias */ 1348 + addr += bias; 1350 1349 /* Find cu die */ 1351 - if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { 1350 + if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { 1351 + pr_warning("No CU DIE is found at %lx\n", addr); 1352 1352 ret = -EINVAL; 1353 1353 goto end; 1354 1354 } ··· 1597 1225 } 1598 1226 1599 1227 end: 1600 - dwarf_end(dbg); 1228 + if (dwfl) 1229 + dwfl_end(dwfl); 1601 1230 if (ret >= 0) 1602 1231 ret = found ? 1 : 0; 1603 1232 return ret; ··· 1731 1358 struct line_finder *lf = param->data; 1732 1359 struct line_range *lr = lf->lr; 1733 1360 1361 + pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die), 1362 + dwarf_diename(sp_die)); 1734 1363 if (dwarf_tag(sp_die) == DW_TAG_subprogram && 1735 1364 die_compare_name(sp_die, lr->function)) { 1736 1365 lf->fname = dwarf_decl_file(sp_die); ··· 1776 1401 Dwarf_Off off = 0, noff; 1777 1402 size_t cuhl; 1778 1403 Dwarf_Die *diep; 1779 - Dwarf *dbg; 1404 + Dwarf *dbg = NULL; 1405 + Dwfl *dwfl; 1406 + Dwarf_Addr bias; /* Currently ignored */ 1780 1407 const char *comp_dir; 1781 1408 1782 - dbg = dwarf_begin(fd, DWARF_C_READ); 1409 + dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); 1783 1410 if (!dbg) { 1784 1411 pr_warning("No dwarf info found in the vmlinux - " 1785 1412 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); ··· 1827 1450 } 1828 1451 1829 1452 pr_debug("path: %s\n", lr->path); 1830 - dwarf_end(dbg); 1831 - 1453 + dwfl_end(dwfl); 1832 1454 return (ret < 0) ? ret : lf.found; 1833 1455 } 1834 1456
+27 -4
tools/perf/util/probe-finder.h
··· 22 22 int max_tevs); 23 23 24 24 /* Find a perf_probe_point from debuginfo */ 25 - extern int find_perf_probe_point(int fd, unsigned long addr, 25 + extern int find_perf_probe_point(unsigned long addr, 26 26 struct perf_probe_point *ppt); 27 27 28 + /* Find a line range */ 28 29 extern int find_line_range(int fd, struct line_range *lr); 30 + 31 + /* Find available variables */ 32 + extern int find_available_vars_at(int fd, struct perf_probe_event *pev, 33 + struct variable_list **vls, int max_points, 34 + bool externs); 29 35 30 36 #include <dwarf.h> 31 37 #include <libdw.h> 38 + #include <libdwfl.h> 32 39 #include <version.h> 33 40 34 41 struct probe_finder { 35 42 struct perf_probe_event *pev; /* Target probe event */ 36 - struct probe_trace_event *tevs; /* Result trace events */ 37 - int ntevs; /* Number of trace events */ 38 - int max_tevs; /* Max number of trace events */ 43 + 44 + /* Callback when a probe point is found */ 45 + int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); 39 46 40 47 /* For function searching */ 41 48 int lno; /* Line number */ ··· 58 51 Dwarf_Op *fb_ops; /* Frame base attribute */ 59 52 struct perf_probe_arg *pvar; /* Current target variable */ 60 53 struct probe_trace_arg *tvar; /* Current result variable */ 54 + }; 55 + 56 + struct trace_event_finder { 57 + struct probe_finder pf; 58 + struct probe_trace_event *tevs; /* Found trace events */ 59 + int ntevs; /* Number of trace events */ 60 + int max_tevs; /* Max number of trace events */ 61 + }; 62 + 63 + struct available_var_finder { 64 + struct probe_finder pf; 65 + struct variable_list *vls; /* Found variable lists */ 66 + int nvls; /* Number of variable lists */ 67 + int max_vls; /* Max no. of variable lists */ 68 + bool externs; /* Find external vars too */ 69 + bool child; /* Search child scopes */ 61 70 }; 62 71 63 72 struct line_finder {
-1
tools/perf/util/ui/browser.c
··· 1 - #include <slang.h> 2 1 #include "libslang.h" 3 2 #include <linux/compiler.h> 4 3 #include <linux/list.h>