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