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