drc: support ms ABI
[picodrive.git] / cpu / debug.c
CommitLineData
5686d931 1/*
5686d931 2 * PDB, the PicoDrive debugger
cff531af 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.
5686d931 7 */
8#define _GNU_SOURCE
9#include <stdio.h>
10
11#include "../pico/pico_int.h"
12#include "debug.h"
13
14static char pdb_pending_cmds[128];
15static char pdb_event_cmds[128];
16
17static 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];
26static int pdb_cpu_count;
27
28static 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
40static int pdb_net_sock = -1;
41
42int 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
71static 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 }
30f0fdd4 91 else
92 memset(&packet, 0, sizeof(packet));
5686d931 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
115static 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
141static 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
150static 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
180static 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
187enum 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
194static int do_print(struct pdb_cpu *cpu, const char *args)
195{
5686d931 196 elprintf(EL_STATUS, "cpu %d (%s)", cpu->id, cpu->name);
f3a57b2d 197#ifndef NO_32X
5686d931 198 if (cpu->type == PDBCT_SH2) {
199 SH2 *sh2 = cpu->context;
f3a57b2d 200 int i;
5686d931 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 }
f3a57b2d 209#endif
5686d931 210 return CMDRET_DONE;
211}
212
213static 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
225static 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
233static int do_step(struct pdb_cpu *cpu, const char *args)
234{
235 cpu->icount = 1;
236 return do_continue(cpu, args);
237}
238
239static 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
252static int do_help(struct pdb_cpu *cpu, const char *args);
253
254static 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
267static 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
275static 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
329static 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
355void 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
367void 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
395prompt:
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
404void 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
410void pdb_cleanup(void)
411{
412 pdb_cpu_count = 0;
413}
414
cff531af 415// vim:shiftwidth=2:expandtab