2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
61 * Author: David B. Golub, Carnegie Mellon University
65 #include <machine/db_machdep.h>
66 #include <string.h> /* For strcpy() */
68 #include <ddb/db_lex.h>
69 #include <ddb/db_variables.h>
70 #include <ddb/db_task_thread.h>
71 #include <ddb/db_sym.h>
72 #include <ddb/db_command.h>
73 #include <ddb/db_expr.h>
74 #include <ddb/db_macro.h>
75 #include <ddb/db_output.h> /* For db_printf() */
77 extern db_expr_t db_radix
;
78 extern db_expr_t db_max_width
;
79 extern db_expr_t db_tab_stop_width
;
80 extern db_expr_t db_max_line
;
81 extern db_expr_t db_auto_wrap
;
82 extern db_expr_t db_macro_level
;
83 extern db_expr_t db_auto_completion
;
85 #define DB_NWORK 32 /* number of work variable */
87 db_expr_t db_work
[DB_NWORK
]; /* work variable */
89 struct db_variable db_vars
[] = {
90 { "maxoff", (db_expr_t
*)&db_maxoff
, FCN_NULL
},
91 { "autowrap", &db_auto_wrap
, FCN_NULL
},
92 { "completion", &db_auto_completion
, FCN_NULL
},
93 { "maxwidth", &db_max_width
, FCN_NULL
},
94 { "radix", &db_radix
, FCN_NULL
},
95 { "tabstops", &db_tab_stop_width
, FCN_NULL
},
96 { "lines", &db_max_line
, FCN_NULL
},
97 { "thr_act", 0, db_set_default_act
},
98 { "task", 0, db_get_task_act
,
100 { "work", &db_work
[0], FCN_NULL
,
101 1, 1, 0, DB_NWORK
-1 },
102 { "arg", 0, db_arg_variable
,
103 1, 1, 1, DB_MACRO_NARGS
,
104 1, 0, DB_MACRO_LEVEL
-1, (int *)&db_macro_level
},
106 struct db_variable
*db_evars
= db_vars
+ sizeof(db_vars
)/sizeof(db_vars
[0]);
110 /* Prototypes for functions local to this file.
113 static char *db_get_suffix(
114 register char *suffix
,
115 short *suffix_value
);
117 static boolean_t
db_cmp_variable_name(
118 struct db_variable
*vp
,
120 register db_var_aux_param_t ap
);
122 static int db_find_variable(
123 struct db_variable
**varp
,
124 db_var_aux_param_t ap
);
126 static int db_set_variable(db_expr_t value
);
128 void db_list_variable(void);
132 register char *suffix
,
137 for (value
= 0; *suffix
&& *suffix
!= '.' && *suffix
!= ':'; suffix
++) {
138 if (*suffix
< '0' || *suffix
> '9')
140 value
= value
*10 + *suffix
- '0';
142 *suffix_value
= value
;
149 db_cmp_variable_name(
150 struct db_variable
*vp
,
152 register db_var_aux_param_t ap
)
154 register char *var_np
, *np
;
157 for (np
= name
, var_np
= vp
->name
; *var_np
; ) {
158 if (*np
++ != *var_np
++)
161 for (level
= 0; *np
&& *np
!= ':' && level
< vp
->max_level
; level
++){
162 if ((np
= db_get_suffix(np
, &ap
->suffix
[level
])) == 0)
165 if ((*np
&& *np
!= ':') || level
< vp
->min_level
166 || (level
> 0 && (ap
->suffix
[0] < vp
->low
167 || (vp
->high
>= 0 && ap
->suffix
[0] > vp
->high
))))
169 strcpy(ap
->modif
, (*np
)? np
+1: "");
170 ap
->thr_act
= (db_option(ap
->modif
, 't')?db_default_act
: THREAD_NULL
);
172 ap
->hidden_level
= -1;
178 struct db_variable
**varp
,
179 db_var_aux_param_t ap
)
182 struct db_variable
*vp
;
186 for (vp
= db_vars
; vp
< db_evars
; vp
++) {
187 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
192 for (vp
= db_regs
; vp
< db_eregs
; vp
++) {
193 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
198 #if defined(ALTERNATE_REGISTER_DEFS)
199 for (vp
= db_altregs
; vp
< db_ealtregs
; vp
++) {
200 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
205 #endif /* defined(ALTERNATE_REGISTER_DEFS) */
207 db_printf("Unknown variable \"$%s\"\n", db_tok_string
);
213 db_get_variable(db_expr_t
*valuep
)
215 struct db_variable
*vp
;
216 struct db_var_aux_param aux_param
;
217 char modif
[TOK_STRING_SIZE
];
219 aux_param
.modif
= modif
;
220 if (!db_find_variable(&vp
, &aux_param
))
223 db_read_write_variable(vp
, valuep
, DB_VAR_GET
, &aux_param
);
229 db_set_variable(db_expr_t value
)
231 struct db_variable
*vp
;
232 struct db_var_aux_param aux_param
;
233 char modif
[TOK_STRING_SIZE
];
235 aux_param
.modif
= modif
;
236 if (!db_find_variable(&vp
, &aux_param
))
239 db_read_write_variable(vp
, &value
, DB_VAR_SET
, &aux_param
);
245 db_read_write_variable(
246 struct db_variable
*vp
,
249 db_var_aux_param_t ap
)
251 int (*func
)(struct db_variable
*, db_expr_t
*,int, db_var_aux_param_t
)
253 struct db_var_aux_param aux_param
;
260 ap
->thr_act
= THREAD_NULL
;
262 if (rw_flag
== DB_VAR_SET
&& vp
->precious
)
263 db_read_write_variable(vp
, &old_value
, DB_VAR_GET
, ap
);
264 if (func
== FCN_NULL
) {
265 if (rw_flag
== DB_VAR_SET
)
266 vp
->valuep
[(ap
->level
)? (ap
->suffix
[0] - vp
->low
): 0] = *valuep
;
268 *valuep
= vp
->valuep
[(ap
->level
)? (ap
->suffix
[0] - vp
->low
): 0];
270 (*func
)(vp
, valuep
, rw_flag
, ap
);
271 if (rw_flag
== DB_VAR_SET
&& vp
->precious
)
272 db_printf("\t$%s:%s<%#x>\t%#8lln\t=\t%#8lln\n", vp
->name
,
273 ap
->modif
, ap
->thr_act
, (unsigned long long)old_value
, (unsigned long long)*valuep
);
277 db_list_variable(void)
279 register struct db_variable
*new;
280 register struct db_variable
*old
;
281 register struct db_variable
*cur
;
288 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
289 if (cur
->min_level
> 0 || cur
->max_level
> 0) {
290 j
= 3 * (cur
->max_level
- cur
->min_level
+ 1) - 1;
291 if (cur
->max_level
> cur
->min_level
)
295 if ((l
= strlen(cur
->name
) + j
) >= len
)
299 old
= (struct db_variable
*)0;
301 new = (struct db_variable
*)0;
302 for (cur
= db_vars
; cur
< db_evars
; cur
++)
303 if ((new == (struct db_variable
*)0 ||
304 strcmp(cur
->name
, new->name
) < 0) &&
305 (old
== (struct db_variable
*)0 ||
306 strcmp(cur
->name
, old
->name
) > 0))
308 if (new == (struct db_variable
*)0)
310 db_reserve_output_position(len
);
311 db_printf(new->name
);
312 j
= strlen(new->name
);
313 if (new->min_level
> 0) {
317 for (i
= new->min_level
- 1; i
> 0; i
--) {
323 if (new->max_level
> new->min_level
) {
330 i
= new->min_level
+ 1;
332 if (new->max_level
> new->min_level
) {
338 while (i
++ < new->max_level
) {
344 if (new->max_level
> new->min_level
) {
359 struct db_variable
*vp
;
360 struct db_var_aux_param aux_param
;
361 char modif
[TOK_STRING_SIZE
];
363 aux_param
.modif
= modif
;
365 if (t
== tIDENT
&& strcmp("help", db_tok_string
) == 0) {
370 db_error("Variable name should be prefixed with $\n");
373 if (!db_find_variable(&vp
, &aux_param
)) {
374 db_error("Unknown variable\n");
382 if (!db_expression(&value
)) {
383 db_error("No value\n");
386 if ((t
= db_read_token()) == tSEMI_COLON
)
391 db_read_write_variable(vp
, &value
, DB_VAR_SET
, &aux_param
);
395 db_show_one_variable(void)
397 struct db_variable
*cur
;
407 struct db_var_aux_param aux_param
;
413 for (cur
= db_vars
; cur
< db_evars
; cur
++)
414 if (db_cmp_variable_name(cur
, db_tok_string
, &aux_param
))
416 if (cur
== db_evars
) {
417 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
418 for (q
= cur
->name
, p
= db_tok_string
; *q
&& *p
== *q
; p
++,q
++)
423 if (cur
== db_evars
) {
424 db_error("Unknown variable\n");
428 for (i
= 0; *p
&& *p
!= ':' && i
< cur
->max_level
; i
++, p
= q
)
429 if ((q
= db_get_suffix(p
, &aux_param
.suffix
[i
])) == 0)
432 if ((*p
&& *p
!= ':') ||
433 (i
> 0 && (aux_param
.suffix
[0] < cur
->low
||
435 aux_param
.suffix
[0] > cur
->high
)))) {
436 db_error("Unknown variable format\n");
440 strcpy(aux_param
.modif
, *p
? p
+ 1 : "");
441 aux_param
.thr_act
= (db_option(aux_param
.modif
, 't') ?
442 db_default_act
: THREAD_NULL
);
445 if (cur
->hidden_level
)
446 if (*cur
->hidden_levelp
>= cur
->hidden_low
&&
447 *cur
->hidden_levelp
<= cur
->hidden_high
) {
449 aux_param
.hidden_level
= h
= *cur
->hidden_levelp
;
452 aux_param
.hidden_level
= h
= cur
->hidden_low
;
454 for (k
= aux_param
.level
> 0 ? aux_param
.suffix
[0] : cur
->high
;
459 aux_param
.hidden_level
= -1;
461 if ((cur
->min_level
== 0 && !cur
->hidden_level
) || cur
->high
< 0)
464 if (cur
->min_level
> 0) {
466 for (k
= aux_param
.level
> 0 ?
467 aux_param
.suffix
[0] : cur
->high
; k
> 9; k
/= 10)
471 if (cur
->hidden_level
&& hidden_level
== 0) {
473 for (k
= aux_param
.hidden_level
>= 0 ?
474 aux_param
.hidden_level
: cur
->hidden_high
; k
> 9; k
/= 10)
478 len
= strlen(cur
->name
) + j
;
479 i
= low
= aux_param
.level
> 0 ? aux_param
.suffix
[0] : cur
->low
;
482 db_printf(cur
->name
);
483 j
= strlen(cur
->name
);
484 if (cur
->high
>= 0) {
485 if (cur
->min_level
> 0) {
488 for (k
= i
; k
> 9; k
/= 10)
491 if (cur
->hidden_level
&& hidden_level
== 0) {
493 for (k
= i
; k
> 9; k
/= 10)
495 while (sl
++ < slen
) {
499 db_printf("[%d]", h
);
501 for (k
= h
; k
> 9; k
/= 10)
512 aux_param
.suffix
[0] = i
;
513 (*cur
->fcn
)(cur
, (db_expr_t
*)0, DB_VAR_SHOW
, &aux_param
);
515 db_printf("%#lln", (unsigned long long)*(cur
->valuep
+ i
));
516 db_find_xtrn_task_sym_and_offset(*(cur
->valuep
+ i
), &name
,
518 if (name
!= (char *)0 && offset
<= db_maxoff
&&
519 offset
!= *(cur
->valuep
+ i
)) {
520 db_printf("\t%s", name
);
522 db_printf("+%#llr", (unsigned long long)offset
);
528 if (aux_param
.level
> 0 || i
++ == cur
->high
) {
529 if (!cur
->hidden_level
||
531 h
++ == cur
->hidden_high
)
533 aux_param
.hidden_level
= h
;
540 db_show_variable(void)
542 struct db_variable
*cur
;
553 struct db_var_aux_param aux_param
;
557 switch(t
= db_read_token()) {
564 t1
= db_read_token();
566 db_show_one_variable();
569 db_error("Not a variable name after $\n");
574 db_error("Variable name should be prefixed with $\n");
581 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
582 if ((cur
->min_level
== 0 && !cur
->hidden_level
) || cur
->high
< 0)
585 if (cur
->min_level
> 0) {
587 for (k
= cur
->high
; k
> 9; k
/= 10)
591 if (cur
->hidden_level
&&
592 (*cur
->hidden_levelp
< cur
->hidden_low
||
593 *cur
->hidden_levelp
> cur
->hidden_high
)) {
595 for (k
= cur
->hidden_high
; k
> 9; k
/= 10)
599 if ((l
= strlen(cur
->name
) + j
) >= len
)
603 aux_param
.modif
= "";
605 aux_param
.thr_act
= THREAD_NULL
;
607 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
609 if (cur
->hidden_level
) {
610 if (*cur
->hidden_levelp
>= cur
->hidden_low
&&
611 *cur
->hidden_levelp
<= cur
->hidden_high
) {
612 h
= cur
->hidden_low
- 1;
613 aux_param
.hidden_level
= *cur
->hidden_levelp
;
616 aux_param
.hidden_level
= cur
->hidden_low
;
619 for (k
= cur
->high
; k
> 9; k
/= 10)
622 aux_param
.hidden_level
= -1;
624 if (cur
!= db_vars
&& cur
->high
>= 0 &&
625 (cur
->min_level
> 0 || cur
->hidden_level
))
629 db_printf(cur
->name
);
630 j
= strlen(cur
->name
);
631 if (cur
->high
>= 0) {
632 if (cur
->min_level
> 0) {
635 for (k
= i
; k
> 9; k
/= 10)
638 if (cur
->hidden_level
&& h
>= cur
->hidden_low
) {
640 for (k
= i
; k
> 9; k
/= 10)
642 while (sl
++ < slen
) {
646 db_printf("[%d]", h
);
648 for (k
= h
; k
> 9; k
/= 10)
658 aux_param
.suffix
[0] = i
;
659 (*cur
->fcn
)(cur
, (db_expr_t
*)0, DB_VAR_SHOW
, &aux_param
);
661 db_printf("%#lln", (unsigned long long)*(cur
->valuep
+ i
));
662 db_find_xtrn_task_sym_and_offset(*(cur
->valuep
+ i
), &name
,
664 if (name
!= (char *)0 && offset
<= db_maxoff
&&
665 offset
!= *(cur
->valuep
+ i
)) {
666 db_printf("\t%s", name
);
668 db_printf("+%#llr", (unsigned long long)offset
);
674 if (i
++ == cur
->high
) {
675 if (!cur
->hidden_level
|| h
++ == cur
->hidden_high
)
677 aux_param
.hidden_level
= h
;
685 * given a name of a machine register, return a variable pointer to it.
691 register db_variable_t regp
;
693 if ( s
== (char *)0 )
696 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
697 if ( strcmp( s
, regp
->name
) == 0 )