2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
59 * Author: David B. Golub, Carnegie Mellon University
63 #include <machine/db_machdep.h>
64 #include <string.h> /* For strcpy() */
66 #include <ddb/db_lex.h>
67 #include <ddb/db_variables.h>
68 #include <ddb/db_task_thread.h>
69 #include <ddb/db_sym.h>
70 #include <ddb/db_command.h>
71 #include <ddb/db_expr.h>
72 #include <ddb/db_macro.h>
73 #include <ddb/db_output.h> /* For db_printf() */
75 extern db_expr_t db_radix
;
76 extern db_expr_t db_max_width
;
77 extern db_expr_t db_tab_stop_width
;
78 extern db_expr_t db_max_line
;
79 extern db_expr_t db_auto_wrap
;
80 extern db_expr_t db_macro_level
;
81 extern db_expr_t db_auto_completion
;
83 #define DB_NWORK 32 /* number of work variable */
85 db_expr_t db_work
[DB_NWORK
]; /* work variable */
87 struct db_variable db_vars
[] = {
88 { "maxoff", (db_expr_t
*)&db_maxoff
, FCN_NULL
},
89 { "autowrap", &db_auto_wrap
, FCN_NULL
},
90 { "completion", &db_auto_completion
, FCN_NULL
},
91 { "maxwidth", &db_max_width
, FCN_NULL
},
92 { "radix", &db_radix
, FCN_NULL
},
93 { "tabstops", &db_tab_stop_width
, FCN_NULL
},
94 { "lines", &db_max_line
, FCN_NULL
},
95 { "thr_act", 0, db_set_default_act
},
96 { "task", 0, db_get_task_act
,
98 { "work", &db_work
[0], FCN_NULL
,
99 1, 1, 0, DB_NWORK
-1 },
100 { "arg", 0, db_arg_variable
,
101 1, 1, 1, DB_MACRO_NARGS
,
102 1, 0, DB_MACRO_LEVEL
-1, (int *)&db_macro_level
},
104 struct db_variable
*db_evars
= db_vars
+ sizeof(db_vars
)/sizeof(db_vars
[0]);
108 /* Prototypes for functions local to this file.
111 static char *db_get_suffix(
112 register char *suffix
,
113 short *suffix_value
);
115 static boolean_t
db_cmp_variable_name(
116 struct db_variable
*vp
,
118 register db_var_aux_param_t ap
);
120 static int db_find_variable(
121 struct db_variable
**varp
,
122 db_var_aux_param_t ap
);
124 static int db_set_variable(db_expr_t value
);
126 void db_list_variable(void);
130 register char *suffix
,
135 for (value
= 0; *suffix
&& *suffix
!= '.' && *suffix
!= ':'; suffix
++) {
136 if (*suffix
< '0' || *suffix
> '9')
138 value
= value
*10 + *suffix
- '0';
140 *suffix_value
= value
;
147 db_cmp_variable_name(
148 struct db_variable
*vp
,
150 register db_var_aux_param_t ap
)
152 register char *var_np
, *np
;
155 for (np
= name
, var_np
= vp
->name
; *var_np
; ) {
156 if (*np
++ != *var_np
++)
159 for (level
= 0; *np
&& *np
!= ':' && level
< vp
->max_level
; level
++){
160 if ((np
= db_get_suffix(np
, &ap
->suffix
[level
])) == 0)
163 if ((*np
&& *np
!= ':') || level
< vp
->min_level
164 || (level
> 0 && (ap
->suffix
[0] < vp
->low
165 || (vp
->high
>= 0 && ap
->suffix
[0] > vp
->high
))))
167 strcpy(ap
->modif
, (*np
)? np
+1: "");
168 ap
->thr_act
= (db_option(ap
->modif
, 't')?db_default_act
: THREAD_NULL
);
170 ap
->hidden_level
= -1;
176 struct db_variable
**varp
,
177 db_var_aux_param_t ap
)
180 struct db_variable
*vp
;
184 for (vp
= db_vars
; vp
< db_evars
; vp
++) {
185 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
190 for (vp
= db_regs
; vp
< db_eregs
; vp
++) {
191 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
196 #if defined(ALTERNATE_REGISTER_DEFS)
197 for (vp
= db_altregs
; vp
< db_ealtregs
; vp
++) {
198 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
203 #endif /* defined(ALTERNATE_REGISTER_DEFS) */
205 db_printf("Unknown variable \"$%s\"\n", db_tok_string
);
211 db_get_variable(db_expr_t
*valuep
)
213 struct db_variable
*vp
;
214 struct db_var_aux_param aux_param
;
215 char modif
[TOK_STRING_SIZE
];
217 aux_param
.modif
= modif
;
218 if (!db_find_variable(&vp
, &aux_param
))
221 db_read_write_variable(vp
, valuep
, DB_VAR_GET
, &aux_param
);
227 db_set_variable(db_expr_t value
)
229 struct db_variable
*vp
;
230 struct db_var_aux_param aux_param
;
231 char modif
[TOK_STRING_SIZE
];
233 aux_param
.modif
= modif
;
234 if (!db_find_variable(&vp
, &aux_param
))
237 db_read_write_variable(vp
, &value
, DB_VAR_SET
, &aux_param
);
243 db_read_write_variable(
244 struct db_variable
*vp
,
247 db_var_aux_param_t ap
)
249 int (*func
)(struct db_variable
*, db_expr_t
*,int, db_var_aux_param_t
)
251 struct db_var_aux_param aux_param
;
258 ap
->thr_act
= THREAD_NULL
;
260 if (rw_flag
== DB_VAR_SET
&& vp
->precious
)
261 db_read_write_variable(vp
, &old_value
, DB_VAR_GET
, ap
);
262 if (func
== FCN_NULL
) {
263 if (rw_flag
== DB_VAR_SET
)
264 vp
->valuep
[(ap
->level
)? (ap
->suffix
[0] - vp
->low
): 0] = *valuep
;
266 *valuep
= vp
->valuep
[(ap
->level
)? (ap
->suffix
[0] - vp
->low
): 0];
268 (*func
)(vp
, valuep
, rw_flag
, ap
);
269 if (rw_flag
== DB_VAR_SET
&& vp
->precious
)
270 db_printf("\t$%s:%s<%#x>\t%#8lln\t=\t%#8lln\n", vp
->name
,
271 ap
->modif
, ap
->thr_act
, (unsigned long long)old_value
, (unsigned long long)*valuep
);
275 db_list_variable(void)
277 register struct db_variable
*new;
278 register struct db_variable
*old
;
279 register struct db_variable
*cur
;
286 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
287 if (cur
->min_level
> 0 || cur
->max_level
> 0) {
288 j
= 3 * (cur
->max_level
- cur
->min_level
+ 1) - 1;
289 if (cur
->max_level
> cur
->min_level
)
293 if ((l
= strlen(cur
->name
) + j
) >= len
)
297 old
= (struct db_variable
*)0;
299 new = (struct db_variable
*)0;
300 for (cur
= db_vars
; cur
< db_evars
; cur
++)
301 if ((new == (struct db_variable
*)0 ||
302 strcmp(cur
->name
, new->name
) < 0) &&
303 (old
== (struct db_variable
*)0 ||
304 strcmp(cur
->name
, old
->name
) > 0))
306 if (new == (struct db_variable
*)0)
308 db_reserve_output_position(len
);
309 db_printf(new->name
);
310 j
= strlen(new->name
);
311 if (new->min_level
> 0) {
315 for (i
= new->min_level
- 1; i
> 0; i
--) {
321 if (new->max_level
> new->min_level
) {
328 i
= new->min_level
+ 1;
330 if (new->max_level
> new->min_level
) {
336 while (i
++ < new->max_level
) {
342 if (new->max_level
> new->min_level
) {
357 struct db_variable
*vp
;
358 struct db_var_aux_param aux_param
;
359 char modif
[TOK_STRING_SIZE
];
361 aux_param
.modif
= modif
;
363 if (t
== tIDENT
&& strcmp("help", db_tok_string
) == 0) {
368 db_error("Variable name should be prefixed with $\n");
371 if (!db_find_variable(&vp
, &aux_param
)) {
372 db_error("Unknown variable\n");
380 if (!db_expression(&value
)) {
381 db_error("No value\n");
384 if ((t
= db_read_token()) == tSEMI_COLON
)
389 db_read_write_variable(vp
, &value
, DB_VAR_SET
, &aux_param
);
393 db_show_one_variable(void)
395 struct db_variable
*cur
;
405 struct db_var_aux_param aux_param
;
411 for (cur
= db_vars
; cur
< db_evars
; cur
++)
412 if (db_cmp_variable_name(cur
, db_tok_string
, &aux_param
))
414 if (cur
== db_evars
) {
415 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
416 for (q
= cur
->name
, p
= db_tok_string
; *q
&& *p
== *q
; p
++,q
++)
421 if (cur
== db_evars
) {
422 db_error("Unknown variable\n");
426 for (i
= 0; *p
&& *p
!= ':' && i
< cur
->max_level
; i
++, p
= q
)
427 if ((q
= db_get_suffix(p
, &aux_param
.suffix
[i
])) == 0)
430 if ((*p
&& *p
!= ':') ||
431 (i
> 0 && (aux_param
.suffix
[0] < cur
->low
||
433 aux_param
.suffix
[0] > cur
->high
)))) {
434 db_error("Unknown variable format\n");
438 strcpy(aux_param
.modif
, *p
? p
+ 1 : "");
439 aux_param
.thr_act
= (db_option(aux_param
.modif
, 't') ?
440 db_default_act
: THREAD_NULL
);
443 if (cur
->hidden_level
)
444 if (*cur
->hidden_levelp
>= cur
->hidden_low
&&
445 *cur
->hidden_levelp
<= cur
->hidden_high
) {
447 aux_param
.hidden_level
= h
= *cur
->hidden_levelp
;
450 aux_param
.hidden_level
= h
= cur
->hidden_low
;
452 for (k
= aux_param
.level
> 0 ? aux_param
.suffix
[0] : cur
->high
;
457 aux_param
.hidden_level
= -1;
459 if ((cur
->min_level
== 0 && !cur
->hidden_level
) || cur
->high
< 0)
462 if (cur
->min_level
> 0) {
464 for (k
= aux_param
.level
> 0 ?
465 aux_param
.suffix
[0] : cur
->high
; k
> 9; k
/= 10)
469 if (cur
->hidden_level
&& hidden_level
== 0) {
471 for (k
= aux_param
.hidden_level
>= 0 ?
472 aux_param
.hidden_level
: cur
->hidden_high
; k
> 9; k
/= 10)
476 len
= strlen(cur
->name
) + j
;
477 i
= low
= aux_param
.level
> 0 ? aux_param
.suffix
[0] : cur
->low
;
480 db_printf(cur
->name
);
481 j
= strlen(cur
->name
);
482 if (cur
->high
>= 0) {
483 if (cur
->min_level
> 0) {
486 for (k
= i
; k
> 9; k
/= 10)
489 if (cur
->hidden_level
&& hidden_level
== 0) {
491 for (k
= i
; k
> 9; k
/= 10)
493 while (sl
++ < slen
) {
497 db_printf("[%d]", h
);
499 for (k
= h
; k
> 9; k
/= 10)
510 aux_param
.suffix
[0] = i
;
511 (*cur
->fcn
)(cur
, (db_expr_t
*)0, DB_VAR_SHOW
, &aux_param
);
513 db_printf("%#lln", (unsigned long long)*(cur
->valuep
+ i
));
514 db_find_xtrn_task_sym_and_offset(*(cur
->valuep
+ i
), &name
,
516 if (name
!= (char *)0 && offset
<= db_maxoff
&&
517 offset
!= *(cur
->valuep
+ i
)) {
518 db_printf("\t%s", name
);
520 db_printf("+%#llr", (unsigned long long)offset
);
526 if (aux_param
.level
> 0 || i
++ == cur
->high
) {
527 if (!cur
->hidden_level
||
529 h
++ == cur
->hidden_high
)
531 aux_param
.hidden_level
= h
;
538 db_show_variable(void)
540 struct db_variable
*cur
;
551 struct db_var_aux_param aux_param
;
555 switch(t
= db_read_token()) {
562 t1
= db_read_token();
564 db_show_one_variable();
567 db_error("Not a variable name after $\n");
572 db_error("Variable name should be prefixed with $\n");
579 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
580 if ((cur
->min_level
== 0 && !cur
->hidden_level
) || cur
->high
< 0)
583 if (cur
->min_level
> 0) {
585 for (k
= cur
->high
; k
> 9; k
/= 10)
589 if (cur
->hidden_level
&&
590 (*cur
->hidden_levelp
< cur
->hidden_low
||
591 *cur
->hidden_levelp
> cur
->hidden_high
)) {
593 for (k
= cur
->hidden_high
; k
> 9; k
/= 10)
597 if ((l
= strlen(cur
->name
) + j
) >= len
)
601 aux_param
.modif
= "";
603 aux_param
.thr_act
= THREAD_NULL
;
605 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
607 if (cur
->hidden_level
) {
608 if (*cur
->hidden_levelp
>= cur
->hidden_low
&&
609 *cur
->hidden_levelp
<= cur
->hidden_high
) {
610 h
= cur
->hidden_low
- 1;
611 aux_param
.hidden_level
= *cur
->hidden_levelp
;
614 aux_param
.hidden_level
= cur
->hidden_low
;
617 for (k
= cur
->high
; k
> 9; k
/= 10)
620 aux_param
.hidden_level
= -1;
622 if (cur
!= db_vars
&& cur
->high
>= 0 &&
623 (cur
->min_level
> 0 || cur
->hidden_level
))
627 db_printf(cur
->name
);
628 j
= strlen(cur
->name
);
629 if (cur
->high
>= 0) {
630 if (cur
->min_level
> 0) {
633 for (k
= i
; k
> 9; k
/= 10)
636 if (cur
->hidden_level
&& h
>= cur
->hidden_low
) {
638 for (k
= i
; k
> 9; k
/= 10)
640 while (sl
++ < slen
) {
644 db_printf("[%d]", h
);
646 for (k
= h
; k
> 9; k
/= 10)
656 aux_param
.suffix
[0] = i
;
657 (*cur
->fcn
)(cur
, (db_expr_t
*)0, DB_VAR_SHOW
, &aux_param
);
659 db_printf("%#lln", (unsigned long long)*(cur
->valuep
+ i
));
660 db_find_xtrn_task_sym_and_offset(*(cur
->valuep
+ i
), &name
,
662 if (name
!= (char *)0 && offset
<= db_maxoff
&&
663 offset
!= *(cur
->valuep
+ i
)) {
664 db_printf("\t%s", name
);
666 db_printf("+%#llr", (unsigned long long)offset
);
672 if (i
++ == cur
->high
) {
673 if (!cur
->hidden_level
|| h
++ == cur
->hidden_high
)
675 aux_param
.hidden_level
= h
;
683 * given a name of a machine register, return a variable pointer to it.
689 register db_variable_t regp
;
691 if ( s
== (char *)0 )
694 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
695 if ( strcmp( s
, regp
->name
) == 0 )