]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_variables.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / osfmk / ddb / db_variables.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53 /*
54 */
55 /*
56 * Author: David B. Golub, Carnegie Mellon University
57 * Date: 7/90
58 */
59
60 #include <machine/db_machdep.h>
61 #include <string.h> /* For strcpy() */
62
63 #include <ddb/db_lex.h>
64 #include <ddb/db_variables.h>
65 #include <ddb/db_task_thread.h>
66 #include <ddb/db_sym.h>
67 #include <ddb/db_command.h>
68 #include <ddb/db_expr.h>
69 #include <ddb/db_macro.h>
70 #include <ddb/db_output.h> /* For db_printf() */
71
72 extern db_expr_t db_radix;
73 extern db_expr_t db_max_width;
74 extern db_expr_t db_tab_stop_width;
75 extern db_expr_t db_max_line;
76 extern db_expr_t db_auto_wrap;
77 extern db_expr_t db_macro_level;
78 extern db_expr_t db_auto_completion;
79
80 #define DB_NWORK 32 /* number of work variable */
81
82 db_expr_t db_work[DB_NWORK]; /* work variable */
83
84 struct db_variable db_vars[] = {
85 { "maxoff", (db_expr_t*)&db_maxoff, FCN_NULL },
86 { "autowrap", &db_auto_wrap, FCN_NULL },
87 { "completion", &db_auto_completion, FCN_NULL },
88 { "maxwidth", &db_max_width, FCN_NULL },
89 { "radix", &db_radix, FCN_NULL },
90 { "tabstops", &db_tab_stop_width, FCN_NULL },
91 { "lines", &db_max_line, FCN_NULL },
92 { "thr_act", 0, db_set_default_act },
93 { "task", 0, db_get_task_act,
94 1, 2, -1, -1 },
95 { "work", &db_work[0], FCN_NULL,
96 1, 1, 0, DB_NWORK-1 },
97 { "arg", 0, db_arg_variable,
98 1, 1, 1, DB_MACRO_NARGS,
99 1, 0, DB_MACRO_LEVEL-1, (int *)&db_macro_level },
100 };
101 struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
102
103
104
105 /* Prototypes for functions local to this file.
106 */
107
108 static char *db_get_suffix(
109 register char *suffix,
110 short *suffix_value);
111
112 static boolean_t db_cmp_variable_name(
113 struct db_variable *vp,
114 char *name,
115 register db_var_aux_param_t ap);
116
117 static int db_find_variable(
118 struct db_variable **varp,
119 db_var_aux_param_t ap);
120
121 static int db_set_variable(db_expr_t value);
122
123 void db_list_variable(void);
124
125 static char *
126 db_get_suffix(
127 register char *suffix,
128 short *suffix_value)
129 {
130 register int value;
131
132 for (value = 0; *suffix && *suffix != '.' && *suffix != ':'; suffix++) {
133 if (*suffix < '0' || *suffix > '9')
134 return(0);
135 value = value*10 + *suffix - '0';
136 }
137 *suffix_value = value;
138 if (*suffix == '.')
139 suffix++;
140 return(suffix);
141 }
142
143 static boolean_t
144 db_cmp_variable_name(
145 struct db_variable *vp,
146 char *name,
147 register db_var_aux_param_t ap)
148 {
149 register char *var_np, *np;
150 register int level;
151
152 for (np = name, var_np = vp->name; *var_np; ) {
153 if (*np++ != *var_np++)
154 return(FALSE);
155 }
156 for (level = 0; *np && *np != ':' && level < vp->max_level; level++){
157 if ((np = db_get_suffix(np, &ap->suffix[level])) == 0)
158 return(FALSE);
159 }
160 if ((*np && *np != ':') || level < vp->min_level
161 || (level > 0 && (ap->suffix[0] < vp->low
162 || (vp->high >= 0 && ap->suffix[0] > vp->high))))
163 return(FALSE);
164 strcpy(ap->modif, (*np)? np+1: "");
165 ap->thr_act = (db_option(ap->modif, 't')?db_default_act: THR_ACT_NULL);
166 ap->level = level;
167 ap->hidden_level = -1;
168 return(TRUE);
169 }
170
171 static int
172 db_find_variable(
173 struct db_variable **varp,
174 db_var_aux_param_t ap)
175 {
176 int t;
177 struct db_variable *vp;
178
179 t = db_read_token();
180 if (t == tIDENT) {
181 for (vp = db_vars; vp < db_evars; vp++) {
182 if (db_cmp_variable_name(vp, db_tok_string, ap)) {
183 *varp = vp;
184 return (1);
185 }
186 }
187 for (vp = db_regs; vp < db_eregs; vp++) {
188 if (db_cmp_variable_name(vp, db_tok_string, ap)) {
189 *varp = vp;
190 return (1);
191 }
192 }
193 #if defined(ALTERNATE_REGISTER_DEFS)
194 for (vp = db_altregs; vp < db_ealtregs; vp++) {
195 if (db_cmp_variable_name(vp, db_tok_string, ap)) {
196 *varp = vp;
197 return (1);
198 }
199 }
200 #endif /* defined(ALTERNATE_REGISTER_DEFS) */
201 }
202 db_printf("Unknown variable \"$%s\"\n", db_tok_string);
203 db_error(0);
204 return (0);
205 }
206
207 int
208 db_get_variable(db_expr_t *valuep)
209 {
210 struct db_variable *vp;
211 struct db_var_aux_param aux_param;
212 char modif[TOK_STRING_SIZE];
213
214 aux_param.modif = modif;
215 if (!db_find_variable(&vp, &aux_param))
216 return (0);
217
218 db_read_write_variable(vp, valuep, DB_VAR_GET, &aux_param);
219
220 return (1);
221 }
222
223 static int
224 db_set_variable(db_expr_t value)
225 {
226 struct db_variable *vp;
227 struct db_var_aux_param aux_param;
228 char modif[TOK_STRING_SIZE];
229
230 aux_param.modif = modif;
231 if (!db_find_variable(&vp, &aux_param))
232 return (0);
233
234 db_read_write_variable(vp, &value, DB_VAR_SET, &aux_param);
235
236 return (1);
237 }
238
239 void
240 db_read_write_variable(
241 struct db_variable *vp,
242 db_expr_t *valuep,
243 int rw_flag,
244 db_var_aux_param_t ap)
245 {
246 int (*func)(struct db_variable*, db_expr_t*,int, db_var_aux_param_t)
247 = vp->fcn;
248 struct db_var_aux_param aux_param;
249 db_expr_t old_value;
250
251 if (ap == 0) {
252 ap = &aux_param;
253 ap->modif = "";
254 ap->level = 0;
255 ap->thr_act = THR_ACT_NULL;
256 }
257 if (rw_flag == DB_VAR_SET && vp->precious)
258 db_read_write_variable(vp, &old_value, DB_VAR_GET, ap);
259 if (func == FCN_NULL) {
260 if (rw_flag == DB_VAR_SET)
261 vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0] = *valuep;
262 else
263 *valuep = vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0];
264 } else
265 (*func)(vp, valuep, rw_flag, ap);
266 if (rw_flag == DB_VAR_SET && vp->precious)
267 db_printf("\t$%s:%s<%#x>\t%#8lln\t=\t%#8lln\n", vp->name,
268 ap->modif, ap->thr_act, old_value, *valuep);
269 }
270
271 void
272 db_list_variable(void)
273 {
274 register struct db_variable *new;
275 register struct db_variable *old;
276 register struct db_variable *cur;
277 unsigned int l;
278 unsigned int len;
279 short i;
280 unsigned int j;
281
282 len = 1;
283 for (cur = db_vars; cur < db_evars; cur++) {
284 if (cur->min_level > 0 || cur->max_level > 0) {
285 j = 3 * (cur->max_level - cur->min_level + 1) - 1;
286 if (cur->max_level > cur->min_level)
287 j += 2;
288 } else
289 j = 0;
290 if ((l = strlen(cur->name) + j) >= len)
291 len = l + 1;
292 }
293
294 old = (struct db_variable *)0;
295 for (;;) {
296 new = (struct db_variable *)0;
297 for (cur = db_vars; cur < db_evars; cur++)
298 if ((new == (struct db_variable *)0 ||
299 strcmp(cur->name, new->name) < 0) &&
300 (old == (struct db_variable *)0 ||
301 strcmp(cur->name, old->name) > 0))
302 new = cur;
303 if (new == (struct db_variable *)0)
304 return;
305 db_reserve_output_position(len);
306 db_printf(new->name);
307 j = strlen(new->name);
308 if (new->min_level > 0) {
309 db_putchar('?');
310 db_putchar('?');
311 j += 2;
312 for (i = new->min_level - 1; i > 0; i--) {
313 db_putchar('.');
314 db_putchar('?');
315 db_putchar('?');
316 j += 3;
317 }
318 if (new->max_level > new->min_level) {
319 db_putchar('[');
320 db_putchar('.');
321 db_putchar('?');
322 db_putchar('?');
323 j += 4;
324 }
325 i = new->min_level + 1;
326 } else {
327 if (new->max_level > new->min_level) {
328 db_putchar('[');
329 j++;
330 }
331 i = new->min_level;
332 }
333 while (i++ < new->max_level) {
334 db_putchar('.');
335 db_putchar('?');
336 db_putchar('?');
337 j += 3;
338 }
339 if (new->max_level > new->min_level) {
340 db_putchar(']');
341 j++;
342 }
343 while (j++ < len)
344 db_putchar(' ');
345 old = new;
346 }
347 }
348
349 void
350 db_set_cmd(void)
351 {
352 db_expr_t value;
353 int t;
354 struct db_variable *vp;
355 struct db_var_aux_param aux_param;
356 char modif[TOK_STRING_SIZE];
357
358 aux_param.modif = modif;
359 t = db_read_token();
360 if (t == tIDENT && strcmp("help", db_tok_string) == 0) {
361 db_list_variable();
362 return;
363 }
364 if (t != tDOLLAR) {
365 db_error("Variable name should be prefixed with $\n");
366 return;
367 }
368 if (!db_find_variable(&vp, &aux_param)) {
369 db_error("Unknown variable\n");
370 return;
371 }
372
373 t = db_read_token();
374 if (t != tEQ)
375 db_unread_token(t);
376
377 if (!db_expression(&value)) {
378 db_error("No value\n");
379 return;
380 }
381 if ((t = db_read_token()) == tSEMI_COLON)
382 db_unread_token(t);
383 else if (t != tEOL)
384 db_error("?\n");
385
386 db_read_write_variable(vp, &value, DB_VAR_SET, &aux_param);
387 }
388
389 void
390 db_show_one_variable(void)
391 {
392 struct db_variable *cur;
393 unsigned int len;
394 unsigned int sl;
395 unsigned int slen;
396 short h;
397 short i;
398 short j;
399 short k;
400 short low;
401 int hidden_level;
402 struct db_var_aux_param aux_param;
403 char *p;
404 char *q;
405 char *name;
406 db_addr_t offset;
407
408 for (cur = db_vars; cur < db_evars; cur++)
409 if (db_cmp_variable_name(cur, db_tok_string, &aux_param))
410 break;
411 if (cur == db_evars) {
412 for (cur = db_vars; cur < db_evars; cur++) {
413 for (q = cur->name, p = db_tok_string; *q && *p == *q; p++,q++)
414 continue;
415 if (*q == '\0')
416 break;
417 }
418 if (cur == db_evars) {
419 db_error("Unknown variable\n");
420 return;
421 }
422
423 for (i = 0; *p && *p != ':' && i < cur->max_level; i++, p = q)
424 if ((q = db_get_suffix(p, &aux_param.suffix[i])) == 0)
425 break;
426 aux_param.level = i;
427 if ((*p && *p != ':') ||
428 (i > 0 && (aux_param.suffix[0] < cur->low ||
429 (cur->high >= 0 &&
430 aux_param.suffix[0] > cur->high)))) {
431 db_error("Unknown variable format\n");
432 return;
433 }
434
435 strcpy(aux_param.modif, *p ? p + 1 : "");
436 aux_param.thr_act = (db_option(aux_param.modif, 't') ?
437 db_default_act : THR_ACT_NULL);
438 }
439
440 if (cur->hidden_level)
441 if (*cur->hidden_levelp >= cur->hidden_low &&
442 *cur->hidden_levelp <= cur->hidden_high) {
443 hidden_level = 1;
444 aux_param.hidden_level = h = *cur->hidden_levelp;
445 } else {
446 hidden_level = 0;
447 aux_param.hidden_level = h = cur->hidden_low;
448 slen = 1;
449 for (k = aux_param.level > 0 ? aux_param.suffix[0] : cur->high;
450 k > 9; k /= 10)
451 slen++;
452 }
453 else
454 aux_param.hidden_level = -1;
455
456 if ((cur->min_level == 0 && !cur->hidden_level) || cur->high < 0)
457 j = 0;
458 else {
459 if (cur->min_level > 0) {
460 j = 1;
461 for (k = aux_param.level > 0 ?
462 aux_param.suffix[0] : cur->high; k > 9; k /= 10)
463 j++;
464 } else
465 j = 0;
466 if (cur->hidden_level && hidden_level == 0) {
467 j += 3;
468 for (k = aux_param.hidden_level >= 0 ?
469 aux_param.hidden_level : cur->hidden_high; k > 9; k /= 10)
470 j++;
471 }
472 }
473 len = strlen(cur->name) + j;
474 i = low = aux_param.level > 0 ? aux_param.suffix[0] : cur->low;
475
476 for (;;) {
477 db_printf(cur->name);
478 j = strlen(cur->name);
479 if (cur->high >= 0) {
480 if (cur->min_level > 0) {
481 db_printf("%d", i);
482 j++;
483 for (k = i; k > 9; k /= 10)
484 j++;
485 }
486 if (cur->hidden_level && hidden_level == 0) {
487 sl = 1;
488 for (k = i; k > 9; k /= 10)
489 sl++;
490 while (sl++ < slen) {
491 db_putchar(' ');
492 j++;
493 }
494 db_printf("[%d]", h);
495 j += 3;
496 for (k = h; k > 9; k /= 10)
497 j++;
498 }
499 }
500
501 while (j++ < len)
502 db_putchar(' ');
503 db_putchar(':');
504 db_putchar(' ');
505
506 if (cur->fcn) {
507 aux_param.suffix[0] = i;
508 (*cur->fcn)(cur, (db_expr_t *)0, DB_VAR_SHOW, &aux_param);
509 } else {
510 db_printf("%#lln", *(cur->valuep + i));
511 db_find_xtrn_task_sym_and_offset(*(cur->valuep + i), &name,
512 &offset, TASK_NULL);
513 if (name != (char *)0 && offset <= db_maxoff &&
514 offset != *(cur->valuep + i)) {
515 db_printf("\t%s", name);
516 if (offset != 0)
517 db_printf("+%#r", offset);
518 }
519 }
520 db_putchar('\n');
521 if (cur->high < 0)
522 break;
523 if (aux_param.level > 0 || i++ == cur->high) {
524 if (!cur->hidden_level ||
525 hidden_level == 0 ||
526 h++ == cur->hidden_high)
527 break;
528 aux_param.hidden_level = h;
529 i = low;
530 }
531 }
532 }
533
534 void
535 db_show_variable(void)
536 {
537 struct db_variable *cur;
538 unsigned int l;
539 unsigned int len;
540 unsigned int sl;
541 unsigned int slen;
542 short h;
543 short i;
544 short j;
545 short k;
546 int t;
547 int t1;
548 struct db_var_aux_param aux_param;
549 char *name;
550 db_addr_t offset;
551
552 switch(t = db_read_token()) {
553 case tEOL:
554 case tEOF:
555 case tSEMI_COLON:
556 break;
557
558 case tDOLLAR:
559 t1 = db_read_token();
560 if (t1 == tIDENT) {
561 db_show_one_variable();
562 return;
563 }
564 db_error("Not a variable name after $\n");
565 db_unread_token(t);
566 return;
567
568 default:
569 db_error("Variable name should be prefixed with $\n");
570 db_unread_token(t);
571 return;
572 }
573 db_unread_token(t);
574
575 slen = len = 1;
576 for (cur = db_vars; cur < db_evars; cur++) {
577 if ((cur->min_level == 0 && !cur->hidden_level) || cur->high < 0)
578 j = 0;
579 else {
580 if (cur->min_level > 0) {
581 j = 1;
582 for (k = cur->high; k > 9; k /= 10)
583 j++;
584 } else
585 j = 0;
586 if (cur->hidden_level &&
587 (*cur->hidden_levelp < cur->hidden_low ||
588 *cur->hidden_levelp > cur->hidden_high)) {
589 j += 3;
590 for (k = cur->hidden_high; k > 9; k /= 10)
591 j++;
592 }
593 }
594 if ((l = strlen(cur->name) + j) >= len)
595 len = l + 1;
596 }
597
598 aux_param.modif = "";
599 aux_param.level = 1;
600 aux_param.thr_act = THR_ACT_NULL;
601
602 for (cur = db_vars; cur < db_evars; cur++) {
603 i = cur->low;
604 if (cur->hidden_level) {
605 if (*cur->hidden_levelp >= cur->hidden_low &&
606 *cur->hidden_levelp <= cur->hidden_high) {
607 h = cur->hidden_low - 1;
608 aux_param.hidden_level = *cur->hidden_levelp;
609 } else {
610 h = cur->hidden_low;
611 aux_param.hidden_level = cur->hidden_low;
612 }
613 slen = 1;
614 for (k = cur->high; k > 9; k /= 10)
615 slen++;
616 } else
617 aux_param.hidden_level = -1;
618
619 if (cur != db_vars && cur->high >= 0 &&
620 (cur->min_level > 0 || cur->hidden_level))
621 db_putchar('\n');
622
623 for (;;) {
624 db_printf(cur->name);
625 j = strlen(cur->name);
626 if (cur->high >= 0) {
627 if (cur->min_level > 0) {
628 db_printf("%d", i);
629 j++;
630 for (k = i; k > 9; k /= 10)
631 j++;
632 }
633 if (cur->hidden_level && h >= cur->hidden_low) {
634 sl = 1;
635 for (k = i; k > 9; k /= 10)
636 sl++;
637 while (sl++ < slen) {
638 db_putchar(' ');
639 j++;
640 }
641 db_printf("[%d]", h);
642 j += 3;
643 for (k = h; k > 9; k /= 10)
644 j++;
645 }
646 }
647 while (j++ < len)
648 db_putchar(' ');
649 db_putchar(':');
650 db_putchar(' ');
651
652 if (cur->fcn) {
653 aux_param.suffix[0] = i;
654 (*cur->fcn)(cur, (db_expr_t *)0, DB_VAR_SHOW, &aux_param);
655 } else {
656 db_printf("%#lln", *(cur->valuep + i));
657 db_find_xtrn_task_sym_and_offset(*(cur->valuep + i), &name,
658 &offset, TASK_NULL);
659 if (name != (char *)0 && offset <= db_maxoff &&
660 offset != *(cur->valuep + i)) {
661 db_printf("\t%s", name);
662 if (offset != 0)
663 db_printf("+%#r", offset);
664 }
665 }
666 db_putchar('\n');
667 if (cur->high < 0)
668 break;
669 if (i++ == cur->high) {
670 if (!cur->hidden_level || h++ == cur->hidden_high)
671 break;
672 aux_param.hidden_level = h;
673 i = cur->low;
674 }
675 }
676 }
677 }
678
679 /*
680 * given a name of a machine register, return a variable pointer to it.
681 */
682 db_variable_t
683 db_find_reg_name(
684 char *s)
685 {
686 register db_variable_t regp;
687
688 if ( s == (char *)0 )
689 return DB_VAR_NULL;
690
691 for (regp = db_regs; regp < db_eregs; regp++) {
692 if ( strcmp( s, regp->name) == 0 )
693 return regp;
694 }
695 return DB_VAR_NULL;
696 }