aboutsummaryrefslogtreecommitdiff
path: root/pkg/ecl/debug.c
blob: a8d0087ca13fd7b035b2b9c74c284c339002c34e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
 */

#define import_spp
#define import_libc
#define import_stdio
#include <iraf.h>

#include "config.h"
#include "operand.h"
#include "mem.h"
#include "grammar.h"
#include "opcodes.h"
#include "param.h"
#include "task.h"
#include "proto.h"


/*
 * DEBUG -- The various debugging functions.
 *
 * the D_XXX grammar rules use the d_xxx routines to dump various tables
 * for debugging purposes.
 * some of these (see setbuiltins()) are done as builtin ltasks, while others
 *   that show dictionary or stack info are not to avoid the complication of
 *   having to work around the fact that builtins are really separate tasks.
 * all write to stderr.
 */

extern	char *nullstr;
extern	int cldebug;
extern	int cltrace;
static	void dd_f();


/* D_STACK -- Go through the instruction stack, starting at locpc, printing
 * what is found until END opcode discovered.  If ss > 0, just go through ss
 * instructions.  Done directly.
 */
static	int	pc_mark = 0;

void 
d_asmark (void) 
{ 
	/* Mark the PC to begin the instruction output.  If not defined,
	 * do the whole script.
	 */
	pc_mark  = pc; 
}


void 
d_assemble (void) 
{ 
	d_stack ((pc_mark ? pc_mark : pc), 0, pc); 
	pc_mark = 0; 
}

void 
d_stack (register XINT locpc, int ss, int endpc)
{
	register struct codeentry *cep;
	int n, opcode, errs = 0;
	
	do {
	    cep = coderef (locpc);
	    opcode = cep->c_opcode;

	    if ((n = d_instr (stderr, "", locpc)) <= 0) {
		errs++;
		locpc += (SZ_CE - 1);
	    } else
		locpc += n;

	    if (ss > 0 && --ss == 0)		/* ss > 0 done first!	*/
		errs = 100;			/* simulate end		*/

	    if (endpc > 0 && locpc > (endpc - SZ_CE))
		break;

	} while (opcode != END && errs < 10);
}


/* D_INSTR -- Decode a single instruction on the output file.  The length of
 * the instruction in memel is returned as the function value.
 */
