1 /*
2 * A Z-Machine
3 * Copyright (C) 2000 Andrew Hunter
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * The debugger
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "debug.h"
29 #include "zscii.h"
30
31 #include <signal.h>
32
33 #define yylval debug_eval_lval
34 #ifndef APPLE_IS_ARBITRARY
35 # include "eval.h"
36 #else
37 # include "eval.tab.h"
38 #endif
39
40 debug_breakpoint* debug_bplist = NULL;
41 int debug_nbps = 0;
42 debug_routine* debug_expr_routine = NULL;
43
44 int* debug_expr = NULL;
45 int debug_expr_pos = 0;
46
47 static debug_breakpoint_handler bp_handler = NULL;
48
49 /*
50 static debug_breakpoint* return_breakpoint;
51 static ZFrame* return_frame;
52 */
53
54 typedef struct debug_display
55 {
56 int* expr;
57 char* desc;
58 ZWord lastvalue;
59 int erm;
60 } debug_display;
61
62 static int ndisps = 0;
63 static debug_display* dbdisp = NULL;
64
65 static debug_address addr;
66
67 /*** ----// 888 \\---- ***/
68
69 /* The debugger console */
70
71 static int stepinto = 0;
72
73 /* Action when a breakpoint occurs */
debug_run_breakpoint(ZDWord pc)74 void debug_run_breakpoint(ZDWord pc)
75 {
76 debug_breakpoint* bp;
77 static int banner = 0;
78 int x;
79 ZFrame* frame;
80
81 bp = debug_get_breakpoint(pc);
82
83 if (bp && bp->usage == 1 && bp->funcbp && !stepinto)
84 return;
85
86 addr = debug_find_address(pc);
87 if (bp && bp->usage == 1 && bp->funcbp &&
88 (!stepinto || addr.routine->defn_fl == 0 || addr.routine->defn_fl == 255))
89 {
90 return;
91 }
92
93 /* Clear any temporary breakpoints */
94 for (x=0; x<debug_nbps; x++)
95 {
96 if (debug_bplist[x].temporary > 0)
97 {
98 debug_clear_breakpoint(debug_bplist + x);
99 x--;
100 }
101 }
102
103 /* Clear any return breakpoints */
104 if (machine.stack.current_frame) {
105 for (frame = machine.stack.current_frame; frame != NULL; frame = frame->last_frame) {
106 frame->break_on_return = 0;
107 }
108 }
109
110 stepinto = 0;
111
112 if (bp_handler != NULL) {
113 /* Run the handler instead of the standard debugging routines */
114 (*bp_handler)(pc);
115 return;
116 }
117
118 display_sanitise();
119 display_printf("=\n");
120
121 /* Print a quick banner if we're just starting up... */
122 if (banner == 0)
123 {
124 banner = 1;
125
126 display_printf("= Welcome to Zoom's symbolic debug mode\n");
127 display_printf("= %i symbols, %i known routines, in %i files\n",
128 debug_syms.nsymbols,
129 debug_syms.nroutines,
130 debug_syms.nfiles);
131 display_printf("= Type 'h' for help\n=\n");
132 }
133
134 /* Display the location information */
135 display_printf("== ");
136 display_set_style(8);
137 display_printf("%s\n", debug_address_string(addr, pc, 0));
138 display_set_style(0);
139
140 if (addr.line != NULL &&
141 addr.line->fl > 0 &&
142 addr.line->ln > 0 &&
143 addr.line->fl != 255)
144 {
145 display_printf("== ");
146 display_set_style(8);
147 if (addr.line->ln-1 > debug_syms.files[addr.line->fl].nlines)
148 display_printf("(Line not found)\n");
149 else
150 display_printf("%s\n",
151 debug_syms.files[addr.line->fl].line[addr.line->ln-1]);
152 display_set_style(0);
153 }
154
155 /* Evaluate any display expressions */
156 for (x=0; x<ndisps; x++)
157 {
158 debug_expr = dbdisp[x].expr;
159 debug_expr_pos = 0;
160 debug_expr_routine = addr.routine;
161 debug_error = NULL;
162 debug_eval_parse();
163
164 if (debug_error == NULL)
165 {
166 if (debug_eval_result != dbdisp[x].lastvalue ||
167 dbdisp[x].erm == 1)
168 {
169 display_printf("==");
170 display_set_colour(1, 7);
171 display_printf("%s=%s\n", dbdisp[x].desc,
172 debug_print_value(debug_eval_result,
173 debug_eval_type));
174 display_set_colour(4, 7);
175 }
176 dbdisp[x].lastvalue = debug_eval_result;
177 dbdisp[x].erm = 0;
178 }
179 else
180 {
181 if (dbdisp[x].erm == 0)
182 {
183 display_printf("==");
184 display_set_colour(1, 7);
185 display_printf("%s=%s\n", dbdisp[x].desc,
186 debug_error);
187 display_set_colour(4, 7);
188 }
189 dbdisp[x].erm = 1;
190 }
191
192 if (debug_eval_type != NULL)
193 free(debug_eval_type);
194 debug_eval_type = NULL;
195 }
196
197 /* Process commands */
198 while (1)
199 {
200 int cline[128];
201
202 cline[0] = 0;
203
204 display_printf("= : ");
205 display_readline(cline, 128, 0);
206
207 if (cline[0] == 0)
208 {
209 cline[0] = 's';
210 cline[1] = 0;
211 }
212
213 switch (cline[0])
214 {
215 case 'h':
216 display_printf("= Commands accepted by the debugger:\n");
217 display_printf("== b<addr> - set breakpoint\n");
218 display_printf("== c - continue execution\n");
219 display_printf("== d<expr> - display an expression after every breakpoint\n");
220 display_printf("== f - finish function\n");
221 display_printf("== h - this message\n");
222 display_printf("== l - list breakpoints\n");
223 display_printf("== n - single step, over functions\n");
224 display_printf("== p<expr> - evaluate expression\n");
225 display_printf("== s - single step, into functions\n");
226 display_printf("== t - stack backtrace\n");
227 display_printf("==\n");
228 display_printf("== Addresses can have one of two forms:\n");
229 display_printf("=== file:line\n");
230 display_printf("=== function\n");
231 display_printf("== Breakpoints will be set on the first line following that specified\n");
232 display_printf("== Expressions are in standard inform syntax (with some restrictions)\n");
233 break;
234
235 case 'c':
236 display_printf("= Continue\n");
237 goto done;
238
239 case 't':
240 {
241 ZFrame* frm;
242 int frmpc;
243 int count;
244
245 display_printf("= Backtrace\n");
246
247 frm = machine.stack.current_frame;
248 frmpc = pc;
249 count = 0;
250
251 while (frm != NULL)
252 {
253 debug_address addr;
254
255 addr = debug_find_address(frmpc);
256
257 display_printf("== %i) ", count);
258 display_set_style(8);
259 display_printf("%s", debug_address_string(addr, frmpc, 1));
260 display_set_style(0);
261 display_printf("\n");
262
263 frmpc = frm->ret;
264 frm = frm->last_frame;
265 count++;
266 }
267 }
268 break;
269
270 case 'd':
271 debug_expr_routine = addr.routine;
272 debug_expr = cline + 1;
273 debug_expr_pos = 0;
274 debug_error = NULL;
275 debug_eval_parse();
276 if (debug_error == NULL)
277 {
278 int len;
279 char* disp;
280
281 for (len=0; debug_expr[len] != 0; len++);
282
283 disp = malloc(sizeof(char)*(len+1));
284 for (len=0; debug_expr[len] != 0; len++)
285 disp[len] = debug_expr[len];
286 disp[len] = 0;
287
288 dbdisp = realloc(dbdisp, sizeof(debug_display)*(ndisps+1));
289 dbdisp[ndisps].desc = disp;
290 dbdisp[ndisps].expr = malloc(sizeof(int)*(len+1));
291
292 for (len=0; debug_expr[len] != 0; len++)
293 dbdisp[ndisps].expr[len] = debug_expr[len];
294 dbdisp[ndisps].expr[len] = 0;
295 dbdisp[ndisps].lastvalue = debug_eval_result;
296 dbdisp[ndisps].erm = 0;
297
298 ndisps++;
299
300 display_printf("= Display: %s=%s\n",
301 disp,
302 debug_print_value(debug_eval_result,
303 debug_eval_type));
304 }
305 else
306 {
307 display_printf("=? %s\n", debug_error);
308 }
309
310 if (debug_eval_type != NULL)
311 free(debug_eval_type);
312 debug_eval_type = NULL;
313 break;
314
315 case 'p':
316 debug_expr_routine = addr.routine;
317 debug_expr = cline + 1;
318 debug_expr_pos = 0;
319 debug_error = NULL;
320 debug_eval_parse();
321 if (debug_error == NULL)
322 {
323 display_printf("= Evaluate: %s\n",
324 debug_print_value(debug_eval_result,
325 debug_eval_type));
326 }
327 else
328 display_printf("=? Evaluate: %s\n", debug_error);
329
330 if (debug_eval_type != NULL)
331 free(debug_eval_type);
332 debug_eval_type = NULL;
333 break;
334
335 case 'l':
336 {
337 int x, num;
338
339 num = 0;
340
341 display_printf("= User breakpoints:\n");
342 for (x=0; x<debug_nbps; x++)
343 {
344 if (debug_bplist[x].usage > (debug_bplist[x].temporary + debug_bplist[x].funcbp))
345 {
346 debug_address bpaddr;
347
348 bpaddr = debug_find_address(debug_bplist[x].address);
349 num++;
350 display_printf("== %i) %s\n", num,
351 debug_address_string(bpaddr,
352 debug_bplist[x].address,
353 1));
354 }
355 }
356 }
357 break;
358
359 case 'b':
360 {
361 char* loc;
362 int x, y;
363 int addr;
364
365 for (x=1; cline[x] != 0 && cline[x] == ' '; x++);
366 for (y=x; cline[y] != 0; y++);
367
368 loc = malloc(sizeof(char)*(y-x+1));
369 for (y=x; cline[y] != 0; y++)
370 {
371 loc[y-x] = cline[y];
372 }
373 loc[y-x] = 0;
374
375 addr = debug_find_named_address(loc);
376
377 if (addr != -1)
378 {
379 debug_breakpoint* obp;
380 debug_address where;
381
382 where = debug_find_address(addr);
383
384 obp = debug_get_breakpoint(addr);
385 if (obp != NULL &&
386 obp->usage > (obp->temporary + obp->funcbp))
387 {
388 display_printf("=? Breakpoint already set at %s\n",
389 debug_address_string(where, addr, 0));
390 }
391 else
392 {
393 debug_set_breakpoint(addr, 0, 0);
394 display_printf("= Breakpoint set at %s\n",
395 debug_address_string(where, addr, 0));
396 }
397 }
398 else
399 {
400 display_printf("=? Location not found\n");
401 }
402
403 free(loc);
404 }
405 break;
406
407 case 's':
408 case 'n':
409 case 'f':
410 {
411 int ln;
412
413 ln = addr.line_no;
414 if (ln != -1)
415 ln++;
416 if (ln >= addr.routine->nlines)
417 ln = -1;
418
419 if (cline[0] == 'n')
420 display_printf("= Next\n");
421 else if (cline[0] == 's')
422 {
423 display_printf("= Step\n");
424 stepinto = 1;
425 }
426 else if (cline[0] == 'f')
427 {
428 display_printf("= Finish\n");
429 }
430
431 /* Set a breakpoint on each line... */
432 if (cline[0] != 'f')
433 {
434 for (ln = 0; ln < addr.routine->nlines; ln++)
435 {
436 debug_set_breakpoint(addr.routine->line[ln].address, 1, 0);
437 }
438 }
439
440 /* Set a breakpoint on the return location of this function */
441 if (machine.stack.current_frame != NULL)
442 {
443 debug_set_breakpoint(machine.stack.current_frame->ret, 1, 0);
444 }
445
446 goto done;
447 }
448
449 default:
450 display_printf("=? Type 'h' for help\n");
451 }
452 }
453
454 done:
455 display_desanitise();
456 }
457
458 /*** ----// 888 \\---- ***/
459
460 /* Breakpoints */
461
debug_set_breakpoint(int address,int temporary,int funcbp)462 int debug_set_breakpoint(int address,
463 int temporary,
464 int funcbp)
465 {
466 debug_breakpoint* bp;
467 int pos;
468
469 bp = debug_get_breakpoint(address);
470 if (bp != NULL)
471 {
472 bp->usage++;
473 bp->temporary += temporary;
474 return 1;
475 }
476
477 if (machine.memory[address] == 0xbc)
478 return 0; /* Breakpoint already set */
479
480 #ifdef DEBUG
481 printf_debug("Setting BP @ %04x\n", address);
482 #endif
483
484 pos = 0;
485
486 /* Find the breakpoint we should insert this new one before */
487 while (pos < debug_nbps && debug_bplist[pos].address < address) {
488 pos++;
489 }
490
491 /* Add a new breakpoint */
492 debug_bplist = realloc(debug_bplist,
493 sizeof(debug_breakpoint)*(debug_nbps+1));
494
495 if (pos < debug_nbps) {
496 /* Move the breakpoints up */
497 memmove(debug_bplist + pos + 1, debug_bplist + pos,
498 (debug_nbps-pos)*sizeof(debug_breakpoint));
499 }
500
501 /* Store the actual breakpoint */
502 debug_bplist[pos].address = address;
503 debug_bplist[pos].original = machine.memory[address];
504 debug_bplist[pos].usage = 1;
505 debug_bplist[pos].temporary = temporary;
506 debug_bplist[pos].funcbp = funcbp;
507
508 /* Add a breakpoint instruction (we use status_nop, as it's just one byte) */
509 machine.memory[address] = 0xbc; /* status_nop, our breakpoint */
510
511 debug_nbps++;
512
513 return 1;
514 }
515
debug_get_breakpoint(int address)516 debug_breakpoint* debug_get_breakpoint(int address)
517 {
518 int top, middle, bottom;
519
520 /* Binary search for the breakpoint (they are stored sorted by address) */
521 top = debug_nbps-1;
522 bottom = 0;
523
524 while (top >= bottom) {
525 middle = (top + bottom) >> 1;
526
527 if (debug_bplist[middle].address > address) {
528 /* Need to search the lower half */
529 top = middle-1;
530 } else if (debug_bplist[middle].address < address) {
531 /* Need to search the upper half */
532 bottom = middle + 1;
533 } else {
534 /* Just right */
535 return debug_bplist + middle;
536 }
537 }
538
539 /*
540 int x;
541
542 for (x=0; x<debug_nbps; x++)
543 {
544 if (debug_bplist[x].address == address)
545 return debug_bplist + x;
546 }
547 */
548
549 return NULL;
550 }
551
debug_clear_breakpoint(debug_breakpoint * bp)552 int debug_clear_breakpoint(debug_breakpoint* bp)
553 {
554 int x;
555
556 x = bp - debug_bplist;
557 if (x < 0 || x >= debug_nbps)
558 return 0;
559
560 bp->usage--;
561 if (bp->temporary > 0)
562 bp->temporary--;
563
564 if (bp->usage <= 0)
565 {
566 machine.memory[bp->address] = bp->original;
567 debug_nbps--;
568 memmove(debug_bplist + x, debug_bplist + x + 1,
569 sizeof(debug_breakpoint)*(debug_nbps-x));
570 return 2;
571 }
572
573 return 1;
574 }
575
576 /*** ----// 888 \\---- ***/
577
578 /* Debug file */
579
580 debug_symbols debug_syms = {
581 0, NULL, NULL, NULL, NULL, 0, NULL, 0,
582 0
583 };
584
debug_add_symbol(char * name,debug_symbol * sym)585 static void debug_add_symbol(char* name,
586 debug_symbol* sym)
587 {
588 int x;
589 char* storename;
590
591 storename = malloc(sizeof(char)*(strlen(name)+1));
592
593 for (x=0; x<strlen(name); x++)
594 {
595 storename[x] = name[x];
596 if (storename[x] >= 'A' && storename[x] <= 'Z')
597 storename[x] += 32;
598 }
599 storename[x] = 0;
600
601 if (hash_get(debug_syms.symbol, (unsigned char*)storename, strlen(name)) != NULL)
602 {
603 display_printf("=? Symbol space clash - %s\n", name);
604 }
605 else
606 debug_syms.nsymbols++;
607 hash_store_happy(debug_syms.symbol,
608 (unsigned char*)storename,
609 strlen(name),
610 sym);
611
612 sym->next = debug_syms.first_symbol;
613 debug_syms.first_symbol = sym;
614
615 free(storename);
616 }
617
618 #ifdef REMOTE_BREAKPOINT
debug_sigusr1(int sig)619 static void debug_sigusr1(int sig) {
620 machine.force_breakpoint = 1;
621 }
622 #endif
623
debug_load_symbols(char * filename,char * pathname)624 void debug_load_symbols(char* filename,
625 char* pathname)
626 {
627 ZFile* file;
628 ZByte* db_file;
629 int size;
630 int pos;
631
632 int done;
633
634 int x;
635
636 debug_routine* this_routine = NULL;
637 debug_symbol* sym;
638
639 #ifdef REMOTE_BREAKPOINT
640 /* SIGUSR1 indicates that we should break ASAP */
641 struct sigaction oldact;
642
643 sigaction(SIGUSR1, NULL, &oldact);
644
645 oldact.sa_flags |= SA_RESTART;
646 oldact.sa_flags &= ~(SA_NODEFER|SA_SIGINFO);
647 oldact.sa_handler = debug_sigusr1;
648
649 sigaction(SIGUSR1, &oldact, NULL);
650 #endif
651
652 size = get_file_size(filename);
653 file = open_file(filename);
654
655 if (file == NULL)
656 {
657 display_printf("=! unable to open file '%s'\n", filename);
658 return;
659 }
660
661 db_file = read_block(file, 0, size);
662
663 close_file(file);
664
665 if (db_file == NULL)
666 return;
667
668 display_printf("= loading symbols from '%s'...\n", filename);
669
670 if (db_file[0] != 0xde || db_file[1] != 0xbf)
671 {
672 display_printf("=! Bad debug file\n");
673 free(db_file);
674 return;
675 }
676
677 debug_syms.largest_object = 0;
678
679 pos = 6;
680
681 done = 0;
682
683 if (debug_syms.symbol == NULL)
684 debug_syms.symbol = hash_create();
685 if (debug_syms.file == NULL)
686 debug_syms.file = hash_create();
687
688 sym = malloc(sizeof(debug_symbol));
689 sym->type = dbg_global;
690 sym->data.global.name = "self";
691 sym->data.global.number = 251-16;
692 debug_add_symbol(sym->data.global.name, sym);
693
694 sym = malloc(sizeof(debug_symbol));
695 sym->type = dbg_global;
696 sym->data.global.name = "sender";
697 sym->data.global.number = 250-16;
698 debug_add_symbol(sym->data.global.name, sym);
699
700 while (pos < size && !done)
701 {
702 switch (db_file[pos])
703 {
704 case DEBUG_EOF_DBR:
705 done = 1;
706 break;
707
708 case DEBUG_FILE_DBR:
709 {
710 debug_file* fl;
711 ZFile* fl_load;
712 ZDWord fl_len;
713
714 char* fn;
715
716 fl = malloc(sizeof(debug_file));
717
718 fl->number = db_file[pos+1];
719 fl->name = malloc(sizeof(char)*(strlen((char*)(db_file + pos + 2)) + 1));
720 strcpy(fl->name, (char*)(db_file + pos + 2));
721 pos += 3 + strlen(fl->name);
722 fl->realname = malloc(sizeof(char)*(strlen((char*)(db_file + pos)) + 1));
723 strcpy(fl->realname, (char*)(db_file + pos));
724 pos += strlen(fl->realname) + 1;
725
726 fl->data = NULL;
727 fl->nlines = 0;
728 fl->line = NULL;
729
730 fn = malloc(sizeof(char)*(strlen(fl->realname)+strlen(pathname)+1));
731 strcpy(fn, fl->realname);
732
733 fl_len = get_file_size(fn);
734 if (fl_len == -1)
735 {
736 strcpy(fn, pathname);
737 strcat(fn, fl->realname);
738 fl_len = get_file_size(fn);
739 }
740 if (fl_len >= 0)
741 {
742 fl_load = open_file(fn);
743 if (fl_load != NULL)
744 {
745 int x;
746
747 fl->data = (char*)read_block(fl_load, 0, fl_len);
748 close_file(fl_load);
749 fl->data = realloc(fl->data, sizeof(char)*(fl_len+2));
750 fl->data[fl_len] = 0;
751
752 fl->nlines++;
753 fl->line = realloc(fl->line, sizeof(char*)*(fl->nlines));
754 fl->line[0] = fl->data;
755
756 for (x=0; x<fl_len; x++)
757 {
758 if (fl->data[x] == 13 || fl->data[x] == 10)
759 {
760 int p;
761
762 p = x;
763
764 if (((fl->data[x+1] == 10 || fl->data[x+1] == 13) &&
765 fl->data[x+1] != fl->data[x]))
766 x++;
767
768 fl->data[p] = 0;
769
770 if (x < fl_len)
771 {
772 fl->nlines++;
773 fl->line = realloc(fl->line,
774 sizeof(char*)*fl->nlines);
775 fl->line[fl->nlines-1] = fl->data + x+1;
776 }
777 }
778 }
779 }
780 }
781 else
782 {
783 display_printf("=? unable to load source file '%s'\n", fl->realname);
784 }
785
786 free(fn);
787
788 debug_syms.nfiles++;
789
790 if (debug_syms.nfiles != fl->number)
791 {
792 display_printf("=! file '%s' doesn't appear in order\n",
793 fl->name);
794 goto failed;
795 }
796
797 debug_syms.files = realloc(debug_syms.files,
798 sizeof(debug_file)*(debug_syms.nfiles+1));
799 debug_syms.files[fl->number] = *fl;
800
801 hash_store_happy(debug_syms.file,
802 (unsigned char*)fl->name,
803 strlen(fl->name),
804 fl);
805 }
806 break;
807
808 case DEBUG_CLASS_DBR:
809 {
810 debug_class c;
811
812 pos++;
813
814 c.name = malloc(sizeof(char)*(strlen(db_file + pos)+1));
815 strcpy(c.name, db_file + pos);
816 pos += strlen(db_file+pos) + 1;
817
818 c.st_fl = db_file[pos++];
819 c.st_ln = db_file[pos++]<<8;
820 c.st_ln |= db_file[pos++];
821 c.st_ch = db_file[pos++];
822
823 c.end_fl = db_file[pos++];
824 c.end_ln = db_file[pos++]<<8;
825 c.end_ln |= db_file[pos++];
826 c.end_ch = db_file[pos++];
827
828 sym = malloc(sizeof(debug_symbol));
829 sym->type = dbg_class;
830 sym->data.class = c;
831 debug_add_symbol(c.name,
832 sym);
833 }
834 break;
835
836 case DEBUG_OBJECT_DBR:
837 {
838 debug_object o;
839
840 pos++;
841
842 o.number = db_file[pos++]<<8;
843 o.number |= db_file[pos++];
844
845 o.name = malloc(sizeof(char)*(strlen(db_file + pos)+1));
846 strcpy(o.name, db_file + pos);
847 pos += strlen(db_file+pos) + 1;
848
849 o.st_fl = db_file[pos++];
850 o.st_ln = db_file[pos++]<<8;
851 o.st_ln |= db_file[pos++];
852 o.st_ch = db_file[pos++];
853
854 o.end_fl = db_file[pos++];
855 o.end_ln = db_file[pos++]<<8;
856 o.end_ln |= db_file[pos++];
857 o.end_ch = db_file[pos++];
858
859 sym = malloc(sizeof(debug_symbol));
860 sym->type = dbg_object;
861 sym->data.object = o;
862 debug_add_symbol(o.name,
863 sym);
864
865 if (o.number > debug_syms.largest_object) debug_syms.largest_object = o.number;
866 }
867 break;
868
869 case DEBUG_GLOBAL_DBR:
870 {
871 debug_global g;
872
873 pos++;
874
875 g.number = db_file[pos++];
876
877 g.name = malloc(sizeof(char)*(strlen(db_file + pos) + 1));
878 strcpy(g.name, db_file + pos);
879 pos += strlen(db_file + pos) + 1;
880
881 sym = malloc(sizeof(debug_symbol));
882 sym->type = dbg_global;
883 sym->data.global = g;
884 debug_add_symbol(g.name,
885 sym);
886 }
887 break;
888
889 case DEBUG_ATTR_DBR:
890 {
891 debug_attr a;
892
893 pos++;
894
895 a.number = db_file[pos++]<<8;
896 a.number |= db_file[pos++];
897
898 a.name = malloc(sizeof(char)*(strlen(db_file + pos) + 1));
899 strcpy(a.name, db_file + pos);
900 pos += strlen(a.name)+1;
901
902 sym = malloc(sizeof(debug_symbol));
903 sym->type = dbg_attr;
904 sym->data.attr = a;
905 debug_add_symbol(a.name,
906 sym);
907 }
908 break;
909
910 case DEBUG_PROP_DBR:
911 {
912 debug_prop p;
913
914 pos++;
915
916 p.number = db_file[pos++]<<8;
917 p.number |= db_file[pos++];
918
919 p.name = malloc(sizeof(char)*(strlen(db_file + pos) + 1));
920 strcpy(p.name, db_file + pos);
921 pos += strlen(p.name)+1;
922
923 sym = malloc(sizeof(debug_symbol));
924 sym->type = dbg_prop;
925 sym->data.prop = p;
926 debug_add_symbol(p.name,
927 sym);
928 }
929 break;
930
931 case DEBUG_ACTION_DBR:
932 {
933 debug_action a;
934
935 pos++;
936
937 a.number = db_file[pos++]<<8;
938 a.number |= db_file[pos++];
939
940 a.name = malloc(sizeof(char)*(strlen(db_file + pos) + 1));
941 strcpy(a.name, db_file + pos);
942 pos += strlen(db_file + pos) + 1;
943
944 sym = malloc(sizeof(debug_symbol));
945 sym->type = dbg_action;
946 sym->data.action = a;
947 /* debug_add_symbol(a.name,
948 sym); */
949 }
950 break;
951
952 case DEBUG_FAKEACT_DBR:
953 {
954 debug_fakeact a;
955
956 pos++;
957
958 a.number = db_file[pos++]<<8;
959 a.number |= db_file[pos++];
960
961 a.name = malloc(sizeof(char)*(strlen(db_file + pos) + 1));
962 strcpy(a.name, db_file + pos);
963 pos += strlen(db_file + pos) + 1;
964
965 sym = malloc(sizeof(debug_symbol));
966 sym->type = dbg_fakeact;
967 sym->data.fakeact = a;
968 /* debug_add_symbol(a.name,
969 sym); */
970 }
971 break;
972
973 case DEBUG_ARRAY_DBR:
974 {
975 debug_array a;
976
977 pos++;
978
979 a.offset = db_file[pos++]<<8;
980 a.offset |= db_file[pos++];
981
982 a.name = malloc(sizeof(char)*(strlen(db_file + pos) + 1));
983 strcpy(a.name, db_file + pos);
984 pos += strlen(db_file + pos) + 1;
985
986 sym = malloc(sizeof(debug_symbol));
987 sym->type = dbg_array;
988 sym->data.array = a;
989 debug_add_symbol(a.name,
990 sym);
991 }
992 break;
993
994 case DEBUG_HEADER_DBR:
995 pos++;
996
997 pos += 64;
998 break;
999
1000 case DEBUG_LINEREF_DBR:
1001 {
1002 debug_line l;
1003 int rno;
1004 int nseq;
1005 int x;
1006
1007 pos++;
1008
1009 rno = db_file[pos++]<<8;
1010 rno |= db_file[pos++];
1011 nseq = db_file[pos++]<<8;
1012 nseq |= db_file[pos++];
1013
1014 if (rno != this_routine->number)
1015 {
1016 display_printf("=! routine number of line does not match current routine\n");
1017 goto failed;
1018 }
1019
1020 for (x=0; x<nseq; x++)
1021 {
1022 l.fl = db_file[pos++];
1023 l.ln = db_file[pos++]<<8;
1024 l.ln |= db_file[pos++];
1025 l.ch = db_file[pos++];
1026
1027 l.address = db_file[pos++]<<8;
1028 l.address |= db_file[pos++];
1029 l.address += this_routine->start;
1030
1031 this_routine->line = realloc(this_routine->line,
1032 sizeof(debug_line)*(this_routine->nlines+1));
1033 this_routine->line[this_routine->nlines] = l;
1034 this_routine->nlines++;
1035 }
1036 }
1037 break;
1038
1039 case DEBUG_ROUTINE_DBR:
1040 {
1041 debug_routine r;
1042
1043 pos++;
1044
1045 r.number = db_file[pos++]<<8;
1046 r.number |= db_file[pos++];
1047 r.defn_fl = db_file[pos++];
1048 r.defn_ln = db_file[pos++]<<8;
1049 r.defn_ln |= db_file[pos++];
1050 r.defn_ch = db_file[pos++];
1051
1052 r.start = db_file[pos++]<<16;
1053 r.start |= db_file[pos++]<<8;
1054 r.start |= db_file[pos++];
1055
1056 r.name = malloc(sizeof(char)*(strlen(db_file+pos) + 1));
1057 strcpy(r.name, db_file + pos);
1058 pos += strlen(r.name)+1;
1059
1060 r.nvars = 0;
1061 r.var = NULL;
1062
1063 while (db_file[pos] != 0)
1064 {
1065 r.var = realloc(r.var, sizeof(char*)*(r.nvars+1));
1066 r.var[r.nvars] = malloc(sizeof(char)*(strlen(db_file+pos) + 1));
1067 strcpy(r.var[r.nvars], db_file+pos);
1068 pos += strlen(r.var[r.nvars]) + 1;
1069 r.nvars++;
1070 }
1071 pos++;
1072
1073 r.nlines = 0;
1074 r.line = NULL;
1075
1076 if (this_routine != NULL &&
1077 this_routine->start >= r.start)
1078 {
1079 display_printf("=! Out of order routines\n");
1080 }
1081
1082 debug_syms.routine = realloc(debug_syms.routine,
1083 sizeof(debug_routine)*
1084 (debug_syms.nroutines+1));
1085
1086 debug_syms.routine[debug_syms.nroutines] = r;
1087 this_routine = debug_syms.routine + debug_syms.nroutines;
1088
1089 debug_syms.nroutines++;
1090
1091 sym = malloc(sizeof(debug_symbol));
1092 sym->type = dbg_routine;
1093 sym->data.routine = debug_syms.nroutines-1;
1094 debug_add_symbol(this_routine->name,
1095 sym);
1096 }
1097 break;
1098
1099 case DEBUG_ROUTINE_END_DBR:
1100 {
1101 int rno;
1102
1103 pos++;
1104
1105 rno = db_file[pos++]<<8;
1106 rno |= db_file[pos++];
1107
1108 if (rno != this_routine->number)
1109 {
1110 display_printf("=! routine number of EOR does not match current routine\n");
1111 goto failed;
1112 }
1113
1114 this_routine->end_fl = db_file[pos++];
1115 this_routine->end_ln = db_file[pos++]<<8;
1116 this_routine->end_ln |= db_file[pos++];
1117 this_routine->end_ch = db_file[pos++];
1118
1119 this_routine->end = db_file[pos++]<<16;
1120 this_routine->end |= db_file[pos++]<<8;
1121 this_routine->end |= db_file[pos++];
1122 }
1123 break;
1124
1125 case DEBUG_MAP_DBR:
1126 {
1127 pos++;
1128
1129 while (db_file[pos] != 0)
1130 {
1131 char* name;
1132 ZDWord address;
1133
1134 name = db_file + pos;
1135 pos += strlen(db_file + pos) + 1;
1136
1137 address = db_file[pos++]<<16;
1138 address |= db_file[pos++]<<8;
1139 address |= db_file[pos++];
1140
1141 /* Fill in various fields according to what we get... */
1142 if (strcmp(name, "code area") == 0)
1143 {
1144 debug_syms.codearea = address;
1145 } else if (strcmp(name, "strings area") == 0) {
1146 debug_syms.stringarea = address;
1147 }
1148 }
1149 pos++;
1150 }
1151 break;
1152
1153 default:
1154 display_printf("=! unknown record type %i\n", db_file[pos]);
1155 goto failed;
1156 return;
1157 }
1158 }
1159
1160 /* Update addresses of routines/lines */
1161 for (x=0; x<debug_syms.nroutines; x++)
1162 {
1163 int y;
1164
1165 debug_syms.routine[x].start += debug_syms.codearea;
1166 debug_syms.routine[x].end += debug_syms.codearea;
1167
1168 for (y=0; y<debug_syms.routine[x].nlines; y++)
1169 {
1170 debug_syms.routine[x].line[y].address += debug_syms.codearea;
1171 }
1172 }
1173
1174 free(db_file);
1175 return;
1176
1177 failed:
1178 free(db_file);
1179 }
1180
1181 /*
1182 * Looks up information about a given (Z-Machine) address - finds routine,
1183 * line information
1184 */
debug_find_address(int address)1185 debug_address debug_find_address(int address)
1186 {
1187 debug_address res;
1188 int x;
1189
1190 res.routine = NULL;
1191 res.line = NULL;
1192 res.line_no = -1;
1193
1194 for (x=0; x<debug_syms.nroutines; x++)
1195 {
1196 if (address > debug_syms.routine[x].start &&
1197 address < debug_syms.routine[x].end)
1198 {
1199 res.routine = debug_syms.routine + x;
1200 break;
1201 }
1202 }
1203
1204 if (res.routine == NULL)
1205 return res;
1206
1207 for (x=0; x<res.routine->nlines; x++)
1208 {
1209 if (res.routine->line[x].address > address)
1210 break;
1211
1212 res.line_no = x;
1213 res.line = res.routine->line + x;
1214 }
1215
1216 return res;
1217 }
1218
1219 /*
1220 * Finds the Z-Machine address of something named by the user
1221 * (eg parserm:3856 for line 3856 of parserm, or InformLibrary.play
1222 * for the start of the InformLibrary.play() routine)
1223 */
debug_find_named_address(const char * name)1224 int debug_find_named_address(const char* name)
1225 {
1226 static char* ourname = NULL;
1227 int x, len;
1228 debug_symbol* sym;
1229
1230 len = strlen(name);
1231 ourname = realloc(ourname, sizeof(char)*(len+1));
1232 strcpy(ourname, name);
1233
1234 /* See if we have a routine... */
1235 for (x=0; x<len; x++)
1236 {
1237 if (ourname[x] >= 'A' && ourname[x] <= 'Z')
1238 {
1239 ourname[x] += 32;
1240 }
1241 }
1242
1243 sym = hash_get(debug_syms.symbol,
1244 ourname,
1245 len);
1246
1247 if (sym != NULL &&
1248 sym->type == dbg_routine)
1249 {
1250 return debug_syms.routine[sym->data.routine].start + 1;
1251 }
1252
1253 /* Files are case-sensitive (usually. Not on Mac OS, bizarrely) */
1254 strcpy(ourname, name);
1255
1256 if (ourname[0] == '#')
1257 {
1258 int adr;
1259
1260 adr = 0;
1261
1262 /* PC value */
1263 for (x=1; x<len; x++)
1264 {
1265 adr <<= 4;
1266 if (ourname[x] >= '0' && ourname[x] <= '9')
1267 adr += ourname[x] - '0';
1268 else if (ourname[x] >= 'A' && ourname[x] <= 'F')
1269 adr += ourname[x] - 'A' + 10;
1270 else if (ourname[x] >= 'a' && ourname[x] <= 'f')
1271 adr += ourname[x] - 'a' + 10;
1272 else
1273 break;
1274 }
1275
1276 if (x == len && adr >= 0 && adr < machine.story_length)
1277 return adr;
1278 }
1279
1280 for (x=len-1;
1281 x>0 && (ourname[x] >= '0' && ourname[x] <= '9');
1282 x--);
1283
1284 if (ourname[x] == ':')
1285 {
1286 debug_file* fl;
1287 int line_no;
1288
1289 ourname[x] = 0;
1290
1291 line_no = atoi(ourname + x + 1);
1292
1293 fl = hash_get(debug_syms.file,
1294 ourname,
1295 strlen(ourname));
1296
1297 if (fl != NULL)
1298 {
1299 for (x=0; x<debug_syms.nroutines; x++)
1300 {
1301 if ((debug_syms.routine[x].defn_fl == fl->number &&
1302 debug_syms.routine[x].end_fl == fl->number) &&
1303 debug_syms.routine[x].defn_ln <= line_no &&
1304 debug_syms.routine[x].end_ln >= line_no)
1305 {
1306 int y;
1307 debug_routine* r;
1308 int found_line = 0;
1309
1310 r = debug_syms.routine + x;
1311
1312 for (y=0; y<r->nlines; y++)
1313 {
1314 found_line = y;
1315
1316 if (r->line[y].ln >= line_no)
1317 break;
1318 }
1319
1320 return r->line[found_line].address;
1321 }
1322 }
1323 }
1324 }
1325
1326 return -1;
1327 }
1328
debug_address_string(debug_address addr,int pc,int format)1329 char* debug_address_string(debug_address addr, int pc, int format)
1330 {
1331 static char* res = NULL;
1332 char num[10];
1333 int len;
1334
1335 len = 0;
1336 res = realloc(res, sizeof(char));
1337 res[0] = 0;
1338
1339 if (addr.routine != NULL &&
1340 addr.line != NULL)
1341 {
1342 if (format == 1)
1343 {
1344 len += strlen(addr.routine->name)+5;
1345 res = realloc(res, sizeof(char)*(len+1));
1346 strcat(res, addr.routine->name);
1347 strcat(res, "() (");
1348 }
1349
1350 if (addr.routine->defn_fl > 0 && addr.routine->defn_fl != 255)
1351 {
1352 len += strlen(debug_syms.files[addr.routine->defn_fl].name)+1;
1353 res = realloc(res, sizeof(char)*(len+1));
1354 strcat(res, debug_syms.files[addr.routine->defn_fl].name);
1355 strcat(res, ":");
1356 }
1357
1358 sprintf(num, "%i", addr.line->ln);
1359
1360 len += strlen(num);
1361 res = realloc(res, sizeof(char)*(len+1));
1362 strcat(res, num);
1363
1364 if (format == 1)
1365 strcat(res, ")");
1366 else
1367 {
1368 len += strlen(addr.routine->name)+3;
1369 res = realloc(res, sizeof(char)*(len+1));
1370 strcat(res, " (");
1371 strcat(res, addr.routine->name);
1372 strcat(res, ")");
1373 }
1374 }
1375 else if (addr.routine != NULL)
1376 {
1377 len += strlen(addr.routine->name)+1;
1378 res = realloc(res, sizeof(char)*(len+1));
1379 strcat(res, addr.routine->name);
1380 strcat(res, ":");
1381
1382 sprintf(num, "#%05x", pc);
1383 len += strlen(num);
1384 res = realloc(res, sizeof(char)*(len+1));
1385 strcat(res, num);
1386 }
1387 else
1388 {
1389 if (format == 1)
1390 {
1391 len += 4;
1392 res = realloc(res, sizeof(char)*(len+1));
1393 strcat(res, "??? ");
1394 }
1395
1396 sprintf(num, "#%05x", pc);
1397 len += strlen(num);
1398 res = realloc(res, sizeof(char)*(len+1));
1399 strcat(res, num);
1400 }
1401
1402 return res;
1403 }
1404
debug_symbol_value(const char * symbol,debug_routine * r)1405 ZWord debug_symbol_value(const char* symbol,
1406 debug_routine* r)
1407 {
1408 static char* sym = NULL;
1409 debug_symbol* res;
1410 int x, len;
1411
1412 len = strlen(symbol);
1413 sym = realloc(sym, sizeof(char)*(len+1));
1414 for (x=0; x<len; x++)
1415 {
1416 if (symbol[x] >= 'A' && symbol[x] <= 'Z')
1417 sym[x] = symbol[x] + 32;
1418 else
1419 sym[x] = symbol[x];
1420 }
1421 sym[len] = 0;
1422
1423 if (r != NULL)
1424 {
1425 for (x=0; x<r->nvars; x++)
1426 {
1427 if (strcmp(r->var[x], symbol) == 0)
1428 {
1429 return machine.stack.current_frame->local[x+1];
1430 }
1431 }
1432 }
1433
1434 res = hash_get(debug_syms.symbol,
1435 sym,
1436 len);
1437
1438 if (res != NULL)
1439 {
1440 switch (res->type)
1441 {
1442 case dbg_class:
1443 return -1;
1444
1445 case dbg_object:
1446 return res->data.object.number;
1447
1448 case dbg_global:
1449 return machine.globals[res->data.global.number<<1]<<8 |
1450 machine.globals[(res->data.global.number<<1)+1];
1451
1452 case dbg_attr:
1453 return -1;
1454
1455 case dbg_prop:
1456 return res->data.prop.number;
1457
1458 case dbg_array:
1459 return GetWord(machine.header, ZH_globals) + res->data.array.offset;
1460
1461 default:
1462 break;
1463 }
1464 }
1465
1466 debug_error = "Symbol not found";
1467 return 0;
1468 }
1469
1470 /* Expression evaluation */
debug_eval_error(const char * erm)1471 void debug_eval_error(const char* erm)
1472 {
1473 debug_error = erm;
1474 }
1475
debug_eval_lex(void)1476 int debug_eval_lex(void)
1477 {
1478 int start;
1479
1480 if (debug_expr[debug_expr_pos] == 0)
1481 return 0;
1482
1483 while (debug_expr[debug_expr_pos] == ' ')
1484 debug_expr_pos++;
1485
1486 start = debug_expr_pos;
1487
1488 if ((debug_expr[debug_expr_pos] >= 'A' && debug_expr[debug_expr_pos] <= 'Z') ||
1489 (debug_expr[debug_expr_pos] >= 'a' && debug_expr[debug_expr_pos] <= 'z'))
1490 {
1491 int x;
1492
1493 /* IDENTIFIER */
1494 while ((debug_expr[debug_expr_pos] >= 'A' && debug_expr[debug_expr_pos] <= 'Z') ||
1495 (debug_expr[debug_expr_pos] >= 'a' && debug_expr[debug_expr_pos] <= 'z') ||
1496 (debug_expr[debug_expr_pos] >= '0' && debug_expr[debug_expr_pos] <= '9') ||
1497 debug_expr[debug_expr_pos] == '_')
1498 {
1499 debug_expr_pos++;
1500 }
1501
1502 yylval.str = malloc(sizeof(char)*(debug_expr_pos-start+1));
1503 for (x=start; x<debug_expr_pos; x++)
1504 {
1505 yylval.str[x-start] = debug_expr[x];
1506 }
1507 yylval.str[debug_expr_pos-start] = 0;
1508
1509 return IDENTIFIER;
1510 }
1511
1512 if (debug_expr[debug_expr_pos] >= '0' && debug_expr[debug_expr_pos] <= '9')
1513 {
1514 /* NUMBER */
1515 yylval.number = 0;
1516
1517 while (debug_expr[debug_expr_pos] >= '0' && debug_expr[debug_expr_pos] <= '9')
1518 {
1519 yylval.number *= 10;
1520 yylval.number += debug_expr[debug_expr_pos] - '0';
1521 debug_expr_pos++;
1522 }
1523 return NUMBER;
1524 }
1525
1526 if (debug_expr[debug_expr_pos] == '$')
1527 {
1528 /* NUMBER */
1529 yylval.number = 0;
1530 debug_expr_pos++;
1531
1532 while ((debug_expr[debug_expr_pos] >= '0' && debug_expr[debug_expr_pos] <= '9') ||
1533 (debug_expr[debug_expr_pos] >= 'A' && debug_expr[debug_expr_pos] <= 'F') ||
1534 (debug_expr[debug_expr_pos] >= 'a' && debug_expr[debug_expr_pos] <= 'f'))
1535 {
1536 yylval.number *= 16;
1537 if (debug_expr[debug_expr_pos] >= '0' && debug_expr[debug_expr_pos] <= '9')
1538 yylval.number += debug_expr[debug_expr_pos] - '0';
1539 else if (debug_expr[debug_expr_pos] >= 'A' && debug_expr[debug_expr_pos] <= 'F')
1540 yylval.number += debug_expr[debug_expr_pos] - 'A' + 10;
1541 else if (debug_expr[debug_expr_pos] >= 'a' && debug_expr[debug_expr_pos] <= 'f')
1542 yylval.number += debug_expr[debug_expr_pos] - 'a' + 10;
1543
1544 debug_expr_pos++;
1545 }
1546
1547 return NUMBER;
1548 }
1549
1550 if (debug_expr[debug_expr_pos] == '-')
1551 {
1552 if (debug_expr[debug_expr_pos+1] == '>')
1553 {
1554 debug_expr_pos+=2;
1555 return BYTEARRAY;
1556 }
1557 if (debug_expr[debug_expr_pos+1] == '-' && debug_expr[debug_expr_pos+2] == '>')
1558 {
1559 debug_expr_pos += 3;
1560 return WORDARRAY;
1561 }
1562 }
1563
1564 if (debug_expr[debug_expr_pos] == '.')
1565 {
1566 if (debug_expr[debug_expr_pos+1] == '&')
1567 {
1568 debug_expr_pos+=2;
1569 return PROPADDR;
1570 }
1571 if (debug_expr[debug_expr_pos+1] == '#')
1572 {
1573 debug_expr_pos+=2;
1574 return PROPLEN;
1575 }
1576 }
1577
1578 debug_expr_pos++;
1579 if (debug_expr[debug_expr_pos-1] < 256)
1580 return debug_expr[debug_expr_pos-1];
1581 return '?';
1582 }
1583
debug_print_value(ZWord value,char * type)1584 char* debug_print_value(ZWord value, char* type)
1585 {
1586 static char res[256];
1587
1588 if (type == NULL)
1589 type = "signed";
1590
1591 if (strcmp(type, "unsigned") == 0)
1592 {
1593 sprintf(res, "%u", value);
1594 }
1595 if (strcmp(type, "hex") == 0)
1596 {
1597 sprintf(res, "$%x\n", value);
1598 }
1599 else
1600 {
1601 sprintf(res, "%i", value);
1602 }
1603
1604 return res;
1605 }
1606
debug_set_bp_handler(debug_breakpoint_handler handler)1607 void debug_set_bp_handler(debug_breakpoint_handler handler) {
1608 static int initialised = 0;
1609 int x;
1610
1611 bp_handler = handler;
1612
1613 if (!initialised) {
1614 initialised = 1;
1615
1616 for (x=0; x<debug_syms.nroutines; x++) {
1617 debug_set_breakpoint(debug_syms.routine[x].start+1,
1618 0, 1);
1619 }
1620 }
1621 }
1622
debug_set_temp_breakpoints(debug_step_type step)1623 void debug_set_temp_breakpoints(debug_step_type step) {
1624 int ln;
1625 ZFrame* frame;
1626
1627 if (addr.routine != NULL) {
1628 ln = addr.line_no;
1629 if (ln != -1) {
1630 ln++;
1631 }
1632
1633 if (ln >= addr.routine->nlines) {
1634 ln = -1;
1635 }
1636
1637 if (step == debug_step_into) {
1638 stepinto = 1;
1639 }
1640
1641 /* Set a breakpoint on each line... */
1642 if (step != debug_step_out) {
1643 for (ln = 0; ln < addr.routine->nlines; ln++) {
1644 debug_set_breakpoint(addr.routine->line[ln].address, 1, 0);
1645 }
1646 }
1647 }
1648
1649 /* Set a breakpoint on the return location of this function */
1650 if (machine.stack.current_frame) {
1651 for (frame = machine.stack.current_frame->last_frame; frame != NULL; frame = frame->last_frame) {
1652 frame->break_on_return = 1;
1653 }
1654 }
1655 }
1656