cavatools: initialize repository
[cavatools.git] / caveat / main.c
1 /*
2 Copyright (c) 2020 Peter Hsu. All Rights Reserved. See LICENCE file for details.
3 */
4
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <assert.h>
9 #include <string.h>
10 #include <sys/mman.h>
11 #include <sys/time.h>
12
13 #include "caveat.h"
14 #include "opcodes.h"
15 #include "insn.h"
16 #include "shmfifo.h"
17 #include "core.h"
18
19
20 #define DEFAULT_REPORT_INTERVAL 1000
21
22
23 struct core_t core;
24
25 const char* tracing;
26 static long bufsize;
27 static const char* func;
28
29 const struct options_t opt[] =
30 {
31 { "--out=s", .s=&tracing, .ds=0, .h="Create trace file/fifo =name" },
32 { "--trace=s", .s=&tracing, .ds=0, .h="synonym for --out" },
33 { "--buffer=i", .i=&bufsize, .di=12, .h="Shared memory buffer size is 2^ =n bytes" },
34 { "--func=s", .s=&func, .ds="_start", .h="Trace function =name" },
35 { "--withregs", .b=&core.params.flags, .bv=tr_has_reg, .h="Include register values in trace" },
36 { "--after=i", .i=&core.params.after, .di=1, .h="Start tracing function after =number calls" },
37 { "--every=i", .i=&core.params.every, .di=1, .h="Trace only every =number times function is called" },
38 { "--skip=i", .i=&core.params.skip, .di=1, .h="Trace function once every =number times called" },
39 { "--report=i", .i=&core.params.report, .di=1000, .h="Progress report every =number million instructions" },
40 { "--quiet", .b=&core.params.quiet, .bv=1, .h="Don't report progress to stderr" },
41 { "-q", .b=&core.params.quiet, .bv=1, .h="short for --quiet" },
42 { 0 }
43 };
44 const char* usage = "caveat [caveat-options] target-program [target-options]";
45
46 int main(int argc, const char* argv[], const char* envp[])
47 {
48 struct timeval start_timeval;
49 gettimeofday(&start_timeval, 0);
50 init_core(&core, clock(), &start_timeval);
51
52 int numopts = parse_options(argv+1);
53 if (argc == numopts+1)
54 help_exit();
55 core.params.report *= 1000000; /* unit is millions of instructions */
56 Addr_t entry_pc = load_elf_binary(argv[1+numopts], 1);
57 insnSpace_init();
58 Addr_t stack_top = initialize_stack(argc-1-numopts, argv+1+numopts, envp);
59 core.pc = entry_pc;
60 core.reg[SP].a = stack_top;
61 if (tracing) {
62 if (!func)
63 func = "_start";
64 if (! find_symbol(func, &core.params.breakpoint, 0)) {
65 fprintf(stderr, "function %s cannot be found in symbol table\n", func);
66 exit(1);
67 }
68 fprintf(stderr, "Tracing %s at 0x%lx\n", func, core.params.breakpoint);
69 core.params.flags |= tr_has_pc | tr_has_mem;
70 core.tb = fifo_create(tracing, bufsize);
71 }
72 else
73 core.params.breakpoint = 0;
74 int rc = run_program(&core);
75 if (tracing) {
76 fifo_put(core.tb, trM(tr_eof, 0));
77 fifo_finish(core.tb);
78 }
79 return rc;
80 }
81
82 #include <signal.h>
83 #include <setjmp.h>
84
85 jmp_buf return_to_top_level;
86
87 void signal_handler(int nSIGnum, siginfo_t* si, void* vcontext)
88 {
89 // ucontext_t* context = (ucontext_t*)vcontext;
90 // context->uc_mcontext.gregs[]
91 fprintf(stderr, "\n\nSegV %p\n", si->si_addr);
92 longjmp(return_to_top_level, 1);
93 }
94
95 int run_program(struct core_t* cpu)
96 {
97 struct sigaction action;
98 memset(&action, 0, sizeof(struct sigaction));
99 sigemptyset(&action.sa_mask);
100 sigemptyset(&action.sa_mask);
101 // action.sa_flags = SA_SIGINFO;
102 action.sa_sigaction = signal_handler;
103 action.sa_flags = 0;
104
105 sigaction(SIGSEGV, &action, NULL);
106 if (setjmp(return_to_top_level) != 0) {
107 //fprintf(stderr, "Back to main\n");
108 print_insn(cpu->pc, stderr);
109 print_registers(cpu->reg, stderr);
110 return -1;
111 }
112 return outer_loop(&core);
113 }
114