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