/* * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ /* * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ #include #include /* For strcpy() */ #include #include #include #include #include #include #include #include /* For db_printf() */ 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 /* number of work variable */ db_expr_t db_work[DB_NWORK]; /* work variable */ 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]); /* Prototypes for functions local to this file. */ 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 /* defined(ALTERNATE_REGISTER_DEFS) */ } 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; } } } } /* * given a name of a machine register, return a variable pointer to it. */ 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; }