2 * debug.c - gawk debugger
6 * Copyright (C) 2004, 2010-2013 the Free Software Foundation, Inc.
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
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 2 of the License, or
14 * (at your option) any later version.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
30 #include <fcntl.h> /* open() */
34 extern SRCFILE *srcfiles;
35 extern INSTRUCTION *rule_list;
36 extern INSTRUCTION *code_block;
37 extern NODE **fcall_list;
38 extern long fcall_count;
39 extern FILE *output_fp;
40 extern IOBUF *curfile;
41 extern const char *command_file;
42 extern const char *get_spec_varname(Func_ptr fptr);
43 extern int zzparse(void);
44 #define read_command() (void) zzparse()
46 extern const char *redir2str(int redirtype);
48 static char *linebuf = NULL; /* used to print a single line of source */
49 static size_t linebuf_len;
53 char *commands_prompt = "> "; /* breakpoint or watchpoint commands list */
54 char *eval_prompt = "@> "; /* awk statement(s) */
56 bool input_from_tty = false;
59 static SRCFILE *cur_srcfile;
60 static long cur_frame = 0;
61 static INSTRUCTION *cur_pc;
64 static bool prog_running = false;
72 struct commands_item {
73 struct commands_item *next;
74 struct commands_item *prev;
80 /* breakpoint structure */
81 typedef struct break_point {
82 struct break_point *next;
83 struct break_point *prev;
89 INSTRUCTION *bpi; /* Op_breakpoint */
91 struct commands_item commands; /* list of commands to run */
94 struct condition cndn;
98 #define BP_ENABLE_ONCE 2 /* enable once */
104 static BREAKPOINT breakpoints = { &breakpoints, &breakpoints, 0 };
106 #ifdef HAVE_LIBREADLINE
107 /* do_save -- save command */
108 static int sess_history_base = 0;
111 #ifndef HAVE_HISTORY_LIST
112 #define HIST_ENTRY void
113 #define history_list() NULL
118 static int last_printed_line = 0;
119 static int last_print_count; /* # of lines printed */
121 /* watch or display item */
123 struct list_item *next;
124 struct list_item *prev;
125 int number; /* item number */
127 NODE *symbol; /* variable or function param */
128 NODE **subs; /* subscripts */
129 int num_subs; /* subscript(dimension) count */
130 char *sname; /* symbol or param name */
134 struct commands_item commands;
136 struct condition cndn;
138 /* This is for the value of the watched item */
143 #define cur_value value[0].n
144 #define cur_size value[0].l
145 #define old_value value[1].n
146 #define old_size value[1].l
152 #define OLD_IS_ARRAY 8 /* old item is array */
153 #define CUR_IS_ARRAY 16 /* current item is array */
156 #define IS_PARAM(d) (((d)->flags & PARAM) != 0)
157 #define IS_SUBSCRIPT(d) (((d)->flags & SUBSCRIPT) != 0)
158 #define IS_FIELD(d) (((d)->flags & FIELD_NUM) != 0)
159 #define WATCHING_ARRAY(d) (((d)->flags & CUR_IS_ARRAY) != 0)
161 static struct list_item display_list = { &display_list, &display_list, 0 };
162 static struct list_item watch_list = { &watch_list, &watch_list, 0 };
165 /* Structure to maintain data for processing debugger commands */
168 long fcall_count; /* 'finish', 'until', 'next', 'step', 'nexti' commands */
169 int sourceline; /* source line number last
170 * time we stopped execution,
171 * used by next, until and step commands
173 char *source; /* next, until and step */
175 INSTRUCTION *pc; /* 'until' and 'return' commands */
176 int repeat_count; /* 'step', 'next', 'stepi', 'nexti' commands */
177 bool print_frame; /* print frame info, 'finish' and 'until' */
178 bool print_ret; /* print returned value, 'finish' */
179 int break_point; /* non-zero (breakpoint number) if stopped at break point */
180 int watch_point; /* non-zero (watchpoint number) if stopped at watch point */
182 int (*check_func)(INSTRUCTION **); /* function to decide when to suspend
183 * awk interpreter and return control
184 * to debugger command interpreter.
187 enum argtype command; /* command type */
191 /* restart related stuff */
192 extern char **d_argv; /* copy of argv array */
193 static bool need_restart = false;
194 enum { BREAK=1, WATCH, DISPLAY, HISTORY, OPTION };
195 static const char *const env_variable[] = {
203 static void serialize(int );
204 static void unserialize(int );
205 static const char *commands_string = NULL;
206 static int commands_string_len = 0;
207 static char line_sep;
208 #define FSEP (char)'\037'
209 #define RSEP (char)'\036'
210 #define CSEP (char)'\035'
213 /* debugger option */
218 void (*assign)(const char *);
219 const char *help_txt;
222 #define DEFAULT_HISTFILE "./.gawk_history"
223 #define DEFAULT_OPTFILE "./.gawkrc"
224 #define DEFAULT_PROMPT "gawk> "
225 #define DEFAULT_LISTSIZE 15
226 #define DEFAULT_HISTSIZE 100
228 static void set_gawk_output(const char *file);
229 static void set_prompt(const char *value);
230 static void set_listsize(const char *value);
231 static void set_trace(const char *value);
232 static void set_save_history(const char *value);
233 static void set_save_options(const char *value);
234 static void set_history_size(const char *value);
235 static const char *options_file = DEFAULT_OPTFILE;
236 #ifdef HAVE_LIBREADLINE
237 static const char *history_file = DEFAULT_HISTFILE;
240 /* debugger option related variables */
242 static char *output_file = "/dev/stdout"; /* gawk output redirection */
243 char *dgawk_prompt = NULL; /* initialized in interpret */
244 static int list_size = DEFAULT_LISTSIZE; /* # of lines that 'list' prints */
245 static int do_trace = false;
246 static int do_save_history = true;
247 static int do_save_options = true;
248 static int history_size = DEFAULT_HISTSIZE; /* max # of lines in history file */
250 static const struct dbg_option option_list[] = {
251 {"history_size", &history_size, NULL, &set_history_size,
252 gettext_noop("set or show the number of lines to keep in history file.") },
253 {"listsize", &list_size, NULL, &set_listsize,
254 gettext_noop("set or show the list command window size.") },
255 {"outfile", NULL, &output_file, &set_gawk_output,
256 gettext_noop("set or show gawk output file.") },
257 {"prompt", NULL, &dgawk_prompt, &set_prompt,
258 gettext_noop("set or show debugger prompt."), },
259 {"save_history", &do_save_history, NULL, &set_save_history,
260 gettext_noop("(un)set or show saving of command history (value=on|off).") },
261 {"save_options", &do_save_options, NULL, &set_save_options,
262 gettext_noop("(un)set or show saving of options (value=on|off).") },
263 {"trace", &do_trace, NULL, &set_trace,
264 gettext_noop("(un)set or show instruction tracing (value=on|off).") },
265 {0, NULL, NULL, NULL, 0},
268 static void save_options(const char *file);
272 jmp_buf pager_quit_tag;
273 bool pager_quit_tag_valid = false;
274 static int screen_width = INT_MAX; /* no of columns */
275 static int screen_height = INT_MAX; /* no of rows */
276 static int pager_lines_printed = 0; /* no of lines printed so far */
278 static void restart(bool run) ATTRIBUTE_NORETURN;
279 static void close_all(void);
280 static int open_readfd(const char *file);
281 static int find_lines(SRCFILE *s);
282 static SRCFILE *source_find(char *src);
283 static int print_lines(char *src, int start_line, int nlines);
284 static void print_symbol(NODE *r, bool isparam);
285 static NODE *find_frame(long num);
286 static NODE *find_param(const char *name, long num, char **pname);
287 static NODE *find_symbol(const char *name, char **pname);
288 static NODE *find_array(const char *name);
289 static void print_field(long field_num);
290 static int print_function(INSTRUCTION *pc, void *);
291 static void print_frame(NODE *func, char *src, int srcline);
292 static void print_numbered_frame(long num);
293 static void print_cur_frame_and_sourceline(void);
294 static INSTRUCTION *find_rule(char *src, long lineno);
295 static INSTRUCTION *mk_breakpoint(char *src, int srcline);
296 static int execute_commands(struct commands_item *commands);
297 static void delete_commands_item(struct commands_item *c);
298 static NODE *execute_code(volatile INSTRUCTION *code);
299 static int pre_execute_code(INSTRUCTION **pi);
300 static int parse_condition(int type, int num, char *expr);
301 static BREAKPOINT *add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent);
302 static BREAKPOINT *set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip);
303 static BREAKPOINT *set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent);
304 static void delete_breakpoint(BREAKPOINT *b);
305 static BREAKPOINT *find_breakpoint(long num);
306 static void display(struct list_item *d);
307 static struct list_item *find_item(struct list_item *list, long num);
308 static struct list_item *add_item(struct list_item *list, int type, NODE *symbol, char *pname);
309 static void delete_item(struct list_item *d);
310 static int breakpoint_triggered(BREAKPOINT *b);
311 static int watchpoint_triggered(struct list_item *w);
312 static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump);
313 static int print_code(INSTRUCTION *pc, void *x);
314 static void next_command();
315 static void debug_post_execute(INSTRUCTION *pc);
316 static int debug_pre_execute(INSTRUCTION **pi);
317 static char *g_readline(const char *prompt);
318 static int prompt_yes_no(const char *, char , int , FILE *);
319 static struct pf_data {
320 Func_print print_func;
325 char * (*read_a_line)(const char *) = 0; /* reads a line of input */
327 struct command_source
331 char * (*read_func)(const char *);
332 int (*close_func)(int);
333 int eof_status; /* see push_cmd_src */
334 int cmd; /* D_source or 0 */
335 char *str; /* sourced file */
336 struct command_source *next;
339 static struct command_source *cmd_src = NULL;
342 #define CHECK_PROG_RUNNING() \
344 if (! prog_running) { \
345 d_error(_("program not running.")); \
351 /* g_readline -- read a line of text; the interface is like 'readline' but
352 * without any command-line editing; used when not compiled with
353 * readline support and/or input is not from terminal (prompt set to NULL).
357 g_readline(const char *prompt)
360 size_t line_size = 100;
365 if (input_from_tty && prompt && *prompt)
366 fprintf(out_fp, "%s", prompt);
368 emalloc(line, char *, line_size + 1, "g_readline");
370 end = line + line_size;
371 while ((n = read(input_fd, buf, 1)) > 0) {
372 if (buf[0] == '\n') {
373 if (p > line && p[-1] == '\r')
378 erealloc(line, char *, 2 * line_size + 1, "g_readline");
379 p = line + line_size;
381 end = line + line_size;
385 if (n == -1 || (n == 0 && p == line)) {
394 /* d_error --- print an error message */
397 d_error(const char *mesg, ...)
400 va_start(args, mesg);
401 fprintf(out_fp, _("error: "));
402 vfprintf(out_fp, mesg, args);
403 fprintf(out_fp, "\n");
407 /* find_lines --- find the positions of the lines in the source file. */
410 find_lines(SRCFILE *s)
419 char lastchar = '\0';
421 emalloc(buf, char *, s->bufsize, "find_lines");
422 pos_size = s->srclines;
423 emalloc(s->line_offset, int *, (pos_size + 2) * sizeof(int), "find_lines");
424 pos = s->line_offset;
427 while ((n = read(s->fd, buf, s->bufsize)) > 0) {
429 lastchar = buf[n - 1];
433 if (++numlines > pos_size) {
434 erealloc(s->line_offset, int *, (2 * pos_size + 2) * sizeof(int), "find_lines");
435 pos = s->line_offset + pos_size;
438 *++pos = ofs + (p - buf);
439 if ((pos[0] - pos[-1]) > maxlen)
440 maxlen = pos[0] - pos[-1]; /* length including NEWLINE */
448 d_error(_("can't read source file `%s' (%s)"),
449 s->src, strerror(errno));
453 fprintf(out_fp, _("source file `%s' is empty.\n"), s->src);
457 if (lastchar != '\n') {
458 /* fake a NEWLINE at end */
461 if ((pos[0] - pos[-1]) > maxlen)
462 maxlen = pos[0] - pos[-1];
465 s->srclines = numlines;
469 /* source_find --- return the SRCFILE struct for the source 'src' */
472 source_find(char *src)
479 if (src == NULL || *src == '\0') {
480 d_error(_("no current source file."));
484 if (cur_srcfile->src == src) /* strcmp(cur_srcfile->src, src) == 0 */
487 for (s = srcfiles->next; s != srcfiles; s = s->next) {
488 if ((s->stype == SRC_FILE || s->stype == SRC_INC)
489 && strcmp(s->src, src) == 0)
493 path = find_source(src, & sbuf, & errno_val, false);
495 for (s = srcfiles->next; s != srcfiles; s = s->next) {
496 if ((s->stype == SRC_FILE || s->stype == SRC_INC)
497 && files_are_same(path, s)) {
505 d_error(_("cannot find source file named `%s' (%s)"), src, strerror(errno_val));
509 /* print_lines --- print source lines, and update 'cur_srcfile' */
512 print_lines(char *src, int start_line, int nlines)
519 s = source_find(src);
522 if (s->fd <= INVALID_HANDLE && (s->fd = srcopen(s)) <= INVALID_HANDLE) {
523 d_error(_("can't open source file `%s' for reading (%s)"),
524 src, strerror(errno));
528 if (fstat(s->fd, &sbuf) == 0 && s->mtime < sbuf.st_mtime) {
529 fprintf(out_fp, _("WARNING: source file `%s' modified since program compilation.\n"),
531 efree(s->line_offset);
532 s->line_offset = NULL;
533 s->mtime = sbuf.st_mtime;
535 /* reopen source file */
537 s->fd = INVALID_HANDLE;
538 if ((s->fd = srcopen(s)) <= INVALID_HANDLE) {
539 d_error(_("can't open source file `%s' for reading (%s)"),
540 src, strerror(errno));
545 /* set binary mode so that byte offset calculations will be right */
546 os_setbinmode(s->fd, O_BINARY);
548 if (s->line_offset == NULL && find_lines(s) != 0)
550 if (start_line < 1 || start_line > s->srclines) {
551 d_error(_("line number %d out of range; `%s' has %d lines"),
552 start_line, src, s->srclines);
557 if ((start_line + nlines - 1) > s->srclines)
558 nlines = s->srclines - start_line + 1;
560 pos = s->line_offset;
561 if (lseek(s->fd, (off_t) pos[start_line - 1], SEEK_SET) < 0) {
562 d_error("%s: %s", src, strerror(errno));
566 if (linebuf == NULL) {
567 emalloc(linebuf, char *, s->maxlen + 20, "print_lines"); /* 19 for line # */
568 linebuf_len = s->maxlen;
569 } else if (linebuf_len < s->maxlen) {
570 erealloc(linebuf, char *, s->maxlen + 20, "print_lines");
571 linebuf_len = s->maxlen;
574 for (i = start_line; i < start_line + nlines; i++) {
575 int supposed_len, len;
578 sprintf(linebuf, "%-8d", i);
580 /* mark the line about to be executed with =>; nlines > 1
581 * condition makes sure that we are in list command
585 bool has_bpt = false;
586 for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
587 if (src == b->src && i == b->bpi->source_line) {
592 if (prog_running && src == source && i == sourceline) {
594 sprintf(linebuf, "%-4d:b=>", i);
596 sprintf(linebuf, "%-4d =>", i);
598 sprintf(linebuf, "%-4d:b ", i);
601 p = linebuf + strlen(linebuf);
602 supposed_len = pos[i] - pos[i - 1];
603 len = read(s->fd, p, supposed_len);
606 d_error(_("can't read source file `%s' (%s)"),
607 src, strerror(errno));
611 d_error(_("unexpected eof while reading file `%s', line %d"),
616 if (i == s->srclines && p[len - 1] != '\n')
619 if (len != supposed_len || p[len - 1] != '\n') {
620 d_error(_("source file `%s' modified since start of program execution"),
625 len += (p - linebuf);
626 if (fwrite(linebuf, sizeof(char), len, out_fp) != len)
631 if (cur_srcfile != s) {
632 if (cur_srcfile->fd != INVALID_HANDLE) {
633 close(cur_srcfile->fd);
634 cur_srcfile->fd = INVALID_HANDLE;
638 return (i - 1); /* no of lines printed */
641 /* do_list --- list command */
644 do_list(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
646 long line_first, line_last;
647 long count = list_size;
649 char *src = cur_srcfile->src;
651 line_first = last_printed_line + 1; /* default or no arg */
652 if (arg == NULL) /* list or list + */
656 case D_int: /* list n or list - */
657 if (arg->a_int < 0) { /* list - */
658 line_first = last_printed_line - last_print_count - list_size + 1;
659 if (line_first < 1) {
660 if (last_printed_line != last_print_count)
667 line_first = arg->a_int - list_size / 2;
673 case D_range: /* list m-n */
675 line_first = arg->a_int;
678 assert(arg->type == D_int);
679 count = arg->a_int - line_first + 1;
684 if (arg->next != NULL) {
686 if (arg->type == D_int) /* list file:n */
688 else if (arg->type == D_range) /* list file:m-n */
690 else if (arg->type == D_func) /* list file:function */
698 case D_func: /* list function */
700 rp = arg->a_node->code_ptr;
701 src = rp->source_file;
702 line_first = rp->source_line - list_size / 2;
712 line_last = print_lines(src, line_first, count);
713 if (line_last != -1) {
714 last_printed_line = line_last;
715 last_print_count = line_last - line_first + 1;
720 /* do_info --- info command */
723 do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
727 if (arg == NULL || arg->type != D_argument)
730 switch (arg->a_argument) {
732 fprintf(out_fp, _("Current source file: %s\n"), cur_srcfile->src);
733 fprintf(out_fp, _("Number of lines: %d\n"), cur_srcfile->srclines);
739 for (s = srcfiles->next; s != srcfiles; s = s->next) {
740 fprintf(out_fp, _("Source file (lines): %s (%d)\n"),
741 (s->stype == SRC_FILE || s->stype == SRC_INC) ? s->src
749 initialize_pager(out_fp);
750 if (setjmp(pager_quit_tag) == 0) {
752 struct commands_item *c;
754 gprintf(out_fp, _("Number Disp Enabled Location\n\n"));
755 for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
757 if ((b->flags & BP_ENABLE_ONCE) != 0)
759 else if ((b->flags & BP_TEMP) != 0)
761 gprintf(out_fp, "%-6d %-4.4s %-7.7s file %s, line #%d\n",
762 b->number, disp, (b->flags & BP_ENABLE) != 0 ? "yes" : "no",
763 b->src, b->bpi->source_line);
764 if (b->hit_count > 0)
765 gprintf(out_fp, _("\tno of hits = %ld\n"), b->hit_count);
766 if ((b->flags & BP_IGNORE) != 0)
767 gprintf(out_fp, _("\tignore next %ld hit(s)\n"), b->ignore_count);
768 if (b->cndn.code != NULL)
769 gprintf(out_fp, _("\tstop condition: %s\n"), b->cndn.expr);
770 if (b->commands.next != &b->commands)
771 gprintf(out_fp, _("\tcommands:\n"));
772 for (c = b->commands.next; c != &b->commands; c = c->next) {
773 gprintf(out_fp, "\t%s\n", c->cmd_string);
774 if (c->cmd == D_eval) {
777 start = strchr(a->a_string, '{');
778 end = strrchr(a->a_string, '}');
779 if (start == NULL || end == NULL)
783 gprintf(out_fp, "%s", start); /* FIXME: translate ? */
792 CHECK_PROG_RUNNING();
793 fprintf(out_fp, _("Current frame: "));
794 print_numbered_frame(cur_frame);
795 if (cur_frame < fcall_count) {
796 fprintf(out_fp, _("Called by frame: "));
797 print_numbered_frame(cur_frame + 1);
800 fprintf(out_fp, _("Caller of frame: "));
801 print_numbered_frame(cur_frame - 1);
810 int arg_count, pcount;
813 CHECK_PROG_RUNNING();
814 f = find_frame(cur_frame);
818 fprintf(out_fp, _("None in main().\n"));
822 pcount = func->param_cnt; /* # of defined params */
824 pc = (INSTRUCTION *) f->reti; /* Op_func_call instruction */
825 arg_count = (pc + 1)->expr_count; /* # of arguments supplied */
827 if (arg_count > pcount) /* extra args */
829 if (arg->a_argument == A_ARGS) {
837 for (i = from; i <= to; i++) {
840 if (r->type == Node_array_ref)
842 fprintf(out_fp, "%s = ", func->fparms[i].param);
843 print_symbol(r, true);
846 fprintf(out_fp, "%s",
847 arg->a_argument == A_ARGS ?
848 _("No arguments.\n") :
854 table = variable_list();
855 initialize_pager(out_fp);
856 if (setjmp(pager_quit_tag) == 0) {
857 gprintf(out_fp, _("All defined variables:\n\n"));
858 print_vars(table, gprintf, out_fp);
864 table = function_list(true);
865 initialize_pager(out_fp);
866 if (setjmp(pager_quit_tag) == 0) {
867 gprintf(out_fp, _("All defined functions:\n\n"));
868 pf_data.print_func = gprintf;
871 (void) foreach_func(table,
872 (int (*)(INSTRUCTION *, void *)) print_function,
880 initialize_pager(out_fp);
881 if (setjmp(pager_quit_tag) == 0) {
882 struct list_item *d, *list;
884 if (arg->a_argument == A_DISPLAY) {
885 list = &display_list;
886 gprintf(out_fp, _("Auto-display variables:\n\n"));
889 gprintf(out_fp, _("Watch variables:\n\n"));
891 for (d = list->prev; d != list; d = d->prev) {
893 struct commands_item *c;
894 NODE *symbol = d->symbol;
896 if (IS_SUBSCRIPT(d)) {
897 gprintf(out_fp, "%d:\t%s", d->number, d->sname);
898 for (i = 0; i < d->num_subs; i++) {
901 gprintf(out_fp, "[\"%s\"]", sub->stptr);
903 gprintf(out_fp, "\n");
904 } else if (IS_FIELD(d))
905 gprintf(out_fp, "%d:\t$%ld\n", d->number, get_number_si(symbol));
907 gprintf(out_fp, "%d:\t%s\n", d->number, d->sname);
908 if (d->cndn.code != NULL)
909 gprintf(out_fp, _("\tstop condition: %s\n"), d->cndn.expr);
910 if (d->commands.next != &d->commands)
911 gprintf(out_fp, _("\tcommands:\n"));
912 for (c = d->commands.next; c != &d->commands; c = c->next) {
913 gprintf(out_fp, "\t%s\n", c->cmd_string);
914 if (c->cmd == D_eval) {
917 start = strchr(a->a_string, '{');
918 end = strrchr(a->a_string, '}');
919 if (start == NULL || end == NULL)
923 gprintf(out_fp, "%s", start); /* FIXME: translate ? */
939 /* print_symbol --- print a symbol table entry */
942 print_symbol(NODE *r, bool isparam)
946 fprintf(out_fp, "untyped variable\n");
949 if (! isparam && r->var_update)
951 valinfo(r->var_value, fprintf, out_fp);
954 fprintf(out_fp, "array, %ld elements\n", assoc_length(r));
957 fprintf(out_fp, "`function'\n");
964 /* find_frame --- find frame given a frame number */
973 assert(prog_running == true);
974 assert(num <= fcall_count);
975 assert(fcall_list[num] != NULL);
976 return fcall_list[num];
979 /* find_param --- find a function parameter in a given frame number */
982 find_param(const char *name, long num, char **pname)
991 if (num < 0 || num > fcall_count || name == NULL)
994 if (f->func_node != NULL) { /* in function */
999 pcount = func->param_cnt;
1000 for (i = 0; i < pcount; i++) {
1001 fparam = func->fparms[i].param;
1002 if (strcmp(name, fparam) == 0) {
1004 if (r->type == Node_array_ref)
1015 /* find_symbol --- find a symbol in current context */
1018 NODE *find_symbol(const char *name, char **pname)
1025 r = find_param(name, cur_frame, pname);
1029 fprintf(out_fp, _("no symbol `%s' in current context\n"), name);
1033 /* find_array -- find an array in current context */
1036 find_array(const char *name)
1039 r = find_symbol(name, NULL);
1040 if (r != NULL && r->type != Node_var_array) {
1041 fprintf(out_fp, _("`%s' is not an array\n"), name);
1047 /* print_field --- print the value of $n */
1050 print_field(long field_num)
1053 lhs = get_field(field_num, NULL);
1054 if (*lhs == Null_field || *lhs == Nnull_string)
1055 fprintf(out_fp, _("$%ld = uninitialized field\n"), field_num);
1057 fprintf(out_fp, "$%ld = ", field_num);
1058 valinfo(*lhs, fprintf, out_fp);
1062 /* print_array --- print the contents of an array */
1065 print_array(volatile NODE *arr, char *arr_name)
1070 size_t num_elems = 0;
1072 volatile int ret = 0;
1073 volatile jmp_buf pager_quit_tag_stack;
1075 if (assoc_empty((NODE *) arr)) {
1076 gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
1080 num_elems = assoc_length((NODE *) arr);
1082 /* sort indices, sub_arrays are also sorted! */
1083 list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN);
1085 PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1086 if (setjmp(pager_quit_tag) == 0) {
1087 for (i = 0; ret == 0 && i < num_elems; i++) {
1089 r = *assoc_lookup((NODE *) arr, subs);
1090 if (r->type == Node_var_array)
1091 ret = print_array(r, r->vname);
1093 gprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
1094 valinfo((NODE *) r, gprintf, out_fp);
1100 POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1102 for (i = 0; i < num_elems; i++)
1109 /* print_subscript --- print an array element */
1112 print_subscript(NODE *arr, char *arr_name, CMDARG *a, int count)
1117 r = in_array(arr, subs);
1119 fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"), subs->stptr, arr_name);
1120 else if (r->type == Node_var_array) {
1122 print_subscript(r, r->vname, a->next, count - 1);
1124 /* print # of elements in array */
1125 fprintf(out_fp, "%s = ", r->vname);
1126 print_symbol(r, false);
1129 fprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
1130 valinfo(r, fprintf, out_fp);
1134 /* do_print_var --- print command */
1137 do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1143 for (a = arg; a != NULL; a = a->next) {
1147 if ((r = find_symbol(name, &pname)) != NULL) {
1148 fprintf(out_fp, "%s = ", name);
1149 print_symbol(r, (pname != NULL));
1154 assert(a->a_count > 0);
1156 r = find_array(name);
1158 print_subscript(r, name, a->next, a->a_count);
1163 if ((r = find_array(name)) != NULL) {
1164 int count = a->a_count;
1165 for (; count > 0; count--) {
1169 value = in_array(r, subs);
1170 if (value == NULL) {
1171 fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"),
1174 } else if (value->type != Node_var_array) {
1175 fprintf(out_fp, _("`%s[\"%s\"]' is not an array\n"),
1184 initialize_pager(out_fp);
1185 print_array((volatile NODE *) r, name);
1191 print_field(get_number_si(a->a_node));
1195 /* notably D_node, subscript for invalid array name; skip */
1202 /* do_set_var --- set command */
1205 do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1211 switch (arg->type) {
1213 name = arg->a_string;
1217 if ((r = find_symbol(name, &pname)) == NULL)
1223 r->var_value = dupnode(Nnull_string);
1226 lhs = &r->var_value;
1228 *lhs = dupnode(val);
1229 if (pname == NULL && r->var_assign != NULL)
1231 fprintf(out_fp, "%s = ", name);
1232 print_symbol(r, (pname != NULL));
1236 d_error(_("`%s' is not a scalar variable"), name);
1244 int count = arg->a_count;
1247 name = arg->a_string;
1248 r = find_array(name);
1251 for (; count > 0; count--) {
1254 value = in_array(r, subs);
1257 if (value != NULL && value->type == Node_var_array)
1258 d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
1263 lhs = assoc_lookup(r, subs);
1265 *lhs = dupnode(val);
1266 fprintf(out_fp, "%s[\"%s\"] = ", name, subs->stptr);
1267 valinfo(*lhs, fprintf, out_fp);
1270 if (value == NULL) {
1272 array = make_array();
1273 array->vname = estrdup(subs->stptr, subs->stlen);
1274 array->parent_array = r;
1275 lhs = assoc_lookup(r, subs);
1279 } else if (value->type != Node_var_array) {
1280 d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
1295 Func_ptr assign = NULL;
1297 field_num = get_number_si(arg->a_node);
1298 assert(field_num >= 0);
1301 lhs = get_field(field_num, &assign);
1303 *lhs = dupnode(val);
1306 print_field(field_num);
1316 /* find_item --- find an item in the watch/display list */
1318 static struct list_item *
1319 find_item(struct list_item *list, long num)
1321 struct list_item *d;
1325 for (d = list->next; d != list; d = d->next) {
1326 if (d->number == num)
1332 /* delete_item --- delete an item from the watch/display list */
1335 delete_item(struct list_item *d)
1337 struct commands_item *c;
1340 if (IS_SUBSCRIPT(d)) {
1341 for (i = 0; i < d->num_subs; i++)
1344 } else if (IS_FIELD(d))
1347 if ((d->flags & CUR_IS_ARRAY) == 0)
1348 unref(d->cur_value);
1349 if ((d->flags & OLD_IS_ARRAY) == 0)
1350 unref(d->old_value);
1352 /* delete commands */
1353 for (c = d->commands.next; c != &d->commands; c = c->next) {
1355 delete_commands_item(c->next);
1358 free_context(d->cndn.ctxt, false);
1359 if (d->cndn.expr != NULL)
1360 efree(d->cndn.expr);
1362 d->next->prev = d->prev;
1363 d->prev->next = d->next;
1367 /* add_item --- craete a watch/display item and add it to the list */
1369 static struct list_item *
1370 add_item(struct list_item *list, int type, NODE *symbol, char *pname)
1372 struct list_item *d;
1374 emalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
1375 memset(d, 0, sizeof(struct list_item));
1376 d->commands.next = d->commands.prev = &d->commands;
1378 d->number = ++list->number;
1379 d->sname = symbol->vname;
1380 if (pname != NULL) { /* function param */
1383 d->fcall_count = fcall_count - cur_frame;
1386 if (type == D_field) {
1389 d->flags |= FIELD_NUM;
1390 } else if (type == D_subscript) {
1393 d->flags |= SUBSCRIPT;
1395 /* array or variable */
1400 d->next = list->next;
1407 /* do_add_item --- add an item to the watch/display list */
1409 static struct list_item *
1410 do_add_item(struct list_item *list, CMDARG *arg)
1412 NODE *symbol = NULL;
1413 char *name, *pname = NULL;
1414 struct list_item *item = NULL;
1416 switch (arg->type) {
1419 name = arg->a_string;
1420 if ((symbol = find_symbol(name, &pname)) == NULL)
1422 if (symbol->type == Node_func) {
1423 d_error(_("`%s' is a function"), name);
1426 if (arg->type == D_subscript && symbol->type != Node_var_array) {
1427 d_error(_("`%s' is not an array\n"), name);
1431 item = add_item(list, arg->type, symbol, pname);
1432 if (item != NULL && arg->type == D_subscript) {
1434 int count = arg->a_count;
1438 emalloc(subs, NODE **, count * sizeof(NODE *), "do_add_item");
1439 for (i = 0; i < count; i++) {
1441 subs[i] = dupnode(arg->a_node);
1442 subs[i] = force_string(subs[i]);
1445 item->num_subs = count;
1450 symbol = dupnode(arg->a_node);
1451 item = add_item(list, D_field, symbol, NULL);
1458 /* watch condition if any */
1459 if (list == &watch_list) {
1461 if (item != NULL && arg != NULL) {
1462 if (parse_condition(D_watch, item->number, arg->a_string) == 0)
1463 arg->a_string = NULL; /* don't let free_cmdarg free it */
1465 fprintf(out_fp, _("watchpoint %d is unconditional\n"), item->number);
1471 /* do_delete_item --- delete a watch/display item from list. */
1474 do_delete_item(struct list_item *list, CMDARG *arg)
1477 while (list->next != list)
1478 delete_item(list->next);
1481 for (; arg != NULL; arg = arg->next) {
1482 struct list_item *d;
1483 if (arg->type == D_range) {
1489 if (j > list->number)
1491 for (; i <= j; i++) {
1492 if ((d = find_item(list, i)) != NULL)
1496 if ((d = find_item(list, arg->a_int)) == NULL) {
1497 /* split into two for easier message translation */
1498 if (list == &display_list)
1499 d_error(_("No display item numbered %ld"),
1502 d_error(_("No watch item numbered %ld"),
1510 /* display --- print an item from the auto-display list */
1513 display(struct list_item *d)
1518 if (IS_PARAM(d) && (d->fcall_count != (fcall_count - cur_frame)))
1521 if (IS_SUBSCRIPT(d)) {
1523 int i = 0, count = d->num_subs;
1524 for (i = 0; i < count; i++) {
1526 r = in_array(symbol, sub);
1528 fprintf(out_fp, _("%d: [\"%s\"] not in array `%s'\n"),
1529 d->number, sub->stptr, d->sname);
1532 if (r->type == Node_var_array) {
1534 if (i == count - 1) /* it's a sub-array */
1535 goto print_sym; /* print # of elements in sub-array */
1538 return; /* FIXME msg and delete item ? */
1539 fprintf(out_fp, "%d: %s[\"%s\"] = ", d->number,
1540 d->sname, sub->stptr);
1541 valinfo(r, fprintf, out_fp);
1544 } else if (IS_FIELD(d)) {
1545 NODE *r = d->symbol;
1546 fprintf(out_fp, "%d: ", d->number);
1547 print_field(get_number_si(r));
1550 fprintf(out_fp, "%d: %s = ", d->number, d->sname);
1551 print_symbol(symbol, IS_PARAM(d));
1556 /* do_display --- display command */
1559 do_display(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1561 struct list_item *d;
1564 /* display all items */
1565 for (d = display_list.prev; d != &display_list; d = d->prev)
1570 if ((d = do_add_item(&display_list, arg)) != NULL)
1576 /* do_undisplay --- undisplay command */
1579 do_undisplay(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1581 do_delete_item(&display_list, arg);
1585 /* condition_triggered --- test if a condition expression is true */
1588 condition_triggered(struct condition *cndn)
1593 assert(cndn != NULL);
1594 if (cndn->code == NULL)
1597 push_context(cndn->ctxt);
1598 r = execute_code((volatile INSTRUCTION *) cndn->code);
1599 pop_context(); /* switch to prev context */
1600 if (r == NULL) /* fatal error */
1601 return false; /* not triggered */
1611 find_subscript(struct list_item *item, NODE **ptr)
1613 NODE *symbol = item->symbol;
1615 int i = 0, count = item->num_subs;
1618 for (i = 0; i < count; i++) {
1619 sub = item->subs[i];
1620 r = in_array(symbol, sub);
1623 if (r->type == Node_var_array)
1625 else if (i < count - 1)
1633 /* cmp_val --- compare values of watched item, returns true if different; */
1636 cmp_val(struct list_item *w, NODE *old, NODE *new)
1639 * case old new result
1640 * ------------------------------
1641 * 1: NULL ARRAY true
1642 * 2: NULL SCALAR true
1643 * 3: NULL NULL false
1644 * 4: SCALAR SCALAR cmp_node
1645 * 5: SCALAR ARRAY true
1646 * 6: SCALAR NULL true
1647 * 7: ARRAY SCALAR true
1648 * 8: ARRAY ARRAY compare size
1649 * 9: ARRAY NULL true
1652 if (WATCHING_ARRAY(w)) {
1656 if (new->type == Node_val) /* 7 */
1658 /* new->type == Node_var_array */ /* 8 */
1659 size = assoc_length(new);
1660 if (w->cur_size == size)
1665 if (! old && ! new) /* 3 */
1667 if ((! old && new) /* 1, 2 */
1668 || (old && ! new)) /* 6 */
1671 if (new->type == Node_var_array) /* 5 */
1673 return cmp_nodes(old, new); /* 4 */
1676 /* watchpoint_triggered --- check if we should stop at this watchpoint;
1677 * update old and current values accordingly.
1681 watchpoint_triggered(struct list_item *w)
1687 if (IS_PARAM(w) && (w->fcall_count != (fcall_count - cur_frame)))
1688 return 0; /* parameter with same name in a different function */
1689 if (! condition_triggered(&w->cndn))
1694 if (IS_SUBSCRIPT(w))
1695 (void) find_subscript(w, &t2);
1696 else if (IS_FIELD(w)) {
1698 field_num = get_number_si(w->symbol);
1699 t2 = *get_field(field_num, NULL);
1701 switch (symbol->type) {
1703 t2 = symbol->var_value;
1705 case Node_var_array:
1715 if (! cmp_val(w, t1, t2))
1718 /* update old and current values */
1720 if ((w->flags & OLD_IS_ARRAY) == 0)
1721 unref(w->old_value);
1722 w->flags &= ~OLD_IS_ARRAY;
1723 if (WATCHING_ARRAY(w)) { /* 7, 8, 9 */
1724 w->old_size = w->cur_size;
1725 w->flags |= OLD_IS_ARRAY;
1727 w->flags &= ~CUR_IS_ARRAY;
1729 } else if (t2->type == Node_val) {
1730 w->flags &= ~CUR_IS_ARRAY;
1731 w->cur_value = dupnode(t2);
1733 w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0;
1734 } else if (! t1) { /* 1, 2 */
1737 if (t2->type == Node_val)
1738 w->cur_value = dupnode(t2);
1740 w->flags |= CUR_IS_ARRAY;
1741 w->cur_size = (t2->type == Node_var_array) ? assoc_length(t2) : 0;
1743 } else /* if (t1->type == Node_val) */ { /* 4, 5, 6 */
1744 w->old_value = w->cur_value;
1747 else if (t2->type == Node_var_array) {
1748 w->flags |= CUR_IS_ARRAY;
1749 w->cur_size = assoc_length(t2);
1751 w->cur_value = dupnode(t2);
1757 /* initialize_watch_item --- initialize current value of a watched item */
1760 initialize_watch_item(struct list_item *w)
1763 NODE *symbol = w->symbol;
1765 if (IS_SUBSCRIPT(w)) {
1766 if (find_subscript(w, &r) == -1) {
1767 d_error(_("attempt to use scalar value as array"));
1772 w->cur_value = (NODE *) 0;
1773 else if (r->type == Node_var_array) { /* it's a sub-array */
1774 w->flags |= CUR_IS_ARRAY;
1775 w->cur_size = assoc_length(r);
1777 w->cur_value = dupnode(r);
1778 } else if (IS_FIELD(w)) {
1781 field_num = get_number_si(t);
1782 r = *get_field(field_num, NULL);
1783 w->cur_value = dupnode(r);
1785 if (symbol->type == Node_var_new)
1786 w->cur_value = (NODE *) 0;
1787 else if (symbol->type == Node_var) {
1788 r = symbol->var_value;
1789 w->cur_value = dupnode(r);
1790 } else if (symbol->type == Node_var_array) {
1791 w->flags |= CUR_IS_ARRAY;
1792 w->cur_size = assoc_length(symbol);
1799 /* do_watch --- watch command */
1802 do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1804 struct list_item *w;
1808 w = do_add_item(&watch_list, arg);
1812 if (initialize_watch_item(w) == -1) {
1817 fprintf(out_fp, "Watchpoint %d: ", w->number);
1820 /* FIXME: common code also in print_watch_item */
1821 if (IS_SUBSCRIPT(w)) {
1822 fprintf(out_fp, "%s", w->sname);
1823 for (i = 0; i < w->num_subs; i++) {
1825 fprintf(out_fp, "[\"%s\"]", sub->stptr);
1827 fprintf(out_fp, "\n");
1828 } else if (IS_FIELD(w))
1829 fprintf(out_fp, "$%ld\n", get_number_si(symbol));
1831 fprintf(out_fp, "%s\n", w->sname);
1836 /* do_unwatch --- unwatch command */
1839 do_unwatch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1841 do_delete_item(&watch_list, arg);
1845 /* callback from pop_frame in eval.c */
1850 struct list_item *item;
1852 /* delete all out of scope watchpoints */
1853 for (item = watch_list.next; item != &watch_list; item = item->next) {
1854 if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1856 _("Watchpoint %d deleted because parameter is out of scope.\n"),
1859 delete_item(item->next);
1863 /* delete all out of scope display items */
1864 for (item = display_list.next; item != &display_list; item = item->next) {
1865 if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1867 _("Display %d deleted because parameter is out of scope.\n"),
1870 delete_item(item->next);
1875 /* print_function --- print function name, parameters, and optionally
1876 * file and line number.
1880 print_function(INSTRUCTION *pc, void *x)
1884 struct pf_data *data = (struct pf_data *) x;
1885 int defn = data->defn;
1886 Func_print print_func = data->print_func;
1887 FILE *fp = data->fp;
1889 func = pc->func_body;
1890 pcount = func->param_cnt;
1892 print_func(fp, "%s(", func->vname);
1893 for (i = 0; i < pcount; i++) {
1894 print_func(fp, "%s", func->fparms[i].param);
1896 print_func(fp, ", ");
1898 print_func(fp, ")");
1900 print_func(fp, _(" in file `%s', line %d\n"),
1901 pc->source_file, pc->source_line);
1905 /* print_frame --- print function name, parameters,
1906 * source and line number of where it is
1911 print_frame(NODE *func, char *src, int srcline)
1914 fprintf(out_fp, "main()");
1916 pf_data.print_func = fprintf;
1917 pf_data.fp = out_fp;
1918 pf_data.defn = false;
1919 (void) print_function(func->code_ptr, &pf_data);
1921 fprintf(out_fp, _(" at `%s':%d"), src, srcline);
1924 /* print_numbered_frame --- print a frame given its number */
1927 print_numbered_frame(long num)
1931 assert(prog_running == true);
1932 f = find_frame(num);
1934 fprintf(out_fp, "#%ld\t ", num);
1935 print_frame(f->func_node, source, sourceline);
1937 fprintf(out_fp, _("#%ld\tin "), num);
1938 print_frame(f->func_node, f->vname,
1939 ((INSTRUCTION *) find_frame(num - 1)->reti)->source_line);
1941 fprintf(out_fp, "\n");
1944 /* do_backtrace --- backtrace command */
1947 do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1950 long last = fcall_count;
1952 CHECK_PROG_RUNNING();
1953 if (arg != NULL && arg->type == D_int) {
1954 long count = arg->a_int;
1956 /* frame_ptr (frame #0), fcall_list[1, 2, ... fcall_count] => total count */
1958 /* toward outermost frame #fcall_count */
1960 if (last > fcall_count)
1963 /* toward innermost frame #0 */
1964 cur = 1 + fcall_count + count;
1970 for (; cur <= last; cur++) {
1971 print_numbered_frame(cur);
1973 if (cur <= fcall_count)
1974 fprintf(out_fp, _("More stack frames follow ...\n"));
1978 /* print_cur_frame_and_sourceline --- print current frame, and
1979 * current source line.
1983 print_cur_frame_and_sourceline()
1989 assert(prog_running == true);
1990 f = find_frame(cur_frame);
1991 if (cur_frame == 0) {
1993 srcline = sourceline;
1995 f = find_frame(cur_frame);
1997 srcline = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
2000 fprintf(out_fp, (cur_frame > 0 ? _("#%ld\tin ") : "#%ld\t "), cur_frame);
2001 print_frame(f->func_node, src, srcline);
2002 fprintf(out_fp, "\n");
2003 print_lines(src, srcline, 1);
2004 last_printed_line = srcline - list_size / 2;
2005 if (last_printed_line < 0)
2006 last_printed_line = 0;
2009 /* do_frame --- frame command */
2012 do_frame(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2014 CHECK_PROG_RUNNING();
2015 if (arg && arg->type == D_int) {
2016 if (arg->a_int < 0 || arg->a_int > fcall_count) {
2017 d_error(_("invalid frame number"));
2020 cur_frame = arg->a_int;
2022 print_cur_frame_and_sourceline();
2026 /* do_up --- up command */
2029 do_up(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2031 CHECK_PROG_RUNNING();
2032 if (arg != NULL && arg->type == D_int)
2033 cur_frame += arg->a_int;
2038 else if (cur_frame > fcall_count)
2039 cur_frame = fcall_count;
2040 print_cur_frame_and_sourceline();
2044 /* do_down --- down command */
2047 do_down(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2049 CHECK_PROG_RUNNING();
2050 if (arg != NULL && arg->type == D_int)
2051 cur_frame -= arg->a_int;
2056 else if (cur_frame > fcall_count)
2057 cur_frame = fcall_count;
2058 print_cur_frame_and_sourceline();
2062 /* find_rule --- find a rule or function in file 'src' containing
2063 * source line 'lineno'
2066 static INSTRUCTION *
2067 find_rule(char *src, long lineno)
2072 * FIXME: The check for zero and code that goes with it
2073 * are probably fragile. A break with no arguments can
2074 * cause this in certain cases. Try to review how this works.
2077 for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) {
2078 if ((rp - 1)->source_file == src && (rp - 1)->source_line > 0)
2082 for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) {
2083 if ((rp - 1)->source_file == src
2084 && lineno >= (rp + 1)->first_line
2085 && lineno <= (rp + 1)->last_line)
2092 /* mk_breakpoint --- create a breakpoint instruction and the corresponding
2093 * breakpoint structure.
2096 static INSTRUCTION *
2097 mk_breakpoint(char *src, int srcline)
2102 bp = bcalloc(Op_breakpoint, 1, srcline);
2103 emalloc(b, BREAKPOINT *, sizeof(BREAKPOINT), "mk_breakpoint");
2104 memset(&b->cndn, 0, sizeof(struct condition));
2105 b->commands.next = b->commands.prev = &b->commands;
2109 b->number = ++watch_list.number; /* breakpoints and watchpoints use same counter */
2110 b->ignore_count = 0;
2112 b->flags = BP_ENABLE;
2117 /* prepend to list */
2118 b->next = breakpoints.next;
2119 b->prev = &breakpoints;
2120 breakpoints.next = b;
2125 /* delete_breakpoint --- delete a breakpoint structure and
2126 * disable the breakpoint instruction.
2130 delete_breakpoint(BREAKPOINT *b)
2132 INSTRUCTION *pc = b->bpi;
2133 struct commands_item *c;
2135 /* N.B.: easiest thing to do is to turn Op_breakpoint into a no-op;
2136 * deleteing the instruction is not that simple,
2137 * since could have reference to it somewhere else (e.g. cur_pc).
2140 pc->opcode = Op_no_op;
2141 pc->source_line = 0;
2142 pc->break_pt = NULL;
2144 /* delete commands */
2145 for (c = b->commands.next; c != &b->commands; c = c->next) {
2147 delete_commands_item(c->next);
2150 free_context(b->cndn.ctxt, false);
2151 if (b->cndn.expr != NULL)
2152 efree(b->cndn.expr);
2154 /* remove from list */
2155 b->next->prev = b->prev;
2156 b->prev->next = b->next;
2160 /* find_breakpoint --- find the breakpoint structure from a breakpoint number */
2163 find_breakpoint(long num)
2170 for (b = breakpoints.next; b != &breakpoints; b = b->next) {
2171 if (b->number == num)
2177 /* add_breakpoint --- add a breakpoint instruction between PREVP and IP */
2180 add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, bool silent)
2184 int lineno = ip->source_line;
2186 /* add new breakpoint instruction at the end of
2187 * already set breakpoints at this line number.
2190 while (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2194 * This is more verbose that it might otherwise be,
2195 * in order to provide easily translatable strings.
2197 if ((b->flags & BP_ENABLE) != 0) {
2198 if ((b->flags & BP_IGNORE) != 0)
2200 _("Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d"),
2207 _("Note: breakpoint %d (enabled), also set at %s:%d"),
2212 if ((b->flags & BP_IGNORE) != 0)
2214 _("Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d"),
2221 _("Note: breakpoint %d (disabled), also set at %s:%d"),
2231 assert(ip->source_line == lineno);
2233 bp = mk_breakpoint(src, lineno);
2238 fprintf(out_fp, _("Breakpoint %d set at file `%s', line %d\n"),
2239 b->number, src, lineno);
2243 /* set_breakpoint_at --- set a breakpoint at given line number*/
2246 set_breakpoint_at(INSTRUCTION *rp, int lineno, bool silent)
2248 INSTRUCTION *ip, *prevp;
2250 for (prevp = rp, ip = rp->nexti; ip; prevp = ip, ip = ip->nexti) {
2251 if (ip->opcode == Op_K_case) {
2252 INSTRUCTION *i1, *i2;
2254 /* Special case: the code line numbers for a switch do not form
2255 * a monotonically increasing sequence. Check if the line # is between
2256 * the first and last statements of the case block before continuing
2259 for (i2 = ip->stmt_start, i1 = i2->nexti; i2 != ip->stmt_end;
2260 i2 = i1, i1 = i1->nexti) {
2261 if (i1->source_line >= lineno)
2262 return add_breakpoint(i2, i1, rp->source_file, silent);
2263 if (i1 == ip->stmt_end)
2268 if (ip->source_line >= lineno)
2269 return add_breakpoint(prevp, ip, rp->source_file, silent);
2270 if (ip == (rp + 1)->lasti)
2276 /* set_breakpoint_next --- set a breakpoint at the next instruction */
2279 set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip)
2283 if (ip == (rp + 1)->lasti)
2286 if (ip->opcode != Op_breakpoint)
2288 for (; ip; prevp = ip, ip = ip->nexti) {
2289 if (ip->source_line > 0)
2290 return add_breakpoint(prevp, ip, rp->source_file, false);
2291 if (ip == (rp + 1)->lasti)
2297 /* set_breakpoint --- set a breakpoint */
2300 set_breakpoint(CMDARG *arg, bool temporary)
2303 BREAKPOINT *b = NULL;
2304 INSTRUCTION *rp, *ip;
2306 SRCFILE *s = cur_srcfile;
2307 char *src = cur_srcfile->src;
2311 * (From GDB Documentation):
2313 * When called without any arguments, break sets a breakpoint at the next instruction
2314 * to be executed in the selected stack frame (see section Examining the Stack).
2315 * In any selected frame but the innermost, this makes your program stop as soon
2316 * as control returns to that frame. This is similar to the effect of a finish command
2317 * in the frame inside the selected frame--except that finish does not leave an
2318 * active breakpoint. If you use break without an argument in the innermost frame,
2319 * GDB stops the next time it reaches the current location; this may be useful
2321 * GDB normally ignores breakpoints when it resumes execution, until at least
2322 * one instruction has been executed. If it did not do this,
2323 * you would be unable to proceed past a breakpoint without first disabling the
2324 * breakpoint. This rule applies whether or not the breakpoint already existed
2325 * when your program stopped.
2327 CHECK_PROG_RUNNING();
2328 if (cur_frame == 0) {
2333 f = find_frame(cur_frame);
2335 ip = (INSTRUCTION *) find_frame(cur_frame - 1)->reti; /* Op_func_call */
2337 rp = find_rule(src, ip->source_line);
2339 if ((b = set_breakpoint_next(rp, ip)) == NULL)
2340 fprintf(out_fp, _("Can't set breakpoint in file `%s'\n"), src);
2342 if (cur_frame == 0) { /* stop next time */
2343 b->flags |= BP_IGNORE;
2344 b->ignore_count = 1;
2347 b->flags |= BP_TEMP;
2354 switch (arg->type) {
2355 case D_string: /* break filename:lineno|function */
2356 s = source_find(arg->a_string);
2358 if (s == NULL || arg == NULL
2359 || (arg->type != D_int && arg->type != D_func))
2362 if (arg->type == D_func) /* break filename:function */
2366 case D_int: /* break lineno */
2367 lineno = (int) arg->a_int;
2368 if (lineno <= 0 || lineno > s->srclines)
2369 d_error(_("line number %d in file `%s' out of range"), lineno, src);
2371 rp = find_rule(src, lineno);
2373 fprintf(out_fp, _("Can't find rule!!!\n"));
2374 if (rp == NULL || (b = set_breakpoint_at(rp, lineno, false)) == NULL)
2375 fprintf(out_fp, _("Can't set breakpoint at `%s':%d\n"),
2377 if (b != NULL && temporary)
2378 b->flags |= BP_TEMP;
2382 case D_func: /* break function */
2385 rp = func->code_ptr;
2386 if ((b = set_breakpoint_at(rp, rp->source_line, false)) == NULL)
2387 fprintf(out_fp, _("Can't set breakpoint in function `%s'\n"),
2390 b->flags |= BP_TEMP;
2391 lineno = b->bpi->source_line;
2397 /* condition if any */
2399 if (b != NULL && arg != NULL) {
2400 if (parse_condition(D_break, b->number, arg->a_string) == 0)
2401 arg->a_string = NULL; /* don't let free_cmdarg free it */
2403 fprintf(out_fp, _("breakpoint %d set at file `%s', line %d is unconditional\n"),
2404 b->number, src, lineno);
2410 /* breakpoint_triggered --- check if we should stop at this breakpoint */
2413 breakpoint_triggered(BREAKPOINT *b)
2415 if ((b->flags & BP_ENABLE) == 0)
2417 if ((b->flags & BP_IGNORE) != 0) {
2418 if (--b->ignore_count <= 0)
2419 b->flags &= ~BP_IGNORE;
2423 if (! condition_triggered(&b->cndn))
2427 if ((b->flags & BP_ENABLE_ONCE) != 0) {
2428 b->flags &= ~BP_ENABLE_ONCE;
2429 b->flags &= ~BP_ENABLE;
2434 /* do_breakpoint --- break command */
2437 do_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2439 return set_breakpoint(arg, false);
2442 /* do_tmp_breakpoint --- tbreak command */
2445 do_tmp_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2447 return set_breakpoint(arg, true);
2450 /* do_clear --- clear command */
2453 do_clear(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2457 INSTRUCTION *rp, *ip;
2459 SRCFILE *s = cur_srcfile;
2460 char *src = cur_srcfile->src;
2461 bool bp_found = false;
2463 if (arg == NULL) { /* clear */
2464 CHECK_PROG_RUNNING();
2465 if (cur_frame == 0) {
2466 lineno = sourceline;
2470 f = find_frame(cur_frame);
2472 lineno = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
2477 switch (arg->type) {
2478 case D_string: /* clear filename:lineno|function */
2479 s = source_find(arg->a_string);
2481 if (s == NULL || arg == NULL ||
2482 (arg->type != D_int && arg->type != D_func))
2485 if (arg->type == D_func)
2489 case D_int: /* clear lineno */
2490 lineno = (int) arg->a_int;
2491 if (lineno <= 0 || lineno > s->srclines) {
2492 d_error(_("line number %d in file `%s' out of range"), lineno, src);
2497 case D_func: /* clear function */
2500 rp = func->code_ptr;
2501 for (ip = rp->nexti; ip; ip = ip->nexti) {
2502 if (ip->source_line <= 0)
2504 if (ip->opcode != Op_breakpoint)
2507 if (++bp_found == 1)
2508 fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2510 fprintf(out_fp, ", %d", b->number);
2511 delete_breakpoint(b);
2514 fprintf(out_fp, _("No breakpoint(s) at entry to function `%s'\n"),
2517 fprintf(out_fp, "\n");
2524 rp = find_rule(src, lineno);
2526 for (ip = rp->nexti; ip; ip = ip->nexti) {
2527 if (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2529 if (++bp_found == 1)
2530 fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2532 fprintf(out_fp, ", %d", b->number);
2533 delete_breakpoint(b);
2535 if (ip == (rp + 1)->lasti)
2541 fprintf(out_fp, _("No breakpoint at file `%s', line #%d\n"),
2544 fprintf(out_fp, "\n");
2548 /* enable_breakpoint --- enable a breakpoint and set its disposition */
2551 enable_breakpoint(BREAKPOINT *b, short disp)
2553 b->flags &= ~(BP_ENABLE_ONCE|BP_TEMP);
2554 b->flags |= BP_ENABLE;
2559 /* do_enable_breakpoint --- enable command */
2562 do_enable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2567 if (arg != NULL && arg->type == D_argument) {
2568 if (arg->a_argument == A_DEL) /* del */
2571 disp = BP_ENABLE_ONCE;
2575 if (arg == NULL) { /* enable [once|del] */
2576 for (b = breakpoints.next; b != &breakpoints; b = b->next)
2577 enable_breakpoint(b, disp);
2580 for (; arg != NULL; arg = arg->next) {
2581 if (arg->type == D_range) {
2587 if (j > breakpoints.number)
2588 j = breakpoints.number;
2589 for (; i <= j; i++) {
2590 if ((b = find_breakpoint(i)) != NULL)
2591 enable_breakpoint(b, disp);
2594 assert(arg->type == D_int);
2595 if ((b = find_breakpoint(arg->a_int)) == NULL)
2596 d_error(_("invalid breakpoint number"));
2598 enable_breakpoint(b, disp);
2604 /* do_delete_breakpoint --- delete command */
2607 do_delete_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2610 bool delete_all = true;
2611 delete_all = prompt_yes_no(
2612 _("Delete all breakpoints? (y or n) "),
2613 _("y")[0], true, out_fp);
2616 while (breakpoints.next != &breakpoints)
2617 delete_breakpoint(breakpoints.next);
2621 for (; arg != NULL; arg = arg->next) {
2623 if (arg->type == D_range) {
2629 if (j > breakpoints.number)
2630 j = breakpoints.number;
2631 for (; i <= j; i++) {
2632 if ((b = find_breakpoint(i)) != NULL)
2633 delete_breakpoint(b);
2636 if ((b = find_breakpoint(arg->a_int)) == NULL)
2637 d_error(_("invalid breakpoint number"));
2639 delete_breakpoint(b);
2645 /* do_ignore_breakpoint --- ignore command */
2648 do_ignore_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2652 if (arg == NULL || arg->type != D_int
2653 || arg->next == NULL || arg->next->type != D_int)
2656 if ((b = find_breakpoint(arg->a_int)) == NULL)
2657 d_error(_("invalid breakpoint number"));
2659 b->ignore_count = arg->next->a_int;
2660 if (b->ignore_count > 0) {
2661 b->flags |= BP_IGNORE;
2662 fprintf(out_fp, _("Will ignore next %ld crossing(s) of breakpoint %d.\n"),
2663 b->ignore_count, b->number);
2665 b->flags &= ~BP_IGNORE;
2666 fprintf(out_fp, _("Will stop next time breakpoint %d is reached.\n"),
2673 /* do_disable_breakpoint --- disable command */
2676 do_disable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2682 for (b = breakpoints.next; b != &breakpoints; b = b->next)
2683 b->flags &= ~BP_ENABLE;
2686 for (; arg != NULL; arg = arg->next) {
2687 if (arg->type == D_range) {
2693 if (j > breakpoints.number)
2694 j = breakpoints.number;
2696 if ((b = find_breakpoint(i)) != NULL)
2697 b->flags &= ~BP_ENABLE;
2699 if ((b = find_breakpoint(arg->a_int)) == NULL)
2700 d_error(_("invalid breakpoint number"));
2702 b->flags &= ~BP_ENABLE;
2708 #ifdef HAVE_LIBREADLINE
2710 /* get_function --- function definition in current context */
2719 func = find_frame(cur_frame)->func_node;
2723 /* initialize_readline --- initialize readline */
2726 initialize_readline()
2728 /* tell readline which stream to use for output,
2729 * default input stream is stdin.
2731 rl_outstream = out_fp;
2733 /* allow conditional parsing of the ~/.inputrc file. */
2734 rl_readline_name = "gawk";
2736 /* our completion function. */
2737 rl_attempted_completion_function = command_completion;
2739 read_a_line = readline;
2742 #define initialize_readline() /* nothing */
2746 /* init_debug --- register debugger exec hooks */
2751 register_exec_hook(debug_pre_execute, debug_post_execute);
2755 /* debug_prog --- debugger entry point */
2758 debug_prog(INSTRUCTION *pc)
2762 input_fd = fileno(stdin);
2764 if (os_isatty(input_fd))
2765 input_from_tty = true;
2766 if (input_fd == 0 && input_from_tty)
2767 initialize_readline();
2770 read_a_line = g_readline;
2772 push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
2774 setbuf(out_fp, (char *) NULL);
2775 for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles;
2776 cur_srcfile = cur_srcfile->prev) {
2777 if (cur_srcfile->stype == SRC_FILE
2778 || cur_srcfile->stype == SRC_INC)
2782 if (cur_srcfile == srcfiles) {
2783 fprintf(out_fp, _("Can only debug programs provided with the `-f' option.\n"));
2787 dgawk_prompt = estrdup(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
2788 dbg_prompt = dgawk_prompt;
2790 memset(&stop, 0, sizeof(stop));
2791 stop.command = D_illegal;
2793 if ((run = getenv("DGAWK_RESTART")) != NULL) {
2794 /* We are restarting; restore state (breakpoints, history etc.)
2795 * passed as environment variables and optionally execute the run command.
2799 unserialize(DISPLAY);
2800 unserialize(HISTORY);
2801 unserialize(OPTION);
2802 unsetenv("DGAWK_RESTART");
2803 fprintf(out_fp, "Restarting ...\n");
2805 (void) do_run(NULL, 0);
2807 } else if (command_file != NULL) {
2808 /* run commands from a file (--debug=file or -D file) */
2810 fd = open_readfd(command_file);
2811 if (fd == INVALID_HANDLE) {
2812 fprintf(stderr, _("can't open source file `%s' for reading (%s)"),
2813 command_file, strerror(errno));
2816 push_cmd_src(fd, false, g_readline, close, 0, EXIT_FAILURE);
2817 cmd_src->str = estrdup(command_file, strlen(command_file));
2822 #ifdef HAVE_LIBREADLINE
2823 (void) read_history(history_file);
2824 sess_history_base = history_length;
2827 /* read saved options */
2828 fd = open_readfd(options_file);
2829 if (fd > INVALID_HANDLE)
2830 push_cmd_src(fd, false, g_readline, close, 0, EXIT_SUCCESS);
2833 /* start the command interpreter */
2834 read_command(); /* yyparse */
2835 return EXIT_SUCCESS;
2839 /* N.B.: ignore breakpoints and watchpoints for return command */
2841 /* check_watchpoint --- check if any watchpoint triggered */
2846 struct list_item *w;
2848 if (stop.command == D_return)
2850 for (w = watch_list.prev; w != &watch_list; w = w->prev) {
2851 int wnum = watchpoint_triggered(w);
2853 stop.watch_point = wnum;
2854 stop.print_frame = true;
2861 /* check_breakpoint --- check if breakpoint triggered */
2864 check_breakpoint(INSTRUCTION **pi)
2869 if (stop.command == D_return)
2871 if (pc->opcode == Op_breakpoint) {
2873 *pi = pc->nexti; /* skip past the breakpoint instruction;
2874 * interpreter doesn't process Op_breakpoint.
2876 bnum = breakpoint_triggered(pc->break_pt);
2878 stop.break_point = bnum;
2879 stop.print_frame = true;
2886 /* restart --- restart the debugger */
2891 /* save state in the environment after serialization */
2898 /* tell the new process to restore state from the environment */
2899 setenv("DGAWK_RESTART", (run ? "true" : "false"), 1);
2901 /* close all open files */
2904 /* start a new process replacing the current process */
2905 execvp(d_argv[0], d_argv);
2907 /* execvp failed !!! */
2908 fprintf(out_fp, _("Failed to restart debugger"));
2912 /* do_run --- run command */
2915 do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2918 if (! input_from_tty)
2919 need_restart = true; /* handled later */
2921 need_restart = prompt_yes_no(
2922 _("Program already running. Restart from beginning (y/n)? "),
2923 _("y")[0], false, out_fp);
2925 if (! need_restart) {
2926 fprintf(out_fp, _("Program not restarted\n"));
2933 /* avoid endless cycles of restarting */
2934 if (command_file != NULL) {
2935 /* input_from_tty = false */
2936 fprintf(stderr, _("error: cannot restart, operation not allowed\n"));
2940 if (cmd_src->cmd == D_source) {
2941 /* input_from_tty = false */
2942 fprintf(out_fp, _("error (%s): cannot restart, ignoring rest of the commands\n"), cmd_src->str);
2947 restart(true); /* does not return */
2950 fprintf(out_fp, _("Starting program: \n"));
2952 prog_running = true;
2953 fatal_tag_valid = true;
2954 if (setjmp(fatal_tag) == 0)
2955 (void) interpret(code_block);
2957 fatal_tag_valid = false;
2958 prog_running = false;
2959 fprintf(out_fp, _("Program exited %s with exit value: %d\n"),
2960 (! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
2963 need_restart = true;
2967 /* do_quit --- quit command */
2970 do_quit(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2972 bool terminate = true;
2974 terminate = prompt_yes_no(
2975 _("The program is running. Exit anyway (y/n)? "),
2976 _("y")[0], true, out_fp);
2979 do_trace = false; /* don't save 'trace on' */
2981 #ifdef HAVE_LIBREADLINE
2982 if (do_save_history && input_from_tty) {
2984 ret = write_history(history_file);
2985 if (ret == 0 && history_length > history_size)
2986 (void) history_truncate_file(history_file, history_size);
2989 if (do_save_options && input_from_tty)
2990 save_options(options_file);
2997 /* do_continue --- continue command */
3000 do_continue(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
3004 CHECK_PROG_RUNNING();
3005 if (! arg || arg->type != D_int)
3008 /* arg is breakpoint ignore count if stopped at a breakpoint */
3009 if (! stop.break_point) {
3010 fprintf(out_fp, _("Not stopped at any breakpoint; argument ignored.\n"));
3013 b = find_breakpoint(stop.break_point);
3015 d_error(_("invalid breakpoint number %d."), stop.break_point);
3018 b->flags |= BP_IGNORE;
3019 b->ignore_count = arg->a_int;
3020 fprintf(out_fp, _("Will ignore next %ld crossings of breakpoint %d.\n"),
3021 b->ignore_count, stop.break_point);
3025 /* next_step --- common code for next and step commands */
3028 next_step(CMDARG *arg, int cmd)
3030 CHECK_PROG_RUNNING();
3031 if (arg != NULL && arg->type == D_int)
3032 stop.repeat_count = arg->a_int;
3034 stop.repeat_count = 1;
3039 /* check_step --- process step command, return true if stopping */
3042 check_step(INSTRUCTION **pi)
3044 if (fcall_count != stop.fcall_count) {
3045 stop.fcall_count = fcall_count;
3046 stop.sourceline = sourceline;
3047 stop.source = source;
3048 stop.print_frame = true;
3049 return (--stop.repeat_count == 0);
3052 if (source != stop.source) {
3053 stop.source = source;
3054 stop.sourceline = sourceline;
3055 return (--stop.repeat_count == 0);
3058 if (sourceline != stop.sourceline) {
3059 stop.sourceline = sourceline;
3060 return (--stop.repeat_count == 0);
3065 /* do_step -- process step command, return true if stopping */
3068 do_step(CMDARG *arg, int cmd)
3071 ret = next_step(arg, cmd);
3073 stop.fcall_count = fcall_count;
3074 stop.source = source;
3075 stop.sourceline = sourceline;
3076 stop.check_func = check_step;
3081 /* do_stepi -- process stepi command, return true if stopping */
3084 check_stepi(INSTRUCTION **pi)
3086 return (--stop.repeat_count == 0);
3089 /* do_stepi -- stepi command */
3092 do_stepi(CMDARG *arg, int cmd)
3095 ret = next_step(arg, cmd);
3097 stop.check_func = check_stepi;
3102 /* check_next -- process next command returning true if stopping */
3105 check_next(INSTRUCTION **pi)
3107 /* make sure not to step inside function calls */
3109 if (fcall_count < stop.fcall_count) {
3110 stop.fcall_count = fcall_count;
3111 stop.sourceline = sourceline;
3112 stop.source = source;
3113 stop.print_frame = true;
3114 return (--stop.repeat_count == 0);
3117 if (fcall_count == stop.fcall_count) {
3118 if (source != stop.source) {
3119 stop.source = source;
3120 stop.sourceline = sourceline;
3121 return (--stop.repeat_count == 0);
3123 if (sourceline != stop.sourceline) {
3124 stop.sourceline = sourceline;
3125 return (--stop.repeat_count == 0);
3131 if (fcall_count > stop.fcall_count) {
3132 stop.source = source;
3133 stop.sourceline = sourceline;
3140 /* do_next -- next command */
3143 do_next(CMDARG *arg, int cmd)
3147 ret = next_step(arg, cmd);
3149 stop.source = source;
3150 stop.sourceline = sourceline;
3151 stop.fcall_count = fcall_count;
3152 stop.check_func = check_next;
3157 /* check_nexti --- process nexti command, returns true if stopping */
3160 check_nexti(INSTRUCTION **pi)
3162 /* make sure not to step inside function calls */
3164 if (fcall_count < stop.fcall_count) {
3165 stop.print_frame = true;
3166 stop.fcall_count = fcall_count;
3168 return (fcall_count == stop.fcall_count
3169 && --stop.repeat_count == 0);
3172 /* do_nexti -- nexti command */
3175 do_nexti(CMDARG *arg, int cmd)
3179 ret = next_step(arg, cmd);
3181 stop.fcall_count = fcall_count;
3182 stop.check_func = check_nexti;
3187 /* check_finish --- process finish command, returns true if stopping */
3190 check_finish(INSTRUCTION **pi)
3192 if (fcall_count == stop.fcall_count) {
3193 stop.print_frame = true;
3199 /* do_finish --- finish command */
3202 do_finish(CMDARG *arg ATTRIBUTE_UNUSED, int cmd)
3204 CHECK_PROG_RUNNING();
3205 if (cur_frame == fcall_count) {
3207 _("'finish' not meaningful in the outermost frame main()\n"));
3210 stop.fcall_count = fcall_count - cur_frame - 1;
3211 assert(stop.fcall_count >= 0);
3212 fprintf(out_fp, _("Run till return from "));
3213 print_numbered_frame(cur_frame);
3214 stop.check_func = check_finish;
3216 stop.print_ret = true;
3220 /* check_return --- process return, returns true if stopping */
3223 check_return(INSTRUCTION **pi)
3225 assert(fcall_count >= stop.fcall_count);
3227 if (fcall_count == stop.fcall_count) {
3228 stop.print_frame = true;
3232 if (fcall_count > stop.fcall_count) { /* innermost frame just returned */
3233 /* force this one to return too */
3236 func = find_frame(cur_frame)->func_node;
3237 assert(func != NULL);
3238 *pi = (func->code_ptr + 1)->lasti;
3239 /* assert((*pi)->opcode == Op_K_return); */
3245 /* do_return --- return command */
3248 do_return(CMDARG *arg, int cmd)
3252 CHECK_PROG_RUNNING();
3253 func = find_frame(cur_frame)->func_node;
3255 fprintf(out_fp, _("'return' not meaningful in the outermost frame main()\n"));
3259 stop.fcall_count = fcall_count - cur_frame - 1;
3260 assert(stop.fcall_count >= 0);
3261 stop.pc = (func->code_ptr + 1)->lasti;
3262 assert(stop.pc->opcode == Op_K_return);
3265 stop.check_func = check_return;
3267 if (arg != NULL && arg->type == D_node) /* optional return value */
3268 n = dupnode(arg->a_node);
3270 n = dupnode(Nnull_string);
3276 /* check_until --- process until, returns true if stopping */
3279 check_until(INSTRUCTION **pi)
3281 if (fcall_count < stop.fcall_count) { /* current stack frame returned */
3282 stop.print_frame = true;
3284 } else if (fcall_count == stop.fcall_count) {
3285 if (stop.pc && *pi == stop.pc) /* until location */
3287 if (stop.sourceline > 0 /* until */
3288 && source == stop.source
3289 && sourceline > stop.sourceline)
3295 /* do_until --- until command */
3298 do_until(CMDARG *arg, int cmd)
3300 SRCFILE *s = cur_srcfile;
3301 char *src = cur_srcfile->src;
3303 INSTRUCTION *rp, *ip;
3306 CHECK_PROG_RUNNING();
3308 stop.sourceline = 0;
3310 if (arg == NULL) { /* until without argument */
3312 /* GDB doc.: continue running until a source line past the current line,
3313 * in the current stack frame, is reached. Is used to avoid single
3314 * stepping through a loop more than once. ...
3315 * This means that when you reach the end of a loop after single
3316 * stepping though it, until makes your program continue execution
3317 * until it exits the loop. In contrast, a next command at the end
3318 * of a loop simply steps back to the beginning of the loop, which
3319 * forces you to step through the next iteration.
3322 stop.source = source;
3323 stop.sourceline = sourceline;
3324 stop.fcall_count = fcall_count - cur_frame;
3325 stop.check_func = check_until;
3330 /* GDB: until location - continue running program until
3331 * either the specified location is reached, or the
3332 * current stack frame returns.
3335 switch (arg->type) {
3336 case D_string: /* until filename : lineno|function */
3337 s = source_find(arg->a_string);
3339 if (s == NULL || arg == NULL
3340 || (arg->type != D_int && arg->type != D_func))
3343 if (arg->type == D_func)
3347 case D_int: /* until lineno */
3348 lineno = arg->a_int;
3349 if (lineno <= 0 || lineno > s->srclines) {
3350 d_error(_("line number %d in file `%s' out of range"),
3356 case D_func: /* until function */
3359 rp = func->code_ptr;
3360 for (ip = rp->nexti; ip; ip = ip->nexti) {
3361 if (ip->opcode != Op_breakpoint && ip->source_line > 0) {
3363 stop.fcall_count = fcall_count - cur_frame;
3364 stop.check_func = check_until;
3369 fprintf(out_fp, _("Can't find specified location in function `%s'\n"),
3376 if ((rp = find_rule(src, lineno)) == NULL) {
3377 d_error(_("invalid source line %d in file `%s'"), lineno, src);
3381 for (ip = rp->nexti; ip; ip = ip->nexti) {
3382 if (ip->opcode != Op_breakpoint && ip->source_line >= lineno) {
3384 stop.fcall_count = fcall_count - cur_frame;
3385 stop.check_func = check_until;
3389 if (ip == (rp + 1)->lasti)
3392 fprintf(out_fp, _("Can't find specified location %d in file `%s'\n"),
3397 /* print_watch_item --- print watched item name, old and current values */
3400 print_watch_item(struct list_item *w)
3406 if (IS_SUBSCRIPT(w)) {
3407 fprintf(out_fp, "%s", w->sname);
3408 for (i = 0; i < w->num_subs; i++) {
3410 fprintf(out_fp, "[\"%s\"]", sub->stptr);
3412 fprintf(out_fp, "\n");
3413 } else if (IS_FIELD(w))
3414 fprintf(out_fp, "$%ld\n", get_number_si(symbol));
3416 fprintf(out_fp, "%s\n", w->sname);
3419 #define print_value(X, S, V) \
3421 fprintf(out_fp, "array, %ld elements\n", w->S); \
3423 fprintf(out_fp, IS_SUBSCRIPT(w) ? \
3424 _("element not in array\n") : _("untyped variable\n")); \
3426 valinfo(w->V, fprintf, out_fp);
3428 fprintf(out_fp, " Old value: ");
3429 print_value((w->flags & OLD_IS_ARRAY) != 0, old_size, old_value);
3430 fprintf(out_fp, " New value: ");
3431 print_value((w->flags & CUR_IS_ARRAY) != 0, cur_size, cur_value);
3436 /* next_command --- (optionally) print stoppage location and reason;
3437 * also fetch next debug command from the user.
3443 static int last_rule = 0;
3444 struct list_item *d = NULL, *w = NULL;
3445 BREAKPOINT *b = NULL;
3448 if (source == NULL) {
3449 stop.command = D_illegal;
3450 stop.check_func = NULL;
3454 if (stop.break_point) {
3455 b = find_breakpoint(stop.break_point);
3459 } else if (stop.watch_point) {
3460 w = find_item(&watch_list, stop.watch_point);
3465 if (cur_rule != last_rule) {
3466 fprintf(out_fp, _("Stopping in %s ...\n"), ruletab[cur_rule]);
3467 last_rule = cur_rule;
3471 fprintf(out_fp, "Breakpoint %d, ", b->number);
3472 else if (w != NULL) {
3473 fprintf(out_fp, "Watchpoint %d: ", w->number);
3474 print_watch_item(w);
3478 if (stop.print_frame) {
3479 print_frame(frame_ptr->func_node, source, sourceline);
3480 fprintf(out_fp, "\n");
3481 stop.print_frame = false;
3484 (void) print_lines(source, sourceline, 1);
3486 /* automatic display of variables */
3487 for (d = display_list.prev; d != &display_list; d = d->prev)
3491 /* update last_printed_line, so that output of 'list' is
3492 * centered around current sourceline
3495 last_printed_line = sourceline - list_size / 2;
3496 if (last_printed_line < 0)
3497 last_printed_line = 0;
3499 /* update current source file */
3500 s = source_find(source);
3501 if (cur_srcfile != s) {
3502 if (cur_srcfile->fd != INVALID_HANDLE) {
3503 close(cur_srcfile->fd);
3504 cur_srcfile->fd = INVALID_HANDLE;
3509 stop.command = D_illegal;
3510 stop.check_func = NULL;
3514 ret = execute_commands(&b->commands);
3515 if ((b->flags & BP_TEMP) != 0)
3516 delete_breakpoint(b);
3517 if (ret) /* resume execution */
3519 } else if (w != NULL && execute_commands(&w->commands))
3522 read_command(); /* zzparse */
3525 /* debug_post_execute --- post_hook in the interpreter */
3528 debug_post_execute(INSTRUCTION *pc)
3530 if (! in_main_context())
3533 switch (pc->opcode) {
3537 if (stop.command == D_finish) {
3538 /* cancel finish command */
3539 stop.print_ret = false;
3540 stop.print_frame = false;
3541 stop.command = D_illegal;
3542 stop.check_func = NULL;
3543 fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"),
3544 op2str(pc->opcode));
3545 } else if (stop.command == D_until) {
3546 /* cancel until command */
3547 stop.print_frame = false;
3548 stop.command = D_illegal;
3549 stop.check_func = NULL;
3550 fprintf(out_fp, _("'until' not meaningful with non-local jump '%s'\n"),
3551 op2str(pc->opcode));
3556 if (stop.command == D_finish
3557 && fcall_count == stop.fcall_count
3561 /* print the returned value before it disappears. */
3563 fprintf(out_fp, "Returned value = ");
3564 valinfo(r, fprintf, out_fp);
3565 stop.print_ret = false;
3578 /* debug_pre_execute --- pre_hook, called by the interpreter before execution;
3579 * checks if execution needs to be suspended and control
3580 * transferred to the debugger.
3584 debug_pre_execute(INSTRUCTION **pi)
3586 static bool cant_stop = false;
3589 if (! in_main_context())
3590 return pre_execute_code(pi);
3593 stop.break_point = 0;
3594 stop.watch_point = 0;
3598 && cur_pc->opcode != Op_breakpoint
3599 && stop.command != D_return
3601 print_instruction(cur_pc, fprintf, out_fp, false);
3603 /* N.B.: For Op_field_spec_lhs must execute instructions upto Op_field_assign
3604 * as a group before stopping. Otherwise, watch/print of field variables
3605 * yield surprising results. Ditto for Op_push_lhs for special variables
3606 * (upto Op_var_assign, the set_FOO routine).
3609 switch (cur_pc->opcode) {
3610 case Op_field_spec_lhs:
3614 case Op_field_assign:
3616 return true; /* may stop at next instruction */
3620 if (m->type == Node_var && m->var_assign)
3624 case Op_arrayfor_incr: /* can have special var as array variable !!! */
3625 m = cur_pc->array_var;
3626 if (m->type == Node_var && m->var_assign)
3632 return true; /* may stop at next instruction */
3635 cur_rule = cur_pc->in_rule;
3643 break; /* processed later in check_breakpoint() */
3646 if (cur_pc->source_line <= 0)
3654 assert(sourceline > 0);
3656 if (check_breakpoint(pi)
3657 || check_watchpoint()
3658 || (stop.check_func && stop.check_func(pi))) {
3659 next_command(); /* return to debugger interface */
3660 if (stop.command == D_return)
3661 *pi = stop.pc; /* jump to this instruction */
3664 /* if cur_pc == *pi, interpreter executes cur_pc;
3665 * Otherwise, jumps to instruction *pi.
3667 return (cur_pc == *pi);
3670 /* print_memory --- print a scalar value */
3673 print_memory(NODE *m, NODE *func, Func_print print_func, FILE *fp)
3677 if (m == Nnull_string)
3678 print_func(fp, "Nnull_string");
3679 else if ((m->flags & NUMBER) != 0) {
3681 if ((m->flags & MPFN) != 0)
3682 print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
3683 else if ((m->flags & MPZN) != 0)
3684 print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
3687 print_func(fp, "%g", m->numbr);
3688 } else if ((m->flags & STRING) != 0)
3689 pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
3690 else if ((m->flags & NUMCUR) != 0) {
3692 if ((m->flags & MPFN) != 0)
3693 print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
3694 else if ((m->flags & MPZN) != 0)
3695 print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
3698 print_func(fp, "%g", m->numbr);
3699 } else if ((m->flags & STRCUR) != 0)
3700 pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
3702 print_func(fp, "-?-");
3703 print_func(fp, " [%s]", flags2str(m->flags));
3707 pp_string_fp(print_func, fp, m->re_exp->stptr, m->re_exp->stlen, '/', false);
3713 case Node_param_list:
3714 assert(func != NULL);
3715 print_func(fp, "%s", func->fparms[m->param_cnt].param);
3720 case Node_var_array:
3721 print_func(fp, "%s", m->vname);
3725 print_func(fp, "?"); /* can't happen */
3729 /* print_instruction --- print a bytecode */
3732 print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
3735 static NODE *func = NULL;
3736 static int noffset = 0;
3739 static char buf[50];
3740 /* offset for 2nd to last lines in a multi-line output */
3741 noffset = sprintf(buf, "[ :%p] %-20.20s: ", (void *) pc,
3742 opcode2str(pc->opcode));
3745 if (pc->opcode == Op_func) {
3746 func = pc->func_body;
3747 pcount = func->param_cnt;
3750 print_func(fp, "\n\t# Function: %s (", func->vname);
3751 for (j = 0; j < pcount; j++) {
3752 print_func(fp, "%s", func->fparms[j].param);
3754 print_func(fp, ", ");
3756 print_func(fp, ")\n\n");
3758 } else if (pc->opcode == Op_rule) {
3760 print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]);
3763 if (pc->opcode == Op_newfile)
3764 print_func(fp, "\n");
3766 if (pc->source_line <= 0)
3767 print_func(fp, "[ :%p] %-20.20s: ", pc, opcode2str(pc->opcode));
3769 print_func(fp, "[%6d:%p] %-20.20s: ",
3770 pc->source_line, pc, opcode2str(pc->opcode));
3772 if (prog_running && ! in_dump) {
3773 /* find Node_func if in function */
3774 func = find_frame(0)->func_node;
3778 switch (pc->opcode) {
3780 print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var));
3784 print_func(fp, "[set_%s()]", get_spec_varname(pc->assign_var));
3785 if (pc->assign_ctxt != 0)
3786 print_func(fp, " [assign_ctxt = %s]", opcode2str(pc->assign_ctxt));
3787 print_func(fp, "\n");
3790 case Op_field_assign:
3791 print_func(fp, "[%s]\n", pc->field_assign == reset_record ?
3792 "reset_record()" : "invalidate_field0()");
3795 case Op_field_spec_lhs:
3796 print_func(fp, "[target_assign = %p] [do_reference = %s]\n",
3797 pc->target_assign, pc->do_reference ? "true" : "false");
3801 print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount,
3802 pc->source_file ? pc->source_file : "cmd. line");
3805 case Op_K_getline_redir:
3806 print_func(fp, "[into_var = %s] [redir_type = \"%s\"]\n",
3807 pc->into_var ? "true" : "false",
3808 redir2str(pc->redir_type));
3812 print_func(fp, "[into_var = %s]\n", pc->into_var ? "true" : "false");
3813 print_func(fp, "%*s[target_beginfile = %p] [target_endfile = %p]\n",
3815 (pc + 1)->target_beginfile, (pc + 1)->target_endfile);
3818 case Op_K_print_rec:
3819 print_func(fp, "[redir_type = \"%s\"]\n", redir2str(pc->redir_type));
3824 print_func(fp, "[expr_count = %ld] [redir_type = \"%s\"]\n",
3825 pc->expr_count, redir2str(pc->redir_type));
3828 case Op_indirect_func_call:
3830 print_func(fp, "[func_name = %s] [arg_count = %ld]\n",
3831 pc->func_name, (pc + 1)->expr_count);
3835 print_func(fp, "[target_newfile = %p] [target_endfile = %p]\n",
3836 pc->target_newfile, pc->target_endfile);
3840 print_func(fp, "[target_jmp = %p] [target_endfile = %p]\n",
3841 pc->target_jmp, pc->target_endfile);
3842 print_func(fp, "%*s[target_get_record = %p]\n",
3843 noffset, "", (pc + 1)->target_get_record);
3847 print_func(fp, "[target_newfile = %p]\n", pc->target_newfile);
3856 case Op_arrayfor_init:
3859 print_func(fp, "[target_jmp = %p]\n", pc->target_jmp);
3862 print_func(fp, "[target_end = %p] [target_atexit = %p]\n",
3863 pc->target_end, pc->target_atexit);
3867 print_func(fp, "[target_jmp = %p] [match_exp = %s]\n",
3868 pc->target_jmp, (pc + 1)->match_exp ? "true" : "false");
3871 case Op_arrayfor_incr:
3872 print_func(fp, "[array_var = %s] [target_jmp = %p]\n",
3873 pc->array_var->type == Node_param_list ?
3874 func->fparms[pc->array_var->param_cnt].param : pc->array_var->vname,
3879 print_func(fp, "[triggered = %ld] [target_jmp = %p]\n",
3880 pc->triggered, pc->target_jmp);
3884 print_func(fp, "[line_range = %p] [target_jmp = %p]\n",
3885 pc->line_range, pc->target_jmp);
3888 case Op_sub_builtin:
3890 const char *fname = "sub";
3891 static const struct flagtab values[] = {
3893 { GENSUB, "GENSUB" },
3894 { LITERAL, "LITERAL" },
3898 if ((pc->sub_flags & GSUB) != 0)
3900 else if ((pc->sub_flags & GENSUB) != 0)
3902 print_func(fp, "%s [arg_count = %ld] [sub_flags = %s]\n",
3903 fname, pc->expr_count,
3904 genflags2str(pc->sub_flags, values));
3909 print_func(fp, "%s [arg_count = %ld]\n", getfname(pc->builtin),
3913 case Op_ext_builtin:
3914 print_func(fp, "%s [arg_count = %ld]\n", (pc + 1)->func_name,
3920 print_func(fp, "[sub_count = %ld]\n", pc->sub_count);
3924 print_memory(pc->memory, func, print_func, fp);
3925 print_func(fp, " [sub_count = %ld]\n", pc->expr_count);
3928 case Op_subscript_lhs:
3929 print_func(fp, "[sub_count = %ld] [do_reference = %s]\n",
3931 pc->do_reference ? "true" : "false");
3936 print_func(fp, "[expr_count = %ld]\n", pc->expr_count);
3940 /* NB: concat_flag CSVAR only used in grammar, don't display it */
3941 print_func(fp, "[expr_count = %ld] [concat_flag = %s]\n",
3943 (pc->concat_flag & CSUBSEP) != 0 ? "CSUBSEP" : "0");
3947 print_func(fp, "[in_rule = %s] [source_file = %s]\n",
3948 ruletab[pc->in_rule],
3949 pc->source_file ? pc->source_file : "cmd. line");
3954 static const char *const linttypetab[] = {
3956 "LINT_assign_in_cond",
3959 print_func(fp, "[lint_type = %s]\n", linttypetab[pc->lint_type]);
3964 print_func(fp, "[exec_count = %ld]\n", pc->exec_count);
3968 print_memory(pc->memory, func, print_func, fp);
3969 if (pc->initval != NULL) {
3970 print_func(fp, " = ");
3971 print_memory(pc->initval, func, print_func, fp);
3973 print_func(fp, "\n");
3977 print_memory(pc->memory, func, print_func, fp);
3978 print_func(fp, " [do_reference = %s]\n",
3979 pc->do_reference ? "true" : "false");
3997 case Op_assign_concat:
3998 print_memory(pc->memory, func, print_func, fp);
4001 print_func(fp, "\n");
4006 /* do_trace_instruction --- trace command */
4009 do_trace_instruction(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4011 if (arg != NULL && arg->type == D_argument
4012 && arg->a_argument == A_TRACE_ON)
4019 /* print_code --- print a list of instructions */
4022 print_code(INSTRUCTION *pc, void *x)
4024 struct pf_data *data = (struct pf_data *) x;
4025 for (; pc != NULL; pc = pc->nexti)
4026 print_instruction(pc, data->print_func, data->fp, data->defn /* in_dump */);
4030 /* do_dump_instructions --- dump command */
4033 do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4038 if (arg != NULL && arg->type == D_string) {
4039 /* dump to a file */
4040 if ((fp = fopen(arg->a_string, "w")) == NULL) {
4041 d_error(_("could not open `%s' for writing (%s)"),
4042 arg->a_string, strerror(errno));
4045 pf_data.print_func = fprintf;
4047 pf_data.defn = true; /* in_dump = true */
4048 (void) print_code(code_block, &pf_data);
4049 funcs = function_list(true);
4050 (void) foreach_func(funcs,
4051 (int (*)(INSTRUCTION *, void *)) print_code,
4058 funcs = function_list(true);
4059 initialize_pager(out_fp);
4060 if (setjmp(pager_quit_tag) == 0) {
4061 pf_data.print_func = gprintf;
4062 pf_data.fp = out_fp;
4063 pf_data.defn = true; /* in_dump = true */
4064 (void) print_code(code_block, &pf_data);
4065 (void) foreach_func(funcs,
4066 (int (*)(INSTRUCTION *, void *)) print_code,
4073 /* do_save --- save command */
4076 do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4078 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
4080 HIST_ENTRY **hist_list;
4083 if ((fp = fopen(arg->a_string, "w")) == NULL) {
4084 d_error(_("could not open `%s' for writing (%s)"),
4085 arg->a_string, strerror(errno));
4089 hist_list = history_list();
4090 if (hist_list && history_length > sess_history_base) {
4091 for (i = sess_history_base; hist_list[i] != NULL; i++) {
4093 line = hist_list[i]->line;
4095 /* exclude save commands;
4096 * N.B.: this test may fail if there is another
4097 * command with the same first 2 letters.
4100 if (strlen(line) > 1
4101 && strncmp(line, "sa", 2) == 0)
4104 fprintf(fp, "%s\n", line);
4112 /* do_option --- option command */
4115 do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4117 const struct dbg_option *opt;
4120 if (arg == NULL) { /* display all available options and corresponding values */
4121 for (opt = option_list; opt->name; opt++) {
4122 if (opt->str_val != NULL)
4123 fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4125 fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4130 name = arg->a_string;
4132 value = arg ? arg->a_string : NULL;
4134 for (opt = option_list; opt->name; opt++) { /* linear search */
4135 if (strcmp(name, opt->name) == 0)
4141 if (value == NULL) { /* display current setting */
4142 if (opt->str_val != NULL)
4143 fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4145 fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4147 (*(opt->assign))(value);
4152 #ifdef HAVE_LIBREADLINE
4154 /* initialize_pager --- initialize our idea of the terminal size */
4157 initialize_pager(FILE *fp)
4159 if (! os_isatty(fileno(fp)) || ! input_from_tty || input_fd != 0) {
4160 screen_width = INT_MAX;
4161 screen_height = INT_MAX;
4163 /* get the terminal size from readline. */
4165 rl_reset_terminal(NULL); /* N.B.: NULL argument means
4166 * "use TERM env variable for terminal name".
4168 rl_get_screen_size(&screen_height, &screen_width);
4169 if (screen_height <= 1)
4170 screen_height = INT_MAX;
4171 if (screen_width <= 1)
4172 screen_width = INT_MAX;
4174 pager_lines_printed = 0;
4179 prompt_continue(FILE *fp)
4181 bool quit_pager = false;
4183 if (os_isatty(fileno(fp)) && input_fd == 0)
4184 quit_pager = prompt_yes_no(
4185 _("\t------[Enter] to continue or q [Enter] to quit------"),
4186 _("q")[0], false, fp);
4188 longjmp(pager_quit_tag, 1);
4189 pager_lines_printed = 0;
4192 /* gprintf --- like fprintf but allows paging */
4195 gprintf(FILE *fp, const char *format, ...)
4198 static char *buf = NULL;
4199 static size_t buflen = 0;
4204 #define GPRINTF_BUFSIZ 512
4206 buflen = GPRINTF_BUFSIZ;
4207 emalloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4208 } else if (buflen - bl < GPRINTF_BUFSIZ/2) {
4209 buflen += GPRINTF_BUFSIZ;
4210 erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4212 #undef GPRINTF_BUFSIZ
4215 va_start(args, format);
4216 nchar = vsnprintf(buf + bl, buflen - bl, format, args);
4220 if (nchar > 0 && nchar < buflen - bl) {
4222 if (buf[bl-1] != '\n') /* buffer output until see a newline at end */
4227 /* enlarge buffer, and try again */
4229 erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4233 for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) {
4234 int sz = (int) (q - p);
4238 cnt = sz > screen_width ? screen_width : sz;
4240 /* do not print partial line before scrolling */
4241 if (cnt < sz && (pager_lines_printed == (screen_height - 2)))
4242 prompt_continue(fp);
4244 if (fwrite(p, sizeof(char), cnt, fp) != cnt)
4249 if (++pager_lines_printed == (screen_height - 1))
4250 prompt_continue(fp);
4258 if (++pager_lines_printed == (screen_height - 1))
4259 prompt_continue(fp);
4267 serialize_subscript(char *buf, int buflen, struct list_item *item)
4269 int bl = 0, nchar, i;
4272 nchar = snprintf(buf, buflen, "%d%c%d%c%s%c%d%c",
4273 item->number, FSEP, D_subscript, FSEP, item->sname, FSEP,
4274 item->num_subs, FSEP);
4277 else if (nchar >= buflen) /* need larger buffer */
4280 for (i = 0; i < item->num_subs; i++) {
4281 sub = item->subs[i];
4282 nchar = snprintf(buf + bl, buflen - bl, "%lu%c%s%c",
4283 (unsigned long) sub->stlen, FSEP, sub->stptr, FSEP);
4287 if (bl >= buflen) /* need larger buffer */
4295 /* serialize --- convert a list structure to a byte stream and
4296 * save in environment.
4302 static char *buf = NULL;
4303 static int buflen = 0;
4305 BREAKPOINT *b = NULL;
4306 struct list_item *wd = NULL;
4307 HIST_ENTRY **hist_list = NULL;
4309 struct dbg_option *opt = NULL;
4310 struct commands_item *commands = NULL, *c;
4312 struct condition *cndn = NULL;
4313 void *ptr, *end_ptr;
4314 #ifdef HAVE_LIBREADLINE
4315 HIST_ENTRY *h = NULL;
4320 end_ptr = (void *) &breakpoints;
4321 ptr = (void *) breakpoints.prev;
4324 end_ptr = (void *) &watch_list;
4325 ptr = (void *) watch_list.prev;
4328 end_ptr = (void *) &display_list;
4329 ptr = (void *) display_list.prev;
4332 hist_list = history_list();
4333 if (hist_list == NULL) /* empty history list */
4336 ptr = (void *) hist_list[0];
4341 n = sizeof(option_list)/sizeof(option_list[0]);
4342 end_ptr = (void *) &option_list[n - 1];
4343 ptr = (void *) option_list;
4351 if (type != HISTORY && ptr == end_ptr) /* empty list */
4354 #define SERIALIZE_BUFSIZ 512
4356 if (buf == NULL) { /* first time */
4357 buflen = SERIALIZE_BUFSIZ;
4358 emalloc(buf, char *, buflen + 2, "serialize");
4362 while (ptr != end_ptr) {
4364 if (buflen - bl < SERIALIZE_BUFSIZ/2) {
4367 erealloc(buf, char *, buflen + 2, "serialize");
4370 #undef SERIALIZE_BUFSIZ
4372 /* field seperator is FSEP ('\037'), and the record separator is RSEP ('\036') */
4376 b = (BREAKPOINT *) ptr;
4378 /* src source_line flags ignore_count hit_count number;
4379 * commands and condition processed later in the end switch
4382 nchar = snprintf(buf + bl, buflen - bl,
4383 "%s%c%d%c%d%c%d%c%d%c%d%c",
4384 b->src, FSEP, b->bpi->source_line, FSEP, b->flags, FSEP,
4385 (int) b->ignore_count, FSEP,
4386 (int) b->hit_count, FSEP, b->number, FSEP);
4388 commands = &b->commands;
4393 wd = (struct list_item *) ptr;
4395 /* subscript -- number type sname num_subs subs(stlen + stptr) [commands [condition]]
4396 * variable -- number type sname [commands [condition]]
4397 * field -- number type symbol(numbr) [commands [condition]]
4400 if (IS_PARAM(wd)) /* exclude parameters */
4402 else if (IS_SUBSCRIPT(wd))
4403 nchar = serialize_subscript(buf + bl, buflen - bl, wd);
4404 else if (IS_FIELD(wd))
4405 nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%d%c",
4406 wd->number, FSEP, D_field, FSEP, (int) get_number_si(wd->symbol), FSEP);
4408 nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%s%c",
4409 wd->number, FSEP, D_variable, FSEP, wd->sname, FSEP);
4411 commands = &wd->commands;
4415 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
4416 h = (HIST_ENTRY *) ptr;
4417 nchar = strlen(h->line);
4418 if (nchar >= buflen - bl)
4419 goto enlarge_buffer;
4420 strcpy(buf + bl, h->line);
4424 opt = (struct dbg_option *) ptr;
4425 if (opt->num_val != NULL)
4426 nchar = snprintf(buf + bl, buflen - bl,
4427 "%s%c%d%c", opt->name, FSEP, *(opt->num_val), FSEP);
4429 nchar = snprintf(buf + bl, buflen - bl,
4430 "%s%c%s%c", opt->name, FSEP, *(opt->str_val), FSEP);
4436 if (nchar == 0) /* skip empty history lines etc.*/
4438 else if (nchar > 0 && nchar < buflen - bl) {
4440 buf[bl] = RSEP; /* record */
4443 goto enlarge_buffer;
4448 /* recreate the `commands' command strings including the `commands'
4449 * and `end' commands; command seperator is '\034'.
4450 * re-parsed in unserialize to recover the commands list.
4451 * Alternatively, one could encode(serialize) each command and it's arguments.
4454 bl--; /* undo RSEP from above */
4456 /* compute required room in buffer */
4458 for (c = commands->next; c != commands; c = c->next) {
4459 nchar += (strlen(c->cmd_string) + 1);
4460 if (c->cmd == D_eval) {
4462 nchar += (strlen(a->a_string) + 1); /* awk statements */
4463 nchar += (strlen("end") + 1);
4467 if (nchar > 0) { /* non-empty commands list */
4468 nchar += (strlen("commands ") + 20 + strlen("end") + 2); /* 20 for cnum (an int) */
4469 if (nchar > buflen - bl) {
4470 buflen = bl + nchar;
4471 erealloc(buf, char *, buflen + 3, "serialize");
4473 nchar = sprintf(buf + bl, "commands %d", cnum);
4476 for (c = commands->next; c != commands; c = c->next) {
4477 nchar = strlen(c->cmd_string);
4478 memcpy(buf + bl, c->cmd_string, nchar);
4482 if (c->cmd == D_eval) {
4484 nchar = strlen(a->a_string); /* statements */
4485 memcpy(buf + bl, a->a_string, nchar);
4488 nchar = strlen("end"); /* end of 'eval' */
4489 memcpy(buf + bl, "end", nchar);
4494 nchar = strlen("end"); /* end of 'commands' */
4495 memcpy(buf + bl, "end", nchar);
4498 buf[bl++] = FSEP; /* field */
4499 buf[bl++] = RSEP; /* record */
4502 /* condition expression */
4504 bl--; /* undo RSEP from above */
4505 nchar = strlen(cndn->expr);
4506 if (nchar > buflen - bl) {
4507 buflen = bl + nchar;
4508 erealloc(buf, char *, buflen + 3, "serialize");
4510 memcpy(buf + bl, cndn->expr, nchar);
4512 buf[bl++] = FSEP; /* field */
4513 buf[bl++] = RSEP; /* record */
4517 ptr = (type == BREAK) ? (void *) b->prev : (void *) wd->prev;
4520 ptr = (void *) wd->prev;
4523 ptr = (void *) hist_list[++hist_index];
4526 ptr = (void *) (++opt);
4533 if (bl > 0) /* non-empty list */
4534 setenv(env_variable[type], buf, 1);
4539 unserialize_commands(char *str, int str_len)
4541 if (str_len <= 0 || str == NULL)
4543 commands_string = str;
4544 commands_string_len = str_len;
4545 push_cmd_src(INVALID_HANDLE, false, read_commands_string, 0, 0, EXIT_FATAL);
4547 read_command(); /* forced to return in do_commands */
4552 /* unserialize_list_item --- create a list_item structure from unserialized data */
4554 static struct list_item *
4555 unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int field_cnt)
4558 struct list_item *l;
4559 NODE *symbol = NULL;
4560 int sub_cnt = 0, cnt;
4563 /* subscript -- number type sname num_subs subs [commands [condition]]
4564 * variable -- number type sname [commands [condition]]
4565 * field -- number type symbol(numbr) commands [commands [condition]]
4568 num = strtol(pstr[0], NULL, 0);
4569 type = strtol(pstr[1], NULL, 0);
4571 if (type == D_field) {
4573 field_num = strtol(pstr[2], NULL, 0);
4574 symbol = make_number((AWKNUM) field_num);
4578 name = estrdup(pstr[2], pstr_len[2]);
4579 symbol = find_symbol(name, NULL);
4584 if (type == D_subscript) {
4586 sub_cnt = strtol(pstr[3], NULL, 0);
4587 emalloc(subs, NODE **, sub_cnt * sizeof(NODE *), "unserialize_list_item");
4589 for (i = 0; i < sub_cnt; i++) {
4590 sub_len = strtol(pstr[cnt], NULL, 0);
4591 subs[i] = make_string(pstr[cnt + 1], sub_len);
4597 l = add_item(list, type, symbol, NULL);
4598 if (type == D_subscript) {
4599 l->num_subs = sub_cnt;
4602 l->number = num; /* keep same item number across executions */
4604 if (list == &watch_list) {
4605 initialize_watch_item(l);
4606 /* unserialize watchpoint `commands' */
4607 unserialize_commands(pstr[cnt], pstr_len[cnt]);
4609 if (field_cnt > cnt) {
4611 expr = estrdup(pstr[cnt], pstr_len[cnt]);
4612 if (parse_condition(D_watch, l->number, expr) != 0)
4615 if (num > list->number) /* update list number counter */
4623 /* unserialize_breakpoint --- create a breakpoint structure from unserialized data */
4626 unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt)
4630 BREAKPOINT *b = NULL;
4634 /* src source_line flags ignore_count hit_count number commands [condition] */
4636 src = estrdup(pstr[0], pstr_len[0]);
4637 s = source_find(src);
4642 lineno = strtol(pstr[1], NULL, 0);
4643 if (lineno <= 0 || lineno > s->srclines)
4645 rp = find_rule(src, lineno);
4647 || (b = set_breakpoint_at(rp, lineno, true)) == NULL
4651 b->flags = strtol(pstr[2], NULL, 0);
4652 b->ignore_count = strtol(pstr[3], NULL, 0);
4653 b->hit_count = strtol(pstr[4], NULL, 0);
4654 b->number = strtol(pstr[5], NULL, 0); /* same number as previous run */
4656 if (field_cnt > 6) /* unserialize breakpoint `commands' */
4657 unserialize_commands(pstr[6], pstr_len[6]);
4659 if (field_cnt > 7) { /* condition expression */
4661 expr = estrdup(pstr[7], pstr_len[7]);
4662 if (parse_condition(D_break, b->number, expr) != 0)
4666 if (b->number > watch_list.number) /* watch and break has same number counter */
4667 watch_list.number = b->number; /* update counter */
4671 /* unserialize_option --- set a debugger option from unserialized data. */
4673 static struct dbg_option *
4674 unserialize_option(char **pstr, int *pstr_len, int field_cnt ATTRIBUTE_UNUSED)
4676 const struct dbg_option *opt;
4678 for (opt = option_list; opt->name; opt++) {
4679 if (strncmp(pstr[0], opt->name, pstr_len[0]) == 0) {
4682 value = estrdup(pstr[1], pstr_len[1]);
4683 (*(opt->assign))(value);
4685 return ((struct dbg_option *) opt);
4691 /* unserialize -- reconstruct list from serialized data stored in
4692 * environment variable.
4696 unserialize(int type)
4699 char *p, *q, *r, *s;
4700 #define MAX_FIELD 30
4701 static char *pstr[MAX_FIELD];
4702 static int pstr_len[MAX_FIELD];
4704 val = getenv(env_variable[type]);
4708 for (p = val; (q = strchr(p, RSEP)) != NULL; p = q + 1) {
4710 if (type == HISTORY) {
4718 while ((s = strchr(r, FSEP)) != NULL && s < q) {
4719 pstr[field_cnt] = r;
4720 pstr_len[field_cnt] = (int) (s - r);
4723 if (field_cnt == MAX_FIELD)
4725 fatal("Increase MAX_FIELD and recompile.\n");
4733 (void) unserialize_breakpoint(pstr, pstr_len, field_cnt);
4736 (void) unserialize_list_item(&display_list, pstr, pstr_len, field_cnt);
4739 (void) unserialize_list_item(&watch_list, pstr, pstr_len, field_cnt);
4742 (void) unserialize_option(pstr, pstr_len, field_cnt);
4745 /* processed at the beginning of for loop */
4752 #ifdef HAVE_LIBREADLINE
4753 if (type == HISTORY)
4754 sess_history_base = history_length;
4757 unsetenv(env_variable[type]);
4762 prompt_yes_no(const char *mesg, char res_true, int res_default, FILE *fp)
4765 int ret = res_default; /* default */
4767 if (input_from_tty) {
4768 fprintf(fp, "%s", _(mesg));
4769 in_str = read_a_line(NULL);
4770 if (in_str == NULL) /* EOF */
4772 ret = (*in_str == res_true);
4778 /* has_break_or_watch_point --- check if given breakpoint or watchpoint
4779 * number exists. When flag any is true,
4780 * check if any breakpoint/watchpoint
4781 * has been set (ignores num). Returns
4782 * type (breakpoint or watchpoint) or 0.
4786 has_break_or_watch_point(int *pnum, bool any)
4788 BREAKPOINT *b = NULL;
4789 struct list_item *w = NULL;
4792 if (breakpoints.next != &breakpoints)
4793 b = breakpoints.next;
4794 if (watch_list.next != &watch_list)
4795 w = watch_list.next;
4807 if (w->number > b->number) {
4815 /* N.B: breakpoints and watchpoints get numbers from a single
4816 * counter/sequencer watch_list.number.
4819 for (b = breakpoints.next; b != &breakpoints; b = b->next) {
4820 if (b->number == *pnum)
4823 for (w = watch_list.next; w != &watch_list; w = w->next) {
4824 if (w->number == *pnum)
4831 /* delete_commands_item --- delete item(command) from `commands' list. */
4834 delete_commands_item(struct commands_item *c)
4836 efree(c->cmd_string);
4837 free_cmdarg(c->arg);
4838 c->next->prev = c->prev;
4839 c->prev->next = c->next;
4843 /* do_commands --- commands command */
4846 do_commands(CMDARG *arg, int cmd)
4848 static BREAKPOINT *b;
4849 static struct list_item *w;
4850 static struct commands_item *commands;
4851 struct commands_item *c;
4853 if (cmd == D_commands) {
4856 type = has_break_or_watch_point(&num, true);
4859 type = has_break_or_watch_point(&num, false);
4863 if (type == D_break)
4864 b = find_breakpoint(num);
4865 else if (type == D_watch)
4866 w = find_item(&watch_list, num);
4867 assert((b != NULL) || (w != NULL));
4868 commands = (b != NULL) ? &b->commands : &w->commands;
4870 /* delete current commands */
4871 for (c = commands->next; c != commands; c = c->next) {
4873 delete_commands_item(c->next);
4877 } else if (cmd == D_end) {
4879 if (read_a_line == read_commands_string) /* unserializig commands */
4880 return true; /* done unserializing, terminate zzparse() */
4883 } else if (cmd == D_silent) {
4888 /* we also append silent command to the list for use
4889 * in `info break(watch)', and to simplify
4890 * serialization/unserialization of commands.
4894 assert(commands != NULL);
4896 emalloc(c, struct commands_item *, sizeof(struct commands_item), "do_commands");
4900 /* N.B.: first arg is the command string, see command.y */
4901 c->cmd_string = arg->a_string;
4902 c->arg = arg->next; /* actual arguments to the command */
4905 /* append to the list */
4906 c->prev = commands->prev;
4913 /* execute_commands --- execute breakpoint/watchpoint commands, the first
4914 * command that resumes execution terminates
4915 * commands processing.
4919 execute_commands(struct commands_item *commands)
4921 struct commands_item *c;
4925 for (c = commands->next; c != commands; c = c->next) {
4926 if (c->cmd == D_silent)
4928 cmd_ptr = get_command(c->cmd); /* command handler */
4929 ret = (*cmd_ptr)(c->arg, c->cmd);
4930 if (ret) /* resume execution (continue, next etc.) */
4936 /* do_print_f --- printf command */
4939 do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4947 volatile jmp_buf fatal_tag_stack;
4949 /* count maximum required size for tmp */
4950 for (a = arg; a != NULL ; a = a->next)
4952 emalloc(tmp, NODE **, count * sizeof(NODE *), "do_print_f");
4954 for (i = 0, a = arg; a != NULL ; i++, a = a->next) {
4958 r = find_symbol(name, NULL);
4961 if (r->type == Node_var_new)
4962 tmp[i] = Nnull_string;
4963 else if (r->type != Node_var) {
4964 d_error(_("`%s' is not a scalar variable"), name);
4967 tmp[i] = r->var_value;
4973 field_num = get_number_si(r);
4974 tmp[i] = *get_field(field_num, NULL);
4979 int cnt = a->a_count;
4981 r = find_array(name);
4985 for (; cnt > 0; cnt--) {
4989 value = in_array(r, subs);
4992 tmp[i] = Nnull_string; /* FIXME: goto done ? */
4993 else if (value->type == Node_var_array) {
4994 d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
5000 if (value == NULL) {
5001 d_error(_("[\"%s\"] not in array `%s'"),
5004 } else if (value->type != Node_var_array) {
5005 d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
5024 tmp[0] = force_string(tmp[0]);
5026 PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5027 if (setjmp(fatal_tag) == 0)
5028 r = format_tree(tmp[0]->stptr, tmp[0]->stlen, tmp, i);
5030 /* fatal error, restore exit_val of program */
5031 exit_val = EXIT_SUCCESS;
5034 POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5037 (void) fwrite(r->stptr, sizeof(char), r->stlen, out_fp);
5045 /* do_source --- source command */
5048 do_source(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5051 char *file = arg->a_string;
5053 fd = open_readfd(file);
5054 if (fd <= INVALID_HANDLE) {
5055 d_error(_("can't open source file `%s' for reading (%s)"),
5056 file, strerror(errno));
5060 push_cmd_src(fd, false, g_readline, close, D_source, EXIT_SUCCESS);
5061 cmd_src->str = estrdup(file, strlen(file));
5065 /* open_readfd --- open a file for reading */
5068 open_readfd(const char *file)
5072 fd = open(file, O_RDONLY);
5073 if (fd <= INVALID_HANDLE)
5074 return INVALID_HANDLE;
5075 else if (os_isdir(fd)) {
5078 return INVALID_HANDLE;
5083 /* find_option --- check if option name is valid */
5086 find_option(char *name)
5091 for (idx = 0; (p = option_list[idx].name); idx++) {
5092 if (strcmp(p, name) == 0)
5098 /* option_help --- display help text for debugger options */
5103 const struct dbg_option *opt;
5105 for (opt = option_list; opt->name; opt++)
5106 fprintf(out_fp, "\t%-15.15s - %s\n", opt->name, _(opt->help_txt));
5109 #ifdef HAVE_LIBREADLINE
5111 /* option_generator --- generator function for option name completion */
5114 option_generator(const char *text, int state)
5116 static size_t textlen;
5120 if (! state) { /* first time */
5121 textlen = strlen(text);
5125 while ((name = option_list[idx++].name)) {
5126 if (strncmp(name, text, textlen) == 0)
5127 return estrdup(name, strlen(name));
5134 /* set_gawk_output --- redirect gawk (normal) output */
5137 set_gawk_output(const char *file)
5139 int fd = INVALID_HANDLE;
5142 if (output_fp != stdout) {
5143 if (output_fp != stderr) {
5148 output_is_tty = os_isatty(fileno(stdout));
5149 output_file = "/dev/stdout";
5152 if (file == NULL || file[0] == '\0')
5156 if ((fd = os_devopen(file, O_WRONLY)) != INVALID_HANDLE) {
5157 fp = fdopen(fd, "w");
5161 } else if (strncmp(file, "/dev/", 5) == 0) {
5162 char *cp = (char *) file + 5;
5164 if (strcmp(cp, "stdout") == 0)
5166 if (strcmp(cp, "stderr") == 0) {
5168 output_file = "/dev/stderr";
5169 output_is_tty = os_isatty(fileno(stderr));
5173 if (strncmp(cp, "fd/", 3) == 0) {
5175 fd = (int) strtoul(cp, NULL, 10);
5176 if (errno == 0 && fd > INVALID_HANDLE) {
5177 fp = fdopen(fd, "w");
5179 fd = INVALID_HANDLE;
5181 fd = INVALID_HANDLE;
5183 /* /dev/ttyN, /dev/pts/N, /dev/null etc. */
5184 fd = open(file, O_WRONLY);
5187 if (fd > INVALID_HANDLE && fp == NULL) {
5188 fp = fdopen(fd, "w");
5195 fp = fopen(file, "w");
5200 output_file = estrdup(file, strlen(file));
5201 setbuf(fp, (char *) NULL);
5202 output_is_tty = os_isatty(fileno(fp));
5204 d_error(_("could not open `%s' for writing (%s)"),
5206 errno != 0 ? strerror(errno) : _("reason unknown"));
5207 fprintf(out_fp, _("sending output to stdout\n"));
5211 /* set_prompt --- set debugger prompt */
5214 set_prompt(const char *value)
5216 efree(dgawk_prompt);
5217 dgawk_prompt = estrdup(value, strlen(value));
5218 dbg_prompt = dgawk_prompt;
5221 /* set_option_flag --- convert option string to flag value */
5224 set_option_flag(const char *value)
5227 if (strcmp(value, "on") == 0)
5229 if (strcmp(value, "off") == 0)
5232 n = strtol(value, NULL, 0);
5233 return (errno == 0 && n != 0);
5236 /* set_option_num --- set integer option value from string */
5239 set_option_num(int *pnum, const char *value)
5243 n = strtol(value, NULL, 0);
5244 if (errno == 0 && n > 0)
5247 d_error(_("invalid number"));
5250 /* set_listsize --- set list output window size */
5253 set_listsize(const char *value)
5255 set_option_num(&list_size, value);
5258 /* set_trace --- set instruction tracing on or off */
5261 set_trace(const char *value)
5263 do_trace = set_option_flag(value);
5266 /* set_save_history --- save history on exit */
5269 set_save_history(const char *value)
5271 do_save_history = set_option_flag(value);
5274 /* set_save_options --- save options on exit */
5277 set_save_options(const char *value)
5279 do_save_options = set_option_flag(value);
5282 /* set_history_size --- maximum entries in history file */
5285 set_history_size(const char *value)
5287 set_option_num(&history_size, value);
5291 /* read_commands_string --- one of the many ways zzlex fetches a line to parse;
5292 * this one is used to parse `commands' string during
5297 read_commands_string(const char *prompt ATTRIBUTE_UNUSED)
5299 char *p, *end, *line;
5301 if (commands_string == NULL)
5304 p = (char *) commands_string;
5305 end = (char *) commands_string + commands_string_len;
5306 for (; p < end; p++) {
5307 if (*p == line_sep) {
5308 line = estrdup(commands_string, p - commands_string);
5309 commands_string = p + 1;
5310 commands_string_len = end - commands_string;
5315 line = estrdup(commands_string, commands_string_len);
5316 commands_string = NULL;
5317 commands_string_len = 0;
5321 /* save_options --- save current options to file */
5324 save_options(const char *file)
5327 const struct dbg_option *opt;
5329 fp = fopen(file, "w");
5333 for (opt = option_list; opt->name; opt++) {
5334 if (opt->str_val != NULL)
5335 fprintf(fp, "option %s = \"%s\"\n", opt->name, *(opt->str_val));
5337 fprintf(fp, "option %s = %d\n", opt->name, *(opt->num_val));
5343 /* close_all --- close all open files */
5349 struct command_source *cs;
5351 (void) nextfile(& curfile, true); /* close input data file */
5352 (void) close_io(& stdio_problem);
5353 if (cur_srcfile->fd != INVALID_HANDLE) {
5354 close(cur_srcfile->fd);
5355 cur_srcfile->fd = INVALID_HANDLE;
5357 for (cs = cmd_src; cs != NULL; cs = cs->next) {
5358 if (cs->close_func && cs->fd != INVALID_HANDLE) {
5359 cs->close_func(cs->fd);
5360 cs->fd = INVALID_HANDLE;
5366 set_gawk_output(NULL); /* closes output_fp if not stdout */
5369 /* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
5372 pre_execute_code(INSTRUCTION **pi)
5374 INSTRUCTION *ei = *pi;
5376 switch (ei->opcode) {
5380 case Op_K_getline: /* getline without redirection */
5381 d_error(_("`%s' not allowed in current context;"
5382 " statement ignored"),
5383 op2str(ei->opcode));
5387 if (ei->nexti != NULL) { /* not an implicit return */
5389 d_error(_("`return' not allowed in current context;"
5390 " statement ignored"));
5391 /* throw away return value already pushed onto stack */
5403 extern INSTRUCTION *unwind_stack(long n);
5406 execute_code(volatile INSTRUCTION *code)
5408 volatile NODE *r = NULL;
5409 volatile jmp_buf fatal_tag_stack;
5410 long save_stack_size;
5411 int save_flags = do_flags;
5413 /* We use one global stack for all contexts.
5414 * Save # of items in stack; in case of
5415 * a fatal error, pop stack until it has that many items.
5418 save_stack_size = (stack_ptr - stack_bottom) + 1;
5421 PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5422 if (setjmp(fatal_tag) == 0) {
5423 (void) interpret((INSTRUCTION *) code);
5425 } else /* fatal error */
5426 (void) unwind_stack(save_stack_size);
5428 POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5429 do_flags = save_flags;
5430 if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */
5431 exit_val = EXIT_SUCCESS;
5437 /* do_eval --- eval command */
5440 do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5444 NODE *this_frame = NULL, *this_func = NULL;
5446 INSTRUCTION *eval, *code = NULL;
5448 int ecount = 0, pcount = 0;
5450 int save_flags = do_flags;
5453 this_frame = find_frame(0);
5454 this_func = this_frame->func_node;
5457 install_params(this_func); /* expose current function parameters to eval */
5458 ctxt = new_context();
5459 ctxt->install_func = append_symbol; /* keep track of newly installed globals */
5461 (void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
5463 ret = parse_program(&code);
5464 do_flags = save_flags;
5465 remove_params(this_func);
5467 pop_context(); /* switch to prev context */
5468 free_context(ctxt, false /* keep_globals */);
5472 f = lookup("@eval");
5474 if (this_func == NULL) { /* in main */
5475 /* do a function call */
5476 eval = bcalloc(Op_func_call, 2, 0);
5477 eval->source_file = cur_srcfile->src;
5478 eval->func_body = f;
5479 eval->func_name = NULL; /* not needed, func_body already assigned */
5480 (eval + 1)->expr_count = 0;
5481 eval->nexti = bcalloc(Op_stop, 1, 0);
5484 /* execute as a part of the current function */
5488 eval = f->code_ptr; /* Op_func */
5489 eval->source_file = cur_srcfile->src;
5490 /* turn implicit Op_K_return into Op_stop */
5491 t = (eval + 1)->lasti; /* Op_K_return */
5492 t->opcode = Op_stop;
5494 /* add or append eval locals to the current frame stack */
5495 ecount = f->param_cnt; /* eval local count */
5496 pcount = this_func->param_cnt;
5500 emalloc(this_frame->stack, NODE **, ecount * sizeof(NODE *), "do_eval");
5502 erealloc(this_frame->stack, NODE **, (pcount + ecount) * sizeof(NODE *), "do_eval");
5504 sp = this_frame->stack + pcount;
5505 for (i = 0; i < ecount; i++) {
5509 np->param_cnt += pcount; /* appending eval locals: fixup param_cnt */
5512 memset(r, 0, sizeof(NODE));
5514 /* local variable */
5515 r->type = Node_var_new;
5516 r->vname = np->param;
5519 this_func->param_cnt += ecount;
5524 pf_data.print_func = fprintf;
5525 pf_data.fp = out_fp;
5526 pf_data.defn = false; /* in_dump = false */
5527 (void) print_code(f->code_ptr, &pf_data);
5530 ret_val = execute_code((volatile INSTRUCTION *) eval);
5532 if (ret_val != NULL)
5533 DEREF(ret_val); /* throw away return value */
5537 if (this_func != NULL && ecount > 0) {
5540 /* undo frame manipulation from above */
5542 /* free eval locals */
5543 sp = this_frame->stack + pcount;
5544 for (i = ecount; i > 0; i--) {
5546 if (r->type == Node_var) /* eval local variable */
5547 DEREF(r->var_value);
5548 else if (r->type == Node_var_array) /* eval local array */
5554 efree(this_frame->stack);
5555 this_frame->stack = NULL;
5557 restore_frame() will free it */
5559 this_func->param_cnt -= ecount;
5562 /* always destroy symbol "@eval", however destroy all newly installed
5563 * globals only if fatal error (execute_code() returing NULL).
5566 pop_context(); /* switch to prev context */
5567 free_context(ctxt, (ret_val != NULL)); /* free all instructions and optionally symbols */
5568 if (ret_val != NULL)
5569 destroy_symbol(f); /* destroy "@eval" */
5575 ... When you use condition, GDB checks expression
5576 immediately for syntactic correctness, and to determine whether symbols
5577 in it have referents in the context of your breakpoint. If expression
5578 uses symbols not referenced in the context of the breakpoint, GDB prints
5581 No symbol "foo" in current context.
5584 static int invalid_symbol = 0;
5587 check_symbol(NODE *r)
5590 d_error(_("No symbol `%s' in current context"), r->vname);
5591 /* install anyway, but keep track of it */
5595 /* parse_condition --- compile a condition expression */
5598 parse_condition(int type, int num, char *expr)
5600 INSTRUCTION *code = NULL;
5601 AWK_CONTEXT *ctxt = NULL;
5604 struct list_item *w;
5605 NODE *this_func = NULL;
5606 INSTRUCTION *it, *stop, *rule;
5607 struct condition *cndn = NULL;
5608 int save_flags = do_flags;
5610 if (type == D_break && (b = find_breakpoint(num)) != NULL) {
5613 rp = find_rule(b->src, b->bpi->source_line);
5614 if (rp != NULL && rp->opcode == Op_func)
5615 this_func = rp->func_body;
5616 } else if (type == D_watch && (w = find_item(&watch_list, num)) != NULL) {
5618 this_func = find_frame(cur_frame)->func_node;
5624 goto out; /* delete condition */
5626 install_params(this_func);
5627 ctxt = new_context();
5629 ctxt->install_func = check_symbol;
5631 (void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
5633 ret = parse_program(&code);
5634 do_flags = save_flags;
5635 remove_params(this_func);
5638 if (ret != 0 || invalid_symbol) {
5639 free_context(ctxt, false /* keep_globals */);
5643 /* condition expression is parsed as awk pattern without
5644 * any action. The code is then modified to end up with
5645 * a `1.0' on stack when the expression is true, `0.0' otherwise.
5648 assert(code != NULL);
5649 rule = ctxt->rule_list.nexti;
5650 stop = bcalloc(Op_stop, 1, 0);
5652 it = rule->firsti; /* Op_K_print_rec */
5653 assert(it->opcode == Op_K_print_rec);
5654 it->opcode = Op_push_i;
5655 it->memory = make_number(1.0);
5656 it->nexti = bcalloc(Op_jmp, 1, 0);
5657 it->nexti->target_jmp = stop;
5658 it->nexti->nexti = rule->lasti;
5660 it = rule->lasti; /* Op_no_op, target for Op_jmp_false */
5661 assert(it->opcode == Op_no_op);
5662 it->opcode = Op_push_i;
5663 it->memory = make_number(0.0);
5667 if (cndn->expr != NULL)
5669 free_context(cndn->ctxt, false);
5677 /* do_condition --- condition command */
5680 do_condition(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5686 type = has_break_or_watch_point(&num, false);
5689 arg = arg->next; /* condition expression */
5691 expr = arg->a_string;
5692 if (parse_condition(type, num, expr) == 0 && arg != NULL)
5693 arg->a_string = NULL; /* don't let free_cmdarg free it */
5697 /* in_cmd_src --- check if filename already in cmd_src */
5700 in_cmd_src(const char *filename)
5702 struct command_source *cs;
5703 for (cs = cmd_src; cs != NULL; cs = cs->next) {
5704 if (cs->str != NULL && strcmp(cs->str, filename) == 0)
5713 if (cmd_src == NULL)
5715 return cmd_src->eof_status;
5722 char * (*readfunc)(const char *),
5723 int (*closefunc)(int),
5727 struct command_source *cs;
5728 emalloc(cs, struct command_source *, sizeof(struct command_source), "push_cmd_src");
5731 cs->read_func = readfunc;
5732 cs->close_func = closefunc;
5735 /* eof_status = EXIT_FATAL - exit with status EXIT_FATAL on EOF or error.
5736 * = EXIT_FAILURE - exit status EXIT_FAILURE on error.
5737 * = EXIT_SUCCESS - don't exit on EOF or error.
5739 cs->eof_status = eofstatus;
5745 input_from_tty = istty;
5746 read_a_line = readfunc;
5752 struct command_source *cs;
5754 if (cmd_src->next == NULL)
5759 if (cs->close_func && cs->fd != INVALID_HANDLE)
5760 cs->close_func(cs->fd);
5761 if (cs->str != NULL)
5765 input_fd = cmd_src->fd;
5766 input_from_tty = cmd_src->is_tty;
5767 read_a_line = cmd_src->read_func;