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