1 /* Nitfol - z-machine interpreter using Glk for output.
2 Copyright (C) 1999 Evin Robertson
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
18 The author can be reached at nitfol@deja.com
26 #define debug_object(o, t)
27 #define debug_attrib(a, o)
31 typedef enum { CONT_GO, CONT_STEP, CONT_NEXT, CONT_FINISH, CONT_UNTIL, CONT_STEPI, CONT_NEXTI } Cont_type;
36 BOOL enter_debugger = FALSE;
40 BOOL exit_debugger = FALSE;
45 int infix_selected_frame;
47 static Cont_type debug_cont = CONT_GO;
48 static int step_count = 0;
50 typedef enum { bp_none, bp_break, bp_write_watch, bp_read_watch, bp_access_watch } bptype;
52 typedef enum { del, del_at_next_stop, disable, donttouch } bpdisp;
54 typedef struct breakpoint breakpoint;
66 int break_frame; /* If not -1, only break at this depth */
72 unsigned ignore_count; /* Don't break until 0 */
76 char *watch_expression;
77 int watch_frame; /* Frame at which to evaluate watch; -1 if no locals */
82 static breakpoint *breaklist;
83 static int breaknumber = 1;
86 void set_step(Cont_type t, int count)
92 do_check_watches = TRUE;
93 if(debug_cont == CONT_GO && breaklist == NULL)
94 do_check_watches = FALSE;
98 int infix_set_break(offset location)
102 infix_location cur_location;
105 infix_print_string("No code at that location.\n");
109 newbreak.number = breaknumber++;
110 newbreak.enabled = TRUE;
111 newbreak.type = bp_break;
112 newbreak.disposition = donttouch;
113 newbreak.PC = location;
114 newbreak.break_frame = -1;
115 newbreak.hit_count = 0;
116 newbreak.ignore_count = 0;
117 newbreak.condition = NULL;
119 LEadd(breaklist, newbreak);
121 infix_print_string("Breakpoint ");
122 infix_print_number(newbreak.number);
123 infix_print_string(" at ");
124 infix_print_number(location);
126 if(infix_decode_PC(&cur_location, location)) {
127 infix_print_string(": file ");
128 infix_print_string(cur_location.file->filename);
129 infix_print_string(", line ");
130 infix_print_number(cur_location.line_num);
132 infix_print_string(".\n");
134 do_check_watches = TRUE;
135 return newbreak.number;
138 static breakpoint *find_breakpoint(int breaknum)
141 LEsearch(breaklist, p, p->number == breaknum);
146 infix_print_string("No breakpoint number ");
147 infix_print_number(breaknum);
148 infix_print_string(".\n");
153 void infix_delete_breakpoint(int breaknum)
156 LEsearchremove(breaklist, p, t, p->number == breaknum, n_free(p->condition));
159 void infix_set_cond(int breaknum, const char *condition)
161 breakpoint *p = find_breakpoint(breaknum);
165 n_free(p->condition);
167 p->condition = n_strdup(condition);
171 void infix_set_ignore(int breaknum, int count)
173 breakpoint *p = find_breakpoint(breaknum);
176 p->ignore_count = count;
179 void infix_set_break_enabled(int breaknum, BOOL enabled)
181 breakpoint *p = find_breakpoint(breaknum);
184 p->enabled = enabled;
187 static void infix_show_break(breakpoint *b)
189 infix_print_number(b->number);
190 infix_print_char(' ');
191 infix_print_string("breakpoint");
192 infix_print_char(' ');
193 infix_print_string("keep");
194 infix_print_char(' ');
196 infix_print_char('y');
198 infix_print_char('n');
199 infix_print_offset(b->PC);
200 infix_print_char(' ');
201 infix_gprint_loc(0, b->PC);
202 infix_print_char('\n');
205 void infix_show_all_breakpoints(void)
209 infix_print_string("No breakpoints or watchpoints.\n");
211 for(p = breaklist; p; p=p->next)
216 void infix_show_breakpoint(int breaknum)
218 breakpoint *p = find_breakpoint(breaknum);
222 infix_print_string("No such breakpoint or watchpoint.\n");
227 typedef struct auto_display auto_display;
229 struct auto_display {
238 static auto_display *displist;
239 static int dispnumber = 1;
241 int infix_auto_display(const char *expression)
243 auto_display newdisp;
244 newdisp.number = dispnumber++;
245 newdisp.enabled = TRUE;
246 newdisp.exp = n_strdup(expression);
248 LEadd(displist, newdisp);
250 return newdisp.number;
253 void perform_displays(void)
256 for(p = displist; p; p=p->next) {
258 infix_print_number(p->number);
259 infix_print_string(": ");
260 infix_print_string(p->exp);
261 infix_print_string(" = ");
262 infix_display(evaluate_expression(p->exp, infix_selected_frame));
268 static auto_display *find_auto_display(int displaynum)
271 LEsearch(displist, p, p->number == displaynum);
276 infix_print_string("No auto-display number ");
277 infix_print_number(displaynum);
278 infix_print_string(".\n");
283 void infix_auto_undisplay(int displaynum)
286 LEsearchremove(displist, p, t, p->number == displaynum, n_free(p->exp));
290 void infix_set_display_enabled(int displaynum, BOOL enabled)
292 auto_display *p = find_auto_display(displaynum);
295 p->enabled = enabled;
299 const char *debug_decode_number(unsigned number)
306 name = infix_get_name(val);
310 name = infix_get_name(val);
314 name = infix_get_name(val);
320 unsigned opcode_counters[OFFSET_END];
323 void check_watches(void)
325 /* This function is called after every instruction, and infix_decode_PC is
326 relatively expensive, so only get it when we need it */
327 infix_location cur_location;
328 BOOL found_location = FALSE;
330 BOOL is_breakpoint = FALSE;
338 if(!infix_decode_PC(&cur_location, oldPC))
340 found_location = TRUE;
341 if(cur_file != cur_location.file || cur_line != cur_location.line_num)
350 depth = stack_get_depth();
351 if(depth < cur_stack_depth) {
353 } else if(cur_stack_depth == depth) {
354 if(!infix_decode_PC(&cur_location, oldPC))
356 found_location = TRUE;
358 if(cur_file != cur_location.file || cur_line != cur_location.line_num)
364 depth = stack_get_depth();
365 if(depth <= cur_stack_depth)
370 depth = stack_get_depth();
371 if(depth < cur_stack_depth)
376 depth = stack_get_depth();
377 if(depth < cur_stack_depth) {
379 } else if(cur_stack_depth == depth) {
380 if(!infix_decode_PC(&cur_location, oldPC))
382 found_location = TRUE;
384 if(cur_file != cur_location.file || cur_line > cur_location.line_num)
393 if(go_debug && step_count && --step_count)
396 for(p = breaklist; p; p=p->next) {
398 BOOL break_hit = FALSE;
405 break_hit = p->PC == oldPC;
409 case bp_access_watch:
415 if(p->ignore_count) {
420 foo = evaluate_expression(p->condition, infix_selected_frame);
421 if(!p->condition || foo.v) {
422 is_breakpoint = TRUE;
427 infix_print_string("Breakpoint ");
428 infix_print_number(p->number);
429 infix_print_string(", ");
431 switch(p->disposition) {
433 infix_delete_breakpoint(p->number);
440 case del_at_next_stop:
451 if(go_debug || enter_debugger) {
452 depth = stack_get_depth();
454 enter_debugger = FALSE;
457 found_location = infix_decode_PC(&cur_location, oldPC);
460 cur_file = cur_location.file;
461 cur_line = cur_location.line_num;
467 if(is_breakpoint || cur_stack_depth != depth) {
468 infix_gprint_loc(depth, 0);
470 infix_file_print_line(cur_file, cur_line);
473 infix_selected_frame = cur_stack_depth = depth;
475 for(p = breaklist; p; p=p->next) {
476 if(p->disposition == del_at_next_stop)
477 infix_delete_breakpoint(p->number);
487 void debug_prompt(void)
490 exit_debugger = FALSE;
492 while(!exit_debugger) {
494 infix_print_string(db_prompt);
496 infix_print_string("(nitfol) ");
497 infix_get_string(buffer, 512);
498 process_debug_command(buffer);
502 void infix_select_frame(int num)
504 if(frame_is_valid(num))
505 infix_selected_frame = num;
508 void infix_show_frame(int frame)
510 infix_print_char('#');
511 infix_print_number(frame);
512 infix_print_string(" ");
513 infix_gprint_loc(frame, 0);
516 void infix_backtrace(int start, int length)
519 for(n = start + length - 1; n >= start; n--) {
526 const char *watchnames[] = {
535 void debug_object(zword objectnum, watchinfo type)
537 /*n_show_debug(E_OBJECT, watchnames[type], objectnum);*/
540 void debug_attrib(zword attribnum, zword objectnum)
542 /*n_show_debug(E_OBJECT, "using attribute", attribnum);*/