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