int 
d_instr (FILE *fp, char *prefix, register XINT locpc)
{
	register struct codeentry *cep;
	int opcode, extra=0;

	cep = coderef (locpc);
	opcode = cep->c_opcode;

	if (prefix[0] == '\t') {
	    if (cltrace > 1) {
		/* For verbose output, get the filename. */
	        fprintf (fp, "    %4d:%s  %6d+%d:\t", cep->c_scriptln,
		    currentask->t_ltp->lt_pname,
	            locpc, cep->c_length);
	    } else {
	        fprintf (fp, "    %4d  %6d+%d:\t", cep->c_scriptln,
	            locpc, cep->c_length);
	    }
	} else
	    fprintf (fp, "%s  %4d  %6d+%d:\t", prefix, cep->c_scriptln,
	        locpc, cep->c_length);


	switch (opcode) {
	case ABSARGSET:   fprintf (fp, "absargset");	goto string;
	case ADDASSIGN:   fprintf (fp, "addassign");	goto string;
	case ASSIGN:	  fprintf (fp, "assign\t");	goto string;
	case CALL:	  fprintf (fp, "call\t");	goto string;
	case CATASSIGN:	  fprintf (fp, "catassign");	goto string;
	case DIVASSIGN:	  fprintf (fp, "divassign");	goto string;
	case GSREDIR:	  fprintf (fp, "gsredir");	goto string;
	case INDIRABSSET: fprintf (fp, "indirabsset");	goto string;
	case INSPECT:	  fprintf (fp, "inspect\t");	goto string;
	case INTRINSIC:	  fprintf (fp, "intrinsic");	goto string;
	case MULASSIGN:	  fprintf (fp, "mulassign");	goto string;
	case OSESC:	  fprintf (fp, "os_escape");	goto string;
	case PUSHPARAM:	  fprintf (fp, "pushparam");	goto string;
	case SUBASSIGN:	  fprintf (fp, "subassign");	goto string;
	case SWOFF:	  fprintf (fp, "swoff\t");	goto string;
	case SWON:	  fprintf (fp, "swon");		goto string;
string:
	    fprintf (fp, "\t%s\n", (char *)&cep->c_args);
	    break;

	case PUSHCONST:	  fprintf (fp, "pushconst"); goto op;
op:
	    {   struct operand *op;

		op = (struct operand *) &cep->c_args;
		fprintf (fp, "\t");
		if ((op->o_type & OT_BASIC) == OT_STRING)
		    fprintf (fp, "`");
		fprop (stderr, op);
		if ((op->o_type & OT_BASIC) == OT_STRING)
		    fprintf (fp, "'");
		fprintf (fp, "\n");
	    }
	    break;

	case ADD:	  fprintf (fp, "add\n"); 	break;
	case ADDPIPE:	  fprintf (fp, "addpipe\n"); 	break;
	case ALLAPPEND:	  fprintf (fp, "allappend\n"); 	break;
	case ALLREDIR:	  fprintf (fp, "allredir\n"); 	break;
	case AND:	  fprintf (fp, "and\n"); 	break;
	case APPENDOUT:	  fprintf (fp, "append\n"); 	break;
	case CHSIGN:	  fprintf (fp, "chsign\n"); 	break;
	case CONCAT:	  fprintf (fp, "concat\n"); 	break;
	case DEFAULT:     fprintf (fp, "default\n"); 	break;
	case DIV:	  fprintf (fp, "div\n"); 	break;
	case END:	  fprintf (fp, "end\n"); 	break;
	case EQ:	  fprintf (fp, "eq\n"); 	break;
	case EXEC:	  fprintf (fp, "exec\n"); 	break;
	case FSCAN:	  fprintf (fp, "fscan\n"); 	break;
	case FSCANF:	  fprintf (fp, "fscanf\n"); 	break;
	case GE:	  fprintf (fp, "ge\n"); 	break;
	case GETPIPE:	  fprintf (fp, "getpipe\n"); 	break;
	case GT:	  fprintf (fp, "gt\n"); 	break;
	case IMMED:	  fprintf (fp, "immed\n"); 	break;
	case LE:	  fprintf (fp, "le\n"); 	break;
	case LT:	  fprintf (fp, "lt\n"); 	break;
	case MUL:	  fprintf (fp, "mul\n"); 	break;
	case NE:	  fprintf (fp, "ne\n"); 	break;
	case NOT:	  fprintf (fp, "not\n"); 	break;
	case OR:	  fprintf (fp, "or\n"); 	break;
	case POW:	  fprintf (fp, "pow\n"); 	break;
	case PRINT:	  fprintf (fp, "print\n"); 	break;
	case REDIR:	  fprintf (fp, "redir\n"); 	break;
	case REDIRIN:	  fprintf (fp, "redirin\n"); 	break;
	case RETURN:	  fprintf (fp, "return\n"); 	break;
	case SCAN:	  fprintf (fp, "scan\n"); 	break;
	case SCANF:	  fprintf (fp, "scanf\n"); 	break;
	case SUB:	  fprintf (fp, "sub\n"); 	break;
	case SWITCH:      fprintf (fp, "switch\n"); 	break;

	case BIFF:	  fprintf (fp, "biff\t"); 	goto offset;
	case GOTO:	  fprintf (fp, "goto\t"); 	goto offset;
offset:
	    /* Print offset with sign, - or +, in all cases. */
	    if ((int)cep->c_args <= 0)
		goto oneint;	/* pick up sign there	*/
	    else
		 fprintf (fp, "\t+%d\n", cep->c_args);
	    break;

	case CASE:        fprintf (fp, "case\t"); 	goto oneint;
	case INDIRPOSSET: fprintf (fp, "indirposset"); 	goto oneint;
	case POSARGSET:	  fprintf (fp, "posargset"); 	goto oneint;
	case RMPIPES:	  fprintf (fp, "rmpipes\t"); 	goto oneint;
oneint:
	    fprintf (fp, "\t%d\n", cep->c_args);
	    break;

	/* Used for arrays. */
	case PUSHINDEX:   fprintf (fp, "pushindex"); 	goto oneint;
	case INDXINCR:    fprintf (fp, "indxincr");
	    /* Output two jump offsets. */
	     fprintf (fp, "\t%d, %d\t", cep->c_args, *(&cep->c_args+1));

	    /* Output array index ranges: {beg, end} * N. */
	    {   memel *ip = (memel *) &cep->c_args;
		int i, n = (int)ip[2];
		for (ip += 2, i=0;  i < n;  i++, ip += 2)
		    fprintf (fp, "%d:%d ", (XINT)*ip, (XINT)(*ip+1));
		fprintf (fp, "\n");
		extra = 2*n + 1;
	    }
	    break;

	default:
	    fprintf (fp, "bad opcode, %d, at pc %d\n", opcode, locpc);
	    return (-1);
	}

	return (cep->c_length + extra);
}


