Main entry for userspace ktap tool. [root@localhost ktap]# ./ktap Usage: ktap [options] file [script args] -- cmd [args] or: ktap [options] -e one-liner -- cmd [args]
Options and arguments: -o file : send script output to file, instead of stderr -p pid : specific tracing pid -C cpu : cpu to monitor in system-wide -T : show timestamp for event -V : show version -v : enable verbose mode -q : suppress start tracing message -d : dry run mode(register NULL callback to perf events) -s : simple event tracing -b : list byte codes -le [glob] : list pre-defined events in system -lf DSO : list available functions from DSO -lm DSO : list available sdt notes from DSO file : program read from script file -- cmd [args] : workload to tracing Signed-off-by: Jovi Zhangwei <jovi.zhang...@gmail.com> --- tools/ktap/kp_main.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 tools/ktap/kp_main.c diff --git a/tools/ktap/kp_main.c b/tools/ktap/kp_main.c new file mode 100644 index 0000000..f4b9a7b --- /dev/null +++ b/tools/ktap/kp_main.c @@ -0,0 +1,443 @@ +/* + * main.c - ktap compiler and loader entry + * + * This file is part of ktap by Jovi Zhangwei. + * + * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhang...@gmail.com>. + * + * ktap is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * ktap is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sched.h> +#include <string.h> +#include <signal.h> +#include <stdarg.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <math.h> +#include <linux/errno.h> + +#include "../../include/uapi/ktap/ktap_types.h" +#include "kp_lex.h" +#include "kp_parse.h" +#include "kp_symbol.h" + +static void usage(const char *msg_fmt, ...) +{ + va_list ap; + + va_start(ap, msg_fmt); + vfprintf(stderr, msg_fmt, ap); + va_end(ap); + + fprintf(stderr, +"Usage: ktap [options] file [script args] -- cmd [args]\n" +" or: ktap [options] -e one-liner -- cmd [args]\n" +"\n" +"Options and arguments:\n" +" -o file : send script output to file, instead of stderr\n" +" -p pid : specific tracing pid\n" +" -C cpu : cpu to monitor in system-wide\n" +" -T : show timestamp for event\n" +" -V : show version\n" +" -v : enable verbose mode\n" +" -q : suppress start tracing message\n" +" -d : dry run mode(register NULL callback to perf events)\n" +" -s : simple event tracing\n" +" -b : list byte codes\n" +" -le [glob] : list pre-defined events in system\n" +#ifndef NO_LIBELF +" -lf DSO : list available functions from DSO\n" +" -lm DSO : list available sdt notes from DSO\n" +#endif +" file : program read from script file\n" +" -- cmd [args] : workload to tracing\n"); + + exit(EXIT_FAILURE); +} + +#define handle_error(str) do { perror(str); exit(-1); } while(0) + +ktap_option_t uparm; +static int ktap_trunk_mem_size = 1024; + +static int kp_writer(const void* p, size_t sz, void* ud) +{ + if (uparm.trunk_len + sz > ktap_trunk_mem_size) { + int new_size = (uparm.trunk_len + sz) * 2; + uparm.trunk = realloc(uparm.trunk, new_size); + ktap_trunk_mem_size = new_size; + } + + memcpy(uparm.trunk + uparm.trunk_len, p, sz); + uparm.trunk_len += sz; + + return 0; +} + + +static int forks; +static char **workload_argv; + +static int fork_workload(int ktap_fd) +{ + int pid; + + pid = fork(); + if (pid < 0) + handle_error("failed to fork"); + + if (pid > 0) + return pid; + + signal(SIGTERM, SIG_DFL); + + execvp("", workload_argv); + + /* + * waiting ktapvm prepare all tracing event + * make it more robust in future. + */ + pause(); + + execvp(workload_argv[0], workload_argv); + + perror(workload_argv[0]); + exit(-1); + + return -1; +} + +#define KTAPVM_PATH "/sys/kernel/debug/ktap/ktapvm" + +static char *output_filename; + +static int run_ktapvm() +{ + int ktapvm_fd, ktap_fd; + int ret; + + ktapvm_fd = open(KTAPVM_PATH, O_RDONLY); + if (ktapvm_fd < 0) + handle_error("open " KTAPVM_PATH " failed"); + + ktap_fd = ioctl(ktapvm_fd, 0, NULL); + if (ktap_fd < 0) + handle_error("ioctl ktapvm failed"); + + kp_create_reader(output_filename); + + if (forks) { + uparm.trace_pid = fork_workload(ktap_fd); + uparm.workload = 1; + } + + ret = ioctl(ktap_fd, KTAP_CMD_IOC_RUN, &uparm); + switch (ret) { + case -EPERM: + case -EACCES: + fprintf(stderr, "You may not have permission to run ktap\n"); + break; + } + + close(ktap_fd); + close(ktapvm_fd); + + return ret; +} + +int verbose; +static int quiet; +static int dry_run; +static int dump_bytecode; +static char oneline_src[1024]; +static int trace_pid = -1; +static int trace_cpu = -1; +static int print_timestamp; + +#define SIMPLE_ONE_LINER_FMT \ + "trace %s { print(cpu(), tid(), execname(), argstr) }" + +static const char *script_file; +static int script_args_start; +static int script_args_end; + +#ifndef NO_LIBELF +struct binary_base +{ + int type; + const char *binary; +}; +static int print_symbol(const char *name, vaddr_t addr, void *arg) +{ + struct binary_base *base = (struct binary_base *)arg; + const char *type = base->type == FIND_SYMBOL ? + "probe" : "sdt"; + + printf("%s:%s:%s\n", type, base->binary, name); + return 0; +} +#endif + +static void parse_option(int argc, char **argv) +{ + char pid[32] = {0}; + char cpu_str[32] = {0}; + char *next_arg; + int i, j; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + script_file = argv[i]; + if (!script_file) + usage(""); + + script_args_start = i + 1; + script_args_end = argc; + + for (j = i + 1; j < argc; j++) { + if (argv[j][0] == '-' && argv[j][1] == '-') + goto found_cmd; + } + + return; + } + + if (argv[i][0] == '-' && argv[i][1] == '-') { + j = i; + goto found_cmd; + } + + next_arg = argv[i + 1]; + + switch (argv[i][1]) { + case 'o': + output_filename = malloc(strlen(next_arg) + 1); + if (!output_filename) + return; + + strncpy(output_filename, next_arg, strlen(next_arg)); + i++; + break; + case 'e': + strncpy(oneline_src, next_arg, strlen(next_arg)); + i++; + break; + case 'p': + strncpy(pid, next_arg, strlen(next_arg)); + trace_pid = atoi(pid); + i++; + break; + case 'C': + strncpy(cpu_str, next_arg, strlen(next_arg)); + trace_cpu = atoi(cpu_str); + i++; + break; + case 'T': + print_timestamp = 1; + break; + case 'v': + verbose = 1; + break; + case 'q': + quiet = 1; + break; + case 'd': + dry_run = 1; + break; + case 's': + sprintf(oneline_src, SIMPLE_ONE_LINER_FMT, next_arg); + i++; + break; + case 'b': + dump_bytecode = 1; + break; + case 'l': /* list available events */ + switch (argv[i][2]) { + case 'e': /* tracepoints */ + list_available_events(next_arg); + exit(EXIT_SUCCESS); +#ifndef NO_LIBELF + case 'f': /* functions in DSO */ + case 'm': /* static marks in DSO */ { + const char *binary = next_arg; + int type = argv[i][2] == 'f' ? + FIND_SYMBOL : FIND_STAPSDT_NOTE; + struct binary_base base = { + .type = type, + .binary = binary, + }; + int ret; + + ret = parse_dso_symbols(binary, type, + print_symbol, + (void *)&base); + if (ret <= 0) { + fprintf(stderr, + "error: no symbols in binary %s\n", + binary); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } +#endif + default: + exit(EXIT_FAILURE); + } + break; + case 'V': + usage("%s\n\n", KTAP_VERSION); + break; + case '?': + case 'h': + usage(""); + break; + default: + usage("wrong argument\n"); + break; + } + } + + return; + + found_cmd: + script_args_end = j; + forks = 1; + workload_argv = &argv[j + 1]; +} + +static ktap_proto_t *parse(const char *chunkname, const char *src) +{ + LexState ls; + + ls.chunkarg = chunkname ? chunkname : "?"; + kp_lex_init(); + kp_buf_init(&ls.sb); + kp_lex_setup(&ls, src); + return kp_parse(&ls); +} + +static void compile(const char *input) +{ + ktap_proto_t *pt; + char *buff; + struct stat sb; + int fdin; + + kp_str_resize(); + + if (oneline_src[0] != '\0') { + pt = parse(input, oneline_src); + goto dump; + } + + fdin = open(input, O_RDONLY); + if (fdin < 0) { + fprintf(stderr, "open file %s failed\n", input); + exit(-1); + } + + if (fstat(fdin, &sb) == -1) + handle_error("fstat failed"); + + buff = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); + if (buff == MAP_FAILED) + handle_error("mmap failed"); + + pt = parse(input, buff); + + munmap(buff, sb.st_size); + close(fdin); + + dump: + if (dump_bytecode) { + kp_dump_proto(pt); + exit(0); + } + + /* bcwrite */ + uparm.trunk = malloc(ktap_trunk_mem_size); + if (!uparm.trunk) + handle_error("malloc failed"); + + kp_bcwrite(pt, kp_writer, NULL, 0); +} + +int main(int argc, char **argv) +{ + char **ktapvm_argv; + int new_index, i; + int ret; + + if (argc == 1) + usage(""); + + parse_option(argc, argv); + + if (oneline_src[0] != '\0') + script_file = "(command line)"; + + compile(script_file); + + ktapvm_argv = (char **)malloc(sizeof(char *)*(script_args_end - + script_args_start + 1)); + if (!ktapvm_argv) { + fprintf(stderr, "canno allocate ktapvm_argv\n"); + return -1; + } + + ktapvm_argv[0] = malloc(strlen(script_file) + 1); + if (!ktapvm_argv[0]) { + fprintf(stderr, "canno allocate memory\n"); + return -1; + } + strcpy(ktapvm_argv[0], script_file); + ktapvm_argv[0][strlen(script_file)] = '\0'; + + /* pass rest argv into ktapvm */ + new_index = 1; + for (i = script_args_start; i < script_args_end; i++) { + ktapvm_argv[new_index] = malloc(strlen(argv[i]) + 1); + if (!ktapvm_argv[new_index]) { + fprintf(stderr, "canno allocate memory\n"); + return -1; + } + strcpy(ktapvm_argv[new_index], argv[i]); + ktapvm_argv[new_index][strlen(argv[i])] = '\0'; + new_index++; + } + + uparm.argv = ktapvm_argv; + uparm.argc = new_index; + uparm.verbose = verbose; + uparm.trace_pid = trace_pid; + uparm.trace_cpu = trace_cpu; + uparm.print_timestamp = print_timestamp; + uparm.quiet = quiet; + uparm.dry_run = dry_run; + + /* start running into kernel ktapvm */ + ret = run_ktapvm(); + + cleanup_event_resources(); + return ret; +} + + -- 1.8.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/