xref: /illumos-gate/usr/src/lib/efcode/engine/debug.c (revision 09e6639b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <ctype.h>
34 
35 #include <fcode/private.h>
36 #include <fcode/log.h>
37 
38 #ifndef DEBUG_LVL
39 #define	DEBUG_LVL	0
40 #endif
41 
42 struct bitab {
43 	token_t bi_ptr;
44 	char *bi_name;
45 	int bi_type;
46 };
47 
48 struct bitab *lookup_builtin(token_t);
49 
50 static int debug_level = DEBUG_LVL;
51 
52 void
set_interpreter_debug_level(long lvl)53 set_interpreter_debug_level(long lvl)
54 {
55 	debug_level = lvl;
56 }
57 
58 long
get_interpreter_debug_level(void)59 get_interpreter_debug_level(void)
60 {
61 	return (debug_level);
62 }
63 
64 void
output_data_stack(fcode_env_t * env,int msglevel)65 output_data_stack(fcode_env_t *env, int msglevel)
66 {
67 	int i;
68 
69 	log_message(msglevel, "( ");
70 	if (DS > env->ds0) {
71 		for (i = 0; i < (DS - env->ds0); i++)
72 			log_message(msglevel, "%llx ",
73 			    (uint64_t)(env->ds0[i + 1]));
74 	} else
75 		log_message(msglevel, "<empty> ");
76 	log_message(msglevel, ") ");
77 }
78 
79 void
output_return_stack(fcode_env_t * env,int show_wa,int msglevel)80 output_return_stack(fcode_env_t *env, int show_wa, int msglevel)
81 {
82 	int i;
83 	int anyout = 0;
84 
85 	log_message(msglevel, "R:( ");
86 	if (show_wa) {
87 		log_message(msglevel, "%s ",
88 		    acf_backup_search(env, (acf_t)WA));
89 		anyout++;
90 	}
91 	if (IP) {
92 		anyout++;
93 		log_message(msglevel, "%s ", acf_backup_search(env, IP));
94 	}
95 	for (i = (RS - env->rs0) - 1; i > 0; i--) {
96 		anyout++;
97 		log_message(msglevel, "%s ",
98 		    acf_backup_search(env, (acf_t)env->rs0[i+1]));
99 	}
100 	if (!anyout)
101 		log_message(msglevel, "<empty> ");
102 	log_message(msglevel, ") ");
103 }
104 
105 void
dump_comma(fcode_env_t * env,char * type)106 dump_comma(fcode_env_t *env, char *type)
107 {
108 	xforth_t d;
109 
110 	if (strcmp(type, "x,") == 0)
111 		d = peek_xforth(env);
112 	else
113 		d = TOS;
114 	log_message(MSG_FC_DEBUG, "%s %p, %llx\n", type, HERE, (uint64_t)d);
115 }
116 
117 static int ndebug_names;
118 #define	MAXDEBUG_NAMES	10
119 static char *debug_names[MAXDEBUG_NAMES];
120 
121 static int ndebug_acfs;
122 #define	MAXDEBUG_ACFS	10
123 static acf_t debug_acfs[MAXDEBUG_ACFS];
124 
125 void
add_debug_acf(fcode_env_t * env,acf_t acf)126 add_debug_acf(fcode_env_t *env, acf_t acf)
127 {
128 	int i;
129 
130 	for (i = 0; i < ndebug_acfs; i++)
131 		if (acf == debug_acfs[i])
132 			return;
133 
134 	if (!within_dictionary(env, acf))
135 		log_message(MSG_ERROR, "Can't debug builtin\n");
136 	else if (ndebug_acfs >= MAXDEBUG_ACFS)
137 		log_message(MSG_ERROR, "Too many debug ACF's\n");
138 	else {
139 		debug_acfs[ndebug_acfs++] = acf;
140 		*LINK_TO_FLAGS(ACF_TO_LINK(acf)) |= FLAG_DEBUG;
141 	}
142 }
143 
144 static void
paren_debug(fcode_env_t * env)145 paren_debug(fcode_env_t *env)
146 {
147 	acf_t acf;
148 
149 	acf = (acf_t)POP(DS);
150 	if (!within_dictionary(env, acf)) {
151 		log_message(MSG_INFO, "acf: %llx not in dictionary\n",
152 		    (uint64_t)acf);
153 		return;
154 	}
155 	if ((acf_t)_ALIGN(acf, token_t) != acf) {
156 		log_message(MSG_INFO, "acf: %llx not aligned\n",
157 		    (uint64_t)acf);
158 		return;
159 	}
160 	if (*acf != (token_t)(&do_colon)) {
161 		log_message(MSG_INFO, "acf: %llx not a colon-def\n",
162 		    (uint64_t)acf);
163 		return;
164 	}
165 	add_debug_acf(env, acf);
166 }
167 
168 static void
debug(fcode_env_t * env)169 debug(fcode_env_t *env)
170 {
171 	fstack_t d;
172 	char *word;
173 	acf_t acf;
174 
175 	parse_word(env);
176 	dollar_find(env);
177 	d = POP(DS);
178 	if (d) {
179 		acf = (acf_t)POP(DS);
180 		add_debug_acf(env, acf);
181 	} else if (ndebug_names >= MAXDEBUG_NAMES) {
182 		log_message(MSG_ERROR, "Too many forward debug words\n");
183 		two_drop(env);
184 	} else {
185 		word = pop_a_duped_string(env, NULL);
186 		log_message(MSG_INFO, "Forward defined word: %s\n", word);
187 		debug_names[ndebug_names++] = word;
188 	}
189 }
190 
191 /*
192  * Eliminate dups and add vocabulary forth to end if not already on list.
193  */
194 static void
order_to_dict_list(fcode_env_t * env,token_t * order[])195 order_to_dict_list(fcode_env_t *env, token_t *order[])
196 {
197 	int i, j, norder = 0;
198 
199 	if (env->current)
200 		order[norder++] = env->current;
201 	for (i = env->order_depth; i >= 0; i--) {
202 		for (j = 0; j < norder && order[j] != env->order[i]; j++)
203 			;
204 		if (j == norder)
205 			order[norder++] = env->order[i];
206 	}
207 	for (j = 0; j < norder && order[j] != (token_t *)&env->forth_voc_link;
208 	    j++)
209 		;
210 	if (j == norder)
211 		order[norder++] = (token_t *)&env->forth_voc_link;
212 	order[norder] = NULL;
213 }
214 
215 static acf_t
search_all_dictionaries(fcode_env_t * env,acf_t (* fn)(fcode_env_t *,acf_t,void *),void * arg)216 search_all_dictionaries(fcode_env_t *env,
217     acf_t (*fn)(fcode_env_t *, acf_t, void *),
218     void *arg)
219 {
220 	token_t *order[MAX_ORDER+1];
221 	int i;
222 	token_t *dptr;
223 	acf_t acf;
224 
225 	order_to_dict_list(env, order);
226 	for (i = 0; (dptr = order[i]) != NULL; i++) {
227 		for (dptr = (token_t *)(*dptr); dptr;
228 		    dptr = (token_t *)(*dptr))
229 			if ((acf = (*fn)(env, LINK_TO_ACF(dptr), arg)) != NULL)
230 				return (acf);
231 	}
232 	return (NULL);
233 }
234 
235 char *
acf_to_str(acf_t acf)236 acf_to_str(acf_t acf)
237 {
238 	static char msg[(sizeof (acf) * 2) + 3];
239 
240 	(void) sprintf(msg, "(%08p)", acf);
241 	return (msg);
242 }
243 
244 char *
get_name_or_acf(token_t * dptr)245 get_name_or_acf(token_t *dptr)
246 {
247 	char *name;
248 
249 	if ((name = get_name(dptr)) != NULL)
250 		return (name);
251 	return (acf_to_str(LINK_TO_ACF(dptr)));
252 }
253 
254 static void
output_acf_name(acf_t acf)255 output_acf_name(acf_t acf)
256 {
257 	char *name;
258 	token_t *dptr;
259 	static int acf_count = 0;
260 
261 	if (acf == NULL) {
262 		if (acf_count)
263 			log_message(MSG_INFO, "\n");
264 		acf_count = 0;
265 		return;
266 	}
267 	dptr = ACF_TO_LINK(acf);
268 	if ((name = get_name(dptr)) == NULL)
269 		name = "<noname>";
270 
271 	log_message(MSG_INFO, "%24s (%08p)", name, acf);
272 	if (++acf_count >= 2) {
273 		log_message(MSG_INFO, "\n");
274 		acf_count = 0;
275 	} else
276 		log_message(MSG_INFO, "    ");
277 }
278 
279 static void
dot_debug(fcode_env_t * env)280 dot_debug(fcode_env_t *env)
281 {
282 	int i;
283 	token_t *dptr;
284 
285 	if (ndebug_names == 0)
286 		log_message(MSG_INFO, "No forward debug words\n");
287 	else {
288 		for (i = 0; i < ndebug_names; i++)
289 			log_message(MSG_INFO, "%s Forward\n", debug_names[i]);
290 	}
291 	if (ndebug_acfs == 0)
292 		log_message(MSG_INFO, "No debug words\n");
293 	else {
294 		for (i = 0; i < ndebug_acfs; i++)
295 			log_message(MSG_INFO, "%s\n",
296 			    get_name_or_acf(ACF_TO_LINK(debug_acfs[i])));
297 	}
298 }
299 
300 static void
do_undebug(fcode_env_t * env,char * name)301 do_undebug(fcode_env_t *env, char *name)
302 {
303 	int i;
304 
305 	for (i = 0; i < ndebug_names; i++) {
306 		if (strcmp(debug_names[i], name) == 0) {
307 			log_message(MSG_INFO, "Undebugging forward word %s\n",
308 			    name);
309 			FREE(debug_names[i]);
310 			for (i++; i < ndebug_names; i++)
311 				debug_names[i - 1] = debug_names[i];
312 			ndebug_names--;
313 			break;
314 		}
315 	}
316 }
317 
318 static void
undebug(fcode_env_t * env)319 undebug(fcode_env_t *env)
320 {
321 	fstack_t d;
322 	acf_t acf;
323 	flag_t *flagp;
324 	char *name;
325 	int i, j;
326 
327 	parse_word(env);
328 	two_dup(env);
329 	dollar_find(env);
330 	d = POP(DS);
331 	if (d) {
332 		acf = (acf_t)POP(DS);
333 		flagp = LINK_TO_FLAGS(ACF_TO_LINK(acf));
334 		if ((*flagp & FLAG_DEBUG) == 0)
335 			log_message(MSG_WARN, "Word not debugged?\n");
336 		else {
337 			log_message(MSG_INFO, "Undebugging acf: %p\n", acf);
338 			*flagp &= ~FLAG_DEBUG;
339 			for (i = 0; i < ndebug_acfs; i++) {
340 				if (debug_acfs[i] == acf) {
341 					for (j = i + 1; j < ndebug_acfs; j++)
342 						debug_acfs[j-1] = debug_acfs[j];
343 					ndebug_acfs--;
344 					break;
345 				}
346 			}
347 		}
348 	} else
349 		two_drop(env);
350 	name = pop_a_string(env, NULL);
351 	do_undebug(env, name);
352 }
353 
354 int
name_is_debugged(fcode_env_t * env,char * name)355 name_is_debugged(fcode_env_t *env, char *name)
356 {
357 	int i;
358 
359 	if (ndebug_names <= 0)
360 		return (0);
361 	for (i = 0; i < ndebug_names; i++)
362 		if (strcmp(debug_names[i], name) == 0)
363 			return (1);
364 	return (0);
365 }
366 
367 /*
368  * This is complicated by being given ACF's to temporary compile words which
369  * don't have a header.
370  */
371 int
is_debug_word(fcode_env_t * env,acf_t acf)372 is_debug_word(fcode_env_t *env, acf_t acf)
373 {
374 	flag_t *flagp;
375 	int i;
376 
377 	/* check to see if any words are being debugged */
378 	if (ndebug_acfs == 0)
379 		return (0);
380 
381 	/* only words in dictionary can be debugged */
382 	if (!within_dictionary(env, acf))
383 		return (0);
384 
385 	/* check that word has "FLAG_DEBUG" on */
386 	flagp = LINK_TO_FLAGS(ACF_TO_LINK(acf));
387 	if ((*flagp & FLAG_DEBUG) == 0)
388 		return (0);
389 
390 	/* look in table of debug acf's */
391 	for (i = 0; i < ndebug_acfs; i++)
392 		if (debug_acfs[i] == acf)
393 			return (1);
394 	return (0);
395 }
396 
397 #define	MAX_DEBUG_STACK	100
398 token_t debug_low[MAX_DEBUG_STACK], debug_high[MAX_DEBUG_STACK];
399 int debug_prev_level[MAX_DEBUG_STACK];
400 int debug_curr_level[MAX_DEBUG_STACK];
401 int ndebug_stack = 0;
402 
403 void
debug_set_level(fcode_env_t * env,int level)404 debug_set_level(fcode_env_t *env, int level)
405 {
406 	debug_curr_level[ndebug_stack - 1] = level;
407 	set_interpreter_debug_level(level);
408 }
409 
410 token_t
find_semi_in_colon_def(fcode_env_t * env,acf_t acf)411 find_semi_in_colon_def(fcode_env_t *env, acf_t acf)
412 {
413 	for (; within_dictionary(env, acf); acf++)
414 		if (*acf == (token_t)(&semi_ptr))
415 			return ((token_t)acf);
416 	return (0);
417 }
418 
419 void
check_for_debug_entry(fcode_env_t * env)420 check_for_debug_entry(fcode_env_t *env)
421 {
422 	int top;
423 
424 	if (is_debug_word(env, WA) && ndebug_stack < MAX_DEBUG_STACK) {
425 		top = ndebug_stack++;
426 		debug_prev_level[top] = get_interpreter_debug_level();
427 		debug_low[top] = (token_t)WA;
428 		if (*WA == (token_t)(&do_colon)) {
429 			debug_high[top] =
430 			    find_semi_in_colon_def(env, WA);
431 		} else {
432 			debug_high[top] = 0;	/* marker... */
433 		}
434 		debug_set_level(env, DEBUG_STEPPING);
435 		output_step_message(env);
436 	}
437 }
438 
439 void
check_for_debug_exit(fcode_env_t * env)440 check_for_debug_exit(fcode_env_t *env)
441 {
442 	if (ndebug_stack) {
443 		int top = ndebug_stack - 1;
444 
445 		if (debug_high[top] == 0) {
446 			set_interpreter_debug_level(debug_prev_level[top]);
447 			ndebug_stack--;
448 		} else if ((token_t)IP >= debug_low[top] &&
449 		    (token_t)IP <= debug_high[top]) {
450 			set_interpreter_debug_level(debug_curr_level[top]);
451 		} else {
452 			set_interpreter_debug_level(debug_prev_level[top]);
453 		}
454 	}
455 }
456 
457 void
check_semi_debug_exit(fcode_env_t * env)458 check_semi_debug_exit(fcode_env_t *env)
459 {
460 	if (ndebug_stack) {
461 		int top = ndebug_stack - 1;
462 
463 		if ((token_t)(IP - 1) == debug_high[top]) {
464 			set_interpreter_debug_level(debug_prev_level[top]);
465 			ndebug_stack--;
466 		}
467 	}
468 }
469 
470 /*
471  * Really entering do_run, since this may be a recursive entry to do_run,
472  * we need to set the debug level to what it was previously.
473  */
474 int
current_debug_state(fcode_env_t * env)475 current_debug_state(fcode_env_t *env)
476 {
477 	if (ndebug_stack) {
478 		int top = ndebug_stack - 1;
479 		set_interpreter_debug_level(debug_prev_level[top]);
480 	}
481 	return (ndebug_stack);
482 }
483 
484 void
clear_debug_state(fcode_env_t * env,int oldstate)485 clear_debug_state(fcode_env_t *env, int oldstate)
486 {
487 	if (ndebug_stack && oldstate <= ndebug_stack) {
488 		set_interpreter_debug_level(debug_prev_level[oldstate]);
489 		ndebug_stack = oldstate;
490 	}
491 }
492 
493 void
unbug(fcode_env_t * env)494 unbug(fcode_env_t *env)
495 {
496 	int i;
497 	token_t *link;
498 	flag_t *flag;
499 
500 	for (i = ndebug_stack - 1; i >= 0; i--) {
501 		link = ACF_TO_LINK(debug_low[i]);
502 		flag = LINK_TO_FLAGS(link);
503 		*flag &= ~FLAG_DEBUG;
504 	}
505 	clear_debug_state(env, 0);
506 }
507 
508 void
output_vitals(fcode_env_t * env)509 output_vitals(fcode_env_t *env)
510 {
511 	log_message(MSG_FC_DEBUG, "IP=%p, *IP=%p, WA=%p, *WA=%p ", IP,
512 	    (IP ? *IP : 0), WA, (WA ? *WA : 0));
513 }
514 
515 int
do_exec_debug(fcode_env_t * env,void * fn)516 do_exec_debug(fcode_env_t *env, void *fn)
517 {
518 	int dl = debug_level;
519 	int show_wa = 1;
520 
521 	if ((dl & (DEBUG_EXEC_DUMP_DS | DEBUG_EXEC_DUMP_RS |
522 	    DEBUG_EXEC_SHOW_VITALS | DEBUG_EXEC_TRACE | DEBUG_TRACING |
523 	    DEBUG_STEPPING)) == 0)
524 		return (0);
525 
526 	if (dl & DEBUG_STEPPING) {
527 		dl |= DEBUG_EXEC_DUMP_DS;
528 	}
529 	if (dl & (DEBUG_STEPPING | DEBUG_EXEC_TRACE)) {
530 		log_message(MSG_FC_DEBUG, "%-15s ", acf_to_name(env, WA));
531 		show_wa = 0;
532 	}
533 	if (dl & DEBUG_EXEC_DUMP_DS)
534 		output_data_stack(env, MSG_FC_DEBUG);
535 	if (dl & DEBUG_EXEC_DUMP_RS)
536 		output_return_stack(env, show_wa, MSG_FC_DEBUG);
537 	if (dl & DEBUG_EXEC_SHOW_VITALS)
538 		output_vitals(env);
539 	if (dl & DEBUG_TRACING)
540 		do_fclib_trace(env, (void *) fn);
541 	log_message(MSG_FC_DEBUG, "\n");
542 	if (dl & DEBUG_STEPPING)
543 		return (do_fclib_step(env));
544 	return (0);
545 }
546 
547 static void
smatch(fcode_env_t * env)548 smatch(fcode_env_t *env)
549 {
550 	int len;
551 	char *str, *p;
552 
553 	if ((str = parse_a_string(env, &len)) == NULL)
554 		log_message(MSG_INFO, "smatch: no string\n");
555 	else {
556 		for (p = (char *)env->base; p < (char *)HERE; p++)
557 			if (memcmp(p, str, len) == 0)
558 				log_message(MSG_DEBUG, "%p\n", p);
559 	}
560 }
561 
562 void
check_vitals(fcode_env_t * env)563 check_vitals(fcode_env_t *env)
564 {
565 	int i;
566 	token_t *dptr;
567 
568 	dptr = env->current;
569 	if (*dptr && !within_dictionary(env, (uchar_t *)*dptr))
570 		log_message(MSG_ERROR, "Current: %p outside dictionary\n",
571 		    *dptr);
572 	for (i = env->order_depth; i >= 0; i--) {
573 		dptr = env->order[i];
574 		if (!dptr)
575 			continue;
576 		if (*dptr && !within_dictionary(env, (uchar_t *)*dptr))
577 			log_message(MSG_ERROR, "Order%d: %p outside"
578 			    " dictionary\n", i, *dptr);
579 	}
580 	if (HERE < env->base || HERE >= env->base + dict_size) {
581 		log_message(MSG_ERROR, "HERE: %p outside range\n", HERE);
582 	}
583 	if (DS < env->ds0 || DS >= &env->ds0[stack_size]) {
584 		forth_abort(env, "DS: %p outside range\n", DS);
585 	}
586 	if (RS < env->rs0 || RS >= &env->rs0[stack_size]) {
587 		log_message(MSG_ERROR, "RS: %p outside range\n", RS);
588 		RS = env->rs0;
589 	}
590 	if (IP && !within_dictionary(env, IP))
591 		log_message(MSG_ERROR, "IP: %p outside dictionary\n", IP);
592 	if (!within_dictionary(env, (void *)env->forth_voc_link))
593 		log_message(MSG_ERROR, "forth_voc_link: %p outside"
594 		    " dictionary\n", env->forth_voc_link);
595 }
596 
597 static void
dump_table(fcode_env_t * env)598 dump_table(fcode_env_t *env)
599 {
600 	int i;
601 
602 	for (i = 0; i < MAX_FCODE; i++) {
603 		if (*(env->table[i].apf) != (token_t)(&f_error)) {
604 			log_message(MSG_DEBUG, "Token: %4x %32s acf = %8p,"
605 			    " %8p\n", i, env->table[i].name, env->table[i].apf,
606 			    *(env->table[i].apf));
607 		}
608 	}
609 	log_message(MSG_DEBUG, "%d FCODES implemented\n", fcode_impl_count);
610 }
611 
612 void
verify_usage(fcode_env_t * env)613 verify_usage(fcode_env_t *env)
614 {
615 	int i, untested = 0;
616 
617 	for (i = 0; i < MAX_FCODE; i++) {
618 		int verify;
619 
620 		verify = env->table[i].flags & (ANSI_WORD|P1275_WORD);
621 		if ((verify) &&
622 #ifdef DEBUG
623 		    (env->table[i].usage == 0) &&
624 #endif
625 		    (env->table[i].apf)) {
626 			log_message(MSG_DEBUG,
627 			    "Untested: %4x %32s acf = %8p, %8p\n", i,
628 			    env->table[i].name, env->table[i].apf,
629 			    *(env->table[i].apf));
630 			untested++;
631 		}
632 	}
633 	if (untested)
634 		log_message(MSG_DEBUG, "%d untested tokens\n", untested);
635 }
636 
637 static void
debugf(fcode_env_t * env)638 debugf(fcode_env_t *env)
639 {
640 	PUSH(DS, (fstack_t)&debug_level);
641 }
642 
643 static void
control(fcode_env_t * env)644 control(fcode_env_t *env)
645 {
646 	PUSH(DS, (fstack_t)&env->control);
647 }
648 
649 struct bittab {
650 	int b_bitval;
651 	char *b_bitname;
652 } bittab[] = {
653 	DEBUG_CONTEXT,		"context",
654 	DEBUG_BYTELOAD_DS,	"byteload-ds",
655 	DEBUG_BYTELOAD_RS,	"byteload-rs",
656 	DEBUG_BYTELOAD_TOKENS,	"byteload-tokens",
657 	DEBUG_NEW_TOKEN,	"new-token",
658 	DEBUG_EXEC_TRACE,	"exec-trace",
659 	DEBUG_EXEC_SHOW_VITALS,	"exec-show-vitals",
660 	DEBUG_EXEC_DUMP_DS,	"exec-dump-ds",
661 	DEBUG_EXEC_DUMP_RS,	"exec-dump-rs",
662 	DEBUG_COMMA,		"comma",
663 	DEBUG_HEADER,		"header",
664 	DEBUG_EXIT_WORDS,	"exit-words",
665 	DEBUG_EXIT_DUMP,	"exit-dump",
666 	DEBUG_DUMP_TOKENS,	"dump-tokens",
667 	DEBUG_COLON,		"colon",
668 	DEBUG_NEXT_VITALS,	"next-vitals",
669 	DEBUG_VOC_FIND,		"voc-find",
670 	DEBUG_DUMP_DICT_TOKENS,	"dump-dict-tokens",
671 	DEBUG_TOKEN_USAGE,	"token-usage",
672 	DEBUG_DUMP_TOKEN_TABLE,	"dump-token-table",
673 	DEBUG_SHOW_STACK,	"show-stack",
674 	DEBUG_SHOW_RS,		"show-rs",
675 	DEBUG_TRACING,		"tracing",
676 	DEBUG_TRACE_STACK,	"trace-stack",
677 	DEBUG_CALL_METHOD,	"call-method",
678 	DEBUG_ACTIONS,		"actions",
679 	DEBUG_STEPPING,		"stepping",
680 	DEBUG_REG_ACCESS,	"reg-access",
681 	DEBUG_ADDR_ABUSE,	"addr-abuse",
682 	DEBUG_FIND_FCODE,	"find-fcode",
683 	DEBUG_UPLOAD,		"upload",
684 	0
685 };
686 
687 void
debug_flags_to_output(fcode_env_t * env,int flags)688 debug_flags_to_output(fcode_env_t *env, int flags)
689 {
690 	int first = 1, i;
691 
692 	for (i = 0; bittab[i].b_bitval != 0; i++)
693 		if (bittab[i].b_bitval & flags) {
694 			if (!first)
695 				log_message(MSG_INFO, ",");
696 			first = 0;
697 			log_message(MSG_INFO, bittab[i].b_bitname);
698 		}
699 	if (first)
700 		log_message(MSG_INFO, "<empty>");
701 	log_message(MSG_INFO, "\n");
702 }
703 
704 static void
dot_debugf(fcode_env_t * env)705 dot_debugf(fcode_env_t *env)
706 {
707 	debug_flags_to_output(env, debug_level);
708 }
709 
710 static void
debugf_qmark(fcode_env_t * env)711 debugf_qmark(fcode_env_t *env)
712 {
713 	debug_flags_to_output(env, 0xffffffff);
714 }
715 
716 int
debug_flags_to_mask(char * str)717 debug_flags_to_mask(char *str)
718 {
719 	int flags = 0;
720 	char *p;
721 	int i;
722 
723 	if (isdigit(*str)) {
724 		if (*str == '0') {
725 			str++;
726 			if (*str == 'x' || *str == 'X') {
727 				(void) sscanf(str + 1, "%x", &flags);
728 			} else
729 				(void) sscanf(str, "%o", &flags);
730 		} else
731 			(void) sscanf(str, "%d", &flags);
732 		return (flags);
733 	}
734 	if (strcmp(str, "clear") == 0)
735 		return (0);
736 	if (strcmp(str, "all") == 0)
737 		return (0xffffffff & ~DEBUG_STEPPING);
738 	if (*str) {
739 		do {
740 			if (p = strchr(str, ','))
741 				*p++ = '\0';
742 			for (i = 0; bittab[i].b_bitname != 0; i++)
743 				if (strcmp(str, bittab[i].b_bitname) == 0) {
744 					flags |= bittab[i].b_bitval;
745 					break;
746 			}
747 			if (bittab[i].b_bitname == 0)
748 				log_message(MSG_WARN,
749 				    "Unknown debug flag: '%s'\n", str);
750 			str = p;
751 		} while (p);
752 	}
753 	return (flags);
754 }
755 
756 static void
set_debugf(fcode_env_t * env)757 set_debugf(fcode_env_t *env)
758 {
759 	char *str;
760 
761 	str = parse_a_string(env, NULL);
762 	debug_level = debug_flags_to_mask(str);
763 }
764 
765 static acf_t
show_a_word(fcode_env_t * env,acf_t acf,void * arg)766 show_a_word(fcode_env_t *env, acf_t acf, void *arg)
767 {
768 	static int nshow_words = 0;
769 
770 	if (acf == NULL) {
771 		if (nshow_words > 0) {
772 			log_message(MSG_DEBUG, "\n");
773 			nshow_words = 0;
774 		}
775 		return (NULL);
776 	}
777 	log_message(MSG_DEBUG, "%15s  ", get_name_or_acf(ACF_TO_LINK(acf)));
778 	nshow_words++;
779 	if (nshow_words >= 4) {
780 		log_message(MSG_DEBUG, "\n");
781 		nshow_words = 0;
782 	}
783 	return (NULL);
784 }
785 
786 void
words(fcode_env_t * env)787 words(fcode_env_t *env)
788 {
789 	(void) search_all_dictionaries(env, show_a_word, NULL);
790 	(void) show_a_word(env, NULL, NULL);
791 }
792 
793 static acf_t
dump_a_word(fcode_env_t * env,acf_t acf,void * arg)794 dump_a_word(fcode_env_t *env, acf_t acf, void *arg)
795 {
796 	output_acf_name(acf);
797 	return (NULL);
798 }
799 
800 void
dump_words(fcode_env_t * env)801 dump_words(fcode_env_t *env)
802 {
803 	(void) search_all_dictionaries(env, dump_a_word, NULL);
804 	output_acf_name(NULL);
805 }
806 
807 static void
dump_line(uchar_t * ptr)808 dump_line(uchar_t *ptr)
809 {
810 	uchar_t *byte;
811 	int i;
812 
813 	log_message(MSG_INFO, "%p  ", ptr);
814 	for (i = 0, byte = ptr; i < 16; i++) {
815 		if (i == 8)
816 			log_message(MSG_INFO, " ");
817 		log_message(MSG_INFO, "%02.2x ", *byte++);
818 	}
819 	log_message(MSG_INFO, " ");
820 	for (i = 0, byte = ptr; i < 16; i++, byte++) {
821 		log_message(MSG_INFO, "%c",
822 		    ((*byte < 0x20) || (*byte > 0x7f)) ? '.' : *byte);
823 	}
824 	log_message(MSG_INFO, "\n");
825 }
826 
827 void
dump_dictionary(fcode_env_t * env)828 dump_dictionary(fcode_env_t *env)
829 {
830 	uchar_t *ptr;
831 
832 	log_message(MSG_INFO, "Dictionary dump: base: %p\n", env->base);
833 	for (ptr = (uchar_t *)(((long)(env->base)) & ~0xf); ptr < HERE;
834 	    ptr += 16)
835 		dump_line(ptr);
836 }
837 
838 static char *
acf_to_fcode_name(fcode_env_t * env,acf_t acf)839 acf_to_fcode_name(fcode_env_t *env, acf_t acf)
840 {
841 	int i;
842 
843 	for (i = 0; i < MAX_FCODE; i++)
844 		if (env->table[i].apf == acf)
845 			return (env->table[i].name);
846 	return (NULL);
847 }
848 
849 static acf_t
acf_match(fcode_env_t * env,acf_t sacf,void * macf)850 acf_match(fcode_env_t *env, acf_t sacf, void *macf)
851 {
852 	if (sacf == (acf_t)macf)
853 		return (sacf);
854 	return (NULL);
855 }
856 
857 /*
858  * Given an ACF, return ptr to name or "unknown" string.
859  */
860 char *
acf_to_name(fcode_env_t * env,acf_t acf)861 acf_to_name(fcode_env_t *env, acf_t acf)
862 {
863 	struct bitab *bip;
864 	static char name_buf[256];
865 	uchar_t *p, *np;
866 	int i, n;
867 
868 	if (!within_dictionary(env, acf)) {
869 		if ((bip = lookup_builtin((token_t)acf)) != NULL)
870 			return (bip->bi_name);
871 		return (NULL);
872 	}
873 	return (get_name_or_acf(ACF_TO_LINK(acf)));
874 }
875 
876 int
within_dictionary(fcode_env_t * env,void * addr)877 within_dictionary(fcode_env_t *env, void *addr)
878 {
879 	return ((uchar_t *)addr >= env->base &&
880 	    (uchar_t *)addr < env->base + dict_size);
881 }
882 
883 static int
within_word(fcode_env_t * env,acf_t acf,acf_t wacf)884 within_word(fcode_env_t *env, acf_t acf, acf_t wacf)
885 {
886 	if (acf == wacf || acf + 1 == wacf)
887 		return (1);
888 	if (*acf == (token_t)(&do_colon)) {
889 		do {
890 			if (acf == wacf)
891 				return (1);
892 		} while (*acf++ != (token_t)(&semi_ptr));
893 	}
894 	return (0);
895 }
896 
897 /*
898  * Given an ACF in the middle of a colon definition, search dictionary towards
899  * beginning for "colon" acf.  If we find a "semi" acf first, we're not in
900  * the middle of a colon-def (temporary execute?).
901  */
902 char *
acf_backup_search(fcode_env_t * env,acf_t acf)903 acf_backup_search(fcode_env_t *env, acf_t acf)
904 {
905 	acf_t nacf;
906 	char *name;
907 
908 	if ((acf_t)_ALIGN(acf, token_t) == acf && within_dictionary(env, acf)) {
909 		for (nacf = acf; nacf >= (acf_t)env->base; nacf--)
910 			if (*nacf == (token_t)(&do_colon) ||
911 			    *nacf == (token_t)(&semi_ptr))
912 				break;
913 		if (nacf >= (acf_t)env->base && *nacf == (token_t)(&do_colon) &&
914 		    (name = get_name(ACF_TO_LINK(nacf))) != NULL)
915 			return (name);
916 	}
917 	return (acf_to_str(acf));
918 }
919 
920 /*
921  * Print out current process's C stack using /usr/proc/bin/pstack
922  */
923 void
ctrace(fcode_env_t * env)924 ctrace(fcode_env_t *env)
925 {
926 	char buf[256];
927 	FILE *fd;
928 
929 	log_message(MSG_DEBUG, "Interpreter C Stack:\n");
930 	(void) sprintf(buf, "/usr/proc/bin/pstack %d", getpid());
931 	if ((fd = popen(buf, "r")) == NULL)
932 		log_perror(MSG_ERROR, "Can't run: %s", buf);
933 	else {
934 		while (fgets(buf, sizeof (buf), fd))
935 			log_message(MSG_DEBUG, buf);
936 		(void) fclose(fd);
937 	}
938 }
939 
940 /*
941  * Dump data, return stacks, try to unthread forth calling stack.
942  */
943 void
ftrace(fcode_env_t * env)944 ftrace(fcode_env_t *env)
945 {
946 	log_message(MSG_DEBUG, "Forth Interpreter Stacks:\n");
947 	output_data_stack(env, MSG_DEBUG);
948 	output_return_stack(env, 1, MSG_DEBUG);
949 	log_message(MSG_DEBUG, "\n");
950 }
951 
952 int in_forth_abort;
953 
954 /*
955  * Handle fatal error, if interactive mode, return to ok prompt.
956  */
957 void
forth_abort(fcode_env_t * env,char * fmt,...)958 forth_abort(fcode_env_t *env, char *fmt, ...)
959 {
960 	va_list ap;
961 	char msg[256];
962 
963 	if (in_forth_abort) {
964 		log_message(MSG_FATAL, "ABORT: abort within forth_abort\n");
965 		abort();
966 	}
967 	in_forth_abort++;
968 
969 	va_start(ap, fmt);
970 	(void) vsprintf(msg, fmt, ap);
971 	log_message(MSG_ERROR, "ABORT: %s\n", msg);
972 
973 	if (env) {
974 		ctrace(env);
975 		ftrace(env);
976 	}
977 
978 	return_to_interact(env);
979 	/*
980 	 * If not in interactive mode, return_to_interact just returns.
981 	 */
982 	exit(1);
983 }
984 
985 /*
986  * Handle fatal system call error
987  */
988 void
forth_perror(fcode_env_t * env,char * fmt,...)989 forth_perror(fcode_env_t *env, char *fmt, ...)
990 {
991 	va_list ap;
992 	char msg[256];
993 	int save_errno = errno;	/* just in case... */
994 
995 	va_start(ap, fmt);
996 	(void) vsprintf(msg, fmt, ap);
997 
998 	forth_abort(env, "%s: %s", msg, strerror(save_errno));
999 }
1000 
1001 static void
show_stack(fcode_env_t * env)1002 show_stack(fcode_env_t *env)
1003 {
1004 #ifdef DEBUG
1005 	debug_level ^= DEBUG_SHOW_STACK;
1006 #else
1007 	/*EMPTY*/
1008 #endif
1009 }
1010 
1011 static void
print_bytes_header(int width,int offset)1012 print_bytes_header(int width, int offset)
1013 {
1014 	int i;
1015 
1016 	for (i = 0; i < width; i++)
1017 		log_message(MSG_INFO, " ");
1018 	log_message(MSG_INFO, "  ");
1019 	for (i = 0; i < 16; i++) {
1020 		if (i == 8)
1021 			log_message(MSG_INFO, " ");
1022 		if (i == offset)
1023 			log_message(MSG_INFO, "\\/ ");
1024 		else
1025 			log_message(MSG_INFO, "%2x ", i);
1026 	}
1027 	log_message(MSG_INFO, " ");
1028 	for (i = 0; i < 16; i++) {
1029 		if (i == offset)
1030 			log_message(MSG_INFO, "v");
1031 		else
1032 			log_message(MSG_INFO, "%x", i);
1033 	}
1034 	log_message(MSG_INFO, "\n");
1035 }
1036 
1037 static void
dump(fcode_env_t * env)1038 dump(fcode_env_t *env)
1039 {
1040 	uchar_t *data;
1041 	int len, offset;
1042 	char buf[20];
1043 
1044 	len = POP(DS);
1045 	data = (uchar_t *)POP(DS);
1046 	offset = ((long)data) & 0xf;
1047 	len += offset;
1048 	data = (uchar_t *)((long)data & ~0xf);
1049 	(void) sprintf(buf, "%p", data);
1050 	print_bytes_header(strlen(buf), offset);
1051 	for (len += offset; len > 0; len -= 16, data += 16)
1052 		dump_line(data);
1053 }
1054 
1055 static acf_t
do_sifting(fcode_env_t * env,acf_t acf,void * pat)1056 do_sifting(fcode_env_t *env, acf_t acf, void *pat)
1057 {
1058 	char *name;
1059 
1060 	if ((name = get_name(ACF_TO_LINK(acf))) != NULL && strstr(name, pat))
1061 		output_acf_name(acf);
1062 	return (NULL);
1063 }
1064 
1065 static void
sifting(fcode_env_t * env)1066 sifting(fcode_env_t *env)
1067 {
1068 	char *pat;
1069 
1070 	if ((pat = parse_a_string(env, NULL)) != NULL) {
1071 		(void) search_all_dictionaries(env, do_sifting, pat);
1072 		output_acf_name(NULL);
1073 	}
1074 }
1075 
1076 void
print_level(int level,int * doprint)1077 print_level(int level, int *doprint)
1078 {
1079 	int i;
1080 
1081 	if (*doprint) {
1082 		log_message(MSG_DEBUG, "\n    ");
1083 		for (i = 0; i < level; i++)
1084 			log_message(MSG_DEBUG, "    ");
1085 		*doprint = 0;
1086 	}
1087 }
1088 
1089 #define	BI_QUOTE	1
1090 #define	BI_BLIT		2
1091 #define	BI_BDO		3
1092 #define	BI_QDO		4
1093 #define	BI_BR		5
1094 #define	BI_QBR		6
1095 #define	BI_BOF		7
1096 #define	BI_LOOP		8
1097 #define	BI_PLOOP	9
1098 #define	BI_TO		10
1099 #define	BI_SEMI		11
1100 #define	BI_COLON	12
1101 #define	BI_NOOP		13
1102 #define	BI_NOTYET	14	/* unimplented in "see" */
1103 
1104 struct bitab bitab[] = {
1105 	(token_t)(&quote_ptr),			"\"",		BI_QUOTE,
1106 	(token_t)(&blit_ptr),			"blit",		BI_BLIT,
1107 	(token_t)(&do_bdo_ptr),			"do",		BI_BDO,
1108 	(token_t)(&do_bqdo_ptr),		"?do",		BI_QDO,
1109 	(token_t)(&bbranch_ptrs[0]),		"br",		BI_BR,
1110 	(token_t)(&bbranch_ptrs[1]),		"qbr",		BI_QBR,
1111 	(token_t)(&bbranch_ptrs[2]),		"bof",		BI_BOF,
1112 	(token_t)(&do_loop_ptr),		"loop",		BI_LOOP,
1113 	(token_t)(&do_ploop_ptr),		"+loop",	BI_PLOOP,
1114 	(token_t)(&to_ptr),			"to",		BI_NOOP,
1115 	(token_t)(&semi_ptr),			";",		BI_SEMI,
1116 	(token_t)(&do_colon),			":",		BI_COLON,
1117 	(token_t)(&tlit_ptr),			"[']",		BI_NOOP,
1118 	(token_t)(&do_leave_ptr),		"leave",	BI_NOTYET,
1119 	(token_t)(&create_ptr),			"create",	BI_NOTYET,
1120 	(token_t)(&does_ptr),			"does>",	BI_NOTYET,
1121 	(token_t)(&value_defines[0][0]),	"a.@",		BI_NOTYET,
1122 	(token_t)(&value_defines[0][1]),	"a.!",		BI_NOTYET,
1123 	(token_t)(&value_defines[0][2]),	"a.nop",	BI_NOTYET,
1124 	(token_t)(&value_defines[1][0]),	"a.i@",		BI_NOTYET,
1125 	(token_t)(&value_defines[1][1]),	"a.i!",		BI_NOTYET,
1126 	(token_t)(&value_defines[1][2]),	"a.iad",	BI_NOTYET,
1127 	(token_t)(&value_defines[2][0]),	"a.defer",	BI_NOTYET,
1128 	(token_t)(&value_defines[2][1]),	"a.@",		BI_NOTYET,
1129 	(token_t)(&value_defines[2][2]),	"a.nop",	BI_NOTYET,
1130 	(token_t)(&value_defines[3][0]),	"a.defexec",	BI_NOTYET,
1131 	(token_t)(&value_defines[3][1]),	"a.iset",	BI_NOTYET,
1132 	(token_t)(&value_defines[3][2]),	"a.iad",	BI_NOTYET,
1133 	(token_t)(&value_defines[4][0]),	"a.binit",	BI_NOTYET,
1134 	(token_t)(&value_defines[4][1]),	"a.2drop",	BI_NOTYET,
1135 	(token_t)(&value_defines[4][2]),	"a.nop",	BI_NOTYET,
1136 	(token_t)(&value_defines[5][0]),	"a.ibinit",	BI_NOTYET,
1137 	(token_t)(&value_defines[5][1]),	"a.2drop",	BI_NOTYET,
1138 	(token_t)(&value_defines[5][2]),	"a.iad",	BI_NOTYET,
1139 	0
1140 };
1141 
1142 struct bitab *
lookup_builtin(token_t builtin)1143 lookup_builtin(token_t builtin)
1144 {
1145 	int i;
1146 
1147 	for (i = 0; bitab[i].bi_ptr; i++)
1148 		if (bitab[i].bi_ptr == builtin)
1149 			return (&bitab[i]);
1150 	return (NULL);
1151 }
1152 
1153 static void
paren_see(fcode_env_t * env)1154 paren_see(fcode_env_t *env)
1155 {
1156 	acf_t save_acf = (acf_t)POP(DS);
1157 	acf_t acf = save_acf;
1158 	int i, n, pass;
1159 	token_t brtab[30], thentab[30], brstk[30];
1160 	int nbrtab = 0, nthentab = 0, nbrstk = 0;
1161 	uchar_t *p;
1162 	int level = 0, doprintlevel = 1, nthen;
1163 	struct bitab *bip;
1164 	token_t last_lit = 0, case_lit = 0, endof_loc = 0, endcase_loc = 0;
1165 
1166 	if ((bip = lookup_builtin(*acf)) == NULL ||
1167 	    bip->bi_type != BI_COLON) {
1168 		if (bip = lookup_builtin((token_t)acf))
1169 			log_message(MSG_INFO, "%s: builtin\n", bip->bi_name);
1170 		else
1171 			log_message(MSG_INFO, "%s: builtin\n",
1172 			    acf_to_name(env, acf));
1173 		return;
1174 	}
1175 	log_message(MSG_INFO, ": %s", acf_to_name(env, acf));
1176 	for (pass = 0; pass < 2; pass++) {
1177 		acf = save_acf;
1178 		for (acf++; ; acf++) {
1179 			if (pass) {
1180 				print_level(level, &doprintlevel);
1181 				for (nthen = 0; nthentab > 0 &&
1182 				    thentab[nthentab-1] == (token_t)acf;
1183 				    nthentab--)
1184 					nthen++;
1185 				if (nthen) {
1186 					level -= nthen;
1187 					doprintlevel = 1;
1188 					print_level(level, &doprintlevel);
1189 					for (i = 0; i < nthen; i++)
1190 						log_message(MSG_INFO, "then ");
1191 				}
1192 				print_level(level, &doprintlevel);
1193 				for (i = 0; i < nbrtab; i += 2)
1194 					if ((token_t)acf == brtab[i]) {
1195 						log_message(MSG_INFO, "begin ");
1196 						brstk[nbrstk++] = brtab[i+1];
1197 						level++;
1198 						doprintlevel = 1;
1199 					}
1200 				print_level(level, &doprintlevel);
1201 				if (case_lit == (token_t)acf) {
1202 					log_message(MSG_INFO, "case ");
1203 					doprintlevel = 1;
1204 					print_level(level, &doprintlevel);
1205 				}
1206 				if (endof_loc == (token_t)acf) {
1207 					log_message(MSG_INFO, "endof ");
1208 					doprintlevel = 1;
1209 					print_level(level, &doprintlevel);
1210 				}
1211 				if (endcase_loc == (token_t)acf) {
1212 					doprintlevel = 1;
1213 					print_level(level, &doprintlevel);
1214 					log_message(MSG_INFO, "endcase ");
1215 				}
1216 			}
1217 			if ((bip = lookup_builtin((token_t)*acf)) == 0) {
1218 				last_lit = (token_t)acf;
1219 				if (pass)
1220 					log_message(MSG_INFO, "%s ",
1221 					    acf_to_name(env, (acf_t)*acf));
1222 				continue;
1223 			}
1224 			if (bip->bi_type == BI_SEMI) {
1225 				if (pass) {
1226 					log_message(MSG_INFO, "\n");
1227 					log_message(MSG_INFO, "%s\n",
1228 					    bip->bi_name);
1229 				}
1230 				break;
1231 			}
1232 			switch (bip->bi_type) {
1233 
1234 			case BI_NOOP:
1235 			case BI_NOTYET:
1236 				if (pass)
1237 					log_message(MSG_INFO, "%s ",
1238 					    bip->bi_name);
1239 				break;
1240 
1241 			case BI_QUOTE:
1242 				if (pass)
1243 					log_message(MSG_INFO, "\" ");
1244 				acf++;
1245 				p = (uchar_t *)acf;
1246 				n = *p++;
1247 				if (pass)
1248 					log_message(MSG_INFO, "%s\" ", p);
1249 				p += n + 1;
1250 				for (; ((token_t)(p)) & (sizeof (token_t) - 1);
1251 				    p++)
1252 					;
1253 				acf = (acf_t)p;
1254 				acf--;
1255 				break;
1256 
1257 			case BI_BLIT:
1258 				acf++;
1259 				if (pass)
1260 					log_message(MSG_INFO, "%x ", *acf);
1261 				break;
1262 
1263 			case BI_BDO:
1264 			case BI_QDO:
1265 				if (pass) {
1266 					log_message(MSG_INFO, "%s ",
1267 					    bip->bi_name);
1268 					doprintlevel = 1;
1269 					level++;
1270 				}
1271 				acf++;
1272 				break;
1273 
1274 			case BI_BR:
1275 				acf++;
1276 				if (pass) {
1277 					if (*acf < (token_t)acf) {
1278 						if (nbrstk) {
1279 							doprintlevel = 1;
1280 							level--;
1281 							print_level(level,
1282 							    &doprintlevel);
1283 							log_message(MSG_INFO,
1284 							    "repeat ");
1285 							nbrstk--;
1286 						} else
1287 							log_message(MSG_INFO,
1288 							    "[br back?]");
1289 					} else if (nthentab) {
1290 						doprintlevel = 1;
1291 						print_level(level - 1,
1292 						    &doprintlevel);
1293 						log_message(MSG_INFO, "else ");
1294 						doprintlevel = 1;
1295 						thentab[nthentab - 1] = *acf;
1296 					}
1297 				} else {
1298 					if (*acf < (token_t)acf) {
1299 						brtab[nbrtab++] = *acf;
1300 						brtab[nbrtab++] = (token_t)acf;
1301 					}
1302 					if (endcase_loc == 0 &&
1303 					    case_lit) {
1304 						endcase_loc = *acf;
1305 					}
1306 				}
1307 				break;
1308 
1309 			case BI_QBR:
1310 				acf++;
1311 				if (pass) {
1312 					if (*acf < (token_t)acf) {
1313 						if (nbrstk) {
1314 							doprintlevel = 1;
1315 							level--;
1316 							print_level(level,
1317 							    &doprintlevel);
1318 							log_message(MSG_INFO,
1319 							    "until ");
1320 							nbrstk--;
1321 						} else
1322 							log_message(MSG_INFO,
1323 							    "[br back?]");
1324 					} else if (nbrstk > 0 &&
1325 					    *acf >= brstk[nbrstk - 1]) {
1326 						doprintlevel = 1;
1327 						print_level(level - 1,
1328 						    &doprintlevel);
1329 						log_message(MSG_INFO,
1330 						    "while ");
1331 						doprintlevel = 1;
1332 					} else {
1333 						log_message(MSG_INFO, "if ");
1334 						doprintlevel = 1;
1335 						level++;
1336 						thentab[nthentab++] = *acf;
1337 					}
1338 				} else if (*acf < (token_t)acf) {
1339 					brtab[nbrtab++] = *acf;
1340 					brtab[nbrtab++] = (token_t)acf;
1341 				}
1342 				break;
1343 
1344 			case BI_BOF:
1345 				acf++;
1346 				if (pass) {
1347 					log_message(MSG_INFO, "of ");
1348 					endof_loc = *acf;
1349 				} else if (case_lit == 0) {
1350 					case_lit = last_lit;
1351 				}
1352 				break;
1353 
1354 			case BI_LOOP:
1355 			case BI_PLOOP:
1356 				if (pass) {
1357 					level--;
1358 					doprintlevel = 1;
1359 					print_level(level, &doprintlevel);
1360 					log_message(MSG_INFO, "%s ",
1361 					    bip->bi_name);
1362 				}
1363 				acf++;
1364 				break;
1365 
1366 			default:
1367 				log_message(MSG_ERROR, "Invalid builtin %s\n",
1368 				    bip->bi_name);
1369 			}
1370 		}
1371 	}
1372 }
1373 
1374 static void
see(fcode_env_t * env)1375 see(fcode_env_t *env)
1376 {
1377 	fstack_t d;
1378 
1379 	parse_word(env);
1380 	dollar_find(env);
1381 	d = POP(DS);
1382 	if (d)
1383 		paren_see(env);
1384 	else {
1385 		log_message(MSG_WARN, "?");
1386 		two_drop(env);
1387 	}
1388 }
1389 
1390 static acf_t
do_dot_calls(fcode_env_t * env,acf_t acf,void * cacf)1391 do_dot_calls(fcode_env_t *env, acf_t acf, void *cacf)
1392 {
1393 	token_t *dptr = ACF_TO_LINK(acf);
1394 	token_t *wptr = acf;
1395 
1396 	if (*wptr == (token_t)(&do_colon)) {
1397 		do {
1398 			if ((acf_t)(*wptr) == (acf_t)cacf)
1399 				output_acf_name(acf);
1400 		} while (*wptr++ != (token_t)(&semi_ptr));
1401 	} else if ((acf_t)(*wptr) == cacf)
1402 		output_acf_name(acf);
1403 	else if (wptr == (token_t *)cacf)
1404 		output_acf_name(acf);
1405 	return (NULL);
1406 }
1407 
1408 static void
dot_calls(fcode_env_t * env)1409 dot_calls(fcode_env_t *env)
1410 {
1411 	acf_t acf = (acf_t)POP(DS);
1412 
1413 	(void) search_all_dictionaries(env, do_dot_calls, acf);
1414 	output_acf_name(NULL);
1415 }
1416 
1417 static void
dot_pci_space(fcode_env_t * env)1418 dot_pci_space(fcode_env_t *env)
1419 {
1420 	fstack_t d = POP(DS);
1421 
1422 	switch ((d >> 24) & 0x3) {
1423 	case 0: log_message(MSG_INFO, "Config,"); break;
1424 	case 1: log_message(MSG_INFO, "IO,"); break;
1425 	case 2: log_message(MSG_INFO, "Memory32,"); break;
1426 	case 3: log_message(MSG_INFO, "Memory64,"); break;
1427 	}
1428 	if (d & 0x80000000)
1429 		log_message(MSG_INFO, "Not_reloc,");
1430 	if (d & 0x400000000)
1431 		log_message(MSG_INFO, "Prefetch,");
1432 	if (d & 0x200000000)
1433 		log_message(MSG_INFO, "Alias,");
1434 	log_message(MSG_INFO, "Bus%d,", (d >> 16) & 0xff);
1435 	log_message(MSG_INFO, "Dev%d,", (d >> 11) & 0x1f);
1436 	log_message(MSG_INFO, "Func%d,", (d >> 8) & 0x7);
1437 	log_message(MSG_INFO, "Reg%x", d & 0xff);
1438 	log_message(MSG_INFO, "\n");
1439 }
1440 
1441 void
fcode_debug(fcode_env_t * env)1442 fcode_debug(fcode_env_t *env)
1443 {
1444 	PUSH(DS, (fstack_t)(&env->fcode_debug));
1445 }
1446 
1447 static void
base_addr(fcode_env_t * env)1448 base_addr(fcode_env_t *env)
1449 {
1450 	PUSH(DS, (fstack_t)env->base);
1451 }
1452 
1453 static int mw_valid;
1454 static int mw_size;
1455 static void *mw_addr;
1456 static fstack_t mw_value;
1457 static fstack_t mw_lastvalue;
1458 
1459 static fstack_t
mw_fetch(void)1460 mw_fetch(void)
1461 {
1462 	switch (mw_size) {
1463 	case 1: return (*((uint8_t *)mw_addr));
1464 	case 2: return (*((uint16_t *)mw_addr));
1465 	case 4: return (*((uint32_t *)mw_addr));
1466 	case 8: return (*((uint64_t *)mw_addr));
1467 	}
1468 	return (0);
1469 }
1470 
1471 void
do_memory_watch(fcode_env_t * env)1472 do_memory_watch(fcode_env_t *env)
1473 {
1474 	fstack_t value;
1475 
1476 	if (!mw_valid)
1477 		return;
1478 	value = mw_fetch();
1479 	if (value != mw_lastvalue) {
1480 		if (mw_valid == 1 || mw_value == value) {
1481 			log_message(MSG_INFO,
1482 			    "memory-watch: %p/%d: %llx -> %llx\n",
1483 			    mw_addr, mw_size, (uint64_t)mw_lastvalue,
1484 			    (uint64_t)value);
1485 			(void) do_fclib_step(env);
1486 		}
1487 		mw_lastvalue = value;
1488 	}
1489 }
1490 
1491 static void
set_memory_watch(fcode_env_t * env,int type,int size,void * addr,fstack_t value)1492 set_memory_watch(fcode_env_t *env, int type, int size, void *addr,
1493     fstack_t value)
1494 {
1495 	switch (size) {
1496 	case 1: case 2: case 4: case 8:
1497 		break;
1498 	default:
1499 		log_message(MSG_ERROR, "set_memory_watch: invalid size: %d\n",
1500 		    size);
1501 		return;
1502 	}
1503 	mw_valid = type;
1504 	mw_size = size;
1505 	mw_addr = addr;
1506 	mw_value = value;
1507 	mw_lastvalue = mw_fetch();
1508 }
1509 
1510 static void
memory_watch(fcode_env_t * env)1511 memory_watch(fcode_env_t *env)
1512 {
1513 	int size = POP(DS);
1514 	void *addr = (void *)POP(DS);
1515 
1516 	set_memory_watch(env, 1, size, addr, 0);
1517 }
1518 
1519 static void
memory_watch_value(fcode_env_t * env)1520 memory_watch_value(fcode_env_t *env)
1521 {
1522 	int size = POP(DS);
1523 	void *addr = (void *)POP(DS);
1524 	fstack_t value = POP(DS);
1525 
1526 	set_memory_watch(env, 2, size, addr, value);
1527 }
1528 
1529 static void
memory_watch_clear(fcode_env_t * env)1530 memory_watch_clear(fcode_env_t *env)
1531 {
1532 	mw_valid = 0;
1533 }
1534 
1535 static void
vsearch(fcode_env_t * env)1536 vsearch(fcode_env_t *env)
1537 {
1538 	fstack_t value;
1539 	int size = POP(DS);
1540 	fstack_t match_value = POP(DS);
1541 	uchar_t *toaddr = (uchar_t *)POP(DS);
1542 	uchar_t *fromaddr = (uchar_t *)POP(DS);
1543 
1544 	log_message(MSG_INFO, "%p to %p by %d looking for %llx\n", fromaddr,
1545 	    toaddr, size, (uint64_t)match_value);
1546 	for (; fromaddr < toaddr; fromaddr += size) {
1547 		switch (size) {
1548 		case 1: value = *((uint8_t *)fromaddr); break;
1549 		case 2: value = *((uint16_t *)fromaddr); break;
1550 		case 4: value = *((uint32_t *)fromaddr); break;
1551 		case 8: value = *((uint64_t *)fromaddr); break;
1552 		default:
1553 			log_message(MSG_INFO, "Invalid size: %d\n", size);
1554 			return;
1555 		}
1556 		if (value == match_value)
1557 			log_message(MSG_INFO, "%p\n", fromaddr);
1558 	}
1559 }
1560 
1561 #pragma init(_init)
1562 
1563 static void
_init(void)1564 _init(void)
1565 {
1566 	fcode_env_t *env = initial_env;
1567 
1568 	ASSERT(env);
1569 	NOTICE;
1570 
1571 	FORTH(IMMEDIATE,	"words",		words);
1572 	FORTH(IMMEDIATE,	"dump-words",		dump_words);
1573 	FORTH(IMMEDIATE,	"dump-dict",		dump_dictionary);
1574 	FORTH(IMMEDIATE,	"dump-table",		dump_table);
1575 	FORTH(0,		"debugf",		debugf);
1576 	FORTH(0,		".debugf",		dot_debugf);
1577 	FORTH(0,		"set-debugf",		set_debugf);
1578 	FORTH(0,		"debugf?",		debugf_qmark);
1579 	FORTH(0,		"control",		control);
1580 	FORTH(0,		"dump",			dump);
1581 	FORTH(IMMEDIATE,	"showstack",		show_stack);
1582 	FORTH(IMMEDIATE,	"sifting",		sifting);
1583 	FORTH(IMMEDIATE,	"ctrace",		ctrace);
1584 	FORTH(IMMEDIATE,	"ftrace",		ftrace);
1585 	FORTH(0,		"see",			see);
1586 	FORTH(0,		"(see)",		paren_see);
1587 	FORTH(0,		"base-addr",		base_addr);
1588 	FORTH(0,		"smatch",		smatch);
1589 	FORTH(0,		".calls",		dot_calls);
1590 	FORTH(0,		".pci-space",		dot_pci_space);
1591 	FORTH(0,		"(debug)",		paren_debug);
1592 	FORTH(0,		"debug",		debug);
1593 	FORTH(0,		".debug",		dot_debug);
1594 	FORTH(0,		"undebug",		undebug);
1595 	FORTH(0,		"memory-watch",		memory_watch);
1596 	FORTH(0,		"memory-watch-value",	memory_watch_value);
1597 	FORTH(0,		"memory-watch-clear",	memory_watch_clear);
1598 	FORTH(0,		"vsearch",		vsearch);
1599 }
1600