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 )