2 * Copyright (c) 2000-2005 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_max_width
;
76 extern db_expr_t db_tab_stop_width
;
77 extern db_expr_t db_max_line
;
78 extern db_expr_t db_auto_wrap
;
79 extern db_expr_t db_macro_level
;
80 extern db_expr_t db_auto_completion
;
82 #define DB_NWORK 32 /* number of work variable */
84 db_expr_t db_work
[DB_NWORK
]; /* work variable */
86 struct db_variable db_vars
[] = {
89 .valuep
= (db_expr_t
*)&db_maxoff
,
93 .valuep
= &db_auto_wrap
,
97 .valuep
= &db_auto_completion
,
101 .valuep
= &db_max_width
,
109 .valuep
= &db_tab_stop_width
,
113 .valuep
= &db_max_line
,
117 .fcn
= db_set_default_act
,
121 .fcn
= db_get_task_act
,
129 .valuep
= &db_work
[0],
132 .high
= DB_NWORK
- 1,
136 .fcn
= db_arg_variable
,
140 .high
= DB_MACRO_NARGS
,
143 .hidden_high
= DB_MACRO_LEVEL
- 1,
144 .hidden_levelp
= (int *)&db_macro_level
,
147 struct db_variable
*db_evars
= db_vars
+ sizeof(db_vars
)/sizeof(db_vars
[0]);
151 /* Prototypes for functions local to this file.
154 static const char *db_get_suffix(const char *, short *);
156 static boolean_t
db_cmp_variable_name(struct db_variable
*, const char *,
159 static int db_find_variable(
160 struct db_variable
**varp
,
161 db_var_aux_param_t ap
);
163 void db_list_variable(void);
166 db_get_suffix(const char *suffix
, short *suffix_value
)
170 for (value
= 0; *suffix
&& *suffix
!= '.' && *suffix
!= ':'; suffix
++) {
171 if (*suffix
< '0' || *suffix
> '9')
173 value
= value
*10 + *suffix
- '0';
175 *suffix_value
= value
;
182 db_cmp_variable_name(struct db_variable
*vp
, const char *name
,
183 db_var_aux_param_t ap
)
185 const char *var_np
, *np
;
188 for (np
= name
, var_np
= vp
->name
; *var_np
; ) {
189 if (*np
++ != *var_np
++)
192 for (level
= 0; *np
&& *np
!= ':' && level
< vp
->max_level
; level
++){
193 if ((np
= db_get_suffix(np
, &ap
->suffix
[level
])) == 0)
196 if ((*np
&& *np
!= ':') || level
< vp
->min_level
197 || (level
> 0 && (ap
->suffix
[0] < vp
->low
198 || (vp
->high
>= 0 && ap
->suffix
[0] > vp
->high
))))
200 strcpy(ap
->modif
, (*np
)? np
+1: "");
201 ap
->thr_act
= (db_option(ap
->modif
, 't')?db_default_act
: THREAD_NULL
);
203 ap
->hidden_level
= -1;
209 struct db_variable
**varp
,
210 db_var_aux_param_t ap
)
213 struct db_variable
*vp
;
217 for (vp
= db_vars
; vp
< db_evars
; vp
++) {
218 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
223 for (vp
= db_regs
; vp
< db_eregs
; vp
++) {
224 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
229 #if defined(ALTERNATE_REGISTER_DEFS)
230 for (vp
= db_altregs
; vp
< db_ealtregs
; vp
++) {
231 if (db_cmp_variable_name(vp
, db_tok_string
, ap
)) {
236 #endif /* defined(ALTERNATE_REGISTER_DEFS) */
238 db_printf("Unknown variable \"$%s\"\n", db_tok_string
);
244 db_get_variable(db_expr_t
*valuep
)
246 struct db_variable
*vp
;
247 struct db_var_aux_param aux_param
;
248 char modif
[TOK_STRING_SIZE
];
250 aux_param
.modif
= modif
;
251 if (!db_find_variable(&vp
, &aux_param
))
254 db_read_write_variable(vp
, valuep
, DB_VAR_GET
, &aux_param
);
260 db_read_write_variable(
261 struct db_variable
*vp
,
264 db_var_aux_param_t ap
)
266 int (*func
)(struct db_variable
*, db_expr_t
*,int, db_var_aux_param_t
)
268 struct db_var_aux_param aux_param
;
275 ap
->thr_act
= THREAD_NULL
;
277 if (rw_flag
== DB_VAR_SET
&& vp
->precious
)
278 db_read_write_variable(vp
, &old_value
, DB_VAR_GET
, ap
);
279 if (func
== FCN_NULL
) {
280 if (rw_flag
== DB_VAR_SET
)
281 vp
->valuep
[(ap
->level
)? (ap
->suffix
[0] - vp
->low
): 0] = *valuep
;
283 *valuep
= vp
->valuep
[(ap
->level
)? (ap
->suffix
[0] - vp
->low
): 0];
285 (*func
)(vp
, valuep
, rw_flag
, ap
);
286 if (rw_flag
== DB_VAR_SET
&& vp
->precious
)
287 db_printf("\t$%s:%s<%#x>\t%#8lln\t=\t%#8lln\n", vp
->name
,
288 ap
->modif
, ap
->thr_act
, (unsigned long long)old_value
, (unsigned long long)*valuep
);
292 db_list_variable(void)
294 register struct db_variable
*new;
295 register struct db_variable
*old
;
296 register struct db_variable
*cur
;
303 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
304 if (cur
->min_level
> 0 || cur
->max_level
> 0) {
305 j
= 3 * (cur
->max_level
- cur
->min_level
+ 1) - 1;
306 if (cur
->max_level
> cur
->min_level
)
310 if ((l
= strlen(cur
->name
) + j
) >= len
)
314 old
= (struct db_variable
*)0;
316 new = (struct db_variable
*)0;
317 for (cur
= db_vars
; cur
< db_evars
; cur
++)
318 if ((new == (struct db_variable
*)0 ||
319 strcmp(cur
->name
, new->name
) < 0) &&
320 (old
== (struct db_variable
*)0 ||
321 strcmp(cur
->name
, old
->name
) > 0))
323 if (new == (struct db_variable
*)0)
325 db_reserve_output_position(len
);
326 db_printf(new->name
);
327 j
= strlen(new->name
);
328 if (new->min_level
> 0) {
332 for (i
= new->min_level
- 1; i
> 0; i
--) {
338 if (new->max_level
> new->min_level
) {
345 i
= new->min_level
+ 1;
347 if (new->max_level
> new->min_level
) {
353 while (i
++ < new->max_level
) {
359 if (new->max_level
> new->min_level
) {
374 struct db_variable
*vp
;
375 struct db_var_aux_param aux_param
;
376 char modif
[TOK_STRING_SIZE
];
378 aux_param
.modif
= modif
;
380 if (t
== tIDENT
&& strcmp("help", db_tok_string
) == 0) {
385 db_error("Variable name should be prefixed with $\n");
388 if (!db_find_variable(&vp
, &aux_param
)) {
389 db_error("Unknown variable\n");
397 if (!db_expression(&value
)) {
398 db_error("No value\n");
401 if ((t
= db_read_token()) == tSEMI_COLON
)
406 db_read_write_variable(vp
, &value
, DB_VAR_SET
, &aux_param
);
410 db_show_one_variable(void)
412 struct db_variable
*cur
;
415 unsigned int slen
= 0;
421 int hidden_level
= 0;
422 struct db_var_aux_param aux_param
;
423 const char *p
= NULL
, *q
;
425 db_addr_t offset
= 0;
427 for (cur
= db_vars
; cur
< db_evars
; cur
++)
428 if (db_cmp_variable_name(cur
, db_tok_string
, &aux_param
))
430 if (cur
== db_evars
) {
431 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
432 for (q
= cur
->name
, p
= db_tok_string
; *q
&& *p
== *q
; p
++,q
++)
437 if (cur
== db_evars
) {
438 db_error("Unknown variable\n");
442 for (i
= 0; *p
&& *p
!= ':' && i
< cur
->max_level
; i
++, p
= q
)
443 if ((q
= db_get_suffix(p
, &aux_param
.suffix
[i
])) == 0)
446 if ((*p
&& *p
!= ':') ||
447 (i
> 0 && (aux_param
.suffix
[0] < cur
->low
||
449 aux_param
.suffix
[0] > cur
->high
)))) {
450 db_error("Unknown variable format\n");
454 strcpy(aux_param
.modif
, *p
? p
+ 1 : "");
455 aux_param
.thr_act
= (db_option(aux_param
.modif
, 't') ?
456 db_default_act
: THREAD_NULL
);
459 if (cur
->hidden_level
)
460 if (*cur
->hidden_levelp
>= cur
->hidden_low
&&
461 *cur
->hidden_levelp
<= cur
->hidden_high
) {
463 aux_param
.hidden_level
= h
= *cur
->hidden_levelp
;
466 aux_param
.hidden_level
= h
= cur
->hidden_low
;
468 for (k
= aux_param
.level
> 0 ? aux_param
.suffix
[0] : cur
->high
;
473 aux_param
.hidden_level
= -1;
475 if ((cur
->min_level
== 0 && !cur
->hidden_level
) || cur
->high
< 0)
478 if (cur
->min_level
> 0) {
480 for (k
= aux_param
.level
> 0 ?
481 aux_param
.suffix
[0] : cur
->high
; k
> 9; k
/= 10)
485 if (cur
->hidden_level
&& hidden_level
== 0) {
487 for (k
= aux_param
.hidden_level
>= 0 ?
488 aux_param
.hidden_level
: cur
->hidden_high
; k
> 9; k
/= 10)
492 len
= strlen(cur
->name
) + j
;
493 i
= low
= aux_param
.level
> 0 ? aux_param
.suffix
[0] : cur
->low
;
496 db_printf(cur
->name
);
497 j
= strlen(cur
->name
);
498 if (cur
->high
>= 0) {
499 if (cur
->min_level
> 0) {
502 for (k
= i
; k
> 9; k
/= 10)
505 if (cur
->hidden_level
&& hidden_level
== 0) {
507 for (k
= i
; k
> 9; k
/= 10)
509 while (sl
++ < slen
) {
513 db_printf("[%d]", h
);
515 for (k
= h
; k
> 9; k
/= 10)
526 aux_param
.suffix
[0] = i
;
527 (*cur
->fcn
)(cur
, (db_expr_t
*)0, DB_VAR_SHOW
, &aux_param
);
529 db_printf("%#lln", (unsigned long long)*(cur
->valuep
+ i
));
530 db_find_xtrn_task_sym_and_offset(*(cur
->valuep
+ i
), &name
,
532 if (name
!= (char *)0 && offset
<= db_maxoff
&&
533 offset
!= *(cur
->valuep
+ i
)) {
534 db_printf("\t%s", name
);
536 db_printf("+%#llr", (unsigned long long)offset
);
542 if (aux_param
.level
> 0 || i
++ == cur
->high
) {
543 if (!cur
->hidden_level
||
545 h
++ == cur
->hidden_high
)
547 aux_param
.hidden_level
= h
;
554 db_show_variable(__unused db_expr_t addr
, __unused boolean_t have_addr
,
555 __unused db_expr_t count
, __unused
char *modif
)
557 struct db_variable
*cur
;
568 struct db_var_aux_param aux_param
;
572 switch(t
= db_read_token()) {
579 t1
= db_read_token();
581 db_show_one_variable();
584 db_error("Not a variable name after $\n");
589 db_error("Variable name should be prefixed with $\n");
596 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
597 if ((cur
->min_level
== 0 && !cur
->hidden_level
) || cur
->high
< 0)
600 if (cur
->min_level
> 0) {
602 for (k
= cur
->high
; k
> 9; k
/= 10)
606 if (cur
->hidden_level
&&
607 (*cur
->hidden_levelp
< cur
->hidden_low
||
608 *cur
->hidden_levelp
> cur
->hidden_high
)) {
610 for (k
= cur
->hidden_high
; k
> 9; k
/= 10)
614 if ((l
= strlen(cur
->name
) + j
) >= len
)
618 aux_param
.modif
= NULL
;
620 aux_param
.thr_act
= THREAD_NULL
;
622 for (cur
= db_vars
; cur
< db_evars
; cur
++) {
624 if (cur
->hidden_level
) {
625 if (*cur
->hidden_levelp
>= cur
->hidden_low
&&
626 *cur
->hidden_levelp
<= cur
->hidden_high
) {
627 h
= cur
->hidden_low
- 1;
628 aux_param
.hidden_level
= *cur
->hidden_levelp
;
631 aux_param
.hidden_level
= cur
->hidden_low
;
634 for (k
= cur
->high
; k
> 9; k
/= 10)
637 aux_param
.hidden_level
= -1;
639 if (cur
!= db_vars
&& cur
->high
>= 0 &&
640 (cur
->min_level
> 0 || cur
->hidden_level
))
644 db_printf(cur
->name
);
645 j
= strlen(cur
->name
);
646 if (cur
->high
>= 0) {
647 if (cur
->min_level
> 0) {
650 for (k
= i
; k
> 9; k
/= 10)
653 if (cur
->hidden_level
&& h
>= cur
->hidden_low
) {
655 for (k
= i
; k
> 9; k
/= 10)
657 while (sl
++ < slen
) {
661 db_printf("[%d]", h
);
663 for (k
= h
; k
> 9; k
/= 10)
673 aux_param
.suffix
[0] = i
;
674 (*cur
->fcn
)(cur
, (db_expr_t
*)0, DB_VAR_SHOW
, &aux_param
);
676 db_printf("%#lln", (unsigned long long)*(cur
->valuep
+ i
));
677 db_find_xtrn_task_sym_and_offset(*(cur
->valuep
+ i
), &name
,
679 if (name
!= (char *)0 && offset
<= db_maxoff
&&
680 offset
!= *(cur
->valuep
+ i
)) {
681 db_printf("\t%s", name
);
683 db_printf("+%#llr", (unsigned long long)offset
);
689 if (i
++ == cur
->high
) {
690 if (!cur
->hidden_level
|| h
++ == cur
->hidden_high
)
692 aux_param
.hidden_level
= h
;
700 * given a name of a machine register, return a variable pointer to it.
706 register db_variable_t regp
;
708 if ( s
== (char *)0 )
711 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
712 if ( strcmp( s
, regp
->name
) == 0 )