Mercurial > repos > blastem
comparison debug.c @ 2170:ada3130b1396
Add memory indirection syntax to debugger parser/evaluator
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 06 Aug 2022 14:50:41 -0700 |
parents | cb9572145f8e |
children | 4b47155965c8 |
comparison
equal
deleted
inserted
replaced
2169:cb9572145f8e | 2170:ada3130b1396 |
---|---|
67 typedef enum { | 67 typedef enum { |
68 TOKEN_NONE, | 68 TOKEN_NONE, |
69 TOKEN_NUM, | 69 TOKEN_NUM, |
70 TOKEN_NAME, | 70 TOKEN_NAME, |
71 TOKEN_OPER, | 71 TOKEN_OPER, |
72 TOKEN_SIZE | 72 TOKEN_SIZE, |
73 TOKEN_LBRACKET, | |
74 TOKEN_RBRACKET, | |
73 } token_type; | 75 } token_type; |
74 | 76 |
75 static const char *token_type_names[] = { | 77 static const char *token_type_names[] = { |
76 "TOKEN_NONE", | 78 "TOKEN_NONE", |
77 "TOKEN_NUM", | 79 "TOKEN_NUM", |
78 "TOKEN_NAME", | 80 "TOKEN_NAME", |
79 "TOKEN_OPER", | 81 "TOKEN_OPER", |
80 "TOKEN_SIZE" | 82 "TOKEN_SIZE", |
83 "TOKEN_LBRACKET", | |
84 "TOKEN_RBRACKET" | |
81 }; | 85 }; |
82 | 86 |
83 typedef struct { | 87 typedef struct { |
84 token_type type; | 88 token_type type; |
85 union { | 89 union { |
151 .type = TOKEN_SIZE, | 155 .type = TOKEN_SIZE, |
152 .v = { | 156 .v = { |
153 .op = {start[1], 0} | 157 .op = {start[1], 0} |
154 } | 158 } |
155 }; | 159 }; |
160 case '[': | |
161 *end = start + 1; | |
162 return (token) { | |
163 .type = TOKEN_LBRACKET | |
164 }; | |
165 case ']': | |
166 *end = start + 1; | |
167 return (token) { | |
168 .type = TOKEN_RBRACKET | |
169 }; | |
156 } | 170 } |
157 *end = start + 1; | 171 *end = start + 1; |
158 while (**end && !isblank(**end) && **end != '.') | 172 while (**end && !isblank(**end) && **end != '.') |
159 { | 173 { |
160 ++*end; | 174 ++*end; |
173 typedef enum { | 187 typedef enum { |
174 EXPR_NONE, | 188 EXPR_NONE, |
175 EXPR_SCALAR, | 189 EXPR_SCALAR, |
176 EXPR_UNARY, | 190 EXPR_UNARY, |
177 EXPR_BINARY, | 191 EXPR_BINARY, |
178 EXPR_SIZE | 192 EXPR_SIZE, |
193 EXPR_MEM | |
179 } expr_type; | 194 } expr_type; |
180 | 195 |
181 typedef struct expr expr; | 196 typedef struct expr expr; |
182 | 197 |
183 struct expr { | 198 struct expr { |
198 free(e->op.v.str); | 213 free(e->op.v.str); |
199 } | 214 } |
200 free(e); | 215 free(e); |
201 } | 216 } |
202 | 217 |
218 static expr *parse_scalar_or_muldiv(char *start, char **end); | |
219 static expr *parse_expression(char *start, char **end); | |
220 | |
203 static expr *parse_scalar(char *start, char **end) | 221 static expr *parse_scalar(char *start, char **end) |
204 { | 222 { |
205 char *after_first; | 223 char *after_first; |
206 token first = parse_token(start, &after_first); | 224 token first = parse_token(start, &after_first); |
207 if (!first.type) { | 225 if (!first.type) { |
220 expr *ret = calloc(1, sizeof(expr)); | 238 expr *ret = calloc(1, sizeof(expr)); |
221 ret->type = EXPR_UNARY; | 239 ret->type = EXPR_UNARY; |
222 ret->op = first; | 240 ret->op = first; |
223 ret->left = target; | 241 ret->left = target; |
224 *end = after_first; | 242 *end = after_first; |
243 return ret; | |
244 } | |
245 if (first.type == TOKEN_LBRACKET) { | |
246 expr *ret = calloc(1, sizeof(expr)); | |
247 ret->type = EXPR_MEM; | |
248 ret->left = parse_expression(after_first, end); | |
249 if (!ret->left) { | |
250 fprintf(stderr, "Expression expected after `[`\n"); | |
251 free(ret); | |
252 return NULL; | |
253 } | |
254 token rbrack = parse_token(*end, end); | |
255 if (rbrack.type != TOKEN_RBRACKET) { | |
256 fprintf(stderr, "Missing closing `]`"); | |
257 free_expr(ret); | |
258 return NULL; | |
259 } | |
260 char *after_size; | |
261 token size = parse_token(*end, &after_size); | |
262 if (size.type == TOKEN_SIZE) { | |
263 *end = after_size; | |
264 ret->op = size; | |
265 } | |
225 return ret; | 266 return ret; |
226 } | 267 } |
227 token second = parse_token(after_first, end); | 268 token second = parse_token(after_first, end); |
228 if (second.type != TOKEN_SIZE) { | 269 if (second.type != TOKEN_SIZE) { |
229 expr *ret = calloc(1, sizeof(expr)); | 270 expr *ret = calloc(1, sizeof(expr)); |
238 ret->left->type = EXPR_SCALAR; | 279 ret->left->type = EXPR_SCALAR; |
239 ret->left->op = second; | 280 ret->left->op = second; |
240 ret->op = first; | 281 ret->op = first; |
241 return ret; | 282 return ret; |
242 } | 283 } |
243 | |
244 static expr *parse_scalar_or_muldiv(char *start, char **end); | |
245 static expr *parse_expression(char *start, char **end); | |
246 | 284 |
247 static expr *maybe_binary(expr *left, char *start, char **end) | 285 static expr *maybe_binary(expr *left, char *start, char **end) |
248 { | 286 { |
249 char *after_first; | 287 char *after_first; |
250 token first = parse_token(start, &after_first); | 288 token first = parse_token(start, &after_first); |
329 ret->type = EXPR_UNARY; | 367 ret->type = EXPR_UNARY; |
330 ret->op = first; | 368 ret->op = first; |
331 ret->left = target; | 369 ret->left = target; |
332 return ret; | 370 return ret; |
333 } | 371 } |
372 if (first.type == TOKEN_LBRACKET) { | |
373 expr *ret = calloc(1, sizeof(expr)); | |
374 ret->type = EXPR_MEM; | |
375 ret->left = parse_expression(after_first, end); | |
376 if (!ret->left) { | |
377 fprintf(stderr, "Expression expected after `[`\n"); | |
378 free(ret); | |
379 return NULL; | |
380 } | |
381 token rbrack = parse_token(*end, end); | |
382 if (rbrack.type != TOKEN_RBRACKET) { | |
383 fprintf(stderr, "Missing closing `]`"); | |
384 free_expr(ret); | |
385 return NULL; | |
386 } | |
387 char *after_size; | |
388 token size = parse_token(*end, &after_size); | |
389 if (size.type == TOKEN_SIZE) { | |
390 *end = after_size; | |
391 ret->op = size; | |
392 } | |
393 return ret; | |
394 } | |
334 char *after_second; | 395 char *after_second; |
335 token second = parse_token(after_first, &after_second); | 396 token second = parse_token(after_first, &after_second); |
336 if (!second.type) { | |
337 expr *ret = calloc(1, sizeof(expr)); | |
338 ret->type = EXPR_SCALAR; | |
339 ret->op = first; | |
340 *end = after_first; | |
341 return ret; | |
342 } | |
343 if (second.type == TOKEN_OPER) { | 397 if (second.type == TOKEN_OPER) { |
344 expr *ret; | 398 expr *ret; |
345 expr *bin = calloc(1, sizeof(expr)); | 399 expr *bin = calloc(1, sizeof(expr)); |
346 bin->type = EXPR_BINARY; | 400 bin->type = EXPR_BINARY; |
347 bin->left = calloc(1, sizeof(expr)); | 401 bin->left = calloc(1, sizeof(expr)); |
378 value->left = calloc(1, sizeof(expr)); | 432 value->left = calloc(1, sizeof(expr)); |
379 value->left->type = EXPR_SCALAR; | 433 value->left->type = EXPR_SCALAR; |
380 value->left->op = first; | 434 value->left->op = first; |
381 return maybe_muldiv(value, after_second, end); | 435 return maybe_muldiv(value, after_second, end); |
382 } else { | 436 } else { |
383 fprintf(stderr, "Unexpected %s after scalar\n", token_type_names[second.type]); | 437 expr *ret = calloc(1, sizeof(expr)); |
384 return NULL; | 438 ret->type = EXPR_SCALAR; |
439 ret->op = first; | |
440 *end = after_first; | |
441 return ret; | |
385 } | 442 } |
386 } | 443 } |
387 | 444 |
388 static expr *parse_expression(char *start, char **end) | 445 static expr *parse_expression(char *start, char **end) |
389 { | 446 { |
406 ret->type = EXPR_UNARY; | 463 ret->type = EXPR_UNARY; |
407 ret->op = first; | 464 ret->op = first; |
408 ret->left = target; | 465 ret->left = target; |
409 return ret; | 466 return ret; |
410 } | 467 } |
468 if (first.type == TOKEN_LBRACKET) { | |
469 expr *ret = calloc(1, sizeof(expr)); | |
470 ret->type = EXPR_MEM; | |
471 ret->left = parse_expression(after_first, end); | |
472 if (!ret->left) { | |
473 fprintf(stderr, "Expression expected after `[`\n"); | |
474 free(ret); | |
475 return NULL; | |
476 } | |
477 token rbrack = parse_token(*end, end); | |
478 if (rbrack.type != TOKEN_RBRACKET) { | |
479 fprintf(stderr, "Missing closing `]`"); | |
480 free_expr(ret); | |
481 return NULL; | |
482 } | |
483 char *after_size; | |
484 token size = parse_token(*end, &after_size); | |
485 if (size.type == TOKEN_SIZE) { | |
486 *end = after_size; | |
487 ret->op = size; | |
488 } | |
489 return ret; | |
490 } | |
411 char *after_second; | 491 char *after_second; |
412 token second = parse_token(after_first, &after_second); | 492 token second = parse_token(after_first, &after_second); |
413 if (!second.type) { | |
414 expr *ret = calloc(1, sizeof(expr)); | |
415 ret->type = EXPR_SCALAR; | |
416 ret->op = first; | |
417 *end = after_first; | |
418 return ret; | |
419 } | |
420 if (second.type == TOKEN_OPER) { | 493 if (second.type == TOKEN_OPER) { |
421 expr *bin = calloc(1, sizeof(expr)); | 494 expr *bin = calloc(1, sizeof(expr)); |
422 bin->type = EXPR_BINARY; | 495 bin->type = EXPR_BINARY; |
423 bin->left = calloc(1, sizeof(expr)); | 496 bin->left = calloc(1, sizeof(expr)); |
424 bin->left->type = EXPR_SCALAR; | 497 bin->left->type = EXPR_SCALAR; |
454 value->left = calloc(1, sizeof(expr)); | 527 value->left = calloc(1, sizeof(expr)); |
455 value->left->type = EXPR_SCALAR; | 528 value->left->type = EXPR_SCALAR; |
456 value->left->op = first; | 529 value->left->op = first; |
457 return maybe_binary(value, after_second, end); | 530 return maybe_binary(value, after_second, end); |
458 } else { | 531 } else { |
459 fprintf(stderr, "Unexpected %s after scalar\n", token_type_names[second.type]); | 532 expr *ret = calloc(1, sizeof(expr)); |
460 return NULL; | 533 ret->type = EXPR_SCALAR; |
534 ret->op = first; | |
535 *end = after_first; | |
536 return ret; | |
461 } | 537 } |
462 } | 538 } |
463 | 539 |
464 typedef struct debug_context debug_context; | 540 typedef struct debug_context debug_context; |
465 typedef uint8_t (*resolver)(debug_context *context, const char *name, uint32_t *out); | 541 typedef uint8_t (*resolver)(debug_context *context, const char *name, uint32_t *out); |
542 typedef uint8_t (*reader)(debug_context *context, uint32_t *out, char size); | |
466 | 543 |
467 struct debug_context { | 544 struct debug_context { |
468 resolver resolve; | 545 resolver resolve; |
546 reader read_mem; | |
469 void *system; | 547 void *system; |
470 }; | 548 }; |
471 | 549 |
472 uint8_t eval_expr(debug_context *context, expr *e, uint32_t *out) | 550 uint8_t eval_expr(debug_context *context, expr *e, uint32_t *out) |
473 { | 551 { |
549 case 'w': | 627 case 'w': |
550 *out &= 0xFFFF; | 628 *out &= 0xFFFF; |
551 break; | 629 break; |
552 } | 630 } |
553 return 1; | 631 return 1; |
632 case EXPR_MEM: | |
633 if (!eval_expr(context, e->left, out)) { | |
634 return 0; | |
635 } | |
636 return context->read_mem(context, out, e->op.v.op[0]); | |
554 default: | 637 default: |
555 return 0; | 638 return 0; |
556 } | 639 } |
557 } | 640 } |
558 | 641 |
606 { | 689 { |
607 //TODO: share this implementation with GDB debugger | 690 //TODO: share this implementation with GDB debugger |
608 return read_byte(address, (void **)context->mem_pointers, &context->options->gen, context); | 691 return read_byte(address, (void **)context->mem_pointers, &context->options->gen, context); |
609 } | 692 } |
610 | 693 |
611 uint16_t m68k_read_word(uint32_t address, m68k_context *context) | 694 static uint16_t m68k_read_word(uint32_t address, m68k_context *context) |
612 { | 695 { |
613 return read_word(address, (void **)context->mem_pointers, &context->options->gen, context); | 696 return read_word(address, (void **)context->mem_pointers, &context->options->gen, context); |
614 } | 697 } |
615 | 698 |
616 uint32_t m68k_read_long(uint32_t address, m68k_context *context) | 699 static uint32_t m68k_read_long(uint32_t address, m68k_context *context) |
617 { | 700 { |
618 return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context); | 701 return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context); |
619 } | 702 } |
620 | 703 |
621 uint8_t resolve_m68k(m68k_context *context, const char *name, uint32_t *out) | 704 static uint8_t read_m68k(m68k_context *context, uint32_t *out, char size) |
705 { | |
706 if (size == 'b') { | |
707 *out = m68k_read_byte(*out, context); | |
708 } else if (size == 'l') { | |
709 *out = m68k_read_long(*out, context); | |
710 } else { | |
711 *out = m68k_read_word(*out, context); | |
712 } | |
713 return 1; | |
714 } | |
715 | |
716 static uint8_t read_genesis(debug_context *context, uint32_t *out, char size) | |
717 { | |
718 genesis_context *gen = context->system; | |
719 return read_m68k(gen->m68k, out, size); | |
720 } | |
721 | |
722 static uint8_t resolve_m68k(m68k_context *context, const char *name, uint32_t *out) | |
622 { | 723 { |
623 if (name[0] == 'd' && name[1] >= '0' && name[1] <= '7') { | 724 if (name[0] == 'd' && name[1] >= '0' && name[1] <= '7') { |
624 *out = context->dregs[name[1]-'0']; | 725 *out = context->dregs[name[1]-'0']; |
625 } else if (name[0] == 'a' && name[1] >= '0' && name[1] <= '7') { | 726 } else if (name[0] == 'a' && name[1] >= '0' && name[1] <= '7') { |
626 *out = context->aregs[name[1]-'0']; | 727 *out = context->aregs[name[1]-'0']; |
638 return 0; | 739 return 0; |
639 } | 740 } |
640 return 1; | 741 return 1; |
641 } | 742 } |
642 | 743 |
643 uint8_t resolve_genesis(debug_context *context, const char *name, uint32_t *out) | 744 static uint8_t resolve_genesis(debug_context *context, const char *name, uint32_t *out) |
644 { | 745 { |
645 genesis_context *gen = context->system; | 746 genesis_context *gen = context->system; |
646 if (resolve_m68k(gen->m68k, name, out)) { | 747 if (resolve_m68k(gen->m68k, name, out)) { |
647 return 1; | 748 return 1; |
648 } | 749 } |
672 default: | 773 default: |
673 fprintf(stderr, "Unrecognized format character: %c\n", format_char); | 774 fprintf(stderr, "Unrecognized format character: %c\n", format_char); |
674 } | 775 } |
675 debug_context c = { | 776 debug_context c = { |
676 .resolve = resolve_genesis, | 777 .resolve = resolve_genesis, |
778 .read_mem = read_genesis, | |
677 .system = context->system | 779 .system = context->system |
678 }; | 780 }; |
679 char *after; | 781 char *after; |
680 expr *e = parse_expression(param, &after); | 782 expr *e = parse_expression(param, &after); |
681 if (e) { | 783 if (e) { |