clarify PicoDrive's license
[picodrive.git] / cpu / debug.c
1 /*
2  * PDB, the PicoDrive debugger
3  * (C) notaz, 2010
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  */
8 #define _GNU_SOURCE
9 #include <stdio.h>
10
11 #include "../pico/pico_int.h"
12 #include "debug.h"
13
14 static char pdb_pending_cmds[128];
15 static char pdb_event_cmds[128];
16
17 static struct pdb_cpu {
18   void *context;
19   int type;
20   int id;
21   const char *name;
22   unsigned int bpts[16];
23   int bpt_count;
24   int icount;
25 } pdb_cpus[5];
26 static int pdb_cpu_count;
27
28 static int pdb_global_icount;
29
30 #ifdef PDB_NET
31 #include <stddef.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <unistd.h>
37
38 #include "debug_net.h"
39
40 static int pdb_net_sock = -1;
41
42 int pdb_net_connect(const char *host, const char *port)
43 {
44   struct sockaddr_in sockadr;
45   int sock = -1;
46   int ret;
47
48   sock = socket(PF_INET, SOCK_STREAM, 0);
49   if (sock == -1) {
50     perror("socket");
51     return -1;
52   }
53
54   sockadr.sin_addr.s_addr = inet_addr(host);
55   sockadr.sin_family = AF_INET;
56   sockadr.sin_port = htons(atoi(port));
57
58   ret = connect(sock, (struct sockaddr *)&sockadr, sizeof(sockadr));
59   if (ret != 0) {
60     perror("pdb_net: connect");
61     close(sock);
62     return -1;
63   }
64
65   printf("pdb_net: connected to %s:%s\n", host, port);
66
67   pdb_net_sock = sock;
68   return 0;
69 }
70
71 static int pdb_net_send(struct pdb_cpu *cpu, unsigned int pc)
72 {
73   packet_t packet;
74   int ret;
75
76   if (pdb_net_sock < 0)
77     return 0; // not connected
78
79   if (cpu->type == PDBCT_SH2) {
80     SH2 *sh2 = cpu->context;
81     int rl = offsetof(SH2, macl) + sizeof(sh2->macl);
82     packet.header.type = PDBCT_SH2;
83     packet.header.cpuid = cpu->id;
84     packet.regs[0] = pc;
85     memcpy(&packet.regs[1], sh2->r, rl);
86     packet.regs[1+24+0] = sh2->pdb_io_csum[0];
87     packet.regs[1+24+1] = sh2->pdb_io_csum[1];
88     packet.header.len = 4 + rl + 4*2;
89     sh2->pdb_io_csum[0] = sh2->pdb_io_csum[1] = 0;
90   }
91
92   ret = send(pdb_net_sock, &packet, sizeof(packet.header) + packet.header.len, MSG_NOSIGNAL);
93   if (ret != sizeof(packet.header) + packet.header.len) {
94     if (ret < 0)
95       perror("send");
96     else
97       printf("send: %d/%d\n", ret, sizeof(packet.header) + packet.header.len);
98     close(pdb_net_sock);
99     pdb_net_sock = -1;
100     ret = -1;
101   }
102   return ret;
103 }
104 #else
105 #define pdb_net_send(a,b) 0
106 #endif // PDB_NET
107
108 #ifdef HAVE_READLINE
109 #include <readline/readline.h>
110 #include <readline/history.h>
111 #endif
112
113 static char *my_readline(const char *prompt)
114 {
115   char *line = NULL;
116
117 #ifdef HAVE_READLINE
118   line = readline("(pdb) ");
119   if (line == NULL)
120     return NULL;
121   if (line[0] != 0)
122     add_history(line);
123 #else
124   size_t size = 0;
125   ssize_t ret;
126
127   printf("(pdb) ");
128   fflush(stdout);
129   ret = getline(&line, &size, stdin);
130   if (ret < 0)
131     return NULL;
132   if (ret > 0 && line[ret - 1] == '\n')
133     line[ret - 1] = 0;
134 #endif
135
136   return line;
137 }
138
139 static struct pdb_cpu *context2cpu(const void *context)
140 {
141   int i;
142   for (i = 0; i < pdb_cpu_count; i++)
143     if (pdb_cpus[i].context == context)
144       return &pdb_cpus[i];
145   return NULL;
146 }
147
148 static const char *get_token(char *buf, int blen, const char *str)
149 {
150   const char *p, *s, *e;
151   int len;
152
153   p = str;
154   while (isspace_(*p))
155     p++;
156   if (*p == 0)
157     return NULL;
158   if (*p == ';') {
159     strcpy(buf, ";");
160     return p + 1;
161   }
162
163   s = p;
164   while (*p != 0 && *p != ';' && !isspace_(*p))
165     p++;
166   e = p;
167   while (isspace_(*e))
168     e++;
169
170   len = p - s;
171   if (len > blen - 1)
172     len = blen - 1;
173   memcpy(buf, s, len);
174   buf[len] = 0;
175   return e;
176 }
177
178 static const char *get_arg(char *buf, int blen, const char *str)
179 {
180   if (*str == ';')
181     return NULL;
182   return get_token(buf, blen, str);
183 }
184
185 enum cmd_ret_e {
186   CMDRET_DONE,          // ..and back to prompt
187 //  CMDRET_PROMPT,        // go to prompt
188   CMDRET_CONT_DO_NEXT,  // continue and do remaining cmds on next event
189   CMDRET_CONT_REDO,     // continue and redo all cmds on next event
190 };
191
192 static int do_print(struct pdb_cpu *cpu, const char *args)
193 {
194   elprintf(EL_STATUS, "cpu %d (%s)", cpu->id, cpu->name);
195 #ifndef NO_32X
196   if (cpu->type == PDBCT_SH2) {
197     SH2 *sh2 = cpu->context;
198     int i;
199     printf("PC,SR %08x,     %03x\n", sh2->pc, sh2->sr & 0x3ff);
200     for (i = 0; i < 16/2; i++)
201       printf("R%d,%2d %08x,%08x\n", i, i + 8, sh2->r[i], sh2->r[i + 8]);
202     printf("gb,vb %08x,%08x\n", sh2->gbr, sh2->vbr);
203     printf("IRQs/mask:        %02x/%02x\n", Pico32x.sh2irqi[sh2->is_slave],
204       Pico32x.sh2irq_mask[sh2->is_slave]);
205     printf("cycles %d/%d (%d)\n", sh2->cycles_done, sh2->cycles_aim, (signed int)sh2->sr >> 12);
206   }
207 #endif
208   return CMDRET_DONE;
209 }
210
211 static int do_step_all(struct pdb_cpu *cpu, const char *args)
212 {
213   char tmp[32];
214   if (!get_arg(tmp, sizeof(tmp), args)) {
215     printf("step_all: missing arg\n");
216     return CMDRET_DONE;
217   }
218
219   pdb_global_icount = atoi(tmp);
220   return CMDRET_CONT_DO_NEXT;
221 }
222
223 static int do_continue(struct pdb_cpu *cpu, const char *args)
224 {
225   char tmp[32];
226   if (get_arg(tmp, sizeof(tmp), args))
227     cpu->icount = atoi(tmp);
228   return CMDRET_CONT_DO_NEXT;
229 }
230
231 static int do_step(struct pdb_cpu *cpu, const char *args)
232 {
233   cpu->icount = 1;
234   return do_continue(cpu, args);
235 }
236
237 static int do_waitcpu(struct pdb_cpu *cpu, const char *args)
238 {
239   char tmp[32];
240   if (!get_arg(tmp, sizeof(tmp), args)) {
241     printf("waitcpu: missing arg\n");
242     return CMDRET_DONE;
243   }
244   if (strcmp(tmp, cpu->name) == 0)
245     return CMDRET_DONE;
246
247   return CMDRET_CONT_REDO;
248 }
249
250 static int do_help(struct pdb_cpu *cpu, const char *args);
251
252 static struct {
253   const char *cmd;
254   const char *help;
255   int (*handler)(struct pdb_cpu *cpu, const char *args);
256 } pdb_cmds[] = {
257   { "help",     "",          do_help },
258   { "continue", "[insns]",   do_continue },
259   { "step",     "[insns]",   do_step },
260   { "step_all", "<insns>",   do_step_all },
261   { "waitcpu",  "<cpuname>", do_waitcpu },
262   { "print",    "",          do_print },
263 };
264
265 static int do_help(struct pdb_cpu *cpu, const char *args)
266 {
267   int i;
268   for (i = 0; i < ARRAY_SIZE(pdb_cmds); i++)
269     printf("%s %s\n", pdb_cmds[i].cmd, pdb_cmds[i].help);
270   return CMDRET_DONE;
271 }
272
273 static int do_comands(struct pdb_cpu *cpu, const char *cmds)
274 {
275   const char *p = cmds;
276   while (p != NULL)
277   {
278     const char *pcmd;
279     char cmd[32];
280     int i, len;
281     int ret = 0;
282
283     pcmd = p;
284     p = get_token(cmd, sizeof(cmd), p);
285     if (p == NULL)
286       break;
287     if (cmd[0] == ';')
288       continue;
289
290     len = strlen(cmd);
291     for (i = 0; i < ARRAY_SIZE(pdb_cmds); i++)
292       if (strncmp(pdb_cmds[i].cmd, cmd, len) == 0) {
293         ret = pdb_cmds[i].handler(cpu, p);
294         break;
295       }
296
297     if (i == ARRAY_SIZE(pdb_cmds)) {
298       printf("bad cmd: %s\n", cmd);
299       break;
300     }
301
302     // skip until next command
303     while (1) {
304       p = get_token(cmd, sizeof(cmd), p);
305       if (p == NULL || cmd[0] == ';')
306         break;
307     }
308
309     pdb_event_cmds[0] = 0;
310     if (ret == CMDRET_CONT_DO_NEXT) {
311       pdb_pending_cmds[0] = 0;
312       if (p != NULL)
313         strcpy(pdb_event_cmds, p);
314       return 0;
315     }
316     if (ret == CMDRET_CONT_REDO) {
317       if (pcmd != pdb_pending_cmds)
318         strncpy(pdb_pending_cmds, pcmd, sizeof(pdb_pending_cmds));
319       return 0;
320     }
321     pdb_pending_cmds[0] = 0;
322   }
323
324   return 1;
325 }
326
327 static void do_prompt(struct pdb_cpu *cpu)
328 {
329   static char prev[128];
330   int ret;
331
332   while (1) {
333     char *line, *cline;
334
335     line = my_readline("(pdb) ");
336     if (line == NULL)
337       break;
338     if (line[0] == 0)
339       cline = prev;
340     else {
341       cline = line;
342       strncpy(prev, line, sizeof(prev));
343     }
344       
345     ret = do_comands(cpu, cline);
346     free(line);
347
348     if (ret == 0)
349       break;
350   }
351 }
352
353 void pdb_register_cpu(void *context, int type, const char *name)
354 {
355   int i = pdb_cpu_count;
356   memset(&pdb_cpus[i], 0, sizeof(pdb_cpus[i]));
357   pdb_cpus[i].context = context;
358   pdb_cpus[i].type = type;
359   pdb_cpus[i].id = pdb_cpu_count;
360   pdb_cpus[i].name = name;
361   pdb_cpus[i].icount = -1;
362   pdb_cpu_count++;
363 }
364
365 void pdb_step(void *context, unsigned int pc)
366 {
367   struct pdb_cpu *cpu = context2cpu(context);
368   int i;
369
370   if (pdb_net_send(cpu, pc) < 0)
371     goto prompt;
372
373   if (pdb_pending_cmds[0] != 0)
374     if (do_comands(cpu, pdb_pending_cmds))
375       goto prompt;
376
377   // breakpoint?
378   for (i = 0; i < cpu->bpt_count; i++)
379     if (cpu->bpts[i] == pc)
380       goto prompt;
381
382   // hit num of insns?
383   if (pdb_global_icount > 0)
384     if (--pdb_global_icount == 0)
385       goto prompt;
386
387   if (cpu->icount > 0)
388     if (--(cpu->icount) == 0)
389       goto prompt;
390
391   return;
392
393 prompt:
394   if (pdb_event_cmds[0] != 0)
395     if (!do_comands(cpu, pdb_event_cmds))
396       return;
397
398   printf("%s @%08x\n", cpu->name, pc);
399   do_prompt(cpu);
400 }
401
402 void pdb_command(const char *cmd)
403 {
404   strncpy(pdb_pending_cmds, cmd, sizeof(pdb_pending_cmds));
405   pdb_pending_cmds[sizeof(pdb_pending_cmds) - 1] = 0;
406 }
407
408 void pdb_cleanup(void)
409 {
410   pdb_cpu_count = 0;
411 }
412
413 // vim:shiftwidth=2:expandtab