2 * debug.c - gawk debugger
6 * Copyright (C) 2004, 2010, 2011 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 r_interpret(INSTRUCTION *);
44 extern int zzparse(void);
45 #define read_command() (void) zzparse()
47 extern int free_instruction(INSTRUCTION *, int *);
48 extern void destroy_symbol(char *name);
49 extern const char *redir2str(int redirtype);
51 static char *linebuf = NULL; /* used to print a single line of source */
52 static size_t linebuf_len;
56 char *commands_Prompt = "> "; /* breakpoint or watchpoint commands list */
57 char *eval_Prompt = "@> "; /* awk statement(s) */
59 int input_from_tty = FALSE;
62 static SRCFILE *cur_srcfile;
63 static long cur_frame = 0;
64 static INSTRUCTION *cur_pc;
67 static int prog_running = FALSE;
75 struct commands_item {
76 struct commands_item *next;
77 struct commands_item *prev;
83 /* breakpoint structure */
84 typedef struct break_point {
85 struct break_point *next;
86 struct break_point *prev;
92 INSTRUCTION *bpi; /* Op_breakpoint */
94 struct commands_item commands; /* list of commands to run */
97 struct condition cndn;
101 #define BP_ENABLE_ONCE 2 /* enable once */
107 static BREAKPOINT breakpoints = { &breakpoints, &breakpoints, 0 };
109 #ifdef HAVE_LIBREADLINE
110 /* do_save -- save command */
111 static int sess_history_base = 0;
115 static int last_printed_line = 0;
116 static int last_print_count; /* # of lines printed */
118 /* watch or display item */
120 struct list_item *next;
121 struct list_item *prev;
122 int number; /* item number */
124 NODE *symbol; /* variable or function param */
125 NODE **subs; /* subscripts */
126 int num_subs; /* subscript(dimension) count */
127 char *sname; /* symbol or param name */
131 struct commands_item commands;
133 struct condition cndn;
135 /* This is for the value of the watched item */
140 #define cur_value value[0].n
141 #define cur_size value[0].l
142 #define old_value value[1].n
143 #define old_size value[1].l
149 #define OLD_IS_ARRAY 8 /* old item is array */
150 #define CUR_IS_ARRAY 16 /* current item is array */
153 #define IS_PARAM(d) (((d)->flags & PARAM) != 0)
154 #define IS_SUBSCRIPT(d) (((d)->flags & SUBSCRIPT) != 0)
155 #define IS_FIELD(d) (((d)->flags & FIELD_NUM) != 0)
156 #define WATCHING_ARRAY(d) (((d)->flags & CUR_IS_ARRAY) != 0)
158 static struct list_item display_list = { &display_list, &display_list, 0 };
159 static struct list_item watch_list = { &watch_list, &watch_list, 0 };
162 /* Structure to maintain data for processing debugger commands */
165 long fcall_count; /* 'finish', 'until', 'next', 'step', 'nexti' commands */
166 int sourceline; /* source line number last
167 * time we stopped execution,
168 * used by next, until and step commands
170 char *source; /* next, until and step */
172 INSTRUCTION *pc; /* 'until' and 'return' commands */
173 int repeat_count; /* 'step', 'next', 'stepi', 'nexti' commands */
174 int print_frame; /* print frame info, 'finish' and 'until' */
175 int print_ret; /* print returned value, 'finish' */
176 int break_point; /* non-zero (breakpoint number) if stopped at break point */
177 int watch_point; /* non-zero (watchpoint number) if stopped at watch point */
179 int (*check_func)(INSTRUCTION **); /* function to decide when to suspend
180 * awk interpreter and return control
181 * to debugger command interpreter.
184 enum argtype command; /* command type */
188 /* restart related stuff */
189 extern char **d_argv; /* copy of argv array */
190 static int need_restart = FALSE;
191 enum { BREAK=1, WATCH, DISPLAY, HISTORY, OPTION };
192 static const char *const env_variable[] = {
200 static void serialize(int );
201 static void unserialize(int );
202 static const char *commands_string = NULL;
203 static int commands_string_len = 0;
204 static char line_sep;
205 #define FSEP (char)'\037'
206 #define RSEP (char)'\036'
207 #define CSEP (char)'\035'
210 /* debugger option */
215 void (*assign)(const char *);
216 const char *help_txt;
219 #define DEFAULT_HISTFILE "./.dgawk_history"
220 #define DEFAULT_OPTFILE "./.dgawkrc"
221 #define DEFAULT_PROMPT "dgawk> "
222 #define DEFAULT_LISTSIZE 15
223 #define DEFAULT_HISTSIZE 100
225 static void set_gawk_output(const char *file);
226 static void set_prompt(const char *value);
227 static void set_listsize(const char *value);
228 static void set_trace(const char *value);
229 static void set_save_history(const char *value);
230 static void set_save_options(const char *value);
231 static void set_history_size(const char *value);
232 static const char *options_file = DEFAULT_OPTFILE;
233 #ifdef HAVE_LIBREADLINE
234 static const char *history_file = DEFAULT_HISTFILE;
237 /* keep all option variables in one place */
239 static char *output_file = "/dev/stdout"; /* gawk output redirection */
240 char *dgawk_Prompt = NULL; /* initialized in interpret */
241 static int list_size = DEFAULT_LISTSIZE; /* # of lines that 'list' prints */
242 static int do_trace = FALSE;
243 static int do_save_history = TRUE;
244 static int do_save_options = TRUE;
245 static int history_size = DEFAULT_HISTSIZE; /* max # of lines in history file */
247 static const struct dbg_option option_list[] = {
248 {"history_size", &history_size, NULL, &set_history_size,
249 gettext_noop("set or show the number of lines to keep in history file.") },
250 {"listsize", &list_size, NULL, &set_listsize,
251 gettext_noop("set or show the list command window size.") },
252 {"outfile", NULL, &output_file, &set_gawk_output,
253 gettext_noop("set or show gawk output file.") },
254 {"prompt", NULL, &dgawk_Prompt, &set_prompt,
255 gettext_noop("set or show debugger prompt."), },
256 {"save_history", &do_save_history, NULL, &set_save_history,
257 gettext_noop("(un)set or show saving of command history (value=on|off).") },
258 {"save_options", &do_save_options, NULL, &set_save_options,
259 gettext_noop("(un)set or show saving of options (value=on|off).") },
260 {"trace", &do_trace, NULL, &set_trace,
261 gettext_noop("(un)set or show instruction tracing (value=on|off).") },
262 {0, NULL, NULL, NULL, 0},
265 static void save_options(const char *file);
269 jmp_buf pager_quit_tag;
270 int pager_quit_tag_valid;
271 static int screen_width = INT_MAX; /* no of columns */
272 static int screen_height = INT_MAX; /* no of rows */
273 static int pager_lines_printed = 0; /* no of lines printed so far */
275 static void restart(int run) ATTRIBUTE_NORETURN;
276 static void close_all(void);
277 static int open_readfd(const char *file);
278 static int find_lines(SRCFILE *s);
279 static SRCFILE *source_find(char *src);
280 static int print_lines(char *src, int start_line, int nlines);
281 static void print_symbol(NODE *r, int isparam);
282 static NODE *find_frame(long num);
283 static NODE *find_param(const char *name, long num, char **pname);
284 static NODE *find_symbol(const char *name, char **pname);
285 static NODE *find_array(const char *name);
286 static void print_field(long field_num);
287 static int print_function(INSTRUCTION *pc, void *);
288 static void print_frame(NODE *func, char *src, int srcline);
289 static void print_numbered_frame(long num);
290 static void print_cur_frame_and_sourceline(void);
291 static INSTRUCTION *find_rule(char *src, long lineno);
292 static INSTRUCTION *mk_breakpoint(char *src, int srcline);
293 static int execute_commands(struct commands_item *commands);
294 static void delete_commands_item(struct commands_item *c);
295 static NODE *execute_code(volatile INSTRUCTION *code);
296 static int pre_execute_code(INSTRUCTION **pi);
297 static int parse_condition(int type, int num, char *expr);
298 static BREAKPOINT *add_breakpoint(INSTRUCTION *, INSTRUCTION *, char *, int);
299 static BREAKPOINT *set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip);
300 static BREAKPOINT *set_breakpoint_at(INSTRUCTION *, int, int);
301 static int set_breakpoint(CMDARG *arg, int temporary);
302 static void delete_breakpoint(BREAKPOINT *b);
303 static BREAKPOINT *find_breakpoint(long num);
304 static void display(struct list_item *d);
305 static struct list_item *find_item(struct list_item *list, long num);
306 static struct list_item *add_item(struct list_item *list, int type, NODE *symbol, char *pname);
307 static void delete_item(struct list_item *d);
308 static int breakpoint_triggered(BREAKPOINT *b);
309 static int watchpoint_triggered(struct list_item *w);
311 static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump);
312 static void next_command();
313 static char *g_readline(const char *prompt);
314 static int prompt_yes_no(const char *, char , int , FILE *);
316 static struct pf_data {
317 Func_print print_func;
322 char * (*read_a_line)(const char *) = 0; /* reads a line of input */
324 struct command_source
328 char * (*read_func)(const char *);
329 int (*close_func)(int);
330 int eof_status; /* see push_cmd_src */
331 int cmd; /* D_source or 0 */
332 char *str; /* sourced file */
333 struct command_source *next;
336 static struct command_source *cmd_src = NULL;
338 #define get_param_count(f) (f)->lnode->param_cnt
339 #define get_params(f) (f)->parmlist
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);
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 if (s->line_offset == NULL && find_lines(s) != 0)
547 if (start_line < 1 || start_line > s->srclines) {
548 d_error(_("line number %d out of range; `%s' has %d lines"),
549 start_line, src, s->srclines);
554 if ((start_line + nlines - 1) > s->srclines)
555 nlines = s->srclines - start_line + 1;
557 pos = s->line_offset;
558 if (lseek(s->fd, (off_t) pos[start_line - 1], SEEK_SET) < 0) {
559 d_error("%s: %s", src, strerror(errno));
563 if (linebuf == NULL) {
564 emalloc(linebuf, char *, s->maxlen + 20, "print_lines"); /* 19 for line # */
565 linebuf_len = s->maxlen;
566 } else if (linebuf_len < s->maxlen) {
567 erealloc(linebuf, char *, s->maxlen + 20, "print_lines");
568 linebuf_len = s->maxlen;
571 for (i = start_line; i < start_line + nlines; i++) {
572 int supposed_len, len;
575 sprintf(linebuf, "%-8d", i);
577 /* mark the line about to be executed with =>; nlines > 1
578 * condition makes sure that we are in list command
583 for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
584 if (src == b->src && i == b->bpi->source_line) {
589 if (prog_running && src == source && i == sourceline) {
591 sprintf(linebuf, "%-4d:b=>", i);
593 sprintf(linebuf, "%-4d =>", i);
595 sprintf(linebuf, "%-4d:b ", i);
598 p = linebuf + strlen(linebuf);
599 supposed_len = pos[i] - pos[i - 1];
600 len = read(s->fd, p, supposed_len);
603 d_error(_("can't read source file `%s' (%s)"),
604 src, strerror(errno));
608 d_error(_("unexpected eof while reading file `%s', line %d"),
613 if (i == s->srclines && p[len - 1] != '\n')
616 if (len != supposed_len || p[len - 1] != '\n') {
617 d_error(_("source file `%s' modified since start of program execution"),
622 len += (p - linebuf);
623 if (fwrite(linebuf, sizeof(char), len, out_fp) != len)
628 if (cur_srcfile != s) {
629 if (cur_srcfile->fd != INVALID_HANDLE) {
630 close(cur_srcfile->fd);
631 cur_srcfile->fd = INVALID_HANDLE;
635 return (i - 1); /* no of lines printed */
638 /* do_list --- list command */
641 do_list(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
643 long line_first, line_last;
644 long count = list_size;
646 char *src = cur_srcfile->src;
648 line_first = last_printed_line + 1; /* default or no arg */
649 if (arg == NULL) /* list or list + */
653 case D_int: /* list n or list - */
654 if (arg->a_int < 0) { /* list - */
655 line_first = last_printed_line - last_print_count - list_size + 1;
656 if (line_first < 1) {
657 if (last_printed_line != last_print_count)
664 line_first = arg->a_int - list_size / 2;
670 case D_range: /* list m-n */
672 line_first = arg->a_int;
675 assert(arg->type == D_int);
676 count = arg->a_int - line_first + 1;
681 if (arg->next != NULL) {
683 if (arg->type == D_int) /* list file:n */
685 else if (arg->type == D_range) /* list file:m-n */
687 else if (arg->type == D_func) /* list file:function */
695 case D_func: /* list function */
697 rp = arg->a_node->code_ptr;
698 src = rp->source_file;
699 line_first = rp->source_line - list_size / 2;
709 line_last = print_lines(src, line_first, count);
710 if (line_last != -1) {
711 last_printed_line = line_last;
712 last_print_count = line_last - line_first + 1;
717 /* do_info --- info command */
720 do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
722 if (arg == NULL || arg->type != D_argument)
725 switch (arg->a_argument) {
727 fprintf(out_fp, _("Current source file: %s\n"), cur_srcfile->src);
728 fprintf(out_fp, _("Number of lines: %d\n"), cur_srcfile->srclines);
734 for (s = srcfiles->next; s != srcfiles; s = s->next) {
735 fprintf(out_fp, _("Source file (lines): %s (%d)\n"),
736 (s->stype == SRC_FILE || s->stype == SRC_INC) ? s->src
744 initialize_pager(out_fp);
745 if (setjmp(pager_quit_tag) == 0) {
747 struct commands_item *c;
749 gprintf(out_fp, _("Number Disp Enabled Location\n\n"));
750 for (b = breakpoints.prev; b != &breakpoints; b = b->prev) {
752 if (b->flags & BP_ENABLE_ONCE)
754 else if(b->flags & BP_TEMP)
756 gprintf(out_fp, "%-6d %-4.4s %-7.7s file %s, line #%d\n",
757 b->number, disp, (b->flags & BP_ENABLE) ? "yes" : "no",
758 b->src, b->bpi->source_line);
759 if (b->hit_count > 0)
760 gprintf(out_fp, _("\tno of hits = %ld\n"), b->hit_count);
761 if (b->flags & BP_IGNORE)
762 gprintf(out_fp, _("\tignore next %ld hit(s)\n"), b->ignore_count);
763 if (b->cndn.code != NULL)
764 gprintf(out_fp, _("\tstop condition: %s\n"), b->cndn.expr);
765 if (b->commands.next != &b->commands)
766 gprintf(out_fp, _("\tcommands:\n"));
767 for (c = b->commands.next; c != &b->commands; c = c->next) {
768 gprintf(out_fp, "\t%s\n", c->cmd_string);
769 if (c->cmd == D_eval) {
772 start = strchr(a->a_string, '{');
773 end = strrchr(a->a_string, '}');
774 if (start == NULL || end == NULL)
778 gprintf(out_fp, "%s", start); /* FIXME: translate ? */
787 CHECK_PROG_RUNNING();
788 fprintf(out_fp, _("Current frame: "));
789 print_numbered_frame(cur_frame);
790 if (cur_frame < fcall_count) {
791 fprintf(out_fp, _("Called by frame: "));
792 print_numbered_frame(cur_frame + 1);
795 fprintf(out_fp, _("Caller of frame: "));
796 print_numbered_frame(cur_frame - 1);
805 int arg_count, pcount;
809 CHECK_PROG_RUNNING();
810 f = find_frame(cur_frame);
814 fprintf(out_fp, _("None in main().\n"));
818 pcount = get_param_count(func); /* # of defined params */
819 pnames = get_params(func); /* param names */
821 pc = (INSTRUCTION *) f->reti; /* Op_func_call instruction */
822 arg_count = (pc + 1)->expr_count; /* # of arguments supplied */
824 if (arg_count > pcount) /* extra args */
826 if (arg->a_argument == A_ARGS) {
834 for (i = from; i <= to; i++) {
837 if (r->type == Node_array_ref)
839 fprintf(out_fp, "%s = ", pnames[i]);
840 print_symbol(r, TRUE);
843 fprintf(out_fp, "%s",
844 arg->a_argument == A_ARGS ?
845 _("No arguments.\n") :
851 initialize_pager(out_fp);
852 if (setjmp(pager_quit_tag) == 0) {
853 gprintf(out_fp, _("All defined variables:\n\n"));
854 print_vars(gprintf, out_fp);
859 initialize_pager(out_fp);
860 if (setjmp(pager_quit_tag) == 0) {
861 gprintf(out_fp, _("All defined functions:\n\n"));
862 pf_data.print_func = gprintf;
865 (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_function,
874 initialize_pager(out_fp);
875 if (setjmp(pager_quit_tag) == 0) {
876 struct list_item *d, *list;
878 if (arg->a_argument == A_DISPLAY) {
879 list = &display_list;
880 gprintf(out_fp, _("Auto-display variables:\n\n"));
883 gprintf(out_fp, _("Watch variables:\n\n"));
885 for (d = list->prev; d != list; d = d->prev) {
887 struct commands_item *c;
888 NODE *symbol = d->symbol;
890 if (IS_SUBSCRIPT(d)) {
891 gprintf(out_fp, "%d:\t%s", d->number, d->sname);
892 for (i = 0; i < d->num_subs; i++) {
895 gprintf(out_fp, "[\"%s\"]", sub->stptr);
897 gprintf(out_fp, "\n");
898 } else if (IS_FIELD(d))
899 gprintf(out_fp, "%d:\t$%ld\n", d->number, (long) symbol->numbr);
901 gprintf(out_fp, "%d:\t%s\n", d->number, d->sname);
902 if (d->cndn.code != NULL)
903 gprintf(out_fp, _("\tstop condition: %s\n"), d->cndn.expr);
904 if (d->commands.next != &d->commands)
905 gprintf(out_fp, _("\tcommands:\n"));
906 for (c = d->commands.next; c != &d->commands; c = c->next) {
907 gprintf(out_fp, "\t%s\n", c->cmd_string);
908 if (c->cmd == D_eval) {
911 start = strchr(a->a_string, '{');
912 end = strrchr(a->a_string, '}');
913 if (start == NULL || end == NULL)
917 gprintf(out_fp, "%s", start); /* FIXME: translate ? */
933 /* print_symbol --- print a symbol table entry */
936 print_symbol(NODE *r, int isparam)
940 fprintf(out_fp, "untyped variable\n");
943 if (! isparam && r->var_update)
945 valinfo(r->var_value, fprintf, out_fp);
948 fprintf(out_fp, "array, %ld elements\n", r->table_size);
951 fprintf(out_fp, "`function'\n");
958 /* find_frame --- find frame given a frame number */
967 assert(prog_running == TRUE);
968 assert(num <= fcall_count);
969 assert(fcall_list[num] != NULL);
970 return fcall_list[num];
973 /* find_param --- find a function parameter in a given frame number */
976 find_param(const char *name, long num, char **pname)
984 if (num < 0 || num > fcall_count || name == NULL)
987 if (f->func_node != NULL) { /* in function */
993 pnames = get_params(func);
994 pcount = get_param_count(func);
996 for (i = 0; i < pcount; i++) {
997 if (strcmp(name, pnames[i]) == 0) {
999 if (r->type == Node_array_ref)
1010 /* find_symbol --- find a symbol in current context */
1013 NODE *find_symbol(const char *name, char **pname)
1020 r = find_param(name, cur_frame, pname);
1024 fprintf(out_fp, _("no symbol `%s' in current context\n"), name);
1028 /* find_array -- find an array in current context */
1031 find_array(const char *name)
1034 r = find_symbol(name, NULL);
1035 if (r != NULL && r->type != Node_var_array) {
1036 fprintf(out_fp, _("`%s' is not an array\n"), name);
1042 /* print_field --- print the value of $n */
1045 print_field(long field_num)
1048 lhs = get_field(field_num, NULL);
1049 if (*lhs == Null_field || *lhs == Nnull_string)
1050 fprintf(out_fp, _("$%ld = uninitialized field\n"), field_num);
1052 fprintf(out_fp, "$%ld = ", field_num);
1053 valinfo(*lhs, fprintf, out_fp);
1057 /* print_array --- print the contents of an array */
1060 print_array(volatile NODE *arr, char *arr_name)
1065 size_t num_elems = 0;
1067 volatile int ret = 0;
1068 volatile jmp_buf pager_quit_tag_stack;
1070 if (arr->var_array == NULL || arr->table_size == 0) {
1071 gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
1075 num_elems = arr->table_size;
1077 /* sort indices, sub_arrays are also sorted! */
1078 list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN);
1080 PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1081 if (setjmp(pager_quit_tag) == 0) {
1082 for (i = 0; ret == 0 && i < num_elems; i++) {
1084 r = bucket->ahvalue;
1085 if (r->type == Node_var_array)
1086 ret = print_array(r, r->vname);
1088 gprintf(out_fp, "%s[\"%s\"] = ", arr_name, bucket->ahname_str);
1089 valinfo((NODE *) r, gprintf, out_fp);
1095 POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1097 for (i = 0; i < num_elems; i++)
1104 /* print_subscript --- print an array element */
1107 print_subscript(NODE *arr, char *arr_name, CMDARG *a, int count)
1112 r = in_array(arr, subs);
1114 fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"), subs->stptr, arr_name);
1115 else if (r->type == Node_var_array) {
1117 print_subscript(r, r->vname, a->next, count - 1);
1119 /* print # of elements in array */
1120 fprintf(out_fp, "%s = ", r->vname);
1121 print_symbol(r, FALSE);
1124 fprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
1125 valinfo(r, fprintf, out_fp);
1129 /* do_print_var --- print command */
1132 do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1138 for (a = arg; a != NULL; a = a->next) {
1142 if ((r = find_symbol(name, &pname)) != NULL) {
1143 fprintf(out_fp, "%s = ", name);
1144 print_symbol(r, (pname != NULL));
1149 assert(a->a_count > 0);
1151 r = find_array(name);
1153 print_subscript(r, name, a->next, a->a_count);
1158 if ((r = find_array(name)) != NULL) {
1159 int count = a->a_count;
1160 for (; count > 0; count--) {
1164 value = in_array(r, subs);
1165 if (value == NULL) {
1166 fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"),
1169 } else if (value->type != Node_var_array) {
1170 fprintf(out_fp, _("`%s[\"%s\"]' is not an array\n"),
1179 initialize_pager(out_fp);
1180 print_array((volatile NODE *) r, name);
1186 print_field(a->a_node->numbr);
1190 /* notably D_node, subscript for invalid array name; skip */
1197 /* do_set_var --- set command */
1200 do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1206 switch (arg->type) {
1208 name = arg->a_string;
1212 if ((r = find_symbol(name, &pname)) == NULL)
1218 r->var_value = Nnull_string;
1221 lhs = &r->var_value;
1223 *lhs = dupnode(val);
1224 if (pname == NULL && r->var_assign != NULL)
1226 fprintf(out_fp, "%s = ", name);
1227 print_symbol(r, (pname != NULL));
1231 d_error(_("`%s' is not a scalar variable"), name);
1239 int count = arg->a_count;
1242 name = arg->a_string;
1243 r = find_array(name);
1246 for (; count > 0; count--) {
1249 value = in_array(r, subs);
1252 if (value != NULL && value->type == Node_var_array)
1253 d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
1258 lhs = assoc_lookup(r, subs, FALSE);
1260 *lhs = dupnode(val);
1261 fprintf(out_fp, "%s[\"%s\"] = ", name, subs->stptr);
1262 valinfo(*lhs, fprintf, out_fp);
1265 if (value == NULL) {
1269 array->type = Node_var_array;
1270 array->var_array = NULL;
1271 array->vname = estrdup(subs->stptr, subs->stlen);
1272 *assoc_lookup(r, subs, FALSE) = array;
1274 } else if (value->type != Node_var_array) {
1275 d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
1290 Func_ptr assign = NULL;
1292 field_num = (long) arg->a_node->numbr;
1293 assert(field_num >= 0);
1296 lhs = get_field(field_num, &assign);
1298 *lhs = dupnode(val);
1301 print_field(field_num);
1311 /* find_item --- find an item in the watch/display list */
1313 static struct list_item *
1314 find_item(struct list_item *list, long num)
1316 struct list_item *d;
1320 for (d = list->next; d != list; d = d->next) {
1321 if (d->number == num)
1327 /* delete_item --- delete an item from the watch/display list */
1330 delete_item(struct list_item *d)
1332 struct commands_item *c;
1335 if (IS_SUBSCRIPT(d)) {
1336 for (i = 0; i < d->num_subs; i++)
1339 } else if (IS_FIELD(d))
1342 if ((d->flags & CUR_IS_ARRAY) == 0)
1343 unref(d->cur_value);
1344 if ((d->flags & OLD_IS_ARRAY) == 0)
1345 unref(d->old_value);
1347 /* delete commands */
1348 for (c = d->commands.next; c != &d->commands; c = c->next) {
1350 delete_commands_item(c->next);
1353 free_context(d->cndn.ctxt, FALSE);
1354 if (d->cndn.expr != NULL)
1355 efree(d->cndn.expr);
1357 d->next->prev = d->prev;
1358 d->prev->next = d->next;
1362 /* add_item --- craete a watch/display item and add it to the list */
1364 static struct list_item *
1365 add_item(struct list_item *list, int type, NODE *symbol, char *pname)
1367 struct list_item *d;
1369 emalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
1370 memset(d, 0, sizeof(struct list_item));
1371 d->commands.next = d->commands.prev = &d->commands;
1373 d->number = ++list->number;
1374 d->sname = symbol->vname;
1375 if (pname != NULL) { /* function param */
1378 d->fcall_count = fcall_count - cur_frame;
1381 if (type == D_field) { /* field number */
1383 d->flags |= FIELD_NUM;
1384 } else if (type == D_subscript) { /* subscript */
1386 d->flags |= SUBSCRIPT;
1387 } else /* array or variable */
1391 d->next = list->next;
1398 /* do_add_item --- add an item to the watch/display list */
1400 static struct list_item *
1401 do_add_item(struct list_item *list, CMDARG *arg)
1403 NODE *symbol = NULL;
1404 char *name, *pname = NULL;
1405 struct list_item *item = NULL;
1407 switch (arg->type) {
1410 name = arg->a_string;
1411 if ((symbol = find_symbol(name, &pname)) == NULL)
1413 if (symbol->type == Node_func) {
1414 d_error(_("`%s' is a function"), name);
1417 if (arg->type == D_subscript && symbol->type != Node_var_array) {
1418 d_error(_("`%s' is not an array\n"), name);
1422 item = add_item(list, arg->type, symbol, pname);
1423 if (item != NULL && arg->type == D_subscript) {
1425 int count = arg->a_count;
1429 emalloc(subs, NODE **, count * sizeof(NODE *), "do_add_item");
1430 for (i = 0; i < count; i++) {
1432 subs[i] = dupnode(arg->a_node);
1433 (void) force_string(subs[i]);
1436 item->num_subs = count;
1441 symbol = dupnode(arg->a_node);
1442 item = add_item(list, D_field, symbol, NULL);
1449 /* watch condition if any */
1450 if (list == &watch_list) {
1452 if (item != NULL && arg != NULL) {
1453 if (parse_condition(D_watch, item->number, arg->a_string) == 0)
1454 arg->a_string = NULL; /* don't let free_cmdarg free it */
1456 fprintf(out_fp, _("watchpoint %d is unconditional\n"), item->number);
1462 /* do_delete_item --- delete a watch/display item from list. */
1465 do_delete_item(struct list_item *list, CMDARG *arg)
1468 while (list->next != list)
1469 delete_item(list->next);
1472 for (; arg != NULL; arg = arg->next) {
1473 struct list_item *d;
1474 if (arg->type == D_range) {
1480 if (j > list->number)
1482 for (; i <= j; i++) {
1483 if ((d = find_item(list, i)) != NULL)
1487 if ((d = find_item(list, arg->a_int)) == NULL) {
1488 /* split into two for easier message translation */
1489 if (list == &display_list)
1490 d_error(_("No display item numbered %ld"),
1493 d_error(_("No watch item numbered %ld"),
1501 /* display --- print an item from the auto-display list */
1504 display(struct list_item *d)
1509 if (IS_PARAM(d) && (d->fcall_count != (fcall_count - cur_frame)))
1512 if (IS_SUBSCRIPT(d)) {
1514 int i = 0, count = d->num_subs;
1515 for (i = 0; i < count; i++) {
1517 r = in_array(symbol, sub);
1519 fprintf(out_fp, _("%d: [\"%s\"] not in array `%s'\n"),
1520 d->number, sub->stptr, d->sname);
1523 if (r->type == Node_var_array) {
1525 if (i == count - 1) /* it's a sub-array */
1526 goto print_sym; /* print # of elements in sub-array */
1529 return; /* FIXME msg and delete item ? */
1530 fprintf(out_fp, "%d: %s[\"%s\"] = ", d->number,
1531 d->sname, sub->stptr);
1532 valinfo(r, fprintf, out_fp);
1535 } else if (IS_FIELD(d)) {
1536 NODE *r = d->symbol;
1537 fprintf(out_fp, "%d: ", d->number);
1538 print_field(r->numbr);
1541 fprintf(out_fp, "%d: %s = ", d->number, d->sname);
1542 print_symbol(symbol, IS_PARAM(d));
1547 /* do_display --- display command */
1550 do_display(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1552 struct list_item *d;
1555 /* display all items */
1556 for (d = display_list.prev; d != &display_list; d = d->prev)
1561 if ((d = do_add_item(&display_list, arg)) != NULL)
1567 /* do_undisplay --- undisplay command */
1570 do_undisplay(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1572 do_delete_item(&display_list, arg);
1576 /* condition_triggered --- test if a condition expression is true */
1579 condition_triggered(struct condition *cndn)
1584 assert(cndn != NULL);
1585 if (cndn->code == NULL)
1588 push_context(cndn->ctxt);
1589 r = execute_code((volatile INSTRUCTION *) cndn->code);
1590 pop_context(); /* switch to prev context */
1591 if (r == NULL) /* fatal error */
1592 return FALSE; /* not triggered */
1595 di = (r->numbr != 0.0);
1603 find_subscript(struct list_item *item, NODE **ptr)
1605 NODE *symbol = item->symbol;
1607 int i = 0, count = item->num_subs;
1610 for (i = 0; i < count; i++) {
1611 sub = item->subs[i];
1612 r = in_array(symbol, sub);
1615 if (r->type == Node_var_array)
1617 else if (i < count - 1)
1624 /* cmp_val --- compare values of watched item, returns TRUE if different; */
1627 cmp_val(struct list_item *w, NODE *old, NODE *new)
1630 * case old new result
1631 * ------------------------------
1632 * 1: NULL ARRAY TRUE
1633 * 2: NULL SCALAR TRUE
1634 * 3: NULL NULL FALSE
1635 * 4: SCALAR SCALAR cmp_node
1636 * 5: SCALAR ARRAY TRUE
1637 * 6: SCALAR NULL TRUE
1638 * 7: ARRAY SCALAR TRUE
1639 * 8: ARRAY ARRAY compare size
1640 * 9: ARRAY NULL TRUE
1643 if (WATCHING_ARRAY(w)) {
1647 if (new->type == Node_val) /* 7 */
1649 /* new->type == Node_var_array */ /* 8 */
1650 if (new->var_array != NULL)
1651 size = new->table_size;
1652 if (w->cur_size == size)
1657 if (! old && ! new) /* 3 */
1659 if ((! old && new) /* 1, 2 */
1660 || (old && ! new)) /* 6 */
1663 if (new->type == Node_var_array) /* 5 */
1665 return cmp_nodes(old, new); /* 4 */
1668 /* watchpoint_triggered --- check if we should stop at this watchpoint;
1669 * update old and current values accordingly.
1673 watchpoint_triggered(struct list_item *w)
1679 if (IS_PARAM(w) && (w->fcall_count != (fcall_count - cur_frame)))
1680 return 0; /* parameter with same name in a different function */
1681 if (! condition_triggered(&w->cndn))
1686 if (IS_SUBSCRIPT(w))
1687 (void) find_subscript(w, &t2);
1688 else if (IS_FIELD(w)) {
1690 field_num = (long) w->symbol->numbr;
1691 t2 = *get_field(field_num, NULL);
1693 switch (symbol->type) {
1695 t2 = symbol->var_value;
1697 case Node_var_array:
1707 if (! cmp_val(w, t1, t2))
1710 /* update old and current values */
1712 if ((w->flags & OLD_IS_ARRAY) == 0)
1713 unref(w->old_value);
1714 w->flags &= ~OLD_IS_ARRAY;
1715 if (WATCHING_ARRAY(w)) { /* 7, 8, 9 */
1716 w->old_size = w->cur_size;
1717 w->flags |= OLD_IS_ARRAY;
1719 w->flags &= ~CUR_IS_ARRAY;
1721 } else if (t2->type == Node_val) {
1722 w->flags &= ~CUR_IS_ARRAY;
1723 w->cur_value = dupnode(t2);
1725 w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
1726 } else if (! t1) { /* 1, 2 */
1729 if (t2->type == Node_val)
1730 w->cur_value = dupnode(t2);
1732 w->flags |= CUR_IS_ARRAY;
1733 w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
1735 } else /* if (t1->type == Node_val) */ { /* 4, 5, 6 */
1736 w->old_value = w->cur_value;
1739 else if (t2->type == Node_var_array) {
1740 w->flags |= CUR_IS_ARRAY;
1741 w->cur_size = (t2->var_array != NULL) ? t2->table_size : 0;
1743 w->cur_value = dupnode(t2);
1749 /* initialize_watch_item --- initialize current value of a watched item */
1752 initialize_watch_item(struct list_item *w)
1755 NODE *symbol = w->symbol;
1757 if (IS_SUBSCRIPT(w)) {
1758 if (find_subscript(w, &r) == -1) {
1759 d_error(_("attempt to use scalar value as array"));
1764 w->cur_value = (NODE *) 0;
1765 else if (r->type == Node_var_array) { /* it's a sub-array */
1766 w->flags |= CUR_IS_ARRAY;
1767 w->cur_size = (r->var_array != NULL) ? r->table_size : 0;
1769 w->cur_value = dupnode(r);
1770 } else if (IS_FIELD(w)) {
1773 field_num = (long) t->numbr;
1774 r = *get_field(field_num, NULL);
1775 w->cur_value = dupnode(r);
1777 if (symbol->type == Node_var_new)
1778 w->cur_value = (NODE *) 0;
1779 else if (symbol->type == Node_var) {
1780 r = symbol->var_value;
1781 w->cur_value = dupnode(r);
1782 } else if (symbol->type == Node_var_array) {
1783 w->flags |= CUR_IS_ARRAY;
1784 w->cur_size = (symbol->var_array != NULL) ? symbol->table_size : 0;
1791 /* do_watch --- watch command */
1794 do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1796 struct list_item *w;
1800 w = do_add_item(&watch_list, arg);
1804 if (initialize_watch_item(w) == -1) {
1809 fprintf(out_fp, "Watchpoint %d: ", w->number);
1812 /* FIXME: common code also in print_watch_item */
1813 if (IS_SUBSCRIPT(w)) {
1814 fprintf(out_fp, "%s", w->sname);
1815 for (i = 0; i < w->num_subs; i++) {
1817 fprintf(out_fp, "[\"%s\"]", sub->stptr);
1819 fprintf(out_fp, "\n");
1820 } else if (IS_FIELD(w))
1821 fprintf(out_fp, "$%ld\n", (long) symbol->numbr);
1823 fprintf(out_fp, "%s\n", w->sname);
1828 /* do_unwatch --- unwatch command */
1831 do_unwatch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1833 do_delete_item(&watch_list, arg);
1837 /* callback from pop_frame in eval.c */
1842 struct list_item *item;
1844 /* delete all out of scope watchpoints */
1845 for (item = watch_list.next; item != &watch_list; item = item->next) {
1846 if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1848 _("Watchpoint %d deleted because parameter is out of scope.\n"),
1851 delete_item(item->next);
1855 /* delete all out of scope display items */
1856 for (item = display_list.next; item != &display_list; item = item->next) {
1857 if (IS_PARAM(item) && (item->fcall_count > fcall_count)) {
1859 _("Display %d deleted because parameter is out of scope.\n"),
1862 delete_item(item->next);
1867 /* print_function --- print function name, parameters, and optionally
1868 * file and line number.
1872 print_function(INSTRUCTION *pc, void *x)
1877 struct pf_data *data = (struct pf_data *) x;
1878 int defn = data->defn;
1879 Func_print print_func = data->print_func;
1880 FILE *fp = data->fp;
1882 func = pc->func_body;
1883 pcount = get_param_count(func);
1884 pnames = get_params(func);
1886 print_func(fp, "%s(", func->lnode->param);
1887 for (i = 0; i < pcount; i++) {
1888 print_func(fp, "%s", pnames[i]);
1890 print_func(fp, ", ");
1892 print_func(fp, ")");
1894 print_func(fp, _(" in file `%s', line %d\n"),
1895 pc->source_file, pc->source_line);
1899 /* print_frame --- print function name, parameters,
1900 * source and line number of where it is
1905 print_frame(NODE *func, char *src, int srcline)
1908 fprintf(out_fp, "main()");
1910 pf_data.print_func = fprintf;
1911 pf_data.fp = out_fp;
1912 pf_data.defn = FALSE;
1913 (void) print_function(func->code_ptr, &pf_data);
1915 fprintf(out_fp, _(" at `%s':%d"), src, srcline);
1918 /* print_numbered_frame --- print a frame given its number */
1921 print_numbered_frame(long num)
1925 assert(prog_running == TRUE);
1926 f = find_frame(num);
1928 fprintf(out_fp, "#%ld\t ", num);
1929 print_frame(f->func_node, source, sourceline);
1931 fprintf(out_fp, _("#%ld\tin "), num);
1932 print_frame(f->func_node, f->vname,
1933 ((INSTRUCTION *) find_frame(num - 1)->reti)->source_line);
1935 fprintf(out_fp, "\n");
1938 /* do_backtrace --- backtrace command */
1941 do_backtrace(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
1944 long last = fcall_count;
1946 CHECK_PROG_RUNNING();
1947 if (arg != NULL && arg->type == D_int) {
1948 long count = arg->a_int;
1950 /* frame_ptr (frame #0), fcall_list[1, 2, ... fcall_count] => total count */
1952 /* toward outermost frame #fcall_count */
1954 if (last > fcall_count)
1957 /* toward innermost frame #0 */
1958 cur = 1 + fcall_count + count;
1964 for (; cur <= last; cur++) {
1965 print_numbered_frame(cur);
1967 if (cur <= fcall_count)
1968 fprintf(out_fp, _("More stack frames follow ...\n"));
1972 /* print_cur_frame_and_sourceline --- print current frame, and
1973 * current source line.
1977 print_cur_frame_and_sourceline()
1983 assert(prog_running == TRUE);
1984 f = find_frame(cur_frame);
1985 if (cur_frame == 0) {
1987 srcline = sourceline;
1989 f = find_frame(cur_frame);
1991 srcline = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
1994 fprintf(out_fp, (cur_frame > 0 ? _("#%ld\tin ") : "#%ld\t "), cur_frame);
1995 print_frame(f->func_node, src, srcline);
1996 fprintf(out_fp, "\n");
1997 print_lines(src, srcline, 1);
1998 last_printed_line = srcline - list_size / 2;
1999 if (last_printed_line < 0)
2000 last_printed_line = 0;
2003 /* do_frame --- frame command */
2006 do_frame(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2008 CHECK_PROG_RUNNING();
2009 if (arg && arg->type == D_int) {
2010 if (arg->a_int < 0 || arg->a_int > fcall_count) {
2011 d_error(_("invalid frame number"));
2014 cur_frame = arg->a_int;
2016 print_cur_frame_and_sourceline();
2020 /* do_up --- up command */
2023 do_up(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2025 CHECK_PROG_RUNNING();
2026 if (arg != NULL && arg->type == D_int)
2027 cur_frame += arg->a_int;
2032 else if (cur_frame > fcall_count)
2033 cur_frame = fcall_count;
2034 print_cur_frame_and_sourceline();
2038 /* do_down --- down command */
2041 do_down(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2043 CHECK_PROG_RUNNING();
2044 if (arg != NULL && arg->type == D_int)
2045 cur_frame -= arg->a_int;
2050 else if (cur_frame > fcall_count)
2051 cur_frame = fcall_count;
2052 print_cur_frame_and_sourceline();
2056 /* find_rule --- find a rule or function in file 'src' containing
2057 * source line 'lineno'
2060 static INSTRUCTION *
2061 find_rule(char *src, long lineno)
2066 for (rp = rule_list->nexti; rp != NULL; rp = rp->nexti) {
2067 if ((rp - 1)->source_file == src
2068 && lineno >= (rp + 1)->first_line
2069 && lineno <= (rp + 1)->last_line)
2075 /* mk_breakpoint --- create a breakpoint instruction and the corresponding
2076 * breakpoint structure.
2079 static INSTRUCTION *
2080 mk_breakpoint(char *src, int srcline)
2085 bp = bcalloc(Op_breakpoint, 1, srcline);
2086 emalloc(b, BREAKPOINT *, sizeof(BREAKPOINT), "mk_breakpoint");
2087 memset(&b->cndn, 0, sizeof(struct condition));
2088 b->commands.next = b->commands.prev = &b->commands;
2092 b->number = ++watch_list.number; /* breakpoints and watchpoints use same counter */
2093 b->ignore_count = 0;
2095 b->flags = BP_ENABLE;
2100 /* prepend to list */
2101 b->next = breakpoints.next;
2102 b->prev = &breakpoints;
2103 breakpoints.next = b;
2108 /* delete_breakpoint --- delete a breakpoint structure and
2109 * disable the breakpoint instruction.
2113 delete_breakpoint(BREAKPOINT *b)
2115 INSTRUCTION *pc = b->bpi;
2116 struct commands_item *c;
2118 /* N.B.: easiest thing to do is to turn Op_breakpoint into a no-op;
2119 * deleteing the instruction is not that simple,
2120 * since could have reference to it somewhere else (e.g. cur_pc).
2123 pc->opcode = Op_no_op;
2124 pc->source_line = 0;
2125 pc->break_pt = NULL;
2127 /* delete commands */
2128 for (c = b->commands.next; c != &b->commands; c = c->next) {
2130 delete_commands_item(c->next);
2133 free_context(b->cndn.ctxt, FALSE);
2134 if (b->cndn.expr != NULL)
2135 efree(b->cndn.expr);
2137 /* remove from list */
2138 b->next->prev = b->prev;
2139 b->prev->next = b->next;
2143 /* find_breakpoint --- find the breakpoint structure from a breakpoint number */
2146 find_breakpoint(long num)
2153 for (b = breakpoints.next; b != &breakpoints; b = b->next) {
2154 if (b->number == num)
2160 /* add_breakpoint --- add a breakpoint instruction between PREVP and IP */
2163 add_breakpoint(INSTRUCTION *prevp, INSTRUCTION *ip, char *src, int silent)
2167 int lineno = ip->source_line;
2169 /* add new breakpoint instruction at the end of
2170 * already set breakpoints at this line number.
2173 while (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2177 * This is more verbose that it might otherwise be,
2178 * in order to provide easily translatable strings.
2180 if (b->flags & BP_ENABLE) {
2181 if (b->flags & BP_IGNORE)
2183 _("Note: breakpoint %d (enabled, ignore next %ld hits), also set at %s:%d"),
2190 _("Note: breakpoint %d (enabled), also set at %s:%d"),
2195 if (b->flags & BP_IGNORE)
2197 _("Note: breakpoint %d (disabled, ignore next %ld hits), also set at %s:%d"),
2204 _("Note: breakpoint %d (disabled), also set at %s:%d"),
2214 assert(ip->source_line == lineno);
2216 bp = mk_breakpoint(src, lineno);
2221 fprintf(out_fp, _("Breakpoint %d set at file `%s', line %d\n"),
2222 b->number, src, lineno);
2226 /* set_breakpoint_at --- set a breakpoint at given line number*/
2229 set_breakpoint_at(INSTRUCTION *rp, int lineno, int silent)
2231 INSTRUCTION *ip, *prevp;
2233 for (prevp = rp, ip = rp->nexti; ip; prevp = ip, ip = ip->nexti) {
2234 if (ip->opcode == Op_K_case) {
2235 INSTRUCTION *i1, *i2;
2237 /* Special case: the code line numbers for a switch do not form
2238 * a monotonically increasing sequence. Check if the line # is between
2239 * the first and last statements of the case block before continuing
2242 for (i2 = ip->stmt_start, i1 = i2->nexti; i2 != ip->stmt_end;
2243 i2 = i1, i1 = i1->nexti) {
2244 if (i1->source_line >= lineno)
2245 return add_breakpoint(i2, i1, rp->source_file, silent);
2246 if (i1 == ip->stmt_end)
2251 if (ip->source_line >= lineno)
2252 return add_breakpoint(prevp, ip, rp->source_file, silent);
2253 if (ip == (rp + 1)->lasti)
2259 /* set_breakpoint_next --- set a breakpoint at the next instruction */
2262 set_breakpoint_next(INSTRUCTION *rp, INSTRUCTION *ip)
2266 if (ip == (rp + 1)->lasti)
2269 if (ip->opcode != Op_breakpoint)
2271 for (; ip; prevp = ip, ip = ip->nexti) {
2272 if (ip->source_line > 0)
2273 return add_breakpoint(prevp, ip, rp->source_file, FALSE);
2274 if (ip == (rp + 1)->lasti)
2280 /* set_breakpoint --- set a breakpoint */
2283 set_breakpoint(CMDARG *arg, int temporary)
2286 BREAKPOINT *b = NULL;
2287 INSTRUCTION *rp, *ip;
2289 SRCFILE *s = cur_srcfile;
2290 char *src = cur_srcfile->src;
2294 * (From GDB Documentation):
2296 * When called without any arguments, break sets a breakpoint at the next instruction
2297 * to be executed in the selected stack frame (see section Examining the Stack).
2298 * In any selected frame but the innermost, this makes your program stop as soon
2299 * as control returns to that frame. This is similar to the effect of a finish command
2300 * in the frame inside the selected frame--except that finish does not leave an
2301 * active breakpoint. If you use break without an argument in the innermost frame,
2302 * GDB stops the next time it reaches the current location; this may be useful
2304 * GDB normally ignores breakpoints when it resumes execution, until at least
2305 * one instruction has been executed. If it did not do this,
2306 * you would be unable to proceed past a breakpoint without first disabling the
2307 * breakpoint. This rule applies whether or not the breakpoint already existed
2308 * when your program stopped.
2310 CHECK_PROG_RUNNING();
2311 if (cur_frame == 0) {
2316 f = find_frame(cur_frame);
2318 ip = (INSTRUCTION *) find_frame(cur_frame - 1)->reti; /* Op_func_call */
2320 rp = find_rule(src, ip->source_line);
2322 if ((b = set_breakpoint_next(rp, ip)) == NULL)
2323 fprintf(out_fp, _("Can't set breakpoint in file `%s'\n"), src);
2325 if (cur_frame == 0) { /* stop next time */
2326 b->flags |= BP_IGNORE;
2327 b->ignore_count = 1;
2330 b->flags |= BP_TEMP;
2337 switch (arg->type) {
2338 case D_string: /* break filename:lineno|function */
2339 s = source_find(arg->a_string);
2341 if (s == NULL || arg == NULL
2342 || (arg->type != D_int && arg->type != D_func))
2345 if (arg->type == D_func) /* break filename:function */
2349 case D_int: /* break lineno */
2350 lineno = (int) arg->a_int;
2351 if (lineno <= 0 || lineno > s->srclines)
2352 d_error(_("line number %d in file `%s' out of range"), lineno, src);
2354 rp = find_rule(src, lineno);
2356 fprintf(out_fp, _("Can't find rule!!!\n"));
2357 if (rp == NULL || (b = set_breakpoint_at(rp, lineno, FALSE)) == NULL)
2358 fprintf(out_fp, _("Can't set breakpoint at `%s':%d\n"),
2360 if (b != NULL && temporary)
2361 b->flags |= BP_TEMP;
2365 case D_func: /* break function */
2368 rp = func->code_ptr;
2369 if ((b = set_breakpoint_at(rp, rp->source_line, FALSE)) == NULL)
2370 fprintf(out_fp, _("Can't set breakpoint in function `%s'\n"),
2371 func->lnode->param);
2373 b->flags |= BP_TEMP;
2374 lineno = b->bpi->source_line;
2380 /* condition if any */
2382 if (b != NULL && arg != NULL) {
2383 if (parse_condition(D_break, b->number, arg->a_string) == 0)
2384 arg->a_string = NULL; /* don't let free_cmdarg free it */
2386 fprintf(out_fp, _("breakpoint %d set at file `%s', line %d is unconditional\n"),
2387 b->number, src, lineno);
2393 /* breakpoint_triggered --- check if we should stop at this breakpoint */
2396 breakpoint_triggered(BREAKPOINT *b)
2398 if ((b->flags & BP_ENABLE) == 0)
2400 if ((b->flags & BP_IGNORE) != 0) {
2401 if (--b->ignore_count <= 0)
2402 b->flags &= ~BP_IGNORE;
2406 if (! condition_triggered(&b->cndn))
2410 if (b->flags & BP_ENABLE_ONCE) {
2411 b->flags &= ~BP_ENABLE_ONCE;
2412 b->flags &= ~BP_ENABLE;
2417 /* do_breakpoint --- break command */
2420 do_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2422 return set_breakpoint(arg, FALSE);
2425 /* do_tmp_breakpoint --- tbreak command */
2428 do_tmp_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2430 return set_breakpoint(arg, TRUE);
2433 /* do_clear --- clear command */
2436 do_clear(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2440 INSTRUCTION *rp, *ip;
2442 SRCFILE *s = cur_srcfile;
2443 char *src = cur_srcfile->src;
2444 int bp_found = FALSE;
2446 if (arg == NULL) { /* clear */
2447 CHECK_PROG_RUNNING();
2448 if (cur_frame == 0) {
2449 lineno = sourceline;
2453 f = find_frame(cur_frame);
2455 lineno = ((INSTRUCTION *) find_frame(cur_frame - 1)->reti)->source_line;
2460 switch (arg->type) {
2461 case D_string: /* clear filename:lineno|function */
2462 s = source_find(arg->a_string);
2464 if (s == NULL || arg == NULL ||
2465 (arg->type != D_int && arg->type != D_func))
2468 if (arg->type == D_func)
2472 case D_int: /* clear lineno */
2473 lineno = (int) arg->a_int;
2474 if (lineno <= 0 || lineno > s->srclines) {
2475 d_error(_("line number %d in file `%s' out of range"), lineno, src);
2480 case D_func: /* clear function */
2483 rp = func->code_ptr;
2484 for (ip = rp->nexti; ip; ip = ip->nexti) {
2485 if (ip->source_line <= 0)
2487 if (ip->opcode != Op_breakpoint)
2490 if (++bp_found == 1)
2491 fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2493 fprintf(out_fp, ", %d", b->number);
2494 delete_breakpoint(b);
2497 fprintf(out_fp, _("No breakpoint(s) at entry to function `%s'\n"),
2498 func->lnode->param);
2500 fprintf(out_fp, "\n");
2507 rp = find_rule(src, lineno);
2509 for (ip = rp->nexti; ip; ip = ip->nexti) {
2510 if (ip->opcode == Op_breakpoint && ip->source_line == lineno) {
2512 if (++bp_found == 1)
2513 fprintf(out_fp, _("Deleted breakpoint %d"), b->number);
2515 fprintf(out_fp, ", %d", b->number);
2516 delete_breakpoint(b);
2518 if (ip == (rp + 1)->lasti)
2524 fprintf(out_fp, _("No breakpoint at file `%s', line #%d\n"),
2527 fprintf(out_fp, "\n");
2531 /* enable_breakpoint --- enable a breakpoint and set its disposition */
2534 enable_breakpoint(BREAKPOINT *b, short disp)
2536 b->flags &= ~(BP_ENABLE_ONCE|BP_TEMP);
2537 b->flags |= BP_ENABLE;
2542 /* do_enable_breakpoint --- enable command */
2545 do_enable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2550 if (arg != NULL && arg->type == D_argument) {
2551 if (arg->a_argument == A_DEL) /* del */
2554 disp = BP_ENABLE_ONCE;
2558 if (arg == NULL) { /* enable [once|del] */
2559 for (b = breakpoints.next; b != &breakpoints; b = b->next)
2560 enable_breakpoint(b, disp);
2563 for (; arg != NULL; arg = arg->next) {
2564 if (arg->type == D_range) {
2570 if (j > breakpoints.number)
2571 j = breakpoints.number;
2572 for (; i <= j; i++) {
2573 if ((b = find_breakpoint(i)) != NULL)
2574 enable_breakpoint(b, disp);
2577 assert(arg->type == D_int);
2578 if ((b = find_breakpoint(arg->a_int)) == NULL)
2579 d_error(_("invalid breakpoint number"));
2581 enable_breakpoint(b, disp);
2587 /* do_delete_breakpoint --- delete command */
2590 do_delete_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2593 int delete_all = TRUE;
2594 delete_all = prompt_yes_no(
2595 _("Delete all breakpoints? (y or n) "),
2596 _("y")[0], TRUE, out_fp);
2599 while (breakpoints.next != &breakpoints)
2600 delete_breakpoint(breakpoints.next);
2604 for (; arg != NULL; arg = arg->next) {
2606 if (arg->type == D_range) {
2612 if (j > breakpoints.number)
2613 j = breakpoints.number;
2614 for (; i <= j; i++) {
2615 if ((b = find_breakpoint(i)) != NULL)
2616 delete_breakpoint(b);
2619 if ((b = find_breakpoint(arg->a_int)) == NULL)
2620 d_error(_("invalid breakpoint number"));
2622 delete_breakpoint(b);
2628 /* do_ignore_breakpoint --- ignore command */
2631 do_ignore_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2635 if (arg == NULL || arg->type != D_int
2636 || arg->next == NULL || arg->next->type != D_int)
2639 if ((b = find_breakpoint(arg->a_int)) == NULL)
2640 d_error(_("invalid breakpoint number"));
2642 b->ignore_count = arg->next->a_int;
2643 if (b->ignore_count > 0) {
2644 b->flags |= BP_IGNORE;
2645 fprintf(out_fp, _("Will ignore next %ld crossing(s) of breakpoint %d.\n"),
2646 b->ignore_count, b->number);
2648 b->flags &= ~BP_IGNORE;
2649 fprintf(out_fp, _("Will stop next time breakpoint %d is reached.\n"),
2656 /* do_disable_breakpoint --- disable command */
2659 do_disable_breakpoint(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2665 for (b = breakpoints.next; b != &breakpoints; b = b->next)
2666 b->flags &= ~BP_ENABLE;
2669 for (; arg != NULL; arg = arg->next) {
2670 if (arg->type == D_range) {
2676 if (j > breakpoints.number)
2677 j = breakpoints.number;
2679 if ((b = find_breakpoint(i)) != NULL)
2680 b->flags &= ~BP_ENABLE;
2682 if ((b = find_breakpoint(arg->a_int)) == NULL)
2683 d_error(_("invalid breakpoint number"));
2685 b->flags &= ~BP_ENABLE;
2691 #ifdef HAVE_LIBREADLINE
2693 /* get_parmlist --- list of function params in current context */
2702 func = find_frame(cur_frame)->func_node;
2703 if (func == NULL) /* in main */
2705 return func->parmlist;
2708 /* initialize_readline --- initialize readline */
2711 initialize_readline()
2713 /* tell readline which stream to use for output,
2714 * default input stream is stdin.
2716 rl_outstream = out_fp;
2718 /* allow conditional parsing of the ~/.inputrc file. */
2719 rl_readline_name = "gawk";
2721 /* our completion function. */
2722 rl_attempted_completion_function = command_completion;
2724 read_a_line = readline;
2727 #define initialize_readline() /* nothing */
2731 /* interpret --- debugger entry point */
2734 interpret(INSTRUCTION *pc)
2738 input_fd = fileno(stdin);
2740 if (os_isatty(input_fd))
2741 input_from_tty = TRUE;
2742 if (input_fd == 0 && input_from_tty)
2743 initialize_readline();
2746 read_a_line = g_readline;
2748 push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
2750 setbuf(out_fp, (char *) NULL);
2751 for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles;
2752 cur_srcfile = cur_srcfile->prev) {
2753 if (cur_srcfile->stype == SRC_FILE
2754 || cur_srcfile->stype == SRC_INC)
2758 if (cur_srcfile == srcfiles) {
2759 fprintf(out_fp, _("Can only debug programs provided with the `-f' option.\n"));
2763 dgawk_Prompt = estrdup(DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
2764 dPrompt = dgawk_Prompt;
2766 memset(&stop, 0, sizeof(stop));
2767 stop.command = D_illegal;
2769 if ((run = getenv("DGAWK_RESTART")) != NULL) {
2770 /* We are restarting; restore state (breakpoints, history etc.)
2771 * passed as environment variables and optionally execute the run command.
2775 unserialize(DISPLAY);
2776 unserialize(HISTORY);
2777 unserialize(OPTION);
2778 unsetenv("DGAWK_RESTART");
2779 fprintf(out_fp, "Restarting ...\n");
2781 (void) do_run(NULL, 0);
2783 } else if (command_file != NULL) {
2784 /* run commands from a file (--command=file or -R file) */
2786 fd = open_readfd(command_file);
2787 if (fd == INVALID_HANDLE) {
2788 fprintf(stderr, _("can't open source file `%s' for reading (%s)"),
2789 command_file, strerror(errno));
2792 push_cmd_src(fd, FALSE, g_readline, close, 0, EXIT_FAILURE);
2793 cmd_src->str = estrdup(command_file, strlen(command_file));
2798 #ifdef HAVE_LIBREADLINE
2799 (void) read_history(history_file);
2800 sess_history_base = history_length;
2803 /* read saved options */
2804 fd = open_readfd(options_file);
2805 if (fd > INVALID_HANDLE)
2806 push_cmd_src(fd, FALSE, g_readline, close, 0, EXIT_SUCCESS);
2809 /* start the command interpreter */
2810 read_command(); /* yyparse */
2811 return EXIT_SUCCESS;
2815 /* N.B.: ignore breakpoints and watchpoints for return command */
2817 /* check_watchpoint --- check if any watchpoint triggered */
2822 struct list_item *w;
2824 if (stop.command == D_return)
2826 for (w = watch_list.prev; w != &watch_list; w = w->prev) {
2827 int wnum = watchpoint_triggered(w);
2829 stop.watch_point = wnum;
2830 stop.print_frame = TRUE;
2837 /* check_breakpoint --- check if breakpoint triggered */
2840 check_breakpoint(INSTRUCTION **pi)
2845 if (stop.command == D_return)
2847 if (pc->opcode == Op_breakpoint) {
2849 *pi = pc->nexti; /* skip past the breakpoint instruction;
2850 * interpreter doesn't process Op_breakpoint.
2852 bnum = breakpoint_triggered(pc->break_pt);
2854 stop.break_point = bnum;
2855 stop.print_frame = TRUE;
2862 /* restart --- restart the debugger */
2867 /* save state in the environment after serialization */
2874 /* tell the new process to restore state from the environment */
2875 setenv("DGAWK_RESTART", (run ? "TRUE" : "FALSE"), 1);
2877 /* close all open files */
2880 /* start a new process replacing the current process */
2881 execvp(d_argv[0], d_argv);
2883 /* execvp failed !!! */
2884 fprintf(out_fp, _("Failed to restart debugger"));
2888 /* do_run --- run command */
2891 do_run(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2894 if (! input_from_tty)
2895 need_restart = TRUE; /* handled later */
2897 need_restart = prompt_yes_no(
2898 _("Program already running. Restart from beginning (y/n)? "),
2899 _("y")[0], FALSE, out_fp);
2901 if (! need_restart) {
2902 fprintf(out_fp, _("Program not restarted\n"));
2909 /* avoid endless cycles of restarting */
2910 if (command_file != NULL) {
2911 /* input_from_tty = FALSE */
2912 fprintf(stderr, _("error: cannot restart, operation not allowed\n"));
2916 if (cmd_src->cmd == D_source) {
2917 /* input_from_tty = FALSE */
2918 fprintf(out_fp, _("error (%s): cannot restart, ignoring rest of the commands\n"), cmd_src->str);
2923 restart(TRUE); /* does not return */
2926 fprintf(out_fp, _("Starting program: \n"));
2928 prog_running = TRUE;
2929 fatal_tag_valid = TRUE;
2930 if (setjmp(fatal_tag) == 0)
2931 (void) r_interpret(code_block);
2933 fatal_tag_valid = FALSE;
2934 prog_running = FALSE;
2935 fprintf(out_fp, _("Program exited %s with exit value: %d\n"),
2936 (! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
2939 need_restart = TRUE;
2943 /* do_quit --- quit command */
2946 do_quit(CMDARG *arg ATTRIBUTE_UNUSED, int cmd ATTRIBUTE_UNUSED)
2948 int terminate = TRUE;
2950 terminate = prompt_yes_no(
2951 _("The program is running. Exit anyway (y/n)? "),
2952 _("y")[0], TRUE, out_fp);
2955 do_trace = FALSE; /* don't save 'trace on' */
2957 #ifdef HAVE_LIBREADLINE
2958 if (do_save_history && input_from_tty) {
2960 ret = write_history(history_file);
2961 if (ret == 0 && history_length > history_size)
2962 (void) history_truncate_file(history_file, history_size);
2965 if (do_save_options && input_from_tty)
2966 save_options(options_file);
2973 /* do_continue --- continue command */
2976 do_continue(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
2980 CHECK_PROG_RUNNING();
2981 if (! arg || arg->type != D_int)
2984 /* arg is breakpoint ignore count if stopped at a breakpoint */
2985 if (! stop.break_point) {
2986 fprintf(out_fp, _("Not stopped at any breakpoint; argument ignored.\n"));
2989 b = find_breakpoint(stop.break_point);
2991 d_error(_("invalid breakpoint number %d."), stop.break_point);
2994 b->flags |= BP_IGNORE;
2995 b->ignore_count = arg->a_int;
2996 fprintf(out_fp, _("Will ignore next %ld crossings of breakpoint %d.\n"),
2997 b->ignore_count, stop.break_point);
3001 /* next_step --- common code for next and step commands */
3004 next_step(CMDARG *arg, int cmd)
3006 CHECK_PROG_RUNNING();
3007 if (arg != NULL && arg->type == D_int)
3008 stop.repeat_count = arg->a_int;
3010 stop.repeat_count = 1;
3015 /* check_step --- process step command, return TRUE if stopping */
3018 check_step(INSTRUCTION **pi)
3020 if (fcall_count != stop.fcall_count) {
3021 stop.fcall_count = fcall_count;
3022 stop.sourceline = sourceline;
3023 stop.source = source;
3024 stop.print_frame = TRUE;
3025 return (--stop.repeat_count == 0);
3028 if (source != stop.source) {
3029 stop.source = source;
3030 stop.sourceline = sourceline;
3031 return (--stop.repeat_count == 0);
3034 if (sourceline != stop.sourceline) {
3035 stop.sourceline = sourceline;
3036 return (--stop.repeat_count == 0);
3041 /* do_step -- process step command, return TRUE if stopping */
3044 do_step(CMDARG *arg, int cmd)
3047 ret = next_step(arg, cmd);
3049 stop.fcall_count = fcall_count;
3050 stop.source = source;
3051 stop.sourceline = sourceline;
3052 stop.check_func = check_step;
3057 /* do_stepi -- process stepi command, return TRUE if stopping */
3060 check_stepi(INSTRUCTION **pi)
3062 return (--stop.repeat_count == 0);
3065 /* do_stepi -- stepi command */
3068 do_stepi(CMDARG *arg, int cmd)
3071 ret = next_step(arg, cmd);
3073 stop.check_func = check_stepi;
3078 /* check_next -- process next command returning TRUE if stopping */
3081 check_next(INSTRUCTION **pi)
3083 /* make sure not to step inside function calls */
3085 if (fcall_count < stop.fcall_count) {
3086 stop.fcall_count = fcall_count;
3087 stop.sourceline = sourceline;
3088 stop.source = source;
3089 stop.print_frame = TRUE;
3090 return (--stop.repeat_count == 0);
3093 if (fcall_count == stop.fcall_count) {
3094 if (source != stop.source) {
3095 stop.source = source;
3096 stop.sourceline = sourceline;
3097 return (--stop.repeat_count == 0);
3099 if (sourceline != stop.sourceline) {
3100 stop.sourceline = sourceline;
3101 return (--stop.repeat_count == 0);
3107 if (fcall_count > stop.fcall_count) {
3108 stop.source = source;
3109 stop.sourceline = sourceline;
3116 /* do_next -- next command */
3119 do_next(CMDARG *arg, int cmd)
3123 ret = next_step(arg, cmd);
3125 stop.source = source;
3126 stop.sourceline = sourceline;
3127 stop.fcall_count = fcall_count;
3128 stop.check_func = check_next;
3133 /* check_nexti --- process nexti command, returns TRUE if stopping */
3136 check_nexti(INSTRUCTION **pi)
3139 /* make sure not to step inside function calls */
3141 if (fcall_count < stop.fcall_count) {
3142 stop.print_frame = TRUE;
3143 stop.fcall_count = fcall_count;
3145 return (fcall_count == stop.fcall_count
3146 && --stop.repeat_count == 0);
3149 /* do_nexti -- nexti command */
3152 do_nexti(CMDARG *arg, int cmd)
3156 ret = next_step(arg, cmd);
3158 stop.fcall_count = fcall_count;
3159 stop.check_func = check_nexti;
3164 /* check_finish --- process finish command, returns TRUE if stopping */
3167 check_finish(INSTRUCTION **pi)
3169 if (fcall_count == stop.fcall_count) {
3170 stop.print_frame = TRUE;
3176 /* do_finish --- finish command */
3179 do_finish(CMDARG *arg ATTRIBUTE_UNUSED, int cmd)
3181 CHECK_PROG_RUNNING();
3182 if (cur_frame == fcall_count) {
3184 _("'finish' not meaningful in the outermost frame main()\n"));
3187 stop.fcall_count = fcall_count - cur_frame - 1;
3188 assert(stop.fcall_count >= 0);
3189 fprintf(out_fp, _("Run till return from "));
3190 print_numbered_frame(cur_frame);
3191 stop.check_func = check_finish;
3193 stop.print_ret = TRUE;
3197 /* check_return --- process return, returns TRUE if stopping */
3200 check_return(INSTRUCTION **pi)
3202 assert(fcall_count >= stop.fcall_count);
3204 if (fcall_count == stop.fcall_count) {
3205 stop.print_frame = TRUE;
3209 if (fcall_count > stop.fcall_count) { /* innermost frame just returned */
3210 /* force this one to return too */
3213 func = find_frame(cur_frame)->func_node;
3214 assert(func != NULL);
3215 *pi = (func->code_ptr + 1)->lasti;
3216 /* assert((*pi)->opcode == Op_K_return); */
3222 /* do_return --- return command */
3225 do_return(CMDARG *arg, int cmd)
3229 CHECK_PROG_RUNNING();
3230 func = find_frame(cur_frame)->func_node;
3232 fprintf(out_fp, _("'return' not meaningful in the outermost frame main()\n"));
3236 stop.fcall_count = fcall_count - cur_frame - 1;
3237 assert(stop.fcall_count >= 0);
3238 stop.pc = (func->code_ptr + 1)->lasti;
3239 assert(stop.pc->opcode == Op_K_return);
3242 stop.check_func = check_return;
3244 if (arg != NULL && arg->type == D_node) { /* optional return value */
3246 n = dupnode(arg->a_node);
3254 /* check_until --- process until, returns TRUE if stopping */
3257 check_until(INSTRUCTION **pi)
3259 if (fcall_count < stop.fcall_count) { /* current stack frame returned */
3260 stop.print_frame = TRUE;
3262 } else if (fcall_count == stop.fcall_count) {
3263 if (stop.pc && *pi == stop.pc) /* until location */
3265 if (stop.sourceline > 0 /* until */
3266 && source == stop.source
3267 && sourceline > stop.sourceline)
3273 /* do_until --- until command */
3276 do_until(CMDARG *arg, int cmd)
3278 SRCFILE *s = cur_srcfile;
3279 char *src = cur_srcfile->src;
3281 INSTRUCTION *rp, *ip;
3284 CHECK_PROG_RUNNING();
3286 stop.sourceline = 0;
3288 if (arg == NULL) { /* until without argument */
3290 /* GDB doc.: continue running until a source line past the current line,
3291 * in the current stack frame, is reached. Is used to avoid single
3292 * stepping through a loop more than once. ...
3293 * This means that when you reach the end of a loop after single
3294 * stepping though it, until makes your program continue execution
3295 * until it exits the loop. In contrast, a next command at the end
3296 * of a loop simply steps back to the beginning of the loop, which
3297 * forces you to step through the next iteration.
3300 stop.source = source;
3301 stop.sourceline = sourceline;
3302 stop.fcall_count = fcall_count - cur_frame;
3303 stop.check_func = check_until;
3308 /* GDB: until location - continue running program until
3309 * either the specified location is reached, or the
3310 * current stack frame returns.
3313 switch (arg->type) {
3314 case D_string: /* until filename : lineno|function */
3315 s = source_find(arg->a_string);
3317 if (s == NULL || arg == NULL
3318 || (arg->type != D_int && arg->type != D_func))
3321 if (arg->type == D_func)
3325 case D_int: /* until lineno */
3326 lineno = arg->a_int;
3327 if (lineno <= 0 || lineno > s->srclines) {
3328 d_error(_("line number %d in file `%s' out of range"),
3334 case D_func: /* until function */
3337 rp = func->code_ptr;
3338 for (ip = rp->nexti; ip; ip = ip->nexti) {
3339 if (ip->opcode != Op_breakpoint && ip->source_line > 0) {
3341 stop.fcall_count = fcall_count - cur_frame;
3342 stop.check_func = check_until;
3347 fprintf(out_fp, _("Can't find specified location in function `%s'\n"),
3348 func->lnode->param);
3354 if ((rp = find_rule(src, lineno)) == NULL) {
3355 d_error(_("invalid source line %d in file `%s'"), lineno, src);
3359 for (ip = rp->nexti; ip; ip = ip->nexti) {
3360 if (ip->opcode != Op_breakpoint && ip->source_line >= lineno) {
3362 stop.fcall_count = fcall_count - cur_frame;
3363 stop.check_func = check_until;
3367 if (ip == (rp + 1)->lasti)
3370 fprintf(out_fp, _("Can't find specified location %d in file `%s'\n"),
3375 /* print_watch_item --- print watched item name, old and current values */
3378 print_watch_item(struct list_item *w)
3384 if (IS_SUBSCRIPT(w)) {
3385 fprintf(out_fp, "%s", w->sname);
3386 for (i = 0; i < w->num_subs; i++) {
3388 fprintf(out_fp, "[\"%s\"]", sub->stptr);
3390 fprintf(out_fp, "\n");
3391 } else if (IS_FIELD(w))
3392 fprintf(out_fp, "$%ld\n", (long) symbol->numbr);
3394 fprintf(out_fp, "%s\n", w->sname);
3397 #define print_value(X, S, V) \
3399 fprintf(out_fp, "array, %ld elements\n", w->S); \
3401 fprintf(out_fp, IS_SUBSCRIPT(w) ? \
3402 _("element not in array\n") : _("untyped variable\n")); \
3404 valinfo(w->V, fprintf, out_fp);
3406 fprintf(out_fp, " Old value: ");
3407 print_value((w->flags & OLD_IS_ARRAY), old_size, old_value);
3408 fprintf(out_fp, " New value: ");
3409 print_value((w->flags & CUR_IS_ARRAY), cur_size, cur_value);
3414 /* next_command --- (optionally) print stoppage location and reason;
3415 * also fetch next debug command from the user.
3421 static int last_rule = 0;
3422 struct list_item *d = NULL, *w = NULL;
3423 BREAKPOINT *b = NULL;
3426 if (source == NULL) {
3427 stop.command = D_illegal;
3428 stop.check_func = NULL;
3432 if (stop.break_point) {
3433 b = find_breakpoint(stop.break_point);
3437 } else if (stop.watch_point) {
3438 w = find_item(&watch_list, stop.watch_point);
3443 if (cur_rule != last_rule) {
3444 fprintf(out_fp, _("Stopping in %s ...\n"), ruletab[cur_rule]);
3445 last_rule = cur_rule;
3449 fprintf(out_fp, "Breakpoint %d, ", b->number);
3450 else if (w != NULL) {
3451 fprintf(out_fp, "Watchpoint %d: ", w->number);
3452 print_watch_item(w);
3456 if (stop.print_frame) {
3457 print_frame(frame_ptr->func_node, source, sourceline);
3458 fprintf(out_fp, "\n");
3459 stop.print_frame = FALSE;
3462 (void) print_lines(source, sourceline, 1);
3464 /* automatic display of variables */
3465 for (d = display_list.prev; d != &display_list; d = d->prev)
3469 /* update last_printed_line, so that output of 'list' is
3470 * centered around current sourceline
3473 last_printed_line = sourceline - list_size / 2;
3474 if (last_printed_line < 0)
3475 last_printed_line = 0;
3477 /* update current source file */
3478 s = source_find(source);
3479 if (cur_srcfile != s) {
3480 if (cur_srcfile->fd != INVALID_HANDLE) {
3481 close(cur_srcfile->fd);
3482 cur_srcfile->fd = INVALID_HANDLE;
3487 stop.command = D_illegal;
3488 stop.check_func = NULL;
3492 ret = execute_commands(&b->commands);
3493 if ((b->flags & BP_TEMP) != 0)
3494 delete_breakpoint(b);
3495 if (ret) /* resume execution */
3497 } else if (w != NULL && execute_commands(&w->commands))
3500 read_command(); /* zzparse */
3503 /* post_execute --- post_hook in the interpreter */
3506 post_execute(INSTRUCTION *pc)
3508 if (! in_main_context())
3511 switch (pc->opcode) {
3515 if (stop.command == D_finish) {
3516 /* cancel finish command */
3517 stop.print_ret = FALSE;
3518 stop.print_frame = FALSE;
3519 stop.command = D_illegal;
3520 stop.check_func = NULL;
3521 fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"),
3522 op2str(pc->opcode));
3523 } else if (stop.command == D_until) {
3524 /* cancel until command */
3525 stop.print_frame = FALSE;
3526 stop.command = D_illegal;
3527 stop.check_func = NULL;
3528 fprintf(out_fp, _("'until' not meaningful with non-local jump '%s'\n"),
3529 op2str(pc->opcode));
3534 if (stop.command == D_finish
3535 && fcall_count == stop.fcall_count
3539 /* print the returned value before it disappears. */
3541 fprintf(out_fp, "Returned value = ");
3542 valinfo(r, fprintf, out_fp);
3543 stop.print_ret = FALSE;
3556 /* pre_execute --- pre_hook, called by the interpreter before execution;
3557 * checks if execution needs to be suspended and control
3558 * transferred to the debugger.
3562 pre_execute(INSTRUCTION **pi)
3564 static int cant_stop = FALSE;
3567 if (! in_main_context())
3568 return pre_execute_code(pi);
3571 stop.break_point = 0;
3572 stop.watch_point = 0;
3576 && cur_pc->opcode != Op_breakpoint
3577 && stop.command != D_return
3579 print_instruction(cur_pc, fprintf, out_fp, FALSE);
3581 /* N.B.: For Op_field_spec_lhs must execute instructions upto Op_field_assign
3582 * as a group before stopping. Otherwise, watch/print of field variables
3583 * yield surprising results. Ditto for Op_push_lhs for special variables
3584 * (upto Op_var_assign, the set_FOO routine).
3587 switch (cur_pc->opcode) {
3588 case Op_field_spec_lhs:
3592 case Op_field_assign:
3594 return TRUE; /* may stop at next instruction */
3598 if (m->type == Node_var && m->var_assign)
3602 case Op_arrayfor_incr: /* can have special var as array variable !!! */
3603 m = cur_pc->array_var;
3604 if (m->type == Node_var && m->var_assign)
3610 return TRUE; /* may stop at next instruction */
3613 cur_rule = cur_pc->in_rule;
3622 break; /* processed later in check_breakpoint() */
3625 if (cur_pc->source_line <= 0)
3633 assert(sourceline > 0);
3635 if (check_breakpoint(pi)
3636 || check_watchpoint()
3637 || (stop.check_func && stop.check_func(pi))) {
3638 next_command(); /* return to debugger interface */
3639 if (stop.command == D_return)
3640 *pi = stop.pc; /* jump to this instruction */
3643 /* if cur_pc == *pi, interpreter executes cur_pc;
3644 * Otherwise, jumps to instruction *pi.
3646 return (cur_pc == *pi);
3649 /* print_memory --- print a scalar value */
3652 print_memory(NODE *m, char **fparms, Func_print print_func, FILE *fp)
3656 if (m == Nnull_string)
3657 print_func(fp, "Nnull_string");
3658 else if ((m->flags & NUMBER) != 0)
3659 print_func(fp, "%g", m->numbr);
3660 else if ((m->flags & STRING) != 0)
3661 pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', FALSE);
3662 else if ((m->flags & NUMCUR) != 0)
3663 print_func(fp, "%g", m->numbr);
3664 else if ((m->flags & STRCUR) != 0)
3665 pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', FALSE);
3667 print_func(fp, "-?-");
3668 print_func(fp, " [%s]", flags2str(m->flags));
3672 pp_string_fp(print_func, fp, m->re_exp->stptr, m->re_exp->stlen, '/', FALSE);
3678 case Node_param_list:
3679 assert(fparms != NULL);
3680 print_func(fp, "%s", fparms[m->param_cnt]);
3685 case Node_var_array:
3686 print_func(fp, "%s", m->vname);
3690 print_func(fp, "?"); /* can't happen */
3694 /* print_instruction --- print a bytecode */
3697 print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
3699 static char **fparms = NULL;
3702 static int noffset = 0;
3705 static char buf[50];
3706 /* offset for 2nd to last lines in a multi-line output */
3707 noffset = sprintf(buf, "[ :%p] %-20.20s: ", pc, opcode2str(pc->opcode));
3710 if (pc->opcode == Op_func) {
3711 func = pc->func_body;
3712 fparms = get_params(func);
3713 pcount = get_param_count(func);
3716 print_func(fp, "\n\t# Function: %s (", func->lnode->param);
3717 for (j = 0; j < pcount; j++) {
3718 print_func(fp, "%s", fparms[j]);
3720 print_func(fp, ", ");
3722 print_func(fp, ")\n\n");
3724 } else if (pc->opcode == Op_ext_func) {
3725 func = pc->func_body;
3726 fparms = get_params(func);
3727 pcount = get_param_count(func);
3729 print_func(fp, "\n\t# Extension function: %s (... %d params ...)\n\n",
3730 func->lnode->param, pcount);
3731 } else if (pc->opcode == Op_rule) {
3733 print_func(fp, "\n\t# %s\n\n", ruletab[pc->in_rule]);
3736 if (pc->opcode == Op_newfile)
3737 print_func(fp, "\n");
3739 if (pc->source_line <= 0)
3740 print_func(fp, "[ :%p] %-20.20s: ", pc, opcode2str(pc->opcode));
3742 print_func(fp, "[%6d:%p] %-20.20s: ",
3743 pc->source_line, pc, opcode2str(pc->opcode));
3745 if (prog_running && ! in_dump) {
3746 /* find params in the current frame */
3747 func = find_frame(0)->func_node;
3749 fparms = get_params(func);
3755 switch (pc->opcode) {
3757 print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var));
3761 print_func(fp, "[set_%s()]", get_spec_varname(pc->assign_var));
3762 if (pc->assign_ctxt != 0)
3763 print_func(fp, " [assign_ctxt = %s]", opcode2str(pc->assign_ctxt));
3764 print_func(fp, "\n");
3767 case Op_field_assign:
3768 print_func(fp, "[%s]\n", pc->field_assign == reset_record ?
3769 "reset_record()" : "invalidate_field0()");
3772 case Op_field_spec_lhs:
3773 print_func(fp, "[target_assign = %p] [do_reference = %s]\n",
3774 pc->target_assign, pc->do_reference ? "TRUE" : "FALSE");
3778 print_func(fp, "[param_cnt = %d]\n", pcount);
3782 print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount,
3783 pc->source_file ? pc->source_file : "cmd. line");
3786 case Op_K_getline_redir:
3787 print_func(fp, "[into_var = %s] [redir_type = \"%s\"]\n",
3788 pc->into_var ? "TRUE" : "FALSE",
3789 redir2str(pc->redir_type));
3793 print_func(fp, "[into_var = %s]\n", pc->into_var ? "TRUE" : "FALSE");
3794 print_func(fp, "%*s[target_beginfile = %p] [target_endfile = %p]\n",
3796 (pc + 1)->target_beginfile, (pc + 1)->target_endfile);
3799 case Op_K_print_rec:
3800 print_func(fp, "[redir_type = \"%s\"]\n", redir2str(pc->redir_type));
3805 print_func(fp, "[expr_count = %ld] [redir_type = \"%s\"]\n",
3806 pc->expr_count, redir2str(pc->redir_type));
3809 case Op_indirect_func_call:
3811 print_func(fp, "[func_name = %s] [arg_count = %ld]\n",
3812 pc->func_name, (pc + 1)->expr_count);
3816 print_func(fp, "[target_newfile = %p] [target_endfile = %p]\n",
3817 pc->target_newfile, pc->target_endfile);
3821 print_func(fp, "[target_jmp = %p] [target_endfile = %p]\n",
3822 pc->target_jmp, pc->target_endfile);
3823 print_func(fp, "%*s[target_get_record = %p]\n",
3824 noffset, "", (pc + 1)->target_get_record);
3828 print_func(fp, "[target_newfile = %p]\n", pc->target_newfile);
3837 case Op_arrayfor_init:
3840 print_func(fp, "[target_jmp = %p]\n", pc->target_jmp);
3843 print_func(fp, "[target_end = %p] [target_atexit = %p]\n",
3844 pc->target_end, pc->target_atexit);
3848 print_func(fp, "[target_jmp = %p] [match_exp = %s]\n",
3849 pc->target_jmp, (pc + 1)->match_exp ? "TRUE" : "FALSE");
3852 case Op_arrayfor_incr:
3853 print_func(fp, "[array_var = %s] [target_jmp = %p]\n",
3854 pc->array_var->type == Node_param_list ?
3855 fparms[pc->array_var->param_cnt] : pc->array_var->vname,
3860 print_func(fp, "[triggered = %ld] [target_jmp = %p]\n",
3861 pc->triggered, pc->target_jmp);
3865 print_func(fp, "[line_range = %p] [target_jmp = %p]\n",
3866 pc->line_range, pc->target_jmp);
3869 case Op_sub_builtin:
3871 const char *fname = "sub";
3872 static const struct flagtab values[] = {
3874 { GENSUB, "GENSUB" },
3875 { LITERAL, "LITERAL" },
3879 if (pc->sub_flags & GSUB)
3881 else if (pc->sub_flags & GENSUB)
3883 print_func(fp, "%s [arg_count = %ld] [sub_flags = %s]\n",
3884 fname, pc->expr_count,
3885 genflags2str(pc->sub_flags, values));
3891 const char *fname = getfname(pc->builtin);
3893 print_func(fp, "(extension func) [arg_count = %ld]\n", pc->expr_count);
3895 print_func(fp, "%s [arg_count = %ld]\n", fname, pc->expr_count);
3901 print_func(fp, "[sub_count = %ld]\n", pc->sub_count);
3905 print_memory(pc->memory, fparms, print_func, fp);
3906 print_func(fp, " [sub_count = %ld]\n", pc->expr_count);
3909 case Op_subscript_lhs:
3910 print_func(fp, "[sub_count = %ld] [do_reference = %s]\n",
3912 pc->do_reference ? "TRUE" : "FALSE");
3917 print_func(fp, "[expr_count = %ld]\n", pc->expr_count);
3921 /* NB: concat_flag CSVAR only used in grammar, don't display it */
3922 print_func(fp, "[expr_count = %ld] [concat_flag = %s]\n",
3924 (pc->concat_flag & CSUBSEP) ? "CSUBSEP" : "0");
3928 print_func(fp, "[in_rule = %s] [source_file = %s]\n",
3929 ruletab[pc->in_rule],
3930 pc->source_file ? pc->source_file : "cmd. line");
3935 static const char *const linttypetab[] = {
3937 "LINT_assign_in_cond",
3940 print_func(fp, "[lint_type = %s]\n", linttypetab[pc->lint_type]);
3945 print_func(fp, "[exec_count = %ld]\n", pc->exec_count);
3950 print_memory(pc->memory, fparms, print_func, fp);
3951 print_func(fp, " [do_reference = %s]\n",
3952 pc->do_reference ? "TRUE" : "FALSE");
3970 case Op_assign_concat:
3971 print_memory(pc->memory, fparms, print_func, fp);
3974 print_func(fp, "\n");
3979 /* do_trace_instruction --- trace command */
3982 do_trace_instruction(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
3984 if (arg != NULL && arg->type == D_argument
3985 && arg->a_argument == A_TRACE_ON)
3992 /* print_code --- print a list of instructions */
3995 print_code(INSTRUCTION *pc, void *x)
3997 struct pf_data *data = (struct pf_data *) x;
3998 for (; pc != NULL; pc = pc->nexti)
3999 print_instruction(pc, data->print_func, data->fp, data->defn /* in_dump */);
4003 /* do_dump_instructions --- dump command */
4006 do_dump_instructions(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4010 if (arg != NULL && arg->type == D_string) {
4011 /* dump to a file */
4012 if ((fp = fopen(arg->a_string, "w")) == NULL) {
4013 d_error(_("could not open `%s' for writing (%s)"),
4014 arg->a_string, strerror(errno));
4017 pf_data.print_func = fprintf;
4019 pf_data.defn = TRUE; /* in_dump = TRUE */
4020 (void) print_code(code_block, &pf_data);
4021 (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
4029 initialize_pager(out_fp);
4030 if (setjmp(pager_quit_tag) == 0) {
4031 pf_data.print_func = gprintf;
4032 pf_data.fp = out_fp;
4033 pf_data.defn = TRUE; /* in_dump = TRUE */
4034 (void) print_code(code_block, &pf_data);
4035 (void) foreach_func((int (*)(INSTRUCTION *, void *)) print_code,
4043 /* do_save --- save command */
4046 do_save(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4048 #ifdef HAVE_LIBREADLINE
4050 HIST_ENTRY **hist_list;
4053 if ((fp = fopen(arg->a_string, "w")) == NULL) {
4054 d_error(_("could not open `%s' for writing (%s)"),
4055 arg->a_string, strerror(errno));
4059 hist_list = history_list();
4060 if (hist_list && history_length > sess_history_base) {
4061 for (i = sess_history_base; hist_list[i] != NULL; i++) {
4063 line = hist_list[i]->line;
4065 /* exclude save commands;
4066 * N.B.: this test may fail if there is another
4067 * command with the same first 2 letters.
4070 if (strlen(line) > 1
4071 && strncmp(line, "sa", 2) == 0)
4074 fprintf(fp, "%s\n", line);
4082 /* do_option --- option command */
4085 do_option(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4087 const struct dbg_option *opt;
4090 if (arg == NULL) { /* display all available options and corresponding values */
4091 for (opt = option_list; opt->name; opt++) {
4092 if (opt->str_val != NULL)
4093 fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4095 fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4100 name = arg->a_string;
4102 value = arg ? arg->a_string : NULL;
4104 for (opt = option_list; opt->name; opt++) { /* linear search */
4105 if (strcmp(name, opt->name) == 0)
4111 if (value == NULL) { /* display current setting */
4112 if (opt->str_val != NULL)
4113 fprintf(out_fp, "%s = \"%s\"\n", opt->name, *(opt->str_val));
4115 fprintf(out_fp, "%s = %d\n", opt->name, *(opt->num_val));
4117 (*(opt->assign))(value);
4122 #ifdef HAVE_LIBREADLINE
4124 /* initialize_pager --- initialize our idea of the terminal size */
4127 initialize_pager(FILE *fp)
4129 if (! os_isatty(fileno(fp)) || ! input_from_tty || input_fd != 0) {
4130 screen_width = INT_MAX;
4131 screen_height = INT_MAX;
4133 /* get the terminal size from readline. */
4135 rl_reset_terminal(NULL); /* N.B.: NULL argument means
4136 * "use TERM env variable for terminal name".
4138 rl_get_screen_size(&screen_height, &screen_width);
4139 if (screen_height <= 1)
4140 screen_height = INT_MAX;
4141 if (screen_width <= 1)
4142 screen_width = INT_MAX;
4144 pager_lines_printed = 0;
4149 prompt_continue(FILE *fp)
4151 int quit_pager = FALSE;
4153 if (os_isatty(fileno(fp)) && input_fd == 0)
4154 quit_pager = prompt_yes_no(
4155 _("\t------[Enter] to continue or q [Enter] to quit------"),
4156 _("q")[0], FALSE, fp);
4158 longjmp(pager_quit_tag, 1);
4159 pager_lines_printed = 0;
4162 /* gprintf --- like fprintf but allows paging */
4165 gprintf(FILE *fp, const char *format, ...)
4168 static char *buf = NULL;
4169 static size_t buflen = 0;
4174 #define GPRINTF_BUFSIZ 512
4176 buflen = GPRINTF_BUFSIZ;
4177 emalloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4178 } else if (buflen - bl < GPRINTF_BUFSIZ/2) {
4179 buflen += GPRINTF_BUFSIZ;
4180 erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4182 #undef GPRINTF_BUFSIZ
4185 va_start(args, format);
4186 nchar = vsnprintf(buf + bl, buflen - bl, format, args);
4190 if (nchar > 0 && nchar < buflen - bl) {
4192 if (buf[bl-1] != '\n') /* buffer output until see a newline at end */
4197 /* enlarge buffer, and try again */
4199 erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4203 for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) {
4204 int sz = (int) (q - p);
4208 cnt = sz > screen_width ? screen_width : sz;
4210 /* do not print partial line before scrolling */
4211 if (cnt < sz && (pager_lines_printed == (screen_height - 2)))
4212 prompt_continue(fp);
4214 if (fwrite(p, sizeof(char), cnt, fp) != cnt)
4219 if (++pager_lines_printed == (screen_height - 1))
4220 prompt_continue(fp);
4228 if (++pager_lines_printed == (screen_height - 1))
4229 prompt_continue(fp);
4237 serialize_subscript(char *buf, int buflen, struct list_item *item)
4239 int bl = 0, nchar, i;
4242 nchar = snprintf(buf, buflen, "%d%c%d%c%s%c%d%c",
4243 item->number, FSEP, D_subscript, FSEP, item->sname, FSEP,
4244 item->num_subs, FSEP);
4247 else if (nchar >= buflen) /* need larger buffer */
4250 for (i = 0; i < item->num_subs; i++) {
4251 sub = item->subs[i];
4252 nchar = snprintf(buf + bl, buflen - bl, "%lu%c%s%c",
4253 (unsigned long) sub->stlen, FSEP, sub->stptr, FSEP);
4257 if (bl >= buflen) /* need larger buffer */
4265 /* serialize --- convert a list structure to a byte stream and
4266 * save in environment.
4272 #ifndef HAVE_LIBREADLINE
4273 #define HIST_ENTRY void
4274 #define history_list() NULL
4277 static char *buf = NULL;
4278 static int buflen = 0;
4280 BREAKPOINT *b = NULL;
4281 struct list_item *wd = NULL;
4282 HIST_ENTRY **hist_list = NULL;
4284 struct dbg_option *opt = NULL;
4285 struct commands_item *commands = NULL, *c;
4287 struct condition *cndn = NULL;
4288 void *ptr, *end_ptr;
4289 #ifdef HAVE_LIBREADLINE
4290 HIST_ENTRY *h = NULL;
4295 end_ptr = (void *) &breakpoints;
4296 ptr = (void *) breakpoints.prev;
4299 end_ptr = (void *) &watch_list;
4300 ptr = (void *) watch_list.prev;
4303 end_ptr = (void *) &display_list;
4304 ptr = (void *) display_list.prev;
4307 hist_list = history_list();
4308 if (hist_list == NULL) /* empty history list */
4311 ptr = (void *) hist_list[0];
4316 n = sizeof(option_list)/sizeof(option_list[0]);
4317 end_ptr = (void *) &option_list[n - 1];
4318 ptr = (void *) option_list;
4326 if (type != HISTORY && ptr == end_ptr) /* empty list */
4329 #define SERIALIZE_BUFSIZ 512
4331 if (buf == NULL) { /* first time */
4332 buflen = SERIALIZE_BUFSIZ;
4333 emalloc(buf, char *, buflen + 2, "serialize");
4337 while (ptr != end_ptr) {
4339 if (buflen - bl < SERIALIZE_BUFSIZ/2) {
4342 erealloc(buf, char *, buflen + 2, "serialize");
4345 #undef SERIALIZE_BUFSIZ
4347 /* field seperator is FSEP ('\037'), and the record separator is RSEP ('\036') */
4351 b = (BREAKPOINT *) ptr;
4353 /* src source_line flags ignore_count hit_count number;
4354 * commands and condition processed later in the end switch
4357 nchar = snprintf(buf + bl, buflen - bl,
4358 "%s%c%d%c%d%c%d%c%d%c%d%c",
4359 b->src, FSEP, b->bpi->source_line, FSEP, b->flags, FSEP,
4360 (int) b->ignore_count, FSEP,
4361 (int) b->hit_count, FSEP, b->number, FSEP);
4363 commands = &b->commands;
4368 wd = (struct list_item *) ptr;
4370 /* subscript -- number type sname num_subs subs(stlen + stptr) [commands [condition]]
4371 * variable -- number type sname [commands [condition]]
4372 * field -- number type symbol(numbr) [commands [condition]]
4375 if (IS_PARAM(wd)) /* exclude parameters */
4377 else if (IS_SUBSCRIPT(wd))
4378 nchar = serialize_subscript(buf + bl, buflen - bl, wd);
4379 else if (IS_FIELD(wd))
4380 nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%d%c",
4381 wd->number, FSEP, D_field, FSEP, (int) wd->symbol->numbr, FSEP);
4383 nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%s%c",
4384 wd->number, FSEP, D_variable, FSEP, wd->sname, FSEP);
4386 commands = &wd->commands;
4390 #ifdef HAVE_LIBREADLINE
4391 h = (HIST_ENTRY *) ptr;
4392 nchar = strlen(h->line);
4393 if (nchar >= buflen - bl)
4394 goto enlarge_buffer;
4395 strcpy(buf + bl, h->line);
4399 opt = (struct dbg_option *) ptr;
4400 if (opt->num_val != NULL)
4401 nchar = snprintf(buf + bl, buflen - bl,
4402 "%s%c%d%c", opt->name, FSEP, *(opt->num_val), FSEP);
4404 nchar = snprintf(buf + bl, buflen - bl,
4405 "%s%c%s%c", opt->name, FSEP, *(opt->str_val), FSEP);
4411 if (nchar == 0) /* skip empty history lines etc.*/
4413 else if (nchar > 0 && nchar < buflen - bl) {
4415 buf[bl] = RSEP; /* record */
4418 goto enlarge_buffer;
4423 /* recreate the `commands' command strings including the `commands'
4424 * and `end' commands; command seperator is '\034'.
4425 * re-parsed in unserialize to recover the commands list.
4426 * Alternatively, one could encode(serialize) each command and it's arguments.
4429 bl--; /* undo RSEP from above */
4431 /* compute required room in buffer */
4433 for (c = commands->next; c != commands; c = c->next) {
4434 nchar += (strlen(c->cmd_string) + 1);
4435 if (c->cmd == D_eval) {
4437 nchar += (strlen(a->a_string) + 1); /* awk statements */
4438 nchar += (strlen("end") + 1);
4442 if (nchar > 0) { /* non-empty commands list */
4443 nchar += (strlen("commands ") + 20 + strlen("end") + 2); /* 20 for cnum (an int) */
4444 if (nchar > buflen - bl) {
4445 buflen = bl + nchar;
4446 erealloc(buf, char *, buflen + 3, "serialize");
4448 nchar = sprintf(buf + bl, "commands %d", cnum);
4451 for (c = commands->next; c != commands; c = c->next) {
4452 nchar = strlen(c->cmd_string);
4453 memcpy(buf + bl, c->cmd_string, nchar);
4457 if (c->cmd == D_eval) {
4459 nchar = strlen(a->a_string); /* statements */
4460 memcpy(buf + bl, a->a_string, nchar);
4463 nchar = strlen("end"); /* end of 'eval' */
4464 memcpy(buf + bl, "end", nchar);
4469 nchar = strlen("end"); /* end of 'commands' */
4470 memcpy(buf + bl, "end", nchar);
4473 buf[bl++] = FSEP; /* field */
4474 buf[bl++] = RSEP; /* record */
4477 /* condition expression */
4479 bl--; /* undo RSEP from above */
4480 nchar = strlen(cndn->expr);
4481 if (nchar > buflen - bl) {
4482 buflen = bl + nchar;
4483 erealloc(buf, char *, buflen + 3, "serialize");
4485 memcpy(buf + bl, cndn->expr, nchar);
4487 buf[bl++] = FSEP; /* field */
4488 buf[bl++] = RSEP; /* record */
4492 ptr = (type == BREAK) ? (void *) b->prev : (void *) wd->prev;
4495 ptr = (void *) wd->prev;
4498 ptr = (void *) hist_list[++hist_index];
4501 ptr = (void *) (++opt);
4508 if (bl > 0) /* non-empty list */
4509 setenv(env_variable[type], buf, 1);
4514 unserialize_commands(char *str, int str_len)
4516 if (str_len <= 0 || str == NULL)
4518 commands_string = str;
4519 commands_string_len = str_len;
4520 push_cmd_src(INVALID_HANDLE, FALSE, read_commands_string, 0, 0, EXIT_FATAL);
4522 read_command(); /* forced to return in do_commands */
4527 /* unserialize_list_item --- create a list_item structure from unserialized data */
4529 static struct list_item *
4530 unserialize_list_item(struct list_item *list, char **pstr, int *pstr_len, int field_cnt)
4533 struct list_item *l;
4534 NODE *symbol = NULL;
4535 int sub_cnt = 0, cnt;
4538 /* subscript -- number type sname num_subs subs [commands [condition]]
4539 * variable -- number type sname [commands [condition]]
4540 * field -- number type symbol(numbr) commands [commands [condition]]
4543 num = strtol(pstr[0], NULL, 0);
4544 type = strtol(pstr[1], NULL, 0);
4546 if (type == D_field) {
4548 field_num = strtol(pstr[2], NULL, 0);
4549 symbol = make_number((AWKNUM) field_num);
4553 name = estrdup(pstr[2], pstr_len[2]);
4554 symbol = find_symbol(name, NULL);
4559 if (type == D_subscript) {
4561 sub_cnt = strtol(pstr[3], NULL, 0);
4562 emalloc(subs, NODE **, sub_cnt * sizeof(NODE *), "unserialize_list_item");
4564 for (i = 0; i < sub_cnt; i++) {
4565 sub_len = strtol(pstr[cnt], NULL, 0);
4566 subs[i] = make_string(pstr[cnt + 1], sub_len);
4572 l = add_item(list, type, symbol, NULL);
4573 if (type == D_subscript) {
4574 l->num_subs = sub_cnt;
4577 l->number = num; /* keep same item number across executions */
4579 if (list == &watch_list) {
4580 initialize_watch_item(l);
4581 /* unserialize watchpoint `commands' */
4582 unserialize_commands(pstr[cnt], pstr_len[cnt]);
4584 if (field_cnt > cnt) {
4586 expr = estrdup(pstr[cnt], pstr_len[cnt]);
4587 if (parse_condition(D_watch, l->number, expr) != 0)
4590 if (num > list->number) /* update list number counter */
4598 /* unserialize_breakpoint --- create a breakpoint structure from unserialized data */
4601 unserialize_breakpoint(char **pstr, int *pstr_len, int field_cnt)
4605 BREAKPOINT *b = NULL;
4609 /* src source_line flags ignore_count hit_count number commands [condition] */
4611 src = estrdup(pstr[0], pstr_len[0]);
4612 s = source_find(src);
4617 lineno = strtol(pstr[1], NULL, 0);
4618 if (lineno <= 0 || lineno > s->srclines)
4620 rp = find_rule(src, lineno);
4622 || (b = set_breakpoint_at(rp, lineno, TRUE)) == NULL
4626 b->flags = strtol(pstr[2], NULL, 0);
4627 b->ignore_count = strtol(pstr[3], NULL, 0);
4628 b->hit_count = strtol(pstr[4], NULL, 0);
4629 b->number = strtol(pstr[5], NULL, 0); /* same number as previous run */
4631 if (field_cnt > 6) /* unserialize breakpoint `commands' */
4632 unserialize_commands(pstr[6], pstr_len[6]);
4634 if (field_cnt > 7) { /* condition expression */
4636 expr = estrdup(pstr[7], pstr_len[7]);
4637 if (parse_condition(D_break, b->number, expr) != 0)
4641 if (b->number > watch_list.number) /* watch and break has same number counter */
4642 watch_list.number = b->number; /* update counter */
4646 /* unserialize_option --- set a debugger option from unserialized data. */
4648 static struct dbg_option *
4649 unserialize_option(char **pstr, int *pstr_len, int field_cnt ATTRIBUTE_UNUSED)
4651 const struct dbg_option *opt;
4653 for (opt = option_list; opt->name; opt++) {
4654 if (strncmp(pstr[0], opt->name, pstr_len[0]) == 0) {
4657 value = estrdup(pstr[1], pstr_len[1]);
4658 (*(opt->assign))(value);
4660 return ((struct dbg_option *) opt);
4666 /* unserialize -- reconstruct list from serialized data stored in
4667 * environment variable.
4671 unserialize(int type)
4674 char *p, *q, *r, *s;
4675 #define MAX_FIELD 30
4676 static char *pstr[MAX_FIELD];
4677 static int pstr_len[MAX_FIELD];
4679 val = getenv(env_variable[type]);
4683 for (p = val; (q = strchr(p, RSEP)) != NULL; p = q + 1) {
4685 if (type == HISTORY) {
4693 while ((s = strchr(r, FSEP)) != NULL && s < q) {
4694 pstr[field_cnt] = r;
4695 pstr_len[field_cnt] = (int) (s - r);
4698 if (field_cnt == MAX_FIELD)
4700 fatal("Increase MAX_FIELD and recompile.\n");
4708 (void) unserialize_breakpoint(pstr, pstr_len, field_cnt);
4711 (void) unserialize_list_item(&display_list, pstr, pstr_len, field_cnt);
4714 (void) unserialize_list_item(&watch_list, pstr, pstr_len, field_cnt);
4717 (void) unserialize_option(pstr, pstr_len, field_cnt);
4720 /* processed at the beginning of for loop */
4727 #ifdef HAVE_LIBREADLINE
4728 if (type == HISTORY)
4729 sess_history_base = history_length;
4732 unsetenv(env_variable[type]);
4737 prompt_yes_no(const char *mesg, char res_true, int res_default, FILE *fp)
4740 int ret = res_default; /* default */
4742 if (input_from_tty) {
4743 fprintf(fp, "%s", _(mesg));
4744 in_str = read_a_line(NULL);
4745 if (in_str == NULL) /* EOF */
4747 ret = (*in_str == res_true);
4753 /* has_break_or_watch_point --- check if given breakpoint or watchpoint
4754 * number exists. When flag any is TRUE,
4755 * check if any breakpoint/watchpoint
4756 * has been set (ignores num). Returns
4757 * type (breakpoint or watchpoint) or 0.
4761 has_break_or_watch_point(int *pnum, int any)
4763 BREAKPOINT *b = NULL;
4764 struct list_item *w = NULL;
4767 if (breakpoints.next != &breakpoints)
4768 b = breakpoints.next;
4769 if (watch_list.next != &watch_list)
4770 w = watch_list.next;
4782 if (w->number > b->number) {
4790 /* N.B: breakpoints and watchpoints get numbers from a single
4791 * counter/sequencer watch_list.number.
4794 for (b = breakpoints.next; b != &breakpoints; b = b->next) {
4795 if (b->number == *pnum)
4798 for (w = watch_list.next; w != &watch_list; w = w->next) {
4799 if (w->number == *pnum)
4806 /* delete_commands_item --- delete item(command) from `commands' list. */
4809 delete_commands_item(struct commands_item *c)
4811 efree(c->cmd_string);
4812 free_cmdarg(c->arg);
4813 c->next->prev = c->prev;
4814 c->prev->next = c->next;
4818 /* do_commands --- commands command */
4821 do_commands(CMDARG *arg, int cmd)
4823 static BREAKPOINT *b;
4824 static struct list_item *w;
4825 static struct commands_item *commands;
4826 struct commands_item *c;
4828 if (cmd == D_commands) {
4831 type = has_break_or_watch_point(&num, TRUE);
4834 type = has_break_or_watch_point(&num, FALSE);
4838 if (type == D_break)
4839 b = find_breakpoint(num);
4840 else if (type == D_watch)
4841 w = find_item(&watch_list, num);
4842 assert((b != NULL) || (w != NULL));
4843 commands = (b != NULL) ? &b->commands : &w->commands;
4845 /* delete current commands */
4846 for (c = commands->next; c != commands; c = c->next) {
4848 delete_commands_item(c->next);
4852 } else if (cmd == D_end) {
4854 if (read_a_line == read_commands_string) /* unserializig commands */
4855 return TRUE; /* done unserializing, terminate zzparse() */
4858 } else if (cmd == D_silent) {
4863 /* we also append silent command to the list for use
4864 * in `info break(watch)', and to simplify
4865 * serialization/unserialization of commands.
4869 assert(commands != NULL);
4871 emalloc(c, struct commands_item *, sizeof(struct commands_item), "do_commands");
4875 /* N.B.: first arg is the command string, see command.y */
4876 c->cmd_string = arg->a_string;
4877 c->arg = arg->next; /* actual arguments to the command */
4880 /* append to the list */
4881 c->prev = commands->prev;
4888 /* execute_commands --- execute breakpoint/watchpoint commands, the first
4889 * command that resumes execution terminates
4890 * commands processing.
4894 execute_commands(struct commands_item *commands)
4896 struct commands_item *c;
4900 for (c = commands->next; c != commands; c = c->next) {
4901 if (c->cmd == D_silent)
4903 cmd_ptr = get_command(c->cmd); /* command handler */
4904 ret = (*cmd_ptr)(c->arg, c->cmd);
4905 if (ret) /* resume execution (continue, next etc.) */
4911 /* do_print_f --- printf command */
4914 do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
4922 volatile jmp_buf fatal_tag_stack;
4924 /* count maximum required size for tmp */
4925 for (a = arg; a != NULL ; a = a->next)
4927 emalloc(tmp, NODE **, count * sizeof(NODE *), "do_print_f");
4929 for (i = 0, a = arg; a != NULL ; i++, a = a->next) {
4933 r = find_symbol(name, NULL);
4936 if (r->type == Node_var_new)
4937 tmp[i] = Nnull_string;
4938 else if (r->type != Node_var) {
4939 d_error(_("`%s' is not a scalar variable"), name);
4942 tmp[i] = r->var_value;
4948 field_num = (long) r->numbr;
4949 tmp[i] = *get_field(field_num, NULL);
4954 int cnt = a->a_count;
4956 r = find_array(name);
4960 for (; cnt > 0; cnt--) {
4964 value = in_array(r, subs);
4967 tmp[i] = Nnull_string; /* FIXME: goto done ? */
4968 else if (value->type == Node_var_array) {
4969 d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
4975 if (value == NULL) {
4976 d_error(_("[\"%s\"] not in array `%s'"),
4979 } else if (value->type != Node_var_array) {
4980 d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
4999 force_string(tmp[0]);
5001 PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5002 if (setjmp(fatal_tag) == 0)
5003 r = format_tree(tmp[0]->stptr, tmp[0]->stlen, tmp, i);
5005 /* fatal error, restore exit_val of program */
5006 exit_val = EXIT_SUCCESS;
5009 POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5012 (void) fwrite(r->stptr, sizeof(char), r->stlen, out_fp);
5020 /* do_source --- source command */
5023 do_source(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5026 char *file = arg->a_string;
5028 fd = open_readfd(file);
5029 if (fd <= INVALID_HANDLE) {
5030 d_error(_("can't open source file `%s' for reading (%s)"),
5031 file, strerror(errno));
5035 push_cmd_src(fd, FALSE, g_readline, close, D_source, EXIT_SUCCESS);
5036 cmd_src->str = estrdup(file, strlen(file));
5040 /* open_readfd --- open a file for reading */
5043 open_readfd(const char *file)
5047 fd = open(file, O_RDONLY);
5048 if (fd <= INVALID_HANDLE)
5049 return INVALID_HANDLE;
5050 else if (os_isdir(fd)) {
5053 return INVALID_HANDLE;
5058 /* find_option --- check if option name is valid */
5061 find_option(char *name)
5066 for (idx = 0; (p = option_list[idx].name); idx++) {
5067 if (strcmp(p, name) == 0)
5073 /* option_help --- display help text for debugger options */
5078 const struct dbg_option *opt;
5080 for (opt = option_list; opt->name; opt++)
5081 fprintf(out_fp, "\t%-15.15s - %s\n", opt->name, _(opt->help_txt));
5084 #ifdef HAVE_LIBREADLINE
5086 /* option_generator --- generator function for option name completion */
5089 option_generator(const char *text, int state)
5091 static size_t textlen;
5095 if (! state) { /* first time */
5096 textlen = strlen(text);
5100 while ((name = option_list[idx++].name)) {
5101 if (strncmp(name, text, textlen) == 0)
5102 return estrdup(name, strlen(name));
5109 /* set_gawk_output --- redirect gawk (normal) output */
5112 set_gawk_output(const char *file)
5114 int fd = INVALID_HANDLE;
5117 if (output_fp != stdout) {
5118 if (output_fp != stderr) {
5123 output_is_tty = os_isatty(fileno(stdout));
5124 output_file = "/dev/stdout";
5127 if (file == NULL || file[0] == '\0')
5131 if ((fd = os_devopen(file, O_WRONLY)) != INVALID_HANDLE) {
5132 fp = fdopen(fd, "w");
5136 } else if (strncmp(file, "/dev/", 5) == 0) {
5137 char *cp = (char *) file + 5;
5139 if (strcmp(cp, "stdout") == 0)
5141 if (strcmp(cp, "stderr") == 0) {
5143 output_file = "/dev/stderr";
5144 output_is_tty = os_isatty(fileno(stderr));
5148 if (strncmp(cp, "fd/", 3) == 0) {
5150 fd = (int) strtoul(cp, NULL, 10);
5151 if (errno == 0 && fd > INVALID_HANDLE) {
5152 fp = fdopen(fd, "w");
5154 fd = INVALID_HANDLE;
5156 fd = INVALID_HANDLE;
5158 /* /dev/ttyN, /dev/pts/N, /dev/null etc. */
5159 fd = open(file, O_WRONLY);
5162 if (fd > INVALID_HANDLE && fp == NULL) {
5163 fp = fdopen(fd, "w");
5170 fp = fopen(file, "w");
5175 output_file = estrdup(file, strlen(file));
5176 setbuf(fp, (char *) NULL);
5177 output_is_tty = os_isatty(fileno(fp));
5179 d_error(_("could not open `%s' for writing (%s)"),
5181 errno != 0 ? strerror(errno) : _("reason unknown"));
5182 fprintf(out_fp, _("sending output to stdout\n"));
5186 /* set_prompt --- set debugger prompt */
5189 set_prompt(const char *value)
5191 efree(dgawk_Prompt);
5192 dgawk_Prompt = estrdup(value, strlen(value));
5193 dPrompt = dgawk_Prompt;
5196 /* set_option_flag --- convert option string to flag value */
5199 set_option_flag(const char *value)
5202 if (strcmp(value, "on") == 0)
5204 if (strcmp(value, "off") == 0)
5207 n = strtol(value, NULL, 0);
5208 return (errno == 0 && n != 0);
5211 /* set_option_num --- set integer option value from string */
5214 set_option_num(int *pnum, const char *value)
5218 n = strtol(value, NULL, 0);
5219 if (errno == 0 && n > 0)
5222 d_error(_("invalid number"));
5225 /* set_listsize --- set list output window size */
5228 set_listsize(const char *value)
5230 set_option_num(&list_size, value);
5233 /* set_trace --- set instruction tracing on or off */
5236 set_trace(const char *value)
5238 do_trace = set_option_flag(value);
5241 /* set_save_history --- save history on exit */
5244 set_save_history(const char *value)
5246 do_save_history = set_option_flag(value);
5249 /* set_save_options --- save options on exit */
5252 set_save_options(const char *value)
5254 do_save_options = set_option_flag(value);
5257 /* set_history_size --- maximum entries in history file */
5260 set_history_size(const char *value)
5262 set_option_num(&history_size, value);
5266 /* read_commands_string --- one of the many ways zzlex fetches a line to parse;
5267 * this one is used to parse `commands' string during
5272 read_commands_string(const char *prompt ATTRIBUTE_UNUSED)
5274 char *p, *end, *line;
5276 if (commands_string == NULL)
5279 p = (char *) commands_string;
5280 end = (char *) commands_string + commands_string_len;
5281 for (; p < end; p++) {
5282 if (*p == line_sep) {
5283 line = estrdup(commands_string, p - commands_string);
5284 commands_string = p + 1;
5285 commands_string_len = end - commands_string;
5290 line = estrdup(commands_string, commands_string_len);
5291 commands_string = NULL;
5292 commands_string_len = 0;
5296 /* save_options --- save current options to file */
5299 save_options(const char *file)
5302 const struct dbg_option *opt;
5304 fp = fopen(file, "w");
5308 for (opt = option_list; opt->name; opt++) {
5309 if (opt->str_val != NULL)
5310 fprintf(fp, "option %s = \"%s\"\n", opt->name, *(opt->str_val));
5312 fprintf(fp, "option %s = %d\n", opt->name, *(opt->num_val));
5318 /* close_all --- close all open files */
5324 struct command_source *cs;
5326 (void) nextfile(&curfile, TRUE); /* close input data file */
5327 (void) close_io(&stdio_problem);
5328 if (cur_srcfile->fd != INVALID_HANDLE) {
5329 close(cur_srcfile->fd);
5330 cur_srcfile->fd = INVALID_HANDLE;
5332 for (cs = cmd_src; cs != NULL; cs = cs->next) {
5333 if (cs->close_func && cs->fd != INVALID_HANDLE) {
5334 cs->close_func(cs->fd);
5335 cs->fd = INVALID_HANDLE;
5339 set_gawk_output(NULL); /* closes output_fp if not stdout */
5342 /* install_params --- install function parameters into the symbol table */
5345 install_params(NODE *func)
5351 /* function parameters of type Node_param_list */
5353 for (np = np->rnode; np != NULL; np = np->rnode)
5354 install_symbol(np->param, np);
5357 /* remove_params --- remove function parameters out of the symbol table */
5360 remove_params(NODE *func)
5367 for (np = np->rnode; np != NULL; np = np->rnode)
5368 remove_symbol(np->param);
5371 /* pre_execute_code --- pre_hook for execute_code, called by pre_execute */
5374 pre_execute_code(INSTRUCTION **pi)
5376 INSTRUCTION *ei = *pi;
5378 switch (ei->opcode) {
5382 case Op_K_getline: /* getline without redirection */
5383 d_error(_("`%s' not allowed in current context;"
5384 " statement ignored"),
5385 op2str(ei->opcode));
5389 if (ei->nexti != NULL) { /* not an implicit return */
5391 d_error(_("`return' not allowed in current context;"
5392 " statement ignored"));
5393 /* throw away return value already pushed onto stack */
5405 extern INSTRUCTION *unwind_stack(long n);
5408 execute_code(volatile INSTRUCTION *code)
5410 volatile NODE *r = NULL;
5411 volatile jmp_buf fatal_tag_stack;
5412 long save_stack_size;
5414 /* We use one global stack for all contexts.
5415 * Save # of items in stack; in case of
5416 * a fatal error, pop stack until it has that many items.
5418 save_stack_size = (stack_ptr - stack_bottom) + 1;
5420 PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5421 if (setjmp(fatal_tag) == 0) {
5422 (void) r_interpret((INSTRUCTION *) code);
5424 } else /* fatal error */
5425 (void) unwind_stack(save_stack_size);
5427 POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5429 if (exit_val != EXIT_SUCCESS) { /* must be EXIT_FATAL? */
5430 exit_val = EXIT_SUCCESS;
5436 /* do_eval --- eval command */
5439 do_eval(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5443 NODE *this_frame = NULL, *this_func = NULL;
5445 INSTRUCTION *eval, *code = NULL;
5447 char **save_parmlist = NULL;
5448 int ecount = 0, pcount = 0;
5452 this_frame = find_frame(0);
5453 this_func = this_frame->func_node;
5456 install_params(this_func); /* expose current function parameters to eval */
5457 ctxt = new_context();
5458 ctxt->install_func = append_symbol; /* keep track of newly installed globals */
5460 (void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
5461 ret = parse_program(&code);
5462 remove_params(this_func);
5464 pop_context(); /* switch to prev context */
5465 free_context(ctxt, FALSE /* keep_globals */);
5469 f = lookup("@eval");
5471 if (this_func == NULL) { /* in main */
5472 /* do a function call */
5473 eval = bcalloc(Op_func_call, 2, 0);
5474 eval->source_file = cur_srcfile->src;
5475 eval->func_body = f;
5476 eval->func_name = NULL; /* not needed, func_body already assigned */
5477 (eval + 1)->expr_count = 0;
5478 eval->nexti = bcalloc(Op_stop, 1, 0);
5481 /* execute as a part of the current function */
5487 eval = f->code_ptr; /* Op_func */
5488 eval->source_file = cur_srcfile->src;
5489 /* turn implicit Op_K_return into Op_stop */
5490 t = (eval + 1)->lasti; /* Op_K_return */
5491 t->opcode = Op_stop;
5493 /* add or append eval locals to the current frame stack */
5494 ecount = f->lnode->param_cnt; /* eval local count */
5495 pcount = this_func->lnode->param_cnt;
5496 save_parmlist = this_func->parmlist;
5500 emalloc(this_frame->stack, NODE **, ecount * sizeof(NODE *), "do_eval");
5502 erealloc(this_frame->stack, NODE **, (pcount + ecount) * sizeof(NODE *), "do_eval");
5504 emalloc(varnames, char **, (pcount + ecount + 1) * sizeof(char *), "do_eval");
5506 memcpy(varnames, save_parmlist, pcount * sizeof(char *));
5507 for (np = f->lnode->rnode, i = 0; np != NULL; np = np->rnode, i++) {
5508 varnames[pcount + i] = np->param;
5509 np->param_cnt += pcount; /* appending eval locals: fixup param_cnt */
5511 varnames[pcount + ecount] = NULL;
5512 sp = this_frame->stack + pcount;
5513 for (i = 0; i < ecount; i++) {
5515 memset(r, 0, sizeof(NODE));
5517 /* local variable */
5518 r->type = Node_var_new;
5519 r->vname = varnames[pcount + i];
5522 this_func->parmlist = varnames;
5523 this_func->lnode->param_cnt += ecount;
5528 pf_data.print_func = fprintf;
5529 pf_data.fp = out_fp;
5530 pf_data.defn = FALSE; /* in_dump = FALSE */
5531 (void) print_code(f->code_ptr, &pf_data);
5534 ret_val = execute_code((volatile INSTRUCTION *) eval);
5536 if (ret_val != NULL)
5537 DEREF(ret_val); /* throw away return value */
5541 if (this_func != NULL && ecount > 0) {
5544 /* undo frame manipulation from above */
5546 /* free eval locals */
5547 sp = this_frame->stack + pcount;
5548 for (i = ecount; i > 0; i--) {
5550 if (r->type == Node_var) /* eval local variable */
5551 DEREF(r->var_value);
5552 else if (r->type == Node_var_array) /* eval local array */
5558 efree(this_frame->stack);
5559 this_frame->stack = NULL;
5561 restore_frame() will free it */
5563 efree(this_func->parmlist);
5564 this_func->parmlist = save_parmlist;
5565 this_func->lnode->param_cnt -= ecount;
5568 /* always destroy symbol "@eval", however destroy all newly installed
5569 * globals only if fatal error in r_interpret (r == NULL).
5572 pop_context(); /* switch to prev context */
5573 free_context(ctxt, (ret_val != NULL)); /* free all instructions and optionally symbols */
5574 if (ret_val != NULL)
5575 destroy_symbol("@eval"); /* destroy "@eval" */
5581 ... When you use condition, GDB checks expression
5582 immediately for syntactic correctness, and to determine whether symbols
5583 in it have referents in the context of your breakpoint. If expression
5584 uses symbols not referenced in the context of the breakpoint, GDB prints
5587 No symbol "foo" in current context.
5590 static int invalid_symbol = 0;
5593 check_symbol(char *name)
5596 d_error(_("No symbol `%s' in current context"), name);
5597 /* install anyway, but keep track of it */
5598 append_symbol(name);
5601 /* parse_condition --- compile a condition expression */
5604 parse_condition(int type, int num, char *expr)
5606 INSTRUCTION *code = NULL;
5607 AWK_CONTEXT *ctxt = NULL;
5610 struct list_item *w;
5611 NODE *this_func = NULL;
5612 INSTRUCTION *it, *stop, *rule;
5613 struct condition *cndn = NULL;
5615 if (type == D_break && (b = find_breakpoint(num)) != NULL) {
5618 rp = find_rule(b->src, b->bpi->source_line);
5619 if (rp != NULL && rp->opcode == Op_func)
5620 this_func = rp->func_body;
5621 } else if (type == D_watch && (w = find_item(&watch_list, num)) != NULL) {
5623 this_func = find_frame(cur_frame)->func_node;
5629 goto out; /* delete condition */
5631 install_params(this_func);
5632 ctxt = new_context();
5634 ctxt->install_func = check_symbol;
5636 (void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
5637 ret = parse_program(&code);
5638 remove_params(this_func);
5641 if (ret != 0 || invalid_symbol) {
5642 free_context(ctxt, FALSE /* keep_globals */);
5646 /* condition expression is parsed as awk pattern without
5647 * any action. The code is then modified to end up with
5648 * a `1.0' on stack when the expression is true, `0.0' otherwise.
5651 assert(code != NULL);
5652 rule = ctxt->rule_list.nexti;
5653 stop = bcalloc(Op_stop, 1, 0);
5655 it = rule->firsti; /* Op_K_print_rec */
5656 assert(it->opcode == Op_K_print_rec);
5657 it->opcode = Op_push_i;
5658 it->memory = mk_number((AWKNUM) 1.0, PERM|NUMBER|NUMCUR);
5659 it->nexti = bcalloc(Op_jmp, 1, 0);
5660 it->nexti->target_jmp = stop;
5661 it->nexti->nexti = rule->lasti;
5663 it = rule->lasti; /* Op_no_op, target for Op_jmp_false */
5664 assert(it->opcode == Op_no_op);
5665 it->opcode = Op_push_i;
5666 it->memory = mk_number((AWKNUM) 0.0, PERM|NUMBER|NUMCUR);
5670 if (cndn->expr != NULL)
5672 free_context(cndn->ctxt, FALSE);
5680 /* do_condition --- condition command */
5683 do_condition(CMDARG *arg, int cmd ATTRIBUTE_UNUSED)
5689 type = has_break_or_watch_point(&num, FALSE);
5692 arg = arg->next; /* condition expression */
5694 expr = arg->a_string;
5695 if (parse_condition(type, num, expr) == 0 && arg != NULL)
5696 arg->a_string = NULL; /* don't let free_cmdarg free it */
5700 /* in_cmd_src --- check if filename already in cmd_src */
5703 in_cmd_src(const char *filename)
5705 struct command_source *cs;
5706 for (cs = cmd_src; cs != NULL; cs = cs->next) {
5707 if (cs->str != NULL && strcmp(cs->str, filename) == 0)
5716 if (cmd_src == NULL)
5718 return cmd_src->eof_status;
5725 char * (*readfunc)(const char *),
5726 int (*closefunc)(int),
5730 struct command_source *cs;
5731 emalloc(cs, struct command_source *, sizeof(struct command_source), "push_cmd_src");
5734 cs->read_func = readfunc;
5735 cs->close_func = closefunc;
5738 /* eof_status = EXIT_FATAL - exit with status EXIT_FATAL on EOF or error.
5739 * = EXIT_FAILURE - exit status EXIT_FAILURE on error.
5740 * = EXIT_SUCCESS - don't exit on EOF or error.
5742 cs->eof_status = eofstatus;
5748 input_from_tty = istty;
5749 read_a_line = readfunc;
5755 struct command_source *cs;
5757 if (cmd_src->next == NULL)
5762 if (cs->close_func && cs->fd != INVALID_HANDLE)
5763 cs->close_func(cs->fd);
5764 if (cs->str != NULL)
5768 input_fd = cmd_src->fd;
5769 input_from_tty = cmd_src->is_tty;
5770 read_a_line = cmd_src->read_func;