2 * main.c - ktap compiler and loader entry
4 * This file is part of ktap by Jovi Zhangwei.
6 * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
8 * ktap is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * ktap is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
36 #include "../include/ktap_types.h"
37 #include "../include/ktap_opcodes.h"
39 #include "../runtime/kp_obj.h"
40 #include "../runtime/kp_str.h"
41 #include "../runtime/kp_tab.h"
46 /*******************************************************************/
48 void *ktapc_reallocv(void *block, size_t osize, size_t nsize)
50 return kp_reallocv(NULL, block, osize, nsize);
53 ktap_closure *ktapc_newclosure(int n)
55 return kp_newclosure(NULL, n);
58 ktap_proto *ktapc_newproto()
60 return kp_newproto(NULL);
63 const ktap_value *ktapc_table_get(ktap_tab *t, const ktap_value *key)
65 return kp_tab_get(t, key);
68 void ktapc_table_setvalue(ktap_tab *t, const ktap_value *key, ktap_value *val)
70 kp_tab_setvalue(NULL, t, key, val);
73 ktap_tab *ktapc_table_new()
75 return kp_tab_new(NULL);
78 ktap_string *ktapc_ts_newlstr(const char *str, size_t l)
80 return kp_tstring_newlstr(NULL, str, l);
83 ktap_string *ktapc_ts_new(const char *str)
85 return kp_tstring_new(NULL, str);
88 int ktapc_ts_eqstr(ktap_string *a, ktap_string *b)
90 return kp_tstring_eqstr(a, b);
93 static void ktapc_runerror(const char *err_msg_fmt, ...)
97 fprintf(stderr, "ktapc_runerror\n");
99 va_start(ap, err_msg_fmt);
100 vfprintf(stderr, err_msg_fmt, ap);
107 * todo: memory leak here
109 char *ktapc_sprintf(const char *fmt, ...)
111 char *msg = malloc(128);
115 vsprintf(msg, fmt, argp);
121 #define MINSIZEARRAY 4
123 void *ktapc_growaux(void *block, int *size, size_t size_elems, int limit,
129 if (*size >= limit/2) { /* cannot double it? */
130 if (*size >= limit) /* cannot grow even a little? */
131 ktapc_runerror("too many %s (limit is %d)\n",
133 newsize = limit; /* still have at least one free place */
135 newsize = (*size) * 2;
136 if (newsize < MINSIZEARRAY)
137 newsize = MINSIZEARRAY; /* minimum size */
140 newblock = ktapc_reallocv(block, (*size) * size_elems, newsize * size_elems);
141 *size = newsize; /* update only when everything else is OK */
145 /*************************************************************************/
147 #define print_base(i) \
149 if (i < f->sizelocvars) /* it's a localvars */ \
150 printf("%s", getstr(f->locvars[i].varname)); \
152 printf("base + %d", i); \
155 #define print_RK(instr, _field) \
157 if (ISK(GETARG_##_field(instr))) \
158 kp_showobj(NULL, k + INDEXK(GETARG_##_field(instr))); \
160 print_base(GETARG_##_field(instr)); \
163 #define print_RKA(instr) print_RK(instr, A)
164 #define print_RKB(instr) print_RK(instr, B)
165 #define print_RKC(instr) print_RK(instr, C)
167 #define print_upvalue(idx) \
172 printf("upvalues[%d]", (idx)); \
175 static void decode_instruction(ktap_proto *f, int instr)
177 int opcode = GET_OPCODE(instr);
182 printf("%.8x\t", instr);
183 printf("%s\t", ktap_opnames[opcode]);
188 print_base(GETARG_A(instr));
190 print_base(GETARG_B(instr));
193 print_base(GETARG_A(instr));
195 print_upvalue(GETARG_B(instr));
196 printf("{"); print_RKC(instr); printf("}");
200 print_base(GETARG_A(instr));
203 print_base(GETARG_B(instr));
210 print_base(GETARG_A(instr));
219 print_base(GETARG_A(instr));
222 kp_showobj(NULL, k + GETARG_Bx(instr));
226 print_base(GETARG_A(instr));
229 printf("\t%d", GETARG_sBx(instr));
233 print_base(GETARG_A(instr));
234 printf(" <- closure(func starts from line %d)",
235 f->p[GETARG_Bx(instr)]->lineinfo[0]);
238 print_upvalue(GETARG_A(instr));
246 print_base(GETARG_A(instr));
249 print_upvalue(GETARG_B(instr));
252 print_base(GETARG_A(instr));
261 static int function_nr = 0;
263 /* this is a debug function used for check bytecode chunk file */
264 static void dump_function(int level, ktap_proto *f)
268 printf("\n----------------------------------------------------\n");
269 printf("function %d [level %d]:\n", function_nr++, level);
270 printf("linedefined: %d\n", f->linedefined);
271 printf("lastlinedefined: %d\n", f->lastlinedefined);
272 printf("numparams: %d\n", f->numparams);
273 printf("is_vararg: %d\n", f->is_vararg);
274 printf("maxstacksize: %d\n", f->maxstacksize);
275 printf("source: %s\n", getstr(f->source));
276 printf("sizelineinfo: %d \t", f->sizelineinfo);
277 for (i = 0; i < f->sizelineinfo; i++)
278 printf("%d ", f->lineinfo[i]);
281 printf("sizek: %d\n", f->sizek);
282 for (i = 0; i < f->sizek; i++) {
283 switch(f->k[i].type) {
288 printf("\tBOOLEAN: ");
289 printf("%d\n", f->k[i].val.b);
292 printf("\tTNUMBER: ");
293 printf("%ld\n", f->k[i].val.n);
297 printf("\tTSTRING: ");
298 printf("%s\n", svalue(&(f->k[i])));
301 printf("\tUnknow constant type %d: ", f->k[i].type);
302 kp_showobj(NULL, &(f->k[i]));
307 printf("sizelocvars: %d\n", f->sizelocvars);
308 for (i = 0; i < f->sizelocvars; i++) {
309 printf("\tlocvars: %s startpc: %d endpc: %d\n",
310 getstr(f->locvars[i].varname), f->locvars[i].startpc,
311 f->locvars[i].endpc);
314 printf("sizeupvalues: %d\n", f->sizeupvalues);
315 for (i = 0; i < f->sizeupvalues; i++) {
316 printf("\tname: %s instack: %d idx: %d\n",
317 getstr(f->upvalues[i].name), f->upvalues[i].instack,
322 printf("sizecode: %d\n", f->sizecode);
323 for (i = 0; i < f->sizecode; i++)
324 decode_instruction(f, f->code[i]);
326 printf("sizep: %d\n", f->sizep);
327 for (i = 0; i < f->sizep; i++)
328 dump_function(level + 1, f->p[i]);
332 static void usage(const char *msg_fmt, ...)
336 va_start(ap, msg_fmt);
337 vfprintf(stderr, msg_fmt, ap);
341 "Usage: ktap [options] file [script args] -- cmd [args]\n"
342 " or: ktap [options] -e one-liner -- cmd [args]\n"
344 "Options and arguments:\n"
345 " -o file : send script output to file, instead of stderr\n"
346 " -p pid : specific tracing pid\n"
347 " -C cpu : cpu to monitor in system-wide\n"
348 " -T : show timestamp for event\n"
349 " -V : show version\n"
350 " -v : enable verbose mode\n"
351 " -q : suppress start tracing message\n"
352 " -s : simple event tracing\n"
353 " -b : list byte codes\n"
354 " -le [glob] : list pre-defined events in system\n"
356 " -lf DSO : list available functions from DSO\n"
357 " -lm DSO : list available sdt notes from DSO\n"
359 " file : program read from script file\n"
360 " -- cmd [args] : workload to tracing\n");
365 ktap_global_state dummy_global_state;
367 static void init_dummy_global_state()
369 memset(&dummy_global_state, 0, sizeof(ktap_global_state));
370 dummy_global_state.seed = 201236;
372 kp_tstring_resize(NULL, 32); /* set inital string hashtable size */
375 #define handle_error(str) do { perror(str); exit(-1); } while(0)
377 static struct ktap_parm uparm;
378 static int ktap_trunk_mem_size = 1024;
380 static int ktapc_writer(const void* p, size_t sz, void* ud)
382 if (uparm.trunk_len + sz > ktap_trunk_mem_size) {
383 int new_size = (uparm.trunk_len + sz) * 2;
384 uparm.trunk = realloc(uparm.trunk, new_size);
385 ktap_trunk_mem_size = new_size;
388 memcpy(uparm.trunk + uparm.trunk_len, p, sz);
389 uparm.trunk_len += sz;
396 static char **workload_argv;
398 static int fork_workload(int ktap_fd)
404 handle_error("failed to fork");
409 signal(SIGTERM, SIG_DFL);
411 execvp("", workload_argv);
414 * waiting ktapvm prepare all tracing event
415 * make it more robust in future.
419 execvp(workload_argv[0], workload_argv);
421 perror(workload_argv[0]);
427 #define KTAPVM_PATH "/sys/kernel/debug/ktap/ktapvm"
429 static char *output_filename;
431 static int run_ktapvm()
433 int ktapvm_fd, ktap_fd;
436 ktapvm_fd = open(KTAPVM_PATH, O_RDONLY);
438 handle_error("open " KTAPVM_PATH " failed");
440 ktap_fd = ioctl(ktapvm_fd, 0, NULL);
442 handle_error("ioctl ktapvm failed");
444 ktapio_create(output_filename);
447 uparm.trace_pid = fork_workload(ktap_fd);
451 ret = ioctl(ktap_fd, KTAP_CMD_IOC_RUN, &uparm);
461 static int dump_bytecode;
462 static char oneline_src[1024];
463 static int trace_pid = -1;
464 static int trace_cpu = -1;
465 static int print_timestamp;
467 #define SIMPLE_ONE_LINER_FMT \
468 "trace %s { print(cpu(), tid(), execname(), argevent) }"
470 static const char *script_file;
471 static int script_args_start;
472 static int script_args_end;
480 static int print_symbol(const char *name, vaddr_t addr, void *arg)
482 struct binary_base *base = (struct binary_base *)arg;
483 const char *type = base->type == FIND_SYMBOL ?
486 printf("%s:%s:%s\n", type, base->binary, name);
491 static void parse_option(int argc, char **argv)
494 char cpu_str[32] = {0};
498 for (i = 1; i < argc; i++) {
499 if (argv[i][0] != '-') {
500 script_file = argv[i];
504 script_args_start = i + 1;
505 script_args_end = argc;
507 for (j = i + 1; j < argc; j++) {
508 if (argv[j][0] == '-' && argv[j][1] == '-')
515 if (argv[i][0] == '-' && argv[i][1] == '-') {
520 next_arg = argv[i + 1];
522 switch (argv[i][1]) {
524 output_filename = malloc(strlen(next_arg) + 1);
525 if (!output_filename)
528 strncpy(output_filename, next_arg, strlen(next_arg));
532 strncpy(oneline_src, next_arg, strlen(next_arg));
536 strncpy(pid, next_arg, strlen(next_arg));
537 trace_pid = atoi(pid);
541 strncpy(cpu_str, next_arg, strlen(next_arg));
542 trace_cpu = atoi(cpu_str);
555 sprintf(oneline_src, SIMPLE_ONE_LINER_FMT, next_arg);
561 case 'l': /* list available events */
562 switch (argv[i][2]) {
563 case 'e': /* tracepoints */
564 list_available_events(next_arg);
567 case 'f': /* functions in DSO */
568 case 'm': /* static marks in DSO */ {
569 const char *binary = next_arg;
570 int type = argv[i][2] == 'f' ?
571 FIND_SYMBOL : FIND_STAPSDT_NOTE;
572 struct binary_base base = {
578 ret = parse_dso_symbols(binary, type,
583 "error: no symbols in binary %s\n",
595 #ifdef CONFIG_KTAP_FFI
596 usage("%s (with FFI)\n\n", KTAP_VERSION);
598 usage("%s\n\n", KTAP_VERSION);
606 usage("wrong argument\n");
616 workload_argv = &argv[j + 1];
619 static void compile(const char *input)
626 if (oneline_src[0] != '\0') {
627 init_dummy_global_state();
629 cl = ktapc_parser(oneline_src, input);
633 fdin = open(input, O_RDONLY);
635 fprintf(stderr, "open file %s failed\n", input);
639 if (fstat(fdin, &sb) == -1)
640 handle_error("fstat failed");
642 buff = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
643 if (buff == MAP_FAILED)
644 handle_error("mmap failed");
646 init_dummy_global_state();
648 cl = ktapc_parser(buff, input);
650 munmap(buff, sb.st_size);
655 dump_function(1, cl->p);
660 uparm.trunk = malloc(ktap_trunk_mem_size);
662 handle_error("malloc failed");
664 ktapc_dump(cl->p, ktapc_writer, NULL, 0);
668 int main(int argc, char **argv)
677 parse_option(argc, argv);
679 if (oneline_src[0] != '\0')
680 script_file = "one-liner";
682 compile(script_file);
684 ktapvm_argv = (char **)malloc(sizeof(char *)*(script_args_end -
685 script_args_start + 1));
687 fprintf(stderr, "canno allocate ktapvm_argv\n");
691 ktapvm_argv[0] = malloc(strlen(script_file) + 1);
692 if (!ktapvm_argv[0]) {
693 fprintf(stderr, "canno allocate memory\n");
696 strcpy(ktapvm_argv[0], script_file);
697 ktapvm_argv[0][strlen(script_file)] = '\0';
699 /* pass rest argv into ktapvm */
701 for (i = script_args_start; i < script_args_end; i++) {
702 ktapvm_argv[new_index] = malloc(strlen(argv[i]) + 1);
703 if (!ktapvm_argv[new_index]) {
704 fprintf(stderr, "canno allocate memory\n");
707 strcpy(ktapvm_argv[new_index], argv[i]);
708 ktapvm_argv[new_index][strlen(argv[i])] = '\0';
712 uparm.argv = ktapvm_argv;
713 uparm.argc = new_index;
714 uparm.verbose = verbose;
715 uparm.trace_pid = trace_pid;
716 uparm.trace_cpu = trace_cpu;
717 uparm.print_timestamp = print_timestamp;
720 /* start running into kernel ktapvm */
723 cleanup_event_resources();