1 /* 2 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com> 3 * 4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License (not later!) 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 */ 21 #define _GNU_SOURCE 22 #include <dirent.h> 23 #include <mntent.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <stdarg.h> 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/wait.h> 31 #include <pthread.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <ctype.h> 35 #include <errno.h> 36 #include <stdbool.h> 37 #include <linux/list.h> 38 #include <linux/kernel.h> 39 40 #include "../perf.h" 41 #include "trace-event.h" 42 #include "debugfs.h" 43 #include "evsel.h" 44 45 #define VERSION "0.5" 46 47 #define _STR(x) #x 48 #define STR(x) _STR(x) 49 #define MAX_PATH 256 50 51 #define TRACE_CTRL "tracing_on" 52 #define TRACE "trace" 53 #define AVAILABLE "available_tracers" 54 #define CURRENT "current_tracer" 55 #define ITER_CTRL "trace_options" 56 #define MAX_LATENCY "tracing_max_latency" 57 58 unsigned int page_size; 59 60 static const char *output_file = "trace.info"; 61 static int output_fd; 62 63 struct event_list { 64 struct event_list *next; 65 const char *event; 66 }; 67 68 struct events { 69 struct events *sibling; 70 struct events *children; 71 struct events *next; 72 char *name; 73 }; 74 75 76 77 static void die(const char *fmt, ...) 78 { 79 va_list ap; 80 int ret = errno; 81 82 if (errno) 83 perror("trace-cmd"); 84 else 85 ret = -1; 86 87 va_start(ap, fmt); 88 fprintf(stderr, " "); 89 vfprintf(stderr, fmt, ap); 90 va_end(ap); 91 92 fprintf(stderr, "\n"); 93 exit(ret); 94 } 95 96 void *malloc_or_die(unsigned int size) 97 { 98 void *data; 99 100 data = malloc(size); 101 if (!data) 102 die("malloc"); 103 return data; 104 } 105 106 static const char *find_debugfs(void) 107 { 108 const char *path = debugfs_mount(NULL); 109 110 if (!path) 111 die("Your kernel not support debugfs filesystem"); 112 113 return path; 114 } 115 116 /* 117 * Finds the path to the debugfs/tracing 118 * Allocates the string and stores it. 119 */ 120 static const char *find_tracing_dir(void) 121 { 122 static char *tracing; 123 static int tracing_found; 124 const char *debugfs; 125 126 if (tracing_found) 127 return tracing; 128 129 debugfs = find_debugfs(); 130 131 tracing = malloc_or_die(strlen(debugfs) + 9); 132 133 sprintf(tracing, "%s/tracing", debugfs); 134 135 tracing_found = 1; 136 return tracing; 137 } 138 139 static char *get_tracing_file(const char *name) 140 { 141 const char *tracing; 142 char *file; 143 144 tracing = find_tracing_dir(); 145 if (!tracing) 146 return NULL; 147 148 file = malloc_or_die(strlen(tracing) + strlen(name) + 2); 149 150 sprintf(file, "%s/%s", tracing, name); 151 return file; 152 } 153 154 static void put_tracing_file(char *file) 155 { 156 free(file); 157 } 158 159 static ssize_t calc_data_size; 160 161 static ssize_t write_or_die(const void *buf, size_t len) 162 { 163 int ret; 164 165 if (calc_data_size) { 166 calc_data_size += len; 167 return len; 168 } 169 170 ret = write(output_fd, buf, len); 171 if (ret < 0) 172 die("writing to '%s'", output_file); 173 174 return ret; 175 } 176 177 int bigendian(void) 178 { 179 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 180 unsigned int *ptr; 181 182 ptr = (unsigned int *)(void *)str; 183 return *ptr == 0x01020304; 184 } 185 186 static unsigned long long copy_file_fd(int fd) 187 { 188 unsigned long long size = 0; 189 char buf[BUFSIZ]; 190 int r; 191 192 do { 193 r = read(fd, buf, BUFSIZ); 194 if (r > 0) { 195 size += r; 196 write_or_die(buf, r); 197 } 198 } while (r > 0); 199 200 return size; 201 } 202 203 static unsigned long long copy_file(const char *file) 204 { 205 unsigned long long size = 0; 206 int fd; 207 208 fd = open(file, O_RDONLY); 209 if (fd < 0) 210 die("Can't read '%s'", file); 211 size = copy_file_fd(fd); 212 close(fd); 213 214 return size; 215 } 216 217 static unsigned long get_size_fd(int fd) 218 { 219 unsigned long long size = 0; 220 char buf[BUFSIZ]; 221 int r; 222 223 do { 224 r = read(fd, buf, BUFSIZ); 225 if (r > 0) 226 size += r; 227 } while (r > 0); 228 229 lseek(fd, 0, SEEK_SET); 230 231 return size; 232 } 233 234 static unsigned long get_size(const char *file) 235 { 236 unsigned long long size = 0; 237 int fd; 238 239 fd = open(file, O_RDONLY); 240 if (fd < 0) 241 die("Can't read '%s'", file); 242 size = get_size_fd(fd); 243 close(fd); 244 245 return size; 246 } 247 248 static void read_header_files(void) 249 { 250 unsigned long long size, check_size; 251 char *path; 252 int fd; 253 254 path = get_tracing_file("events/header_page"); 255 fd = open(path, O_RDONLY); 256 if (fd < 0) 257 die("can't read '%s'", path); 258 259 /* unfortunately, you can not stat debugfs files for size */ 260 size = get_size_fd(fd); 261 262 write_or_die("header_page", 12); 263 write_or_die(&size, 8); 264 check_size = copy_file_fd(fd); 265 close(fd); 266 267 if (size != check_size) 268 die("wrong size for '%s' size=%lld read=%lld", 269 path, size, check_size); 270 put_tracing_file(path); 271 272 path = get_tracing_file("events/header_event"); 273 fd = open(path, O_RDONLY); 274 if (fd < 0) 275 die("can't read '%s'", path); 276 277 size = get_size_fd(fd); 278 279 write_or_die("header_event", 13); 280 write_or_die(&size, 8); 281 check_size = copy_file_fd(fd); 282 if (size != check_size) 283 die("wrong size for '%s'", path); 284 put_tracing_file(path); 285 close(fd); 286 } 287 288 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 289 { 290 while (tps) { 291 if (!strcmp(sys, tps->name)) 292 return true; 293 tps = tps->next; 294 } 295 296 return false; 297 } 298 299 static void copy_event_system(const char *sys, struct tracepoint_path *tps) 300 { 301 unsigned long long size, check_size; 302 struct dirent *dent; 303 struct stat st; 304 char *format; 305 DIR *dir; 306 int count = 0; 307 int ret; 308 309 dir = opendir(sys); 310 if (!dir) 311 die("can't read directory '%s'", sys); 312 313 while ((dent = readdir(dir))) { 314 if (dent->d_type != DT_DIR || 315 strcmp(dent->d_name, ".") == 0 || 316 strcmp(dent->d_name, "..") == 0 || 317 !name_in_tp_list(dent->d_name, tps)) 318 continue; 319 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 320 sprintf(format, "%s/%s/format", sys, dent->d_name); 321 ret = stat(format, &st); 322 free(format); 323 if (ret < 0) 324 continue; 325 count++; 326 } 327 328 write_or_die(&count, 4); 329 330 rewinddir(dir); 331 while ((dent = readdir(dir))) { 332 if (dent->d_type != DT_DIR || 333 strcmp(dent->d_name, ".") == 0 || 334 strcmp(dent->d_name, "..") == 0 || 335 !name_in_tp_list(dent->d_name, tps)) 336 continue; 337 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 338 sprintf(format, "%s/%s/format", sys, dent->d_name); 339 ret = stat(format, &st); 340 341 if (ret >= 0) { 342 /* unfortunately, you can not stat debugfs files for size */ 343 size = get_size(format); 344 write_or_die(&size, 8); 345 check_size = copy_file(format); 346 if (size != check_size) 347 die("error in size of file '%s'", format); 348 } 349 350 free(format); 351 } 352 closedir(dir); 353 } 354 355 static void read_ftrace_files(struct tracepoint_path *tps) 356 { 357 char *path; 358 359 path = get_tracing_file("events/ftrace"); 360 361 copy_event_system(path, tps); 362 363 put_tracing_file(path); 364 } 365 366 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) 367 { 368 while (tps) { 369 if (!strcmp(sys, tps->system)) 370 return true; 371 tps = tps->next; 372 } 373 374 return false; 375 } 376 377 static void read_event_files(struct tracepoint_path *tps) 378 { 379 struct dirent *dent; 380 struct stat st; 381 char *path; 382 char *sys; 383 DIR *dir; 384 int count = 0; 385 int ret; 386 387 path = get_tracing_file("events"); 388 389 dir = opendir(path); 390 if (!dir) 391 die("can't read directory '%s'", path); 392 393 while ((dent = readdir(dir))) { 394 if (dent->d_type != DT_DIR || 395 strcmp(dent->d_name, ".") == 0 || 396 strcmp(dent->d_name, "..") == 0 || 397 strcmp(dent->d_name, "ftrace") == 0 || 398 !system_in_tp_list(dent->d_name, tps)) 399 continue; 400 count++; 401 } 402 403 write_or_die(&count, 4); 404 405 rewinddir(dir); 406 while ((dent = readdir(dir))) { 407 if (dent->d_type != DT_DIR || 408 strcmp(dent->d_name, ".") == 0 || 409 strcmp(dent->d_name, "..") == 0 || 410 strcmp(dent->d_name, "ftrace") == 0 || 411 !system_in_tp_list(dent->d_name, tps)) 412 continue; 413 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 414 sprintf(sys, "%s/%s", path, dent->d_name); 415 ret = stat(sys, &st); 416 if (ret >= 0) { 417 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 418 copy_event_system(sys, tps); 419 } 420 free(sys); 421 } 422 423 closedir(dir); 424 put_tracing_file(path); 425 } 426 427 static void read_proc_kallsyms(void) 428 { 429 unsigned int size, check_size; 430 const char *path = "/proc/kallsyms"; 431 struct stat st; 432 int ret; 433 434 ret = stat(path, &st); 435 if (ret < 0) { 436 /* not found */ 437 size = 0; 438 write_or_die(&size, 4); 439 return; 440 } 441 size = get_size(path); 442 write_or_die(&size, 4); 443 check_size = copy_file(path); 444 if (size != check_size) 445 die("error in size of file '%s'", path); 446 447 } 448 449 static void read_ftrace_printk(void) 450 { 451 unsigned int size, check_size; 452 char *path; 453 struct stat st; 454 int ret; 455 456 path = get_tracing_file("printk_formats"); 457 ret = stat(path, &st); 458 if (ret < 0) { 459 /* not found */ 460 size = 0; 461 write_or_die(&size, 4); 462 goto out; 463 } 464 size = get_size(path); 465 write_or_die(&size, 4); 466 check_size = copy_file(path); 467 if (size != check_size) 468 die("error in size of file '%s'", path); 469 out: 470 put_tracing_file(path); 471 } 472 473 static struct tracepoint_path * 474 get_tracepoints_path(struct list_head *pattrs) 475 { 476 struct tracepoint_path path, *ppath = &path; 477 struct perf_evsel *pos; 478 int nr_tracepoints = 0; 479 480 list_for_each_entry(pos, pattrs, node) { 481 if (pos->attr.type != PERF_TYPE_TRACEPOINT) 482 continue; 483 ++nr_tracepoints; 484 ppath->next = tracepoint_id_to_path(pos->attr.config); 485 if (!ppath->next) 486 die("%s\n", "No memory to alloc tracepoints list"); 487 ppath = ppath->next; 488 } 489 490 return nr_tracepoints > 0 ? path.next : NULL; 491 } 492 493 bool have_tracepoints(struct list_head *pattrs) 494 { 495 struct perf_evsel *pos; 496 497 list_for_each_entry(pos, pattrs, node) 498 if (pos->attr.type == PERF_TYPE_TRACEPOINT) 499 return true; 500 501 return false; 502 } 503 504 int read_tracing_data(int fd, struct list_head *pattrs) 505 { 506 char buf[BUFSIZ]; 507 struct tracepoint_path *tps = get_tracepoints_path(pattrs); 508 509 /* 510 * What? No tracepoints? No sense writing anything here, bail out. 511 */ 512 if (tps == NULL) 513 return -1; 514 515 output_fd = fd; 516 517 buf[0] = 23; 518 buf[1] = 8; 519 buf[2] = 68; 520 memcpy(buf + 3, "tracing", 7); 521 522 write_or_die(buf, 10); 523 524 write_or_die(VERSION, strlen(VERSION) + 1); 525 526 /* save endian */ 527 if (bigendian()) 528 buf[0] = 1; 529 else 530 buf[0] = 0; 531 532 write_or_die(buf, 1); 533 534 /* save size of long */ 535 buf[0] = sizeof(long); 536 write_or_die(buf, 1); 537 538 /* save page_size */ 539 page_size = sysconf(_SC_PAGESIZE); 540 write_or_die(&page_size, 4); 541 542 read_header_files(); 543 read_ftrace_files(tps); 544 read_event_files(tps); 545 read_proc_kallsyms(); 546 read_ftrace_printk(); 547 548 return 0; 549 } 550 551 ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) 552 { 553 ssize_t size; 554 int err = 0; 555 556 calc_data_size = 1; 557 err = read_tracing_data(fd, pattrs); 558 size = calc_data_size - 1; 559 calc_data_size = 0; 560 561 if (err < 0) 562 return err; 563 564 return size; 565 } 566