1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * builtin-ftrace.c 4 * 5 * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org> 6 */ 7 8 #include "builtin.h" 9 10 #include <errno.h> 11 #include <unistd.h> 12 #include <signal.h> 13 #include <stdlib.h> 14 #include <fcntl.h> 15 #include <poll.h> 16 #include <linux/capability.h> 17 #include <linux/string.h> 18 19 #include "debug.h" 20 #include <subcmd/pager.h> 21 #include <subcmd/parse-options.h> 22 #include <api/fs/tracing_path.h> 23 #include "evlist.h" 24 #include "target.h" 25 #include "cpumap.h" 26 #include "thread_map.h" 27 #include "util/cap.h" 28 #include "util/config.h" 29 30 #define DEFAULT_TRACER "function_graph" 31 32 struct perf_ftrace { 33 struct evlist *evlist; 34 struct target target; 35 const char *tracer; 36 struct list_head filters; 37 struct list_head notrace; 38 struct list_head graph_funcs; 39 struct list_head nograph_funcs; 40 int graph_depth; 41 }; 42 43 struct filter_entry { 44 struct list_head list; 45 char name[]; 46 }; 47 48 static bool done; 49 50 static void sig_handler(int sig __maybe_unused) 51 { 52 done = true; 53 } 54 55 /* 56 * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 57 * we asked by setting its exec_error to the function below, 58 * ftrace__workload_exec_failed_signal. 59 * 60 * XXX We need to handle this more appropriately, emitting an error, etc. 61 */ 62 static void ftrace__workload_exec_failed_signal(int signo __maybe_unused, 63 siginfo_t *info __maybe_unused, 64 void *ucontext __maybe_unused) 65 { 66 /* workload_exec_errno = info->si_value.sival_int; */ 67 done = true; 68 } 69 70 static int __write_tracing_file(const char *name, const char *val, bool append) 71 { 72 char *file; 73 int fd, ret = -1; 74 ssize_t size = strlen(val); 75 int flags = O_WRONLY; 76 char errbuf[512]; 77 char *val_copy; 78 79 file = get_tracing_file(name); 80 if (!file) { 81 pr_debug("cannot get tracing file: %s\n", name); 82 return -1; 83 } 84 85 if (append) 86 flags |= O_APPEND; 87 else 88 flags |= O_TRUNC; 89 90 fd = open(file, flags); 91 if (fd < 0) { 92 pr_debug("cannot open tracing file: %s: %s\n", 93 name, str_error_r(errno, errbuf, sizeof(errbuf))); 94 goto out; 95 } 96 97 /* 98 * Copy the original value and append a '\n'. Without this, 99 * the kernel can hide possible errors. 100 */ 101 val_copy = strdup(val); 102 if (!val_copy) 103 goto out_close; 104 val_copy[size] = '\n'; 105 106 if (write(fd, val_copy, size + 1) == size + 1) 107 ret = 0; 108 else 109 pr_debug("write '%s' to tracing/%s failed: %s\n", 110 val, name, str_error_r(errno, errbuf, sizeof(errbuf))); 111 112 free(val_copy); 113 out_close: 114 close(fd); 115 out: 116 put_tracing_file(file); 117 return ret; 118 } 119 120 static int write_tracing_file(const char *name, const char *val) 121 { 122 return __write_tracing_file(name, val, false); 123 } 124 125 static int append_tracing_file(const char *name, const char *val) 126 { 127 return __write_tracing_file(name, val, true); 128 } 129 130 static int reset_tracing_cpu(void); 131 static void reset_tracing_filters(void); 132 133 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) 134 { 135 if (write_tracing_file("tracing_on", "0") < 0) 136 return -1; 137 138 if (write_tracing_file("current_tracer", "nop") < 0) 139 return -1; 140 141 if (write_tracing_file("set_ftrace_pid", " ") < 0) 142 return -1; 143 144 if (reset_tracing_cpu() < 0) 145 return -1; 146 147 if (write_tracing_file("max_graph_depth", "0") < 0) 148 return -1; 149 150 reset_tracing_filters(); 151 return 0; 152 } 153 154 static int set_tracing_pid(struct perf_ftrace *ftrace) 155 { 156 int i; 157 char buf[16]; 158 159 if (target__has_cpu(&ftrace->target)) 160 return 0; 161 162 for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) { 163 scnprintf(buf, sizeof(buf), "%d", 164 ftrace->evlist->core.threads->map[i]); 165 if (append_tracing_file("set_ftrace_pid", buf) < 0) 166 return -1; 167 } 168 return 0; 169 } 170 171 static int set_tracing_cpumask(struct perf_cpu_map *cpumap) 172 { 173 char *cpumask; 174 size_t mask_size; 175 int ret; 176 int last_cpu; 177 178 last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1); 179 mask_size = last_cpu / 4 + 2; /* one more byte for EOS */ 180 mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */ 181 182 cpumask = malloc(mask_size); 183 if (cpumask == NULL) { 184 pr_debug("failed to allocate cpu mask\n"); 185 return -1; 186 } 187 188 cpu_map__snprint_mask(cpumap, cpumask, mask_size); 189 190 ret = write_tracing_file("tracing_cpumask", cpumask); 191 192 free(cpumask); 193 return ret; 194 } 195 196 static int set_tracing_cpu(struct perf_ftrace *ftrace) 197 { 198 struct perf_cpu_map *cpumap = ftrace->evlist->core.cpus; 199 200 if (!target__has_cpu(&ftrace->target)) 201 return 0; 202 203 return set_tracing_cpumask(cpumap); 204 } 205 206 static int reset_tracing_cpu(void) 207 { 208 struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL); 209 int ret; 210 211 ret = set_tracing_cpumask(cpumap); 212 perf_cpu_map__put(cpumap); 213 return ret; 214 } 215 216 static int __set_tracing_filter(const char *filter_file, struct list_head *funcs) 217 { 218 struct filter_entry *pos; 219 220 list_for_each_entry(pos, funcs, list) { 221 if (append_tracing_file(filter_file, pos->name) < 0) 222 return -1; 223 } 224 225 return 0; 226 } 227 228 static int set_tracing_filters(struct perf_ftrace *ftrace) 229 { 230 int ret; 231 232 ret = __set_tracing_filter("set_ftrace_filter", &ftrace->filters); 233 if (ret < 0) 234 return ret; 235 236 ret = __set_tracing_filter("set_ftrace_notrace", &ftrace->notrace); 237 if (ret < 0) 238 return ret; 239 240 ret = __set_tracing_filter("set_graph_function", &ftrace->graph_funcs); 241 if (ret < 0) 242 return ret; 243 244 /* old kernels do not have this filter */ 245 __set_tracing_filter("set_graph_notrace", &ftrace->nograph_funcs); 246 247 return ret; 248 } 249 250 static void reset_tracing_filters(void) 251 { 252 write_tracing_file("set_ftrace_filter", " "); 253 write_tracing_file("set_ftrace_notrace", " "); 254 write_tracing_file("set_graph_function", " "); 255 write_tracing_file("set_graph_notrace", " "); 256 } 257 258 static int set_tracing_depth(struct perf_ftrace *ftrace) 259 { 260 char buf[16]; 261 262 if (ftrace->graph_depth == 0) 263 return 0; 264 265 if (ftrace->graph_depth < 0) { 266 pr_err("invalid graph depth: %d\n", ftrace->graph_depth); 267 return -1; 268 } 269 270 snprintf(buf, sizeof(buf), "%d", ftrace->graph_depth); 271 272 if (write_tracing_file("max_graph_depth", buf) < 0) 273 return -1; 274 275 return 0; 276 } 277 278 static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) 279 { 280 char *trace_file; 281 int trace_fd; 282 char buf[4096]; 283 struct pollfd pollfd = { 284 .events = POLLIN, 285 }; 286 287 if (!perf_cap__capable(CAP_SYS_ADMIN)) { 288 pr_err("ftrace only works for %s!\n", 289 #ifdef HAVE_LIBCAP_SUPPORT 290 "users with the SYS_ADMIN capability" 291 #else 292 "root" 293 #endif 294 ); 295 return -1; 296 } 297 298 signal(SIGINT, sig_handler); 299 signal(SIGUSR1, sig_handler); 300 signal(SIGCHLD, sig_handler); 301 signal(SIGPIPE, sig_handler); 302 303 if (reset_tracing_files(ftrace) < 0) { 304 pr_err("failed to reset ftrace\n"); 305 goto out; 306 } 307 308 /* reset ftrace buffer */ 309 if (write_tracing_file("trace", "0") < 0) 310 goto out; 311 312 if (argc && perf_evlist__prepare_workload(ftrace->evlist, 313 &ftrace->target, argv, false, 314 ftrace__workload_exec_failed_signal) < 0) { 315 goto out; 316 } 317 318 if (set_tracing_pid(ftrace) < 0) { 319 pr_err("failed to set ftrace pid\n"); 320 goto out_reset; 321 } 322 323 if (set_tracing_cpu(ftrace) < 0) { 324 pr_err("failed to set tracing cpumask\n"); 325 goto out_reset; 326 } 327 328 if (set_tracing_filters(ftrace) < 0) { 329 pr_err("failed to set tracing filters\n"); 330 goto out_reset; 331 } 332 333 if (set_tracing_depth(ftrace) < 0) { 334 pr_err("failed to set graph depth\n"); 335 goto out_reset; 336 } 337 338 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 339 pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 340 goto out_reset; 341 } 342 343 setup_pager(); 344 345 trace_file = get_tracing_file("trace_pipe"); 346 if (!trace_file) { 347 pr_err("failed to open trace_pipe\n"); 348 goto out_reset; 349 } 350 351 trace_fd = open(trace_file, O_RDONLY); 352 353 put_tracing_file(trace_file); 354 355 if (trace_fd < 0) { 356 pr_err("failed to open trace_pipe\n"); 357 goto out_reset; 358 } 359 360 fcntl(trace_fd, F_SETFL, O_NONBLOCK); 361 pollfd.fd = trace_fd; 362 363 if (write_tracing_file("tracing_on", "1") < 0) { 364 pr_err("can't enable tracing\n"); 365 goto out_close_fd; 366 } 367 368 perf_evlist__start_workload(ftrace->evlist); 369 370 while (!done) { 371 if (poll(&pollfd, 1, -1) < 0) 372 break; 373 374 if (pollfd.revents & POLLIN) { 375 int n = read(trace_fd, buf, sizeof(buf)); 376 if (n < 0) 377 break; 378 if (fwrite(buf, n, 1, stdout) != 1) 379 break; 380 } 381 } 382 383 write_tracing_file("tracing_on", "0"); 384 385 /* read remaining buffer contents */ 386 while (true) { 387 int n = read(trace_fd, buf, sizeof(buf)); 388 if (n <= 0) 389 break; 390 if (fwrite(buf, n, 1, stdout) != 1) 391 break; 392 } 393 394 out_close_fd: 395 close(trace_fd); 396 out_reset: 397 reset_tracing_files(ftrace); 398 out: 399 return done ? 0 : -1; 400 } 401 402 static int perf_ftrace_config(const char *var, const char *value, void *cb) 403 { 404 struct perf_ftrace *ftrace = cb; 405 406 if (!strstarts(var, "ftrace.")) 407 return 0; 408 409 if (strcmp(var, "ftrace.tracer")) 410 return -1; 411 412 if (!strcmp(value, "function_graph") || 413 !strcmp(value, "function")) { 414 ftrace->tracer = value; 415 return 0; 416 } 417 418 pr_err("Please select \"function_graph\" (default) or \"function\"\n"); 419 return -1; 420 } 421 422 static int parse_filter_func(const struct option *opt, const char *str, 423 int unset __maybe_unused) 424 { 425 struct list_head *head = opt->value; 426 struct filter_entry *entry; 427 428 entry = malloc(sizeof(*entry) + strlen(str) + 1); 429 if (entry == NULL) 430 return -ENOMEM; 431 432 strcpy(entry->name, str); 433 list_add_tail(&entry->list, head); 434 435 return 0; 436 } 437 438 static void delete_filter_func(struct list_head *head) 439 { 440 struct filter_entry *pos, *tmp; 441 442 list_for_each_entry_safe(pos, tmp, head, list) { 443 list_del_init(&pos->list); 444 free(pos); 445 } 446 } 447 448 int cmd_ftrace(int argc, const char **argv) 449 { 450 int ret; 451 struct perf_ftrace ftrace = { 452 .tracer = DEFAULT_TRACER, 453 .target = { .uid = UINT_MAX, }, 454 }; 455 const char * const ftrace_usage[] = { 456 "perf ftrace [<options>] [<command>]", 457 "perf ftrace [<options>] -- <command> [<options>]", 458 NULL 459 }; 460 const struct option ftrace_options[] = { 461 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", 462 "tracer to use: function_graph(default) or function"), 463 OPT_STRING('p', "pid", &ftrace.target.pid, "pid", 464 "trace on existing process id"), 465 OPT_INCR('v', "verbose", &verbose, 466 "be more verbose"), 467 OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide, 468 "system-wide collection from all CPUs"), 469 OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", 470 "list of cpus to monitor"), 471 OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", 472 "trace given functions only", parse_filter_func), 473 OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func", 474 "do not trace given functions", parse_filter_func), 475 OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func", 476 "Set graph filter on given functions", parse_filter_func), 477 OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func", 478 "Set nograph filter on given functions", parse_filter_func), 479 OPT_INTEGER('D', "graph-depth", &ftrace.graph_depth, 480 "Max depth for function graph tracer"), 481 OPT_END() 482 }; 483 484 INIT_LIST_HEAD(&ftrace.filters); 485 INIT_LIST_HEAD(&ftrace.notrace); 486 INIT_LIST_HEAD(&ftrace.graph_funcs); 487 INIT_LIST_HEAD(&ftrace.nograph_funcs); 488 489 ret = perf_config(perf_ftrace_config, &ftrace); 490 if (ret < 0) 491 return -1; 492 493 argc = parse_options(argc, argv, ftrace_options, ftrace_usage, 494 PARSE_OPT_STOP_AT_NON_OPTION); 495 if (!argc && target__none(&ftrace.target)) 496 usage_with_options(ftrace_usage, ftrace_options); 497 498 ret = target__validate(&ftrace.target); 499 if (ret) { 500 char errbuf[512]; 501 502 target__strerror(&ftrace.target, ret, errbuf, 512); 503 pr_err("%s\n", errbuf); 504 goto out_delete_filters; 505 } 506 507 ftrace.evlist = evlist__new(); 508 if (ftrace.evlist == NULL) { 509 ret = -ENOMEM; 510 goto out_delete_filters; 511 } 512 513 ret = perf_evlist__create_maps(ftrace.evlist, &ftrace.target); 514 if (ret < 0) 515 goto out_delete_evlist; 516 517 ret = __cmd_ftrace(&ftrace, argc, argv); 518 519 out_delete_evlist: 520 evlist__delete(ftrace.evlist); 521 522 out_delete_filters: 523 delete_filter_func(&ftrace.filters); 524 delete_filter_func(&ftrace.notrace); 525 delete_filter_func(&ftrace.graph_funcs); 526 delete_filter_func(&ftrace.nograph_funcs); 527 528 return ret; 529 } 530