source: buchla-emu/emu/gdb.c@ 5fa5369

Last change on this file since 5fa5369 was 5fa5369, checked in by Thomas Lopatic <thomas@…>, 3 years ago

Single-stepping looks OK.

  • Property mode set to 100644
File size: 11.9 KB
Line 
1/*
2 * Copyright (C) 2017 The Contributors
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * A copy of the GNU General Public License can be found in the file
15 * "gpl.txt" in the top directory of this repository.
16 */
17
18#include <all.h>
19
20#define ver(...) _ver(gdb_verbose, 0, __VA_ARGS__)
21#define ver2(...) _ver(gdb_verbose, 1, __VA_ARGS__)
22#define ver3(...) _ver(gdb_verbose, 2, __VA_ARGS__)
23
24int32_t gdb_verbose = 0;
25
26#define PORT 12053
27#define SZ_BUF 10000
28
29#define RES_ERR \
30 ((result_t){ .ok = false })
31
32#define RES_OK \
33 ((result_t){ .ok = true })
34
35#define RES_DAT(_out, _n_out) \
36 ((result_t){ .ok = true, .out = (uint8_t *)_out, .n_out = (int32_t)_n_out })
37
38#define LOCK_NONE 0
39#define LOCK_REQ 1
40#define LOCK_ACK 2
41
42typedef enum {
43 STATE_HEAD,
44 STATE_DATA,
45 STATE_CHECK_1,
46 STATE_CHECK_2,
47 STATE_ACK
48} state_t;
49
50typedef struct {
51 bool ok;
52 const uint8_t *out;
53 int32_t n_out;
54} result_t;
55
56static TCPsocket lis;
57static SDLNet_SocketSet set;
58
59static state_t state;
60static SDL_atomic_t lock;
61
62void gdb_init(void)
63{
64 ver("gdb init");
65
66 IPaddress addr;
67
68 if (SDLNet_ResolveHost(&addr, NULL, PORT) < 0) {
69 fail("SDLNet_ResolveHost() failed: %s", SDLNet_GetError());
70 }
71
72 lis = SDLNet_TCP_Open(&addr);
73
74 if (lis == NULL) {
75 fail("SDLNet_TCP_Open() failed: %s", SDLNet_GetError());
76 }
77
78 set = SDLNet_AllocSocketSet(2);
79
80 if (set == NULL) {
81 fail("SDLNet_AllocSocketSet() failed: %s", SDLNet_GetError());
82 }
83
84 if (SDLNet_TCP_AddSocket(set, lis) < 0) {
85 fail("SDLNet_AddSocket() failed: %s", SDLNet_GetError());
86 }
87
88 SDL_AtomicSet(&lock, 0);
89}
90
91void gdb_quit(void)
92{
93 ver("gdb quit");
94
95 SDLNet_FreeSocketSet(set);
96 SDLNet_TCP_Close(lis);
97}
98
99void gdb_inst(void)
100{
101 ver3("gdb inst");
102
103 if (SDL_AtomicGet(&lock) == LOCK_NONE) {
104 return;
105 }
106
107 if (SDL_UnlockMutex(cpu_mutex) < 0) {
108 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
109 }
110
111 ver2("<- lock req");
112 ver2("-> lock ack");
113 SDL_AtomicSet(&lock, LOCK_ACK);
114
115 while (SDL_AtomicGet(&lock) == LOCK_ACK) {
116 SDL_Delay(100);
117 }
118
119 ver2("<- lock none / req");
120
121 if (SDL_LockMutex(cpu_mutex) < 0) {
122 fail("SDL_LockMutex() failed: %s", SDL_GetError());
123 }
124}
125
126static void stop_cpu(void)
127{
128 ver2("-> lock req");
129 SDL_AtomicSet(&lock, LOCK_REQ);
130
131 while (SDL_AtomicGet(&lock) != LOCK_ACK) {
132 SDL_Delay(100);
133 }
134
135 ver2("<- lock ack");
136}
137
138static void cont_cpu(void)
139{
140 ver2("-> lock none");
141 SDL_AtomicSet(&lock, LOCK_NONE);
142}
143
144static void step_cpu(void)
145{
146 ver2("-> lock req");
147 SDL_AtomicSet(&lock, LOCK_REQ);
148}
149
150static void wait_cpu(void)
151{
152 while (SDL_AtomicGet(&lock) != LOCK_ACK) {
153 SDL_Delay(100);
154 }
155
156 ver2("<- lock ack");
157}
158
159static int32_t hex_digit(char c)
160{
161 if (c >= '0' && c <= '9') {
162 return c - '0';
163 }
164
165 if (c >= 'a' && c <= 'f') {
166 return 10 + c - 'a';
167 }
168
169 if (c >= 'A' && c <= 'F') {
170 return 10 + c - 'A';
171 }
172
173 return -1;
174}
175
176static int32_t hex_num(const char **pp)
177{
178 int32_t res = 0;
179 int32_t dig;
180
181 while ((dig = hex_digit(**pp)) >= 0) {
182 res = (res << 4) | dig;
183 ++*pp;
184 }
185
186 return res;
187}
188
189static result_t com_reason(void)
190{
191 // 0x05 = SIGTRAP
192 return RES_DAT("S05", 3);
193}
194
195static void set_pc(const char **req)
196{
197 int32_t addr = hex_num(req);
198
199 if (SDL_LockMutex(cpu_mutex) < 0) {
200 fail("SDL_LockMutex() failed: %s", SDL_GetError());
201 }
202
203 m68k_set_reg(M68K_REG_PC, (uint32_t)addr);
204
205 if (SDL_UnlockMutex(cpu_mutex) < 0) {
206 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
207 }
208}
209
210static result_t com_cont(const char *req)
211{
212 if (req[0] != 0) {
213 set_pc(&req);
214 }
215
216 cont_cpu();
217 wait_cpu();
218
219 // 0x05 = SIGTRAP
220 return RES_DAT("S05", 3);
221}
222
223static result_t com_step(const char *req)
224{
225 if (req[0] != 0) {
226 set_pc(&req);
227 }
228
229 step_cpu();
230 wait_cpu();
231
232 // 0x05 = SIGTRAP
233 return RES_DAT("S05", 3);
234}
235
236static result_t com_rd_reg(void)
237{
238 static char buf[(8 + 8 + 2) * 8 + 1];
239
240 if (SDL_LockMutex(cpu_mutex) < 0) {
241 fail("SDL_LockMutex() failed: %s", SDL_GetError());
242 }
243
244 uint32_t d0 = m68k_get_reg(NULL, M68K_REG_D0);
245 uint32_t d1 = m68k_get_reg(NULL, M68K_REG_D1);
246 uint32_t d2 = m68k_get_reg(NULL, M68K_REG_D2);
247 uint32_t d3 = m68k_get_reg(NULL, M68K_REG_D3);
248 uint32_t d4 = m68k_get_reg(NULL, M68K_REG_D4);
249 uint32_t d5 = m68k_get_reg(NULL, M68K_REG_D5);
250 uint32_t d6 = m68k_get_reg(NULL, M68K_REG_D6);
251 uint32_t d7 = m68k_get_reg(NULL, M68K_REG_D7);
252
253 uint32_t a0 = m68k_get_reg(NULL, M68K_REG_A0);
254 uint32_t a1 = m68k_get_reg(NULL, M68K_REG_A1);
255 uint32_t a2 = m68k_get_reg(NULL, M68K_REG_A2);
256 uint32_t a3 = m68k_get_reg(NULL, M68K_REG_A3);
257 uint32_t a4 = m68k_get_reg(NULL, M68K_REG_A4);
258 uint32_t a5 = m68k_get_reg(NULL, M68K_REG_A5);
259 uint32_t a6 = m68k_get_reg(NULL, M68K_REG_A6);
260 uint32_t a7 = m68k_get_reg(NULL, M68K_REG_A7);
261
262 uint32_t ps = m68k_get_reg(NULL, M68K_REG_SR);
263 uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
264
265 if (SDL_UnlockMutex(cpu_mutex) < 0) {
266 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
267 }
268
269 sprintf(buf,
270 "%08x%08x%08x%08x%08x%08x%08x%08x"
271 "%08x%08x%08x%08x%08x%08x%08x%08x"
272 "%08x%08x",
273 d0, d1, d2, d3, d4, d5, d6, d7,
274 a0, a1, a2, a3, a4, a5, a6, a7,
275 ps, pc);
276
277 return RES_DAT(buf, sizeof buf - 1);
278}
279
280static result_t com_wr_reg(const char *req)
281{
282 uint32_t d0, d1, d2, d3, d4, d5, d6, d7;
283 uint32_t a0, a1, a2, a3, a4, a5, a6, a7;
284 uint32_t ps, pc;
285
286 if (sscanf(req,
287 "%08x%08x%08x%08x%08x%08x%08x%08x"
288 "%08x%08x%08x%08x%08x%08x%08x%08x"
289 "%08x%08x",
290 &d0, &d1, &d2, &d3, &d4, &d5, &d6, &d7,
291 &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7,
292 &ps, &pc) != 8 + 8 + 2) {
293 return RES_DAT("E01", 3);
294 }
295
296 if (SDL_LockMutex(cpu_mutex) < 0) {
297 fail("SDL_LockMutex() failed: %s", SDL_GetError());
298 }
299
300 m68k_set_reg(M68K_REG_D0, d0);
301 m68k_set_reg(M68K_REG_D1, d1);
302 m68k_set_reg(M68K_REG_D2, d2);
303 m68k_set_reg(M68K_REG_D3, d3);
304 m68k_set_reg(M68K_REG_D4, d4);
305 m68k_set_reg(M68K_REG_D5, d5);
306 m68k_set_reg(M68K_REG_D6, d6);
307 m68k_set_reg(M68K_REG_D7, d7);
308
309 m68k_set_reg(M68K_REG_A0, a0);
310 m68k_set_reg(M68K_REG_A1, a1);
311 m68k_set_reg(M68K_REG_A2, a2);
312 m68k_set_reg(M68K_REG_A3, a3);
313 m68k_set_reg(M68K_REG_A4, a4);
314 m68k_set_reg(M68K_REG_A5, a5);
315 m68k_set_reg(M68K_REG_A6, a6);
316 m68k_set_reg(M68K_REG_A7, a7);
317
318 m68k_set_reg(M68K_REG_SR, ps);
319 m68k_set_reg(M68K_REG_PC, pc);
320
321 if (SDL_UnlockMutex(cpu_mutex) < 0) {
322 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
323 }
324
325 return RES_DAT("OK", 2);
326}
327
328static result_t com_rd_mem(const char *req)
329{
330 int32_t addr = hex_num(&req);
331
332 if (*req++ != ',') {
333 return RES_DAT("E01", 3);
334 }
335
336 int32_t len = hex_num(&req);
337
338 if (*req != 0 || len == 0) {
339 return RES_DAT("E01", 3);
340 }
341
342 if (len > 10000) {
343 len = 10000;
344 }
345
346 static char buf[10000 * 2 + 1];
347
348 if (SDL_LockMutex(cpu_mutex) < 0) {
349 fail("SDL_LockMutex() failed: %s", SDL_GetError());
350 }
351
352 for (int32_t i = 0; i < len; ++i) {
353 uint8_t byte = cpu_peek(addr + i);
354 sprintf(buf + i * 2, "%02x", byte);
355 }
356
357 if (SDL_UnlockMutex(cpu_mutex) < 0) {
358 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
359 }
360
361 return RES_DAT(buf, len * 2);
362}
363
364static result_t com_wr_mem(const char *req)
365{
366 int32_t addr = hex_num(&req);
367
368 if (*req++ != ',') {
369 return RES_DAT("E01", 3);
370 }
371
372 int32_t len = hex_num(&req);
373
374 if (*req++ != ':') {
375 return RES_DAT("E01", 3);
376 }
377
378 if (SDL_LockMutex(cpu_mutex) < 0) {
379 fail("SDL_LockMutex() failed: %s", SDL_GetError());
380 }
381
382 int32_t i;
383
384 for (i = 0; i < len; ++i) {
385 int32_t hi = hex_digit(*req++);
386
387 if (hi < 0) {
388 break;
389 }
390
391 int32_t lo = hex_digit(*req++);
392
393 if (lo < 0) {
394 break;
395 }
396
397 cpu_poke(addr + i, (uint8_t)((hi << 4) | lo));
398 }
399
400 if (SDL_UnlockMutex(cpu_mutex) < 0) {
401 fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
402 }
403
404 return RES_DAT("OK", 2);
405}
406
407static result_t handle(const char *req)
408{
409 result_t res;
410
411 switch (req[0]) {
412 case '?':
413 res = com_reason();
414 break;
415
416 case 'c':
417 res = com_cont(req + 1);
418 break;
419
420 case 'C':
421 res = com_cont(req + 4);
422 break;
423
424 case 's':
425 res = com_step(req + 1);
426 break;
427
428 case 'S':
429 res = com_step(req + 4);
430 break;
431
432 case 'g':
433 res = com_rd_reg();
434 break;
435
436 case 'G':
437 res = com_wr_reg(req + 1);
438 break;
439
440 case 'm':
441 res = com_rd_mem(req + 1);
442 break;
443
444 case 'M':
445 res = com_wr_mem(req + 1);
446 break;
447
448 default:
449 res = RES_DAT("", 0);
450 break;
451 }
452
453 if (!res.ok || res.n_out > SZ_BUF - 5) {
454 fail("unexpected result");
455 }
456
457 static const uint8_t *hex = (uint8_t *)"0123456789abcdef";
458 static uint8_t buf[SZ_BUF];
459
460 buf[0] = '$';
461 memcpy(buf + 1, res.out, (size_t)res.n_out);
462
463 int32_t sum = 0;
464
465 for (int32_t i = 0; i < res.n_out; ++i) {
466 sum = (sum + res.out[i]) % 256;
467 }
468
469 buf[res.n_out + 1] = '#';
470 buf[res.n_out + 2] = hex[sum / 16];
471 buf[res.n_out + 3] = hex[sum % 16];
472 buf[res.n_out + 4] = 0;
473
474 ver2("resp %s", (char *)buf);
475 return RES_DAT(buf, res.n_out + 4);
476}
477
478static result_t input(uint8_t byte)
479{
480 static int32_t n_buf;
481 static uint8_t buf[SZ_BUF];
482 static int32_t sum;
483 static int32_t check;
484
485 int32_t hex;
486 result_t res;
487
488 ver3("input %c st %d n %d", byte, (int32_t)state, n_buf);
489
490 switch (state) {
491 case STATE_HEAD:
492 if (byte != '$') {
493 err("expected '$'");
494 return RES_ERR;
495 }
496
497 sum = 0;
498 n_buf = 0;
499 state = STATE_DATA;
500 return RES_OK;
501
502 case STATE_DATA:
503 if (n_buf == SZ_BUF - 1) {
504 err("packet too long");
505 return RES_ERR;
506 }
507
508 if (byte == '#') {
509 state = STATE_CHECK_1;
510 return RES_DAT("+", 1);
511 }
512
513 sum = (sum + byte) % 256;
514 buf[n_buf] = byte;
515 ++n_buf;
516 return RES_OK;
517
518 case STATE_CHECK_1:
519 hex = hex_digit((char)byte);
520
521 if (hex < 0) {
522 err("malformed checksum (0x%02x)", byte);
523 return RES_ERR;
524 }
525
526 check = hex << 4;
527 state = STATE_CHECK_2;
528 return RES_OK;
529
530 case STATE_CHECK_2:
531 hex = hex_digit((char)byte);
532
533 if (hex < 0) {
534 err("malformed checksum (0x%02x)", byte);
535 return RES_ERR;
536 }
537
538 check |= hex;
539
540 if (sum != check) {
541 err("invalid checksum");
542 return RES_ERR;
543 }
544
545 buf[n_buf] = 0;
546 ver2("pack %s", buf);
547
548 res = handle((char *)buf);
549
550 if (!res.ok) {
551 return RES_ERR;
552 }
553
554 state = STATE_ACK;
555 return RES_DAT(res.out, res.n_out);
556
557 case STATE_ACK:
558 if (byte != '+') {
559 err("invalid ACK (0x%02x)", byte);
560 return RES_ERR;
561 }
562
563 state = STATE_HEAD;
564 return RES_OK;
565
566 default:
567 fail("invalid state");
568 }
569
570 // not reached, but Eclipse doesn't know
571 return RES_ERR;
572}
573
574static void con_close(TCPsocket con)
575{
576 if (SDLNet_TCP_DelSocket(set, con) < 0) {
577 fail("SDLNet_TCP_DelSocket() failed: %s", SDLNet_GetError());
578 }
579
580 SDLNet_TCP_Close(con);
581 cont_cpu();
582}
583
584void gdb_loop(void)
585{
586 inf("entering GDB loop");
587 TCPsocket con = NULL;
588
589 while (SDL_AtomicGet(&run) != 0) {
590 int32_t n_act = SDLNet_CheckSockets(set, 250);
591
592 if (n_act < 0) {
593 fail("SDLNet_CheckSockets() failed: %s", SDLNet_GetError());
594 }
595
596 if (n_act == 0) {
597 continue;
598 }
599
600 if (SDLNet_SocketReady(lis) != 0) {
601 ver("incoming connection");
602
603 if (con != NULL) {
604 ver("closing old");
605 con_close(con);
606 }
607
608 ver("accepting new");
609 con = SDLNet_TCP_Accept(lis);
610
611 if (con == NULL) {
612 fail("SDLNet_TCP_Accept() failed: %s", SDLNet_GetError());
613 }
614
615 if (SDLNet_TCP_AddSocket(set, con) < 0) {
616 fail("SDLNet_AddSocket() failed: %s", SDLNet_GetError());
617 }
618
619 stop_cpu();
620 state = STATE_ACK;
621 continue;
622 }
623
624 if (con == NULL || SDLNet_SocketReady(con) == 0) {
625 continue;
626 }
627
628 ver3("reading");
629 uint8_t byte;
630
631 if (SDLNet_TCP_Recv(con, &byte, 1) < 1) {
632 ver("peer closed");
633 con_close(con);
634 con = NULL;
635 continue;
636 }
637
638 result_t res = input(byte);
639
640 if (!res.ok) {
641 err("invalid packet from GDB");
642 con_close(con);
643 con = NULL;
644 continue;
645 }
646
647 if (res.out == NULL) {
648 continue;
649 }
650
651 if (SDLNet_TCP_Send(con, res.out, res.n_out) != res.n_out) {
652 err("connection error");
653 con_close(con);
654 con = NULL;
655 continue;
656 }
657 }
658
659 if (con != NULL) {
660 con_close(con);
661 }
662
663 inf("leaving GDB loop");
664}
Note: See TracBrowser for help on using the repository browser.