/* print neat things about the dictionary and stack.
 * done directly.
 */
void 
d_d (void)
{
	char *stackaddr = (char *)stack;  /*  just so we may subtract	*/
	char *otheraddr;


	eprintf ("\ndictionary indices:\n");
	eprintf ("\tmaxd-1\t%u (%u)\n", maxd-1, dictionary[maxd-1]);
	eprintf ("\ttopd\t%u (%u)\n", topd, dictionary[topd]);
	eprintf ("\tpachead\t%u (`%s')\n", pachead,
	    reference (package, pachead)->pk_name);
	eprintf ("\tparhead\t%u (`%s')\n", parhead,
	    reference (pfile, parhead)->pf_ltp->lt_lname);

	eprintf ("\ndictionary pointers (shown as indices)\n");
	eprintf ("\tcurpack\t%u (`%s')\n", dereference (curpack),
	    curpack->pk_name);
	eprintf ("\tdictionary\t%u\n", dictionary);

	eprintf ("\nstack indices\n");
	eprintf ("\ttopcs\t%d\n", topcs);
	eprintf ("\ttopos\t%d\n", topos);
	eprintf ("\tbasos\t%d\n", basos);
	eprintf ("\tpc\t%d\n", pc);
	otheraddr = (char *)currentask;
	eprintf ("\tcurrentask\t%u (`%s')\n", btoi (otheraddr - stackaddr),
	    currentask->t_ltp->lt_lname);
	otheraddr = (char *)firstask;
	eprintf ("\tfirstask\t%u (`%s')\n", btoi (otheraddr - stackaddr),
	    firstask->t_ltp->lt_lname);
}


/* print all loaded pfiles and their params from parhead.
 * done as a builtin task. depends on the fact that the fake param file
 * has been unlinked from parhead before the builtin is run to avoid showing
 * it. see execnewtask().
 */
void 
d_p (void)
{
	register struct pfile *pfp;
	register struct param *pp;
	register FILE *fp;
	int flags;

	fp = currentask->t_stderr;
	eprintf ("loaded parameter files -\n");
	for (pfp = reference (pfile, parhead); pfp; pfp = pfp->pf_npf) {
	    eprintf ("\n\t%s: ", pfp->pf_ltp->lt_lname);
	    flags = pfp->pf_flags;
	    if (flags & PF_UPDATE) eprintf ("updated, ");
	    if (flags & PF_FAKE) eprintf ("fake, ");
	    if (flags & PF_COPY) eprintf ("copy, ");
	    if (flags & PF_PSETREF) eprintf ("contains pset pars, ");
	    eprintf ("\n");
	    for (pp = pfp->pf_pp; pp != NULL; pp = pp->p_np)
		printparam (pp, fp);
	}
}


/* print info about the tasks currently on the control stack.
 * done as a builtin. no attempt is made to hide the task running for this 
 * builtin.
 */
void 
d_t (void)
{
	struct task *tp;
	int    flags;

	eprintf ("stacked tasks (most recent first)\n\n");
	for (tp=currentask; (XINT)tp<(XINT)&stack[STACKSIZ]; tp=next_task(tp)) {
	    flags = tp->t_flags;
	    eprintf ("%s:\t", tp->t_ltp->lt_lname);
	    if (flags & T_SCRIPT) eprintf ("script, ");
	    if (flags & T_CL) eprintf ("cl, ");
	    if (flags & T_INTERACTIVE) eprintf ("interactive, ");
	    if (flags & T_MYOUT) eprintf ("new out, ");
	    if (flags & T_MYIN) eprintf ("new in, ");
	    if (flags & T_MYERR) eprintf ("new err, ");
	    if (flags & T_MYSTDGRAPH) eprintf ("new stdgraph, ");
	    if (flags & T_MYSTDIMAGE) eprintf ("new stdimage, ");
	    if (flags & T_MYSTDPLOT) eprintf ("new stdplot, ");
	    if (flags & T_BUILTIN)
		eprintf ("builtin, ");
	    else
		eprintf ("mode = `%s' ", tp->t_modep->p_val.v_s);
	    eprintf ("\n");
	}
}


