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