diff options
Diffstat (limited to 'usr/src/lib/efcode/engine/debug.c')
-rw-r--r-- | usr/src/lib/efcode/engine/debug.c | 1601 |
1 files changed, 1601 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/engine/debug.c b/usr/src/lib/efcode/engine/debug.c new file mode 100644 index 0000000000..bcdd238b94 --- /dev/null +++ b/usr/src/lib/efcode/engine/debug.c @@ -0,0 +1,1601 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#ifndef DEBUG_LVL +#define DEBUG_LVL 0 +#endif + +struct bitab { + token_t bi_ptr; + char *bi_name; + int bi_type; +}; + +struct bitab *lookup_builtin(token_t); + +static int debug_level = DEBUG_LVL; + +void +set_interpreter_debug_level(long lvl) +{ + debug_level = lvl; +} + +long +get_interpreter_debug_level(void) +{ + return (debug_level); +} + +void +output_data_stack(fcode_env_t *env, int msglevel) +{ + int i; + + log_message(msglevel, "( "); + if (DS > env->ds0) { + for (i = 0; i < (DS - env->ds0); i++) + log_message(msglevel, "%llx ", + (uint64_t)(env->ds0[i + 1])); + } else + log_message(msglevel, "<empty> "); + log_message(msglevel, ") "); +} + +void +output_return_stack(fcode_env_t *env, int show_wa, int msglevel) +{ + int i; + int anyout = 0; + + log_message(msglevel, "R:( "); + if (show_wa) { + log_message(msglevel, "%s ", + acf_backup_search(env, (acf_t)WA)); + anyout++; + } + if (IP) { + anyout++; + log_message(msglevel, "%s ", acf_backup_search(env, IP)); + } + for (i = (RS - env->rs0) - 1; i > 0; i--) { + anyout++; + log_message(msglevel, "%s ", + acf_backup_search(env, (acf_t)env->rs0[i+1])); + } + if (!anyout) + log_message(msglevel, "<empty> "); + log_message(msglevel, ") "); +} + +void +dump_comma(fcode_env_t *env, char *type) +{ + xforth_t d; + + if (strcmp(type, "x,") == 0) + d = peek_xforth(env); + else + d = TOS; + log_message(MSG_FC_DEBUG, "%s %p, %llx\n", type, HERE, (uint64_t)d); +} + +static int ndebug_names; +#define MAXDEBUG_NAMES 10 +static char *debug_names[MAXDEBUG_NAMES]; + +static int ndebug_acfs; +#define MAXDEBUG_ACFS 10 +static acf_t debug_acfs[MAXDEBUG_ACFS]; + +void +add_debug_acf(fcode_env_t *env, acf_t acf) +{ + int i; + + for (i = 0; i < ndebug_acfs; i++) + if (acf == debug_acfs[i]) + return; + + if (!within_dictionary(env, acf)) + log_message(MSG_ERROR, "Can't debug builtin\n"); + else if (ndebug_acfs >= MAXDEBUG_ACFS) + log_message(MSG_ERROR, "Too many debug ACF's\n"); + else { + debug_acfs[ndebug_acfs++] = acf; + *LINK_TO_FLAGS(ACF_TO_LINK(acf)) |= FLAG_DEBUG; + } +} + +static void +paren_debug(fcode_env_t *env) +{ + acf_t acf; + + acf = (acf_t)POP(DS); + if (!within_dictionary(env, acf)) { + log_message(MSG_INFO, "acf: %llx not in dictionary\n", + (uint64_t)acf); + return; + } + if ((acf_t)_ALIGN(acf, token_t) != acf) { + log_message(MSG_INFO, "acf: %llx not aligned\n", + (uint64_t)acf); + return; + } + if (*acf != (token_t)(&do_colon)) { + log_message(MSG_INFO, "acf: %llx not a colon-def\n", + (uint64_t)acf); + return; + } + add_debug_acf(env, acf); +} + +static void +debug(fcode_env_t *env) +{ + fstack_t d; + char *word; + acf_t acf; + + parse_word(env); + dollar_find(env); + d = POP(DS); + if (d) { + acf = (acf_t)POP(DS); + add_debug_acf(env, acf); + } else if (ndebug_names >= MAXDEBUG_NAMES) { + log_message(MSG_ERROR, "Too many forward debug words\n"); + two_drop(env); + } else { + word = pop_a_duped_string(env, NULL); + log_message(MSG_INFO, "Forward defined word: %s\n", word); + debug_names[ndebug_names++] = word; + } +} + +/* + * Eliminate dups and add vocabulary forth to end if not already on list. + */ +static void +order_to_dict_list(fcode_env_t *env, token_t *order[]) +{ + int i, j, norder = 0; + + if (env->current) + order[norder++] = env->current; + for (i = env->order_depth; i >= 0; i--) { + for (j = 0; j < norder && order[j] != env->order[i]; j++) + ; + if (j == norder) + order[norder++] = env->order[i]; + } + for (j = 0; j < norder && order[j] != (token_t *)&env->forth_voc_link; + j++) + ; + if (j == norder) + order[norder++] = (token_t *)&env->forth_voc_link; + order[norder] = NULL; +} + +static acf_t +search_all_dictionaries(fcode_env_t *env, + acf_t (*fn)(fcode_env_t *, acf_t, void *), + void *arg) +{ + token_t *order[MAX_ORDER+1]; + int i; + token_t *dptr; + acf_t acf; + + order_to_dict_list(env, order); + for (i = 0; (dptr = order[i]) != NULL; i++) { + for (dptr = (token_t *)(*dptr); dptr; + dptr = (token_t *)(*dptr)) + if ((acf = (*fn)(env, LINK_TO_ACF(dptr), arg)) != NULL) + return (acf); + } + return (NULL); +} + +char * +acf_to_str(acf_t acf) +{ + static char msg[(sizeof (acf) * 2) + 3]; + + sprintf(msg, "(%08p)", acf); + return (msg); +} + +char * +get_name_or_acf(token_t *dptr) +{ + char *name; + + if ((name = get_name(dptr)) != NULL) + return (name); + return (acf_to_str(LINK_TO_ACF(dptr))); +} + +static void +output_acf_name(acf_t acf) +{ + char *name; + token_t *dptr; + static int acf_count = 0; + + if (acf == NULL) { + if (acf_count) + log_message(MSG_INFO, "\n"); + acf_count = 0; + return; + } + dptr = ACF_TO_LINK(acf); + if ((name = get_name(dptr)) == NULL) + name = "<noname>"; + + log_message(MSG_INFO, "%24s (%08p)", name, acf); + if (++acf_count >= 2) { + log_message(MSG_INFO, "\n"); + acf_count = 0; + } else + log_message(MSG_INFO, " "); +} + +static void +dot_debug(fcode_env_t *env) +{ + int i; + token_t *dptr; + + if (ndebug_names == 0) + log_message(MSG_INFO, "No forward debug words\n"); + else { + for (i = 0; i < ndebug_names; i++) + log_message(MSG_INFO, "%s Forward\n", debug_names[i]); + } + if (ndebug_acfs == 0) + log_message(MSG_INFO, "No debug words\n"); + else { + for (i = 0; i < ndebug_acfs; i++) + log_message(MSG_INFO, "%s\n", + get_name_or_acf(ACF_TO_LINK(debug_acfs[i]))); + } +} + +static void +do_undebug(fcode_env_t *env, char *name) +{ + int i; + + for (i = 0; i < ndebug_names; i++) { + if (strcmp(debug_names[i], name) == 0) { + log_message(MSG_INFO, "Undebugging forward word %s\n", + name); + FREE(debug_names[i]); + for (i++; i < ndebug_names; i++) + debug_names[i - 1] = debug_names[i]; + ndebug_names--; + break; + } + } +} + +static void +undebug(fcode_env_t *env) +{ + fstack_t d; + acf_t acf; + flag_t *flagp; + char *name; + int i, j; + + parse_word(env); + two_dup(env); + dollar_find(env); + d = POP(DS); + if (d) { + acf = (acf_t)POP(DS); + flagp = LINK_TO_FLAGS(ACF_TO_LINK(acf)); + if ((*flagp & FLAG_DEBUG) == 0) + log_message(MSG_WARN, "Word not debugged?\n"); + else { + log_message(MSG_INFO, "Undebugging acf: %p\n", acf); + *flagp &= ~FLAG_DEBUG; + for (i = 0; i < ndebug_acfs; i++) { + if (debug_acfs[i] == acf) { + for (j = i + 1; j < ndebug_acfs; j++) + debug_acfs[j-1] = debug_acfs[j]; + ndebug_acfs--; + break; + } + } + } + } else + two_drop(env); + name = pop_a_string(env, NULL); + do_undebug(env, name); +} + +int +name_is_debugged(fcode_env_t *env, char *name) +{ + int i; + + if (ndebug_names <= 0) + return (0); + for (i = 0; i < ndebug_names; i++) + if (strcmp(debug_names[i], name) == 0) + return (1); + return (0); +} + +/* + * This is complicated by being given ACF's to temporary compile words which + * don't have a header. + */ +int +is_debug_word(fcode_env_t *env, acf_t acf) +{ + flag_t *flagp; + int i; + + /* check to see if any words are being debugged */ + if (ndebug_acfs == 0) + return (0); + + /* only words in dictionary can be debugged */ + if (!within_dictionary(env, acf)) + return (0); + + /* check that word has "FLAG_DEBUG" on */ + flagp = LINK_TO_FLAGS(ACF_TO_LINK(acf)); + if ((*flagp & FLAG_DEBUG) == 0) + return (0); + + /* look in table of debug acf's */ + for (i = 0; i < ndebug_acfs; i++) + if (debug_acfs[i] == acf) + return (1); + return (0); +} + +#define MAX_DEBUG_STACK 100 +token_t debug_low[MAX_DEBUG_STACK], debug_high[MAX_DEBUG_STACK]; +int debug_prev_level[MAX_DEBUG_STACK]; +int debug_curr_level[MAX_DEBUG_STACK]; +int ndebug_stack = 0; + +void +debug_set_level(fcode_env_t *env, int level) +{ + debug_curr_level[ndebug_stack - 1] = level; + set_interpreter_debug_level(level); +} + +token_t +find_semi_in_colon_def(fcode_env_t *env, acf_t acf) +{ + for (; within_dictionary(env, acf); acf++) + if (*acf == (token_t)(&semi_ptr)) + return ((token_t)acf); + return (0); +} + +void +check_for_debug_entry(fcode_env_t *env) +{ + int top; + + if (is_debug_word(env, WA) && ndebug_stack < MAX_DEBUG_STACK) { + top = ndebug_stack++; + debug_prev_level[top] = get_interpreter_debug_level(); + debug_low[top] = (token_t)WA; + if (*WA == (token_t)(&do_colon)) { + debug_high[top] = + find_semi_in_colon_def(env, WA); + } else { + debug_high[top] = 0; /* marker... */ + } + debug_set_level(env, DEBUG_STEPPING); + output_step_message(env); + } +} + +void +check_for_debug_exit(fcode_env_t *env) +{ + if (ndebug_stack) { + int top = ndebug_stack - 1; + + if (debug_high[top] == 0) { + set_interpreter_debug_level(debug_prev_level[top]); + ndebug_stack--; + } else if ((token_t)IP >= debug_low[top] && + (token_t)IP <= debug_high[top]) { + set_interpreter_debug_level(debug_curr_level[top]); + } else { + set_interpreter_debug_level(debug_prev_level[top]); + } + } +} + +void +check_semi_debug_exit(fcode_env_t *env) +{ + if (ndebug_stack) { + int top = ndebug_stack - 1; + + if ((token_t)(IP - 1) == debug_high[top]) { + set_interpreter_debug_level(debug_prev_level[top]); + ndebug_stack--; + } + } +} + +/* + * Really entering do_run, since this may be a recursive entry to do_run, + * we need to set the debug level to what it was previously. + */ +int +current_debug_state(fcode_env_t *env) +{ + if (ndebug_stack) { + int top = ndebug_stack - 1; + set_interpreter_debug_level(debug_prev_level[top]); + } + return (ndebug_stack); +} + +void +clear_debug_state(fcode_env_t *env, int oldstate) +{ + if (ndebug_stack && oldstate <= ndebug_stack) { + set_interpreter_debug_level(debug_prev_level[oldstate]); + ndebug_stack = oldstate; + } +} + +void +unbug(fcode_env_t *env) +{ + int i; + token_t *link; + flag_t *flag; + + for (i = ndebug_stack - 1; i >= 0; i--) { + link = ACF_TO_LINK(debug_low[i]); + flag = LINK_TO_FLAGS(link); + *flag &= ~FLAG_DEBUG; + } + clear_debug_state(env, 0); +} + +void +output_vitals(fcode_env_t *env) +{ + log_message(MSG_FC_DEBUG, "IP=%p, *IP=%p, WA=%p, *WA=%p ", IP, + (IP ? *IP : 0), WA, (WA ? *WA : 0)); +} + +int +do_exec_debug(fcode_env_t *env, void *fn) +{ + int dl = debug_level; + int show_wa = 1; + + if ((dl & (DEBUG_EXEC_DUMP_DS | DEBUG_EXEC_DUMP_RS | + DEBUG_EXEC_SHOW_VITALS | DEBUG_EXEC_TRACE | DEBUG_TRACING | + DEBUG_STEPPING)) == 0) + return (0); + + if (dl & DEBUG_STEPPING) { + dl |= DEBUG_EXEC_DUMP_DS; + } + if (dl & (DEBUG_STEPPING | DEBUG_EXEC_TRACE)) { + log_message(MSG_FC_DEBUG, "%-15s ", acf_to_name(env, WA)); + show_wa = 0; + } + if (dl & DEBUG_EXEC_DUMP_DS) + output_data_stack(env, MSG_FC_DEBUG); + if (dl & DEBUG_EXEC_DUMP_RS) + output_return_stack(env, show_wa, MSG_FC_DEBUG); + if (dl & DEBUG_EXEC_SHOW_VITALS) + output_vitals(env); + if (dl & DEBUG_TRACING) + do_fclib_trace(env, (void *) fn); + log_message(MSG_FC_DEBUG, "\n"); + if (dl & DEBUG_STEPPING) + return (do_fclib_step(env)); + return (0); +} + +static void +smatch(fcode_env_t *env) +{ + int len; + char *str, *p; + + if ((str = parse_a_string(env, &len)) == NULL) + log_message(MSG_INFO, "smatch: no string\n"); + else { + for (p = (char *)env->base; p < (char *)HERE; p++) + if (memcmp(p, str, len) == 0) + log_message(MSG_DEBUG, "%p\n", p); + } +} + +void +check_vitals(fcode_env_t *env) +{ + int i; + token_t *dptr; + + dptr = env->current; + if (*dptr && !within_dictionary(env, (uchar_t *)*dptr)) + log_message(MSG_ERROR, "Current: %p outside dictionary\n", + *dptr); + for (i = env->order_depth; i >= 0; i--) { + dptr = env->order[i]; + if (!dptr) + continue; + if (*dptr && !within_dictionary(env, (uchar_t *)*dptr)) + log_message(MSG_ERROR, "Order%d: %p outside" + " dictionary\n", i, *dptr); + } + if (HERE < env->base || HERE >= env->base + dict_size) { + log_message(MSG_ERROR, "HERE: %p outside range\n", HERE); + } + if (DS < env->ds0 || DS >= &env->ds0[stack_size]) { + forth_abort(env, "DS: %p outside range\n", DS); + } + if (RS < env->rs0 || RS >= &env->rs0[stack_size]) { + log_message(MSG_ERROR, "RS: %p outside range\n", RS); + RS = env->rs0; + } + if (IP && !within_dictionary(env, IP)) + log_message(MSG_ERROR, "IP: %p outside dictionary\n", IP); + if (!within_dictionary(env, (void *)env->forth_voc_link)) + log_message(MSG_ERROR, "forth_voc_link: %p outside" + " dictionary\n", env->forth_voc_link); +} + +static void +dump_table(fcode_env_t *env) +{ + int i; + + for (i = 0; i < MAX_FCODE; i++) { + if (*(env->table[i].apf) != (token_t)(&f_error)) { + log_message(MSG_DEBUG, "Token: %4x %32s acf = %8p," + " %8p\n", i, env->table[i].name, env->table[i].apf, + *(env->table[i].apf)); + } + } + log_message(MSG_DEBUG, "%d FCODES implemented\n", fcode_impl_count); +} + +void +verify_usage(fcode_env_t *env) +{ + int i, untested = 0; + + for (i = 0; i < MAX_FCODE; i++) { + int verify; + + verify = env->table[i].flags & (ANSI_WORD|P1275_WORD); + if ((verify) && +#ifdef DEBUG + (env->table[i].usage == 0) && +#endif + (env->table[i].apf)) { + log_message(MSG_DEBUG, + "Untested: %4x %32s acf = %8p, %8p\n", i, + env->table[i].name, env->table[i].apf, + *(env->table[i].apf)); + untested++; + } + } + if (untested) + log_message(MSG_DEBUG, "%d untested tokens\n", untested); +} + +static void +debugf(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&debug_level); +} + +static void +control(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)&env->control); +} + +struct bittab { + int b_bitval; + char *b_bitname; +} bittab[] = { + DEBUG_CONTEXT, "context", + DEBUG_BYTELOAD_DS, "byteload-ds", + DEBUG_BYTELOAD_RS, "byteload-rs", + DEBUG_BYTELOAD_TOKENS, "byteload-tokens", + DEBUG_NEW_TOKEN, "new-token", + DEBUG_EXEC_TRACE, "exec-trace", + DEBUG_EXEC_SHOW_VITALS, "exec-show-vitals", + DEBUG_EXEC_DUMP_DS, "exec-dump-ds", + DEBUG_EXEC_DUMP_RS, "exec-dump-rs", + DEBUG_COMMA, "comma", + DEBUG_HEADER, "header", + DEBUG_EXIT_WORDS, "exit-words", + DEBUG_EXIT_DUMP, "exit-dump", + DEBUG_DUMP_TOKENS, "dump-tokens", + DEBUG_COLON, "colon", + DEBUG_NEXT_VITALS, "next-vitals", + DEBUG_VOC_FIND, "voc-find", + DEBUG_DUMP_DICT_TOKENS, "dump-dict-tokens", + DEBUG_TOKEN_USAGE, "token-usage", + DEBUG_DUMP_TOKEN_TABLE, "dump-token-table", + DEBUG_SHOW_STACK, "show-stack", + DEBUG_SHOW_RS, "show-rs", + DEBUG_TRACING, "tracing", + DEBUG_TRACE_STACK, "trace-stack", + DEBUG_CALL_METHOD, "call-method", + DEBUG_ACTIONS, "actions", + DEBUG_STEPPING, "stepping", + DEBUG_REG_ACCESS, "reg-access", + DEBUG_ADDR_ABUSE, "addr-abuse", + DEBUG_FIND_FCODE, "find-fcode", + DEBUG_UPLOAD, "upload", + 0 +}; + +void +debug_flags_to_output(fcode_env_t *env, int flags) +{ + int first = 1, i; + + for (i = 0; bittab[i].b_bitval != 0; i++) + if (bittab[i].b_bitval & flags) { + if (!first) + log_message(MSG_INFO, ","); + first = 0; + log_message(MSG_INFO, bittab[i].b_bitname); + } + if (first) + log_message(MSG_INFO, "<empty>"); + log_message(MSG_INFO, "\n"); +} + +static void +dot_debugf(fcode_env_t *env) +{ + debug_flags_to_output(env, debug_level); +} + +static void +debugf_qmark(fcode_env_t *env) +{ + debug_flags_to_output(env, 0xffffffff); +} + +int +debug_flags_to_mask(char *str) +{ + int flags = 0; + char *p; + int i; + + if (isdigit(*str)) { + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') { + sscanf(str + 1, "%x", &flags); + } else + sscanf(str, "%o", &flags); + } else + sscanf(str, "%d", &flags); + return (flags); + } + if (strcmp(str, "clear") == 0) + return (0); + if (strcmp(str, "all") == 0) + return (0xffffffff & ~DEBUG_STEPPING); + if (*str) { + do { + if (p = strchr(str, ',')) + *p++ = '\0'; + for (i = 0; bittab[i].b_bitname != 0; i++) + if (strcmp(str, bittab[i].b_bitname) == 0) { + flags |= bittab[i].b_bitval; + break; + } + if (bittab[i].b_bitname == 0) + log_message(MSG_WARN, + "Unknown debug flag: '%s'\n", str); + str = p; + } while (p); + } + return (flags); +} + +static void +set_debugf(fcode_env_t *env) +{ + char *str; + + str = parse_a_string(env, NULL); + debug_level = debug_flags_to_mask(str); +} + +static acf_t +show_a_word(fcode_env_t *env, acf_t acf, void *arg) +{ + static int nshow_words = 0; + + if (acf == NULL) { + if (nshow_words > 0) { + log_message(MSG_DEBUG, "\n"); + nshow_words = 0; + } + return (NULL); + } + log_message(MSG_DEBUG, "%15s ", get_name_or_acf(ACF_TO_LINK(acf))); + nshow_words++; + if (nshow_words >= 4) { + log_message(MSG_DEBUG, "\n"); + nshow_words = 0; + } + return (NULL); +} + +void +words(fcode_env_t *env) +{ + (void) search_all_dictionaries(env, show_a_word, NULL); + (void) show_a_word(env, NULL, NULL); +} + +static acf_t +dump_a_word(fcode_env_t *env, acf_t acf, void *arg) +{ + output_acf_name(acf); + return (NULL); +} + +void +dump_words(fcode_env_t *env) +{ + (void) search_all_dictionaries(env, dump_a_word, NULL); + output_acf_name(NULL); +} + +static void +dump_line(uchar_t *ptr) +{ + uchar_t *byte; + int i; + + log_message(MSG_INFO, "%p ", (uint32_t)ptr); + for (i = 0, byte = ptr; i < 16; i++) { + if (i == 8) + log_message(MSG_INFO, " "); + log_message(MSG_INFO, "%02.2x ", *byte++); + } + log_message(MSG_INFO, " "); + for (i = 0, byte = ptr; i < 16; i++, byte++) { + log_message(MSG_INFO, "%c", + ((*byte < 0x20) || (*byte > 0x7f)) ? '.' : *byte); + } + log_message(MSG_INFO, "\n"); +} + +void +dump_dictionary(fcode_env_t *env) +{ + uchar_t *ptr; + + log_message(MSG_INFO, "Dictionary dump: base: %p\n", env->base); + for (ptr = (uchar_t *)(((long)(env->base)) & ~0xf); ptr < HERE; + ptr += 16) + dump_line(ptr); +} + +static char * +acf_to_fcode_name(fcode_env_t *env, acf_t acf) +{ + int i; + + for (i = 0; i < MAX_FCODE; i++) + if (env->table[i].apf == acf) + return (env->table[i].name); + return (NULL); +} + +static acf_t +acf_match(fcode_env_t *env, acf_t sacf, void *macf) +{ + if (sacf == (acf_t)macf) + return (sacf); + return (NULL); +} + +/* + * Given an ACF, return ptr to name or "unknown" string. + */ +char * +acf_to_name(fcode_env_t *env, acf_t acf) +{ + struct bitab *bip; + static char name_buf[256]; + uchar_t *p, *np; + int i, n; + + if (!within_dictionary(env, acf)) { + if ((bip = lookup_builtin((token_t)acf)) != NULL) + return (bip->bi_name); + return (NULL); + } + return (get_name_or_acf(ACF_TO_LINK(acf))); +} + +int +within_dictionary(fcode_env_t *env, void *addr) +{ + return ((uchar_t *)addr >= env->base && + (uchar_t *)addr < env->base + dict_size); +} + +static int +within_word(fcode_env_t *env, acf_t acf, acf_t wacf) +{ + if (acf == wacf || acf + 1 == wacf) + return (1); + if (*acf == (token_t)(&do_colon)) { + do { + if (acf == wacf) + return (1); + } while (*acf++ != (token_t)(&semi_ptr)); + } + return (0); +} + +/* + * Given an ACF in the middle of a colon definition, search dictionary towards + * beginning for "colon" acf. If we find a "semi" acf first, we're not in + * the middle of a colon-def (temporary execute?). + */ +char * +acf_backup_search(fcode_env_t *env, acf_t acf) +{ + acf_t nacf; + char *name; + + if ((acf_t)_ALIGN(acf, token_t) == acf && within_dictionary(env, acf)) { + for (nacf = acf; nacf >= (acf_t)env->base; nacf--) + if (*nacf == (token_t)(&do_colon) || + *nacf == (token_t)(&semi_ptr)) + break; + if (nacf >= (acf_t)env->base && *nacf == (token_t)(&do_colon) && + (name = get_name(ACF_TO_LINK(nacf))) != NULL) + return (name); + } + return (acf_to_str(acf)); +} + +/* + * Print out current process's C stack using /usr/proc/bin/pstack + */ +void +ctrace(fcode_env_t *env) +{ + char buf[256]; + FILE *fd; + + log_message(MSG_DEBUG, "Interpreter C Stack:\n"); + sprintf(buf, "/usr/proc/bin/pstack %d", getpid()); + if ((fd = popen(buf, "r")) == NULL) + log_perror(MSG_ERROR, "Can't run: %s", buf); + else { + while (fgets(buf, sizeof (buf), fd)) + log_message(MSG_DEBUG, buf); + fclose(fd); + } +} + +/* + * Dump data, return stacks, try to unthread forth calling stack. + */ +void +ftrace(fcode_env_t *env) +{ + log_message(MSG_DEBUG, "Forth Interpreter Stacks:\n"); + output_data_stack(env, MSG_DEBUG); + output_return_stack(env, 1, MSG_DEBUG); + log_message(MSG_DEBUG, "\n"); +} + +int in_forth_abort; + +/* + * Handle fatal error, if interactive mode, return to ok prompt. + */ +void +forth_abort(fcode_env_t *env, char *fmt, ...) +{ + va_list ap; + char msg[256]; + + if (in_forth_abort) { + log_message(MSG_FATAL, "ABORT: abort within forth_abort\n"); + abort(); + } + in_forth_abort++; + + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + log_message(MSG_ERROR, "ABORT: %s\n", msg); + + if (env) { + ctrace(env); + ftrace(env); + } + + return_to_interact(env); + /* + * If not in interactive mode, return_to_interact just returns. + */ + exit(1); +} + +/* + * Handle fatal system call error + */ +void +forth_perror(fcode_env_t *env, char *fmt, ...) +{ + va_list ap; + char msg[256]; + int save_errno = errno; /* just in case... */ + + va_start(ap, fmt); + vsprintf(msg, fmt, ap); + + forth_abort(env, "%s: %s", msg, strerror(save_errno)); +} + +static void +show_stack(fcode_env_t *env) +{ +#ifdef DEBUG + debug_level ^= DEBUG_SHOW_STACK; +#else + /*EMPTY*/ +#endif +} + +static void +print_bytes_header(int width, int offset) +{ + int i; + + for (i = 0; i < width; i++) + log_message(MSG_INFO, " "); + log_message(MSG_INFO, " "); + for (i = 0; i < 16; i++) { + if (i == 8) + log_message(MSG_INFO, " "); + if (i == offset) + log_message(MSG_INFO, "\\/ "); + else + log_message(MSG_INFO, "%2x ", i); + } + log_message(MSG_INFO, " "); + for (i = 0; i < 16; i++) { + if (i == offset) + log_message(MSG_INFO, "v"); + else + log_message(MSG_INFO, "%x", i); + } + log_message(MSG_INFO, "\n"); +} + +static void +dump(fcode_env_t *env) +{ + uchar_t *data; + int len, offset; + char buf[20]; + + len = POP(DS); + data = (uchar_t *)POP(DS); + offset = ((long)data) & 0xf; + len += offset; + data = (uchar_t *)((long)data & ~0xf); + sprintf(buf, "%p", (uint32_t)data); + print_bytes_header(strlen(buf), offset); + for (len += offset; len > 0; len -= 16, data += 16) + dump_line(data); +} + +static acf_t +do_sifting(fcode_env_t *env, acf_t acf, void *pat) +{ + char *name; + + if ((name = get_name(ACF_TO_LINK(acf))) != NULL && strstr(name, pat)) + output_acf_name(acf); + return (NULL); +} + +static void +sifting(fcode_env_t *env) +{ + char *pat; + + if ((pat = parse_a_string(env, NULL)) != NULL) { + (void) search_all_dictionaries(env, do_sifting, pat); + output_acf_name(NULL); + } +} + +void +print_level(int level, int *doprint) +{ + int i; + + if (*doprint) { + log_message(MSG_DEBUG, "\n "); + for (i = 0; i < level; i++) + log_message(MSG_DEBUG, " "); + *doprint = 0; + } +} + +#define BI_QUOTE 1 +#define BI_BLIT 2 +#define BI_BDO 3 +#define BI_QDO 4 +#define BI_BR 5 +#define BI_QBR 6 +#define BI_BOF 7 +#define BI_LOOP 8 +#define BI_PLOOP 9 +#define BI_TO 10 +#define BI_SEMI 11 +#define BI_COLON 12 +#define BI_NOOP 13 +#define BI_NOTYET 14 /* unimplented in "see" */ + +struct bitab bitab[] = { + (token_t)("e_ptr), "\"", BI_QUOTE, + (token_t)(&blit_ptr), "blit", BI_BLIT, + (token_t)(&do_bdo_ptr), "do", BI_BDO, + (token_t)(&do_bqdo_ptr), "?do", BI_QDO, + (token_t)(&bbranch_ptrs[0]), "br", BI_BR, + (token_t)(&bbranch_ptrs[1]), "qbr", BI_QBR, + (token_t)(&bbranch_ptrs[2]), "bof", BI_BOF, + (token_t)(&do_loop_ptr), "loop", BI_LOOP, + (token_t)(&do_ploop_ptr), "+loop", BI_PLOOP, + (token_t)(&to_ptr), "to", BI_NOOP, + (token_t)(&semi_ptr), ";", BI_SEMI, + (token_t)(&do_colon), ":", BI_COLON, + (token_t)(&tlit_ptr), "[']", BI_NOOP, + (token_t)(&do_leave_ptr), "leave", BI_NOTYET, + (token_t)(&create_ptr), "create", BI_NOTYET, + (token_t)(&does_ptr), "does>", BI_NOTYET, + (token_t)(&value_defines[0][0]), "a.@", BI_NOTYET, + (token_t)(&value_defines[0][1]), "a.!", BI_NOTYET, + (token_t)(&value_defines[0][2]), "a.nop", BI_NOTYET, + (token_t)(&value_defines[1][0]), "a.i@", BI_NOTYET, + (token_t)(&value_defines[1][1]), "a.i!", BI_NOTYET, + (token_t)(&value_defines[1][2]), "a.iad", BI_NOTYET, + (token_t)(&value_defines[2][0]), "a.defer", BI_NOTYET, + (token_t)(&value_defines[2][1]), "a.@", BI_NOTYET, + (token_t)(&value_defines[2][2]), "a.nop", BI_NOTYET, + (token_t)(&value_defines[3][0]), "a.defexec", BI_NOTYET, + (token_t)(&value_defines[3][1]), "a.iset", BI_NOTYET, + (token_t)(&value_defines[3][2]), "a.iad", BI_NOTYET, + (token_t)(&value_defines[4][0]), "a.binit", BI_NOTYET, + (token_t)(&value_defines[4][1]), "a.2drop", BI_NOTYET, + (token_t)(&value_defines[4][2]), "a.nop", BI_NOTYET, + (token_t)(&value_defines[5][0]), "a.ibinit", BI_NOTYET, + (token_t)(&value_defines[5][1]), "a.2drop", BI_NOTYET, + (token_t)(&value_defines[5][2]), "a.iad", BI_NOTYET, + 0 +}; + +struct bitab * +lookup_builtin(token_t builtin) +{ + int i; + + for (i = 0; bitab[i].bi_ptr; i++) + if (bitab[i].bi_ptr == builtin) + return (&bitab[i]); + return (NULL); +} + +static void +paren_see(fcode_env_t *env) +{ + acf_t save_acf = (acf_t)POP(DS); + acf_t acf = save_acf; + int i, n, pass; + token_t brtab[30], thentab[30], brstk[30]; + int nbrtab = 0, nthentab = 0, nbrstk = 0; + uchar_t *p; + int level = 0, doprintlevel = 1, nthen; + struct bitab *bip; + token_t last_lit = 0, case_lit = 0, endof_loc = 0, endcase_loc = 0; + + if ((bip = lookup_builtin(*acf)) == NULL || + bip->bi_type != BI_COLON) { + if (bip = lookup_builtin((token_t)acf)) + log_message(MSG_INFO, "%s: builtin\n", bip->bi_name); + else + log_message(MSG_INFO, "%s: builtin\n", + acf_to_name(env, acf)); + return; + } + log_message(MSG_INFO, ": %s", acf_to_name(env, acf)); + for (pass = 0; pass < 2; pass++) { + acf = save_acf; + for (acf++; ; acf++) { + if (pass) { + print_level(level, &doprintlevel); + for (nthen = 0; nthentab > 0 && + thentab[nthentab-1] == (token_t)acf; + nthentab--) + nthen++; + if (nthen) { + level -= nthen; + doprintlevel = 1; + print_level(level, &doprintlevel); + for (i = 0; i < nthen; i++) + log_message(MSG_INFO, "then "); + } + print_level(level, &doprintlevel); + for (i = 0; i < nbrtab; i += 2) + if ((token_t)acf == brtab[i]) { + log_message(MSG_INFO, "begin "); + brstk[nbrstk++] = brtab[i+1]; + level++; + doprintlevel = 1; + } + print_level(level, &doprintlevel); + if (case_lit == (token_t)acf) { + log_message(MSG_INFO, "case "); + doprintlevel = 1; + print_level(level, &doprintlevel); + } + if (endof_loc == (token_t)acf) { + log_message(MSG_INFO, "endof "); + doprintlevel = 1; + print_level(level, &doprintlevel); + } + if (endcase_loc == (token_t)acf) { + doprintlevel = 1; + print_level(level, &doprintlevel); + log_message(MSG_INFO, "endcase "); + } + } + if ((bip = lookup_builtin((token_t)*acf)) == 0) { + last_lit = (token_t)acf; + if (pass) + log_message(MSG_INFO, "%s ", + acf_to_name(env, (acf_t)*acf)); + continue; + } + if (bip->bi_type == BI_SEMI) { + if (pass) { + log_message(MSG_INFO, "\n"); + log_message(MSG_INFO, "%s\n", + bip->bi_name); + } + break; + } + switch (bip->bi_type) { + + case BI_NOOP: + case BI_NOTYET: + if (pass) + log_message(MSG_INFO, "%s ", + bip->bi_name); + break; + + case BI_QUOTE: + if (pass) + log_message(MSG_INFO, "\" "); + acf++; + p = (uchar_t *)acf; + n = *p++; + if (pass) + log_message(MSG_INFO, "%s\" ", p); + p += n + 1; + for (; ((token_t)(p)) & (sizeof (token_t) - 1); + p++) + ; + acf = (acf_t)p; + acf--; + break; + + case BI_BLIT: + acf++; + if (pass) + log_message(MSG_INFO, "%x ", *acf); + break; + + case BI_BDO: + case BI_QDO: + if (pass) { + log_message(MSG_INFO, "%s ", + bip->bi_name); + doprintlevel = 1; + level++; + } + acf++; + break; + + case BI_BR: + acf++; + if (pass) { + if (*acf < (token_t)acf) { + if (nbrstk) { + doprintlevel = 1; + level--; + print_level(level, + &doprintlevel); + log_message(MSG_INFO, + "repeat "); + nbrstk--; + } else + log_message(MSG_INFO, + "[br back?]"); + } else if (nthentab) { + doprintlevel = 1; + print_level(level - 1, + &doprintlevel); + log_message(MSG_INFO, "else "); + doprintlevel = 1; + thentab[nthentab - 1] = *acf; + } + } else { + if (*acf < (token_t)acf) { + brtab[nbrtab++] = *acf; + brtab[nbrtab++] = (token_t)acf; + } + if (endcase_loc == 0 && + case_lit) { + endcase_loc = *acf; + } + } + break; + + case BI_QBR: + acf++; + if (pass) { + if (*acf < (token_t)acf) { + if (nbrstk) { + doprintlevel = 1; + level--; + print_level(level, + &doprintlevel); + log_message(MSG_INFO, + "until "); + nbrstk--; + } else + log_message(MSG_INFO, + "[br back?]"); + } else if (nbrstk > 0 && + *acf >= brstk[nbrstk - 1]) { + doprintlevel = 1; + print_level(level - 1, + &doprintlevel); + log_message(MSG_INFO, + "while "); + doprintlevel = 1; + } else { + log_message(MSG_INFO, "if "); + doprintlevel = 1; + level++; + thentab[nthentab++] = *acf; + } + } else if (*acf < (token_t)acf) { + brtab[nbrtab++] = *acf; + brtab[nbrtab++] = (token_t)acf; + } + break; + + case BI_BOF: + acf++; + if (pass) { + log_message(MSG_INFO, "of "); + endof_loc = *acf; + } else if (case_lit == 0) { + case_lit = last_lit; + } + break; + + case BI_LOOP: + case BI_PLOOP: + if (pass) { + level--; + doprintlevel = 1; + print_level(level, &doprintlevel); + log_message(MSG_INFO, "%s ", + bip->bi_name); + } + acf++; + break; + + default: + log_message(MSG_ERROR, "Invalid builtin %s\n", + bip->bi_name); + } + } + } +} + +static void +see(fcode_env_t *env) +{ + fstack_t d; + + parse_word(env); + dollar_find(env); + d = POP(DS); + if (d) + paren_see(env); + else { + log_message(MSG_WARN, "?"); + two_drop(env); + } +} + +static acf_t +do_dot_calls(fcode_env_t *env, acf_t acf, void *cacf) +{ + token_t *dptr = ACF_TO_LINK(acf); + token_t *wptr = acf; + + if (*wptr == (token_t)(&do_colon)) { + do { + if ((acf_t)(*wptr) == (acf_t)cacf) + output_acf_name(acf); + } while (*wptr++ != (token_t)(&semi_ptr)); + } else if ((acf_t)(*wptr) == cacf) + output_acf_name(acf); + else if (wptr == (token_t *)cacf) + output_acf_name(acf); + return (NULL); +} + +static void +dot_calls(fcode_env_t *env) +{ + acf_t acf = (acf_t)POP(DS); + + search_all_dictionaries(env, do_dot_calls, acf); + output_acf_name(NULL); +} + +static void +dot_pci_space(fcode_env_t *env) +{ + fstack_t d = POP(DS); + + switch ((d >> 24) & 0x3) { + case 0: log_message(MSG_INFO, "Config,"); break; + case 1: log_message(MSG_INFO, "IO,"); break; + case 2: log_message(MSG_INFO, "Memory32,"); break; + case 3: log_message(MSG_INFO, "Memory64,"); break; + } + if (d & 0x80000000) + log_message(MSG_INFO, "Not_reloc,"); + if (d & 0x400000000) + log_message(MSG_INFO, "Prefetch,"); + if (d & 0x200000000) + log_message(MSG_INFO, "Alias,"); + log_message(MSG_INFO, "Bus%d,", (d >> 16) & 0xff); + log_message(MSG_INFO, "Dev%d,", (d >> 11) & 0x1f); + log_message(MSG_INFO, "Func%d,", (d >> 8) & 0x7); + log_message(MSG_INFO, "Reg%x", d & 0xff); + log_message(MSG_INFO, "\n"); +} + +void +fcode_debug(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)(&env->fcode_debug)); +} + +static void +base_addr(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)env->base); +} + +static int mw_valid; +static int mw_size; +static void *mw_addr; +static fstack_t mw_value; +static fstack_t mw_lastvalue; + +static fstack_t +mw_fetch(void) +{ + switch (mw_size) { + case 1: return (*((uint8_t *)mw_addr)); + case 2: return (*((uint16_t *)mw_addr)); + case 4: return (*((uint32_t *)mw_addr)); + case 8: return (*((uint64_t *)mw_addr)); + } + return (0); +} + +void +do_memory_watch(fcode_env_t *env) +{ + fstack_t value; + + if (!mw_valid) + return; + value = mw_fetch(); + if (value != mw_lastvalue) { + if (mw_valid == 1 || mw_value == value) { + log_message(MSG_INFO, + "memory-watch: %p/%d: %llx -> %llx\n", + mw_addr, mw_size, (uint64_t)mw_lastvalue, + (uint64_t)value); + do_fclib_step(env); + } + mw_lastvalue = value; + } +} + +static void +set_memory_watch(fcode_env_t *env, int type, int size, void *addr, + fstack_t value) +{ + switch (size) { + case 1: case 2: case 4: case 8: + break; + default: + log_message(MSG_ERROR, "set_memory_watch: invalid size: %d\n", + size); + return; + } + mw_valid = type; + mw_size = size; + mw_addr = addr; + mw_value = value; + mw_lastvalue = mw_fetch(); +} + +static void +memory_watch(fcode_env_t *env) +{ + int size = POP(DS); + void *addr = (void *)POP(DS); + + set_memory_watch(env, 1, size, addr, 0); +} + +static void +memory_watch_value(fcode_env_t *env) +{ + int size = POP(DS); + void *addr = (void *)POP(DS); + fstack_t value = POP(DS); + + set_memory_watch(env, 2, size, addr, value); +} + +static void +memory_watch_clear(fcode_env_t *env) +{ + mw_valid = 0; +} + +static void +vsearch(fcode_env_t *env) +{ + fstack_t value; + int size = POP(DS); + fstack_t match_value = POP(DS); + uchar_t *toaddr = (uchar_t *)POP(DS); + uchar_t *fromaddr = (uchar_t *)POP(DS); + + log_message(MSG_INFO, "%p to %p by %d looking for %llx\n", fromaddr, + toaddr, size, (uint64_t)match_value); + for (; fromaddr < toaddr; fromaddr += size) { + switch (size) { + case 1: value = *((uint8_t *)fromaddr); break; + case 2: value = *((uint16_t *)fromaddr); break; + case 4: value = *((uint32_t *)fromaddr); break; + case 8: value = *((uint64_t *)fromaddr); break; + default: + log_message(MSG_INFO, "Invalid size: %d\n", size); + return; + } + if (value == match_value) + log_message(MSG_INFO, "%p\n", fromaddr); + } +} + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + NOTICE; + + FORTH(IMMEDIATE, "words", words); + FORTH(IMMEDIATE, "dump-words", dump_words); + FORTH(IMMEDIATE, "dump-dict", dump_dictionary); + FORTH(IMMEDIATE, "dump-table", dump_table); + FORTH(0, "debugf", debugf); + FORTH(0, ".debugf", dot_debugf); + FORTH(0, "set-debugf", set_debugf); + FORTH(0, "debugf?", debugf_qmark); + FORTH(0, "control", control); + FORTH(0, "dump", dump); + FORTH(IMMEDIATE, "showstack", show_stack); + FORTH(IMMEDIATE, "sifting", sifting); + FORTH(IMMEDIATE, "ctrace", ctrace); + FORTH(IMMEDIATE, "ftrace", ftrace); + FORTH(0, "see", see); + FORTH(0, "(see)", paren_see); + FORTH(0, "base-addr", base_addr); + FORTH(0, "smatch", smatch); + FORTH(0, ".calls", dot_calls); + FORTH(0, ".pci-space", dot_pci_space); + FORTH(0, "(debug)", paren_debug); + FORTH(0, "debug", debug); + FORTH(0, ".debug", dot_debug); + FORTH(0, "undebug", undebug); + FORTH(0, "memory-watch", memory_watch); + FORTH(0, "memory-watch-value", memory_watch_value); + FORTH(0, "memory-watch-clear", memory_watch_clear); + FORTH(0, "vsearch", vsearch); +} |