/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * 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. 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_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ /* * HISTORY * * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez * Import of Mac OS X kernel (~semeria) * * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez * Import of OSF Mach kernel (~mburg) * * Revision 1.2.18.5 1996/01/09 19:16:34 devrcs * Search the alternate register names if configured * Changed declarations of 'register foo' to 'register int foo'. * [1995/12/01 21:42:42 jfraser] * * Merged '64-bit safe' changes from DEC alpha port. * [1995/11/21 18:03:56 jfraser] * * Revision 1.2.18.4 1995/02/23 21:43:56 alanl * Merged with DIPC2_SHARED. * [1995/01/05 13:35:55 alanl] * * Revision 1.2.21.1 1994/11/04 09:53:26 dwm * mk6 CR668 - 1.3b26 merge * * Revision 1.2.4.6 1994/05/06 18:40:13 tmt * Merged osc1.3dec/shared with osc1.3b19 * Merge Alpha changes into osc1.312b source code. * 64bit cleanup. * * End1.3merge * [1994/11/04 08:50:12 dwm] * * Revision 1.2.18.2 1994/09/23 01:22:35 ezf * change marker to not FREE * [1994/09/22 21:11:24 ezf] * * Revision 1.2.18.1 1994/06/11 21:12:37 bolinger * Merge up to NMK17.2. * [1994/06/11 20:03:04 bolinger] * * Revision 1.2.23.1 1994/12/06 19:43:18 alanl * Intel merge, Oct 94 code drop. * Added db_find_reg_name (came from db_print.c). * [94/11/28 mmp] * * Revision 1.2.16.1 1994/02/08 10:59:08 bernadat * Added completion variable. * [93/08/17 paire] * * Set up new fields (hidden_xxx) of db_vars[] array that are supposed * to be helpful to display variables depending on an internal value * like db_macro_level for macro arguments. * Added db_auto_wrap as new variable. * Added "set help" for listing all available variables. * Added db_show_variable() and db_show_one_variable() * to print variable values. * [93/08/12 paire] * [94/02/08 bernadat] * * Revision 1.2.4.4 1993/08/11 20:38:20 elliston * Add ANSI Prototypes. CR #9523. * [1993/08/11 03:34:13 elliston] * * Revision 1.2.4.3 1993/07/27 18:28:27 elliston * Add ANSI prototypes. CR #9523. * [1993/07/27 18:13:22 elliston] * * Revision 1.2.4.2 1993/06/09 02:21:02 gm * Added to OSF/1 R1.3 from NMK15.0. * [1993/06/02 20:57:43 jeffc] * * Revision 1.2 1993/04/19 16:03:25 devrcs * Changes from mk78: * Added void to db_read_write_variable(). * Removed unused variable 'func' from db_set_cmd(). * [92/05/16 jfriedl] * [93/02/02 bruel] * * Print old value when changing register values. * [barbou@gr.osf.org] * [92/12/03 bernadat] * * Revision 1.1 1992/09/30 02:01:31 robert * Initial revision * * $EndLog$ */ /* CMU_HIST */ /* * Revision 2.5 91/10/09 16:03:59 af * Revision 2.4.3.1 91/10/05 13:08:27 jeffreyh * Added suffix handling and thread handling of variables. * Added new variables: lines, task, thread, work and arg. * Moved db_read_variable and db_write_variable to db_variables.h * as macros, and added db_read_write_variable instead. * Changed some error messages. * [91/08/29 tak] * * Revision 2.4.3.1 91/10/05 13:08:27 jeffreyh * Added suffix handling and thread handling of variables. * Added new variables: lines, task, thread, work and arg. * Moved db_read_variable and db_write_variable to db_variables.h * as macros, and added db_read_write_variable instead. * Changed some error messages. * [91/08/29 tak] * * Revision 2.4 91/05/14 15:36:57 mrt * Correcting copyright * * Revision 2.3 91/02/05 17:07:19 mrt * Changed to new Mach copyright * [91/01/31 16:19:46 mrt] * * Revision 2.2 90/08/27 21:53:24 dbg * New db_read/write_variable functions. Should be used instead * of dereferencing valuep directly, which might not be a true * pointer if there is an fcn() access function. * [90/08/20 af] * * Fix declarations. * Check for trailing garbage after last expression on command line. * [90/08/10 14:34:54 dbg] * * Created. * [90/07/25 dbg] * */ /* CMU_ENDHIST */ /* * 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_radix; 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[] = { { "maxoff", (db_expr_t*)&db_maxoff, FCN_NULL }, { "autowrap", &db_auto_wrap, FCN_NULL }, { "completion", &db_auto_completion, FCN_NULL }, { "maxwidth", &db_max_width, FCN_NULL }, { "radix", &db_radix, FCN_NULL }, { "tabstops", &db_tab_stop_width, FCN_NULL }, { "lines", &db_max_line, FCN_NULL }, { "thr_act", 0, db_set_default_act }, { "task", 0, db_get_task_act, 1, 2, -1, -1 }, { "work", &db_work[0], FCN_NULL, 1, 1, 0, DB_NWORK-1 }, { "arg", 0, db_arg_variable, 1, 1, 1, DB_MACRO_NARGS, 1, 0, DB_MACRO_LEVEL-1, (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 char *db_get_suffix( register char *suffix, short *suffix_value); static boolean_t db_cmp_variable_name( struct db_variable *vp, char *name, register db_var_aux_param_t ap); static int db_find_variable( struct db_variable **varp, db_var_aux_param_t ap); static int db_set_variable(db_expr_t value); void db_list_variable(void); static char * db_get_suffix( register 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, char *name, register db_var_aux_param_t ap) { register char *var_np, *np; register 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: THR_ACT_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); } static int db_set_variable(db_expr_t value) { 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, &value, DB_VAR_SET, &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 = ""; ap->level = 0; ap->thr_act = THR_ACT_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%#8n\t=\t%#8n\n", vp->name, ap->modif, ap->thr_act, old_value, *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; short h; short i; short j; short k; short low; int hidden_level; struct db_var_aux_param aux_param; char *p; char *q; char *name; db_addr_t offset; 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 : THR_ACT_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("%#n", *(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("+%#r", 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(void) { struct db_variable *cur; unsigned int l; unsigned int len; unsigned int sl; unsigned int slen; short h; short i; 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 = ""; aux_param.level = 1; aux_param.thr_act = THR_ACT_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("%#n", *(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("+%#r", 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; }