]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_sym.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / osfmk / ddb / db_sym.c
1 /*
2 * Copyright (c) 2000-2005 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(), strcmp() */
65 #include <mach/std_types.h>
66 #include <kern/misc_protos.h> /* For printf() */
67 #include <kern/kalloc.h>
68 #include <ddb/db_sym.h>
69 #include <ddb/db_task_thread.h>
70 #include <ddb/db_command.h>
71 #include <ddb/db_output.h> /* For db_printf() */
72
73 #include <vm/vm_map.h> /* vm_map_t */
74
75 /*
76 * Multiple symbol tables
77 *
78 * mach, bootstrap, name_server, default_pager, unix, 1 spare
79 */
80 #define MAXNOSYMTABS 6
81
82 db_symtab_t db_symtabs[MAXNOSYMTABS];
83 int db_nsymtab = 0;
84
85 db_symtab_t *db_last_symtab;
86
87 unsigned long db_maxoff = 0x4000;
88 extern char end;
89 unsigned long db_maxval = (unsigned long)&end;
90 natural_t db_minval = 0x1000;
91
92 /* Prototypes for functions local to this file. XXX -- should be static!
93 */
94 static char *db_qualify(
95 char *sym,
96 register char *symtabname);
97
98 boolean_t db_eqname(
99 char *src,
100 char *dst,
101 unsigned c);
102
103 boolean_t db_symbol_is_ambiguous(char *name);
104
105 void db_shorten_filename(char **filenamep);
106
107 void qsort_swap(
108 register int *a,
109 register int *b,
110 register int size);
111
112 void qsort_rotate(
113 register int *a,
114 register int *b,
115 register int *c,
116 register int size);
117
118 void qsort_recur(
119 char *left,
120 char *right,
121 int eltsize,
122 int (*compfun)(char *, char *));
123
124 void qsort_checker(
125 char *table,
126 int nbelts,
127 int eltsize,
128 int (*compfun)(char *, char *));
129
130 void bubble_sort(
131 char *table,
132 int nbelts,
133 int eltsize,
134 int (*compfun)(char *, char *));
135
136 int no_print_completion(
137 db_symtab_t *stab,
138 char *symstr );
139 int no_lookup_incomplete(
140 db_symtab_t *stab,
141 char *symstr,
142 char **name,
143 int *len,
144 int *toadd);
145
146 /*
147 * Initialization routine for ddb.
148 */
149 void
150 ddb_init(void)
151 {
152 X_db_init();
153 db_machdep_init();
154 }
155
156 extern vm_map_t kernel_map;
157 /*
158 * Add symbol table, with given name, to list of symbol tables.
159 */
160 boolean_t
161 db_add_symbol_table(
162 int type,
163 char *start,
164 char *db_end,
165 const char *name,
166 char *ref,
167 char *map_pointer,
168 unsigned long minsym,
169 unsigned long maxsym,
170 boolean_t sorted)
171 {
172 register db_symtab_t *st;
173
174 if (db_nsymtab >= MAXNOSYMTABS)
175 return (FALSE);
176
177 st = &db_symtabs[db_nsymtab];
178 st->type = type;
179 st->start = start;
180 st->end = db_end;
181 st->private = ref;
182 if (map_pointer == (char *)kernel_map ||
183 (VM_MIN_KERNEL_ADDRESS - VM_MAX_ADDRESS > 0 &&
184 minsym - VM_MIN_KERNEL_ADDRESS > 0))
185 st->map_pointer = 0;
186 else
187 st->map_pointer = map_pointer;
188 strcpy(st->name, name);
189 st->minsym = minsym;
190 st->maxsym = maxsym;
191 if (maxsym == 0)
192 st->sorted = FALSE;
193 else {
194 st->sorted = sorted;
195 if (db_maxval < maxsym + db_maxoff)
196 db_maxval = maxsym + db_maxoff;
197 }
198 db_nsymtab++;
199
200 return (TRUE);
201 }
202
203 /*
204 * db_qualify("vm_map", "ux") returns "ux::vm_map".
205 *
206 * Note: return value points to static data whose content is
207 * overwritten by each call... but in practice this seems okay.
208 */
209 static char *
210 db_qualify(
211 char *symname,
212 register char *symtabname)
213 {
214 static char tmp[256];
215 register char *s;
216
217 s = tmp;
218 while ((*s++ = *symtabname++)) {
219 ;
220 }
221 s[-1] = ':';
222 *s++ = ':';
223 while ((*s++ = *symname++)) {
224 ;
225 }
226 return tmp;
227 }
228
229
230 boolean_t
231 db_eqname(
232 char *src,
233 char *dst,
234 unsigned c)
235 {
236 if (!strcmp(src, dst))
237 return (TRUE);
238 if (src[0] == (char)c)
239 return (!strcmp(src+1,dst));
240 return (FALSE);
241 }
242
243 boolean_t
244 db_value_of_name(
245 const char *name,
246 db_expr_t *valuep)
247 {
248 db_sym_t sym;
249
250 sym = db_lookup(name);
251 if (sym == DB_SYM_NULL)
252 return (FALSE);
253 db_symbol_values(0, sym, &name, valuep);
254 return (TRUE);
255 }
256
257 /*
258 * Display list of possible completions for a symbol.
259 */
260 void
261 db_print_completion(
262 char *symstr)
263 {
264 register int i;
265 int symtab_start = 0;
266 int symtab_end = db_nsymtab;
267 register char *cp;
268
269 /*
270 * Look for, remove, and remember any symbol table specifier.
271 */
272 for (cp = symstr; *cp; cp++) {
273 if (*cp == ':' && cp[1] == ':') {
274 *cp = '\0';
275 for (i = 0; i < db_nsymtab; i++) {
276 if (! strcmp(symstr, db_symtabs[i].name)) {
277 symtab_start = i;
278 symtab_end = i + 1;
279 break;
280 }
281 }
282 *cp = ':';
283 if (i == db_nsymtab)
284 return;
285 symstr = cp+2;
286 }
287 }
288
289 /*
290 * Look in the specified set of symbol tables.
291 * Return on first match.
292 */
293 for (i = symtab_start; i < symtab_end; i++) {
294 if (X_db_print_completion(&db_symtabs[i], symstr))
295 break;
296 }
297 }
298
299 /*
300 * Lookup a (perhaps incomplete) symbol.
301 * If the symbol has a qualifier (e.g., ux::vm_map),
302 * then only the specified symbol table will be searched;
303 * otherwise, all symbol tables will be searched.
304 */
305 int
306 db_lookup_incomplete(
307 char *symstr,
308 int symlen)
309 {
310 register int i;
311 int symtab_start = 0;
312 int symtab_end = db_nsymtab;
313 register char *cp;
314 int nsym = 0;
315 char *name = (char *)0;
316 int len;
317 int toadd;
318
319 /*
320 * Look for, remove, and remember any symbol table specifier.
321 */
322 for (cp = symstr; *cp; cp++) {
323 if (*cp == ':' && cp[1] == ':') {
324 *cp = '\0';
325 for (i = 0; i < db_nsymtab; i++) {
326 if (! strcmp(symstr, db_symtabs[i].name)) {
327 symtab_start = i;
328 symtab_end = i + 1;
329 break;
330 }
331 }
332 *cp = ':';
333 if (i == db_nsymtab)
334 return 0;
335 symstr = cp+2;
336 }
337 }
338
339 /*
340 * Look in the specified set of symbol tables.
341 * Return on first match.
342 */
343 for (i = symtab_start; i < symtab_end; i++) {
344 nsym = X_db_lookup_incomplete(&db_symtabs[i], symstr,
345 &name, &len, &toadd);
346 if (nsym > 0) {
347 if (toadd > 0) {
348 len = strlen(symstr);
349 if (len + toadd >= symlen)
350 return 0;
351 bcopy(&name[len], &symstr[len], toadd);
352 symstr[len + toadd] = '\0';
353 }
354 break;
355 }
356 }
357 return nsym;
358 }
359
360 /*
361 * Lookup a symbol.
362 * If the symbol has a qualifier (e.g., ux::vm_map),
363 * then only the specified symbol table will be searched;
364 * otherwise, all symbol tables will be searched.
365 */
366 db_sym_t
367 db_lookup(const char *symstr)
368 {
369 db_sym_t sp;
370 int i;
371 int symtab_start = 0;
372 int symtab_end = db_nsymtab;
373 char *cp;
374
375 /*
376 * Look for, remove, and remember any symbol table specifier.
377 */
378 for (cp = symstr; *cp; cp++) {
379 if (*cp == ':' && cp[1] == ':') {
380 *cp = '\0';
381 for (i = 0; i < db_nsymtab; i++) {
382 if (! strcmp(symstr, db_symtabs[i].name)) {
383 symtab_start = i;
384 symtab_end = i + 1;
385 break;
386 }
387 }
388 *cp = ':';
389 if (i == db_nsymtab)
390 db_error("Invalid symbol table name\n");
391 symstr = cp+2;
392 }
393 }
394
395 /*
396 * Look in the specified set of symbol tables.
397 * Return on first match.
398 */
399 for (i = symtab_start; i < symtab_end; i++) {
400 if ((sp = X_db_lookup(&db_symtabs[i], symstr))) {
401 db_last_symtab = &db_symtabs[i];
402 return sp;
403 }
404 }
405 return 0;
406 }
407
408 /*
409 * Print a symbol completion
410 */
411 void
412 db_sym_print_completion(
413 db_symtab_t *stab,
414 char *name,
415 int function,
416 char *fname,
417 int line)
418 {
419 if (stab != db_symtabs)
420 db_printf("%s::", stab->name);
421 db_printf(name);
422 if (function) {
423 db_putchar('(');
424 db_putchar(')');
425 }
426 if (fname) {
427 db_printf(" [static from %s", fname);
428 if (line > 0)
429 db_printf(":%d", line);
430 db_putchar(']');
431 }
432 db_putchar('\n');
433 }
434
435 /*
436 * Common utility routine to parse a symbol string into a file
437 * name, a (possibly incomplete) symbol name without line number.
438 * This routine is called from aout_db_print_completion if the object
439 * dependent handler supports qualified search with a file name.
440 * It parses the symbol string, and call an object dependent routine
441 * with parsed file name and symbol name.
442 */
443 int
444 db_sym_parse_and_print_completion(
445 int (*func)(db_symtab_t *,
446 char *),
447 db_symtab_t *symtab,
448 char *symstr)
449 {
450 register char *p;
451 register int n;
452 char *sym_name;
453 char *component[2];
454 int nsym;
455
456 /*
457 * disassemble the symbol into components: [file_name:]symbol
458 */
459 component[0] = symstr;
460 component[1] = 0;
461 for (p = symstr, n = 1; *p; p++) {
462 if (*p == ':') {
463 if (n == 2)
464 break;
465 *p = 0;
466 component[n++] = p+1;
467 }
468 }
469 if (*p == 0) {
470 if (n == 1) {
471 sym_name = component[0];
472 } else {
473 sym_name = component[1];
474 }
475 nsym = func(symtab, sym_name);
476 } else
477 nsym = 0;
478 if (n == 2)
479 component[1][-1] = ':';
480 return nsym;
481 }
482
483 /*
484 * Common utility routine to parse a symbol string into a file
485 * name, a (possibly incomplete) symbol name without line number.
486 * This routine is called from X_db_lookup_incomplete if the object
487 * dependent handler supports qualified search with a file name.
488 * It parses the symbol string, and call an object dependent routine
489 * with parsed file name and symbol name.
490 */
491 int
492 db_sym_parse_and_lookup_incomplete(
493 int (*func)(db_symtab_t *,
494 char *,
495 char *,
496 int,
497 db_sym_t*,
498 char **,
499 int *),
500 db_symtab_t *symtab,
501 char *symstr,
502 char **name,
503 int *len,
504 int *toadd)
505 {
506 register char *p;
507 register int n;
508 char *file_name = 0;
509 char *sym_name = 0;
510 char *component[2];
511 int nsym = 0;
512
513 /*
514 * disassemble the symbol into components: [file_name:]symbol
515 */
516 component[0] = symstr;
517 component[1] = 0;
518 for (p = symstr, n = 1; *p; p++) {
519 if (*p == ':') {
520 if (n == 2)
521 break;
522 *p = 0;
523 component[n++] = p+1;
524 }
525 }
526 if (*p == 0) {
527 if (n == 1) {
528 file_name = 0;
529 sym_name = component[0];
530 } else {
531 file_name = component[0];
532 sym_name = component[1];
533 }
534 nsym = func(symtab, file_name, sym_name, 0, (db_sym_t *)0,
535 name, len);
536 if (nsym > 0)
537 *toadd = *len - strlen(sym_name);
538 }
539 if (n == 2)
540 component[1][-1] = ':';
541 return(nsym);
542 }
543
544 /*
545 * Common utility routine to parse a symbol string into a file
546 * name, a symbol name and line number.
547 * This routine is called from aout_db_lookup if the object dependent
548 * handler supports qualified search with a file name or a line number.
549 * It parses the symbol string, and call an object dependent routine
550 * with parsed file name, symbol name and line number.
551 */
552 db_sym_t
553 db_sym_parse_and_lookup(
554 int (*func)(db_symtab_t *, char *, char *, int,
555 db_sym_t*, char **, int *),
556 db_symtab_t *symtab,
557 char *symstr)
558 {
559 register char *p;
560 register int n;
561 int n_name;
562 int line_number;
563 char *file_name = 0;
564 char *sym_name = 0;
565 char *component[3];
566 db_sym_t found = DB_SYM_NULL;
567
568 /*
569 * disassemble the symbol into components:
570 * [file_name:]symbol[:line_nubmer]
571 */
572 component[0] = symstr;
573 component[1] = component[2] = 0;
574 for (p = symstr, n = 1; *p; p++) {
575 if (*p == ':') {
576 if (n >= 3)
577 break;
578 *p = 0;
579 component[n++] = p+1;
580 }
581 }
582 if (*p != 0)
583 goto out;
584 line_number = 0;
585 n_name = n;
586 p = component[n-1];
587 if (*p >= '0' && *p <= '9') {
588 if (n == 1)
589 goto out;
590 for (line_number = 0; *p; p++) {
591 if (*p < '0' || *p > '9')
592 goto out;
593 line_number = line_number*10 + *p - '0';
594 }
595 n_name--;
596 } else if (n >= 3)
597 goto out;
598 if (n_name == 1) {
599 for (p = component[0]; *p && *p != '.'; p++);
600 if (*p == '.') {
601 file_name = component[0];
602 sym_name = 0;
603 } else {
604 file_name = 0;
605 sym_name = component[0];
606 }
607 } else {
608 file_name = component[0];
609 sym_name = component[1];
610 }
611 (void) func(symtab, file_name, sym_name, line_number, &found,
612 (char **)0, (int *)0);
613
614 out:
615 while (--n >= 1)
616 component[n][-1] = ':';
617 return(found);
618 }
619
620 /*
621 * Does this symbol name appear in more than one symbol table?
622 * Used by db_symbol_values to decide whether to qualify a symbol.
623 */
624 boolean_t db_qualify_ambiguous_names = TRUE;
625
626 boolean_t
627 db_symbol_is_ambiguous(char *name)
628 {
629 register int i;
630 register
631 boolean_t found_once = FALSE;
632
633 if (!db_qualify_ambiguous_names)
634 return FALSE;
635
636 for (i = 0; i < db_nsymtab; i++) {
637 if (X_db_lookup(&db_symtabs[i], name)) {
638 if (found_once)
639 return TRUE;
640 found_once = TRUE;
641 }
642 }
643 return FALSE;
644 }
645
646 /*
647 * Find the closest symbol to val, and return its name
648 * and the difference between val and the symbol found.
649 */
650 unsigned int db_search_maxoff = 0x4000;
651 db_sym_t
652 db_search_task_symbol(
653 register db_addr_t val,
654 db_strategy_t strategy,
655 db_addr_t *offp, /* better be unsigned */
656 task_t task)
657 {
658 db_addr_t diff, newdiff;
659 register int i;
660 db_symtab_t *sp;
661 db_sym_t ret = DB_SYM_NULL, sym;
662 vm_map_t map_for_val;
663
664 if (task == TASK_NULL)
665 task = db_current_task();
666 map_for_val = (task == TASK_NULL)? VM_MAP_NULL: task->map;
667 again:
668 newdiff = diff = -1;
669 db_last_symtab = 0;
670 for (sp = &db_symtabs[0], i = 0;
671 i < db_nsymtab;
672 sp++, i++) {
673 if ((((vm_map_t)sp->map_pointer == VM_MAP_NULL) ||
674 ((vm_map_t)sp->map_pointer == map_for_val)) &&
675 ((sp->maxsym == 0) ||
676 ((val >= (db_addr_t)sp->minsym) &&
677 (val <= (db_addr_t)sp->maxsym)))) {
678 sym = X_db_search_symbol(sp, val, strategy,
679 (db_expr_t *)&newdiff);
680 if (newdiff < diff) {
681 db_last_symtab = sp;
682 diff = newdiff;
683 ret = sym;
684 if (diff <= db_search_maxoff)
685 break;
686 }
687 }
688 }
689 if (ret == DB_SYM_NULL && map_for_val != VM_MAP_NULL) {
690 map_for_val = VM_MAP_NULL;
691 goto again;
692 }
693 *offp = diff;
694 return ret;
695 }
696
697 /*
698 * Find the closest symbol to val, and return its name
699 * and the difference between val and the symbol found.
700 * Also return the filename and linenumber if available.
701 */
702 db_sym_t
703 db_search_task_symbol_and_line(
704 register db_addr_t val,
705 __unused db_strategy_t strategy,
706 db_expr_t *offp,
707 char **filenamep,
708 int *linenump,
709 task_t task,
710 int *argsp)
711 {
712 db_addr_t diff, newdiff;
713 register int i;
714 db_symtab_t *sp;
715 db_sym_t ret = DB_SYM_NULL, sym;
716 vm_map_t map_for_val;
717 char *func;
718 char *filename;
719 int linenum;
720 int args;
721
722 if (task == TASK_NULL)
723 task = db_current_task();
724 map_for_val = (task == TASK_NULL)? VM_MAP_NULL: task->map;
725 *filenamep = (char *) 0;
726 *linenump = 0;
727 *argsp = -1;
728 again:
729 filename = (char *) 0;
730 linenum = 0;
731 newdiff = diff = ~0UL;
732 db_last_symtab = 0;
733 for (sp = &db_symtabs[0], i = 0;
734 i < db_nsymtab;
735 sp++, i++) {
736 if ((((vm_map_t)sp->map_pointer == VM_MAP_NULL) ||
737 ((vm_map_t)sp->map_pointer == map_for_val)) &&
738 ((sp->maxsym == 0) ||
739 ((val >= (db_addr_t)sp->minsym) &&
740 (val <= (db_addr_t)sp->maxsym)))) {
741
742 sym = X_db_search_by_addr(sp, val, &filename, &func,
743 &linenum, (db_expr_t *)&newdiff,
744 &args);
745 if (sym && newdiff < diff) {
746 db_last_symtab = sp;
747 diff = newdiff;
748 ret = sym;
749 *filenamep = filename;
750 *linenump = linenum;
751 *argsp = args;
752 if (diff <= db_search_maxoff)
753 break;
754 }
755 }
756 }
757 if (ret == DB_SYM_NULL && map_for_val != VM_MAP_NULL) {
758 map_for_val = VM_MAP_NULL;
759 goto again;
760 }
761 *offp = diff;
762 if (*filenamep)
763 db_shorten_filename(filenamep);
764 return ret;
765 }
766
767 /*
768 * Return name and value of a symbol
769 */
770 void
771 db_symbol_values(
772 db_symtab_t *stab,
773 db_sym_t sym,
774 const char **namep,
775 db_expr_t *valuep)
776 {
777 db_expr_t value;
778 char *name;
779
780 if (sym == DB_SYM_NULL) {
781 *namep = 0;
782 return;
783 }
784 if (stab == 0)
785 stab = db_last_symtab;
786
787 X_db_symbol_values(stab, sym, &name, &value);
788
789 if (db_symbol_is_ambiguous(name)) {
790 *namep = db_qualify(name, db_last_symtab->name);
791 }else {
792 *namep = name;
793 }
794 if (valuep)
795 *valuep = value;
796 }
797
798
799 /*
800 * Print a the closest symbol to value
801 *
802 * After matching the symbol according to the given strategy
803 * we print it in the name+offset format, provided the symbol's
804 * value is close enough (eg smaller than db_maxoff).
805 * We also attempt to print [filename:linenum] when applicable
806 * (eg for procedure names).
807 *
808 * If we could not find a reasonable name+offset representation,
809 * then we just print the value in hex. Small values might get
810 * bogus symbol associations, e.g. 3 might get some absolute
811 * value like _INCLUDE_VERSION or something, therefore we do
812 * not accept symbols whose value is zero (and use plain hex).
813 */
814
815 void
816 db_task_printsym(
817 db_addr_t off,
818 db_strategy_t strategy,
819 task_t task)
820 {
821 db_expr_t d;
822 char *filename;
823 char *name;
824 db_expr_t value;
825 int linenum;
826 db_sym_t cursym;
827
828 if (off >= db_maxval || off < db_minval) {
829 db_printf("%#lln", (unsigned long long)off);
830 return;
831 }
832 cursym = db_search_task_symbol(off, strategy, &d, task);
833
834 db_symbol_values(0, cursym, &name, &value);
835 if (name == 0 || d >= db_maxoff || value == 0) {
836 db_printf("%#lln",(unsigned long long) off);
837 return;
838 }
839 db_printf("%s", name);
840 if (d)
841 db_printf("+%llx", (unsigned long long)d);
842 if (strategy == DB_STGY_PROC) {
843 if (db_line_at_pc(cursym, &filename, &linenum, off)) {
844 db_printf(" [%s", filename);
845 if (linenum > 0)
846 db_printf(":%d", linenum);
847 db_printf("]");
848 }
849 }
850 }
851
852 /*
853 * Return symbol name for a given offset and
854 * change the offset to be relative to this symbol.
855 * Very usefull for xpr, when you want to log offsets
856 * in a user friendly way.
857 */
858
859 char null_sym[] = "";
860
861 char *
862 db_get_sym(db_expr_t *off)
863 {
864 db_sym_t cursym;
865 db_expr_t value;
866 char *name;
867 db_addr_t d;
868
869 cursym = db_search_symbol(*off, DB_STGY_ANY, &d);
870 db_symbol_values(0, cursym, &name, &value);
871 if (name)
872 *off = d;
873 else
874 name = null_sym;
875 return(name);
876 }
877
878 void
879 db_printsym(
880 db_expr_t off,
881 db_strategy_t strategy)
882 {
883 db_task_printsym(off, strategy, TASK_NULL);
884 }
885
886 int db_short_filename = 1;
887
888 void
889 db_shorten_filename(char **filenamep)
890 {
891 char *cp, *cp_slash;
892
893 if (! *filenamep)
894 return;
895 for (cp = cp_slash = *filenamep; *cp; cp++) {
896 if (*cp == '/')
897 cp_slash = cp;
898 }
899 if (*cp_slash == '/')
900 *filenamep = cp_slash+1;
901 }
902
903 int
904 db_task_getlinenum(
905 db_expr_t off,
906 task_t task)
907 {
908 db_addr_t d;
909 char *filename;
910 char *name;
911 db_expr_t value;
912 int linenum;
913 db_sym_t cursym;
914 db_strategy_t strategy = DB_STGY_PROC;
915
916 if (off >= db_maxval || off < db_minval) {
917 db_printf("%#lln", (unsigned long long)off);
918 return(-1);
919 }
920 cursym = db_search_task_symbol(off, strategy, &d, task);
921
922 db_symbol_values(0, cursym, &name, &value);
923 if (name == 0 || d >= db_maxoff || value == 0) {
924 return(-1);
925 }
926 if (db_line_at_pc(cursym, &filename, &linenum, off))
927 return(linenum);
928 else
929 return(-1);
930 }
931
932 boolean_t
933 db_line_at_pc(
934 db_sym_t sym,
935 char **filename,
936 int *linenum,
937 db_expr_t pc)
938 {
939 boolean_t result;
940
941 if (db_last_symtab == 0)
942 return FALSE;
943 if (X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc)) {
944 if (db_short_filename)
945 db_shorten_filename(filename);
946 result = TRUE;
947 } else
948 result = FALSE;
949 return(result);
950 }
951
952 int qsort_check = 0;
953
954 void
955 db_qsort(
956 char *table,
957 int nbelts,
958 int eltsize,
959 int (*compfun)(char *, char *))
960 {
961 if (nbelts <= 0 || eltsize <= 0 || compfun == 0) {
962 printf("qsort: invalid parameters\n");
963 return;
964 }
965 qsort_recur(table, table + nbelts * eltsize, eltsize, compfun);
966
967 if (qsort_check)
968 qsort_checker(table, nbelts, eltsize, compfun);
969 }
970
971 void
972 qsort_swap(
973 register int *a,
974 register int *b,
975 register int size)
976 {
977 register int temp;
978 char *aa, *bb;
979 char ctemp;
980
981 for (; size >= (signed)sizeof (int); size -= sizeof (int), a++, b++) {
982 temp = *a;
983 *a = *b;
984 *b = temp;
985 }
986 aa = (char *)a;
987 bb = (char *)b;
988 for (; size > 0; size--, aa++, bb++) {
989 ctemp = *aa;
990 *aa = *bb;
991 *bb = ctemp;
992 }
993 }
994
995 /* rotate the three elements to the left */
996 void
997 qsort_rotate(
998 register int *a,
999 register int *b,
1000 register int *c,
1001 register int size)
1002 {
1003 register int temp;
1004 char *aa, *bb, *cc;
1005 char ctemp;
1006
1007 for (; size >= (signed)sizeof(int);
1008 size -= sizeof(int), a++, b++, c++) {
1009 temp = *a;
1010 *a = *c;
1011 *c = *b;
1012 *b = temp;
1013 }
1014 aa = (char *)a;
1015 bb = (char *)b;
1016 cc = (char *)c;
1017 for (; size > 0; size--, aa++, bb++, cc++) {
1018 ctemp = *aa;
1019 *aa = *cc;
1020 *cc = *bb;
1021 *bb = ctemp;
1022 }
1023 }
1024
1025 void
1026 qsort_recur(
1027 char *left,
1028 char *right,
1029 int eltsize,
1030 int (*compfun)(char *, char *))
1031 {
1032 char *i, *j;
1033 char *sameleft, *sameright;
1034
1035 top:
1036 if (left + eltsize - 1 >= right) {
1037 return;
1038 }
1039
1040 /* partition element (reference for "same"ness */
1041 sameleft = left + (((right - left) / eltsize) / 2) * eltsize;
1042 sameright = sameleft;
1043
1044 i = left;
1045 j = right - eltsize;
1046
1047 again:
1048 while (i < sameleft) {
1049 int comp;
1050
1051 comp = (*compfun)(i, sameleft);
1052 if (comp == 0) {
1053 /*
1054 * Move to the "same" partition.
1055 */
1056 /*
1057 * Shift the left part of the "same" partition to
1058 * the left, so that "same" elements stay in their
1059 * original order.
1060 */
1061 sameleft -= eltsize;
1062 qsort_swap((int *) i, (int *) sameleft, eltsize);
1063 } else if (comp < 0) {
1064 /*
1065 * Stay in the "left" partition.
1066 */
1067 i += eltsize;
1068 } else {
1069 /*
1070 * Should be moved to the "right" partition.
1071 * Wait until the next loop finds an appropriate
1072 * place to store this element.
1073 */
1074 break;
1075 }
1076 }
1077
1078 while (j > sameright) {
1079 int comp;
1080
1081 comp = (*compfun)(sameright, j);
1082 if (comp == 0) {
1083 /*
1084 * Move to the right of the "same" partition.
1085 */
1086 sameright += eltsize;
1087 qsort_swap((int *) sameright, (int *) j, eltsize);
1088 } else if (comp > 0) {
1089 /*
1090 * Move to the "left" partition.
1091 */
1092 if (i == sameleft) {
1093 /*
1094 * Unfortunately, the "left" partition
1095 * has already been fully processed, so
1096 * we have to shift the "same" partition
1097 * to the right to free a "left" element.
1098 * This is done by moving the leftest same
1099 * to the right of the "same" partition.
1100 */
1101 sameright += eltsize;
1102 qsort_rotate((int *) sameleft, (int*) sameright,
1103 (int *) j, eltsize);
1104 sameleft += eltsize;
1105 i = sameleft;
1106 } else {
1107 /*
1108 * Swap with the "left" partition element
1109 * waiting to be moved to the "right"
1110 * partition.
1111 */
1112 qsort_swap((int *) i, (int *) j, eltsize);
1113 j -= eltsize;
1114 /*
1115 * Go back to the 1st loop.
1116 */
1117 i += eltsize;
1118 goto again;
1119 }
1120 } else {
1121 /*
1122 * Stay in the "right" partition.
1123 */
1124 j -= eltsize;
1125 }
1126 }
1127
1128 if (i != sameleft) {
1129 /*
1130 * The second loop completed (the"right" partition is ok),
1131 * but we have to go back to the first loop, and deal with
1132 * the element waiting for a place in the "right" partition.
1133 * Let's shift the "same" zone to the left.
1134 */
1135 sameleft -= eltsize;
1136 qsort_rotate((int *) sameright, (int *) sameleft, (int *) i,
1137 eltsize);
1138 sameright -= eltsize;
1139 j = sameright;
1140 /*
1141 * Go back to 1st loop.
1142 */
1143 goto again;
1144 }
1145
1146 /*
1147 * The partitions are correct now. Recur on the smallest side only.
1148 */
1149 if (sameleft - left >= right - (sameright + eltsize)) {
1150 qsort_recur(sameright + eltsize, right, eltsize, compfun);
1151 /*
1152 * The "right" partition is now completely sorted.
1153 * The "same" partition is OK, so...
1154 * Ignore them, and start the loops again on the
1155 * "left" partition.
1156 */
1157 right = sameleft;
1158 goto top;
1159 } else {
1160 qsort_recur(left, sameleft, eltsize, compfun);
1161 /*
1162 * The "left" partition is now completely sorted.
1163 * The "same" partition is OK, so ...
1164 * Ignore them, and start the loops again on the
1165 * "right" partition.
1166 */
1167 left = sameright + eltsize;
1168 goto top;
1169 }
1170 }
1171
1172 void
1173 qsort_checker(
1174 char *table,
1175 int nbelts,
1176 int eltsize,
1177 int (*compfun)(char *, char *))
1178 {
1179 char *curr, *prev, *last;
1180
1181 prev = table;
1182 curr = prev + eltsize;
1183 last = table + (nbelts * eltsize);
1184
1185 while (prev < last) {
1186 if ((*compfun)(prev, curr) > 0) {
1187 printf("**** qsort_checker: error between 0x%x and 0x%x!!!\n", prev, curr);
1188 break;
1189 }
1190 prev = curr;
1191 curr += eltsize;
1192 }
1193 printf("qsort_checker: OK\n");
1194 }
1195
1196 int qsort_search_debug = 0;
1197
1198 void
1199 db_qsort_limit_search(
1200 char *target,
1201 char **start,
1202 char **db_end,
1203 int eltsize,
1204 int (*compfun)(char *, char *))
1205 {
1206 register char *left, *right;
1207 char *oleft, *oright, *part;
1208 int nbiter = 0;
1209 int comp;
1210
1211 oleft = left = *start;
1212 oright = right = *db_end;
1213 part = (char *) 0;
1214
1215 while (left < right) {
1216 nbiter++;
1217 part = left + (((right - left) / eltsize) / 2) * eltsize;
1218 comp = (*compfun)(target, part);
1219 if (comp > 0) {
1220 oleft = left;
1221 oright = right;
1222 left = part;
1223 if (left == oleft)
1224 break;
1225 if (qsort_search_debug > 1)
1226 printf(" [ Moved left from 0x%x to 0x%x]\n",
1227 oleft, left);
1228 } else if (comp < 0) {
1229 oright = right;
1230 oleft = left;
1231 right = part;
1232 if (qsort_search_debug > 1)
1233 printf(" [ Moved right from 0x%x to 0x%x]\n",
1234 oright, right);
1235 } else {
1236 if (qsort_search_debug > 1)
1237 printf(" [ FOUND! left=0x%x right=0x%x]\n",
1238 left, right);
1239 for (left = part;
1240 left > *start && (*compfun)(left, part) == 0;
1241 left -= eltsize);
1242 for (right = part + eltsize;
1243 right < *db_end && (*compfun)(right, part) == 0;
1244 right += eltsize);
1245 oright = right;
1246 oleft = left;
1247 break;
1248 }
1249 }
1250
1251 if (qsort_search_debug)
1252 printf("[ Limited from %x-%x to %x-%x in %d iters ]\n",
1253 *start, *db_end, oleft, oright, nbiter);
1254 *start = oleft;
1255 *db_end = oright;
1256 }
1257
1258 void
1259 bubble_sort(
1260 char *table,
1261 int nbelts,
1262 int eltsize,
1263 int (*compfun)(char *, char *))
1264 {
1265 boolean_t sorted;
1266 char *b_end;
1267 register char *p;
1268
1269 b_end = table + ((nbelts-1) * eltsize);
1270 do {
1271 sorted = TRUE;
1272 for (p = table; p < b_end; p += eltsize) {
1273 if ((*compfun)(p, p + eltsize) > 0) {
1274 qsort_swap((int *) p, (int *) (p + eltsize),
1275 eltsize);
1276 sorted = FALSE;
1277 }
1278 }
1279 } while (sorted == FALSE);
1280
1281 if (qsort_check)
1282 qsort_checker(table, nbelts, eltsize, compfun);
1283 }
1284
1285 vm_offset_t vm_min_inks_addr = VM_MAX_KERNEL_ADDRESS;
1286
1287 void
1288 db_install_inks(
1289 vm_offset_t base)
1290 {
1291 /* save addr to demarcate kernel/inks boundary (1st time only) */
1292 if (vm_min_inks_addr == VM_MAX_KERNEL_ADDRESS) {
1293 vm_min_inks_addr = base;
1294 db_qualify_ambiguous_names = TRUE;
1295 }
1296 }
1297
1298 extern void db_clone_offsetXXX(char *, long);
1299
1300 void
1301 db_clone_symtabXXX(
1302 char *clonee, /* which symtab to clone */
1303 char *cloner, /* in-kernel-server name */
1304 vm_offset_t base) /* base address of cloner */
1305 {
1306 db_symtab_t *st, *st_src;
1307 char * memp;
1308 vm_size_t size;
1309 long offset;
1310
1311 if (db_nsymtab >= MAXNOSYMTABS) {
1312 db_printf("db_clone_symtab: Too Many Symbol Tables\n");
1313 return;
1314 }
1315
1316 db_install_inks(base);
1317
1318 st = &db_symtabs[db_nsymtab]; /* destination symtab */
1319 if ((st_src = db_symtab_cloneeXXX(clonee)) == 0) {
1320 db_printf("db_clone_symtab: clonee (%s) not found\n", clonee);
1321 return;
1322 }
1323 /* alloc new symbols */
1324 size = (vm_size_t)(st_src->end - st_src->private);
1325 memp = (char *)kalloc( round_page(size) );
1326 if (!memp) {
1327 db_printf("db_clone_symtab: no memory for symtab\n");
1328 return;
1329 }
1330
1331 *st = *st_src; /* bulk copy src -> dest */
1332 strcpy(st->name, cloner); /* new name */
1333 st->private = memp; /* copy symbols */
1334 bcopy((const char *)st_src->private, st->private, size);
1335 st->start = memp + sizeof(int); /* fixup pointers to symtab */
1336 st->end = memp + *(int *)memp;
1337 st->map_pointer = 0; /* no map because kernel-loaded */
1338
1339 /* Offset symbols, leaving strings pointing into st_src */
1340 offset = base - st_src->minsym;
1341 st->minsym += offset;
1342 st->maxsym += offset;
1343 db_clone_offsetXXX(memp, offset);
1344 db_nsymtab++;
1345
1346 db_printf( "[ cloned symbol table for %s: range 0x%x to 0x%x %s]\n",
1347 st->name, st->minsym, st->maxsym,
1348 st->sorted ? "(sorted) " : "");
1349 db_maxval = (unsigned int)st->maxsym + db_maxoff;
1350 }
1351
1352 db_symtab_t *
1353 db_symtab_cloneeXXX(
1354 char *clonee)
1355 {
1356 db_symtab_t *st, *st_src;
1357
1358 st = &db_symtabs[db_nsymtab]; /* destination symtab */
1359 for (st_src = &db_symtabs[0]; st_src < st; ++st_src)
1360 if (!strcmp(clonee, st_src->name))
1361 break;
1362 return ((st_src < st) ? st_src : 0);
1363 }
1364
1365 /*
1366 * Switch into symbol-table specific routines
1367 */
1368
1369 #if !defined(__alpha) && !defined(INTEL860)
1370 #define DB_NO_COFF
1371 #endif
1372
1373 #ifndef DB_NO_AOUT
1374 #include <ddb/db_aout.h>
1375 #endif
1376
1377 #ifndef DB_NO_COFF
1378 #include <ddb/db_coff.h>
1379 #endif
1380
1381 static void no_init(void)
1382
1383 {
1384 db_printf("Non-existent code for ddb init\n");
1385 }
1386
1387 static boolean_t
1388 no_sym_init(__unused char *nstart, __unused char *nend, const char *name,
1389 __unused char *task_addr)
1390 {
1391 db_printf("Non-existent code for init of symtab %s\n", name);
1392 return FALSE;
1393 }
1394
1395 static db_sym_t
1396 no_lookup(__unused db_symtab_t *stab, char *symstr)
1397 {
1398 db_printf("Bogus lookup of symbol %s\n", symstr);
1399 return DB_SYM_NULL;
1400 }
1401
1402 static db_sym_t
1403 no_search(__unused db_symtab_t *stab, db_addr_t off,
1404 __unused db_strategy_t strategy, __unused db_expr_t *diffp)
1405 {
1406 db_printf("Bogus search for offset %#llXn", (unsigned long long)off);
1407 return DB_SYM_NULL;
1408 }
1409
1410 static boolean_t
1411 no_line_at_pc(__unused db_symtab_t *stab, __unused db_sym_t sym,
1412 __unused char **file, __unused int *line, db_expr_t pc)
1413 {
1414 db_printf("Bogus search for pc %#llX\n", (unsigned long long)pc);
1415 return FALSE;
1416 }
1417
1418 static void
1419 no_symbol_values(__unused db_sym_t sym, char **namep, db_expr_t *valuep)
1420 {
1421 db_printf("Bogus symbol value resolution\n");
1422 if (namep) *namep = NULL;
1423 if (valuep) *valuep = 0;
1424 }
1425
1426 static db_sym_t
1427 no_search_by_addr(__unused db_symtab_t *stab, db_addr_t off,
1428 __unused char **file, __unused char **func,
1429 __unused int *line, __unused db_expr_t *diffp,
1430 __unused int *args)
1431 {
1432 db_printf("Bogus search for address %#llX\n", (unsigned long long)off);
1433 return DB_SYM_NULL;
1434 }
1435
1436 int
1437 no_print_completion(__unused db_symtab_t *stab, __unused char *symstr)
1438 {
1439 db_printf("Bogus print completion: not supported\n");
1440 return 0;
1441 }
1442
1443 int
1444 no_lookup_incomplete(__unused db_symtab_t *stab,
1445 __unused char *symstr, __unused char **name,
1446 __unused int *len, __unused int *toadd)
1447 {
1448 db_printf("Bogus lookup incomplete: not supported\n");
1449 return 0;
1450 }
1451
1452 #define NONE \
1453 { \
1454 .init = no_init, \
1455 .sym_init = no_sym_init, \
1456 .lookup = no_lookup, \
1457 .search_symbol = no_search, \
1458 .line_at_pc = no_line_at_pc, \
1459 .symbol_values = no_symbol_values, \
1460 .search_by_addr = no_search_by_addr, \
1461 .print_completion = no_print_completion, \
1462 .lookup_incomplete = no_lookup_incomplete, \
1463 }
1464
1465 struct db_sym_switch x_db[] = {
1466
1467 /* BSD a.out format (really, sdb/dbx(1) symtabs) */
1468 #ifdef DB_NO_AOUT
1469 NONE,
1470 #else /* DB_NO_AOUT */
1471 {
1472 .init = aout_db_init,
1473 .sym_init = aout_db_sym_init,
1474 .lookup = aout_db_lookup,
1475 .search_symbol = aout_db_search_symbol,
1476 .line_at_pc = aout_db_line_at_pc,
1477 .symbol_values = aout_db_symbol_values,
1478 .search_by_addr = aout_db_search_by_addr,
1479 .print_completion = aout_db_print_completion,
1480 .lookup_incomplete = aout_db_lookup_incomplete,
1481 },
1482 #endif /* DB_NO_AOUT */
1483
1484 #ifdef DB_NO_COFF
1485 NONE,
1486 #else /* DB_NO_COFF */
1487 {
1488 .init = coff_db_init,
1489 .sym_init = coff_db_sym_init,
1490 .lookup = coff_db_lookup,
1491 .search_symbol = coff_db_search_symbol,
1492 .line_at_pc = coff_db_line_at_pc,
1493 .symbol_values = coff_db_symbol_values,
1494 .search_by_addr = coff_db_search_by_addr,
1495 .print_completion = coff_db_print_completion,
1496 .lookup_incomplete = coff_db_lookup_incomplete,
1497 },
1498 #endif /* DB_NO_COFF */
1499
1500 /* Machdep, not inited here */
1501 NONE
1502 };