drc: support ms ABI
[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   else
92     memset(&packet, 0, sizeof(packet));
93
94   ret = send(pdb_net_sock, &packet, sizeof(packet.header) + packet.header.len, MSG_NOSIGNAL);
95   if (ret != sizeof(packet.header) + packet.header.len) {
96     if (ret < 0)
97       perror("send");
98     else
99       printf("send: %d/%d\n", ret, sizeof(packet.header) + packet.header.len);
100     close(pdb_net_sock);
101     pdb_net_sock = -1;
102     ret = -1;
103   }
104   return ret;
105 }
106 #else
107 #define pdb_net_send(a,b) 0
108 #endif // PDB_NET
109
110 #ifdef HAVE_READLINE
111 #include <readline/readline.h>
112 #include <readline/history.h>
113 #endif
114
115 static char *my_readline(const char *prompt)
116 {
117   char *line = NULL;
118
119 #ifdef HAVE_READLINE
120   line = readline("(pdb) ");
121   if (line == NULL)
122     return NULL;
123   if (line[0] != 0)
124     add_history(line);
125 #else
126   size_t size = 0;
127   ssize_t ret;
128
129   printf("(pdb) ");
130   fflush(stdout);
131   ret = getline(&line, &size, stdin);
132   if (ret < 0)
133     return NULL;
134   if (ret > 0 && line[ret - 1] == '\n')
135     line[ret - 1] = 0;
136 #endif
137
138   return line;
139 }
140
141 static struct pdb_cpu *context2cpu(const void *context)
142 {
143   int i;
144   for (i = 0; i < pdb_cpu_count; i++)
145     if (pdb_cpus[i].context == context)
146       return &pdb_cpus[i];
147   return NULL;
148 }
149
150 static const char *get_token(char *buf, int blen, const char *str)
151 {
152   const char *p, *s, *e;
153   int len;
154
155   p = str;
156   while (isspace_(*p))
157     p++;
158   if (*p == 0)
159     return NULL;
160   if (*p == ';') {
161     strcpy(buf, ";");
162     return p + 1;
163   }
164
165   s = p;
166   while (*p != 0 && *p != ';' && !isspace_(*p))
167     p++;
168   e = p;
169   while (isspace_(*e))
170     e++;
171
172   len = p - s;
173   if (len > blen - 1)
174     len = blen - 1;
175   memcpy(buf, s, len);
176   buf[len] = 0;
177   return e;
178 }
179
180 static const char *get_arg(char *buf, int blen, const char *str)
181 {
182   if (*str == ';')
183     return NULL;
184   return get_token(buf, blen, str);
185 }
186
187 enum cmd_ret_e {
188   CMDRET_DONE,          // ..and back to prompt
189 //  CMDRET_PROMPT,        // go to prompt
190   CMDRET_CONT_DO_NEXT,  // continue and do remaining cmds on next event
191   CMDRET_CONT_REDO,     // continue and redo all cmds on next event
192 };
193
194 static int do_print(struct pdb_cpu *cpu, const char *args)
195 {
196   elprintf(EL_STATUS, "cpu %d (%s)", cpu->id, cpu->name);
197 #ifndef NO_32X
198   if (cpu->type == PDBCT_SH2) {
199     SH2 *sh2 = cpu->context;
200     int i;
201     printf("PC,SR %08x,     %03x\n", sh2->pc, sh2->sr & 0x3ff);
202     for (i = 0; i < 16/2; i++)
203       printf("R%d,%2d %08x,%08x\n", i, i + 8, sh2->r[i], sh2->r[i + 8]);
204     printf("gb,vb %08x,%08x\n", sh2->gbr, sh2->vbr);
205     printf("IRQs/mask:        %02x/%02x\n", Pico32x.sh2irqi[sh2->is_slave],
206       Pico32x.sh2irq_mask[sh2->is_slave]);
207     printf("cycles %d/%d (%d)\n", sh2->cycles_done, sh2->cycles_aim, (signed int)sh2->sr >> 12);
208   }
209 #endif
210   return CMDRET_DONE;
211 }
212
213 static int do_step_all(struct pdb_cpu *cpu, const char *args)
214 {
215   char tmp[32];
216   if (!get_arg(tmp, sizeof(tmp), args)) {
217     printf("step_all: missing arg\n");
218     return CMDRET_DONE;
219   }
220
221   pdb_global_icount = atoi(tmp);
222   return CMDRET_CONT_DO_NEXT;
223 }
224
225 static int do_continue(struct pdb_cpu *cpu, const char *args)
226 {
227   char tmp[32];
228   if (get_arg(tmp, sizeof(tmp), args))
229     cpu->icount = atoi(tmp);
230   return CMDRET_CONT_DO_NEXT;
231 }
232
233 static int do_step(struct pdb_cpu *cpu, const char *args)
234 {
235   cpu->icount = 1;
236   return do_continue(cpu, args);
237 }
238
239 static int do_waitcpu(struct pdb_cpu *cpu, const char *args)
240 {
241   char tmp[32];
242   if (!get_arg(tmp, sizeof(tmp), args)) {
243     printf("waitcpu: missing arg\n");
244     return CMDRET_DONE;
245   }
246   if (strcmp(tmp, cpu->name) == 0)
247     return CMDRET_DONE;
248
249   return CMDRET_CONT_REDO;
250 }
251
252 static int do_help(struct pdb_cpu *cpu, const char *args);
253
254 static struct {
255   const char *cmd;
256   const char *help;
257   int (*handler)(struct pdb_cpu *cpu, const char *args);
258 } pdb_cmds[] = {
259   { "help",     "",          do_help },
260   { "continue", "[insns]",   do_continue },
261   { "step",     "[insns]",   do_step },
262   { "step_all", "<insns>",   do_step_all },
263   { "waitcpu",  "<cpuname>", do_waitcpu },
264   { "print",    "",          do_print },
265 };
266
267 static int do_help(struct pdb_cpu *cpu, const char *args)
268 {
269   int i;
270   for (i = 0; i < ARRAY_SIZE(pdb_cmds); i++)
271     printf("%s %s\n", pdb_cmds[i].cmd, pdb_cmds[i].help);
272   return CMDRET_DONE;
273 }
274
275 static int do_comands(struct pdb_cpu *cpu, const char *cmds)
276 {
277   const char *p = cmds;
278   while (p != NULL)
279   {
280     const char *pcmd;
281     char cmd[32];
282     int i, len;
283     int ret = 0;
284
285     pcmd = p;
286     p = get_token(cmd, sizeof(cmd), p);
287     if (p == NULL)
288       break;
289     if (cmd[0] == ';')
290       continue;
291
292     len = strlen(cmd);
293     for (i = 0; i < ARRAY_SIZE(pdb_cmds); i++)
294       if (strncmp(pdb_cmds[i].cmd, cmd, len) == 0) {
295         ret = pdb_cmds[i].handler(cpu, p);
296         break;
297       }
298
299     if (i == ARRAY_SIZE(pdb_cmds)) {
300       printf("bad cmd: %s\n", cmd);
301       break;
302     }
303
304     // skip until next command
305     while (1) {
306       p = get_token(cmd, sizeof(cmd), p);
307       if (p == NULL || cmd[0] == ';')
308         break;
309     }
310
311     pdb_event_cmds[0] = 0;
312     if (ret == CMDRET_CONT_DO_NEXT) {
313       pdb_pending_cmds[0] = 0;
314       if (p != NULL)
315         strcpy(pdb_event_cmds, p);
316       return 0;
317     }
318     if (ret == CMDRET_CONT_REDO) {
319       if (pcmd != pdb_pending_cmds)
320         strncpy(pdb_pending_cmds, pcmd, sizeof(pdb_pending_cmds));
321       return 0;
322     }
323     pdb_pending_cmds[0] = 0;
324   }
325
326   return 1;
327 }
328
329 static void do_prompt(struct pdb_cpu *cpu)
330 {
331   static char prev[128];
332   int ret;
333
334   while (1) {
335     char *line, *cline;
336
337     line = my_readline("(pdb) ");
338     if (line == NULL)
339       break;
340     if (line[0] == 0)
341       cline = prev;
342     else {
343       cline = line;
344       strncpy(prev, line, sizeof(prev));
345     }
346       
347     ret = do_comands(cpu, cline);
348     free(line);
349
350     if (ret == 0)
351       break;
352   }
353 }
354
355 void pdb_register_cpu(void *context, int type, const char *name)
356 {
357   int i = pdb_cpu_count;
358   memset(&pdb_cpus[i], 0, sizeof(pdb_cpus[i]));
359   pdb_cpus[i].context = context;
360   pdb_cpus[i].type = type;
361   pdb_cpus[i].id = pdb_cpu_count;
362   pdb_cpus[i].name = name;
363   pdb_cpus[i].icount = -1;
364   pdb_cpu_count++;
365 }
366
367 void pdb_step(void *context, unsigned int pc)
368 {
369   struct pdb_cpu *cpu = context2cpu(context);
370   int i;
371
372   if (pdb_net_send(cpu, pc) < 0)
373     goto prompt;
374
375   if (pdb_pending_cmds[0] != 0)
376     if (do_comands(cpu, pdb_pending_cmds))
377       goto prompt;
378
379   // breakpoint?
380   for (i = 0; i < cpu->bpt_count; i++)
381     if (cpu->bpts[i] == pc)
382       goto prompt;
383
384   // hit num of insns?
385   if (pdb_global_icount > 0)
386     if (--pdb_global_icount == 0)
387       goto prompt;
388
389   if (cpu->icount > 0)
390     if (--(cpu->icount) == 0)
391       goto prompt;
392
393   return;
394
395 prompt:
396   if (pdb_event_cmds[0] != 0)
397     if (!do_comands(cpu, pdb_event_cmds))
398       return;
399
400   printf("%s @%08x\n", cpu->name, pc);
401   do_prompt(cpu);
402 }
403
404 void pdb_command(const char *cmd)
405 {
406   strncpy(pdb_pending_cmds, cmd, sizeof(pdb_pending_cmds));
407   pdb_pending_cmds[sizeof(pdb_pending_cmds) - 1] = 0;
408 }
409
410 void pdb_cleanup(void)
411 {
412   pdb_cpu_count = 0;
413 }
414
415 // vim:shiftwidth=2:expandtab