1 /*
2  * debug.c - gawk debugger
3  */
4 
5 /*
6  * Copyright (C) 2004, 2010-2013, 2016-2021 the Free Software Foundation, Inc.
7  *
8  * This file is part of GAWK, the GNU implementation of the
9  * AWK Programming Language.
10  *
11  * GAWK is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * GAWK is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
24  */
25 
26 #include "awk.h"
27 #include "cmd.h"
28 
29 #ifndef O_RDONLY
30 #include <fcntl.h>	/* open() */
31 #endif
32 
33 #ifdef __MINGW32__
34 #define execvp(p,a) w32_execvp(p,a)
35 int w32_execvp(const char *, char **);
36 #endif
37 
38 extern bool exiting;
39 extern SRCFILE *srcfiles;
40 extern INSTRUCTION *rule_list;
41 extern INSTRUCTION *code_block;
42 extern NODE **fcall_list;
43 extern long fcall_count;
44 extern FILE *output_fp;
45 extern IOBUF *curfile;
46 extern const char *command_file;
47 extern const char *get_spec_varname(Func_ptr fptr);
48 extern int zzparse(void);
49 #define read_command()		(void) zzparse()
50 
51 extern const char *redir2str(int redirtype);
52 
53 static char *linebuf = NULL;	/* used to print a single line of source */
54 static size_t linebuf_len;
55 
56 FILE *out_fp;
57 const char *dbg_prompt;
58 const char *commands_prompt = "> ";	/* breakpoint or watchpoint commands list */
59 const char *eval_prompt = "@> ";	/* awk statement(s) */
60 
61 bool input_from_tty = false;
62 int input_fd;
63 
64 static SRCFILE *cur_srcfile;
65 static long cur_frame = 0;
66 static INSTRUCTION *cur_pc;
67 int cur_rule = 0;
68 
69 static bool prog_running = false;
70 
71 struct condition {
72 	INSTRUCTION *code;
73 	AWK_CONTEXT *ctxt;
74 	char *expr;
75 };
76 
77 struct commands_item {
78 	struct commands_item *next;
79 	struct commands_item *prev;
80 	int cmd;
81 	char *cmd_string;
82 	CMDARG *arg;
83 };
84 
85 /* breakpoint structure */
86 typedef struct break_point {
87 	struct break_point *next;
88 	struct break_point *prev;
89 	int number;
90 
91 	long ignore_count;
92 	long hit_count;
93 	char *src;
94 	INSTRUCTION *bpi;	/* Op_breakpoint */
95 
96 	struct commands_item commands;  /* list of commands to run */
97 	bool silent;
98 
99 	struct condition cndn;
100 
101 	short flags;
102 #define BP_ENABLE       1
103 #define BP_ENABLE_ONCE  2		/* enable once */
104 #define BP_TEMP         4
105 #define BP_IGNORE       8
106 
107 } BREAKPOINT;
108 
109 static BREAKPOINT breakpoints = { &breakpoints, &breakpoints, 0 };
110 
111 #ifdef HAVE_LIBREADLINE
112 /* do_save -- save command */
113 static int sess_history_base = 0;
114 #endif
115 
116 #ifndef HAVE_HISTORY_LIST
117 #define HIST_ENTRY void
118 #define history_list()	NULL
119 #endif
120 
121 
122 /* 'list' command */
123 static int last_printed_line = 0;
124 static int last_print_count;	/* # of lines printed */
125 
126 /* watch or display item */
127 struct list_item {
128 	struct list_item *next;
129 	struct list_item *prev;
130 	int number;     /* item number */
131 
132 	NODE *symbol;   /* variable or function param */
133 	NODE **subs;    /* subscripts */
134 	int num_subs;	/* subscript(dimension) count */
135 	char *sname;	/* symbol or param name */
136 
137 	long fcall_count;
138 
139 	struct commands_item commands;
140 	int silent;
141 	struct condition cndn;
142 
143 	/* This is for the value of the watched item */
144 	union {
145 		NODE *n;
146 		long l;
147 	} value[2];
148 #define cur_value value[0].n
149 #define cur_size  value[0].l
150 #define old_value value[1].n
151 #define old_size  value[1].l
152 
153 	int flags;
154 #define PARAM           1
155 #define SUBSCRIPT       2
156 #define FIELD_NUM       4
157 #define OLD_IS_ARRAY    8    /* old item is array */
158 #define CUR_IS_ARRAY    16   /* current item is array */
159 };
160 
161 #define IS_PARAM(d)	(((d)->flags & PARAM) != 0)
162 #define IS_SUBSCRIPT(d)	(((d)->flags & SUBSCRIPT) != 0)
163 #define IS_FIELD(d)	(((d)->flags & FIELD_NUM) != 0)
164 #define WATCHING_ARRAY(d)	(((d)->flags & CUR_IS_ARRAY) != 0)
165 
166 static struct list_item display_list = { &display_list, &display_list, 0 };
167 static struct list_item watch_list = { &watch_list, &watch_list, 0 };
168 
169 
170 /* Structure to maintain data for processing debugger commands */
171 
172 static struct {
173 	long fcall_count;    /* 'finish', 'until', 'next', 'step', 'nexti' commands */
174 	int sourceline;      /* source line number last
175 	                      * time we stopped execution,
176 	                      * used by next, until and step commands
177 	                      */
178 	char *source;        /* next, until and step */
179 
180 	INSTRUCTION *pc;     /* 'until' and 'return' commands */
181 	int repeat_count;    /* 'step', 'next', 'stepi', 'nexti' commands */
182 	bool print_frame;    /* print frame info,  'finish' and 'until' */
183 	bool print_ret;      /* print returned value, 'finish' */
184 	int break_point;     /* non-zero (breakpoint number) if stopped at break point */
185 	int watch_point;     /* non-zero (watchpoint number) if stopped at watch point */
186 
187 	int (*check_func)(INSTRUCTION **);      /* function to decide when to suspend
188 	                                         * awk interpreter and return control
189 	                                         * to debugger command interpreter.
190 	                                         */
191 
192 	enum argtype command;		 /* command type */
193 } stop;
194 
195 
196 /* restart related stuff */
197 extern char **d_argv;	/* copy of argv array */
198 static bool need_restart = false;
199 enum { BREAK=1, WATCH, DISPLAY, HISTORY, OPTION };
200 static const char *const env_variable[] = {
201 	"",
202 	"DGAWK_BREAK",
203 	"DGAWK_WATCH",
204 	"DGAWK_DISPLAY",
205 	"DGAWK_HISTORY",
206 	"DGAWK_OPTION",
207 };
208 static void serialize_list(int type);
209 static void unserialize_list(int type);
210 static const char *commands_string = NULL;
211 static int commands_string_len = 0;
212 static char line_sep;
213 #define FSEP	(char)'\037'
214 #define RSEP	(char)'\036'
215 #define CSEP	(char)'\035'
216 
217 
218 /* debugger option */
219 struct dbg_option {
220 	const char *name;
221 	int *num_val;
222 	const char **str_val;
223 	void (*assign)(const char *);
224 	const char *help_txt;
225 };
226 
227 #define DEFAULT_HISTFILE	"./.gawk_history"
228 #define DEFAULT_OPTFILE		"./.gawkrc"
229 #define DEFAULT_PROMPT		"gawk> "
230 #define DEFAULT_LISTSIZE	15
231 #define DEFAULT_HISTSIZE	100
232 
233 static void set_gawk_output(const char *file);
234 static void set_prompt(const char *value);
235 static void set_listsize(const char *value);
236 static void set_trace(const char *value);
237 static void set_save_history(const char *value);
238 static void set_save_options(const char *value);
239 static void set_history_size(const char *value);
240 static const char *options_file = DEFAULT_OPTFILE;
241 #ifdef HAVE_LIBREADLINE
242 static const char *history_file = DEFAULT_HISTFILE;
243 #endif
244 
245 /* debugger option related variables */
246 
247 static const char *output_file = "/dev/stdout";  /* gawk output redirection */
248 const char *dgawk_prompt = NULL;                 /* initialized in interpret */
249 static int list_size = DEFAULT_LISTSIZE;   /* # of lines that 'list' prints */
250 static int do_trace = false;
251 static int do_save_history = true;
252 static int do_save_options = true;
253 static int history_size = DEFAULT_HISTSIZE;  /* max # of lines in history file */
254 
255 static const struct dbg_option option_list[] = {
256 {"history_size", &history_size, NULL, &set_history_size,
257 	gettext_noop("set or show the number of lines to keep in history file") },
258 {"listsize", &list_size, NULL, &set_listsize,
259 	gettext_noop("set or show the list command window size") },
260 {"outfile", NULL, &output_file, &set_gawk_output,
261 	gettext_noop("set or show gawk output file") },
262 {"prompt", NULL, &dgawk_prompt, &set_prompt,
263 	gettext_noop("set or show debugger prompt"), },
264 {"save_history", &do_save_history, NULL, &set_save_history,
265 	gettext_noop("(un)set or show saving of command history (value=on|off)") },
266 {"save_options", &do_save_options, NULL, &set_save_options,
267 	gettext_noop("(un)set or show saving of options (value=on|off)") },
268 {"trace", &do_trace, NULL, &set_trace,
269 	gettext_noop("(un)set or show instruction tracing (value=on|off)") },
270 {0, NULL, NULL, NULL, 0},
271 };
272 
273 static void save_options(const char *file);
274 
275 
276 /* pager */
277 jmp_buf pager_quit_tag;
278 int pager_quit_tag_valid = 0;
279 static int screen_width = INT_MAX;	/* no of columns */
280 static int screen_height = INT_MAX;	/* no of rows */
281 static int pager_lines_printed = 0;	/* no of lines printed so far */
282 
283 static void restart(bool run) ATTRIBUTE_NORETURN;
284 static void close_all(void);
285 static int open_readfd(const char *file);
286 static int find_lines(SRCFILE *s);
287 static SRCFILE *source_find(char *src);
288 static int print_lines(char *src, int start_line, int nlines);
289 static void print_symbol(NODE *r, bool isparam);
290 static NODE *find_frame(long num);
291 static NODE *find_param(const char *name, long num, char **pname);
292 static NODE *find_symbol(const char *name, char **pname);
293 static NODE *find_array(const char *name);
294 static void print_field(long field_num);
295 static int print_function(INSTRUCTION *pc, void *);
296 static void print_frame(NODE *func, char *src, int srcline);
297 static void print_numbered_frame(long num);
298 static void print_cur_frame_and_sourceline(void);
299 static INSTRUCTION *find_rule(char *src, long lineno);
300 static INSTRUCTION *mk_breakpoint(char *src, int srcline);
301 static int execute_commands(struct commands_item *commands);
302 static void delete_commands_item(struct commands_item *c);
303 static NODE *execute_code(volatile INSTRUCTION *code);
304 static int pre_execute_code(INSTRUCTION **pi);
305 static int parse_condition(int type, int num, char *expr);
306 static BREAKPOINT *add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent);
307 static BREAKPOINT *set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip);
308 static BREAKPOINT *set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent);
309 static void delete_breakpoint(BREAKPOINT *b);
310 static BREAKPOINT *find_breakpoint(long num);
311 static void display(struct list_item *d);
312 static struct list_item *find_item(struct list_item *list, long num);
313 static struct list_item *add_item(struct list_item *list, int type, NODE *symbol, char *pname);
314 static void delete_item(struct list_item *d);
315 static int breakpoint_triggered(BREAKPOINT *b);
316 static int watchpoint_triggered(struct list_item *w);
317 static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump);
318 static void print_ns_list(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump);
319 static int print_code(INSTRUCTION *pc, void *x);
320 static void next_command();
321 static void debug_post_execute(INSTRUCTION *pc);
322 static int debug_pre_execute(INSTRUCTION **pi);
323 static char *g_readline(const char *prompt);
324 static int prompt_yes_no(const char *, char , int , FILE *);
325 static struct pf_data {
326 	Func_print print_func;
327 	bool defn;
328 	FILE *fp;
329 } pf_data;
330 
331 char * (*read_a_line)(const char *) = 0;	/* reads a line of input */
332 
333 struct command_source
334 {
335 	int fd;
336 	int is_tty;
337 	char * (*read_func)(const char *);
338 	int (*close_func)(int);
339 	int eof_status;		/* see push_cmd_src */
340 	int cmd;		/* D_source or 0 */
341 	char *str;		/* sourced file */
342 	struct command_source *next;
343 };
344 
345 static struct command_source *cmd_src = NULL;
346 
347 #define PUSH_BINDING(stack, tag, val)	\
348 if (val++) \
349 	memcpy((char *) (stack), (const char *) tag, sizeof(jmp_buf))
350 #define POP_BINDING(stack, tag, val)	\
351 if (--val) \
352 	memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf))
353 
354 
355 #define CHECK_PROG_RUNNING() \
356 	do { \
357 		if (! prog_running) { \
358 			d_error(_("program not running")); \
359 			return false; \
360 		} \
361 	} while (false)
362 
363 // On z/OS, one needs to use %#p to get the leading 0x in the output.
364 // Having that makes it consistent with Linux and makes the use of
365 // helper scripts easier.
366 #ifdef USE_EBCDIC
367 #define PTRFMT	"%#p"
368 #else
369 #define PTRFMT	"%p"
370 #endif
371 
372 
373 /* g_readline --  read a line of text; the interface is like 'readline' but
374  *		without	any command-line editing; used when not compiled with
375  *		readline support and/or input is not from terminal (prompt set to NULL).
376  */
377 
378 static char *
g_readline(const char * prompt)379 g_readline(const char *prompt)
380 {
381 	char *line;
382 	size_t line_size = 100;
383 	static char buf[2];
384 	char *p, *end;
385 	int n;
386 
387 	if (input_from_tty && prompt && *prompt)
388 		fprintf(out_fp, "%s", prompt);
389 
390 	emalloc(line, char *, line_size + 1, "g_readline");
391 	p = line;
392 	end = line + line_size;
393 	while ((n = read(input_fd, buf, 1)) > 0) {
394 		if (buf[0] == '\n') {
395 			if (p > line && p[-1] == '\r')
396 				p--;
397 			break;
398 		}
399 		if (p == end) {
400 			erealloc(line, char *, 2 * line_size + 1, "g_readline");
401 			p = line + line_size;
402 			line_size *= 2;
403 			end = line + line_size;
404 		}
405 		*p++ = buf[0];
406 	}
407 	if (n == -1 || (n == 0 && p == line)) {
408 		efree(line);
409 		return NULL;
410 	}
411 	*p = '\0';
412 	return line;
413 }
414 
415 
416 /* d_error --- print an error message */
417 
418 void
d_error(const char * mesg,...)419 d_error(const char *mesg, ...)
420 {
421 	va_list args;
422 	va_start(args, mesg);
423 	fprintf(out_fp, _("error: "));
424 	vfprintf(out_fp, mesg, args);
425 	fprintf(out_fp, "\n");
426 	va_end(args);
427 }
428 
429 /* find_lines --- find the positions of the lines in the source file. */
430 
431 static int
find_lines(SRCFILE * s)432 find_lines(SRCFILE *s)
433 {
434 	char *buf, *p, *end;
435 	int n;
436 	int ofs = 0;
437 	int *pos;
438 	int pos_size;
439 	int maxlen = 0;
440 	int numlines = 0;
441 	char lastchar = '\0';
442 
443 	emalloc(buf, char *, s->bufsize, "find_lines");
444 	pos_size = s->srclines;
445 	emalloc(s->line_offset, int *, (pos_size + 2) * sizeof(int), "find_lines");
446 	pos = s->line_offset;
447 	pos[0] = 0;
448 
449 	while ((n = read(s->fd, buf, s->bufsize)) > 0) {
450 		end = buf + n;
451 		lastchar = buf[n - 1];
452 		p = buf;
453 		while (p < end) {
454 			if (*p++ == '\n') {
455 				if (++numlines > pos_size) {
456 					erealloc(s->line_offset, int *, (2 * pos_size + 2) * sizeof(int), "find_lines");
457 					pos = s->line_offset + pos_size;
458 					pos_size *= 2;
459 				}
460 				*++pos = ofs + (p - buf);
461 				if ((pos[0] - pos[-1]) > maxlen)
462 					maxlen = pos[0] - pos[-1];	/* length including NEWLINE */
463 			}
464 		}
465 		ofs += n;
466 	}
467 	efree(buf);
468 
469 	if (n == -1) {
470 		d_error(_("cannot read source file `%s': %s"),
471 					s->src, strerror(errno));
472 		return -1;
473 	}
474 	if (ofs <= 0) {
475 		fprintf(out_fp, _("source file `%s' is empty.\n"), s->src);
476 		return -1;
477 	}
478 
479 	if (lastchar != '\n') {
480 		/* fake a NEWLINE at end */
481 		*++pos = ofs + 1;
482 		numlines++;
483 		if ((pos[0] - pos[-1]) > maxlen)
484 			maxlen = pos[0] - pos[-1];
485 	}
486 	s->maxlen = maxlen;
487 	s->srclines = numlines;
488 	return 0;
489 }
490 
491 /* source_find --- return the SRCFILE struct for the source 'src' */
492 
493 static SRCFILE *
source_find(char * src)494 source_find(char *src)
495 {
496 	SRCFILE *s;
497 	struct stat sbuf;
498 	char *path;
499 	int errno_val = 0;
500 
501 	if (src == NULL || *src == '\0') {
502 		d_error(_("no current source file"));
503 		return NULL;
504 	}
505 
506 	if (cur_srcfile->src == src)  /* strcmp(cur_srcfile->src, src) == 0 */
507 		return cur_srcfile;
508 
509 	for (s = srcfiles->next; s != srcfiles; s = s->next) {
510 		if ((s->stype == SRC_FILE || s->stype == SRC_INC)
511 				&& strcmp(s->src, src) == 0)
512 			return s;
513 	}
514 
515 	path = find_source(src, & sbuf, & errno_val, false);
516 	if (path != NULL) {
517 		for (s = srcfiles->next; s != srcfiles; s = s->next) {
518 			if ((s->stype == SRC_FILE || s->stype == SRC_INC)
519 			    		&& files_are_same(path, s)) {
520 				efree(path);
521 				return s;
522 			}
523 		}
524 		efree(path);
525 	}
526 
527 	d_error(_("cannot find source file named `%s': %s"), src, strerror(errno_val));
528 	return NULL;
529 }
530 
531 /* print_lines --- print source lines, and update 'cur_srcfile' */
532 
533 static int
print_lines(char * src,int start_line,int nlines)534 print_lines(char *src, int start_line, int nlines)
535 {
536 	SRCFILE *s;
537 	int *pos;
538 	int i;
539 	struct stat sbuf;
540 
541 	s = source_find(src);
542 	if (s == NULL)
543 		return -1;
544 	if (s->fd <= INVALID_HANDLE && (s->fd = srcopen(s)) <= INVALID_HANDLE) {
545 		d_error(_("cannot open source file `%s' for reading: %s"),
546 				src, strerror(errno));
547 		return -1;
548 	}
549 
550 	if (fstat(s->fd, &sbuf) == 0 && s->mtime < sbuf.st_mtime) {
551 		fprintf(out_fp, _("warning: source file `%s' modified since program compilation.\n"),
552 				src);
553 		efree(s->line_offset);
554 		s->line_offset = NULL;
555 		s->mtime = sbuf.st_mtime;
556 
557 		/* reopen source file */
558 		close(s->fd);
559 		s->fd = INVALID_HANDLE;
560 		if ((s->fd = srcopen(s)) <= INVALID_HANDLE) {
561 			d_error(_("cannot open source file `%s' for reading: %s"),
562 					src, strerror(errno));
563 			return -1;
564 		}
565 	}
566 
567 	/* set binary mode so that byte offset calculations will be right */
568 	os_setbinmode(s->fd, O_BINARY);
569 
570 	if (s->line_offset == NULL && find_lines(s) != 0)
571 		return -1;
572   	if (start_line < 1 || start_line > s->srclines) {
573 		d_error(_("line number %d out of range; `%s' has %d lines"),
574 					start_line, src, s->srclines);
575 		return -1;
576 	}
577 
578 	assert(nlines > 0);
579 	if ((start_line + nlines - 1) > s->srclines)
580 		nlines = s->srclines - start_line + 1;
581 
582 	pos = s->line_offset;
583 	if (lseek(s->fd, (off_t) pos[start_line - 1], SEEK_SET) < 0) {
584 		d_error("%s: %s", src, strerror(errno));
585 		return -1;
586 	}
587 
588 	if (linebuf == NULL) {
589 		emalloc(linebuf, char *, s->maxlen + 20, "print_lines"); /* 19 for line # */
590 		linebuf_len = s->maxlen;
591 	} else if (linebuf_len < s->maxlen) {
592 		erealloc(linebuf, char *, s->maxlen + 20, "print_lines");
593 		linebuf_len = s->maxlen;
594 	}
595 
596 	for (i = start_line; i < start_line + nlines; i++) {
597 		int supposed_len, len;
598 		char *p;
599 
600 		sprintf(linebuf, "%-8d", i);
601 
602 		/* mark the line about to be executed with =>; nlines > 1
603 	 	 * condition makes sure that we are in list command
604 		 */
605 		if (nlines > 1) {
606 			BREAKPOINT *b;
607 			bool has_bpt = false;
608 			for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
609 				if (src == b->src && i == b->bpi->source_line) {
610 					has_bpt = true;
611 					break;
612 				}
613 			}
614 			if (prog_running && src == source && i == sourceline) {
615 				if (has_bpt)
616 					sprintf(linebuf, "%-4d:b=>", i);
617 				else
618 					sprintf(linebuf, "%-4d  =>", i);
619 			} else if (has_bpt)
620 				sprintf(linebuf, "%-4d:b  ", i);
621 		}
622 
623 		p = linebuf + strlen(linebuf);
624 		supposed_len = pos[i] - pos[i - 1];
625 		len = read(s->fd, p, supposed_len);
626 		switch (len) {
627 		case -1:
628 			d_error(_("cannot read source file `%s': %s"),
629 						src, strerror(errno));
630 			return -1;
631 
632 		case 0:
633 			d_error(_("unexpected eof while reading file `%s', line %d"),
634 						src, i);
635 			return -1;
636 
637 		default:
638 			if (i == s->srclines && p[len - 1] != '\n')
639 				p[len++] = '\n';
640 #if 0
641 			if (len != supposed_len || p[len - 1] != '\n') {
642 				d_error(_("source file `%s' modified since start of program execution"),
643 						src);
644 				return -1;
645 			}
646 #endif
647 			len += (p - linebuf);
648 			if (fwrite(linebuf, sizeof(char), len, out_fp) != len)
649 				return -1;
650 		}
651 	}
652 
653 	if (cur_srcfile != s) {
654 		if (cur_srcfile->fd != INVALID_HANDLE) {
655 			close(cur_srcfile->fd);
656 			cur_srcfile->fd = INVALID_HANDLE;
657 		}
658 		cur_srcfile = s;
659 	}
660 	return (i - 1);		/* no of lines printed */
661 }
662 
663 /* do_list --- list command */
664 
665 int
do_list(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)666 do_list(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
667 {
668 	long line_first, line_last;
669 	long count = list_size;
670 	INSTRUCTION *rp;
671 	char *src = cur_srcfile->src;
672 
673 	line_first = last_printed_line + 1;		/* default or no arg */
674 	if (arg == NULL)	/* list or list + */
675 		goto list;
676 
677 	switch (arg->type) {
678 	case D_int:		/* list n or list - */
679 		if (arg->a_int < 0) {		/* list - */
680 			line_first = last_printed_line - last_print_count - list_size + 1;
681 			if (line_first < 1) {
682 				if (last_printed_line != last_print_count)
683 					line_first = 1;
684 				else
685 					return false;
686 			}
687 		} else {
688 line:
689 			line_first = arg->a_int - list_size / 2;
690 			if (line_first < 1)
691 				line_first = 1;
692 		}
693 		break;
694 
695 	case D_range:	/* list m-n */
696 range:
697 		line_first = arg->a_int;
698 		arg = arg->next;
699 		assert(arg != NULL);
700 		assert(arg->type == D_int);
701 		count = arg->a_int - line_first + 1;
702 		break;
703 
704 	case D_string:
705 		src = arg->a_string;
706 		if (arg->next != NULL) {
707 			arg = arg->next;
708 			if (arg->type == D_int)	/* list file:n */
709 				goto line;
710 			else if (arg->type == D_range)	/* list file:m-n */
711 				goto range;
712 			else if (arg->type == D_func)	/* list file:function */
713 				goto func;
714 			else
715 				line_first = 1;
716 		} else
717 			line_first = 1;
718 		break;
719 
720 	case D_func:	/* list function */
721 func:
722 		rp = arg->a_node->code_ptr;
723 		src = rp->source_file;
724 		line_first = rp->source_line - list_size / 2;
725 		if (line_first < 1)
726 			line_first = 1;
727 		break;
728 
729 	default:
730 		break;
731  	}
732 
733 list:
734 	line_last = print_lines(src, line_first, count);
735 	if (line_last != -1) {
736 		last_printed_line = line_last;
737 		last_print_count = line_last - line_first + 1;
738 	}
739 	return false;
740 }
741 
742 /* do_info --- info command */
743 
744 int
do_info(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)745 do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
746 {
747 	NODE **table;
748 
749 	if (arg == NULL || arg->type != D_argument)
750 		return false;
751 
752 	switch (arg->a_argument) {
753 	case A_SOURCE:
754 		fprintf(out_fp, _("Current source file: %s\n"), cur_srcfile->src);
755 		fprintf(out_fp, _("Number of lines: %d\n"), cur_srcfile->srclines);
756 		break;
757 
758 	case A_SOURCES:
759 	{
760 		SRCFILE *s;
761 		for (s = srcfiles->next; s != srcfiles; s = s->next) {
762 			fprintf(out_fp, _("Source file (lines): %s (%d)\n"),
763 					(s->stype == SRC_FILE || s->stype == SRC_INC) ? s->src
764 			 		                                      : "cmd. line",
765 					s->srclines);
766 		}
767 	}
768 		break;
769 
770 	case A_BREAK:
771 		initialize_pager(out_fp);
772 		if (setjmp(pager_quit_tag) == 0) {
773 			BREAKPOINT *b;
774 			struct commands_item *c;
775 
776 			gprintf(out_fp, _("Number  Disp  Enabled  Location\n\n"));
777 			for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
778 				const char *disp = "keep";
779 				if ((b->flags & BP_ENABLE_ONCE) != 0)
780 					disp = "dis";
781 				else if ((b->flags & BP_TEMP) != 0)
782 					disp = "del";
783 				gprintf(out_fp, "%-6d  %-4.4s  %-7.7s  file %s, line #%d\n",
784 						b->number, disp, (b->flags & BP_ENABLE) != 0 ? "yes" : "no",
785 					 	b->src,	b->bpi->source_line);
786 				if (b->hit_count > 0)
787 					gprintf(out_fp, _("\tnumber of hits = %ld\n"), b->hit_count);
788 				if ((b->flags & BP_IGNORE) != 0)
789 					gprintf(out_fp, _("\tignore next %ld hit(s)\n"), b->ignore_count);
790 				if (b->cndn.code != NULL)
791 					gprintf(out_fp, _("\tstop condition: %s\n"), b->cndn.expr);
792 				if (b->commands.next != &b->commands)
793 					gprintf(out_fp, _("\tcommands:\n"));
794 				for (c = b->commands.next; c != &b->commands; c = c->next) {
795 					gprintf(out_fp, "\t%s\n", c->cmd_string);
796 					if (c->cmd == D_eval) {
797 						char *start, *end;
798 						CMDARG *a = c->arg;
799 						start = strchr(a->a_string, '{');
800 						end = strrchr(a->a_string, '}');
801 						if (start == NULL || end == NULL)
802 							continue;
803 						start++;
804 						*end = '\0';
805 						gprintf(out_fp, "%s", start);	/* FIXME: translate ? */
806 						*end = '}';
807 					}
808 				}
809 			}
810 		}
811 		break;
812 
813 	case A_FRAME:
814 		CHECK_PROG_RUNNING();
815 		fprintf(out_fp, _("Current frame: "));
816 		print_numbered_frame(cur_frame);
817 		if (cur_frame < fcall_count) {
818 			fprintf(out_fp, _("Called by frame: "));
819 			print_numbered_frame(cur_frame + 1);
820 		}
821 		if (cur_frame > 0) {
822 			fprintf(out_fp, _("Caller of frame: "));
823 			print_numbered_frame(cur_frame - 1);
824 		}
825 		break;
826 
827 	case A_ARGS:
828 	case A_LOCALS:
829 	{
830 		NODE *f, *func;
831 		INSTRUCTION *pc;
832 		int arg_count, pcount;
833 		int i, from, to;
834 
835 		CHECK_PROG_RUNNING();
836 		f = find_frame(cur_frame);
837 		func = f->func_node;
838 		if (func == NULL) {
839 			/* print ARGV ? */
840 			fprintf(out_fp, _("None in main().\n"));
841 			return false;
842 		}
843 
844 		pcount = func->param_cnt;              /* # of defined params */
845 
846 		pc = (INSTRUCTION *) f->reti;          /* Op_func_call instruction */
847 		arg_count = (pc + 1)->expr_count;      /* # of arguments supplied */
848 
849 		if (arg_count > pcount)                /* extra args */
850 			arg_count = pcount;
851 		if (arg->a_argument == A_ARGS) {
852 			from = 0;
853 			to = arg_count - 1;
854 		} else {
855 			from = arg_count;
856 			to = pcount - 1;
857 		}
858 
859 		for (i = from; i <= to; i++) {
860 			NODE *r;
861 			r = f->stack[i];
862 			if (r->type == Node_array_ref)
863 				r = r->orig_array;
864 			fprintf(out_fp, "%s = ", func->fparms[i].param);
865 			print_symbol(r, true);
866 		}
867 		if (to < from)
868 			fprintf(out_fp, "%s",
869 				arg->a_argument == A_ARGS ?
870 					_("No arguments.\n") :
871 					_("No locals.\n"));
872 	}
873 		break;
874 
875 	case A_VARIABLES:
876 		table = variable_list();
877 		initialize_pager(out_fp);
878 		if (setjmp(pager_quit_tag) == 0) {
879 			gprintf(out_fp, _("All defined variables:\n\n"));
880 			print_vars(table, gprintf, out_fp);
881 		}
882 		efree(table);
883 		break;
884 
885 	case A_FUNCTIONS:
886 		table = function_list(true);
887 		initialize_pager(out_fp);
888 		if (setjmp(pager_quit_tag) == 0) {
889 			gprintf(out_fp, _("All defined functions:\n\n"));
890 			pf_data.print_func = gprintf;
891 			pf_data.fp = out_fp;
892 			pf_data.defn = true;
893 			(void) foreach_func(table,
894 			            (int (*)(INSTRUCTION *, void *)) print_function,
895 			            &pf_data);
896 		}
897 		efree(table);
898 		break;
899 
900 	case A_DISPLAY:
901 	case A_WATCH:
902 		initialize_pager(out_fp);
903 		if (setjmp(pager_quit_tag) == 0) {
904 			struct list_item *d, *list;
905 
906 			if (arg->a_argument == A_DISPLAY) {
907 				list = &display_list;
908 				gprintf(out_fp, _("Auto-display variables:\n\n"));
909 			} else {
910 				list = &watch_list;
911 				gprintf(out_fp, _("Watch variables:\n\n"));
912 			}
913 			for (d = list->prev; d != list; d = d->prev) {
914 				int i;
915 				struct commands_item *c;
916 				NODE *symbol = d->symbol;
917 
918 				if (IS_SUBSCRIPT(d)) {
919 					gprintf(out_fp, "%d:\t%s",  d->number, d->sname);
920 					for (i = 0; i < d->num_subs; i++) {
921 						NODE *sub;
922 						sub = d->subs[i];
923 						gprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
924 					}
925 					gprintf(out_fp, "\n");
926 				} else if (IS_FIELD(d))
927 					gprintf(out_fp, "%d:\t$%ld\n", d->number, get_number_si(symbol));
928 				else
929 					gprintf(out_fp, "%d:\t%s\n", d->number, d->sname);
930 				if (d->cndn.code != NULL)
931 					gprintf(out_fp, _("\tstop condition: %s\n"), d->cndn.expr);
932 				if (d->commands.next != &d->commands)
933 					gprintf(out_fp, _("\tcommands:\n"));
934 				for (c = d->commands.next; c != &d->commands; c = c->next) {
935 					gprintf(out_fp, "\t%s\n", c->cmd_string);
936 					if (c->cmd == D_eval) {
937 						char *start, *end;
938 						CMDARG *a = c->arg;
939 						start = strchr(a->a_string, '{');
940 						end = strrchr(a->a_string, '}');
941 						if (start == NULL || end == NULL)
942 							continue;
943 						start++;
944 						*end = '\0';
945 						gprintf(out_fp, "%s", start);	/* FIXME: translate ? */
946 						*end = '}';
947 					}
948 				}
949 
950 			}
951 		}
952 		break;
953 
954 	default:
955 		break;
956 	}
957 
958 	return false;
959 }
960 
961 /* print_symbol --- print a symbol table entry */
962 
963 static void
print_symbol(NODE * r,bool isparam)964 print_symbol(NODE *r, bool isparam)
965 {
966 	switch (r->type) {
967 	case Node_var_new:
968 		fprintf(out_fp, "untyped variable\n");
969 		break;
970 	case Node_var:
971 		if (! isparam && r->var_update)
972 			r->var_update();
973 		valinfo(r->var_value, fprintf, out_fp);
974 		break;
975 	case Node_var_array:
976 		fprintf(out_fp, "array, %ld elements\n", (long) assoc_length(r));
977 		break;
978 	case Node_func:
979 		fprintf(out_fp, "`function'\n");
980 		break;
981 	default:
982 		break;
983 	}
984 }
985 
986 /* find_frame --- find frame given a frame number */
987 
988 static NODE *
find_frame(long num)989 find_frame(long num)
990 {
991 	assert(num >= 0);
992 	if (num == 0)
993 		return frame_ptr;
994 
995 	assert(prog_running == true);
996 	assert(num <= fcall_count);
997 	assert(fcall_list[num] != NULL);
998 	return fcall_list[num];
999 }
1000 
1001 /* find_param --- find a function parameter in a given frame number */
1002 
1003 static NODE *
find_param(const char * name,long num,char ** pname)1004 find_param(const char *name, long num, char **pname)
1005 {
1006 	NODE *r = NULL;
1007 	NODE *f;
1008 	char *fparam;
1009 
1010 	if (pname)
1011 		*pname = NULL;
1012 
1013 	if (num < 0 || num > fcall_count || name == NULL)
1014 		return NULL;
1015 	f = find_frame(num);
1016 	if (f->func_node != NULL) {		/* in function */
1017 		NODE *func;
1018 		int i, pcount;
1019 
1020 		func = f->func_node;
1021 		pcount = func->param_cnt;
1022 		for (i = 0; i < pcount; i++) {
1023 			fparam = func->fparms[i].param;
1024 			if (strcmp(name, fparam) == 0) {
1025 				r = f->stack[i];
1026 				if (r->type == Node_array_ref)
1027 					r = r->orig_array;
1028 				if (pname)
1029 					*pname = fparam;
1030 				break;
1031 			}
1032 		}
1033 	}
1034 	return r;
1035 }
1036 
1037 /* find_symbol --- find a symbol in current context */
1038 
1039 static
find_symbol(const char * name,char ** pname)1040 NODE *find_symbol(const char *name, char **pname)
1041 {
1042 	NODE *r = NULL;
1043 
1044 	if (pname)
1045 		*pname = NULL;
1046 	if (prog_running)
1047 		r = find_param(name, cur_frame, pname);
1048 	if (r == NULL)
1049 		r = lookup(name); // for now, require fully qualified name
1050 	if (r == NULL)
1051 		fprintf(out_fp, _("no symbol `%s' in current context\n"), name);
1052 	return r;
1053 }
1054 
1055 /* find_array -- find an array in current context */
1056 
1057 static NODE *
find_array(const char * name)1058 find_array(const char *name)
1059 {
1060 	NODE *r;
1061 	r = find_symbol(name, NULL);
1062 	if (r != NULL && r->type != Node_var_array) {
1063 		fprintf(out_fp, _("`%s' is not an array\n"), name);
1064 		return NULL;
1065 	}
1066 	return r;
1067 }
1068 
1069 /* print_field --- print the value of $n */
1070 
1071 static void
print_field(long field_num)1072 print_field(long field_num)
1073 {
1074 	NODE **lhs;
1075 	lhs = get_field(field_num, NULL);
1076 	if (*lhs == Null_field || *lhs == Nnull_string)
1077 		fprintf(out_fp, _("$%ld = uninitialized field\n"), field_num);
1078 	else {
1079 		fprintf(out_fp, "$%ld = ", field_num);
1080 		valinfo(*lhs, fprintf, out_fp);
1081 	}
1082 }
1083 
1084 /* print_array --- print the contents of an array */
1085 
1086 static int
print_array(volatile NODE * arr,char * arr_name)1087 print_array(volatile NODE *arr, char *arr_name)
1088 {
1089 	NODE *subs;
1090 	NODE **list;
1091 	int i;
1092 	size_t num_elems = 0;
1093 	volatile NODE *r;
1094 	volatile int ret = 0;
1095 	volatile jmp_buf pager_quit_tag_stack;
1096 
1097 	if (assoc_empty((NODE *) arr)) {
1098 		gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
1099 		return 0;
1100 	}
1101 
1102 	num_elems = assoc_length((NODE *) arr);
1103 
1104 	/* sort indices, sub_arrays are also sorted! */
1105 	list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN);
1106 
1107 	PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1108 	if (setjmp(pager_quit_tag) == 0) {
1109 		for (i = 0; ret == 0 && i < num_elems; i++) {
1110 			subs = list[i];
1111 			r = *assoc_lookup((NODE *) arr, subs);
1112 			if (r->type == Node_var_array)
1113 				ret = print_array(r, r->vname);
1114 			else {
1115 				gprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr);
1116 				valinfo((NODE *) r, gprintf, out_fp);
1117 			}
1118 		}
1119 	} else
1120 		ret = 1;
1121 
1122 	POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1123 
1124 	for (i = 0; i < num_elems; i++)
1125 		unref(list[i]);
1126 	efree(list);
1127 
1128 	return ret;
1129 }
1130 
1131 /* print_subscript --- print an array element */
1132 
1133 static void
print_subscript(NODE * arr,char * arr_name,CMDARG * a,int count)1134 print_subscript(NODE *arr, char *arr_name, CMDARG *a, int count)
1135 {
1136 	NODE *r, *subs;
1137 
1138 	subs = a->a_node;
1139 	r = in_array(arr, subs);
1140 	if (r == NULL)
1141 		fprintf(out_fp, _("subscript \"%.*s\" is not in array `%s'\n"), (int) subs->stlen, subs->stptr, arr_name);
1142 	else if (r->type == Node_var_array) {
1143 		if (count > 1)
1144 			print_subscript(r, r->vname, a->next, count - 1);
1145 		else {
1146 			/* print # of elements in array */
1147 			fprintf(out_fp, "%s = ", r->vname);
1148 			print_symbol(r, false);
1149 		}
1150 	} else {
1151 		fprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr);
1152 		valinfo(r, fprintf, out_fp);
1153 	}
1154 }
1155 
1156 /* do_print_var --- print command */
1157 
1158 int
do_print_var(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1159 do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1160 {
1161 	NODE *r;
1162 	CMDARG *a;
1163 	char *name, *pname;
1164 
1165 	for (a = arg; a != NULL; a = a->next) {
1166 		switch (a->type) {
1167 		case D_variable:
1168 			name = a->a_string;
1169 			if ((r = find_symbol(name, &pname)) != NULL) {
1170 				fprintf(out_fp, "%s = ", name);
1171 				print_symbol(r, (pname != NULL));
1172 			}
1173 			break;
1174 
1175 		case D_subscript:
1176 			assert(a->a_count > 0);
1177 			name = a->a_string;
1178 			r = find_array(name);
1179 			if (r != NULL)
1180 				print_subscript(r, name, a->next, a->a_count);
1181 			break;
1182 
1183 		case D_array:
1184 			name = a->a_string;
1185 			if ((r = find_array(name)) != NULL) {
1186 				int count = a->a_count;
1187 				for (; count > 0; count--) {
1188 					NODE *value, *subs;
1189 					a = a->next;
1190 					subs = a->a_node;
1191 					value = in_array(r, subs);
1192 					if (value == NULL) {
1193 						fprintf(out_fp, _("subscript \"%.*s\" is not in array `%s'\n"),
1194 									(int) subs->stlen, subs->stptr, name);
1195 						break;
1196 					} else if (value->type != Node_var_array) {
1197 						fprintf(out_fp, _("`%s[\"%.*s\"]' is not an array\n"),
1198 									name, (int) subs->stlen, subs->stptr);
1199 						break;
1200 					} else {
1201 						r = value;
1202 						name = r->vname;
1203 					}
1204 				}
1205 				if (count == 0) {
1206 					initialize_pager(out_fp);
1207 					print_array((volatile NODE *) r, name);
1208 				}
1209 			}
1210 			break;
1211 
1212 		case D_field:
1213 			print_field(get_number_si(a->a_node));
1214 			break;
1215 
1216 		default:
1217 			/* notably D_node, subscript for invalid array name; skip */
1218 			break;
1219 		}
1220 	}
1221 	return false;
1222 }
1223 
1224 /* do_set_var --- set command */
1225 
1226 int
do_set_var(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1227 do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1228 {
1229 	NODE *r, *val;
1230 	NODE **lhs;
1231 	char *name, *pname;
1232 
1233 	switch (arg->type) {
1234 	case D_variable:
1235 		name = arg->a_string;
1236 		arg = arg->next;
1237 		val = arg->a_node;
1238 
1239 		if ((r = find_symbol(name, &pname)) == NULL)
1240 			break;
1241 
1242 		switch (r->type) {
1243 		case Node_var_new:
1244 			r->type = Node_var;
1245 			r->var_value = dupnode(Nnull_string);
1246 			/* fall through */
1247 		case Node_var:
1248 			lhs = &r->var_value;
1249 			unref(*lhs);
1250 			*lhs = dupnode(val);
1251 			if (pname == NULL && r->var_assign != NULL)
1252 				r->var_assign();
1253 			fprintf(out_fp, "%s = ", name);
1254 			print_symbol(r, (pname != NULL));
1255 			break;
1256 
1257 		default:
1258 			d_error(_("`%s' is not a scalar variable"), name);
1259 			break;
1260 		}
1261 		break;
1262 
1263 	case D_subscript:
1264 	{
1265 		NODE *subs, *value;
1266 		int count = arg->a_count;
1267 		NODE *newval;
1268 
1269 		assert(count > 0);
1270 		name = arg->a_string;
1271 		r = find_array(name);
1272 		if (r == NULL)
1273 			break;
1274 		for (; count > 0; count--) {
1275 			arg = arg->next;
1276 			subs = arg->a_node;
1277 			value = in_array(r, subs);
1278 
1279 			if (count == 1) {
1280 				if (value != NULL && value->type == Node_var_array)
1281 					d_error(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
1282 								name, (int) subs->stlen, subs->stptr);
1283 				else {
1284 					arg = arg->next;
1285 					val = arg->a_node;
1286 					newval = dupnode(val);
1287 					// subs should not be freed, so
1288 					// use dupnode in call to assoc_set.
1289 					assoc_set(r, dupnode(subs), newval);
1290 					fprintf(out_fp, "%s[\"%.*s\"] = ", name, (int) subs->stlen, subs->stptr);
1291 					valinfo(newval, fprintf, out_fp);
1292 				}
1293 			} else {
1294 				if (value == NULL) {
1295 					NODE *array;
1296 					array = make_array();
1297 					array->vname = estrdup(subs->stptr, subs->stlen);
1298 					array->parent_array = r;
1299 					// subs should not be freed, so
1300 					// use dupnode in call to assoc_set.
1301 					assoc_set(r, dupnode(subs), array);
1302 					r = array;
1303 				} else if (value->type != Node_var_array) {
1304 					d_error(_("attempt to use scalar `%s[\"%.*s\"]' as array"),
1305 							name, (int) subs->stlen, subs->stptr);
1306 					break;
1307 				} else {
1308 					r = value;
1309 					name = r->vname;
1310 				}
1311 			}
1312 		}
1313 	}
1314 		break;
1315 
1316 	case D_field:
1317 	{
1318 		long field_num;
1319 		Func_ptr assign = NULL;
1320 
1321 		field_num = get_number_si(arg->a_node);
1322 		assert(field_num >= 0);
1323 		arg = arg->next;
1324 		val = arg->a_node;
1325 		lhs = get_field(field_num, &assign);
1326 		if (assign)
1327 			/* call assign to copy fields before unref frees $0 */
1328 			assign();
1329 		unref(*lhs);
1330 		*lhs = dupnode(val);
1331 		print_field(field_num);
1332 	}
1333 		break;
1334 
1335 	default:
1336 		break;
1337 	}
1338 	return false;
1339 }
1340 
1341 /* find_item --- find an item in the watch/display list */
1342 
1343 static struct list_item *
find_item(struct list_item * list,long num)1344 find_item(struct list_item *list, long num)
1345 {
1346 	struct list_item *d;
1347 
1348 	if (num <= 0)
1349 		return NULL;
1350 	for (d = list->next; d != list; d = d->next) {
1351 		if (d->number == num)
1352 			return d;
1353 	}
1354 	return NULL;
1355 }
1356 
1357 /* delete_item --- delete an item from the watch/display list */
1358 
1359 static void
delete_item(struct list_item * d)1360 delete_item(struct list_item *d)
1361 {
1362 	struct commands_item *c;
1363 	int i;
1364 
1365 	if (IS_SUBSCRIPT(d)) {
1366 		for (i = 0; i < d->num_subs; i++)
1367 			unref(d->subs[i]);
1368 		efree(d->subs);
1369 	} else if (IS_FIELD(d))
1370 		unref(d->symbol);
1371 
1372 	if ((d->flags & CUR_IS_ARRAY) == 0)
1373 		unref(d->cur_value);
1374 	if ((d->flags & OLD_IS_ARRAY) == 0)
1375 		unref(d->old_value);
1376 
1377 	/* delete commands */
1378 	for (c = d->commands.next; c != &d->commands; c = c->next) {
1379 		c = c->prev;
1380 		delete_commands_item(c->next);
1381 	}
1382 
1383 	free_context(d->cndn.ctxt, false);
1384 	if (d->cndn.expr != NULL)
1385 		efree(d->cndn.expr);
1386 
1387 	d->next->prev = d->prev;
1388 	d->prev->next = d->next;
1389 	efree(d);
1390 }
1391 
1392 /* add_item --- craete a watch/display item and add it to the list */
1393 
1394 static struct list_item *
add_item(struct list_item * list,int type,NODE * symbol,char * pname)1395 add_item(struct list_item *list, int type, NODE *symbol, char *pname)
1396 {
1397 	struct list_item *d;
1398 
1399 	ezalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
1400 	d->commands.next = d->commands.prev = &d->commands;
1401 
1402 	d->number = ++list->number;
1403 	d->sname = symbol->vname;
1404 	if (pname != NULL) {	/* function param */
1405 		d->sname = pname;
1406 		d->flags |= PARAM;
1407 		d->fcall_count = fcall_count - cur_frame;
1408 	}
1409 
1410 	if (type == D_field) {
1411 		/* field number */
1412 		d->symbol = symbol;
1413 		d->flags |= FIELD_NUM;
1414 	} else if (type == D_subscript) {
1415 		/* subscript */
1416 		d->symbol = symbol;
1417 		d->flags |= SUBSCRIPT;
1418 	} else {
1419 		/* array or variable */
1420 		d->symbol = symbol;
1421 	}
1422 
1423 	/* add to list */
1424 	d->next = list->next;
1425 	d->prev = list;
1426 	list->next = d;
1427 	d->next->prev = d;
1428 	return d;
1429 }
1430 
1431 /* do_add_item --- add an item to the watch/display list */
1432 
1433 static struct list_item *
do_add_item(struct list_item * list,CMDARG * arg)1434 do_add_item(struct list_item *list, CMDARG *arg)
1435 {
1436 	NODE *symbol = NULL;
1437 	char *name, *pname = NULL;
1438 	struct list_item *item = NULL;
1439 
1440 	switch (arg->type) {
1441 	case D_subscript:
1442 	case D_variable:
1443 		name = arg->a_string;
1444 		if ((symbol = find_symbol(name, &pname)) == NULL)
1445 			return NULL;
1446 		if (symbol->type == Node_func) {
1447 			d_error(_("`%s' is a function"), name);
1448 			return NULL;
1449 		}
1450 		if (arg->type == D_subscript && symbol->type != Node_var_array) {
1451 			d_error(_("`%s' is not an array\n"), name);
1452 			return NULL;
1453 		}
1454 
1455 		item = add_item(list, arg->type, symbol, pname);
1456 		if (item != NULL && arg->type == D_subscript) {
1457 			NODE **subs;
1458 			int count = arg->a_count;
1459 			int i;
1460 
1461 			assert(count > 0);
1462 			emalloc(subs, NODE **, count * sizeof(NODE *), "do_add_item");
1463 			for (i = 0; i < count; i++) {
1464 				arg = arg->next;
1465 				subs[i] = dupnode(arg->a_node);
1466 				subs[i] = force_string(subs[i]);
1467 			}
1468 			item->subs = subs;
1469 			item->num_subs = count;
1470 		}
1471 		break;
1472 
1473 	case D_field:
1474 		symbol = dupnode(arg->a_node);
1475 		item = add_item(list, D_field, symbol, NULL);
1476 		break;
1477 
1478 	default:
1479 		break;
1480 	}
1481 
1482 	/* watch condition if any */
1483 	if (list == &watch_list) {
1484 		arg = arg->next;
1485 		if (item != NULL && arg != NULL) {
1486 			if (parse_condition(D_watch, item->number, arg->a_string) == 0)
1487 				arg->a_string = NULL;	/* don't let free_cmdarg free it */
1488 			else
1489 				fprintf(out_fp, _("watchpoint %d is unconditional\n"), item->number);
1490 		}
1491 	}
1492 	return item;
1493 }
1494 
1495 /* do_delete_item --- delete a watch/display item from list. */
1496 
1497 static void
do_delete_item(struct list_item * list,CMDARG * arg)1498 do_delete_item(struct list_item *list, CMDARG *arg)
1499 {
1500 	if (arg == NULL) {
1501 		while (list->next != list)
1502 			delete_item(list->next);
1503 	}
1504 
1505 	for (; arg != NULL; arg = arg->next) {
1506 		struct list_item *d;
1507 		if (arg->type == D_range) {
1508 			long i, j;
1509 
1510 			i = arg->a_int;
1511 			arg = arg->next;
1512 			j = arg->a_int;
1513 			if (j > list->number)
1514 				j = list->number;
1515 			for (; i <= j; i++) {
1516 				if ((d = find_item(list, i)) != NULL)
1517 					delete_item(d);
1518 			}
1519 		} else {
1520 			if ((d = find_item(list, arg->a_int)) == NULL) {
1521 				/* split into two for easier message translation */
1522 				if (list == &display_list)
1523 					d_error(_("no display item numbered %ld"),
1524 						arg->a_int);
1525 				else
1526 					d_error(_("no watch item numbered %ld"),
1527 						arg->a_int);
1528 			} else
1529 				delete_item(d);
1530 		}
1531 	}
1532 }
1533 
1534 /* display --- print an item from the auto-display list */
1535 
1536 static void
display(struct list_item * d)1537 display(struct list_item *d)
1538 {
1539 	NODE *symbol;
1540 
1541 	symbol = d->symbol;
1542 	if (IS_PARAM(d)	&& (d->fcall_count != (fcall_count - cur_frame)))
1543 		return;
1544 
1545 	if (IS_SUBSCRIPT(d)) {
1546 		NODE *sub, *r;
1547 		int i = 0, count = d->num_subs;
1548 		for (i = 0; i < count; i++) {
1549 			sub = d->subs[i];
1550 			r = in_array(symbol, sub);
1551 			if (r == NULL) {
1552 				fprintf(out_fp, _("%d: subscript \"%.*s\" is not in array `%s'\n"),
1553 							d->number, (int) sub->stlen, sub->stptr, d->sname);
1554 				break;
1555 			}
1556 			if (r->type == Node_var_array) {
1557 				symbol = r;
1558 				if (i == count - 1)	/* it's a sub-array */
1559 					goto print_sym;		/* print # of elements in sub-array */
1560 			} else {
1561 				if (i != count - 1)
1562 					return;		/* FIXME msg and delete item ? */
1563 				fprintf(out_fp, "%d: %s[\"%.*s\"] = ", d->number,
1564 							d->sname, (int) sub->stlen, sub->stptr);
1565 				valinfo(r, fprintf, out_fp);
1566 			}
1567 		}
1568 	} else if (IS_FIELD(d)) {
1569 		NODE *r = d->symbol;
1570 		fprintf(out_fp, "%d: ", d->number);
1571 		print_field(get_number_si(r));
1572 	} else {
1573 print_sym:
1574 		fprintf(out_fp, "%d: %s = ", d->number, d->sname);
1575 		print_symbol(symbol, IS_PARAM(d));
1576 	}
1577 }
1578 
1579 
1580 /* do_display --- display command */
1581 
1582 int
do_display(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1583 do_display(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1584 {
1585 	struct list_item *d;
1586 
1587 	if (arg == NULL) {
1588 		/* display all items */
1589 		for (d = display_list.prev; d != &display_list; d = d->prev)
1590 			display(d);
1591 		return false;
1592 	}
1593 
1594 	if ((d = do_add_item(&display_list, arg)) != NULL)
1595 		display(d);
1596 
1597 	return false;
1598 }
1599 
1600 /* do_undisplay --- undisplay command */
1601 
1602 int
do_undisplay(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1603 do_undisplay(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1604 {
1605 	do_delete_item(&display_list, arg);
1606 	return false;
1607 }
1608 
1609 /* condition_triggered --- test if a condition expression is true */
1610 
1611 static int
condition_triggered(struct condition * cndn)1612 condition_triggered(struct condition *cndn)
1613 {
1614 	NODE *r;
1615 	int di;
1616 
1617 	assert(cndn != NULL);
1618 	if (cndn->code == NULL)
1619 		return true;
1620 
1621 	push_context(cndn->ctxt);
1622 	r = execute_code((volatile INSTRUCTION *) cndn->code);
1623 	pop_context();  /* switch to prev context */
1624 	if (r == NULL)      /* fatal error */
1625 		return false;   /* not triggered */
1626 
1627 	force_number(r);
1628 	di = ! is_zero(r);
1629 	DEREF(r);
1630 	return di;
1631 }
1632 
1633 
1634 static int
find_subscript(struct list_item * item,NODE ** ptr)1635 find_subscript(struct list_item *item, NODE **ptr)
1636 {
1637 	NODE *symbol = item->symbol;
1638 	NODE *sub, *r;
1639 	int i = 0, count = item->num_subs;
1640 
1641 	r = *ptr = NULL;
1642 	for (i = 0; i < count; i++) {
1643 		sub = item->subs[i];
1644 		r = in_array(symbol, sub);
1645 		if (r == NULL)
1646 			return 0;
1647 		if (r->type == Node_var_array)
1648 			symbol = r;
1649 		else if (i < count - 1)
1650 			return -1;
1651 	}
1652 	if (r != NULL)
1653 		*ptr = r;
1654 	return 0;
1655 }
1656 
1657 /* cmp_val --- compare values of watched item, returns true if different; */
1658 
1659 static int
cmp_val(struct list_item * w,NODE * old,NODE * new)1660 cmp_val(struct list_item *w, NODE *old, NODE *new)
1661 {
1662 		/*
1663 		 *	case    old     new     result
1664 		 *	------------------------------
1665 		 *	1:      NULL    ARRAY   true
1666 		 *	2:      NULL    SCALAR  true
1667 		 *	3:      NULL    NULL    false
1668 		 *	4:      SCALAR  SCALAR  cmp_node
1669 		 *	5:      SCALAR  ARRAY   true
1670 		 *	6:      SCALAR  NULL    true
1671 		 *	7:      ARRAY   SCALAR  true
1672 		 *	8:      ARRAY   ARRAY   compare size
1673 		 *	9:      ARRAY   NULL    true
1674 		 */
1675 
1676 	if (WATCHING_ARRAY(w)) {
1677 		long size = 0;
1678 		if (! new)		/* 9 */
1679 			return true;
1680 		if (new->type == Node_val)	/* 7 */
1681 			return true;
1682 		/* new->type == Node_var_array */	/* 8 */
1683 		size = assoc_length(new);
1684 		if (w->cur_size == size)
1685 			return false;
1686 		return true;
1687 	}
1688 
1689 	if (! old && ! new)	/* 3 */
1690 		return false;
1691 	if ((! old && new)	/* 1, 2 */
1692 			|| (old && ! new))	/* 6 */
1693 		return true;
1694 
1695 	if (new->type == Node_var_array)	/* 5 */
1696 		return true;
1697 	return cmp_nodes(old, new, true);	/* 4 */
1698 }
1699 
1700 /* watchpoint_triggered --- check if we should stop at this watchpoint;
1701  *                          update old and current values accordingly.
1702  */
1703 
1704 static int
watchpoint_triggered(struct list_item * w)1705 watchpoint_triggered(struct list_item *w)
1706 {
1707 	NODE *symbol;
1708 	NODE *t1, *t2;
1709 
1710 	symbol = w->symbol;
1711 	if (IS_PARAM(w) && (w->fcall_count != (fcall_count - cur_frame)))
1712 		return 0; /* parameter with same name in a different function */
1713 	if (! condition_triggered(&w->cndn))
1714 		return 0;
1715 
1716 	t1 = w->cur_value;
1717 	t2 = (NODE *) 0;
1718 	if (IS_SUBSCRIPT(w))
1719 		(void) find_subscript(w, &t2);
1720 	else if (IS_FIELD(w)) {
1721 		long field_num;
1722 		field_num = get_number_si(w->symbol);
1723 		t2 = *get_field(field_num, NULL);
1724 	} else {
1725 		switch (symbol->type) {
1726 		case Node_var:
1727 			t2 = symbol->var_value;
1728 			break;
1729 		case Node_var_array:
1730 			t2 = symbol;
1731 			break;
1732 		case Node_var_new:
1733 			break;
1734 		default:
1735 			cant_happen();
1736 		}
1737 	}
1738 
1739 	if (! cmp_val(w, t1, t2))
1740 		return 0;
1741 
1742 	/* update old and current values */
1743 
1744 	if ((w->flags & OLD_IS_ARRAY) == 0)
1745 		unref(w->old_value);
1746 	w->flags &= ~OLD_IS_ARRAY;
1747 	if (WATCHING_ARRAY(w)) {	/* 7, 8, 9 */
1748 		w->old_size = w->cur_size;
1749 		w->flags |= OLD_IS_ARRAY;
1750 		if (! t2) {
1751 			w->flags &= ~CUR_IS_ARRAY;
1752 			w->cur_value = 0;
1753 		} else if (t2->type == Node_val) {
1754 			w->flags &= ~CUR_IS_ARRAY;
1755 			w->cur_value = dupnode(t2);
1756 		} else
1757 			w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0;
1758 	} else if (! t1) { /* 1, 2 */
1759 		w->old_value = 0;
1760 		/* new != NULL */
1761 		if (t2->type == Node_val)
1762 			w->cur_value = dupnode(t2);
1763 		else {
1764 			w->flags |= CUR_IS_ARRAY;
1765 			w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0;
1766 		}
1767 	} else /* if (t1->type == Node_val) */ {	/* 4, 5, 6 */
1768 		w->old_value = w->cur_value;
1769 		if (! t2)
1770 			w->cur_value = 0;
1771 		else if (t2->type == Node_var_array) {
1772 			w->flags |= CUR_IS_ARRAY;
1773 			w->cur_size = assoc_length(t2);
1774 		} else
1775 			w->cur_value = dupnode(t2);
1776 	}
1777 
1778 	return w->number;
1779 }
1780 
1781 /* initialize_watch_item --- initialize current value of a watched item */
1782 
1783 static int
initialize_watch_item(struct list_item * w)1784 initialize_watch_item(struct list_item *w)
1785 {
1786 	NODE *t, *r;
1787 	NODE *symbol = w->symbol;
1788 
1789 	if (IS_SUBSCRIPT(w)) {
1790 		if (find_subscript(w, &r) == -1) {
1791 			d_error(_("attempt to use scalar value as array"));
1792 			return -1;
1793 		}
1794 
1795 		if (r == NULL)
1796 			w->cur_value = (NODE *) 0;
1797 		else if (r->type == Node_var_array) { /* it's a sub-array */
1798 			w->flags |= CUR_IS_ARRAY;
1799 			w->cur_size = assoc_length(r);
1800 		} else
1801 			w->cur_value = dupnode(r);
1802 	} else if (IS_FIELD(w)) {
1803 		long field_num;
1804 		t = w->symbol;
1805 		field_num = get_number_si(t);
1806 		r = *get_field(field_num, NULL);
1807 		w->cur_value = dupnode(r);
1808 	} else {
1809 		if (symbol->type == Node_var_new)
1810 			w->cur_value = (NODE *) 0;
1811 		else if (symbol->type == Node_var) {
1812 			r = symbol->var_value;
1813 			w->cur_value = dupnode(r);
1814 		} else if (symbol->type == Node_var_array) {
1815 			w->flags |= CUR_IS_ARRAY;
1816 			w->cur_size = assoc_length(symbol);
1817 		} else if (symbol->type == Node_val && (symbol->flags & REGEX) != 0) {
1818 			w->cur_value = dupnode(symbol);
1819 		} /* else
1820 			can't happen */
1821 	}
1822 	return 0;
1823 }
1824 
1825 /* do_watch --- watch command */
1826 
1827 int
do_watch(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1828 do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1829 {
1830 	struct list_item *w;
1831 	NODE *symbol, *sub;
1832 	int i;
1833 
1834 	w = do_add_item(&watch_list, arg);
1835 	if (w == NULL)
1836 		return false;
1837 
1838 	if (initialize_watch_item(w) == -1) {
1839 		delete_item(w);
1840 		return false;
1841 	}
1842 
1843 	fprintf(out_fp, "Watchpoint %d: ", w->number);
1844 	symbol = w->symbol;
1845 
1846 	/* FIXME: common code also in print_watch_item */
1847 	if (IS_SUBSCRIPT(w)) {
1848 		fprintf(out_fp, "%s", w->sname);
1849 		for (i = 0; i < w->num_subs; i++) {
1850 			sub = w->subs[i];
1851 			fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
1852 		}
1853 		fprintf(out_fp, "\n");
1854 	} else if (IS_FIELD(w))
1855 		fprintf(out_fp, "$%ld\n", get_number_si(symbol));
1856 	else
1857 		fprintf(out_fp, "%s\n", w->sname);
1858 
1859 	return false;
1860 }
1861 
1862 /* do_unwatch --- unwatch command */
1863 
1864 int
do_unwatch(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1865 do_unwatch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1866 {
1867 	do_delete_item(&watch_list, arg);
1868 	return false;
1869 }
1870 
1871 /* callback from pop_frame in eval.c */
1872 
1873 void
frame_popped()1874 frame_popped()
1875 {
1876 	struct list_item *item;
1877 
1878 	/* delete all out of scope watchpoints */
1879 	for (item = watch_list.next; item != &watch_list; item = item->next) {
1880 		if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1881 			fprintf(out_fp,
1882 				_("Watchpoint %d deleted because parameter is out of scope.\n"),
1883 				item->number);
1884 			item = item->prev;
1885 			delete_item(item->next);
1886 		}
1887 	}
1888 
1889 	/* delete all out of scope display items */
1890 	for (item = display_list.next; item != &display_list; item = item->next) {
1891 		if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1892 			fprintf(out_fp,
1893 				_("Display %d deleted because parameter is out of scope.\n"),
1894 				item->number);
1895 			item = item->prev;
1896 			delete_item(item->next);
1897 		}
1898 	}
1899 }
1900 
1901 /* print_function --- print function name, parameters, and optionally
1902  *                file and line number.
1903  */
1904 
1905 static int
print_function(INSTRUCTION * pc,void * x)1906 print_function(INSTRUCTION *pc, void *x)
1907 {
1908 	NODE *func;
1909 	int i, pcount;
1910 	struct pf_data *data = (struct pf_data *) x;
1911 	int defn = data->defn;
1912 	Func_print print_func = data->print_func;
1913 	FILE *fp = data->fp;
1914 
1915 	func = pc->func_body;
1916 	pcount = func->param_cnt;
1917 
1918 	print_func(fp, "%s(", func->vname);
1919 	for (i = 0; i < pcount; i++) {
1920 		print_func(fp, "%s", func->fparms[i].param);
1921 		if (i < pcount - 1)
1922 			print_func(fp, ", ");
1923 	}
1924 	print_func(fp, ")");
1925 	if (defn)
1926 		print_func(fp, _(" in file `%s', line %d\n"),
1927 				pc->source_file, pc->source_line);
1928 	return 0;
1929 }
1930 
1931 /* print_frame --- print function name, parameters,
1932  *                 source and line number of where it is
1933  *                 executing.
1934  */
1935 
1936 static void
print_frame(NODE * func,char * src,int srcline)1937 print_frame(NODE *func, char *src, int srcline)
1938 {
1939 	if (func == NULL)
1940 		fprintf(out_fp, "main()");
1941 	else {
1942 		pf_data.print_func = fprintf;
1943 		pf_data.fp = out_fp;
1944 		pf_data.defn = false;
1945 		(void) print_function(func->code_ptr, &pf_data);
1946 	}
1947 	fprintf(out_fp, _(" at `%s':%d"), src, srcline);
1948 }
1949 
1950 /* print_numbered_frame --- print a frame given its number */
1951 
1952 static void
print_numbered_frame(long num)1953 print_numbered_frame(long num)
1954 {
1955 	NODE *f;
1956 
1957 	assert(prog_running == true);
1958 	f = find_frame(num);
1959 	if (num == 0) {
1960 		fprintf(out_fp, "#%ld\t ", num);
1961 		print_frame(f->func_node, source, sourceline);
1962 	} else {
1963 		fprintf(out_fp, _("#%ld\tin "), num);
1964 		print_frame(f->func_node, f->vname,
1965 			((INSTRUCTION *) find_frame(num - 1)->reti)->source_line);
1966 	}
1967 	fprintf(out_fp, "\n");
1968 }
1969 
1970 /* do_backtrace --- backtrace command */
1971 
1972 int
do_backtrace(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)1973 do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1974 {
1975 	long cur = 0;
1976 	long last = fcall_count;
1977 
1978 	CHECK_PROG_RUNNING();
1979 	if (arg != NULL && arg->type == D_int) {
1980 		long count = arg->a_int;
1981 
1982 		/* frame_ptr (frame #0),  fcall_list[1, 2, ... fcall_count] => total count */
1983 		if (count >= 0) {
1984 			/* toward outermost frame #fcall_count */
1985 			last = count - 1;
1986 			if (last > fcall_count)
1987 				 last = fcall_count;
1988 		} else {
1989 			/* toward innermost frame #0 */
1990 			cur = 1 + fcall_count + count;
1991 			if (cur < 0)
1992 				cur = 0;
1993 		}
1994 	}
1995 
1996 	for (; cur <= last; cur++) {
1997 		print_numbered_frame(cur);
1998 	}
1999 	if (cur <= fcall_count)
2000 		fprintf(out_fp, _("More stack frames follow ...\n"));
2001 	return false;
2002 }
2003 
2004 /* print_cur_frame_and_sourceline --- print current frame, and
2005  *                                    current source line.
2006  */
2007 
2008 static void
print_cur_frame_and_sourceline()2009 print_cur_frame_and_sourceline()
2010 {
2011 	NODE *f;
2012 	int srcline;
2013 	char *src;
2014 
2015 	assert(prog_running == true);
2016 	f = find_frame(cur_frame);
2017 	if (cur_frame == 0) {
2018 		src = source;
2019 		srcline = sourceline;
2020 	} else {
2021 		f = find_frame(cur_frame);
2022 		src = f->vname;
2023 		srcline = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
2024 	}
2025 
2026 	fprintf(out_fp, (cur_frame > 0 ? _("#%ld\tin ") : "#%ld\t "), cur_frame);
2027 	print_frame(f->func_node, src, srcline);
2028 	fprintf(out_fp, "\n");
2029 	print_lines(src, srcline, 1);
2030 	last_printed_line = srcline - list_size / 2;
2031 	if (last_printed_line < 0)
2032 		last_printed_line = 0;
2033 }
2034 
2035 /* do_frame --- frame command */
2036 
2037 int
do_frame(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2038 do_frame(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2039 {
2040 	CHECK_PROG_RUNNING();
2041 	if (arg && arg->type == D_int) {
2042 		if (arg->a_int < 0 || arg->a_int > fcall_count) {
2043 			d_error(_("invalid frame number"));
2044 			return false;
2045 		}
2046 		cur_frame = arg->a_int;
2047 	}
2048 	print_cur_frame_and_sourceline();
2049 	return false;
2050 }
2051 
2052 /* do_up --- up command */
2053 
2054 int
do_up(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2055 do_up(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2056 {
2057 	CHECK_PROG_RUNNING();
2058 	if (arg != NULL && arg->type == D_int)
2059 		cur_frame += arg->a_int;
2060 	else
2061 		cur_frame++;
2062 	if (cur_frame < 0)
2063 		cur_frame = 0;
2064 	else if (cur_frame > fcall_count)
2065 		cur_frame = fcall_count;
2066 	print_cur_frame_and_sourceline();
2067 	return false;
2068 }
2069 
2070 /* do_down --- down command */
2071 
2072 int
do_down(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2073 do_down(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2074 {
2075 	CHECK_PROG_RUNNING();
2076 	if (arg != NULL && arg->type == D_int)
2077 		cur_frame -= arg->a_int;
2078 	else
2079 		cur_frame--;
2080 	if (cur_frame < 0)
2081 		cur_frame = 0;
2082 	else if (cur_frame > fcall_count)
2083 		cur_frame = fcall_count;
2084 	print_cur_frame_and_sourceline();
2085 	return false;
2086 }
2087 
2088 /* find_rule --- find a rule or function in file 'src' containing
2089  *               source line 'lineno'
2090  */
2091 
2092 static INSTRUCTION *
find_rule(char * src,long lineno)2093 find_rule(char *src, long lineno)
2094 {
2095 	INSTRUCTION *rp;
2096 
2097 	/*
2098 	 * FIXME: The check for zero and code that goes with it
2099 	 * are probably fragile.  A break with no arguments can
2100 	 * cause this in certain cases. Try to review how this works.
2101 	 */
2102 	if (lineno == 0) {
2103 		for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) {
2104 			if ((rp - 1)->source_file == src && (rp - 1)->source_line > 0)
2105 				return (rp - 1);
2106 		}
2107 	} else {
2108 		for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) {
2109 			if ((rp - 1)->source_file == src
2110 					&& lineno >= (rp + 1)->first_line
2111 					&& lineno <= (rp + 1)->last_line)
2112 				return (rp - 1);
2113 		}
2114 	}
2115 	return NULL;
2116 }
2117 
2118 /* mk_breakpoint --- create a breakpoint instruction and the corresponding
2119  *                   breakpoint structure.
2120  */
2121 
2122 static INSTRUCTION *
mk_breakpoint(char * src,int srcline)2123 mk_breakpoint(char *src, int srcline)
2124 {
2125 	INSTRUCTION *bp;
2126 	BREAKPOINT *b;
2127 
2128 	bp = bcalloc(Op_breakpoint, 1, srcline);
2129 	emalloc(b, BREAKPOINT *, sizeof(BREAKPOINT), "mk_breakpoint");
2130 	memset(&b->cndn, 0, sizeof(struct condition));
2131 	b->commands.next = b->commands.prev = &b->commands;
2132 	b->silent = false;
2133 
2134 
2135 	b->number = ++watch_list.number;	/* breakpoints and watchpoints use same counter */
2136 	b->ignore_count = 0;
2137 	b->hit_count = 0;
2138 	b->flags = BP_ENABLE;
2139 	b->src = src;
2140 	bp->break_pt = b;
2141 	b->bpi = bp;
2142 
2143 	/* prepend to list */
2144 	b->next = breakpoints.next;
2145 	b->prev = &breakpoints;
2146 	breakpoints.next = b;
2147 	b->next->prev = b;
2148 	return bp;
2149 }
2150 
2151 /* delete_breakpoint --- delete a breakpoint structure and
2152  *                       disable the breakpoint instruction.
2153  */
2154 
2155 static void
delete_breakpoint(BREAKPOINT * b)2156 delete_breakpoint(BREAKPOINT *b)
2157 {
2158 	INSTRUCTION *pc = b->bpi;
2159 	struct commands_item *c;
2160 
2161 	/* N.B.: easiest thing to do is to turn Op_breakpoint into a no-op;
2162 	 * deleteing the instruction is not that simple,
2163 	 * since could have reference to it somewhere else (e.g. cur_pc).
2164 	 */
2165 
2166 	pc->opcode = Op_no_op;
2167 	pc->source_line = 0;
2168 	pc->break_pt = NULL;
2169 
2170 	/* delete commands */
2171 	for (c = b->commands.next; c != &b->commands; c = c->next) {
2172 		c = c->prev;
2173 		delete_commands_item(c->next);
2174 	}
2175 
2176 	free_context(b->cndn.ctxt, false);
2177 	if (b->cndn.expr != NULL)
2178 		efree(b->cndn.expr);
2179 
2180 	/* remove from list */
2181 	b->next->prev = b->prev;
2182 	b->prev->next = b->next;
2183 	efree(b);
2184 }
2185 
2186 /* find_breakpoint --- find the breakpoint structure from a breakpoint number */
2187 
2188 static BREAKPOINT *
find_breakpoint(long num)2189 find_breakpoint(long num)
2190 {
2191 	BREAKPOINT *b;
2192 
2193 	if (num <= 0)
2194 		return NULL;
2195 
2196 	for (b = breakpoints.next; b != &breakpoints; b = b->next) {
2197 		if (b->number == num)
2198 			return b;
2199 	}
2200 	return NULL;
2201 }
2202 
2203 /* add_breakpoint --- add a breakpoint instruction between PREVP and IP */
2204 
2205 static BREAKPOINT *
add_breakpoint(INSTRUCTION * prevp,INSTRUCTION * ip,char * src,bool silent)2206 add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent)
2207 {
2208 	BREAKPOINT *b;
2209 	INSTRUCTION *bp;
2210 	int lineno = ip->source_line;
2211 
2212 	/* add new breakpoint instruction at the end of
2213 	 * already set breakpoints at this line number.
2214 	 */
2215 
2216 	while (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2217 		if (! silent) {
2218 			b = ip->break_pt;
2219 			/*
2220 			 * This is more verbose that it might otherwise be,
2221 			 * in order to provide easily translatable strings.
2222 			 */
2223 			if ((b->flags & BP_ENABLE) != 0) {
2224 				if ((b->flags & BP_IGNORE) != 0)
2225 					fprintf(out_fp,
2226 			_("Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d"),
2227 						b->number,
2228 						b->ignore_count,
2229 						b->src,
2230 						lineno);
2231 				else
2232 					fprintf(out_fp,
2233 			_("Note: breakpoint %d (enabled), also set at %s:%d"),
2234 						b->number,
2235 						b->src,
2236 						lineno);
2237 			} else {
2238 				if ((b->flags & BP_IGNORE) != 0)
2239 					fprintf(out_fp,
2240 			_("Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d"),
2241 						b->number,
2242 						b->ignore_count,
2243 						b->src,
2244 						lineno);
2245 				else
2246 					fprintf(out_fp,
2247 			_("Note: breakpoint %d (disabled), also set at %s:%d"),
2248 						b->number,
2249 						b->src,
2250 						lineno);
2251 			}
2252 		}
2253 		prevp = ip;
2254 		ip = ip->nexti;
2255 	}
2256 
2257 	assert(ip->source_line == lineno);
2258 
2259 	bp = mk_breakpoint(src, lineno);
2260 	prevp->nexti = bp;
2261 	bp->nexti = ip;
2262 	b = bp->break_pt;
2263 	if (! silent)
2264 		fprintf(out_fp, _("Breakpoint %d set at file `%s', line %d\n"),
2265 						b->number, src, lineno);
2266 	return b;
2267 }
2268 
2269 /* set_breakpoint_at --- set a breakpoint at given line number*/
2270 
2271 static BREAKPOINT *
set_breakpoint_at(INSTRUCTION * rp,int lineno,bool silent)2272 set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent)
2273 {
2274 	INSTRUCTION *ip, *prevp;
2275 
2276 	for (prevp = rp, ip = rp->nexti; ip; prevp = ip, ip = ip->nexti) {
2277 		if (ip->opcode == Op_K_case) {
2278 			INSTRUCTION *i1, *i2;
2279 
2280 			/* Special case: the code line numbers for a switch do not form
2281 			 * a monotonically increasing sequence. Check if the line # is between
2282 			 * the first and last statements of the case block before continuing
2283 			 * the search.
2284 			 */
2285 			for (i2 = ip->stmt_start, i1 = i2->nexti; i2 != ip->stmt_end;
2286 								i2 = i1, i1 = i1->nexti) {
2287 				if (i1->source_line >= lineno)
2288 					return add_breakpoint(i2, i1, rp->source_file, silent);
2289 				if (i1 == ip->stmt_end)
2290 					break;
2291 			}
2292 		}
2293 
2294 		if (ip->source_line >= lineno)
2295 			return add_breakpoint(prevp, ip, rp->source_file, silent);
2296 		if (ip == (rp + 1)->lasti)
2297 			break;
2298 	}
2299 	return NULL;
2300 }
2301 
2302 /* set_breakpoint_next --- set a breakpoint at the next instruction */
2303 
2304 static BREAKPOINT *
set_breakpoint_next(INSTRUCTION * rp,INSTRUCTION * ip)2305 set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip)
2306 {
2307 	INSTRUCTION *prevp;
2308 
2309 	if (ip == (rp + 1)->lasti)
2310 		return NULL;
2311 	prevp = ip;
2312 	if (ip->opcode != Op_breakpoint)
2313 		ip = ip->nexti;
2314 	for (; ip; prevp = ip, ip = ip->nexti) {
2315 		if (ip->source_line > 0)
2316 			return add_breakpoint(prevp, ip, rp->source_file, false);
2317 		if (ip == (rp + 1)->lasti)
2318 			break;
2319 	}
2320 	return NULL;
2321 }
2322 
2323 /* set_breakpoint --- set a breakpoint */
2324 
2325 static int
set_breakpoint(CMDARG * arg,bool temporary)2326 set_breakpoint(CMDARG *arg, bool temporary)
2327 {
2328 	int lineno;
2329 	BREAKPOINT *b = NULL;
2330 	INSTRUCTION *rp, *ip;
2331 	NODE *func;
2332 	SRCFILE *s = cur_srcfile;
2333 	char *src = cur_srcfile->src;
2334 
2335 	if (arg == NULL) {
2336 /*
2337 * (From GDB Documentation):
2338 *
2339 * When called without any arguments, break sets a breakpoint at the next instruction
2340 * to be executed in the selected stack frame (see section Examining the Stack).
2341 * In any selected frame but the innermost, this makes your program stop as soon
2342 * as control returns to that frame. This is similar to the effect of a finish command
2343 * in the frame inside the selected frame--except that finish does not leave an
2344 * active breakpoint. If you use break without an argument in the innermost frame,
2345 * GDB stops the next time it reaches the current location; this may be useful
2346 * inside loops.
2347 * GDB normally ignores breakpoints when it resumes execution, until at least
2348 * one instruction has been executed. If it did not do this,
2349 * you would be unable to proceed past a breakpoint without first disabling the
2350 * breakpoint. This rule applies whether or not the breakpoint already existed
2351 * when your program stopped.
2352 */
2353 		CHECK_PROG_RUNNING();
2354 		if (cur_frame == 0) {
2355 			src = source;
2356 			ip = cur_pc;
2357 		} else {
2358 			NODE *f;
2359 			f = find_frame(cur_frame);
2360 			src = f->vname;
2361 			ip = (INSTRUCTION *) find_frame(cur_frame - 1)->reti;  /* Op_func_call */
2362 		}
2363 		rp = find_rule(src, ip->source_line);
2364 		assert(rp != NULL);
2365 		if ((b = set_breakpoint_next(rp, ip)) == NULL)
2366 			fprintf(out_fp, _("cannot set breakpoint in file `%s'\n"), src);
2367 		else {
2368 			if (cur_frame == 0) {	/* stop next time */
2369 				b->flags |= BP_IGNORE;
2370 				b->ignore_count = 1;
2371 			}
2372 			if (temporary)
2373 				b->flags |= BP_TEMP;
2374 		}
2375 		return false;
2376 	}
2377 
2378 	/* arg != NULL */
2379 
2380 	switch (arg->type) {
2381 	case D_string:	/* break filename:lineno|function */
2382 		s = source_find(arg->a_string);
2383 		arg = arg->next;
2384 		if (s == NULL || arg == NULL
2385 				|| (arg->type != D_int && arg->type != D_func))
2386 			return false;
2387 		src = s->src;
2388 		if (arg->type == D_func) /* break filename:function */
2389 			goto func;
2390 		else
2391 			/* fall through */
2392 	case D_int:		/* break lineno */
2393 		lineno = (int) arg->a_int;
2394 		if (lineno <= 0 || lineno > s->srclines)
2395 			d_error(_("line number %d in file `%s' is out of range"), lineno, src);
2396 		else {
2397 			rp = find_rule(src, lineno);
2398 			if (rp == NULL)
2399 				fprintf(out_fp, _("internal error: cannot find rule\n"));
2400 			if (rp == NULL || (b = set_breakpoint_at(rp, lineno, false)) == NULL)
2401 				fprintf(out_fp, _("cannot set breakpoint at `%s':%d\n"),
2402 						src, lineno);
2403 			if (b != NULL && temporary)
2404 				b->flags |= BP_TEMP;
2405 		}
2406 		break;
2407 
2408 	case D_func:	/* break function */
2409 func:
2410 		func = arg->a_node;
2411 		rp = func->code_ptr;
2412 		if ((b = set_breakpoint_at(rp, rp->source_line, false)) == NULL)
2413 			fprintf(out_fp, _("cannot set breakpoint in function `%s'\n"),
2414 						func->vname);
2415 		else {
2416 			if (temporary)
2417 				b->flags |= BP_TEMP;
2418 			lineno = b->bpi->source_line;
2419 		}
2420 		break;
2421 
2422 	default:
2423 		return false;
2424 	}
2425 	/* condition if any */
2426 	arg = arg->next;
2427 	if (b != NULL && arg != NULL) {
2428 		if (parse_condition(D_break, b->number, arg->a_string) == 0)
2429 			arg->a_string = NULL;	/* don't let free_cmdarg free it */
2430 		else
2431 			fprintf(out_fp, _("breakpoint %d set at file `%s', line %d is unconditional\n"),
2432 							b->number, src, lineno);
2433 	}
2434 	return false;
2435 }
2436 
2437 
2438 /* breakpoint_triggered --- check if we should stop at this breakpoint */
2439 
2440 static int
breakpoint_triggered(BREAKPOINT * b)2441 breakpoint_triggered(BREAKPOINT *b)
2442 {
2443 	if ((b->flags & BP_ENABLE) == 0)
2444 		return 0;
2445 	if ((b->flags & BP_IGNORE) != 0) {
2446 		if (--b->ignore_count <= 0)
2447 			b->flags &= ~BP_IGNORE;
2448 		return 0;
2449 	}
2450 
2451 	if (! condition_triggered(&b->cndn))
2452 		return 0;
2453 
2454 	b->hit_count++;
2455 	if ((b->flags & BP_ENABLE_ONCE) != 0) {
2456 		b->flags &= ~BP_ENABLE_ONCE;
2457 		b->flags &= ~BP_ENABLE;
2458 	}
2459 	return b->number;
2460 }
2461 
2462 /* do_breakpoint --- break command */
2463 
2464 int
do_breakpoint(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2465 do_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2466 {
2467 	return set_breakpoint(arg, false);
2468 }
2469 
2470 /* do_tmp_breakpoint --- tbreak command */
2471 
2472 int
do_tmp_breakpoint(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2473 do_tmp_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2474 {
2475 	return set_breakpoint(arg, true);
2476 }
2477 
2478 /* do_clear --- clear command */
2479 
2480 int
do_clear(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2481 do_clear(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2482 {
2483 	int lineno;
2484 	BREAKPOINT *b;
2485 	INSTRUCTION *rp, *ip;
2486 	NODE *func;
2487 	SRCFILE *s = cur_srcfile;
2488 	char *src = cur_srcfile->src;
2489 	int bp_found = 0;
2490 
2491 	if (arg == NULL) {	/* clear */
2492 		CHECK_PROG_RUNNING();
2493 		if (cur_frame == 0) {
2494 			lineno = sourceline;
2495 			src = source;
2496 		} else {
2497 			NODE *f;
2498 			f = find_frame(cur_frame);
2499 			src = f->vname;
2500 			lineno = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
2501 		}
2502 		goto delete_bp;
2503 	}
2504 
2505 	switch (arg->type) {
2506 	case D_string:	/* clear filename:lineno|function */
2507 		s = source_find(arg->a_string);
2508 		arg = arg->next;
2509 		if (s == NULL || arg == NULL ||
2510 				(arg->type != D_int && arg->type != D_func))
2511 			return false;
2512 		src = s->src;
2513 		if (arg->type == D_func)
2514 			goto func;
2515 		/* else
2516 			fall through */
2517 	case D_int:	/* clear lineno */
2518 		lineno = (int) arg->a_int;
2519 		if (lineno <= 0 || lineno > s->srclines) {
2520 			d_error(_("line number %d in file `%s' out of range"), lineno, src);
2521 			return false;
2522 		}
2523 		break;
2524 
2525 	case D_func:	/* clear function */
2526 func:
2527 		func = arg->a_node;
2528 		rp = func->code_ptr;
2529 		for (ip = rp->nexti; ip; ip = ip->nexti) {
2530 			if (ip->source_line <= 0)
2531 				continue;
2532 			if (ip->opcode != Op_breakpoint)
2533 				break;
2534 			b = ip->break_pt;
2535 			if (++bp_found == 1)
2536 				fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2537 			else
2538 				fprintf(out_fp, ", %d", b->number);
2539 			delete_breakpoint(b);
2540 		}
2541 		if (bp_found == 0)
2542 			fprintf(out_fp, _("No breakpoint(s) at entry to function `%s'\n"),
2543 					func->vname);
2544 		else
2545 			fprintf(out_fp, "\n");
2546 		/* fall through */
2547 	default:
2548 		return false;
2549 	}
2550 
2551 delete_bp:
2552 	rp = find_rule(src, lineno);
2553 	if (rp != NULL) {
2554 		for (ip = rp->nexti; ip; ip = ip->nexti) {
2555 			if (ip->opcode == Op_breakpoint	&& ip->source_line == lineno) {
2556 				b = ip->break_pt;
2557 				if (++bp_found == 1)
2558 					fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2559 				else
2560 					fprintf(out_fp, ", %d", b->number);
2561 				delete_breakpoint(b);
2562 			}
2563 			if (ip == (rp + 1)->lasti)
2564 				break;
2565 		}
2566 	}
2567 
2568 	if (bp_found == 0)
2569 		fprintf(out_fp, _("No breakpoint at file `%s', line #%d\n"),
2570 					src, (int) lineno);
2571 	else
2572 		fprintf(out_fp, "\n");
2573 	return false;
2574 }
2575 
2576 /* enable_breakpoint --- enable a breakpoint and set its disposition */
2577 
2578 static inline void
enable_breakpoint(BREAKPOINT * b,short disp)2579 enable_breakpoint(BREAKPOINT *b, short disp)
2580 {
2581 	b->flags &= ~(BP_ENABLE_ONCE|BP_TEMP);
2582 	b->flags |= BP_ENABLE;
2583 	if (disp)
2584 		b->flags |= disp;
2585 }
2586 
2587 /* do_enable_breakpoint --- enable command */
2588 
2589 int
do_enable_breakpoint(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2590 do_enable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2591 {
2592 	BREAKPOINT *b;
2593 	short disp = 0;
2594 
2595 	if (arg != NULL && arg->type == D_argument) {
2596 		if (arg->a_argument == A_DEL)	/* del */
2597 			disp = BP_TEMP;
2598 		else						/* once */
2599 			disp = BP_ENABLE_ONCE;
2600 		arg = arg->next;
2601 	}
2602 
2603 	if (arg == NULL) {	/* enable [once|del] */
2604 		for (b = breakpoints.next; b != &breakpoints; b = b->next)
2605 			enable_breakpoint(b, disp);
2606 	}
2607 
2608 	for (; arg != NULL; arg = arg->next) {
2609 		if (arg->type == D_range) {
2610 			long i, j;
2611 
2612 			i = arg->a_int;
2613 			arg = arg->next;
2614 			j = arg->a_int;
2615 			if (j > breakpoints.number)
2616 				j = breakpoints.number;
2617 			for (; i <= j; i++) {
2618 				if ((b = find_breakpoint(i)) != NULL)
2619 					enable_breakpoint(b, disp);
2620 			}
2621 		} else {
2622 			assert(arg->type == D_int);
2623 			if ((b = find_breakpoint(arg->a_int)) == NULL)
2624 				d_error(_("invalid breakpoint number"));
2625 			else
2626 				enable_breakpoint(b, disp);
2627 		}
2628 	}
2629 	return false;
2630 }
2631 
2632 /* do_delete_breakpoint --- delete command */
2633 
2634 int
do_delete_breakpoint(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2635 do_delete_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2636 {
2637 	if (arg == NULL) {
2638 		bool delete_all = true;
2639 		delete_all = prompt_yes_no(
2640 					_("Delete all breakpoints? (y or n) "),
2641 					_("y")[0], true, out_fp);
2642 
2643 		if (delete_all) {
2644 			while (breakpoints.next != &breakpoints)
2645 				delete_breakpoint(breakpoints.next);
2646 		}
2647 	}
2648 
2649 	for (; arg != NULL; arg = arg->next) {
2650 		BREAKPOINT *b;
2651 		if (arg->type == D_range) {
2652 			long i, j;
2653 
2654 			i = arg->a_int;
2655 			arg = arg->next;
2656 			j = arg->a_int;
2657 			if (j > breakpoints.number)
2658 				j = breakpoints.number;
2659 			for (; i <= j; i++) {
2660 				if ((b = find_breakpoint(i)) != NULL)
2661 					delete_breakpoint(b);
2662 			}
2663 		} else {
2664 			if ((b = find_breakpoint(arg->a_int)) == NULL)
2665 				d_error(_("invalid breakpoint number"));
2666 			else
2667 				delete_breakpoint(b);
2668 		}
2669 	}
2670 	return false;
2671 }
2672 
2673 /* do_ignore_breakpoint --- ignore command */
2674 
2675 int
do_ignore_breakpoint(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2676 do_ignore_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2677 {
2678 	BREAKPOINT *b;
2679 
2680 	if (arg == NULL || arg->type != D_int
2681 			|| arg->next == NULL || arg->next->type != D_int)
2682 		return false;
2683 
2684 	if ((b = find_breakpoint(arg->a_int)) == NULL)
2685 		d_error(_("invalid breakpoint number"));
2686 	else {
2687 		b->ignore_count = arg->next->a_int;
2688 		if (b->ignore_count > 0) {
2689 			b->flags |= BP_IGNORE;
2690 			fprintf(out_fp, _("Will ignore next %ld crossing(s) of breakpoint %d.\n"),
2691 					b->ignore_count, b->number);
2692 		} else {
2693 			b->flags &= ~BP_IGNORE;
2694  			fprintf(out_fp, _("Will stop next time breakpoint %d is reached.\n"),
2695 					b->number);
2696 		}
2697 	}
2698 	return false;
2699 }
2700 
2701 /* do_disable_breakpoint --- disable command */
2702 
2703 int
do_disable_breakpoint(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)2704 do_disable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2705 {
2706 	BREAKPOINT *b;
2707 
2708 	if (arg == NULL) {
2709 		/* disable all */
2710 		for (b = breakpoints.next; b != &breakpoints; b = b->next)
2711 			b->flags &= ~BP_ENABLE;
2712 	}
2713 
2714 	for (; arg != NULL; arg = arg->next) {
2715 		if (arg->type == D_range) {
2716 			long i, j;
2717 
2718 			i = arg->a_int;
2719 			arg = arg->next;
2720 			j = arg->a_int;
2721 			if (j > breakpoints.number)
2722 				j = breakpoints.number;
2723 			for (; i <= j; i++)
2724 				if ((b = find_breakpoint(i)) != NULL)
2725 					b->flags &= ~BP_ENABLE;
2726 		} else {
2727 			if ((b = find_breakpoint(arg->a_int)) == NULL)
2728 				d_error(_("invalid breakpoint number"));
2729 			else
2730 				b->flags &= ~BP_ENABLE;
2731 		}
2732 	}
2733 	return false;
2734 }
2735 
2736 #ifdef HAVE_LIBREADLINE
2737 
2738 /* get_function --- function definition in current context */
2739 
2740 NODE *
get_function()2741 get_function()
2742 {
2743 	NODE *func;
2744 
2745 	if (! prog_running)
2746 		return NULL;
2747 	func = find_frame(cur_frame)->func_node;
2748 	return func;
2749 }
2750 
2751 /* initialize_readline --- initialize readline */
2752 
2753 static void
initialize_readline()2754 initialize_readline()
2755 {
2756 	/* tell readline which stream to use for output,
2757 	 * default input stream is stdin.
2758 	 */
2759 	rl_outstream = out_fp;
2760 
2761 	/* allow conditional parsing of the ~/.inputrc file. */
2762 	rl_readline_name = "gawk";
2763 
2764 	/* our completion function. */
2765 	rl_attempted_completion_function = command_completion;
2766 
2767 	read_a_line = readline;
2768 }
2769 #else
2770 #define initialize_readline()	/* nothing */
2771 #endif
2772 
2773 
2774 /* init_debug --- register debugger exec hooks */
2775 
2776 void
init_debug()2777 init_debug()
2778 {
2779 	register_exec_hook(debug_pre_execute, debug_post_execute);
2780 }
2781 
2782 
2783 /* debug_prog --- debugger entry point */
2784 
2785 int
debug_prog(INSTRUCTION * pc)2786 debug_prog(INSTRUCTION *pc)
2787 {
2788 	char *run;
2789 
2790 	input_fd = fileno(stdin);
2791 	out_fp = stdout;
2792 	if (os_isatty(input_fd))
2793 		input_from_tty = true;
2794 	if (input_fd == 0 && input_from_tty)
2795 		initialize_readline();
2796 
2797 	if (! read_a_line)
2798 		read_a_line = g_readline;
2799 
2800 	push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
2801 
2802 	setbuf(out_fp, (char *) NULL);
2803 	for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles;
2804 			cur_srcfile = cur_srcfile->prev) {
2805 		if (cur_srcfile->stype == SRC_FILE
2806 			|| cur_srcfile->stype == SRC_INC)
2807 			break;
2808 	}
2809 
2810 	if (cur_srcfile == srcfiles) {
2811 		fprintf(out_fp, _("Can only debug programs provided with the `-f' option.\n"));
2812 		exit(EXIT_FAILURE);
2813 	}
2814 
2815 	dgawk_prompt = estrdup(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
2816 	dbg_prompt = dgawk_prompt;
2817 
2818 	memset(&stop, 0, sizeof(stop));
2819 	stop.command = D_illegal;
2820 
2821 	if ((run = getenv("DGAWK_RESTART")) != NULL) {
2822 		/* We are restarting; restore state (breakpoints, history etc.)
2823 		 * passed as environment variables and optionally execute the run command.
2824 		 */
2825 		unserialize_list(BREAK);
2826 		unserialize_list(WATCH);
2827 		unserialize_list(DISPLAY);
2828 		unserialize_list(HISTORY);
2829 		unserialize_list(OPTION);
2830 		unsetenv("DGAWK_RESTART");
2831 		fprintf(out_fp, "Restarting ...\n");
2832 		if (strcasecmp(run, "true") == 0)
2833 			(void) do_run(NULL, 0);
2834 
2835 	} else if (command_file != NULL) {
2836 		/* run commands from a file (--debug=file  or -D file) */
2837 		int fd;
2838 		fd = open_readfd(command_file);
2839 		if (fd == INVALID_HANDLE) {
2840 			fprintf(stderr, _("cannot open source file `%s' for reading: %s"),
2841 						command_file, strerror(errno));
2842 			exit(EXIT_FAILURE);
2843 		}
2844 		push_cmd_src(fd, false, g_readline, close, 0, EXIT_FAILURE);
2845 		cmd_src->str = estrdup(command_file, strlen(command_file));
2846 
2847 	} else {
2848 		int fd;
2849 
2850 #ifdef HAVE_LIBREADLINE
2851 		(void) read_history(history_file);
2852 		sess_history_base = history_length;
2853 #endif
2854 
2855 		/* read saved options */
2856 		fd = open_readfd(options_file);
2857 		if (fd > INVALID_HANDLE)
2858 			push_cmd_src(fd, false, g_readline, close, 0, EXIT_SUCCESS);
2859 	}
2860 
2861 	/* start the command interpreter */
2862 	read_command();	/* yyparse */
2863 	return EXIT_SUCCESS;
2864 }
2865 
2866 
2867 /* N.B.: ignore breakpoints and watchpoints for return command */
2868 
2869 /* check_watchpoint --- check if any watchpoint triggered */
2870 
2871 static int
check_watchpoint()2872 check_watchpoint()
2873 {
2874 	struct list_item *w;
2875 
2876 	if (stop.command == D_return)
2877 		return false;
2878 	for (w = watch_list.prev; w != &watch_list; w = w->prev) {
2879 		int wnum = watchpoint_triggered(w);
2880 		if (wnum > 0) {
2881 			stop.watch_point = wnum;
2882 			stop.print_frame = true;
2883 			return true;
2884 		}
2885 	}
2886 	return false;
2887 }
2888 
2889 /* check_breakpoint --- check if breakpoint triggered */
2890 
2891 static int
check_breakpoint(INSTRUCTION ** pi)2892 check_breakpoint(INSTRUCTION **pi)
2893 {
2894 	INSTRUCTION *pc;
2895 
2896 	pc = *pi;
2897 	if (stop.command == D_return)
2898 		return false;
2899 	if (pc->opcode == Op_breakpoint) {
2900 		int bnum;
2901 		*pi = pc->nexti;    /* skip past the breakpoint instruction;
2902 		                     * interpreter doesn't process Op_breakpoint.
2903 		                     */
2904 		bnum = breakpoint_triggered(pc->break_pt);
2905 		if (bnum > 0) {
2906 			stop.break_point = bnum;
2907 			stop.print_frame = true;
2908 			return true;
2909 		}
2910 	}
2911 	return false;
2912 }
2913 
2914 /* restart --- restart the debugger */
2915 
2916 static void
restart(bool run)2917 restart(bool run)
2918 {
2919 	/* save state in the environment after serialization */
2920 	serialize_list(BREAK);
2921 	serialize_list(WATCH);
2922 	serialize_list(DISPLAY);
2923 	serialize_list(HISTORY);
2924 	serialize_list(OPTION);
2925 
2926 	/* tell the new process to restore state from the environment */
2927 	setenv("DGAWK_RESTART", (run ? "true" : "false"), 1);
2928 
2929 	/* close all open files */
2930 	close_all();
2931 
2932 	/* start a new process replacing the current process */
2933 	execvp(d_argv[0], d_argv);
2934 
2935 	/* execvp failed !!! */
2936 	fprintf(out_fp, _("Failed to restart debugger"));
2937 	exit(EXIT_FAILURE);
2938 }
2939 
2940 /* do_run --- run command */
2941 
2942 int
do_run(CMDARG * arg ATTRIBUTE_UNUSED,int cmd ATTRIBUTE_UNUSED)2943 do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2944 {
2945 	if (prog_running) {
2946 		if (! input_from_tty)
2947 			need_restart = true;	/* handled later */
2948 		else {
2949 			need_restart = prompt_yes_no(
2950 			         _("Program already running. Restart from beginning (y/n)? "),
2951 			         _("y")[0], false, out_fp);
2952 
2953 			if (! need_restart) {
2954 				fprintf(out_fp, _("Program not restarted\n"));
2955 				return false;
2956 			}
2957 		}
2958 	}
2959 
2960 	if (need_restart) {
2961 		/* avoid endless cycles of restarting */
2962 		if (command_file != NULL) {
2963 			/* input_from_tty = false */
2964 			fprintf(stderr, _("error: cannot restart, operation not allowed\n"));
2965 			exit(EXIT_FAILURE);
2966 		}
2967 
2968 		if (cmd_src->cmd == D_source) {
2969 			/* input_from_tty = false */
2970 			fprintf(out_fp, _("error (%s): cannot restart, ignoring rest of the commands\n"), cmd_src->str);
2971 			pop_cmd_src();
2972 			return false;
2973 		}
2974 
2975 		restart(true);	/* does not return */
2976 	}
2977 
2978 	fprintf(out_fp, _("Starting program:\n"));
2979 
2980 	prog_running = true;
2981 	fatal_tag_valid = 1;
2982 	if (setjmp(fatal_tag) == 0)
2983 		(void) interpret(code_block);
2984 
2985 	fatal_tag_valid = 0;
2986 	prog_running = false;
2987 	fprintf(out_fp, (! exiting && exit_val != EXIT_SUCCESS)
2988 				? _("Program exited abnormally with exit value: %d\n")
2989 				: _("Program exited normally with exit value: %d\n"),
2990 			exit_val);
2991 	need_restart = true;
2992 	return false;
2993 }
2994 
2995 /* do_quit --- quit command */
2996 
2997 int
do_quit(CMDARG * arg ATTRIBUTE_UNUSED,int cmd ATTRIBUTE_UNUSED)2998 do_quit(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2999 {
3000 	bool terminate = true;
3001 	if (prog_running)
3002 		terminate = prompt_yes_no(
3003 		            _("The program is running. Exit anyway (y/n)? "),
3004 		            _("y")[0], true, out_fp);
3005 	if (terminate) {
3006 		close_all();
3007 		do_trace = false; 	/* don't save 'trace on' */
3008 
3009 #ifdef HAVE_LIBREADLINE
3010 		if (do_save_history && input_from_tty) {
3011 			int ret;
3012 			ret = write_history(history_file);
3013 			if (ret == 0 && history_length > history_size)
3014 				(void) history_truncate_file(history_file, history_size);
3015 		}
3016 #endif
3017 		if (do_save_options && input_from_tty)
3018 			save_options(options_file);
3019 
3020 		exit(exit_val);
3021 	}
3022 	return false;
3023 }
3024 
3025 /* do_continue --- continue command */
3026 
3027 int
do_continue(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)3028 do_continue(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
3029 {
3030 	BREAKPOINT *b;
3031 
3032 	CHECK_PROG_RUNNING();
3033 	if (! arg || arg->type != D_int)
3034 		return true;
3035 
3036 	/* arg is breakpoint ignore count if stopped at a breakpoint */
3037 	if (! stop.break_point) {
3038 		fprintf(out_fp, _("Not stopped at any breakpoint; argument ignored.\n"));
3039 		return true;
3040 	}
3041 	b = find_breakpoint(stop.break_point);
3042 	if (b == NULL) {
3043 		d_error(_("invalid breakpoint number %d"), stop.break_point);
3044 		return false;
3045 	}
3046 	b->flags |= BP_IGNORE;
3047 	b->ignore_count = arg->a_int;
3048 	fprintf(out_fp, _("Will ignore next %ld crossings of breakpoint %d.\n"),
3049 				b->ignore_count, stop.break_point);
3050 	return true;
3051 }
3052 
3053 /* next_step --- common code for next and step commands */
3054 
3055 static int
next_step(CMDARG * arg,int cmd)3056 next_step(CMDARG *arg, int cmd)
3057 {
3058 	CHECK_PROG_RUNNING();
3059 	if (arg != NULL && arg->type == D_int)
3060 		stop.repeat_count = arg->a_int;
3061 	else
3062 		stop.repeat_count = 1;
3063 	stop.command = (enum argtype) cmd;
3064 	return true;
3065 }
3066 
3067 /* check_step --- process step command, return true if stopping */
3068 
3069 static int
check_step(INSTRUCTION ** pi)3070 check_step(INSTRUCTION **pi)
3071 {
3072 	if (fcall_count != stop.fcall_count) {
3073 		stop.fcall_count = fcall_count;
3074 		stop.sourceline = sourceline;
3075 		stop.source = source;
3076 		stop.print_frame = true;
3077 		return (--stop.repeat_count == 0);
3078 	}
3079 
3080 	if (source != stop.source) {
3081 		stop.source = source;
3082 		stop.sourceline = sourceline;
3083 		return (--stop.repeat_count == 0);
3084 	}
3085 
3086 	if (sourceline != stop.sourceline) {
3087 		stop.sourceline = sourceline;
3088 		return (--stop.repeat_count == 0);
3089 	}
3090 	return false;
3091 }
3092 
3093 /* do_step -- process step command, return true if stopping */
3094 
3095 int
do_step(CMDARG * arg,int cmd)3096 do_step(CMDARG *arg, int cmd)
3097 {
3098 	int ret;
3099 	ret = next_step(arg, cmd);
3100 	if (ret) {
3101 		stop.fcall_count = fcall_count;
3102 		stop.source = source;
3103 		stop.sourceline = sourceline;
3104 		stop.check_func = check_step;
3105 	}
3106 	return ret;
3107 }
3108 
3109 /* do_stepi -- process stepi command, return true if stopping */
3110 
3111 static int
check_stepi(INSTRUCTION ** pi)3112 check_stepi(INSTRUCTION **pi)
3113 {
3114 	return (--stop.repeat_count == 0);
3115 }
3116 
3117 /* do_stepi -- stepi command */
3118 
3119 int
do_stepi(CMDARG * arg,int cmd)3120 do_stepi(CMDARG *arg, int cmd)
3121 {
3122 	int ret;
3123 	ret = next_step(arg, cmd);
3124 	if (ret)
3125 		stop.check_func = check_stepi;
3126 	return ret;
3127 }
3128 
3129 
3130 /* check_next -- process next command returning true if stopping */
3131 
3132 static int
check_next(INSTRUCTION ** pi)3133 check_next(INSTRUCTION **pi)
3134 {
3135 	/* make sure not to step inside function calls */
3136 
3137 	if (fcall_count < stop.fcall_count) {
3138 		stop.fcall_count = fcall_count;
3139 		stop.sourceline = sourceline;
3140 		stop.source = source;
3141 		stop.print_frame = true;
3142 		return (--stop.repeat_count == 0);
3143 	}
3144 
3145 	if (fcall_count == stop.fcall_count) {
3146 		if (source != stop.source) {
3147 			stop.source = source;
3148 			stop.sourceline = sourceline;
3149 			return (--stop.repeat_count == 0);
3150 		}
3151 		if (sourceline != stop.sourceline) {
3152 			stop.sourceline = sourceline;
3153 			return (--stop.repeat_count == 0);
3154 		}
3155 	}
3156 
3157 #if 0
3158 	/* redundant ? */
3159 	if (fcall_count > stop.fcall_count) {
3160 		stop.source = source;
3161 		stop.sourceline = sourceline;
3162 	}
3163 #endif
3164 
3165 	return false;
3166 }
3167 
3168 /* do_next -- next command */
3169 
3170 int
do_next(CMDARG * arg,int cmd)3171 do_next(CMDARG *arg, int cmd)
3172 {
3173 	int ret;
3174 
3175 	ret = next_step(arg, cmd);
3176 	if (ret) {
3177 		stop.source = source;
3178 		stop.sourceline = sourceline;
3179 		stop.fcall_count = fcall_count;
3180 		stop.check_func = check_next;
3181 	}
3182 	return ret;
3183 }
3184 
3185 /* check_nexti --- process nexti command, returns true if stopping */
3186 
3187 static int
check_nexti(INSTRUCTION ** pi)3188 check_nexti(INSTRUCTION **pi)
3189 {
3190 	/* make sure not to step inside function calls */
3191 
3192 	if (fcall_count < stop.fcall_count) {
3193 		stop.print_frame = true;
3194 		stop.fcall_count = fcall_count;
3195 	}
3196 	return (fcall_count == stop.fcall_count
3197 			&& --stop.repeat_count == 0);
3198 }
3199 
3200 /* do_nexti -- nexti command */
3201 
3202 int
do_nexti(CMDARG * arg,int cmd)3203 do_nexti(CMDARG *arg, int cmd)
3204 {
3205 	int ret;
3206 
3207 	ret = next_step(arg, cmd);
3208 	if (ret) {
3209 		stop.fcall_count = fcall_count;
3210 		stop.check_func = check_nexti;
3211 	}
3212 	return ret;
3213 }
3214 
3215 /* check_finish --- process finish command, returns true if stopping */
3216 
3217 static int
check_finish(INSTRUCTION ** pi)3218 check_finish(INSTRUCTION **pi)
3219 {
3220 	if (fcall_count == stop.fcall_count) {
3221 		stop.print_frame = true;
3222 		return true;
3223 	}
3224 	return false;
3225 }
3226 
3227 /* do_finish --- finish command */
3228 
3229 int
do_finish(CMDARG * arg ATTRIBUTE_UNUSED,int cmd)3230 do_finish(CMDARG *arg ATTRIBUTE_UNUSED, int cmd)
3231 {
3232 	CHECK_PROG_RUNNING();
3233 	if (cur_frame == fcall_count) {
3234 		fprintf(out_fp,
3235 			_("'finish' not meaningful in the outermost frame main()\n"));
3236 		return false;
3237 	}
3238 	stop.fcall_count = fcall_count - cur_frame - 1;
3239 	assert(stop.fcall_count >= 0);
3240 	fprintf(out_fp, _("Run until return from "));
3241 	print_numbered_frame(cur_frame);
3242 	stop.check_func = check_finish;
3243 	stop.command = (enum argtype) cmd;
3244 	stop.print_ret = true;
3245 	return true;
3246 }
3247 
3248 /* check_return --- process return, returns true if stopping */
3249 
3250 static int
check_return(INSTRUCTION ** pi)3251 check_return(INSTRUCTION **pi)
3252 {
3253 	assert(fcall_count >= stop.fcall_count);
3254 
3255 	if (fcall_count == stop.fcall_count) {
3256 		stop.print_frame = true;
3257 		return true;
3258 	}
3259 
3260 	if (fcall_count > stop.fcall_count) {	/* innermost frame just returned */
3261 		/* force this one to return too */
3262 		NODE *func;
3263 
3264 		func = find_frame(cur_frame)->func_node;
3265 		assert(func != NULL);
3266 		*pi = (func->code_ptr + 1)->lasti;
3267 		/* assert((*pi)->opcode == Op_K_return); */
3268 	}
3269 
3270 	return false;
3271 }
3272 
3273 /* do_return --- return command */
3274 
3275 int
do_return(CMDARG * arg,int cmd)3276 do_return(CMDARG *arg, int cmd)
3277 {
3278 	NODE *func, *n;
3279 
3280 	CHECK_PROG_RUNNING();
3281 	func = find_frame(cur_frame)->func_node;
3282 	if (func == NULL) {
3283 		fprintf(out_fp, _("'return' not meaningful in the outermost frame main()\n"));
3284 		return false;
3285 	}
3286 
3287 	stop.fcall_count = fcall_count - cur_frame - 1;
3288 	assert(stop.fcall_count >= 0);
3289 	stop.pc = (func->code_ptr + 1)->lasti;
3290 	assert(stop.pc->opcode == Op_K_return);
3291 	stop.command = (enum argtype) cmd;
3292 
3293 	stop.check_func = check_return;
3294 
3295 	if (arg != NULL && arg->type == D_node)	/* optional return value */
3296 		n = dupnode(arg->a_node);
3297 	else
3298 		n = dupnode(Nnull_string);
3299 	PUSH(n);
3300 
3301 	return true;
3302 }
3303 
3304 /* check_until --- process until, returns true if stopping */
3305 
3306 int
check_until(INSTRUCTION ** pi)3307 check_until(INSTRUCTION **pi)
3308 {
3309 	if (fcall_count < stop.fcall_count) { /* current stack frame returned */
3310 		stop.print_frame = true;
3311 		return true;
3312 	} else if (fcall_count == stop.fcall_count) {
3313 		if (stop.pc && *pi == stop.pc)		/* until location */
3314 			return true;
3315 		if (stop.sourceline > 0		/* until */
3316 				&& source == stop.source
3317 				&& sourceline > stop.sourceline)
3318 			return true;
3319 	}
3320 	return false;
3321 }
3322 
3323 /* do_until --- until command */
3324 
3325 int
do_until(CMDARG * arg,int cmd)3326 do_until(CMDARG *arg, int cmd)
3327 {
3328 	SRCFILE *s = cur_srcfile;
3329 	char *src = cur_srcfile->src;
3330 	int lineno;
3331 	INSTRUCTION *rp, *ip;
3332 	NODE *func;
3333 
3334 	CHECK_PROG_RUNNING();
3335 	stop.pc = NULL;
3336 	stop.sourceline = 0;
3337 
3338 	if (arg == NULL) {	/* until without argument */
3339 
3340     /* GDB doc.: continue running until a source line past the current line,
3341      * in the current stack frame, is reached. Is used to avoid single
3342      * stepping through a loop more than once. ...
3343      * This means that when you reach the end of a loop after single
3344      * stepping though it, until makes your program continue execution
3345      * until it exits the loop. In contrast, a next command at the end
3346      * of a loop simply steps back to the beginning of the loop, which
3347      * forces you to step through the next iteration.
3348      */
3349 
3350 		stop.source = source;
3351 		stop.sourceline = sourceline;
3352 		stop.fcall_count = fcall_count - cur_frame;
3353 		stop.check_func = check_until;
3354 		stop.command = (enum argtype) cmd;
3355 		return true;
3356 	}
3357 
3358     /* GDB: until location - continue running program until
3359      * either the specified location is reached, or the
3360      * current stack frame returns.
3361      */
3362 
3363 	switch (arg->type) {
3364 	case D_string:	/* until filename : lineno|function */
3365 		s = source_find(arg->a_string);
3366 		arg = arg->next;
3367 		if (s == NULL || arg == NULL
3368 				|| (arg->type != D_int && arg->type != D_func))
3369 			return false;
3370 		src = s->src;
3371 		if (arg->type == D_func)
3372 			goto func;
3373 		/* else
3374 			fall through */
3375 	case D_int:	/* until lineno */
3376 		lineno = arg->a_int;
3377 		if (lineno <= 0 || lineno > s->srclines) {
3378 			d_error(_("line number %d in file `%s' out of range"),
3379 						lineno, src);
3380 			return false;
3381 		}
3382 		break;
3383 
3384 	case D_func:	/* until function */
3385 func:
3386 		func = arg->a_node;
3387 		rp = func->code_ptr;
3388 		for (ip = rp->nexti; ip; ip = ip->nexti) {
3389 			if (ip->opcode != Op_breakpoint && ip->source_line > 0) {
3390 				stop.pc = ip;
3391 				stop.fcall_count = fcall_count - cur_frame;
3392 				stop.check_func = check_until;
3393 				stop.command = (enum argtype) cmd;
3394 				return true;
3395 			}
3396 		}
3397 		fprintf(out_fp, _("cannot find specified location in function `%s'\n"),
3398 				func->vname);
3399 		/* fall through */
3400 	default:
3401 		return false;
3402 	}
3403 
3404 	if ((rp = find_rule(src, lineno)) == NULL) {
3405 		d_error(_("invalid source line %d in file `%s'"), lineno, src);
3406 		return false;
3407 	}
3408 
3409 	for (ip = rp->nexti; ip; ip = ip->nexti) {
3410 		if (ip->opcode != Op_breakpoint && ip->source_line >= lineno) {
3411 			stop.pc = ip;
3412 			stop.fcall_count = fcall_count - cur_frame;
3413 			stop.check_func = check_until;
3414 			stop.command = (enum argtype) cmd;
3415 			return true;
3416 		}
3417 		if (ip == (rp + 1)->lasti)
3418 			break;
3419 	}
3420 	fprintf(out_fp, _("cannot find specified location %d in file `%s'\n"),
3421 				lineno, src);
3422 	return false;
3423 }
3424 
3425 /* print_watch_item --- print watched item name, old and current values */
3426 
3427 static void
print_watch_item(struct list_item * w)3428 print_watch_item(struct list_item *w)
3429 {
3430 	NODE *symbol, *sub;
3431 	int i;
3432 
3433 	symbol = w->symbol;
3434 	if (IS_SUBSCRIPT(w)) {
3435 		fprintf(out_fp, "%s", w->sname);
3436 		for (i = 0; i < w->num_subs; i++) {
3437 			sub = w->subs[i];
3438 			fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
3439 		}
3440 		fprintf(out_fp, "\n");
3441 	} else if (IS_FIELD(w))
3442 		fprintf(out_fp, "$%ld\n", get_number_si(symbol));
3443 	else
3444 		fprintf(out_fp, "%s\n", w->sname);
3445 
3446 
3447 #define print_value(X, S, V)                                        \
3448 if (X)                                                              \
3449 	fprintf(out_fp, "array, %ld elements\n", w->S);                 \
3450 else if (! w->V)                                                    \
3451 	fprintf(out_fp, IS_SUBSCRIPT(w) ?                               \
3452 			_("element not in array\n") : _("untyped variable\n")); \
3453 else                                                                \
3454 	valinfo(w->V, fprintf, out_fp);
3455 
3456 	fprintf(out_fp, "  Old value: ");
3457 	print_value((w->flags & OLD_IS_ARRAY) != 0, old_size, old_value);
3458 	fprintf(out_fp, "  New value: ");
3459 	print_value((w->flags & CUR_IS_ARRAY) != 0, cur_size, cur_value);
3460 
3461 #undef print_value
3462 }
3463 
3464 /* next_command --- (optionally) print stoppage location and reason;
3465  *                  also fetch next debug command from the user.
3466  */
3467 
3468 static void
next_command()3469 next_command()
3470 {
3471 	static int last_rule = 0;
3472 	struct list_item *d = NULL, *w = NULL;
3473 	BREAKPOINT *b = NULL;
3474 	SRCFILE *s;
3475 
3476 	if (source == NULL) {
3477 		stop.command = D_illegal;
3478 		stop.check_func = NULL;
3479 		return;
3480 	}
3481 
3482 	if (stop.break_point) {
3483 		b = find_breakpoint(stop.break_point);
3484 		assert(b != NULL);
3485 		if (b->silent)
3486 			goto no_output;
3487 	} else if (stop.watch_point) {
3488 		w = find_item(&watch_list, stop.watch_point);
3489 		if (w->silent)
3490 			goto no_output;
3491 	}
3492 
3493 	if (cur_rule != last_rule) {
3494 		fprintf(out_fp, _("Stopping in %s ...\n"), ruletab[cur_rule]);
3495 		last_rule = cur_rule;
3496 	}
3497 
3498 	if (b != NULL)
3499 		fprintf(out_fp, "Breakpoint %d, ", b->number);
3500 	else if (w != NULL) {
3501 		fprintf(out_fp, "Watchpoint %d: ", w->number);
3502 		print_watch_item(w);
3503 	}
3504 
3505 	/* frame info */
3506 	if (stop.print_frame) {
3507 		print_frame(frame_ptr->func_node, source, sourceline);
3508 		fprintf(out_fp, "\n");
3509 		stop.print_frame = false;
3510 	}
3511 
3512 	(void) print_lines(source, sourceline, 1);
3513 
3514 	/* automatic display of variables */
3515 	for (d = display_list.prev; d != &display_list; d = d->prev)
3516 		display(d);
3517 
3518 no_output:
3519 	/* update last_printed_line, so that  output of 'list' is
3520 	 * centered around current sourceline
3521 	 */
3522 
3523 	last_printed_line = sourceline - list_size / 2;
3524 	if (last_printed_line < 0)
3525 		last_printed_line = 0;
3526 
3527 	/* update current source file */
3528 	s = source_find(source);
3529 	if (cur_srcfile != s) {
3530 		if (cur_srcfile->fd != INVALID_HANDLE) {
3531 			close(cur_srcfile->fd);
3532 			cur_srcfile->fd = INVALID_HANDLE;
3533 		}
3534 		cur_srcfile = s;
3535 	}
3536 
3537 	stop.command = D_illegal;
3538 	stop.check_func = NULL;
3539 
3540 	if (b != NULL) {
3541 		int ret;
3542 		ret = execute_commands(&b->commands);
3543 		if ((b->flags & BP_TEMP) != 0)
3544 			delete_breakpoint(b);
3545 		if (ret)	/* resume execution */
3546 			return;
3547 	} else if (w != NULL && execute_commands(&w->commands))
3548 		return;
3549 
3550 	read_command();		/* zzparse */
3551 }
3552 
3553 /* debug_post_execute --- post_hook in the interpreter */
3554 
3555 static void
debug_post_execute(INSTRUCTION * pc)3556 debug_post_execute(INSTRUCTION *pc)
3557 {
3558 	if (! in_main_context())
3559 		return;
3560 
3561 	switch (pc->opcode) {
3562 	case Op_K_next:
3563 	case Op_K_nextfile:
3564 	case Op_K_exit:
3565 		if (stop.command == D_finish) {
3566 			/* cancel finish command */
3567 			stop.print_ret = false;
3568 			stop.print_frame = false;
3569 			stop.command = D_illegal;
3570 			stop.check_func = NULL;
3571 			fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"),
3572 							op2str(pc->opcode));
3573 		} else if (stop.command == D_until) {
3574 			/* cancel until command */
3575 			stop.print_frame = false;
3576 			stop.command = D_illegal;
3577 			stop.check_func = NULL;
3578 			fprintf(out_fp, _("'until' not meaningful with non-local jump '%s'\n"),
3579 							op2str(pc->opcode));
3580 		}
3581 		break;
3582 
3583 	case Op_K_return:
3584 		if (stop.command == D_finish
3585 				&& fcall_count == stop.fcall_count
3586 				&& stop.print_ret
3587 		) {
3588 			NODE *r;
3589 			/* print the returned value before it disappears. */
3590 			r = TOP();
3591 			fprintf(out_fp, "Returned value = ");
3592 			valinfo(r, fprintf, out_fp);
3593 			stop.print_ret = false;
3594 		}
3595 		break;
3596 
3597 	case Op_newfile:
3598 	case Op_get_record:
3599 		return;
3600 
3601 	default:
3602 		break;
3603 	}
3604 }
3605 
3606 /* debug_pre_execute --- pre_hook, called by the interpreter before execution;
3607  *                 checks if execution needs to be suspended and control
3608  *                 transferred to the debugger.
3609  */
3610 
3611 static int
debug_pre_execute(INSTRUCTION ** pi)3612 debug_pre_execute(INSTRUCTION **pi)
3613 {
3614 	static bool cant_stop = false;
3615 	NODE *m;
3616 
3617 	if (! in_main_context())
3618 		return pre_execute_code(pi);
3619 
3620 	cur_pc = *pi;
3621 	stop.break_point = 0;
3622 	stop.watch_point = 0;
3623 	cur_frame = 0;
3624 
3625 	if (do_trace
3626 		&& cur_pc->opcode != Op_breakpoint
3627 		&& stop.command != D_return
3628 	)
3629 		print_instruction(cur_pc, fprintf, out_fp, false);
3630 
3631 /* N.B.: For Op_field_spec_lhs must execute instructions upto Op_field_assign
3632  * as a group before stopping. Otherwise, watch/print of field variables
3633  * yield surprising results. Ditto for Op_push_lhs for special variables
3634  * (upto Op_var_assign, the set_FOO routine).
3635  */
3636 
3637 	switch (cur_pc->opcode) {
3638 	case Op_field_spec_lhs:
3639 		cant_stop = true;
3640 		break;
3641 
3642 	case Op_field_assign:
3643 		cant_stop = false;
3644 		return true; /* may stop at next instruction */
3645 
3646 	case Op_push_lhs:
3647 		m = cur_pc->memory;
3648 		if (m->type == Node_var && m->var_assign)
3649 			cant_stop = true;
3650 		break;
3651 
3652 	case Op_arrayfor_incr:	/* can have special var as array variable !!! */
3653 		m = cur_pc->array_var;
3654 		if (m->type == Node_var && m->var_assign)
3655 			cant_stop = true;
3656 		break;
3657 
3658 	case Op_var_assign:
3659 		cant_stop = false;
3660 		return true; /* may stop at next instruction */
3661 
3662 	case Op_rule:
3663 		cur_rule = cur_pc->in_rule;
3664 		return true;
3665 
3666 	case Op_func:
3667 	case Op_var_update:
3668 		return true;
3669 
3670 	case Op_breakpoint:
3671 		break;	/* processed later in check_breakpoint() */
3672 
3673 	default:
3674 		if (cur_pc->source_line <= 0)
3675 			return true;
3676 		break;
3677 	}
3678 
3679 	if (cant_stop)
3680 		return true;
3681 
3682 	assert(sourceline > 0);
3683 
3684 	/*
3685 	 * 11/2015: This used to check breakpoints first, but that could
3686 	 * produce strange behavior, where a watchpoint doesn't print until
3687 	 * some time after the data changed.  This reworks things so that
3688 	 * watchpoints are checked first. It's a bit of a hack, but
3689 	 * the behavior for the user is more logical.
3690 	 */
3691 	if (check_watchpoint()) {
3692 		next_command();	/* return to debugger interface */
3693 		if (stop.command == D_return)
3694 			*pi = stop.pc;	/* jump to this instruction */
3695 		else if (cur_pc->opcode == Op_breakpoint)
3696 			cur_pc = cur_pc->nexti;    /* skip past the breakpoint instruction */
3697 	} else if (check_breakpoint(pi)
3698 			|| (stop.check_func && stop.check_func(pi))) {
3699 		next_command();	/* return to debugger interface */
3700 		if (stop.command == D_return)
3701 			*pi = stop.pc;	/* jump to this instruction */
3702 	}
3703 
3704 	/* if cur_pc == *pi, interpreter executes cur_pc;
3705 	 * Otherwise, jumps to instruction *pi.
3706 	 */
3707 	return (cur_pc == *pi);
3708 }
3709 
3710 /* print_memory --- print a scalar value */
3711 
3712 static void
print_memory(NODE * m,NODE * func,Func_print print_func,FILE * fp)3713 print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
3714 {
3715 	switch (m->type) {
3716 	case Node_val:
3717 		if (m == Nnull_string)
3718 			print_func(fp, "Nnull_string");
3719 		else if ((m->flags & NUMBER) != 0) {
3720 #ifdef HAVE_MPFR
3721 			if ((m->flags & MPFN) != 0)
3722 				print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
3723 			else if ((m->flags & MPZN) != 0)
3724 				print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
3725 			else
3726 #endif
3727 				print_func(fp, "%g", m->numbr);
3728 		} else if ((m->flags & STRING) != 0)
3729 			pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
3730 		else if ((m->flags & REGEX) != 0) {
3731 			print_func(fp, "@");
3732 			pp_string_fp(print_func, fp, m->stptr, m->stlen, '/', false);
3733 		} else
3734 			print_func(fp, "-?-");
3735 		print_func(fp, " [%s]", flags2str(m->flags));
3736 		break;
3737 
3738 	case Node_regex:
3739 		pp_string_fp(print_func, fp, m->re_exp->stptr, m->re_exp->stlen, '/', false);
3740 		break;
3741 
3742 	case Node_dynregex:
3743 		break;
3744 
3745 	case Node_param_list:
3746 		assert(func != NULL);
3747 		print_func(fp, "%s", func->fparms[m->param_cnt].param);
3748 		break;
3749 
3750 	case Node_var:
3751 	case Node_var_new:
3752 	case Node_var_array:
3753 		print_func(fp, "%s", m->vname);
3754 		break;
3755 
3756 	default:
3757 		print_func(fp, "?");  /* can't happen */
3758 	}
3759 }
3760 
3761 /* print_instruction --- print a bytecode */
3762 
3763 static void
print_instruction(INSTRUCTION * pc,Func_print print_func,FILE * fp,int in_dump)3764 print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
3765 {
3766 	int pcount = 0;
3767 	static NODE *func = NULL;
3768 	static int noffset = 0;
3769 
3770 	if (noffset == 0) {
3771 		static char buf[50];
3772 		/* offset for 2nd to last lines in a multi-line output */
3773 		noffset = sprintf(buf, "[      :" PTRFMT "] %-20.20s: ", (void *) pc,
3774 				opcode2str(pc->opcode));
3775 	}
3776 
3777 	if (pc->opcode == Op_func) {
3778 		func = pc->func_body;
3779 		pcount = func->param_cnt;
3780 		if (in_dump) {
3781 			int j;
3782 			print_func(fp, "\n\t# Function: %s (", func->vname);
3783 			for (j = 0; j < pcount; j++) {
3784 				print_func(fp, "%s", func->fparms[j].param);
3785 				if (j < pcount - 1)
3786 					print_func(fp, ", ");
3787 			}
3788 			print_func(fp, ")\n\n");
3789 		}
3790 	} else if (pc->opcode == Op_rule) {
3791 		if (in_dump)
3792 			print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]);
3793 	}
3794 
3795 	if (pc->opcode == Op_newfile)
3796 		print_func(fp, "\n");
3797 
3798 	if (pc->source_line <= 0)
3799 		print_func(fp, "[      :" PTRFMT "] %-20.20s: ", pc, opcode2str(pc->opcode));
3800 	else
3801 		print_func(fp, "[%6d:" PTRFMT "] %-20.20s: ",
3802 		                pc->source_line, pc, opcode2str(pc->opcode));
3803 
3804 	if (prog_running && ! in_dump) {
3805 		/* find Node_func if in function */
3806 		func = find_frame(0)->func_node;
3807 	}
3808 
3809 
3810 	switch (pc->opcode) {
3811 	case Op_K_if:
3812 		print_func(fp, "[branch_if = " PTRFMT "] [branch_else = " PTRFMT "] [branch_else->lasti = " PTRFMT "]\n",
3813 				pc->branch_if, pc->branch_else, pc->branch_else->lasti);
3814 		break;
3815 
3816 	case Op_K_else:
3817 		print_func(fp, "[branch_end = " PTRFMT "]\n", pc->branch_end);
3818 		break;
3819 
3820 	case Op_K_while:
3821 		print_func(fp, "[while_body = " PTRFMT "] [target_break = " PTRFMT "]\n", (pc+1)->while_body, pc->target_break);
3822 		break;
3823 
3824 	case Op_K_do:
3825 		print_func(fp, "[doloop_cond = " PTRFMT "] [target_break = " PTRFMT "]", (pc+1)->doloop_cond, pc->target_break);
3826 		if (pc->comment)
3827 			print_func(fp, " [comment = " PTRFMT "]", pc->comment);
3828 		print_func(fp, "\n");
3829 		if (pc->comment)
3830 			print_instruction(pc->comment, print_func, fp, in_dump);
3831 		break;
3832 
3833 	case Op_K_for:
3834 		print_func(fp, "[forloop_cond = " PTRFMT "] ", (pc+1)->forloop_cond);
3835 		/* fall through */
3836 	case Op_K_arrayfor:
3837 		print_func(fp, "[forloop_body = " PTRFMT "] ", (pc+1)->forloop_body);
3838 		print_func(fp, "[target_break = " PTRFMT "] [target_continue = " PTRFMT "]", pc->target_break, pc->target_continue);
3839 		if (pc->comment != NULL) {
3840 			print_func(fp, " [comment = " PTRFMT "]\n", (pc)->comment);
3841 			print_instruction(pc->comment, print_func, fp, in_dump);
3842 		} else
3843 			print_func(fp, "\n");
3844 		break;
3845 
3846 	case Op_K_switch:
3847 	{
3848 		bool need_newline = false;
3849 		print_func(fp, "[switch_start = " PTRFMT "] [switch_end = " PTRFMT "]\n", (pc+1)->switch_start, (pc+1)->switch_end);
3850 		if (pc->comment || (pc+1)->switch_end->comment)
3851 			print_func(fp, "%*s", noffset, "");
3852 		if (pc->comment) {
3853 			print_func(fp, "[start_comment = " PTRFMT "]", pc->comment);
3854 			need_newline = true;
3855 		}
3856 		if ((pc+1)->switch_end->comment) {
3857 			print_func(fp, "[end_comment = " PTRFMT "]", (pc + 1)->switch_end->comment);
3858 			need_newline = true;
3859 		}
3860 		if (need_newline)
3861 			print_func(fp, "\n");
3862 		if (pc->comment)
3863 			print_instruction(pc->comment, print_func, fp, in_dump);
3864 		if ((pc+1)->switch_end->comment)
3865 			print_instruction((pc+1)->switch_end->comment, print_func, fp, in_dump);
3866 	}
3867 		break;
3868 
3869 	case Op_K_default:
3870 		print_func(fp, "[stmt_start = " PTRFMT "] [stmt_end = " PTRFMT "]", pc->stmt_start, pc->stmt_end);
3871 		if (pc->comment) {
3872 			print_func(fp, " [comment = " PTRFMT "]\n", pc->comment);
3873 			print_instruction(pc->comment, print_func, fp, in_dump);
3874 		} else
3875 			print_func(fp, "\n");
3876 		break;
3877 
3878 	case Op_var_update:
3879 		print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var));
3880 		break;
3881 
3882 	case Op_var_assign:
3883 		print_func(fp, "[set_%s()]", get_spec_varname(pc->assign_var));
3884 		if (pc->assign_ctxt != 0)
3885 			print_func(fp, " [assign_ctxt = %s]", opcode2str((OPCODE) pc->assign_ctxt));
3886 		print_func(fp, "\n");
3887 		break;
3888 
3889 	case Op_field_assign:
3890 		print_func(fp, "[%s]\n", pc->field_assign == reset_record ?
3891 					"reset_record()" : "invalidate_field0()");
3892 		break;
3893 
3894 	case Op_field_spec_lhs:
3895 		print_func(fp, "[target_assign = " PTRFMT "] [do_reference = %s]\n",
3896 				pc->target_assign, pc->do_reference ? "true" : "false");
3897 		break;
3898 
3899 	case Op_func:
3900 		print_func(fp, "[param_cnt = %d] [source_file = %s]", pcount,
3901 				pc->source_file ? pc->source_file : "cmd. line");
3902 		if (pc[3].nexti != NULL) {
3903 			print_func(fp, "[ns_list = " PTRFMT "]\n", pc[3].nexti);
3904 			print_ns_list(pc[3].nexti, print_func, fp, in_dump);
3905 		} else
3906 			print_func(fp, "\n");
3907 		break;
3908 
3909 	case Op_K_getline_redir:
3910 		print_func(fp, "[into_var = %s] [redir_type = \"%s\"]\n",
3911 		                pc->into_var ? "true" : "false",
3912 		                redir2str(pc->redir_type));
3913 		break;
3914 
3915 	case Op_K_getline:
3916 		print_func(fp, "[into_var = %s]\n", pc->into_var ? "true" : "false");
3917 		print_func(fp, "%*s[target_beginfile = " PTRFMT "] [target_endfile = " PTRFMT "]\n",
3918 		                noffset, "",
3919 		                (pc + 1)->target_beginfile, (pc + 1)->target_endfile);
3920 		break;
3921 
3922 	case Op_K_print_rec:
3923 		print_func(fp, "[redir_type = \"%s\"]\n", redir2str(pc->redir_type));
3924 		break;
3925 
3926 	case Op_K_print:
3927 	case Op_K_printf:
3928 		print_func(fp, "[expr_count = %ld] [redir_type = \"%s\"]\n",
3929 		                pc->expr_count, redir2str(pc->redir_type));
3930 		break;
3931 
3932 	case Op_indirect_func_call:
3933 	case Op_func_call:
3934 		print_func(fp, "[func_name = %s] [arg_count = %ld]\n",
3935 		                pc->func_name, (pc + 1)->expr_count);
3936 		break;
3937 
3938 	case Op_K_nextfile:
3939 		print_func(fp, "[target_newfile = " PTRFMT "] [target_endfile = " PTRFMT "]\n",
3940 		                pc->target_newfile, pc->target_endfile);
3941 		break;
3942 
3943 	case Op_newfile:
3944 		print_func(fp, "[target_jmp = " PTRFMT "] [target_endfile = " PTRFMT "]\n",
3945 		                pc->target_jmp, pc->target_endfile);
3946 		print_func(fp, "%*s[target_get_record = " PTRFMT "]\n",
3947 		                noffset, "", (pc + 1)->target_get_record);
3948 		break;
3949 
3950 	case Op_get_record:
3951 		print_func(fp, "[target_newfile = " PTRFMT "]\n", pc->target_newfile);
3952 		break;
3953 
3954 	case Op_jmp:
3955 	case Op_jmp_false:
3956 	case Op_jmp_true:
3957 	case Op_and:
3958 	case Op_or:
3959 	case Op_K_next:
3960 	case Op_arrayfor_init:
3961 	case Op_K_break:
3962 	case Op_K_continue:
3963 		print_func(fp, "[target_jmp = " PTRFMT "]\n", pc->target_jmp);
3964 		break;
3965 
3966 	case Op_K_exit:
3967 		print_func(fp, "[target_end = " PTRFMT "] [target_atexit = " PTRFMT "]\n",
3968 						pc->target_end, pc->target_atexit);
3969 		break;
3970 
3971 	case Op_K_case:
3972 		print_func(fp, "[target_jmp = " PTRFMT "] [match_exp = %s]",
3973 						pc->target_jmp,	(pc + 1)->match_exp ? "true" : "false");
3974 		if (pc->comment) {
3975 			print_func(fp, " [comment = " PTRFMT "]\n", pc->comment);
3976 			print_instruction(pc->comment, print_func, fp, in_dump);
3977 		} else
3978 			print_func(fp, "\n");
3979 		break;
3980 
3981 	case Op_K_namespace:
3982 		print_func(fp, "[namespace = %s]", pc->ns_name);
3983 		if (pc->nexti)
3984 			print_func(fp, "[nexti = " PTRFMT "]", pc->nexti);
3985 		if (pc->comment)
3986 			print_func(fp, "[comment = " PTRFMT "]", pc->comment);
3987 		print_func(fp, "\n");
3988 		break;
3989 
3990 	case Op_arrayfor_incr:
3991 		print_func(fp, "[array_var = %s] [target_jmp = " PTRFMT "]\n",
3992 		                pc->array_var->type == Node_param_list ?
3993 		                   func->fparms[pc->array_var->param_cnt].param : pc->array_var->vname,
3994 		                pc->target_jmp);
3995 		break;
3996 
3997 	case Op_line_range:
3998 		print_func(fp, "[triggered = %ld] [target_jmp = " PTRFMT "]\n",
3999 		                pc->triggered, pc->target_jmp);
4000 		break;
4001 
4002 	case Op_cond_pair:
4003 		print_func(fp, "[line_range = " PTRFMT "] [target_jmp = " PTRFMT "]\n",
4004 		                pc->line_range, pc->target_jmp);
4005 		break;
4006 
4007 	case Op_sub_builtin:
4008 	{
4009 		const char *fname = "sub";
4010 		static const struct flagtab values[] = {
4011 			{ GSUB, "GSUB" },
4012 			{ GENSUB, "GENSUB" },
4013 			{ LITERAL, "LITERAL" },
4014 			{ 0, NULL }
4015 		};
4016 
4017 		if ((pc->sub_flags & GSUB) != 0)
4018 			fname = "gsub";
4019 		else if ((pc->sub_flags & GENSUB) != 0)
4020 			fname = "gensub";
4021 		print_func(fp, "%s [arg_count = %ld] [sub_flags = %s]\n",
4022 				fname, pc->expr_count,
4023 				genflags2str(pc->sub_flags, values));
4024 	}
4025 		break;
4026 
4027 	case Op_builtin:
4028 		print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin, false),
4029 						pc->expr_count);
4030 		break;
4031 
4032 	case Op_ext_builtin:
4033 		print_func(fp, "%s [arg_count = %ld]\n", (pc + 1)->func_name,
4034 						pc->expr_count);
4035 		break;
4036 
4037 	case Op_subscript:
4038 	case Op_sub_array:
4039 		print_func(fp, "[sub_count = %ld]\n", pc->sub_count);
4040 		break;
4041 
4042 	case Op_store_sub:
4043 		print_memory(pc->memory, func, print_func, fp);
4044 		print_func(fp, " [sub_count = %ld]\n", pc->expr_count);
4045 		break;
4046 
4047 	case Op_subscript_lhs:
4048 		print_func(fp, "[sub_count = %ld] [do_reference = %s]\n",
4049 		                pc->sub_count,
4050 		                pc->do_reference ? "true" : "false");
4051 		break;
4052 
4053 	case Op_K_delete:
4054 	case Op_in_array:
4055 		print_func(fp, "[expr_count = %ld]\n", pc->expr_count);
4056 		break;
4057 
4058 	case Op_concat:
4059 		/* NB: concat_flag CSVAR only used in grammar, don't display it */
4060 		print_func(fp, "[expr_count = %ld] [concat_flag = %s]\n",
4061 						pc->expr_count,
4062 						(pc->concat_flag & CSUBSEP) != 0 ? "CSUBSEP" : "0");
4063 		break;
4064 
4065 	case Op_rule:
4066 		print_func(fp, "[in_rule = %s] [source_file = %s]",
4067 		                ruletab[pc->in_rule],
4068 		                pc->source_file ? pc->source_file : "cmd. line");
4069 		if (pc[3].nexti != NULL) {
4070 			print_func(fp, "[ns_list = " PTRFMT "]\n", pc[3].nexti);
4071 			print_ns_list(pc[3].nexti, print_func, fp, in_dump);
4072 		} else
4073 			print_func(fp, "\n");
4074 		break;
4075 
4076 	case Op_lint:
4077 	{
4078 		static const char *const linttypetab[] = {
4079 			"LINT_illegal",
4080 			"LINT_assign_in_cond",
4081 			"LINT_no_effect"
4082 		};
4083 		print_func(fp, "[lint_type = %s]\n", linttypetab[pc->lint_type]);
4084 	}
4085 		break;
4086 
4087 	case Op_exec_count:
4088 		print_func(fp, "[exec_count = " EXEC_COUNT_FMT "]\n", pc->exec_count);
4089 		break;
4090 
4091  	case Op_store_var:
4092 		print_memory(pc->memory, func, print_func, fp);
4093 		if (pc->initval != NULL) {
4094 			print_func(fp, " = ");
4095 			print_memory(pc->initval, func, print_func, fp);
4096 		}
4097 		print_func(fp, "\n");
4098 		break;
4099 
4100 	case Op_push_lhs:
4101 		print_memory(pc->memory, func, print_func, fp);
4102 		print_func(fp, " [do_reference = %s]\n",
4103 		                pc->do_reference ? "true" : "false");
4104 		break;
4105 
4106 	case Op_comment:
4107 		print_memory(pc->memory, func, print_func, fp);
4108 		print_func(fp, " [comment_type = %s]",
4109 			pc->memory->comment_type == EOL_COMMENT ?
4110 						"EOL" : "BLOCK");
4111 		if (pc->comment) {
4112 			print_func(fp, " [comment = " PTRFMT "]\n", pc->comment);
4113 			print_instruction(pc->comment, print_func, fp, in_dump);
4114 		} else
4115 			print_func(fp, "\n");
4116 		break;
4117 
4118 	case Op_push_i:
4119 	case Op_push:
4120 	case Op_push_arg:
4121 	case Op_push_arg_untyped:
4122 	case Op_push_param:
4123 	case Op_push_array:
4124 	case Op_push_re:
4125 	case Op_match_rec:
4126 	case Op_match:
4127 	case Op_nomatch:
4128 	case Op_plus_i:
4129 	case Op_minus_i:
4130 	case Op_times_i:
4131 	case Op_exp_i:
4132 	case Op_quotient_i:
4133 	case Op_mod_i:
4134 	case Op_assign_concat:
4135 		print_memory(pc->memory, func, print_func, fp);
4136 		/* fall through */
4137 	default:
4138 		print_func(fp, "\n");
4139 		break;
4140 	}
4141 }
4142 
4143 /* do_trace_instruction --- trace command */
4144 
4145 int
do_trace_instruction(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)4146 do_trace_instruction(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4147 {
4148 	if (arg != NULL && arg->type == D_argument
4149 			&& arg->a_argument == A_TRACE_ON)
4150 		do_trace = true;
4151 	else
4152 		do_trace = false;
4153 	return false;
4154 }
4155 
4156 /* print_code --- print a list of instructions */
4157 
4158 static int
print_code(INSTRUCTION * pc,void * x)4159 print_code(INSTRUCTION *pc, void *x)
4160 {
4161 	struct pf_data *data = (struct pf_data *) x;
4162 	for (; pc != NULL; pc = pc->nexti)
4163 		print_instruction(pc, data->print_func, data->fp, data->defn /* in_dump */);
4164 	return 0;
4165 }
4166 
4167 /* print_ns_list --- print the list of namespaces */
4168 
4169 static void
print_ns_list(INSTRUCTION * pc,Func_print print_func,FILE * fp,int in_dump)4170 print_ns_list(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
4171 {
4172 	for (; pc != NULL; pc = pc->nexti) {
4173 		print_instruction(pc, print_func, fp, in_dump);
4174 		if (pc->comment != NULL)
4175 			print_instruction(pc->comment, print_func, fp, in_dump);
4176 	}
4177 }
4178 
4179 /* do_dump_instructions --- dump command */
4180 
4181 int
do_dump_instructions(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)4182 do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4183 {
4184 	FILE *fp;
4185   	NODE **funcs;
4186 
4187 	if (arg != NULL && arg->type == D_string) {
4188 		/* dump to a file */
4189 		if ((fp = fopen(arg->a_string, "w")) == NULL) {
4190 			d_error(_("could not open `%s' for writing: %s"),
4191 					arg->a_string, strerror(errno));
4192 			return false;
4193 		}
4194 		pf_data.print_func = fprintf;
4195 		pf_data.fp = fp;
4196 		pf_data.defn = true;	/* in_dump = true */
4197 		(void) print_code(code_block, &pf_data);
4198 		funcs = function_list(true);
4199 		(void) foreach_func(funcs,
4200 		                     (int (*)(INSTRUCTION *, void *)) print_code,
4201 		                     &pf_data);
4202 		efree(funcs);
4203 		fclose(fp);
4204 		return false;
4205 	}
4206 
4207 	funcs = function_list(true);
4208 	initialize_pager(out_fp);
4209 	if (setjmp(pager_quit_tag) == 0) {
4210 		pf_data.print_func = gprintf;
4211 		pf_data.fp = out_fp;
4212 		pf_data.defn = true;	/* in_dump = true */
4213 		(void) print_code(code_block, &pf_data);
4214 		(void) foreach_func(funcs,
4215 		                    (int (*)(INSTRUCTION *, void *)) print_code,
4216 		                     &pf_data);
4217 	}
4218 	efree(funcs);
4219 	return false;
4220 }
4221 
4222 /* do_save --- save command */
4223 
4224 int
do_save(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)4225 do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4226 {
4227 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
4228 	FILE *fp;
4229 	HIST_ENTRY **hist_list;
4230 	int i;
4231 
4232 	if ((fp = fopen(arg->a_string, "w")) == NULL) {
4233 		d_error(_("could not open `%s' for writing: %s"),
4234 				arg->a_string, strerror(errno));
4235 		return false;
4236 	}
4237 
4238 	hist_list = history_list();
4239 	if (hist_list && history_length > sess_history_base) {
4240 		for (i = sess_history_base; hist_list[i] != NULL; i++) {
4241 			char *line;
4242 			line = hist_list[i]->line;
4243 
4244 			/* exclude save commands;
4245 			 * N.B.: this test may fail if there is another
4246 			 * command with the same first 2 letters.
4247 			 */
4248 
4249 			if (strlen(line) > 1
4250 			    && strncmp(line, "sa", 2) == 0)
4251 				continue;
4252 
4253 			fprintf(fp, "%s\n", line);
4254 		}
4255 	}
4256 	fclose(fp);
4257 #endif
4258 	return false;
4259 }
4260 
4261 /* do_option --- option command */
4262 
4263 int
do_option(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)4264 do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4265 {
4266 	const struct dbg_option *opt;
4267 	char *name, *value;
4268 
4269 	if (arg == NULL) {	/* display all available options and corresponding values */
4270 		for (opt = option_list; opt->name; opt++) {
4271 			if (opt->str_val != NULL)
4272 				fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4273 			else
4274 				fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4275 		}
4276 		return false;
4277 	}
4278 
4279 	name = arg->a_string;
4280 	arg = arg->next;
4281 	value = arg ? arg->a_string : NULL;
4282 
4283 	for (opt = option_list; opt->name; opt++) {	/* linear search */
4284 		if (strcmp(name, opt->name) == 0)
4285 			break;
4286 	}
4287 	if (! opt->name)
4288 		return false;
4289 
4290 	if (value == NULL) {	/* display current setting */
4291 		if (opt->str_val != NULL)
4292 			fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4293 		else
4294 			fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4295 	} else
4296 		(*(opt->assign))(value);
4297 	return false;
4298 }
4299 
4300 
4301 #ifdef HAVE_LIBREADLINE
4302 
4303 /* initialize_pager --- initialize our idea of the terminal size */
4304 
4305 void
initialize_pager(FILE * fp)4306 initialize_pager(FILE *fp)
4307 {
4308 	if (! os_isatty(fileno(fp)) || ! input_from_tty || input_fd != 0) {
4309 		screen_width = INT_MAX;
4310 		screen_height = INT_MAX;
4311 	} else {
4312 		/* get the terminal size from readline. */
4313 
4314 		rl_reset_terminal(NULL); /* N.B.: NULL argument means
4315 		                          * "use TERM env variable for terminal name".
4316 		                          */
4317 		rl_get_screen_size(&screen_height, &screen_width);
4318 		if (screen_height <= 1)
4319 			screen_height = INT_MAX;
4320 		if (screen_width <= 1)
4321 			screen_width = INT_MAX;
4322 	}
4323 	pager_lines_printed = 0;
4324 }
4325 #endif
4326 
4327 static void
prompt_continue(FILE * fp)4328 prompt_continue(FILE *fp)
4329 {
4330 	bool quit_pager = false;
4331 
4332 	if (os_isatty(fileno(fp)) && input_fd == 0)
4333 		quit_pager = prompt_yes_no(
4334 			// TRANSLATORS: don't translate the 'q' inside the brackets.
4335 	                _("\t------[Enter] to continue or [q] + [Enter] to quit------"),
4336 	                'q', false, fp);
4337 	if (quit_pager)
4338 		longjmp(pager_quit_tag, 1);
4339 	pager_lines_printed = 0;
4340 }
4341 
4342 /* gprintf --- like fprintf but allows paging */
4343 
4344 int
gprintf(FILE * fp,const char * format,...)4345 gprintf(FILE *fp, const char *format, ...)
4346 {
4347 	va_list args;
4348 	static char *buf = NULL;
4349 	static size_t buflen = 0;
4350 	static int bl = 0;
4351 	char *p, *q;
4352 	int nchar;
4353 
4354 #define GPRINTF_BUFSIZ 512
4355 	if (buf == NULL) {
4356 		buflen = GPRINTF_BUFSIZ;
4357 		emalloc(buf, char *, buflen * sizeof(char), "gprintf");
4358 	} else if (buflen - bl < GPRINTF_BUFSIZ/2) {
4359 		buflen += GPRINTF_BUFSIZ;
4360 		erealloc(buf, char *, buflen * sizeof(char), "gprintf");
4361 	}
4362 #undef GPRINTF_BUFSIZ
4363 
4364 	while (true) {
4365 		va_start(args, format);
4366 		nchar = vsnprintf(buf + bl, buflen - bl, format, args);
4367 		va_end(args);
4368 		if (nchar == 0)
4369 			return 0;
4370 		if (nchar > 0 && nchar < buflen - bl) {
4371 			bl += nchar;
4372 			if (buf[bl-1] != '\n') /* buffer output until see a newline at end */
4373 				return nchar;
4374 			break;
4375 		}
4376 
4377 		/* enlarge buffer, and try again */
4378 		buflen *= 2;
4379 		erealloc(buf, char *, buflen * sizeof(char), "gprintf");
4380 	}
4381 
4382 	bl = 0;
4383 	for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) {
4384 		int sz = (int) (q - p);
4385 
4386 		while (sz > 0) {
4387 			int cnt;
4388 			cnt = sz > screen_width ? screen_width : sz;
4389 
4390 			/* do not print partial line before scrolling */
4391 			if (cnt < sz && (pager_lines_printed == (screen_height - 2)))
4392 				prompt_continue(fp);
4393 
4394 			if (fwrite(p, sizeof(char), cnt, fp) != cnt)
4395 				return -1;
4396 			if (cnt == sz)
4397 				break;
4398 			else {
4399 				if (++pager_lines_printed == (screen_height - 1))
4400 					prompt_continue(fp);
4401 				sz -= screen_width;
4402 				assert(sz > 0);
4403 				p += cnt;
4404 			}
4405 		}
4406 
4407 		fprintf(fp, "\n");
4408 		if (++pager_lines_printed == (screen_height - 1))
4409 			prompt_continue(fp);
4410 		p++;
4411 	}
4412 	return nchar;
4413 }
4414 
4415 
4416 static int
serialize_subscript(char * buf,int buflen,struct list_item * item)4417 serialize_subscript(char *buf, int buflen, struct list_item *item)
4418 {
4419 	int bl, nchar, i;
4420 	NODE *sub;
4421 
4422 	nchar = snprintf(buf, buflen, "%d%c%d%c%s%c%d%c",
4423 				item->number, FSEP, D_subscript, FSEP, item->sname, FSEP,
4424 				item->num_subs, FSEP);
4425 	if (nchar <= 0)
4426 		return 0;
4427 	else if (nchar >= buflen)	/* need larger buffer */
4428 		return nchar;
4429  	bl = nchar;
4430 	for (i = 0; i < item->num_subs; i++) {
4431 		sub = item->subs[i];
4432 		nchar = snprintf(buf + bl, buflen - bl, "%lu%c%.*s%c",
4433 					(unsigned long) sub->stlen, FSEP,
4434 					(int) sub->stlen, sub->stptr, FSEP);
4435 		if (nchar <= 0)
4436 			return 0;
4437 		bl += nchar;
4438 		if (bl >= buflen)	/* need larger buffer */
4439 			return bl;
4440 	}
4441 	return bl;
4442 }
4443 
4444 
4445 /*
4446  * serialize_list--- convert a list structure to a byte stream and
4447  *               save in environment.
4448  */
4449 
4450 static void
serialize_list(int type)4451 serialize_list(int type)
4452 {
4453 	static char *buf = NULL;
4454 	static int buflen = 0;
4455 	int bl;
4456 	BREAKPOINT *b = NULL;
4457 	struct list_item *wd = NULL;
4458 	HIST_ENTRY **hist_list = NULL;
4459 	int hist_index = 0;
4460 	struct dbg_option *opt = NULL;
4461 	struct commands_item *commands = NULL, *c;
4462 	int cnum = 0;
4463 	struct condition *cndn = NULL;
4464 	void *ptr, *end_ptr;
4465 #ifdef HAVE_LIBREADLINE
4466 	HIST_ENTRY *h = NULL;
4467 #endif
4468 
4469 	switch (type) {
4470 	case BREAK:
4471 		end_ptr = (void *) &breakpoints;
4472 		ptr = (void *) breakpoints.prev;
4473 		break;
4474 	case WATCH:
4475 		end_ptr = (void *) &watch_list;
4476 		ptr = (void *) watch_list.prev;
4477 		break;
4478 	case DISPLAY:
4479 		end_ptr = (void *) &display_list;
4480 		ptr = (void *) display_list.prev;
4481 		break;
4482 	case HISTORY:
4483 		hist_list = history_list();
4484 		if (hist_list == NULL) /* empty history list */
4485 			return;
4486 		end_ptr = NULL;
4487 		ptr = (void *) hist_list[0];
4488 		break;
4489 	case OPTION:
4490 	{
4491 		int n;
4492 		n = sizeof(option_list)/sizeof(option_list[0]);
4493 		end_ptr = (void *) &option_list[n - 1];
4494 		ptr = (void *) option_list;
4495 	}
4496 		break;
4497 
4498 	default:
4499 		return;
4500 	}
4501 
4502 	if (type != HISTORY && ptr == end_ptr)		/* empty list */
4503 		return;
4504 
4505 #define SERIALIZE_BUFSIZ 512
4506 
4507 	if (buf == NULL) {	/* first time */
4508 		buflen = SERIALIZE_BUFSIZ;
4509 		emalloc(buf, char *, buflen + 1, "serialize");
4510 	}
4511 	bl = 0;
4512 
4513 	while (ptr != end_ptr) {
4514 		int nchar = 0;
4515 		if (buflen - bl < SERIALIZE_BUFSIZ/2) {
4516 enlarge_buffer:
4517 			buflen *= 2;
4518 			erealloc(buf, char *, buflen + 1, "serialize");
4519 		}
4520 
4521 #undef SERIALIZE_BUFSIZ
4522 
4523 		/* field seperator is FSEP ('\037'), and the record separator is RSEP ('\036') */
4524 
4525 		switch (type) {
4526 		case BREAK:
4527 			b = (BREAKPOINT *) ptr;
4528 
4529 			/* src source_line flags ignore_count hit_count number;
4530 			 * commands and condition processed later in the end switch
4531 			 */
4532 
4533 			nchar = snprintf(buf + bl, buflen - bl,
4534 			                 "%s%c%d%c%d%c%d%c%d%c%d%c",
4535 			                 b->src, FSEP, b->bpi->source_line, FSEP, b->flags, FSEP,
4536 			                 (int) b->ignore_count, FSEP,
4537 			                 (int) b->hit_count, FSEP, b->number, FSEP);
4538 			cnum = b->number;
4539 			commands = &b->commands;
4540 			cndn = &b->cndn;
4541 			break;
4542 		case DISPLAY:
4543 		case WATCH:
4544 			wd = (struct list_item *) ptr;
4545 
4546 			/* subscript    -- number type sname num_subs subs(stlen + stptr) [commands [condition]]
4547 			 * variable     -- number type sname [commands [condition]]
4548 			 * field        -- number type symbol(numbr) [commands [condition]]
4549 			 */
4550 
4551 			if (IS_PARAM(wd))	/* exclude parameters */
4552 				nchar = 0;
4553 			else if (IS_SUBSCRIPT(wd))
4554 				nchar = serialize_subscript(buf + bl, buflen - bl, wd);
4555 			else if (IS_FIELD(wd))
4556 				nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%d%c",
4557 				            wd->number, FSEP, D_field, FSEP, (int) get_number_si(wd->symbol), FSEP);
4558 			else
4559 				nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%s%c",
4560 				            wd->number, FSEP, D_variable, FSEP, wd->sname, FSEP);
4561 			cnum = wd->number;
4562 			commands = &wd->commands;
4563 			cndn = &wd->cndn;
4564 			break;
4565 		case HISTORY:
4566 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
4567 			h = (HIST_ENTRY *) ptr;
4568 			nchar = strlen(h->line);
4569 			if (nchar >= buflen - bl)
4570 				goto enlarge_buffer;
4571 			strcpy(buf + bl, h->line);
4572 #endif
4573 			break;
4574 		case OPTION:
4575 			opt = (struct dbg_option *) ptr;
4576 			if (opt->num_val != NULL)
4577 				nchar = snprintf(buf + bl, buflen - bl,
4578 								"%s%c%d%c", opt->name, FSEP, *(opt->num_val), FSEP);
4579 			else
4580 				nchar = snprintf(buf + bl, buflen - bl,
4581 								"%s%c%s%c", opt->name, FSEP, *(opt->str_val), FSEP);
4582 			break;
4583 		default:
4584 			break;
4585 		}
4586 
4587 		if (nchar == 0)	/* skip empty history lines etc.*/
4588 			;
4589 		else if (nchar > 0 && nchar  < buflen - bl) {
4590 			bl += nchar;
4591 			buf[bl] = RSEP;	/* record */
4592 			buf[++bl] = '\0';
4593 		} else
4594 			goto enlarge_buffer;
4595 
4596 		switch (type) {
4597 		case BREAK:
4598 		case WATCH:
4599 			/* recreate the `commands' command strings including the `commands'
4600 			 * and `end' commands; command seperator is '\034'.
4601 			 * re-parsed in unserialize_list to recover the commands list.
4602 			 * Alternatively, one could encode(serialize) each command and it's arguments.
4603 			 */
4604 
4605 			bl--;	/* undo RSEP from above */
4606 
4607 			/* compute required room in buffer */
4608 			nchar = 0;
4609 			for (c = commands->next; c != commands; c = c->next) {
4610 				nchar += (strlen(c->cmd_string) + 1);
4611 				if (c->cmd == D_eval) {
4612 					CMDARG *a = c->arg;
4613 					nchar += (strlen(a->a_string) + 1);	/* awk statements */
4614 					nchar += (strlen("end") + 1);
4615 				}
4616 			}
4617 
4618 			if (nchar > 0) {	/* non-empty commands list */
4619 				nchar += (strlen("commands ") + 20 /*cnum*/ + 1 /*CSEP*/ + strlen("end") + 1 /*FSEP*/);
4620 				if (nchar >= buflen - bl) {
4621 					buflen = bl + nchar + 1 /*RSEP*/;
4622 					erealloc(buf, char *, buflen + 1, "serialize_list");
4623 				}
4624 				nchar = sprintf(buf + bl, "commands %d", cnum);
4625 				bl += nchar;
4626 				buf[bl++] = CSEP;
4627 				for (c = commands->next; c != commands; c = c->next) {
4628 					nchar = strlen(c->cmd_string);
4629 					memcpy(buf + bl, c->cmd_string, nchar);
4630 					bl += nchar;
4631 					buf[bl++] = CSEP;
4632 
4633 					if (c->cmd == D_eval) {
4634 						CMDARG *a = c->arg;
4635 						nchar = strlen(a->a_string);	/* statements */
4636 						memcpy(buf + bl, a->a_string, nchar);
4637 						bl += nchar;
4638 						buf[bl++] = CSEP;
4639 						nchar = strlen("end");	/* end of 'eval' */
4640 						memcpy(buf + bl, "end", nchar);
4641 						bl += nchar;
4642 						buf[bl++] = CSEP;
4643 					}
4644 				}
4645 				nchar = strlen("end");	/* end of 'commands' */
4646 				memcpy(buf + bl, "end", nchar);
4647 				bl += nchar;
4648 				buf[bl++] = FSEP;		/* field */
4649 			}
4650 			buf[bl++] = RSEP;		/* record */
4651 			buf[bl] = '\0';
4652 
4653 			/* condition expression */
4654 			if (cndn->expr) {
4655 				bl--;	/* undo RSEP from above */
4656 				nchar = strlen(cndn->expr);
4657 				if (nchar + 1 /*FSEP*/ >= buflen - bl) {
4658 					buflen = bl + nchar + 1 /*FSEP*/ + 1 /*RSEP*/;
4659 					erealloc(buf, char *, buflen + 1, "serialize_list");
4660 				}
4661 				memcpy(buf + bl, cndn->expr, nchar);
4662 				bl += nchar;
4663 				buf[bl++] = FSEP;		/* field */
4664 				buf[bl++] = RSEP;		/* record */
4665 				buf[bl] = '\0';
4666 			}
4667 
4668 			ptr = (type == BREAK) ? (void *) b->prev : (void *) wd->prev;
4669 			break;
4670 		case DISPLAY:
4671 			ptr = (void *) wd->prev;
4672 			break;
4673 		case HISTORY:
4674 			ptr = (void *) hist_list[++hist_index];
4675 			break;
4676 		case OPTION:
4677 			ptr = (void *) (++opt);
4678 			break;
4679 		default:
4680 			break;
4681 		}
4682 	}
4683 
4684 	if (bl > 0)	/* non-empty list */
4685 		setenv(env_variable[type], buf, 1);
4686 }
4687 
4688 
4689 static void
unserialize_commands(char * str,int str_len)4690 unserialize_commands(char *str, int str_len)
4691 {
4692 	if (str_len <= 0 || str == NULL)
4693 		return;
4694 	commands_string = str;
4695 	commands_string_len = str_len;
4696 	push_cmd_src(INVALID_HANDLE, false, read_commands_string, 0, 0, EXIT_FATAL);
4697 	line_sep = CSEP;
4698 	read_command();		/* forced to return in do_commands */
4699 	pop_cmd_src();
4700 }
4701 
4702 
4703 /* unserialize_list_item --- create a list_item structure from unserialized data */
4704 
4705 static struct list_item *
unserialize_list_item(struct list_item * list,char ** pstr,int * pstr_len,int field_cnt)4706 unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int field_cnt)
4707 {
4708 	int num, type, i;
4709 	struct list_item *l;
4710 	NODE *symbol = NULL;
4711 	int sub_cnt = 0, cnt;
4712 	NODE **subs = NULL;
4713 
4714 	/* subscript	-- number type sname num_subs subs [commands [condition]]
4715 	 * variable		-- number type sname [commands [condition]]
4716 	 * field		-- number type symbol(numbr) commands [commands [condition]]
4717 	 */
4718 
4719 	num = strtol(pstr[0], NULL, 0);
4720 	type = strtol(pstr[1], NULL, 0);
4721 
4722 	if (type == D_field) {
4723 		int field_num;
4724 		field_num = strtol(pstr[2], NULL, 0);
4725 		symbol = make_number((AWKNUM) field_num);
4726 		cnt = 3;
4727 	} else {
4728 		char *name;
4729 		name = estrdup(pstr[2], pstr_len[2]);
4730 		symbol = find_symbol(name, NULL);
4731 		efree(name);
4732 		if (symbol == NULL)
4733 			return NULL;
4734 		cnt = 3;
4735 		if (type == D_subscript) {
4736 			int sub_len;
4737 			sub_cnt = strtol(pstr[3], NULL, 0);
4738 			emalloc(subs, NODE **, sub_cnt * sizeof(NODE *), "unserialize_list_item");
4739 			cnt++;
4740 			for (i = 0; i < sub_cnt; i++) {
4741 				sub_len = strtol(pstr[cnt], NULL, 0);
4742 				subs[i] = make_string(pstr[cnt + 1], sub_len);
4743 				cnt += 2;
4744 			}
4745 		}
4746 	}
4747 
4748 	l = add_item(list, type, symbol, NULL);
4749 	if (type == D_subscript) {
4750 		l->num_subs = sub_cnt;
4751 		l->subs = subs;
4752 	}
4753 	l->number = num;	/* keep same item number across executions */
4754 
4755 	if (list == &watch_list) {
4756 		initialize_watch_item(l);
4757 		/* unserialize watchpoint `commands' */
4758 		unserialize_commands(pstr[cnt], pstr_len[cnt]);
4759 		cnt++;
4760 		if (field_cnt > cnt) {
4761 			char *expr;
4762 			expr = estrdup(pstr[cnt], pstr_len[cnt]);
4763 			if (parse_condition(D_watch, l->number, expr) != 0)
4764 				efree(expr);
4765 		}
4766 		if (num > list->number)   /* update list number counter */
4767 			list->number = num;
4768 	} else
4769 		list->number = num;
4770 
4771 	return l;
4772 }
4773 
4774 /* unserialize_breakpoint --- create a breakpoint structure from unserialized data */
4775 
4776 static BREAKPOINT *
unserialize_breakpoint(char ** pstr,int * pstr_len,int field_cnt)4777 unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt)
4778 {
4779 	char *src;
4780 	int lineno;
4781 	BREAKPOINT *b = NULL;
4782 	INSTRUCTION *rp;
4783 	SRCFILE *s;
4784 
4785 	/* src source_line flags ignore_count hit_count number commands [condition] */
4786 
4787 	src = estrdup(pstr[0], pstr_len[0]);
4788 	s = source_find(src);
4789 	efree(src);
4790 	if (s == NULL)
4791 		return NULL;
4792 	src = s->src;
4793 	lineno = strtol(pstr[1], NULL, 0);
4794 	if (lineno <= 0 || lineno > s->srclines)
4795 		return NULL;
4796 	rp = find_rule(src, lineno);
4797 	if (rp == NULL
4798 			||  (b = set_breakpoint_at(rp, lineno, true)) == NULL
4799 	)
4800 		return NULL;
4801 
4802 	b->flags =  strtol(pstr[2], NULL, 0);
4803 	b->ignore_count = strtol(pstr[3], NULL, 0);
4804 	b->hit_count = strtol(pstr[4], NULL, 0);
4805 	b->number =  strtol(pstr[5], NULL, 0);	/* same number as previous run */
4806 
4807 	if (field_cnt > 6)	/* unserialize breakpoint `commands' */
4808 		unserialize_commands(pstr[6], pstr_len[6]);
4809 
4810 	if (field_cnt > 7) {	/* condition expression */
4811 		char *expr;
4812 		expr = estrdup(pstr[7], pstr_len[7]);
4813 		if (parse_condition(D_break, b->number, expr) != 0)
4814 			efree(expr);
4815 	}
4816 
4817 	if (b->number > watch_list.number)  /* watch and break has same number counter */
4818 		watch_list.number = b->number;  /* update counter */
4819 	return b;
4820 }
4821 
4822 /* unserialize_option --- set a debugger option from unserialized data. */
4823 
4824 static struct dbg_option *
unserialize_option(char ** pstr,int * pstr_len,int field_cnt ATTRIBUTE_UNUSED)4825 unserialize_option(char **pstr, int *pstr_len, int field_cnt ATTRIBUTE_UNUSED)
4826 {
4827 	const struct dbg_option *opt;
4828 
4829 	for (opt = option_list; opt->name; opt++) {
4830 		if (strncmp(pstr[0], opt->name, pstr_len[0]) == 0) {
4831 			char *value;
4832 
4833 			value = estrdup(pstr[1], pstr_len[1]);
4834 			(*(opt->assign))(value);
4835 			efree(value);
4836 			return ((struct dbg_option *) opt);
4837 		}
4838 	}
4839 	return NULL;
4840 }
4841 
4842 /* unserialize_list -- reconstruct list from serialized data stored in
4843  *                environment variable.
4844  */
4845 
4846 static void
unserialize_list(int type)4847 unserialize_list(int type)
4848 {
4849 	char *val;
4850 	char *p, *q, *r, *s;
4851 #define MAX_FIELD 30
4852 	static char *pstr[MAX_FIELD];
4853 	static int pstr_len[MAX_FIELD];
4854 
4855 	val = getenv(env_variable[type]);
4856 	if (val == NULL)
4857 		return;
4858 
4859 	for (p = val; (q = strchr(p, RSEP)) != NULL; p = q + 1) {
4860 		int field_cnt = 0;
4861 		if (type == HISTORY) {
4862 			*q = '\0';
4863 			add_history(p);
4864 			*q = RSEP;
4865 			continue;
4866 		}
4867 
4868 		r = p;
4869 		while ((s = strchr(r, FSEP)) != NULL && s < q) {
4870 			pstr[field_cnt] = r;
4871 			pstr_len[field_cnt] = (int) (s - r);
4872 			r = s + 1;
4873 			field_cnt++;
4874 			if (field_cnt == MAX_FIELD)
4875 #ifdef GAWKDEBUG
4876 				fatal("Increase MAX_FIELD and recompile");
4877 #else
4878 				return;
4879 #endif
4880 		}
4881 
4882 		switch (type) {
4883 		case BREAK:
4884 			(void) unserialize_breakpoint(pstr, pstr_len, field_cnt);
4885 			break;
4886 		case DISPLAY:
4887 			(void) unserialize_list_item(&display_list, pstr, pstr_len, field_cnt);
4888 			break;
4889 		case WATCH:
4890 			(void) unserialize_list_item(&watch_list, pstr, pstr_len, field_cnt);
4891 			break;
4892 		case OPTION:
4893 			(void) unserialize_option(pstr, pstr_len, field_cnt);
4894 			break;
4895 		case HISTORY:
4896 			/* processed at the beginning of for loop */
4897 			break;
4898 		default:
4899 			break;
4900 		}
4901 	}
4902 
4903 #ifdef HAVE_LIBREADLINE
4904 	if (type == HISTORY)
4905 		sess_history_base = history_length;
4906 #endif
4907 
4908 	unsetenv(env_variable[type]);
4909 #undef MAX_FIELD
4910 }
4911 
4912 static int
prompt_yes_no(const char * mesg,char res_true,int res_default,FILE * fp)4913 prompt_yes_no(const char *mesg, char res_true, int res_default, FILE *fp)
4914 {
4915 	char *in_str;
4916 	int ret = res_default; /* default */
4917 
4918 	if (input_from_tty) {
4919 		fprintf(fp, "%s", _(mesg));
4920 		in_str = read_a_line(NULL);
4921 		if (in_str == NULL)	/* EOF */
4922 			exit(EXIT_FAILURE);
4923 		ret = (*in_str == res_true);
4924 		efree(in_str);
4925 	}
4926 	return ret;
4927 }
4928 
4929 /* has_break_or_watch_point --- check if given breakpoint or watchpoint
4930  *                              number exists. When flag any is true,
4931  *                              check if any breakpoint/watchpoint
4932  *                              has been set (ignores num). Returns
4933  *                              type (breakpoint or watchpoint) or 0.
4934  */
4935 
4936 int
has_break_or_watch_point(int * pnum,bool any)4937 has_break_or_watch_point(int *pnum, bool any)
4938 {
4939 	BREAKPOINT *b = NULL;
4940 	struct list_item *w = NULL;
4941 
4942 	if (any) {
4943 		if (breakpoints.next != &breakpoints)
4944 			b = breakpoints.next;
4945 		if (watch_list.next != &watch_list)
4946 			w = watch_list.next;
4947 
4948 		if (! b && ! w)
4949 			return 0;
4950 		if (b && ! w) {
4951 			*pnum = b->number;
4952 			return D_break;
4953 		}
4954 		if (w && ! b) {
4955 			*pnum = w->number;
4956 			return D_watch;
4957 		}
4958 		if (w->number > b->number) {
4959 			*pnum = w->number;
4960 			return D_watch;
4961 		}
4962 		*pnum = b->number;
4963 		return D_break;
4964 	}
4965 
4966 	/* N.B: breakpoints and watchpoints get numbers from a single
4967 	 * counter/sequencer watch_list.number.
4968 	 */
4969 
4970 	for (b = breakpoints.next; b != &breakpoints; b = b->next) {
4971 		if (b->number == *pnum)
4972 			return D_break;
4973 	}
4974 	for (w = watch_list.next; w != &watch_list; w = w->next) {
4975 		if (w->number == *pnum)
4976 			return D_watch;
4977 	}
4978 
4979 	return 0;
4980 }
4981 
4982 /* delete_commands_item --- delete item(command) from `commands' list. */
4983 
4984 static void
delete_commands_item(struct commands_item * c)4985 delete_commands_item(struct commands_item *c)
4986 {
4987 	efree(c->cmd_string);
4988 	free_cmdarg(c->arg);
4989 	c->next->prev = c->prev;
4990 	c->prev->next = c->next;
4991 	efree(c);
4992 }
4993 
4994 /* do_commands --- commands command */
4995 
4996 int
do_commands(CMDARG * arg,int cmd)4997 do_commands(CMDARG *arg, int cmd)
4998 {
4999 	static BREAKPOINT *b;
5000 	static struct list_item *w;
5001 	static struct commands_item *commands;
5002 	struct commands_item *c;
5003 
5004 	if (cmd == D_commands) {
5005 		int num = -1, type;
5006 		if (arg == NULL)
5007 			type = has_break_or_watch_point(&num, true);
5008 		else {
5009 			num = arg->a_int;
5010 			type = has_break_or_watch_point(&num, false);
5011 		}
5012 		b = NULL;
5013 		w = NULL;
5014 		if (type == D_break)
5015 			b = find_breakpoint(num);
5016 		else if (type == D_watch)
5017 			w = find_item(&watch_list, num);
5018 		assert((b != NULL) || (w != NULL));
5019 		commands = (b != NULL) ? &b->commands : &w->commands;
5020 
5021 		/* delete current commands */
5022 		for (c = commands->next; c != commands; c = c->next) {
5023 			c = c->prev;
5024 			delete_commands_item(c->next);
5025 		}
5026 		return false;
5027 
5028 	} else if (cmd == D_end) {
5029 		commands = NULL;
5030 		if (read_a_line == read_commands_string) /* unserializig commands */
5031 			return true;	/* done unserializing, terminate zzparse() */
5032 		return false;
5033 
5034 	} else if (cmd == D_silent) {
5035 		if (b != NULL)
5036 			b->silent = true;
5037 		else if (w != NULL)
5038 			w->silent = true;
5039 		/* we also append silent command to the list for use
5040 		 * in `info break(watch)', and to simplify
5041 		 * serialization/unserialization of commands.
5042 		 */
5043 	}
5044 
5045 	assert(commands != NULL);
5046 
5047 	emalloc(c, struct commands_item *, sizeof(struct commands_item), "do_commands");
5048 	c->next = NULL;
5049 	c->cmd = cmd;
5050 
5051 	/* N.B.: first arg is the command string, see command.y */
5052 	c->cmd_string = arg->a_string;
5053 	c->arg = arg->next; /* actual arguments to the command */
5054 	efree(arg);
5055 
5056 	/* append to the list */
5057 	c->prev = commands->prev;
5058 	c->next = commands;
5059 	commands->prev = c;
5060 	c->prev->next = c;
5061 	return false;
5062 }
5063 
5064 /* execute_commands --- execute breakpoint/watchpoint commands, the first
5065  *                      command that resumes execution terminates
5066  *                      commands processing.
5067  */
5068 
5069 static int
execute_commands(struct commands_item * commands)5070 execute_commands(struct commands_item *commands)
5071 {
5072 	struct commands_item *c;
5073 	Func_cmd cmd_ptr;
5074 	bool ret = false;
5075 
5076 	for (c = commands->next; c != commands; c = c->next) {
5077 		if (c->cmd == D_silent)
5078 			continue;
5079 		cmd_ptr = get_command(c->cmd);		/* command handler */
5080 		ret = (*cmd_ptr)(c->arg, c->cmd);
5081 		if (ret)	/* resume execution (continue, next etc.) */
5082 			break;
5083 	}
5084 	return ret;
5085 }
5086 
5087 /* do_print_f --- printf command */
5088 
5089 int
do_print_f(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)5090 do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5091 {
5092 	int count = 0;
5093 	int i;
5094 	CMDARG *a;
5095 	NODE **tmp;
5096 	char *name;
5097 	NODE *r;
5098 	volatile jmp_buf fatal_tag_stack;
5099 
5100 	/* count maximum required size for tmp */
5101 	for (a = arg; a != NULL ; a = a->next)
5102 		count++;
5103 	emalloc(tmp, NODE **, count * sizeof(NODE *), "do_print_f");
5104 
5105 	for (i = 0, a = arg; a != NULL ; i++, a = a->next) {
5106 		switch (a->type) {
5107 		case D_variable:
5108 			name = a->a_string;
5109 			r = find_symbol(name, NULL);
5110 			if (r == NULL)
5111 				goto done;
5112 			if (r->type == Node_var_new)
5113 				tmp[i] = Nnull_string;
5114 			else if (r->type != Node_var) {
5115 				d_error(_("`%s' is not a scalar variable"), name);
5116 				goto done;
5117 			} else
5118 				tmp[i] = r->var_value;
5119 			break;
5120 		case D_field:
5121 		{
5122 			long field_num;
5123 			r = a->a_node;
5124 			field_num = get_number_si(r);
5125 			tmp[i] = *get_field(field_num, NULL);
5126 		}
5127 			break;
5128 		case D_subscript:
5129 		{
5130 			int cnt = a->a_count;
5131 			name = a->a_string;
5132 			r = find_array(name);
5133 			if (r == NULL)
5134 				goto done;
5135 
5136 			for (; cnt > 0; cnt--) {
5137 				NODE *value, *subs;
5138 				a = a->next;
5139 				subs = a->a_node;
5140 				value = in_array(r, subs);
5141 				if (cnt == 1) {
5142 					if (value == NULL)
5143 						tmp[i] = Nnull_string;		/* FIXME: goto done ? */
5144 					else if (value->type == Node_var_array) {
5145 						d_error(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
5146 									name, (int) subs->stlen, subs->stptr);
5147 						goto done;
5148 					} else
5149 						tmp[i] = value;
5150 				} else {
5151 					if (value == NULL) {
5152 						d_error(_("[\"%.*s\"] not in array `%s'"),
5153 									(int) subs->stlen, subs->stptr, name);
5154 						goto done;
5155 					} else if (value->type != Node_var_array) {
5156 						d_error(_("attempt to use scalar `%s[\"%.*s\"]' as array"),
5157 									name, (int) subs->stlen, subs->stptr);
5158 						goto done;
5159 					} else {
5160 						r = value;
5161 						name = r->vname;
5162 					}
5163 				}
5164 			}
5165 		}
5166 			break;
5167 		case D_node:
5168 			tmp[i] = a->a_node;
5169 			break;
5170 		default:
5171 			break;
5172 		}
5173 	}
5174 
5175 	tmp[0] = force_string(tmp[0]);
5176 
5177 	PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5178 	if (setjmp(fatal_tag) == 0)
5179 		r = format_tree(tmp[0]->stptr, tmp[0]->stlen, tmp, i);
5180 	else {
5181 		/* fatal error, restore exit_val of program */
5182 		exit_val = EXIT_SUCCESS;
5183 		r = NULL;
5184 	}
5185 	POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5186 
5187 	if (r != NULL) {
5188 		(void) fwrite(r->stptr, sizeof(char), r->stlen, out_fp);
5189 		unref(r);
5190 	}
5191 done:
5192 	efree(tmp);
5193 	return false;
5194 }
5195 
5196 /* do_source --- source command */
5197 
5198 int
do_source(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)5199 do_source(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5200 {
5201 	int fd;
5202 	char *file = arg->a_string;
5203 
5204 	fd = open_readfd(file);
5205 	if (fd <= INVALID_HANDLE) {
5206 		d_error(_("cannot open source file `%s' for reading: %s"),
5207 					file, strerror(errno));
5208 		return false;
5209 	}
5210 
5211 	push_cmd_src(fd, false, g_readline, close, D_source, EXIT_SUCCESS);
5212 	cmd_src->str = estrdup(file, strlen(file));
5213 	return false;
5214 }
5215 
5216 /* open_readfd --- open a file for reading */
5217 
5218 static int
open_readfd(const char * file)5219 open_readfd(const char *file)
5220 {
5221 	int fd;
5222 
5223 	fd = open(file, O_RDONLY);
5224 	if (fd <= INVALID_HANDLE)
5225 		return INVALID_HANDLE;
5226 	else if (os_isdir(fd)) {
5227 		(void) close(fd);
5228 		errno = EISDIR;
5229 		return INVALID_HANDLE;
5230 	}
5231 	return fd;
5232 }
5233 
5234 /* find_option --- check if option name is valid */
5235 
5236 int
find_option(char * name)5237 find_option(char *name)
5238 {
5239 	const char *p;
5240 	int idx;
5241 
5242 	for (idx = 0; (p = option_list[idx].name); idx++) {
5243 		if (strcmp(p, name) == 0)
5244 			return idx;
5245 	}
5246 	return -1;
5247 }
5248 
5249 /* option_help --- display help text for debugger options */
5250 
5251 void
option_help()5252 option_help()
5253 {
5254 	const struct dbg_option *opt;
5255 
5256 	for (opt = option_list; opt->name; opt++)
5257 		fprintf(out_fp, "\t%-15.15s - %s\n", opt->name, _(opt->help_txt));
5258 }
5259 
5260 #ifdef HAVE_LIBREADLINE
5261 
5262 /* option_generator --- generator function for option name completion */
5263 
5264 char *
option_generator(const char * text,int state)5265 option_generator(const char *text, int state)
5266 {
5267 	static size_t textlen;
5268 	static int idx;
5269 	const char *name;
5270 
5271 	if (! state) {	/* first time */
5272 		textlen = strlen(text);
5273 		idx = 0;
5274 	}
5275 
5276 	while ((name = option_list[idx++].name)) {
5277 		if (strncmp(name, text, textlen) == 0)
5278 			return estrdup(name, strlen(name));
5279 	}
5280 	return NULL;
5281 }
5282 
5283 #endif
5284 
5285 /* set_gawk_output --- redirect gawk (normal) output */
5286 
5287 static void
set_gawk_output(const char * file)5288 set_gawk_output(const char *file)
5289 {
5290 	int fd = INVALID_HANDLE;
5291 	FILE *fp = NULL;
5292 
5293 	if (output_fp != stdout) {
5294 		if (output_fp != stderr) {
5295 			fclose(output_fp);
5296 			efree((void*) output_file);
5297 		}
5298 		output_fp = stdout;
5299 		output_is_tty = os_isatty(fileno(stdout));
5300 		output_file = "/dev/stdout";
5301 	}
5302 
5303 	if (file == NULL || file[0] == '\0')
5304 		return;
5305 
5306 	errno = 0;
5307 	if ((fd = os_devopen(file, O_WRONLY)) != INVALID_HANDLE) {
5308 		fp = fdopen(fd, "w");
5309 		if (fp == NULL)
5310 			close(fd);
5311 
5312 	} else if (strncmp(file, "/dev/", 5) == 0) {
5313 		char *cp = (char *) file + 5;
5314 
5315 		if (strcmp(cp, "stdout") == 0)
5316 			return;
5317 		if (strcmp(cp, "stderr") == 0) {
5318 			output_fp = stderr;
5319 			output_file = "/dev/stderr";
5320 			output_is_tty = os_isatty(fileno(stderr));
5321 			return;
5322 		}
5323 
5324 		if (strncmp(cp, "fd/", 3) == 0) {
5325 			cp += 3;
5326 			fd = (int) strtoul(cp, NULL, 10);
5327 			if (errno == 0 && fd > INVALID_HANDLE) {
5328 				fp = fdopen(fd, "w");
5329 				if (fp == NULL)
5330 					fd = INVALID_HANDLE;
5331 			} else
5332 				fd = INVALID_HANDLE;
5333 		} else {
5334 			/* /dev/ttyN, /dev/pts/N, /dev/null etc. */
5335 			fd = open(file, O_WRONLY);
5336 		}
5337 
5338 		if (fd > INVALID_HANDLE && fp == NULL) {
5339 			fp = fdopen(fd, "w");
5340 			if (fp == NULL)
5341 				close(fd);
5342 		}
5343 
5344 	} else {
5345 		/* regular file */
5346 		fp = fopen(file, "w");
5347 	}
5348 
5349 	if (fp != NULL) {
5350 		output_fp = fp;
5351 		output_file = estrdup(file, strlen(file));
5352 		setbuf(fp, (char *) NULL);
5353 		output_is_tty = os_isatty(fileno(fp));
5354 	} else {
5355 		d_error(_("could not open `%s' for writing: %s"),
5356 					file,
5357 					errno != 0 ? strerror(errno) : _("reason unknown"));
5358 		fprintf(out_fp, _("sending output to stdout\n"));
5359 	}
5360 }
5361 
5362 /* set_prompt --- set debugger prompt */
5363 
5364 static void
set_prompt(const char * value)5365 set_prompt(const char *value)
5366 {
5367 	efree((void *) dgawk_prompt);
5368 	dgawk_prompt = estrdup(value, strlen(value));
5369 	dbg_prompt = dgawk_prompt;
5370 }
5371 
5372 /* set_option_flag --- convert option string to flag value */
5373 
5374 static int
set_option_flag(const char * value)5375 set_option_flag(const char *value)
5376 {
5377 	long n;
5378 	if (strcmp(value, "on") == 0)
5379 		return true;
5380 	if (strcmp(value, "off") == 0)
5381 		return false;
5382 	errno = 0;
5383 	n = strtol(value, NULL, 0);
5384 	return (errno == 0 && n != 0);
5385 }
5386 
5387 /* set_option_num --- set integer option value from string */
5388 
5389 static void
set_option_num(int * pnum,const char * value)5390 set_option_num(int *pnum, const char *value)
5391 {
5392 	long n;
5393 	errno = 0;
5394 	n = strtol(value, NULL, 0);
5395 	if (errno == 0 && n > 0)
5396 		*pnum = n;
5397 	else
5398 		d_error(_("invalid number"));
5399 }
5400 
5401 /* set_listsize --- set list output window size */
5402 
5403 static void
set_listsize(const char * value)5404 set_listsize(const char *value)
5405 {
5406 	set_option_num(&list_size, value);
5407 }
5408 
5409 /* set_trace --- set instruction tracing on or off */
5410 
5411 static void
set_trace(const char * value)5412 set_trace(const char *value)
5413 {
5414 	do_trace = set_option_flag(value);
5415 }
5416 
5417 /* set_save_history --- save history on exit */
5418 
5419 static void
set_save_history(const char * value)5420 set_save_history(const char *value)
5421 {
5422 	do_save_history = set_option_flag(value);
5423 }
5424 
5425 /* set_save_options --- save options on exit */
5426 
5427 static void
set_save_options(const char * value)5428 set_save_options(const char *value)
5429 {
5430 	do_save_options = set_option_flag(value);
5431 }
5432 
5433 /* set_history_size --- maximum entries in history file */
5434 
5435 static void
set_history_size(const char * value)5436 set_history_size(const char *value)
5437 {
5438 	set_option_num(&history_size, value);
5439 }
5440 
5441 
5442 /* read_commands_string --- one of the many ways zzlex fetches a line to parse;
5443  *                          this one is used to parse `commands' string during
5444  *                          unserialization.
5445  */
5446 
5447 char *
read_commands_string(const char * prompt ATTRIBUTE_UNUSED)5448 read_commands_string(const char *prompt ATTRIBUTE_UNUSED)
5449 {
5450 	char *p, *end, *line;
5451 
5452 	if (commands_string == NULL)
5453 		return NULL;
5454 
5455 	p = (char *) commands_string;
5456 	end = (char *) commands_string + commands_string_len;
5457 	for (; p < end; p++) {
5458 		if (*p == line_sep) {
5459 			line = estrdup(commands_string, p - commands_string);
5460 			commands_string = p + 1;
5461 			commands_string_len = end - commands_string;
5462 			return line;
5463 		}
5464 	}
5465 
5466 	line = estrdup(commands_string, commands_string_len);
5467 	commands_string = NULL;
5468 	commands_string_len = 0;
5469 	return line;
5470 }
5471 
5472 /* save_options --- save current options to file */
5473 
5474 static void
save_options(const char * file)5475 save_options(const char *file)
5476 {
5477 	FILE *fp;
5478 	const struct dbg_option *opt;
5479 
5480 	fp = fopen(file, "w");
5481 	if (fp == NULL)
5482 		return;
5483 
5484 	for (opt = option_list; opt->name; opt++) {
5485 		if (opt->str_val != NULL)
5486 			fprintf(fp, "option %s = \"%s\"\n", opt->name, *(opt->str_val));
5487 		else
5488 			fprintf(fp, "option %s = %d\n", opt->name, *(opt->num_val));
5489 	}
5490 	fclose(fp);
5491 	chmod(file, 0600);
5492 }
5493 
5494 /* close_all --- close all open files */
5495 
5496 static void
close_all()5497 close_all()
5498 {
5499 	bool stdio_problem, got_EPIPE;
5500 	struct command_source *cs;
5501 
5502 	(void) nextfile(& curfile, true);	/* close input data file */
5503 	(void) close_io(& stdio_problem, & got_EPIPE);
5504 	if (cur_srcfile->fd != INVALID_HANDLE) {
5505 		close(cur_srcfile->fd);
5506 		cur_srcfile->fd = INVALID_HANDLE;
5507 	}
5508 	for (cs = cmd_src; cs != NULL; cs = cs->next) {
5509 		if (cs->close_func && cs->fd != INVALID_HANDLE) {
5510 			cs->close_func(cs->fd);
5511 			cs->fd = INVALID_HANDLE;
5512 		}
5513 	}
5514 
5515 	close_extensions();
5516 
5517 	set_gawk_output(NULL);	/* closes output_fp if not stdout */
5518 }
5519 
5520 /* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
5521 
5522 static int
pre_execute_code(INSTRUCTION ** pi)5523 pre_execute_code(INSTRUCTION **pi)
5524 {
5525 	INSTRUCTION *ei = *pi;
5526 
5527 	switch (ei->opcode) {
5528 	case Op_K_exit:
5529 	case Op_K_next:
5530 	case Op_K_nextfile:
5531 	case Op_K_getline:	/* getline without redirection */
5532 		d_error(_("`%s' not allowed in current context;"
5533 				" statement ignored"),
5534 				op2str(ei->opcode));
5535 		*pi = ei->nexti;
5536 		break;
5537 	case Op_K_return_from_eval:
5538 		if (ei->nexti != NULL) {	/* not an implicit return */
5539 			NODE *r;
5540 			d_error(_("`return' not allowed in current context;"
5541 					" statement ignored"));
5542 			/* throw away return value already pushed onto stack */
5543 			r = POP_SCALAR();
5544 			DEREF(r);
5545 			*pi = ei->nexti;
5546 		}
5547 		break;
5548 	default:
5549 		break;
5550 	}
5551 	return (ei == *pi);
5552 }
5553 
5554 extern INSTRUCTION *unwind_stack(long n);
5555 
5556 static NODE *
execute_code(volatile INSTRUCTION * code)5557 execute_code(volatile INSTRUCTION *code)
5558 {
5559 	volatile NODE *r = NULL;
5560 	volatile jmp_buf fatal_tag_stack;
5561 	long save_stack_size;
5562 	int save_flags = do_flags;
5563 
5564 	/* We use one global stack for all contexts.
5565 	 * Save # of items in stack; in case of
5566 	 * a fatal error, pop stack until it has that many items.
5567 	 */
5568 
5569 	save_stack_size = (stack_ptr  - stack_bottom) + 1;
5570 	do_flags = false;
5571 
5572 	PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5573 	if (setjmp(fatal_tag) == 0) {
5574 		(void) interpret((INSTRUCTION *) code);
5575 		r = POP_SCALAR();
5576 	} else	/* fatal error */
5577 		(void) unwind_stack(save_stack_size);
5578 
5579 	POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5580 	do_flags = save_flags;
5581 	if (exit_val != EXIT_SUCCESS) {	/* must be EXIT_FATAL? */
5582 		exit_val = EXIT_SUCCESS;
5583 		return NULL;
5584 	}
5585 	return (NODE *) r;
5586 }
5587 
5588 /* do_eval --- eval command */
5589 
5590 int
do_eval(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)5591 do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5592 {
5593 	NODE *r, *ret_val;
5594 	NODE *f = NULL;
5595 	NODE *this_frame = NULL, *this_func = NULL;
5596 	NODE **sp;
5597 	INSTRUCTION *eval, *code = NULL;
5598 	AWK_CONTEXT *ctxt;
5599 	int ecount = 0, pcount = 0;
5600 	int ret;
5601 	int save_flags = do_flags;
5602 	SRCFILE *the_source;
5603 
5604 	if (prog_running) {
5605 		this_frame = find_frame(0);
5606 		this_func = this_frame->func_node;
5607 	}
5608 
5609 	install_params(this_func);	/* expose current function parameters to eval */
5610 	ctxt = new_context();
5611 	ctxt->install_func = append_symbol;	/* keep track of newly installed globals */
5612 	push_context(ctxt);
5613 	the_source = add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
5614 	do_flags &= DO_MPFR;	// preserve this flag only
5615 	ret = parse_program(&code, true);
5616 	do_flags = save_flags;
5617 	remove_params(this_func);
5618 	if (ret != 0) {
5619 		pop_context();	/* switch to prev context */
5620 		free_context(ctxt, false /* keep_globals */);
5621 
5622 		/* Remove @eval from FUNCTAB. */
5623 		NODE *s = make_string("@eval", 5);
5624 		(void) assoc_remove(func_table, s);
5625 		unref(s);
5626 
5627 		return false;
5628 	}
5629 
5630 	f = lookup("@eval");
5631 	assert(f != NULL);
5632 	if (this_func == NULL) {	/* in main */
5633 		/* do a function call */
5634 		eval = bcalloc(Op_func_call, 2, 0);
5635 		eval->source_file = cur_srcfile->src;
5636 		eval->func_body = f;
5637 		eval->func_name = NULL;	/* not needed, func_body already assigned */
5638 		(eval + 1)->expr_count = 0;
5639 		eval->nexti = bcalloc(Op_stop, 1, 0);
5640 
5641 	} else {
5642 		/* execute as a part of the current function */
5643 		int i;
5644 		INSTRUCTION *t;
5645 
5646 		eval = f->code_ptr;	/* Op_func */
5647 		eval->source_file = cur_srcfile->src;
5648 		/* turn implicit Op_K_return into Op_stop */
5649 		t = (eval + 1)->lasti;	/* Op_K_return */
5650 		t->opcode = Op_stop;
5651 
5652 		/* add or append eval locals to the current frame stack */
5653 		ecount = f->param_cnt;	/* eval local count */
5654 		pcount = this_func->param_cnt;
5655 
5656 		if (ecount > 0) {
5657 			if (pcount == 0)
5658 				emalloc(this_frame->stack, NODE **, ecount * sizeof(NODE *), "do_eval");
5659 			else
5660 				erealloc(this_frame->stack, NODE **, (pcount + ecount) * sizeof(NODE *), "do_eval");
5661 
5662 			sp = this_frame->stack + pcount;
5663 			for (i = 0; i < ecount; i++) {
5664 				NODE *np;
5665 
5666 				np = f->fparms + i;
5667 				np->param_cnt += pcount;	/* appending eval locals: fixup param_cnt */
5668 
5669 				getnode(r);
5670 				memset(r, 0, sizeof(NODE));
5671 				*sp++ = r;
5672 				/* local variable */
5673 				r->type = Node_var_new;
5674 				r->vname = np->param;
5675 			}
5676 
5677 			this_func->param_cnt += ecount;
5678 		}
5679 	}
5680 
5681 #if 0
5682 	pf_data.print_func = fprintf;
5683 	pf_data.fp = out_fp;
5684 	pf_data.defn = false;	/* in_dump = false */
5685 	(void) print_code(f->code_ptr, &pf_data);
5686 #endif
5687 
5688 	ret_val = execute_code((volatile INSTRUCTION *) eval);
5689 
5690 	if (ret_val != NULL)
5691 		DEREF(ret_val);	/* throw away return value */
5692 	/* else
5693 		fatal error */
5694 
5695 	if (this_func != NULL && ecount > 0) {
5696 		int i;
5697 
5698 		/* undo frame manipulation from above */
5699 
5700 		/* free eval locals */
5701 		sp = this_frame->stack + pcount;
5702 		for (i = ecount; i > 0; i--) {
5703 			r = *sp;
5704 			if (r->type == Node_var)     /* eval local variable */
5705 				DEREF(r->var_value);
5706 			else if (r->type == Node_var_array)     /* eval local array */
5707 				assoc_clear(r);
5708 			freenode(r);
5709 			*sp++ = (NODE *) 0;
5710 		}
5711 		if (pcount == 0) {
5712 			efree(this_frame->stack);
5713 			this_frame->stack = NULL;
5714 		} /* else
5715 				restore_frame() will free it */
5716 
5717 		this_func->param_cnt -= ecount;
5718 	}
5719 
5720 	/*
5721 	 * Always destroy symbol "@eval", however destroy all newly installed
5722 	 * globals only if fatal error (execute_code() returing NULL).
5723 	 */
5724 
5725 	pop_context();	/* switch to prev context */
5726 	free_context(ctxt, (ret_val != NULL));   /* free all instructions and optionally symbols */
5727 
5728 	if (ret_val != NULL) {
5729 		/*
5730 		 * Remove @eval from FUNCTAB, so that above code
5731 		 * will work the next time around.
5732 		 */
5733 		NODE *s = make_string("@eval", 5);
5734 
5735 		(void) assoc_remove(func_table, s);
5736 		unref(s);
5737 	}
5738 
5739 	free(f->vname);
5740 	freenode(f);
5741 
5742 	free_srcfile(the_source);
5743 
5744 	return false;
5745 }
5746 
5747 /*
5748 GDB Documentation:
5749 	... When you use condition, GDB checks expression
5750 immediately for syntactic correctness, and to determine whether symbols
5751 in it have referents in the context of your breakpoint. If expression
5752 uses symbols not referenced in the context of the breakpoint, GDB prints
5753 an error message:
5754 
5755     No symbol "foo" in current context.
5756 */
5757 
5758 static int invalid_symbol = 0;
5759 
5760 static void
check_symbol(NODE * r)5761 check_symbol(NODE *r)
5762 {
5763 	invalid_symbol++;
5764 	d_error(_("no symbol `%s' in current context"), r->vname);
5765 	/* install anyway, but keep track of it */
5766 	append_symbol(r);
5767 }
5768 
5769 /* parse_condition --- compile a condition expression */
5770 
5771 static int
parse_condition(int type,int num,char * expr)5772 parse_condition(int type, int num, char *expr)
5773 {
5774 	INSTRUCTION *code = NULL;
5775 	AWK_CONTEXT *ctxt = NULL;
5776 	int ret;
5777 	BREAKPOINT *b;
5778 	struct list_item *w;
5779 	NODE *this_func = NULL;
5780 	INSTRUCTION *it, *stop, *rule;
5781 	struct condition *cndn = NULL;
5782 	int save_flags = do_flags;
5783 
5784 	if (type == D_break && (b = find_breakpoint(num)) != NULL) {
5785 		INSTRUCTION *rp;
5786 		cndn = &b->cndn;
5787 		rp = find_rule(b->src, b->bpi->source_line);
5788 		if (rp != NULL && rp->opcode == Op_func)
5789 			this_func = rp->func_body;
5790 	} else if (type == D_watch && (w = find_item(&watch_list, num)) != NULL) {
5791 		cndn = &w->cndn;
5792 		this_func = find_frame(cur_frame)->func_node;
5793 	}
5794 
5795 	if (cndn == NULL)
5796 		return -1;
5797 	if (expr == NULL)
5798 		goto out;	/* delete condition */
5799 
5800 	install_params(this_func);
5801 	ctxt = new_context();
5802 	invalid_symbol = 0;
5803 	ctxt->install_func = check_symbol;
5804 	push_context(ctxt);
5805 	(void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
5806 	do_flags = false;
5807 	ret = parse_program(&code, true);
5808 	do_flags = save_flags;
5809 	remove_params(this_func);
5810 	pop_context();
5811 
5812 	if (ret != 0 || invalid_symbol) {
5813 		free_context(ctxt, false /* keep_globals */);
5814 		return -1;
5815 	}
5816 
5817 	/* condition expression is parsed as awk pattern without
5818 	 * any action. The code is then modified to end up with
5819 	 * a `1.0' on stack when the expression is true, `0.0' otherwise.
5820 	 */
5821 
5822 	assert(code != NULL);
5823 	rule = ctxt->rule_list.nexti;
5824 	stop = bcalloc(Op_stop, 1, 0);
5825 
5826 	it = rule->firsti;	/* Op_K_print_rec */
5827 	assert(it->opcode == Op_K_print_rec);
5828 	it->opcode = Op_push_i;
5829 	it->memory = make_number(1.0);
5830 	it->nexti = bcalloc(Op_jmp, 1, 0);
5831 	it->nexti->target_jmp = stop;
5832 	it->nexti->nexti = rule->lasti;
5833 
5834 	it = rule->lasti;		/* Op_no_op, target for Op_jmp_false */
5835 	assert(it->opcode == Op_no_op);
5836 	it->opcode = Op_push_i;
5837 	it->memory = make_number(0.0);
5838 	it->nexti = stop;
5839 
5840 out:
5841 	if (cndn->expr != NULL)
5842 		efree(cndn->expr);
5843 	free_context(cndn->ctxt, false);
5844 	cndn->code = code;
5845 	cndn->expr = expr;
5846 	cndn->ctxt = ctxt;
5847 
5848 	return 0;
5849 }
5850 
5851 /* do_condition --- condition command */
5852 
5853 int
do_condition(CMDARG * arg,int cmd ATTRIBUTE_UNUSED)5854 do_condition(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5855 {
5856 	int type, num;
5857 	char *expr = NULL;
5858 
5859 	num = arg->a_int;
5860 	type = has_break_or_watch_point(&num, false);
5861 	if (! type)
5862 		return false;
5863 	arg = arg->next;	/* condition expression */
5864 	if (arg != NULL)
5865 		expr = arg->a_string;
5866 	if (parse_condition(type, num, expr) == 0 && arg != NULL)
5867 		arg->a_string = NULL;	/* don't let free_cmdarg free it */
5868 	return false;
5869 }
5870 
5871 /* in_cmd_src --- check if filename already in cmd_src */
5872 
5873 int
in_cmd_src(const char * filename)5874 in_cmd_src(const char *filename)
5875 {
5876 	struct command_source *cs;
5877 	for (cs = cmd_src; cs != NULL; cs = cs->next) {
5878 		if (cs->str != NULL && strcmp(cs->str, filename) == 0)
5879 			return true;
5880 	}
5881 	return false;
5882 }
5883 
5884 int
get_eof_status()5885 get_eof_status()
5886 {
5887 	if (cmd_src == NULL)
5888 		return EXIT_FATAL;
5889 	return cmd_src->eof_status;
5890 }
5891 
5892 void
push_cmd_src(int fd,bool istty,char * (* readfunc)(const char *),int (* closefunc)(int),int ctype,int eofstatus)5893 push_cmd_src(
5894 	int fd,
5895 	bool istty,
5896 	char * (*readfunc)(const char *),
5897 	int (*closefunc)(int),
5898 	int ctype,
5899 	int eofstatus)
5900 {
5901 	struct command_source *cs;
5902 	emalloc(cs, struct command_source *, sizeof(struct command_source), "push_cmd_src");
5903 	cs->fd = fd;
5904 	cs->is_tty = istty;
5905 	cs->read_func = readfunc;
5906 	cs->close_func = closefunc;
5907 	cs->cmd = ctype;
5908 
5909 	/* eof_status = EXIT_FATAL     - exit with status EXIT_FATAL on EOF or error.
5910 	 *            = EXIT_FAILURE   - exit status EXIT_FAILURE on error.
5911 	 *            = EXIT_SUCCESS   - don't exit on EOF or error.
5912 	 */
5913 	cs->eof_status = eofstatus;
5914 	cs->str = NULL;
5915 	cs->next = cmd_src;
5916 	cmd_src = cs;
5917 
5918 	input_fd = fd;
5919 	input_from_tty = istty;
5920 	read_a_line = readfunc;
5921 }
5922 
5923 int
pop_cmd_src()5924 pop_cmd_src()
5925 {
5926 	struct command_source *cs;
5927 
5928 	if (cmd_src->next == NULL)
5929 		return -1;
5930 
5931 	cs = cmd_src;
5932 	cmd_src = cs->next;
5933 	if (cs->close_func && cs->fd != INVALID_HANDLE)
5934 		cs->close_func(cs->fd);
5935 	if (cs->str != NULL)
5936 		efree(cs->str);
5937 	efree(cs);
5938 
5939 	input_fd = cmd_src->fd;
5940 	input_from_tty = cmd_src->is_tty;
5941 	read_a_line = cmd_src->read_func;
5942 	return 0;
5943 }
5944