1 #include <vector>
2 #include <map>
3 #include <string>
4 #include <cstdio>
5 #include <cstring>
6 #include <cstdlib>
7 #include <cerrno>
8 #include <climits>
9 #include "interactor.h"
10 #include "cpu.h"
11 #include "vmips.h"
12 
13 /*----------------------------------------------------------------------------*/
14 
15 class SimpleInteractor;
16 
17 typedef void (*func_t) (SimpleInteractor *, int, char **);
18 typedef std::map<const char *, func_t> command_table_t;
19 
20 #define DEFAULT_PROMPT "vmips=> "
21 
22 class SimpleInteractor: public Interactor {
23     const char *prompt;
24     command_table_t commands;
25     int interacting;
26 public:
SimpleInteractor()27     SimpleInteractor() : prompt(DEFAULT_PROMPT), interacting(0) { }
~SimpleInteractor()28     virtual ~SimpleInteractor() { }
29     void interact();
30     virtual void stop_interacting();
31     func_t find_function(const char *cmd);
32     void do_one_command(char *buf);
33     std::vector<char *> parse_string(char *buf);
34     void register_command(func_t func, const char *name);
35 };
36 
37 /*----------------------------------------------------------------------------*/
38 
go_fn(SimpleInteractor * in,int argc,char ** argv)39 void go_fn (SimpleInteractor *in, int argc, char **argv)
40 {
41     machine->state = vmips::RUN;
42     in->stop_interacting();
43 }
44 
step_fn(SimpleInteractor * in,int argc,char ** argv)45 void step_fn (SimpleInteractor *in, int argc, char **argv)
46 {
47     machine->step();
48     printf("PC is now 0x%x\n", machine->cpu->debug_get_pc());
49 }
50 
regs_fn(SimpleInteractor * in,int argc,char ** argv)51 void regs_fn (SimpleInteractor *in, int argc, char **argv)
52 {
53     machine->cpu->dump_regs (stdout);
54 }
55 
cp0_fn(SimpleInteractor * in,int argc,char ** argv)56 void cp0_fn (SimpleInteractor *in, int argc, char **argv)
57 {
58     machine->cpu->cpzero_dump_regs_and_tlb (stdout);
59 }
60 
stack_fn(SimpleInteractor * in,int argc,char ** argv)61 void stack_fn (SimpleInteractor *in, int argc, char **argv)
62 {
63     machine->cpu->dump_stack (stdout);
64 }
65 
parse_address(const char * cmd,const char * addr_str,uint32 * result)66 static int parse_address (const char *cmd, const char *addr_str, uint32 *result)
67 {
68     unsigned long addr;
69     char *endptr = NULL;
70     errno = 0;
71     addr = strtoul(addr_str, &endptr, 0);
72     if ((addr == 0) && (endptr == addr_str)) {
73 	printf("%s: Can't parse address.\n", cmd);
74 	return -1;
75     }
76     if (((errno == ERANGE) && (addr == ULONG_MAX))
77 #if (SIZEOF_LONG > 4)
78 	|| (addr > 0xffffffffUL)
79 #endif
80 	)
81     {
82 	printf("%s: Address out of range.\n", cmd);
83 	return -1;
84     }
85     *result = (uint32) addr;
86     return 0;
87 }
88 
mem_fn(SimpleInteractor * in,int argc,char ** argv)89 void mem_fn (SimpleInteractor *in, int argc, char **argv)
90 {
91     uint32 addr;
92     char *endptr = NULL;
93     if (argc != 2) {
94         printf("mem: usage: mem <addr>\n");
95         return;
96     }
97     if (parse_address("mem", argv[1], &addr) < 0) {
98 	return;
99     }
100     if (addr & 3) {
101 	printf("mem: Address not word-aligned.\n");
102 	return;
103     }
104     uint32 nwords = 8;
105     while (nwords--) {
106         machine->cpu->dump_mem (stdout, addr);
107         addr += 4;
108     }
109 }
110 
dis_fn(SimpleInteractor * in,int argc,char ** argv)111 void dis_fn (SimpleInteractor *in, int argc, char **argv)
112 {
113     uint32 addr;
114     char *endptr = NULL;
115     if (argc != 2) {
116         printf("dis: usage: dis <addr>\n");
117         return;
118     }
119     if (parse_address("dis", argv[1], &addr) < 0) {
120 	return;
121     }
122     if (addr & 3) {
123 	printf("dis: Address not word-aligned.\n");
124 	return;
125     }
126     uint32 nwords = 8;
127     while (nwords--) {
128 	// FIXME: disasm can only go to stderr! Lame.
129         machine->cpu->dis_mem (stderr, addr);
130         addr += 4;
131     }
132 }
133 
halt_fn(SimpleInteractor * in,int argc,char ** argv)134 void halt_fn (SimpleInteractor *in, int argc, char **argv)
135 {
136     machine->halt ();
137     in->stop_interacting();
138 }
139 
help_fn(SimpleInteractor * in,int argc,char ** argv)140 void help_fn (SimpleInteractor *in, int argc, char **argv)
141 {
142     printf
143     ("You are in the VMIPS interactive inspector.\n"
144      "Commands marked with (*) will exit the interactive inspector.\n"
145      "go     - continue execution (*)\n"
146      "step   - attempt to step one instruction\n"
147      "halt   - halt machine and quit VMIPS (*)\n"
148      "quit   - same as halt (*)\n"
149      "regs   - print CPU registers\n"
150      "cp0    - print CP0 registers and TLB\n"
151      "mem A  - print first few words of memory at word address A\n"
152      "dis A  - disassemble first few words of memory at word address A\n"
153      "stack  - print first few words of stack\n"
154      "help   - print this command list\n");
155 }
156 
157 /*----------------------------------------------------------------------------*/
158 
parse_string(char * buf)159 std::vector<char *> SimpleInteractor::parse_string(char *buf)
160 {
161     std::vector<char *> rv;
162     int len = strlen(buf);
163     char *first, *last, *end = &buf[len], *p = &buf[0];
164     while (p < end) {
165 	while ((p < end) && (isspace(*p))) {
166 	    ++p;
167 	}
168 	first = p;
169 	while ((p < end) && (!isspace(*p))) {
170 	    ++p;
171 	}
172 	last = p;
173 	if (last < end) {
174 	    *last = '\0';
175 	}
176 	if (*first != '\0') {
177 	    rv.push_back(first);
178 	}
179 	++p;
180     }
181     rv.push_back(NULL);
182     return rv;
183 }
184 
find_function(const char * cmd)185 func_t SimpleInteractor::find_function(const char *cmd)
186 {
187     for (command_table_t::iterator i = commands.begin();
188         i != commands.end(); ++i) {
189         if (strcmp(i->first, cmd) == 0) {
190             return i->second;
191         }
192     }
193     return NULL;
194 }
195 
do_one_command(char * buf)196 void SimpleInteractor::do_one_command(char *buf)
197 {
198     std::vector<char *> argvec = parse_string(buf);
199     int argc = argvec.size() - 1;
200     char **argv = &argvec[0];
201     if (argc != 0) {
202 	func_t f = find_function(argv[0]);
203 	if (f) {
204 	    f(this, argc, argv);
205 	} else {
206 	    printf("Unknown command \"%s\"\n", argv[0]);
207 	}
208     }
209 }
210 
interact()211 void SimpleInteractor::interact()
212 {
213     interacting++;
214     while (interacting) {
215 	char buf[256];
216 	fputs(prompt, stdout);
217 	if (fgets(buf, 256, stdin)) {
218             do_one_command(buf);
219 	} else {
220 	    interacting--;
221 	}
222     }
223 }
224 
stop_interacting()225 void SimpleInteractor::stop_interacting()
226 {
227     interacting--;
228 }
229 
register_command(func_t func,const char * name)230 void SimpleInteractor::register_command(func_t func, const char *name)
231 {
232     commands[name] = func;
233 }
234 
create_interactor()235 Interactor *create_interactor()
236 {
237     SimpleInteractor *in = new SimpleInteractor;
238     in->register_command(go_fn, "go");
239     in->register_command(step_fn, "step");
240     in->register_command(regs_fn, "regs");
241     in->register_command(cp0_fn, "cp0");
242     in->register_command(mem_fn, "mem");
243     in->register_command(dis_fn, "dis");
244     in->register_command(stack_fn, "stack");
245     in->register_command(halt_fn, "halt");
246     in->register_command(halt_fn, "quit");
247     in->register_command(help_fn, "help");
248     return in;
249 }
250