/* print all loaded packages and their ltasks from pachead.
 * builtin.
 */
void 
d_l (void)
{
	register struct package *pkp;
	register struct ltask *ltp;
	int flags;

	eprintf ("loaded packages -\n");
	for (pkp = reference (package,pachead); pkp; pkp = pkp->pk_npk) {
	    eprintf ("(%u) package `%s':\n", pkp, pkp->pk_name);
	    for (ltp = pkp->pk_ltp; ltp != NULL; ltp = ltp->lt_nlt) {
		flags = ltp->lt_flags;
		eprintf ("\t(%u)\t%s: ", ltp, ltp->lt_lname);
		if (flags & LT_BUILTIN)
		    eprintf ("builtin, ");
		else
		    eprintf ("in %s (%d), ", ltp->lt_pname,
			ltp->lt_pname);
		if (flags & LT_SCRIPT) eprintf ("script, ");
		if (!(flags & LT_PFILE)) eprintf ("no pfile, ");
		if (flags & LT_STDINB) eprintf ("b_in, ");
		if (flags & LT_STDOUTB) eprintf ("b_out, ");
		if (flags & LT_INVIS) eprintf ("invisible, ");
		eprintf ("\n");
	    }
	}
}


/* D_F -- Determine the number of logical (e.g. dev$null, stropen) and physical
 * (host system) file slots available.
 */
void 
d_f (void)
{
	dd_f ("logical:  ", "dev$null");
	dd_f ("physical: ", "hlib$iraf.h");
}

static void
dd_f (char *msg, char *fname)
{
	FILE	*fp[128];
	int	fn;

	eprintf (msg);
	fn = 0;
	while ((fp[fn] = fopen (fname, "r")) != NULL) {
	    eprintf ("%d,", fileno(fp[fn]));
	    if (++fn >= 128)
		break;
	}
	eprintf ("\n");
	while (fn > 0)
	    fclose (fp[--fn]);
}


/* enable debugging messages.
 * builtins.
 */
void 
d_on (void)
{
	cldebug = 1;
}

/* disable debugging.
 */
void 
d_off (void)
{
	cldebug = 0;
}

/* Enable/disable instruction tracing.
 */
void 
d_trace (int value)
{
	cltrace = value;
}


/* Dump operand stack until underflow occurs.
 */
void 
e_dumpop (void)
{
	struct	operand o;

	forever {
	    o = popop();
	    oprop (&o);
	}
}


/* Format a multiline exec-task message string for debug output.
 */
void 
d_fmtmsg (FILE *fp, char *prefix, char *message, int width)
{
	register char *ip, *op, *cp;
	char lbuf[SZ_COMMAND], obuf[SZ_COMMAND];
	int len_prefix, nchars;

	len_prefix = strlen (prefix);

	for (ip=message, op=obuf;  *ip;  ) {
	    /* Get next message line. */
	    for (cp=lbuf, nchars=0;  (*cp++ = *ip);  ip++, nchars++) {
		if (*ip == '\\' && *(ip+1) == '\n') {
		    *cp++ = 'n';
		    nchars += 2;
		    ip += 2;
		    break;
		} else if (*ip == '\n') {
		    *(cp-1) = '\\';
		    *cp++ = 'n';
		    nchars += 2;
		    ip++;
		    break;
		}
	    }
	    *cp++ = '\0';

	    /* Flush output line if it is full. */
	    if (len_prefix + op-obuf + nchars > width) {
		if (op > obuf) {
		    *op++ = '\0';
		    fprintf (fp, "%s%s\n", prefix, obuf);
		    op = obuf;
		} else {
		    fprintf (fp, "%s%s\n", prefix, lbuf);
		    op = obuf;
		    continue;
		}
	    }

	    /* Copy line to output buffer. */
	    for (cp=lbuf;  *cp;  )
		*op++ = *cp++;
	}

	/* Flush anything left in output buffer. */
	if (op > obuf) {
	    *op++ = '\0';
	    fprintf (fp, "%s%s\n", prefix, obuf);
	}
}


/* D_PROF -- Enable script execution profiling.
 */
void 
d_prof (void) 
{
}