trace-event-info.c revision 7d82a4640abdcc3ffbd89c7971a11e4ac7953b7f
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/* 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 69unsigned int page_size; 70 71static const char *output_file = "trace.info"; 72static int output_fd; 73 74struct event_list { 75 struct event_list *next; 76 const char *event; 77}; 78 79struct events { 80 struct events *sibling; 81 struct events *children; 82 struct events *next; 83 char *name; 84}; 85 86 87 88static 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 107void *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 117static 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 */ 131static 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 150static 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 165static void put_tracing_file(char *file) 166{ 167 free(file); 168} 169 170static ssize_t calc_data_size; 171 172static 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 188int 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 197static 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 214static 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 228static 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 245static 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 259static 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 299static 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 310static 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 366static 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 377static 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 388static 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 438static 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 460static 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); 480out: 481 put_tracing_file(path); 482} 483 484static struct tracepoint_path * 485get_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 504bool 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 515int 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 562ssize_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