]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_variables.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / osfmk / ddb / db_variables.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
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.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 /*
59 * Author: David B. Golub, Carnegie Mellon University
60 * Date: 7/90
61 */
62
63 #include <machine/db_machdep.h>
64 #include <string.h> /* For strcpy() */
65
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() */
74
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;
82
83 #define DB_NWORK 32 /* number of work variable */
84
85 db_expr_t db_work[DB_NWORK]; /* work variable */
86
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,
97 1, 2, -1, -1 },
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 },
103 };
104 struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
105
106
107
108 /* Prototypes for functions local to this file.
109 */
110
111 static char *db_get_suffix(
112 register char *suffix,
113 short *suffix_value);
114
115 static boolean_t db_cmp_variable_name(
116 struct db_variable *vp,
117 char *name,
118 register db_var_aux_param_t ap);
119
120 static int db_find_variable(
121 struct db_variable **varp,
122 db_var_aux_param_t ap);
123
124 static int db_set_variable(db_expr_t value);
125
126 void db_list_variable(void);
127
128 static char *
129 db_get_suffix(
130 register char *suffix,
131 short *suffix_value)
132 {
133 register int value;
134
135 for (value = 0; *suffix && *suffix != '.' && *suffix != ':'; suffix++) {
136 if (*suffix < '0' || *suffix > '9')
137 return(0);
138 value = value*10 + *suffix - '0';
139 }
140 *suffix_value = value;
141 if (*suffix == '.')
142 suffix++;
143 return(suffix);
144 }
145
146 static boolean_t
147 db_cmp_variable_name(
148 struct db_variable *vp,
149 char *name,
150 register db_var_aux_param_t ap)
151 {
152 register char *var_np, *np;
153 register int level;
154
155 for (np = name, var_np = vp->name; *var_np; ) {
156 if (*np++ != *var_np++)
157 return(FALSE);
158 }
159 for (level = 0; *np && *np != ':' && level < vp->max_level; level++){
160 if ((np = db_get_suffix(np, &ap->suffix[level])) == 0)
161 return(FALSE);
162 }
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))))
166 return(FALSE);
167 strcpy(ap->modif, (*np)? np+1: "");
168 ap->thr_act = (db_option(ap->modif, 't')?db_default_act: THREAD_NULL);
169 ap->level = level;
170 ap->hidden_level = -1;
171 return(TRUE);
172 }
173
174 static int
175 db_find_variable(
176 struct db_variable **varp,
177 db_var_aux_param_t ap)
178 {
179 int t;
180 struct db_variable *vp;
181
182 t = db_read_token();
183 if (t == tIDENT) {
184 for (vp = db_vars; vp < db_evars; vp++) {
185 if (db_cmp_variable_name(vp, db_tok_string, ap)) {
186 *varp = vp;
187 return (1);
188 }
189 }
190 for (vp = db_regs; vp < db_eregs; vp++) {
191 if (db_cmp_variable_name(vp, db_tok_string, ap)) {
192 *varp = vp;
193 return (1);
194 }
195 }
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)) {
199 *varp = vp;
200 return (1);
201 }
202 }
203 #endif /* defined(ALTERNATE_REGISTER_DEFS) */
204 }
205 db_printf("Unknown variable \"$%s\"\n", db_tok_string);
206 db_error(0);
207 return (0);
208 }
209
210 int
211 db_get_variable(db_expr_t *valuep)
212 {
213 struct db_variable *vp;
214 struct db_var_aux_param aux_param;
215 char modif[TOK_STRING_SIZE];
216
217 aux_param.modif = modif;
218 if (!db_find_variable(&vp, &aux_param))
219 return (0);
220
221 db_read_write_variable(vp, valuep, DB_VAR_GET, &aux_param);
222
223 return (1);
224 }
225
226 static int
227 db_set_variable(db_expr_t value)
228 {
229 struct db_variable *vp;
230 struct db_var_aux_param aux_param;
231 char modif[TOK_STRING_SIZE];
232
233 aux_param.modif = modif;
234 if (!db_find_variable(&vp, &aux_param))
235 return (0);
236
237 db_read_write_variable(vp, &value, DB_VAR_SET, &aux_param);
238
239 return (1);
240 }
241
242 void
243 db_read_write_variable(
244 struct db_variable *vp,
245 db_expr_t *valuep,
246 int rw_flag,
247 db_var_aux_param_t ap)
248 {
249 int (*func)(struct db_variable*, db_expr_t*,int, db_var_aux_param_t)
250 = vp->fcn;
251 struct db_var_aux_param aux_param;
252 db_expr_t old_value;
253
254 if (ap == 0) {
255 ap = &aux_param;
256 ap->modif = "";
257 ap->level = 0;
258 ap->thr_act = THREAD_NULL;
259 }
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;
265 else
266 *valuep = vp->valuep[(ap->level)? (ap->suffix[0] - vp->low): 0];
267 } else
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);
272 }
273
274 void
275 db_list_variable(void)
276 {
277 register struct db_variable *new;
278 register struct db_variable *old;
279 register struct db_variable *cur;
280 unsigned int l;
281 unsigned int len;
282 short i;
283 unsigned int j;
284
285 len = 1;
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)
290 j += 2;
291 } else
292 j = 0;
293 if ((l = strlen(cur->name) + j) >= len)
294 len = l + 1;
295 }
296
297 old = (struct db_variable *)0;
298 for (;;) {
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))
305 new = cur;
306 if (new == (struct db_variable *)0)
307 return;
308 db_reserve_output_position(len);
309 db_printf(new->name);
310 j = strlen(new->name);
311 if (new->min_level > 0) {
312 db_putchar('?');
313 db_putchar('?');
314 j += 2;
315 for (i = new->min_level - 1; i > 0; i--) {
316 db_putchar('.');
317 db_putchar('?');
318 db_putchar('?');
319 j += 3;
320 }
321 if (new->max_level > new->min_level) {
322 db_putchar('[');
323 db_putchar('.');
324 db_putchar('?');
325 db_putchar('?');
326 j += 4;
327 }
328 i = new->min_level + 1;
329 } else {
330 if (new->max_level > new->min_level) {
331 db_putchar('[');
332 j++;
333 }
334 i = new->min_level;
335 }
336 while (i++ < new->max_level) {
337 db_putchar('.');
338 db_putchar('?');
339 db_putchar('?');
340 j += 3;
341 }
342 if (new->max_level > new->min_level) {
343 db_putchar(']');
344 j++;
345 }
346 while (j++ < len)
347 db_putchar(' ');
348 old = new;
349 }
350 }
351
352 void
353 db_set_cmd(void)
354 {
355 db_expr_t value;
356 int t;
357 struct db_variable *vp;
358 struct db_var_aux_param aux_param;
359 char modif[TOK_STRING_SIZE];
360
361 aux_param.modif = modif;
362 t = db_read_token();
363 if (t == tIDENT && strcmp("help", db_tok_string) == 0) {
364 db_list_variable();
365 return;
366 }
367 if (t != tDOLLAR) {
368 db_error("Variable name should be prefixed with $\n");
369 return;
370 }
371 if (!db_find_variable(&vp, &aux_param)) {
372 db_error("Unknown variable\n");
373 return;
374 }
375
376 t = db_read_token();
377 if (t != tEQ)
378 db_unread_token(t);
379
380 if (!db_expression(&value)) {
381 db_error("No value\n");
382 return;
383 }
384 if ((t = db_read_token()) == tSEMI_COLON)
385 db_unread_token(t);
386 else if (t != tEOL)
387 db_error("?\n");
388
389 db_read_write_variable(vp, &value, DB_VAR_SET, &aux_param);
390 }
391
392 void
393 db_show_one_variable(void)
394 {
395 struct db_variable *cur;
396 unsigned int len;
397 unsigned int sl;
398 unsigned int slen;
399 short h;
400 short i;
401 short j;
402 short k;
403 short low;
404 int hidden_level;
405 struct db_var_aux_param aux_param;
406 char *p;
407 char *q;
408 char *name;
409 db_addr_t offset;
410
411 for (cur = db_vars; cur < db_evars; cur++)
412 if (db_cmp_variable_name(cur, db_tok_string, &aux_param))
413 break;
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++)
417 continue;
418 if (*q == '\0')
419 break;
420 }
421 if (cur == db_evars) {
422 db_error("Unknown variable\n");
423 return;
424 }
425
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)
428 break;
429 aux_param.level = i;
430 if ((*p && *p != ':') ||
431 (i > 0 && (aux_param.suffix[0] < cur->low ||
432 (cur->high >= 0 &&
433 aux_param.suffix[0] > cur->high)))) {
434 db_error("Unknown variable format\n");
435 return;
436 }
437
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);
441 }
442
443 if (cur->hidden_level)
444 if (*cur->hidden_levelp >= cur->hidden_low &&
445 *cur->hidden_levelp <= cur->hidden_high) {
446 hidden_level = 1;
447 aux_param.hidden_level = h = *cur->hidden_levelp;
448 } else {
449 hidden_level = 0;
450 aux_param.hidden_level = h = cur->hidden_low;
451 slen = 1;
452 for (k = aux_param.level > 0 ? aux_param.suffix[0] : cur->high;
453 k > 9; k /= 10)
454 slen++;
455 }
456 else
457 aux_param.hidden_level = -1;
458
459 if ((cur->min_level == 0 && !cur->hidden_level) || cur->high < 0)
460 j = 0;
461 else {
462 if (cur->min_level > 0) {
463 j = 1;
464 for (k = aux_param.level > 0 ?
465 aux_param.suffix[0] : cur->high; k > 9; k /= 10)
466 j++;
467 } else
468 j = 0;
469 if (cur->hidden_level && hidden_level == 0) {
470 j += 3;
471 for (k = aux_param.hidden_level >= 0 ?
472 aux_param.hidden_level : cur->hidden_high; k > 9; k /= 10)
473 j++;
474 }
475 }
476 len = strlen(cur->name) + j;
477 i = low = aux_param.level > 0 ? aux_param.suffix[0] : cur->low;
478
479 for (;;) {
480 db_printf(cur->name);
481 j = strlen(cur->name);
482 if (cur->high >= 0) {
483 if (cur->min_level > 0) {
484 db_printf("%d", i);
485 j++;
486 for (k = i; k > 9; k /= 10)
487 j++;
488 }
489 if (cur->hidden_level && hidden_level == 0) {
490 sl = 1;
491 for (k = i; k > 9; k /= 10)
492 sl++;
493 while (sl++ < slen) {
494 db_putchar(' ');
495 j++;
496 }
497 db_printf("[%d]", h);
498 j += 3;
499 for (k = h; k > 9; k /= 10)
500 j++;
501 }
502 }
503
504 while (j++ < len)
505 db_putchar(' ');
506 db_putchar(':');
507 db_putchar(' ');
508
509 if (cur->fcn) {
510 aux_param.suffix[0] = i;
511 (*cur->fcn)(cur, (db_expr_t *)0, DB_VAR_SHOW, &aux_param);
512 } else {
513 db_printf("%#lln", (unsigned long long)*(cur->valuep + i));
514 db_find_xtrn_task_sym_and_offset(*(cur->valuep + i), &name,
515 &offset, TASK_NULL);
516 if (name != (char *)0 && offset <= db_maxoff &&
517 offset != *(cur->valuep + i)) {
518 db_printf("\t%s", name);
519 if (offset != 0)
520 db_printf("+%#llr", (unsigned long long)offset);
521 }
522 }
523 db_putchar('\n');
524 if (cur->high < 0)
525 break;
526 if (aux_param.level > 0 || i++ == cur->high) {
527 if (!cur->hidden_level ||
528 hidden_level == 0 ||
529 h++ == cur->hidden_high)
530 break;
531 aux_param.hidden_level = h;
532 i = low;
533 }
534 }
535 }
536
537 void
538 db_show_variable(void)
539 {
540 struct db_variable *cur;
541 unsigned int l;
542 unsigned int len;
543 unsigned int sl;
544 unsigned int slen;
545 short h;
546 short i;
547 short j;
548 short k;
549 int t;
550 int t1;
551 struct db_var_aux_param aux_param;
552 char *name;
553 db_addr_t offset;
554
555 switch(t = db_read_token()) {
556 case tEOL:
557 case tEOF:
558 case tSEMI_COLON:
559 break;
560
561 case tDOLLAR:
562 t1 = db_read_token();
563 if (t1 == tIDENT) {
564 db_show_one_variable();
565 return;
566 }
567 db_error("Not a variable name after $\n");
568 db_unread_token(t);
569 return;
570
571 default:
572 db_error("Variable name should be prefixed with $\n");
573 db_unread_token(t);
574 return;
575 }
576 db_unread_token(t);
577
578 slen = len = 1;
579 for (cur = db_vars; cur < db_evars; cur++) {
580 if ((cur->min_level == 0 && !cur->hidden_level) || cur->high < 0)
581 j = 0;
582 else {
583 if (cur->min_level > 0) {
584 j = 1;
585 for (k = cur->high; k > 9; k /= 10)
586 j++;
587 } else
588 j = 0;
589 if (cur->hidden_level &&
590 (*cur->hidden_levelp < cur->hidden_low ||
591 *cur->hidden_levelp > cur->hidden_high)) {
592 j += 3;
593 for (k = cur->hidden_high; k > 9; k /= 10)
594 j++;
595 }
596 }
597 if ((l = strlen(cur->name) + j) >= len)
598 len = l + 1;
599 }
600
601 aux_param.modif = "";
602 aux_param.level = 1;
603 aux_param.thr_act = THREAD_NULL;
604
605 for (cur = db_vars; cur < db_evars; cur++) {
606 i = cur->low;
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;
612 } else {
613 h = cur->hidden_low;
614 aux_param.hidden_level = cur->hidden_low;
615 }
616 slen = 1;
617 for (k = cur->high; k > 9; k /= 10)
618 slen++;
619 } else
620 aux_param.hidden_level = -1;
621
622 if (cur != db_vars && cur->high >= 0 &&
623 (cur->min_level > 0 || cur->hidden_level))
624 db_putchar('\n');
625
626 for (;;) {
627 db_printf(cur->name);
628 j = strlen(cur->name);
629 if (cur->high >= 0) {
630 if (cur->min_level > 0) {
631 db_printf("%d", i);
632 j++;
633 for (k = i; k > 9; k /= 10)
634 j++;
635 }
636 if (cur->hidden_level && h >= cur->hidden_low) {
637 sl = 1;
638 for (k = i; k > 9; k /= 10)
639 sl++;
640 while (sl++ < slen) {
641 db_putchar(' ');
642 j++;
643 }
644 db_printf("[%d]", h);
645 j += 3;
646 for (k = h; k > 9; k /= 10)
647 j++;
648 }
649 }
650 while (j++ < len)
651 db_putchar(' ');
652 db_putchar(':');
653 db_putchar(' ');
654
655 if (cur->fcn) {
656 aux_param.suffix[0] = i;
657 (*cur->fcn)(cur, (db_expr_t *)0, DB_VAR_SHOW, &aux_param);
658 } else {
659 db_printf("%#lln", (unsigned long long)*(cur->valuep + i));
660 db_find_xtrn_task_sym_and_offset(*(cur->valuep + i), &name,
661 &offset, TASK_NULL);
662 if (name != (char *)0 && offset <= db_maxoff &&
663 offset != *(cur->valuep + i)) {
664 db_printf("\t%s", name);
665 if (offset != 0)
666 db_printf("+%#llr", (unsigned long long)offset);
667 }
668 }
669 db_putchar('\n');
670 if (cur->high < 0)
671 break;
672 if (i++ == cur->high) {
673 if (!cur->hidden_level || h++ == cur->hidden_high)
674 break;
675 aux_param.hidden_level = h;
676 i = cur->low;
677 }
678 }
679 }
680 }
681
682 /*
683 * given a name of a machine register, return a variable pointer to it.
684 */
685 db_variable_t
686 db_find_reg_name(
687 char *s)
688 {
689 register db_variable_t regp;
690
691 if ( s == (char *)0 )
692 return DB_VAR_NULL;
693
694 for (regp = db_regs; regp < db_eregs; regp++) {
695 if ( strcmp( s, regp->name) == 0 )
696 return regp;
697 }
698 return DB_VAR_NULL;
699 }