#include <machine/db_machdep.h>
#include <string.h>
#include <ddb/db_lex.h>
#include <ddb/db_variables.h>
#include <ddb/db_task_thread.h>
#include <ddb/db_sym.h>
#include <ddb/db_command.h>
#include <ddb/db_expr.h>
#include <ddb/db_macro.h>
#include <ddb/db_output.h>
extern db_expr_t db_max_width;
extern db_expr_t db_tab_stop_width;
extern db_expr_t db_max_line;
extern db_expr_t db_auto_wrap;
extern db_expr_t db_macro_level;
extern db_expr_t db_auto_completion;
#define DB_NWORK 32
db_expr_t db_work[DB_NWORK];
struct db_variable db_vars[] = {
{
.name = "maxoff",
.valuep = (db_expr_t*)&db_maxoff,
},
{
.name = "autowrap",
.valuep = &db_auto_wrap,
},
{
.name = "completion",
.valuep = &db_auto_completion,
},
{
.name = "maxwidth",
.valuep = &db_max_width,
},
{
.name = "radix",
.valuep = &db_radix,
},
{
.name = "tabstops",
.valuep = &db_tab_stop_width,
},
{
.name = "lines",
.valuep = &db_max_line,
},
{
.name = "thr_act",
.fcn = db_set_default_act,
},
{
.name = "task",
.fcn = db_get_task_act,
.min_level = 1,
.max_level = 2,
.low = -1,
.high = -1,
},
{
.name = "work",
.valuep = &db_work[0],
.min_level = 1,
.max_level = 1,
.high = DB_NWORK - 1,
},
{
.name = "arg",
.fcn = db_arg_variable,
.min_level = 1,
.max_level = 1,
.low = 1,
.high = DB_MACRO_NARGS,
.hidden_level = 1,
.hidden_low = 0,
.hidden_high = DB_MACRO_LEVEL - 1,
.hidden_levelp = (int *)&db_macro_level,
},
};
struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
static const char *db_get_suffix(const char *, short *);
static boolean_t db_cmp_variable_name(struct db_variable *, const char *,
db_var_aux_param_t);
static int db_find_variable(
struct db_variable **varp,
db_var_aux_param_t ap);
void db_list_variable(void);
static const char *
db_get_suffix(const char *suffix, short *suffix_value)
{
register int value;
for (value = 0; *suffix && *suffix != '.' && *suffix != ':'; suffix++) {
if (*suffix < '0' || *suffix > '9')
return(0);
value = value*10 + *suffix - '0';
}
*suffix_value = value;
if (*suffix == '.')
suffix++;
return(suffix);
}
static boolean_t
db_cmp_variable_name(struct db_variable *vp, const char *name,
db_var_aux_param_t ap)
{
const char *var_np, *np;
int level;
for (np = name, var_np = vp->name; *var_np; ) {
if (*np++ != *var_np++)
return(FALSE);
}
for (level = 0; *np && *np != ':' && level < vp->max_level; level++){
if ((np = db_get_suffix(np, &ap->suffix[level])) == 0)
return(FALSE);
}
if ((*np && *np != ':') || level < vp->min_level
|| (level > 0 && (ap->suffix[0] < vp->low
|| (vp->high >= 0 && ap->suffix[0] > vp->high))))
return(FALSE);
strcpy(ap->modif, (*np)? np+1: "");
ap->thr_act = (db_option(ap->modif, 't')?db_default_act: THREAD_NULL);
ap->level = level;
ap->hidden_level = -1;
return(TRUE);
}
static int
db_find_variable(
struct db_variable **varp,
db_var_aux_param_t ap)
{
int t;
struct db_variable *vp;
t = db_read_token();
if (t == tIDENT) {
for (vp = db_vars; vp < db_evars; vp++) {
if (db_cmp_variable_name(vp, db_tok_string, ap)) {
*varp = vp;
return (1);
}
}
for (vp = db_regs; vp < db_eregs; vp++) {
if (db_cmp_variable_name(vp, db_tok_string, ap)) {
*varp = vp;
return (1);
}
}
#if defined(ALTERNATE_REGISTER_DEFS)
for (vp = db_altregs; vp < db_ealtregs; vp++) {
if (db_cmp_variable_name(vp, db_tok_string, ap)) {
*varp = vp;
return (1);
}
}
#endif
}
db_printf("Unknown variable \"$%s\"\n", db_tok_string);
db_error(0);
return (0);
}
int
db_get_variable(db_expr_t *valuep)
{
struct db_variable *vp;
struct db_var_aux_param aux_param;
char modif[TOK_STRING_SIZE];
aux_param.modif = modif;
if (!db_find_variable(&vp, &aux_param))
return (0);
db_read_write_variable(vp, valuep, DB_VAR_GET, &aux_param);
return (1);
}
void
db_read_write_variable(
struct db_variable *vp,
db_expr_t *valuep,
int rw_flag,
db_var_aux_param_t ap)
{
int (*func)(struct db_variable*, db_expr_t*,int, db_var_aux_param_t)
= vp->fcn;
struct db_var_aux_param aux_param;
db_expr_t old_value;
if (ap == 0) {
ap = &aux_param;
ap->modif = NULL;
ap->level = 0;
ap->thr_act = THREAD_NULL;
}
if (rw_flag == DB_VAR_SET && vp->precious)
db_read_write_variable(vp, &old_value, DB_VAR_GET, ap);
if (func == FCN_NULL) {
if (rw_flag == DB_VAR_SET)
vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0] = *valuep;
else
*valuep = vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0];
} else
(*func)(vp, valuep, rw_flag, ap);
if (rw_flag == DB_VAR_SET && vp->precious)
db_printf("\t$%s:%s<%#x>\t%#8lln\t=\t%#8lln\n", vp->name,
ap->modif, ap->thr_act, (unsigned long long)old_value, (unsigned long long)*valuep);
}
void
db_list_variable(void)
{
register struct db_variable *new;
register struct db_variable *old;
register struct db_variable *cur;
unsigned int l;
unsigned int len;
short i;
unsigned int j;
len = 1;
for (cur = db_vars; cur < db_evars; cur++) {
if (cur->min_level > 0 || cur->max_level > 0) {
j = 3 * (cur->max_level - cur->min_level + 1) - 1;
if (cur->max_level > cur->min_level)
j += 2;
} else
j = 0;
if ((l = strlen(cur->name) + j) >= len)
len = l + 1;
}
old = (struct db_variable *)0;
for (;;) {
new = (struct db_variable *)0;
for (cur = db_vars; cur < db_evars; cur++)
if ((new == (struct db_variable *)0 ||
strcmp(cur->name, new->name) < 0) &&
(old == (struct db_variable *)0 ||
strcmp(cur->name, old->name) > 0))
new = cur;
if (new == (struct db_variable *)0)
return;
db_reserve_output_position(len);
db_printf(new->name);
j = strlen(new->name);
if (new->min_level > 0) {
db_putchar('?');
db_putchar('?');
j += 2;
for (i = new->min_level - 1; i > 0; i--) {
db_putchar('.');
db_putchar('?');
db_putchar('?');
j += 3;
}
if (new->max_level > new->min_level) {
db_putchar('[');
db_putchar('.');
db_putchar('?');
db_putchar('?');
j += 4;
}
i = new->min_level + 1;
} else {
if (new->max_level > new->min_level) {
db_putchar('[');
j++;
}
i = new->min_level;
}
while (i++ < new->max_level) {
db_putchar('.');
db_putchar('?');
db_putchar('?');
j += 3;
}
if (new->max_level > new->min_level) {
db_putchar(']');
j++;
}
while (j++ < len)
db_putchar(' ');
old = new;
}
}
void
db_set_cmd(void)
{
db_expr_t value;
int t;
struct db_variable *vp;
struct db_var_aux_param aux_param;
char modif[TOK_STRING_SIZE];
aux_param.modif = modif;
t = db_read_token();
if (t == tIDENT && strcmp("help", db_tok_string) == 0) {
db_list_variable();
return;
}
if (t != tDOLLAR) {
db_error("Variable name should be prefixed with $\n");
return;
}
if (!db_find_variable(&vp, &aux_param)) {
db_error("Unknown variable\n");
return;
}
t = db_read_token();
if (t != tEQ)
db_unread_token(t);
if (!db_expression(&value)) {
db_error("No value\n");
return;
}
if ((t = db_read_token()) == tSEMI_COLON)
db_unread_token(t);
else if (t != tEOL)
db_error("?\n");
db_read_write_variable(vp, &value, DB_VAR_SET, &aux_param);
}
void
db_show_one_variable(void)
{
struct db_variable *cur;
unsigned int len;
unsigned int sl;
unsigned int slen = 0;
short h = 0;
short i;
unsigned short j;
short k;
short low;
int hidden_level = 0;
struct db_var_aux_param aux_param;
const char *p = NULL, *q;
char *name;
db_addr_t offset = 0;
for (cur = db_vars; cur < db_evars; cur++)
if (db_cmp_variable_name(cur, db_tok_string, &aux_param))
break;
if (cur == db_evars) {
for (cur = db_vars; cur < db_evars; cur++) {
for (q = cur->name, p = db_tok_string; *q && *p == *q; p++,q++)
continue;
if (*q == '\0')
break;
}
if (cur == db_evars) {
db_error("Unknown variable\n");
return;
}
for (i = 0; *p && *p != ':' && i < cur->max_level; i++, p = q)
if ((q = db_get_suffix(p, &aux_param.suffix[i])) == 0)
break;
aux_param.level = i;
if ((*p && *p != ':') ||
(i > 0 && (aux_param.suffix[0] < cur->low ||
(cur->high >= 0 &&
aux_param.suffix[0] > cur->high)))) {
db_error("Unknown variable format\n");
return;
}
strcpy(aux_param.modif, *p ? p + 1 : "");
aux_param.thr_act = (db_option(aux_param.modif, 't') ?
db_default_act : THREAD_NULL);
}
if (cur->hidden_level)
if (*cur->hidden_levelp >= cur->hidden_low &&
*cur->hidden_levelp <= cur->hidden_high) {
hidden_level = 1;
aux_param.hidden_level = h = *cur->hidden_levelp;
} else {
hidden_level = 0;
aux_param.hidden_level = h = cur->hidden_low;
slen = 1;
for (k = aux_param.level > 0 ? aux_param.suffix[0] : cur->high;
k > 9; k /= 10)
slen++;
}
else
aux_param.hidden_level = -1;
if ((cur->min_level == 0 && !cur->hidden_level) || cur->high < 0)
j = 0;
else {
if (cur->min_level > 0) {
j = 1;
for (k = aux_param.level > 0 ?
aux_param.suffix[0] : cur->high; k > 9; k /= 10)
j++;
} else
j = 0;
if (cur->hidden_level && hidden_level == 0) {
j += 3;
for (k = aux_param.hidden_level >= 0 ?
aux_param.hidden_level : cur->hidden_high; k > 9; k /= 10)
j++;
}
}
len = strlen(cur->name) + j;
i = low = aux_param.level > 0 ? aux_param.suffix[0] : cur->low;
for (;;) {
db_printf(cur->name);
j = strlen(cur->name);
if (cur->high >= 0) {
if (cur->min_level > 0) {
db_printf("%d", i);
j++;
for (k = i; k > 9; k /= 10)
j++;
}
if (cur->hidden_level && hidden_level == 0) {
sl = 1;
for (k = i; k > 9; k /= 10)
sl++;
while (sl++ < slen) {
db_putchar(' ');
j++;
}
db_printf("[%d]", h);
j += 3;
for (k = h; k > 9; k /= 10)
j++;
}
}
while (j++ < len)
db_putchar(' ');
db_putchar(':');
db_putchar(' ');
if (cur->fcn) {
aux_param.suffix[0] = i;
(*cur->fcn)(cur, (db_expr_t *)0, DB_VAR_SHOW, &aux_param);
} else {
db_printf("%#lln", (unsigned long long)*(cur->valuep + i));
db_find_xtrn_task_sym_and_offset(*(cur->valuep + i), &name,
&offset, TASK_NULL);
if (name != (char *)0 && offset <= db_maxoff &&
offset != *(cur->valuep + i)) {
db_printf("\t%s", name);
if (offset != 0)
db_printf("+%#llr", (unsigned long long)offset);
}
}
db_putchar('\n');
if (cur->high < 0)
break;
if (aux_param.level > 0 || i++ == cur->high) {
if (!cur->hidden_level ||
hidden_level == 0 ||
h++ == cur->hidden_high)
break;
aux_param.hidden_level = h;
i = low;
}
}
}
void
db_show_variable(__unused db_expr_t addr, __unused boolean_t have_addr,
__unused db_expr_t count, __unused char *modif)
{
struct db_variable *cur;
unsigned int l;
unsigned int len;
unsigned int sl;
unsigned int slen;
short h = 0;
short i;
unsigned short j;
short k;
int t;
int t1;
struct db_var_aux_param aux_param;
char *name;
db_addr_t offset;
switch(t = db_read_token()) {
case tEOL:
case tEOF:
case tSEMI_COLON:
break;
case tDOLLAR:
t1 = db_read_token();
if (t1 == tIDENT) {
db_show_one_variable();
return;
}
db_error("Not a variable name after $\n");
db_unread_token(t);
return;
default:
db_error("Variable name should be prefixed with $\n");
db_unread_token(t);
return;
}
db_unread_token(t);
slen = len = 1;
for (cur = db_vars; cur < db_evars; cur++) {
if ((cur->min_level == 0 && !cur->hidden_level) || cur->high < 0)
j = 0;
else {
if (cur->min_level > 0) {
j = 1;
for (k = cur->high; k > 9; k /= 10)
j++;
} else
j = 0;
if (cur->hidden_level &&
(*cur->hidden_levelp < cur->hidden_low ||
*cur->hidden_levelp > cur->hidden_high)) {
j += 3;
for (k = cur->hidden_high; k > 9; k /= 10)
j++;
}
}
if ((l = strlen(cur->name) + j) >= len)
len = l + 1;
}
aux_param.modif = NULL;
aux_param.level = 1;
aux_param.thr_act = THREAD_NULL;
for (cur = db_vars; cur < db_evars; cur++) {
i = cur->low;
if (cur->hidden_level) {
if (*cur->hidden_levelp >= cur->hidden_low &&
*cur->hidden_levelp <= cur->hidden_high) {
h = cur->hidden_low - 1;
aux_param.hidden_level = *cur->hidden_levelp;
} else {
h = cur->hidden_low;
aux_param.hidden_level = cur->hidden_low;
}
slen = 1;
for (k = cur->high; k > 9; k /= 10)
slen++;
} else
aux_param.hidden_level = -1;
if (cur != db_vars && cur->high >= 0 &&
(cur->min_level > 0 || cur->hidden_level))
db_putchar('\n');
for (;;) {
db_printf(cur->name);
j = strlen(cur->name);
if (cur->high >= 0) {
if (cur->min_level > 0) {
db_printf("%d", i);
j++;
for (k = i; k > 9; k /= 10)
j++;
}
if (cur->hidden_level && h >= cur->hidden_low) {
sl = 1;
for (k = i; k > 9; k /= 10)
sl++;
while (sl++ < slen) {
db_putchar(' ');
j++;
}
db_printf("[%d]", h);
j += 3;
for (k = h; k > 9; k /= 10)
j++;
}
}
while (j++ < len)
db_putchar(' ');
db_putchar(':');
db_putchar(' ');
if (cur->fcn) {
aux_param.suffix[0] = i;
(*cur->fcn)(cur, (db_expr_t *)0, DB_VAR_SHOW, &aux_param);
} else {
db_printf("%#lln", (unsigned long long)*(cur->valuep + i));
db_find_xtrn_task_sym_and_offset(*(cur->valuep + i), &name,
&offset, TASK_NULL);
if (name != (char *)0 && offset <= db_maxoff &&
offset != *(cur->valuep + i)) {
db_printf("\t%s", name);
if (offset != 0)
db_printf("+%#llr", (unsigned long long)offset);
}
}
db_putchar('\n');
if (cur->high < 0)
break;
if (i++ == cur->high) {
if (!cur->hidden_level || h++ == cur->hidden_high)
break;
aux_param.hidden_level = h;
i = cur->low;
}
}
}
}
db_variable_t
db_find_reg_name(
char *s)
{
register db_variable_t regp;
if ( s == (char *)0 )
return DB_VAR_NULL;
for (regp = db_regs; regp < db_eregs; regp++) {
if ( strcmp( s, regp->name) == 0 )
return regp;
}
return DB_VAR_NULL;
}