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