2
* debug.c - gawk debugger
2
* debug.c - gawk debugger
6
* Copyright (C) 2004, 2010-2013, 2016-2023 the Free Software Foundation, Inc.
6
* Copyright (C) 2004, 2010-2013 the Free Software Foundation, Inc.
8
8
* This file is part of GAWK, the GNU implementation of the
9
9
* AWK Programming Language.
11
11
* GAWK is free software; you can redistribute it and/or modify
12
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
13
* the Free Software Foundation; either version 2 of the License, or
14
14
* (at your option) any later version.
16
16
* GAWK is distributed in the hope that it will be useful,
17
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
19
* GNU General Public License for more details.
21
21
* You should have received a copy of the GNU General Public License
22
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
23
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
180
175
INSTRUCTION *pc; /* 'until' and 'return' commands */
181
176
int repeat_count; /* 'step', 'next', 'stepi', 'nexti' commands */
182
177
bool print_frame; /* print frame info, 'finish' and 'until' */
183
bool print_ret; /* print returned value, 'finish' */
178
bool print_ret; /* print returned value, 'finish' */
184
179
int break_point; /* non-zero (breakpoint number) if stopped at break point */
185
180
int watch_point; /* non-zero (watchpoint number) if stopped at watch point */
198
193
static bool need_restart = false;
199
194
enum { BREAK=1, WATCH, DISPLAY, HISTORY, OPTION };
200
195
static const char *const env_variable[] = {
208
static void serialize_list(int type);
209
static void unserialize_list(int type);
203
static void serialize(int );
204
static void unserialize(int );
210
205
static const char *commands_string = NULL;
211
206
static int commands_string_len = 0;
212
207
static char line_sep;
245
240
/* debugger option related variables */
247
static const char *output_file = "/dev/stdout"; /* gawk output redirection */
248
const char *dgawk_prompt = NULL; /* initialized in interpret */
242
static char *output_file = "/dev/stdout"; /* gawk output redirection */
243
char *dgawk_prompt = NULL; /* initialized in interpret */
249
244
static int list_size = DEFAULT_LISTSIZE; /* # of lines that 'list' prints */
250
245
static int do_trace = false;
251
246
static int do_save_history = true;
255
250
static const struct dbg_option option_list[] = {
256
251
{"history_size", &history_size, NULL, &set_history_size,
257
gettext_noop("set or show the number of lines to keep in history file") },
252
gettext_noop("set or show the number of lines to keep in history file.") },
258
253
{"listsize", &list_size, NULL, &set_listsize,
259
gettext_noop("set or show the list command window size") },
254
gettext_noop("set or show the list command window size.") },
260
255
{"outfile", NULL, &output_file, &set_gawk_output,
261
gettext_noop("set or show gawk output file") },
256
gettext_noop("set or show gawk output file.") },
262
257
{"prompt", NULL, &dgawk_prompt, &set_prompt,
263
gettext_noop("set or show debugger prompt"), },
258
gettext_noop("set or show debugger prompt."), },
264
259
{"save_history", &do_save_history, NULL, &set_save_history,
265
gettext_noop("(un)set or show saving of command history (value=on|off)") },
260
gettext_noop("(un)set or show saving of command history (value=on|off).") },
266
261
{"save_options", &do_save_options, NULL, &set_save_options,
267
gettext_noop("(un)set or show saving of options (value=on|off)") },
262
gettext_noop("(un)set or show saving of options (value=on|off).") },
268
263
{"trace", &do_trace, NULL, &set_trace,
269
gettext_noop("(un)set or show instruction tracing (value=on|off)") },
264
gettext_noop("(un)set or show instruction tracing (value=on|off).") },
270
265
{0, NULL, NULL, NULL, 0},
277
272
jmp_buf pager_quit_tag;
278
int pager_quit_tag_valid = 0;
273
bool pager_quit_tag_valid = false;
279
274
static int screen_width = INT_MAX; /* no of columns */
280
275
static int screen_height = INT_MAX; /* no of rows */
281
static int pager_lines_printed = 0; /* no of lines printed so far */
276
static int pager_lines_printed = 0; /* no of lines printed so far */
283
278
static void restart(bool run) ATTRIBUTE_NORETURN;
284
279
static void close_all(void);
315
310
static int breakpoint_triggered(BREAKPOINT *b);
316
311
static int watchpoint_triggered(struct list_item *w);
317
312
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
313
static int print_code(INSTRUCTION *pc, void *x);
320
314
static void next_command();
321
315
static void debug_post_execute(INSTRUCTION *pc);
345
339
static struct command_source *cmd_src = NULL;
347
#define PUSH_BINDING(stack, tag, val) \
349
memcpy((char *) (stack), (const char *) tag, sizeof(jmp_buf))
350
#define POP_BINDING(stack, tag, val) \
352
memcpy((char *) tag, (const char *) (stack), sizeof(jmp_buf))
355
342
#define CHECK_PROG_RUNNING() \
357
344
if (! prog_running) { \
358
d_error(_("program not running")); \
345
d_error(_("program not running.")); \
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.
373
351
/* g_readline -- read a line of text; the interface is like 'readline' but
374
352
* without any command-line editing; used when not compiled with
544
522
if (s->fd <= INVALID_HANDLE && (s->fd = srcopen(s)) <= INVALID_HANDLE) {
545
d_error(_("cannot open source file `%s' for reading: %s"),
523
d_error(_("can't open source file `%s' for reading (%s)"),
546
524
src, strerror(errno));
550
528
if (fstat(s->fd, &sbuf) == 0 && s->mtime < sbuf.st_mtime) {
551
fprintf(out_fp, _("warning: source file `%s' modified since program compilation.\n"),
529
fprintf(out_fp, _("WARNING: source file `%s' modified since program compilation.\n"),
553
531
efree(s->line_offset);
554
532
s->line_offset = NULL;
784
762
b->number, disp, (b->flags & BP_ENABLE) != 0 ? "yes" : "no",
785
763
b->src, b->bpi->source_line);
786
764
if (b->hit_count > 0)
787
gprintf(out_fp, _("\tnumber of hits = %ld\n"), b->hit_count);
765
gprintf(out_fp, _("\tno of hits = %ld\n"), b->hit_count);
788
766
if ((b->flags & BP_IGNORE) != 0)
789
767
gprintf(out_fp, _("\tignore next %ld hit(s)\n"), b->ignore_count);
790
768
if (b->cndn.code != NULL)
920
898
for (i = 0; i < d->num_subs; i++) {
922
900
sub = d->subs[i];
923
gprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
901
gprintf(out_fp, "[\"%s\"]", sub->stptr);
925
gprintf(out_fp, "\n");
903
gprintf(out_fp, "\n");
926
904
} else if (IS_FIELD(d))
927
905
gprintf(out_fp, "%d:\t$%ld\n", d->number, get_number_si(symbol));
967
945
case Node_var_new:
968
946
fprintf(out_fp, "untyped variable\n");
971
fprintf(out_fp, "untyped element\n");
974
949
if (! isparam && r->var_update)
976
951
valinfo(r->var_value, fprintf, out_fp);
978
953
case Node_var_array:
979
fprintf(out_fp, "array, %ld elements\n", (long) assoc_length(r));
954
fprintf(out_fp, "array, %ld elements\n", assoc_length(r));
982
957
fprintf(out_fp, "`function'\n");
1087
/* print_array_names --- print the stack of array names */
1090
print_array_names(const char **names, size_t num_names, FILE *out_fp)
1094
gprintf(out_fp, "%s", names[0]);
1095
for (i = 1; i < num_names; i++)
1096
gprintf(out_fp, "[\"%s\"]", names[i]);
1099
1062
/* print_array --- print the contents of an array */
1109
1072
volatile int ret = 0;
1110
1073
volatile jmp_buf pager_quit_tag_stack;
1112
// manage a stack of names for printing deeply nested arrays
1113
static const char **names = NULL;
1114
static size_t cur_name = 0;
1115
static size_t num_names = 0;
1116
#define INITIAL_NAME_COUNT 10
1118
if (names == NULL) {
1119
emalloc(names, const char **, INITIAL_NAME_COUNT * sizeof(char *), "print_array");
1120
memset(names, 0, INITIAL_NAME_COUNT * sizeof(char *));
1121
num_names = INITIAL_NAME_COUNT;
1124
1075
if (assoc_empty((NODE *) arr)) {
1125
1076
gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
1134
1085
PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
1135
1086
if (setjmp(pager_quit_tag) == 0) {
1136
// push name onto stack
1137
if (cur_name >= num_names) {
1139
erealloc(names, const char **, num_names * sizeof(char *), "print_array");
1141
names[cur_name++] = arr_name;
1143
// and print the array
1144
1087
for (i = 0; ret == 0 && i < num_elems; i++) {
1145
1088
subs = list[i];
1146
1089
r = *assoc_lookup((NODE *) arr, subs);
1147
if (r->type == Node_var_array) {
1148
// 12/2023: Use sub->stptr here, not r->vname, since
1149
// a subarray could have been created via
1150
// split() or some other mechanism where flags has NUMINT in it.
1151
// In this case, r->vname can be NULL, so pass in the
1152
// subscript itself. This should be fixed in the code that
1153
// builds such arrays.
1154
ret = print_array(r, subs->stptr);
1156
print_array_names(names, cur_name, out_fp);
1157
gprintf(out_fp, "[\"%.*s\"] = ", (int) subs->stlen, subs->stptr);
1090
if (r->type == Node_var_array)
1091
ret = print_array(r, r->vname);
1093
gprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
1158
1094
valinfo((NODE *) r, gprintf, out_fp);
1181
1116
subs = a->a_node;
1182
1117
r = in_array(arr, subs);
1184
fprintf(out_fp, _("subscript \"%.*s\" is not in array `%s'\n"), (int) subs->stlen, subs->stptr, arr_name);
1119
fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"), subs->stptr, arr_name);
1185
1120
else if (r->type == Node_var_array) {
1187
1122
print_subscript(r, r->vname, a->next, count - 1);
1189
1124
/* print # of elements in array */
1190
1125
fprintf(out_fp, "%s = ", r->vname);
1191
print_symbol(r, false);
1126
print_symbol(r, false);
1194
fprintf(out_fp, "%s[\"%.*s\"] = ", arr_name, (int) subs->stlen, subs->stptr);
1129
fprintf(out_fp, "%s[\"%s\"] = ", arr_name, subs->stptr);
1195
1130
valinfo(r, fprintf, out_fp);
1228
1163
if ((r = find_array(name)) != NULL) {
1229
1164
int count = a->a_count;
1230
1165
for (; count > 0; count--) {
1233
1168
subs = a->a_node;
1234
1169
value = in_array(r, subs);
1235
1170
if (value == NULL) {
1236
fprintf(out_fp, _("subscript \"%.*s\" is not in array `%s'\n"),
1237
(int) subs->stlen, subs->stptr, name);
1171
fprintf(out_fp, _("[\"%s\"] not in array `%s'\n"),
1239
1174
} else if (value->type != Node_var_array) {
1240
fprintf(out_fp, _("`%s[\"%.*s\"]' is not an array\n"),
1241
name, (int) subs->stlen, subs->stptr);
1175
fprintf(out_fp, _("`%s[\"%s\"]' is not an array\n"),
1323
1256
if (count == 1) {
1324
1257
if (value != NULL && value->type == Node_var_array)
1325
d_error(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
1326
name, (int) subs->stlen, subs->stptr);
1258
d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
1328
1261
arg = arg->next;
1329
1262
val = arg->a_node;
1330
newval = dupnode(val);
1331
// subs should not be freed, so
1332
// use dupnode in call to assoc_set.
1333
assoc_set(r, dupnode(subs), newval);
1334
fprintf(out_fp, "%s[\"%.*s\"] = ", name, (int) subs->stlen, subs->stptr);
1335
valinfo(newval, fprintf, out_fp);
1263
lhs = assoc_lookup(r, subs);
1265
*lhs = dupnode(val);
1266
fprintf(out_fp, "%s[\"%s\"] = ", name, subs->stptr);
1267
valinfo(*lhs, fprintf, out_fp);
1338
1270
if (value == NULL) {
1340
1272
array = make_array();
1341
1273
array->vname = estrdup(subs->stptr, subs->stlen);
1342
1274
array->parent_array = r;
1343
// subs should not be freed, so
1344
// use dupnode in call to assoc_set.
1345
assoc_set(r, dupnode(subs), array);
1275
lhs = assoc_lookup(r, subs);
1347
1279
} else if (value->type != Node_var_array) {
1348
d_error(_("attempt to use scalar `%s[\"%.*s\"]' as array"),
1349
name, (int) subs->stlen, subs->stptr);
1280
d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
1441
1372
struct list_item *d;
1443
ezalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
1374
emalloc(d, struct list_item *, sizeof(struct list_item), "add_item");
1375
memset(d, 0, sizeof(struct list_item));
1444
1376
d->commands.next = d->commands.prev = &d->commands;
1446
1378
d->number = ++list->number;
1564
1496
if ((d = find_item(list, arg->a_int)) == NULL) {
1565
1497
/* split into two for easier message translation */
1566
1498
if (list == &display_list)
1567
d_error(_("no display item numbered %ld"),
1499
d_error(_("No display item numbered %ld"),
1570
d_error(_("no watch item numbered %ld"),
1502
d_error(_("No watch item numbered %ld"),
1573
1505
delete_item(d);
1593
1525
sub = d->subs[i];
1594
1526
r = in_array(symbol, sub);
1595
1527
if (r == NULL) {
1596
fprintf(out_fp, _("%d: subscript \"%.*s\" is not in array `%s'\n"),
1597
d->number, (int) sub->stlen, sub->stptr, d->sname);
1528
fprintf(out_fp, _("%d: [\"%s\"] not in array `%s'\n"),
1529
d->number, sub->stptr, d->sname);
1600
1532
if (r->type == Node_var_array) {
1602
1534
if (i == count - 1) /* it's a sub-array */
1603
1535
goto print_sym; /* print # of elements in sub-array */
1605
1537
if (i != count - 1)
1606
1538
return; /* FIXME msg and delete item ? */
1607
fprintf(out_fp, "%d: %s[\"%.*s\"] = ", d->number,
1608
d->sname, (int) sub->stlen, sub->stptr);
1539
fprintf(out_fp, "%d: %s[\"%s\"] = ", d->number,
1540
d->sname, sub->stptr);
1609
1541
valinfo(r, fprintf, out_fp);
1705
1633
/* cmp_val --- compare values of watched item, returns true if different; */
1708
cmp_val(struct list_item *w, NODE *old, NODE *new)
1636
cmp_val(struct list_item *w, NODE *old, NODE *new)
1711
1639
* case old new result
1712
1640
* ------------------------------
1713
* 1: NULL ARRAY true
1641
* 1: NULL ARRAY true
1714
1642
* 2: NULL SCALAR true
1715
1643
* 3: NULL NULL false
1716
1644
* 4: SCALAR SCALAR cmp_node
1717
1645
* 5: SCALAR ARRAY true
1718
1646
* 6: SCALAR NULL true
1719
1647
* 7: ARRAY SCALAR true
1720
* 8: ARRAY ARRAY compare size
1648
* 8: ARRAY ARRAY compare size
1721
1649
* 9: ARRAY NULL true
2412
2337
rp = find_rule(src, ip->source_line);
2413
2338
assert(rp != NULL);
2414
2339
if ((b = set_breakpoint_next(rp, ip)) == NULL)
2415
fprintf(out_fp, _("cannot set breakpoint in file `%s'\n"), src);
2340
fprintf(out_fp, _("Can't set breakpoint in file `%s'\n"), src);
2417
2342
if (cur_frame == 0) { /* stop next time */
2418
2343
b->flags |= BP_IGNORE;
2441
2366
case D_int: /* break lineno */
2442
2367
lineno = (int) arg->a_int;
2443
2368
if (lineno <= 0 || lineno > s->srclines)
2444
d_error(_("line number %d in file `%s' is out of range"), lineno, src);
2369
d_error(_("line number %d in file `%s' out of range"), lineno, src);
2446
2371
rp = find_rule(src, lineno);
2447
2372
if (rp == NULL)
2448
fprintf(out_fp, _("internal error: cannot find rule\n"));
2373
fprintf(out_fp, _("Can't find rule!!!\n"));
2449
2374
if (rp == NULL || (b = set_breakpoint_at(rp, lineno, false)) == NULL)
2450
fprintf(out_fp, _("cannot set breakpoint at `%s':%d\n"),
2375
fprintf(out_fp, _("Can't set breakpoint at `%s':%d\n"),
2452
2377
if (b != NULL && temporary)
2453
2378
b->flags |= BP_TEMP;
2459
2384
func = arg->a_node;
2460
2385
rp = func->code_ptr;
2461
2386
if ((b = set_breakpoint_at(rp, rp->source_line, false)) == NULL)
2462
fprintf(out_fp, _("cannot set breakpoint in function `%s'\n"),
2387
fprintf(out_fp, _("Can't set breakpoint in function `%s'\n"),
2466
b->flags |= BP_TEMP;
2467
lineno = b->bpi->source_line;
2390
b->flags |= BP_TEMP;
2391
lineno = b->bpi->source_line;
2845
2769
if (! read_a_line)
2846
2770
read_a_line = g_readline;
2848
push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
2772
push_cmd_src(input_fd, input_from_tty, read_a_line, 0, 0, EXIT_FATAL);
2850
setbuf(out_fp, (char *) NULL);
2774
setbuf(out_fp, (char *) NULL);
2851
2775
for (cur_srcfile = srcfiles->prev; cur_srcfile != srcfiles;
2852
2776
cur_srcfile = cur_srcfile->prev) {
2853
2777
if (cur_srcfile->stype == SRC_FILE
2870
2794
/* We are restarting; restore state (breakpoints, history etc.)
2871
2795
* passed as environment variables and optionally execute the run command.
2873
unserialize_list(BREAK);
2874
unserialize_list(WATCH);
2875
unserialize_list(DISPLAY);
2876
unserialize_list(HISTORY);
2877
unserialize_list(OPTION);
2799
unserialize(DISPLAY);
2800
unserialize(HISTORY);
2801
unserialize(OPTION);
2878
2802
unsetenv("DGAWK_RESTART");
2879
fprintf(out_fp, _("Restarting ...\n"));
2880
if (strcasecmp(run, "true") == 0)
2803
fprintf(out_fp, "Restarting ...\n");
2881
2805
(void) do_run(NULL, 0);
2883
2807
} else if (command_file != NULL) {
3023
2947
restart(true); /* does not return */
3026
fprintf(out_fp, _("Starting program:\n"));
2950
fprintf(out_fp, _("Starting program: \n"));
3028
2952
prog_running = true;
3029
fatal_tag_valid = 1;
2953
fatal_tag_valid = true;
3030
2954
if (setjmp(fatal_tag) == 0)
3031
2955
(void) interpret(code_block);
3033
fatal_tag_valid = 0;
2957
fatal_tag_valid = false;
3034
2958
prog_running = false;
3035
fprintf(out_fp, (! exiting && exit_val != EXIT_SUCCESS)
3036
? _("Program exited abnormally with exit value: %d\n")
3037
: _("Program exited normally with exit value: %d\n"),
2959
fprintf(out_fp, _("Program exited %s with exit value: %d\n"),
2960
(! exiting && exit_val != EXIT_SUCCESS) ? "abnormally"
3039
2963
need_restart = true;
3286
3210
stop.fcall_count = fcall_count - cur_frame - 1;
3287
3211
assert(stop.fcall_count >= 0);
3288
fprintf(out_fp, _("Run until return from "));
3212
fprintf(out_fp, _("Run till return from "));
3289
3213
print_numbered_frame(cur_frame);
3290
3214
stop.check_func = check_finish;
3291
stop.command = (enum argtype) cmd;
3292
3216
stop.print_ret = true;
3459
3384
stop.fcall_count = fcall_count - cur_frame;
3460
3385
stop.check_func = check_until;
3461
stop.command = (enum argtype) cmd;
3464
3389
if (ip == (rp + 1)->lasti)
3467
fprintf(out_fp, _("cannot find specified location %d in file `%s'\n"),
3392
fprintf(out_fp, _("Can't find specified location %d in file `%s'\n"),
3482
3407
fprintf(out_fp, "%s", w->sname);
3483
3408
for (i = 0; i < w->num_subs; i++) {
3484
3409
sub = w->subs[i];
3485
fprintf(out_fp, "[\"%.*s\"]", (int) sub->stlen, sub->stptr);
3410
fprintf(out_fp, "[\"%s\"]", sub->stptr);
3487
fprintf(out_fp, "\n");
3412
fprintf(out_fp, "\n");
3488
3413
} else if (IS_FIELD(w))
3489
3414
fprintf(out_fp, "$%ld\n", get_number_si(symbol));
3616
3541
stop.command = D_illegal;
3617
3542
stop.check_func = NULL;
3618
3543
fprintf(out_fp, _("'finish' not meaningful with non-local jump '%s'\n"),
3619
op2str(pc->opcode));
3544
op2str(pc->opcode));
3620
3545
} else if (stop.command == D_until) {
3621
3546
/* cancel until command */
3622
3547
stop.print_frame = false;
3623
3548
stop.command = D_illegal;
3624
3549
stop.check_func = NULL;
3625
3550
fprintf(out_fp, _("'until' not meaningful with non-local jump '%s'\n"),
3626
op2str(pc->opcode));
3551
op2str(pc->opcode));
3729
3654
assert(sourceline > 0);
3732
* 11/2015: This used to check breakpoints first, but that could
3733
* produce strange behavior, where a watchpoint doesn't print until
3734
* some time after the data changed. This reworks things so that
3735
* watchpoints are checked first. It's a bit of a hack, but
3736
* the behavior for the user is more logical.
3738
if (check_watchpoint()) {
3739
next_command(); /* return to debugger interface */
3740
if (stop.command == D_return)
3741
*pi = stop.pc; /* jump to this instruction */
3742
else if (cur_pc->opcode == Op_breakpoint)
3743
cur_pc = cur_pc->nexti; /* skip past the breakpoint instruction */
3744
} else if (check_breakpoint(pi)
3656
if (check_breakpoint(pi)
3657
|| check_watchpoint()
3745
3658
|| (stop.check_func && stop.check_func(pi))) {
3746
3659
next_command(); /* return to debugger interface */
3747
3660
if (stop.command == D_return)
3774
3687
print_func(fp, "%g", m->numbr);
3775
3688
} else if ((m->flags & STRING) != 0)
3776
3689
pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
3777
else if ((m->flags & REGEX) != 0) {
3778
print_func(fp, "@");
3779
pp_string_fp(print_func, fp, m->stptr, m->stlen, '/', false);
3690
else if ((m->flags & NUMCUR) != 0) {
3692
if ((m->flags & MPFN) != 0)
3693
print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr));
3694
else if ((m->flags & MPZN) != 0)
3695
print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i));
3698
print_func(fp, "%g", m->numbr);
3699
} else if ((m->flags & STRCUR) != 0)
3700
pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', false);
3781
3702
print_func(fp, "-?-");
3782
3703
print_func(fp, " [%s]", flags2str(m->flags));
3847
3764
print_func(fp, "\n");
3849
3766
if (pc->source_line <= 0)
3850
print_func(fp, "[ :" PTRFMT "] %-20.20s: ", pc, opcode2str(pc->opcode));
3767
print_func(fp, "[ :%p] %-20.20s: ", pc, opcode2str(pc->opcode));
3852
print_func(fp, "[%6d:" PTRFMT "] %-20.20s: ",
3769
print_func(fp, "[%6d:%p] %-20.20s: ",
3853
3770
pc->source_line, pc, opcode2str(pc->opcode));
3855
3772
if (prog_running && ! in_dump) {
3857
3774
func = find_frame(0)->func_node;
3861
3778
switch (pc->opcode) {
3863
print_func(fp, "[branch_if = " PTRFMT "] [branch_else = " PTRFMT "] [branch_else->lasti = " PTRFMT "]\n",
3864
pc->branch_if, pc->branch_else, pc->branch_else->lasti);
3868
print_func(fp, "[branch_end = " PTRFMT "]\n", pc->branch_end);
3872
print_func(fp, "[while_body = " PTRFMT "] [target_break = " PTRFMT "]\n", (pc+1)->while_body, pc->target_break);
3876
print_func(fp, "[doloop_cond = " PTRFMT "] [target_break = " PTRFMT "]", (pc+1)->doloop_cond, pc->target_break);
3878
print_func(fp, " [comment = " PTRFMT "]", pc->comment);
3879
print_func(fp, "\n");
3881
print_instruction(pc->comment, print_func, fp, in_dump);
3885
print_func(fp, "[forloop_cond = " PTRFMT "] ", (pc+1)->forloop_cond);
3888
print_func(fp, "[forloop_body = " PTRFMT "] ", (pc+1)->forloop_body);
3889
print_func(fp, "[target_break = " PTRFMT "] [target_continue = " PTRFMT "]", pc->target_break, pc->target_continue);
3890
if (pc->comment != NULL) {
3891
print_func(fp, " [comment = " PTRFMT "]\n", (pc)->comment);
3892
print_instruction(pc->comment, print_func, fp, in_dump);
3894
print_func(fp, "\n");
3899
bool need_newline = false;
3900
print_func(fp, "[switch_start = " PTRFMT "] [switch_end = " PTRFMT "]\n", (pc+1)->switch_start, (pc+1)->switch_end);
3901
if (pc->comment || (pc+1)->switch_end->comment)
3902
print_func(fp, "%*s", noffset, "");
3904
print_func(fp, "[start_comment = " PTRFMT "]", pc->comment);
3905
need_newline = true;
3907
if ((pc+1)->switch_end->comment) {
3908
print_func(fp, "[end_comment = " PTRFMT "]", (pc + 1)->switch_end->comment);
3909
need_newline = true;
3912
print_func(fp, "\n");
3914
print_instruction(pc->comment, print_func, fp, in_dump);
3915
if ((pc+1)->switch_end->comment)
3916
print_instruction((pc+1)->switch_end->comment, print_func, fp, in_dump);
3921
print_func(fp, "[stmt_start = " PTRFMT "] [stmt_end = " PTRFMT "]", pc->stmt_start, pc->stmt_end);
3923
print_func(fp, " [comment = " PTRFMT "]\n", pc->comment);
3924
print_instruction(pc->comment, print_func, fp, in_dump);
3926
print_func(fp, "\n");
3929
3779
case Op_var_update:
3930
3780
print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var));
3945
3795
case Op_field_spec_lhs:
3946
print_func(fp, "[target_assign = " PTRFMT "] [do_reference = %s]\n",
3796
print_func(fp, "[target_assign = %p] [do_reference = %s]\n",
3947
3797
pc->target_assign, pc->do_reference ? "true" : "false");
3951
print_func(fp, "[param_cnt = %d] [source_file = %s]", pcount,
3801
print_func(fp, "[param_cnt = %d] [source_file = %s]\n", pcount,
3952
3802
pc->source_file ? pc->source_file : "cmd. line");
3953
if (pc[3].nexti != NULL) {
3954
print_func(fp, "[ns_list = " PTRFMT "]\n", pc[3].nexti);
3955
print_ns_list(pc[3].nexti, print_func, fp, in_dump);
3957
print_func(fp, "\n");
3960
3805
case Op_K_getline_redir:
3989
3834
case Op_K_nextfile:
3990
print_func(fp, "[target_newfile = " PTRFMT "] [target_endfile = " PTRFMT "]\n",
3835
print_func(fp, "[target_newfile = %p] [target_endfile = %p]\n",
3991
3836
pc->target_newfile, pc->target_endfile);
3994
3839
case Op_newfile:
3995
print_func(fp, "[target_jmp = " PTRFMT "] [target_endfile = " PTRFMT "]\n",
3840
print_func(fp, "[target_jmp = %p] [target_endfile = %p]\n",
3996
3841
pc->target_jmp, pc->target_endfile);
3997
print_func(fp, "%*s[target_get_record = " PTRFMT "]\n",
3842
print_func(fp, "%*s[target_get_record = %p]\n",
3998
3843
noffset, "", (pc + 1)->target_get_record);
4001
3846
case Op_get_record:
4002
print_func(fp, "[target_newfile = " PTRFMT "]\n", pc->target_newfile);
3847
print_func(fp, "[target_newfile = %p]\n", pc->target_newfile);
4011
3856
case Op_arrayfor_init:
4012
3857
case Op_K_break:
4013
3858
case Op_K_continue:
4014
print_func(fp, "[target_jmp = " PTRFMT "]\n", pc->target_jmp);
3859
print_func(fp, "[target_jmp = %p]\n", pc->target_jmp);
4017
3861
case Op_K_exit:
4018
print_func(fp, "[target_end = " PTRFMT "] [target_atexit = " PTRFMT "]\n",
3862
print_func(fp, "[target_end = %p] [target_atexit = %p]\n",
4019
3863
pc->target_end, pc->target_atexit);
4022
3866
case Op_K_case:
4023
print_func(fp, "[target_jmp = " PTRFMT "] [match_exp = %s]",
3867
print_func(fp, "[target_jmp = %p] [match_exp = %s]\n",
4024
3868
pc->target_jmp, (pc + 1)->match_exp ? "true" : "false");
4026
print_func(fp, " [comment = " PTRFMT "]\n", pc->comment);
4027
print_instruction(pc->comment, print_func, fp, in_dump);
4029
print_func(fp, "\n");
4032
case Op_K_namespace:
4033
print_func(fp, "[namespace = %s]", pc->ns_name);
4035
print_func(fp, "[nexti = " PTRFMT "]", pc->nexti);
4037
print_func(fp, "[comment = " PTRFMT "]", pc->comment);
4038
print_func(fp, "\n");
4041
3871
case Op_arrayfor_incr:
4042
print_func(fp, "[array_var = %s] [target_jmp = " PTRFMT "]\n",
3872
print_func(fp, "[array_var = %s] [target_jmp = %p]\n",
4043
3873
pc->array_var->type == Node_param_list ?
4044
3874
func->fparms[pc->array_var->param_cnt].param : pc->array_var->vname,
4045
3875
pc->target_jmp);
4048
3878
case Op_line_range:
4049
print_func(fp, "[triggered = %ld] [target_jmp = " PTRFMT "]\n",
3879
print_func(fp, "[triggered = %ld] [target_jmp = %p]\n",
4050
3880
pc->triggered, pc->target_jmp);
4053
3883
case Op_cond_pair:
4054
print_func(fp, "[line_range = " PTRFMT "] [target_jmp = " PTRFMT "]\n",
3884
print_func(fp, "[line_range = %p] [target_jmp = %p]\n",
4055
3885
pc->line_range, pc->target_jmp);
4109
3939
case Op_concat:
4110
/* NB: concat_flag CSVAR only used in grammar, don't display it */
3940
/* NB: concat_flag CSVAR only used in grammar, don't display it */
4111
3941
print_func(fp, "[expr_count = %ld] [concat_flag = %s]\n",
4112
3942
pc->expr_count,
4113
3943
(pc->concat_flag & CSUBSEP) != 0 ? "CSUBSEP" : "0");
4117
print_func(fp, "[in_rule = %s] [source_file = %s]",
3947
print_func(fp, "[in_rule = %s] [source_file = %s]\n",
4118
3948
ruletab[pc->in_rule],
4119
3949
pc->source_file ? pc->source_file : "cmd. line");
4120
if (pc[3].nexti != NULL) {
4121
print_func(fp, "[ns_list = " PTRFMT "]\n", pc[3].nexti);
4122
print_ns_list(pc[3].nexti, print_func, fp, in_dump);
4124
print_func(fp, "\n");
4153
3978
print_func(fp, " [do_reference = %s]\n",
4154
3979
pc->do_reference ? "true" : "false");
4158
print_memory(pc->memory, func, print_func, fp);
4159
print_func(fp, " [comment_type = %s]",
4160
pc->memory->comment_type == EOL_COMMENT ?
4163
print_func(fp, " [comment = " PTRFMT "]\n", pc->comment);
4164
print_instruction(pc->comment, print_func, fp, in_dump);
4166
print_func(fp, "\n");
4169
3982
case Op_push_i:
4171
3984
case Op_push_arg:
4172
case Op_push_arg_untyped:
4173
3985
case Op_push_param:
4174
3986
case Op_push_array:
4175
3987
case Op_push_re:
4218
/* print_ns_list --- print the list of namespaces */
4221
print_ns_list(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump)
4223
for (; pc != NULL; pc = pc->nexti) {
4224
print_instruction(pc, print_func, fp, in_dump);
4225
if (pc->comment != NULL)
4226
print_instruction(pc->comment, print_func, fp, in_dump);
4230
4030
/* do_dump_instructions --- dump command */
4383
4183
if (os_isatty(fileno(fp)) && input_fd == 0)
4384
4184
quit_pager = prompt_yes_no(
4385
// TRANSLATORS: don't translate the 'q' inside the brackets.
4386
_("\t------[Enter] to continue or [q] + [Enter] to quit------"),
4185
_("\t------[Enter] to continue or q [Enter] to quit------"),
4186
_("q")[0], false, fp);
4388
4187
if (quit_pager)
4389
4188
longjmp(pager_quit_tag, 1);
4390
4189
pager_lines_printed = 0;
4393
/* gprintf --- like fprintf but allows paging */
4192
/* gprintf --- like fprintf but allows paging */
4396
4195
gprintf(FILE *fp, const char *format, ...)
4405
4204
#define GPRINTF_BUFSIZ 512
4406
4205
if (buf == NULL) {
4407
4206
buflen = GPRINTF_BUFSIZ;
4408
emalloc(buf, char *, buflen * sizeof(char), "gprintf");
4207
emalloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4409
4208
} else if (buflen - bl < GPRINTF_BUFSIZ/2) {
4410
4209
buflen += GPRINTF_BUFSIZ;
4411
erealloc(buf, char *, buflen * sizeof(char), "gprintf");
4210
erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4413
4212
#undef GPRINTF_BUFSIZ
4416
4215
va_start(args, format);
4417
4216
nchar = vsnprintf(buf + bl, buflen - bl, format, args);
4428
/* enlarge buffer, and try again */
4227
/* enlarge buffer, and try again */
4430
erealloc(buf, char *, buflen * sizeof(char), "gprintf");
4229
erealloc(buf, char *, (buflen + 2) * sizeof(char), "gprintf");
4434
4233
for (p = buf; (q = strchr(p, '\n')) != NULL; p = q + 1) {
4435
int sz = (int) (q - p);
4234
int sz = (int) (q - p);
4437
4236
while (sz > 0) {
4478
4277
else if (nchar >= buflen) /* need larger buffer */
4481
4280
for (i = 0; i < item->num_subs; i++) {
4482
4281
sub = item->subs[i];
4483
nchar = snprintf(buf + bl, buflen - bl, "%lu%c%.*s%c",
4484
(unsigned long) sub->stlen, FSEP,
4485
(int) sub->stlen, sub->stptr, FSEP);
4282
nchar = snprintf(buf + bl, buflen - bl, "%lu%c%s%c",
4283
(unsigned long) sub->stlen, FSEP, sub->stptr, FSEP);
4486
4284
if (nchar <= 0)
4669
4467
if (nchar > 0) { /* non-empty commands list */
4670
nchar += (strlen("commands ") + 20 /*cnum*/ + 1 /*CSEP*/ + strlen("end") + 1 /*FSEP*/);
4671
if (nchar >= buflen - bl) {
4672
buflen = bl + nchar + 1 /*RSEP*/;
4673
erealloc(buf, char *, buflen + 1, "serialize_list");
4468
nchar += (strlen("commands ") + 20 + strlen("end") + 2); /* 20 for cnum (an int) */
4469
if (nchar > buflen - bl) {
4470
buflen = bl + nchar;
4471
erealloc(buf, char *, buflen + 3, "serialize");
4675
4473
nchar = sprintf(buf + bl, "commands %d", cnum);
4696
4494
nchar = strlen("end"); /* end of 'commands' */
4697
4495
memcpy(buf + bl, "end", nchar);
4699
buf[bl++] = FSEP; /* field */
4498
buf[bl++] = FSEP; /* field */
4701
4499
buf[bl++] = RSEP; /* record */
4702
4500
buf[bl] = '\0';
4704
/* condition expression */
4502
/* condition expression */
4705
4503
if (cndn->expr) {
4706
4504
bl--; /* undo RSEP from above */
4707
4505
nchar = strlen(cndn->expr);
4708
if (nchar + 1 /*FSEP*/ >= buflen - bl) {
4709
buflen = bl + nchar + 1 /*FSEP*/ + 1 /*RSEP*/;
4710
erealloc(buf, char *, buflen + 1, "serialize_list");
4506
if (nchar > buflen - bl) {
4507
buflen = bl + nchar;
4508
erealloc(buf, char *, buflen + 3, "serialize");
4712
4510
memcpy(buf + bl, cndn->expr, nchar);
4858
4656
if (field_cnt > 6) /* unserialize breakpoint `commands' */
4859
4657
unserialize_commands(pstr[6], pstr_len[6]);
4861
if (field_cnt > 7) { /* condition expression */
4659
if (field_cnt > 7) { /* condition expression */
4863
4661
expr = estrdup(pstr[7], pstr_len[7]);
4864
4662
if (parse_condition(D_break, b->number, expr) != 0)
5193
4991
if (value == NULL)
5194
4992
tmp[i] = Nnull_string; /* FIXME: goto done ? */
5195
4993
else if (value->type == Node_var_array) {
5196
d_error(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
5197
name, (int) subs->stlen, subs->stptr);
4994
d_error(_("attempt to use array `%s[\"%s\"]' in a scalar context"),
5200
4998
tmp[i] = value;
5202
5000
if (value == NULL) {
5203
d_error(_("[\"%.*s\"] not in array `%s'"),
5204
(int) subs->stlen, subs->stptr, name);
5001
d_error(_("[\"%s\"] not in array `%s'"),
5206
5004
} else if (value->type != Node_var_array) {
5207
d_error(_("attempt to use scalar `%s[\"%.*s\"]' as array"),
5208
name, (int) subs->stlen, subs->stptr);
5005
d_error(_("attempt to use scalar `%s[\"%s\"]' as array"),
5228
5026
PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5229
5027
if (setjmp(fatal_tag) == 0)
5230
r = format_args(tmp[0]->stptr, tmp[0]->stlen, tmp, i);
5028
r = format_tree(tmp[0]->stptr, tmp[0]->stlen, tmp, i);
5232
5030
/* fatal error, restore exit_val of program */
5233
5031
exit_val = EXIT_SUCCESS;
5403
5201
setbuf(fp, (char *) NULL);
5404
5202
output_is_tty = os_isatty(fileno(fp));
5406
d_error(_("could not open `%s' for writing: %s"),
5204
d_error(_("could not open `%s' for writing (%s)"),
5408
5206
errno != 0 ? strerror(errno) : _("reason unknown"));
5409
5207
fprintf(out_fp, _("sending output to stdout\n"));
5416
5214
set_prompt(const char *value)
5418
efree((void *) dgawk_prompt);
5216
efree(dgawk_prompt);
5419
5217
dgawk_prompt = estrdup(value, strlen(value));
5420
5218
dbg_prompt = dgawk_prompt;
5423
/* set_option_flag --- convert option string to flag value */
5221
/* set_option_flag --- convert option string to flag value */
5426
5224
set_option_flag(const char *value)
5550
bool stdio_problem, got_EPIPE;
5551
5349
struct command_source *cs;
5553
5351
(void) nextfile(& curfile, true); /* close input data file */
5554
(void) close_io(& stdio_problem, & got_EPIPE);
5352
(void) close_io(& stdio_problem);
5555
5353
if (cur_srcfile->fd != INVALID_HANDLE) {
5556
5354
close(cur_srcfile->fd);
5557
5355
cur_srcfile->fd = INVALID_HANDLE;
5610
5408
volatile NODE *r = NULL;
5611
5409
volatile jmp_buf fatal_tag_stack;
5612
// long save_stack_size; // see comment below
5410
long save_stack_size;
5613
5411
int save_flags = do_flags;
5615
5413
/* We use one global stack for all contexts.
5616
5414
* Save # of items in stack; in case of
5617
5415
* a fatal error, pop stack until it has that many items.
5620
// save_stack_size = (stack_ptr - stack_bottom) + 1; // see comment below
5418
save_stack_size = (stack_ptr - stack_bottom) + 1;
5621
5419
do_flags = false;
5623
5421
PUSH_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5624
5422
if (setjmp(fatal_tag) == 0) {
5625
5423
(void) interpret((INSTRUCTION *) code);
5626
5424
r = POP_SCALAR();
5627
} else { /* fatal error */
5630
* Initially, the code did this:
5632
* (void) unwind_stack(save_stack_size);
5634
* to attempt to recover and keep going. But a fatal error
5635
* can corrupt memory. Instead of trying to recover, just
5638
// Let the user know, but DON'T use the fatal() function!
5639
fprintf(stderr, _("fatal error during eval, need to restart.\n"));
5640
// Go back to debugger
5641
restart(false); // does not return
5425
} else /* fatal error */
5426
(void) unwind_stack(save_stack_size);
5644
5428
POP_BINDING(fatal_tag_stack, fatal_tag, fatal_tag_valid);
5645
5429
do_flags = save_flags;
5664
5448
int ecount = 0, pcount = 0;
5666
5450
int save_flags = do_flags;
5667
SRCFILE *the_source;
5669
5452
if (prog_running) {
5670
5453
this_frame = find_frame(0);
5671
5454
this_func = this_frame->func_node;
5674
install_params(this_func); /* expose current function parameters to eval */
5457
install_params(this_func); /* expose current function parameters to eval */
5675
5458
ctxt = new_context();
5676
5459
ctxt->install_func = append_symbol; /* keep track of newly installed globals */
5677
5460
push_context(ctxt);
5678
the_source = add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
5679
do_flags &= DO_MPFR; // preserve this flag only
5680
ret = parse_program(&code, true);
5461
(void) add_srcfile(SRC_CMDLINE, arg->a_string, srcfiles, NULL, NULL);
5463
ret = parse_program(&code);
5681
5464
do_flags = save_flags;
5682
5465
remove_params(this_func);
5683
5466
if (ret != 0) {
5684
5467
pop_context(); /* switch to prev context */
5685
5468
free_context(ctxt, false /* keep_globals */);
5687
/* Remove @eval from FUNCTAB. */
5688
NODE *s = make_string("@eval", 5);
5689
(void) assoc_remove(func_table, s);
5782
5559
this_func->param_cnt -= ecount;
5786
* Always destroy symbol "@eval", however destroy all newly installed
5562
/* always destroy symbol "@eval", however destroy all newly installed
5787
5563
* globals only if fatal error (execute_code() returing NULL).
5790
5566
pop_context(); /* switch to prev context */
5791
5567
free_context(ctxt, (ret_val != NULL)); /* free all instructions and optionally symbols */
5793
if (ret_val != NULL) {
5795
* Remove @eval from FUNCTAB, so that above code
5796
* will work the next time around.
5798
NODE *s = make_string("@eval", 5);
5800
(void) assoc_remove(func_table, s);
5807
free_srcfile(the_source);
5568
if (ret_val != NULL)
5569
destroy_symbol(f); /* destroy "@eval" */
5869
5630
push_context(ctxt);
5870
5631
(void) add_srcfile(SRC_CMDLINE, expr, srcfiles, NULL, NULL);
5871
5632
do_flags = false;
5872
ret = parse_program(&code, true);
5633
ret = parse_program(&code);
5873
5634
do_flags = save_flags;
5874
remove_params(this_func);
5635
remove_params(this_func);
5877
5638
if (ret != 0 || invalid_symbol) {