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