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