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 56 unsigned int page_size; 57 58 static const char *output_file = "trace.info"; 59 static int output_fd; 60 61 struct event_list { 62 struct event_list *next; 63 const char *event; 64 }; 65 66 struct events { 67 struct events *sibling; 68 struct events *children; 69 struct events *next; 70 char *name; 71 }; 72 73 74 75 static 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 94 void *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 104 static 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 */ 118 static 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 137 static 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 152 static void put_tracing_file(char *file) 153 { 154 free(file); 155 } 156 157 static ssize_t write_or_die(const void *buf, size_t len) 158 { 159 int ret; 160 161 ret = write(output_fd, buf, len); 162 if (ret < 0) 163 die("writing to '%s'", output_file); 164 165 return ret; 166 } 167 168 int bigendian(void) 169 { 170 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 171 unsigned int *ptr; 172 173 ptr = (unsigned int *)(void *)str; 174 return *ptr == 0x01020304; 175 } 176 177 static unsigned long long copy_file_fd(int fd) 178 { 179 unsigned long long size = 0; 180 char buf[BUFSIZ]; 181 int r; 182 183 do { 184 r = read(fd, buf, BUFSIZ); 185 if (r > 0) { 186 size += r; 187 write_or_die(buf, r); 188 } 189 } while (r > 0); 190 191 return size; 192 } 193 194 static unsigned long long copy_file(const char *file) 195 { 196 unsigned long long size = 0; 197 int fd; 198 199 fd = open(file, O_RDONLY); 200 if (fd < 0) 201 die("Can't read '%s'", file); 202 size = copy_file_fd(fd); 203 close(fd); 204 205 return size; 206 } 207 208 static unsigned long get_size_fd(int fd) 209 { 210 unsigned long long size = 0; 211 char buf[BUFSIZ]; 212 int r; 213 214 do { 215 r = read(fd, buf, BUFSIZ); 216 if (r > 0) 217 size += r; 218 } while (r > 0); 219 220 lseek(fd, 0, SEEK_SET); 221 222 return size; 223 } 224 225 static unsigned long get_size(const char *file) 226 { 227 unsigned long long size = 0; 228 int fd; 229 230 fd = open(file, O_RDONLY); 231 if (fd < 0) 232 die("Can't read '%s'", file); 233 size = get_size_fd(fd); 234 close(fd); 235 236 return size; 237 } 238 239 static void read_header_files(void) 240 { 241 unsigned long long size, check_size; 242 char *path; 243 int fd; 244 245 path = get_tracing_file("events/header_page"); 246 fd = open(path, O_RDONLY); 247 if (fd < 0) 248 die("can't read '%s'", path); 249 250 /* unfortunately, you can not stat debugfs files for size */ 251 size = get_size_fd(fd); 252 253 write_or_die("header_page", 12); 254 write_or_die(&size, 8); 255 check_size = copy_file_fd(fd); 256 close(fd); 257 258 if (size != check_size) 259 die("wrong size for '%s' size=%lld read=%lld", 260 path, size, check_size); 261 put_tracing_file(path); 262 263 path = get_tracing_file("events/header_event"); 264 fd = open(path, O_RDONLY); 265 if (fd < 0) 266 die("can't read '%s'", path); 267 268 size = get_size_fd(fd); 269 270 write_or_die("header_event", 13); 271 write_or_die(&size, 8); 272 check_size = copy_file_fd(fd); 273 if (size != check_size) 274 die("wrong size for '%s'", path); 275 put_tracing_file(path); 276 close(fd); 277 } 278 279 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 280 { 281 while (tps) { 282 if (!strcmp(sys, tps->name)) 283 return true; 284 tps = tps->next; 285 } 286 287 return false; 288 } 289 290 static void copy_event_system(const char *sys, struct tracepoint_path *tps) 291 { 292 unsigned long long size, check_size; 293 struct dirent *dent; 294 struct stat st; 295 char *format; 296 DIR *dir; 297 int count = 0; 298 int ret; 299 300 dir = opendir(sys); 301 if (!dir) 302 die("can't read directory '%s'", sys); 303 304 while ((dent = readdir(dir))) { 305 if (dent->d_type != DT_DIR || 306 strcmp(dent->d_name, ".") == 0 || 307 strcmp(dent->d_name, "..") == 0 || 308 !name_in_tp_list(dent->d_name, tps)) 309 continue; 310 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 311 sprintf(format, "%s/%s/format", sys, dent->d_name); 312 ret = stat(format, &st); 313 free(format); 314 if (ret < 0) 315 continue; 316 count++; 317 } 318 319 write_or_die(&count, 4); 320 321 rewinddir(dir); 322 while ((dent = readdir(dir))) { 323 if (dent->d_type != DT_DIR || 324 strcmp(dent->d_name, ".") == 0 || 325 strcmp(dent->d_name, "..") == 0 || 326 !name_in_tp_list(dent->d_name, tps)) 327 continue; 328 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 329 sprintf(format, "%s/%s/format", sys, dent->d_name); 330 ret = stat(format, &st); 331 332 if (ret >= 0) { 333 /* unfortunately, you can not stat debugfs files for size */ 334 size = get_size(format); 335 write_or_die(&size, 8); 336 check_size = copy_file(format); 337 if (size != check_size) 338 die("error in size of file '%s'", format); 339 } 340 341 free(format); 342 } 343 closedir(dir); 344 } 345 346 static void read_ftrace_files(struct tracepoint_path *tps) 347 { 348 char *path; 349 350 path = get_tracing_file("events/ftrace"); 351 352 copy_event_system(path, tps); 353 354 put_tracing_file(path); 355 } 356 357 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) 358 { 359 while (tps) { 360 if (!strcmp(sys, tps->system)) 361 return true; 362 tps = tps->next; 363 } 364 365 return false; 366 } 367 368 static void read_event_files(struct tracepoint_path *tps) 369 { 370 struct dirent *dent; 371 struct stat st; 372 char *path; 373 char *sys; 374 DIR *dir; 375 int count = 0; 376 int ret; 377 378 path = get_tracing_file("events"); 379 380 dir = opendir(path); 381 if (!dir) 382 die("can't read directory '%s'", path); 383 384 while ((dent = readdir(dir))) { 385 if (dent->d_type != DT_DIR || 386 strcmp(dent->d_name, ".") == 0 || 387 strcmp(dent->d_name, "..") == 0 || 388 strcmp(dent->d_name, "ftrace") == 0 || 389 !system_in_tp_list(dent->d_name, tps)) 390 continue; 391 count++; 392 } 393 394 write_or_die(&count, 4); 395 396 rewinddir(dir); 397 while ((dent = readdir(dir))) { 398 if (dent->d_type != DT_DIR || 399 strcmp(dent->d_name, ".") == 0 || 400 strcmp(dent->d_name, "..") == 0 || 401 strcmp(dent->d_name, "ftrace") == 0 || 402 !system_in_tp_list(dent->d_name, tps)) 403 continue; 404 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 405 sprintf(sys, "%s/%s", path, dent->d_name); 406 ret = stat(sys, &st); 407 if (ret >= 0) { 408 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 409 copy_event_system(sys, tps); 410 } 411 free(sys); 412 } 413 414 closedir(dir); 415 put_tracing_file(path); 416 } 417 418 static void read_proc_kallsyms(void) 419 { 420 unsigned int size, check_size; 421 const char *path = "/proc/kallsyms"; 422 struct stat st; 423 int ret; 424 425 ret = stat(path, &st); 426 if (ret < 0) { 427 /* not found */ 428 size = 0; 429 write_or_die(&size, 4); 430 return; 431 } 432 size = get_size(path); 433 write_or_die(&size, 4); 434 check_size = copy_file(path); 435 if (size != check_size) 436 die("error in size of file '%s'", path); 437 438 } 439 440 static void read_ftrace_printk(void) 441 { 442 unsigned int size, check_size; 443 char *path; 444 struct stat st; 445 int ret; 446 447 path = get_tracing_file("printk_formats"); 448 ret = stat(path, &st); 449 if (ret < 0) { 450 /* not found */ 451 size = 0; 452 write_or_die(&size, 4); 453 goto out; 454 } 455 size = get_size(path); 456 write_or_die(&size, 4); 457 check_size = copy_file(path); 458 if (size != check_size) 459 die("error in size of file '%s'", path); 460 out: 461 put_tracing_file(path); 462 } 463 464 static struct tracepoint_path * 465 get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 466 { 467 struct tracepoint_path path, *ppath = &path; 468 int i, nr_tracepoints = 0; 469 470 for (i = 0; i < nb_events; i++) { 471 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 472 continue; 473 ++nr_tracepoints; 474 ppath->next = tracepoint_id_to_path(pattrs[i].config); 475 if (!ppath->next) 476 die("%s\n", "No memory to alloc tracepoints list"); 477 ppath = ppath->next; 478 } 479 480 return nr_tracepoints > 0 ? path.next : NULL; 481 } 482 483 int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 484 { 485 char buf[BUFSIZ]; 486 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events); 487 488 /* 489 * What? No tracepoints? No sense writing anything here, bail out. 490 */ 491 if (tps == NULL) 492 return -1; 493 494 output_fd = fd; 495 496 buf[0] = 23; 497 buf[1] = 8; 498 buf[2] = 68; 499 memcpy(buf + 3, "tracing", 7); 500 501 write_or_die(buf, 10); 502 503 write_or_die(VERSION, strlen(VERSION) + 1); 504 505 /* save endian */ 506 if (bigendian()) 507 buf[0] = 1; 508 else 509 buf[0] = 0; 510 511 write_or_die(buf, 1); 512 513 /* save size of long */ 514 buf[0] = sizeof(long); 515 write_or_die(buf, 1); 516 517 /* save page_size */ 518 page_size = sysconf(_SC_PAGESIZE); 519 write_or_die(&page_size, 4); 520 521 read_header_files(); 522 read_ftrace_files(tps); 523 read_event_files(tps); 524 read_proc_kallsyms(); 525 read_ftrace_printk(); 526 527 return 0; 528 } 529