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