2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
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.
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.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
59 * Author: David B. Golub, Carnegie Mellon University
63 * Symbol table routines for a.out format files.
65 #include <mach/mach_types.h>
66 #include <mach/boolean.h>
67 #include <mach/std_types.h>
68 #include <machine/db_machdep.h> /* data types */
70 #include <string.h> /* For strcpy(), strcmp() */
71 #include <ddb/db_aout.h>
72 #include <ddb/db_output.h> /* For db_printf() */
73 #include <ddb/db_sym.h>
77 #include <ddb/nlist.h> /* a.out symbol table */
80 #include <libkern/kernel_mach_header.h>
82 #define private static
84 private int aout_db_order_symbols(char *, char *);
85 private int aout_db_compare_symbols(char *, char *);
86 private boolean_t
aout_db_is_filename(char *);
87 private boolean_t
aout_db_eq_name(struct nlist
*, char *, int);
90 * An a.out symbol table as loaded into the kernel debugger:
92 * symtab -> size of symbol entries, in bytes
93 * sp -> first symbol entry
95 * ep -> last symbol entry + 1
96 * strtab == start of string table
97 * size of string table in bytes,
103 * Find pointers to the start and end of the symbol entries,
104 * given a pointer to the start of the symbol table.
106 #define db_get_aout_symtab(symtab, sp, ep) \
107 (sp = (struct nlist *)(((vm_offset_t *)(symtab)) + 1), \
108 ep = (struct nlist *)((char *)sp + *((int *)(symtab))))
110 char *db_sorting_sym_end
;
113 aout_db_order_symbols(
117 struct nlist
*sym1
= (struct nlist
*) s1
;
118 struct nlist
*sym2
= (struct nlist
*) s2
;
120 if (sym1
->n_value
!= sym2
->n_value
)
121 return (sym1
->n_value
- sym2
->n_value
);
123 return (sym1
->n_un
.n_name
- sym2
->n_un
.n_name
);
128 aout_db_compare_symbols(
132 return (((struct nlist
*) sym1
)->n_value
-
133 ((struct nlist
*) sym2
)->n_value
);
136 int db_sorting_limit
= 50000;
140 char * symtab
, /* pointer to start of symbol table */
141 __unused
char *esymtab
, /* pointer to end of string table,
142 for checking - may be rounded up to
145 char * task_addr
) /* use for this task only */
147 struct nlist
*sym_start
, *sym_end
, *dbsym_start
, *dbsym_end
;
149 char *strtab
, *dbstrtab
;
151 char *estrtab
, *dbestrtab
;
152 unsigned long minsym
= ~0;
153 unsigned long maxsym
= 0;
159 if (!getsymtab((kernel_mach_header_t
*)symtab
,
160 (vm_offset_t
*)&sym_start
, &nsyms
,
161 (vm_offset_t
*)&strtab
, (vm_size_t
*)&db_strlen
)) {
164 sym_end
= sym_start
+ nsyms
;
165 estrtab
= strtab
+ db_strlen
;
168 * We haven't actually started up VM yet, so we can just steal some pages to
169 * make a working copy of the symbols and strings
172 dbsym_start
= (struct nlist
*)pmap_steal_memory(((unsigned int)sym_end
- (unsigned int)sym_start
+ 4096) & -4096); /* Get space for symbols */
173 dbstrtab
= (char *)pmap_steal_memory(((unsigned int)estrtab
- (unsigned int)strtab
+ 4096) & -4096); /* Get space for strings */
175 bcopy((char *)sym_start
, (char *)dbsym_start
, (unsigned int)sym_end
- (unsigned int)sym_start
); /* Copy symbols */
176 bcopy(strtab
, dbstrtab
, (unsigned int)estrtab
- (unsigned int)strtab
); /* Copy strings */
178 dbsym_end
= dbsym_start
+ nsyms
;
179 dbestrtab
= dbstrtab
+ db_strlen
;
181 sorting
= ((dbsym_end
- dbsym_start
) < db_sorting_limit
);
183 for (sp
= dbsym_start
; sp
< dbsym_end
; sp
++) {
185 strx
= sp
->n_un
.n_strx
;
187 if (strx
> db_strlen
) {
191 sp
->n_un
.n_name
= dbstrtab
+ strx
;
193 if (sp
->n_type
!= N_ABS
) {
194 if (sp
->n_value
> 0 && sp
->n_value
< minsym
)
195 minsym
= sp
->n_value
;
196 if (sp
->n_value
> maxsym
)
197 maxsym
= sp
->n_value
;
205 db_qsort((char *) dbsym_start
, dbsym_end
- dbsym_start
,
206 sizeof(struct nlist
), aout_db_order_symbols
);
211 if (db_add_symbol_table(SYMTAB_AOUT
,
221 /* Successfully added symbol table */
223 pmap_protect(kernel_pmap
,
224 (vm_offset_t
) dbsym_start
, (vm_offset_t
) dbsym_end
,
225 VM_PROT_READ
|VM_PROT_WRITE
);
226 pmap_protect(kernel_pmap
,
227 (vm_offset_t
) dbstrtab
, (vm_offset_t
) dbestrtab
,
228 VM_PROT_READ
|VM_PROT_WRITE
);
235 * This KLUDGE offsets the n_values of a copied symbol table
237 void db_clone_offsetXXX(char *, long);
239 db_clone_offsetXXX(char * symtab
, long offset
)
241 register struct nlist
*sym_start
, *sym_end
, *sp
;
243 db_get_aout_symtab((int *)symtab
, sym_start
, sym_end
);
245 for (sp
= sym_start
; sp
< sym_end
; sp
++)
246 if (sp
->n_type
!= N_ABS
)
247 sp
->n_value
+= offset
;
252 * check file name or not (check xxxx.x pattern)
255 aout_db_is_filename(char *name
)
268 * special name comparison routine with a name in the symbol table entry
276 register char *s1
, *s2
;
278 s1
= sp
->n_un
.n_name
;
280 #ifndef __NO_UNDERSCORES__
281 if (*s1
== '_' && *s2
&& *s2
!= '_')
283 #endif /* __NO_UNDERSCORES__ */
285 if (*s1
++ != *s2
++) {
287 * check .c .o file name comparison case
289 if (*s2
== 0 && sp
->n_un
.n_name
<= s1
- 2
290 && s1
[-2] == '.' && s1
[-1] == 'o')
298 * do special check for
300 * xxx.ttt for N_DATA and N_BSS
302 return(*s1
== 0 || (*s1
== ':' && sp
->n_type
== N_FUN
) ||
303 (*s1
== '.' && (sp
->n_type
== N_DATA
|| sp
->n_type
== N_BSS
)));
307 * search a symbol table with name and type
308 * fp(in,out): last found text file name symbol entry
310 private struct nlist
*
319 struct nlist
*file_sp
= *fp
;
320 struct nlist
*found_sp
= 0;
322 for ( ; sp
< ep
; sp
++) {
325 if (sp
->n_type
== N_TEXT
&& aout_db_is_filename(sp
->n_un
.n_name
))
328 if (sp
->n_type
== type
) {
329 /* dwm_debug: b26 name, mk6 added last param */
330 if (aout_db_eq_name(sp
, name
, 0))
333 if (sp
->n_type
== N_SO
)
337 if (sp
->n_type
& N_STAB
)
339 if (sp
->n_un
.n_name
&& aout_db_eq_name(sp
, name
, incomplete
)) {
341 * In case of qaulified search by a file,
342 * return it immediately with some check.
343 * Otherwise, search external one
346 if ((file_sp
== *fp
) || (sp
->n_type
& N_EXT
))
348 } else if ((sp
->n_type
& N_EXT
) ||
349 (incomplete
&& !aout_db_is_filename(sp
->n_un
.n_name
)))
359 * Print sorted possible completions for a symbol.
360 * Use n_other field to mark completion symbols in order
364 aout_db_qualified_print_completion(
371 struct nlist
*ep1
= NULL
;
372 struct nlist
*fp
= 0;
381 sp
= aout_db_search_name((struct nlist
*)stab
->start
,
382 (struct nlist
*)stab
->end
,
384 if (sp
== (struct nlist
*)0)
387 symlen
= strlen(sym
);
390 if (strncmp(cur
->n_un
.n_name
, sym
, symlen
) == 0)
395 cur
= aout_db_search_name(cur
+ 1, (struct nlist
*)stab
->end
,
406 if (strncmp(&cur
->n_un
.n_name
[cur
->n_other
- 1],
407 &new->n_un
.n_name
[new->n_other
- 1],
415 if ((new->n_type
& N_EXT
) == 0) {
416 for (cur
= new - 1; cur
> (struct nlist
*)stab
->start
; cur
--) {
417 if (cur
->n_type
== N_SO
||
418 (stab
->sorted
&& cur
->n_value
< new->n_value
))
421 cur
->n_type
== N_SLINE
&&
422 cur
->n_value
== new->n_value
)
425 cur
->n_type
== N_FUN
&&
426 cur
->n_value
== new->n_value
)
430 if (cur
->n_type
== N_SO
)
431 fname
= cur
->n_un
.n_name
;
435 if (line
== 0 || func
== 0)
437 cur
< (struct nlist
*)stab
->end
; cur
++) {
438 if (cur
->n_type
== N_SO
||
439 (stab
->sorted
&& cur
->n_value
> new->n_value
))
442 cur
->n_type
== N_SLINE
&&
443 cur
->n_value
== new->n_value
) {
449 cur
->n_type
== N_FUN
&&
450 cur
->n_value
== new->n_value
) {
458 for (cur
= new - 1; cur
> (struct nlist
*)stab
->start
; cur
--) {
459 if (cur
->n_type
== N_SO
||
460 (stab
->sorted
&& cur
->n_value
< new->n_value
))
463 cur
->n_type
== N_FUN
&&
464 cur
->n_value
== new->n_value
)
469 cur
< (struct nlist
*)stab
->end
; cur
++) {
470 if (cur
->n_type
== N_SO
||
471 (stab
->sorted
&& cur
->n_value
> new->n_value
))
473 if (cur
->n_type
== N_FUN
&&
474 cur
->n_value
== new->n_value
) {
481 db_sym_print_completion(stab
, &new->n_un
.n_name
[new->n_other
- 1],
490 } else if (new == sp1
)
500 * search a (possibly incomplete) symbol with file, func and line qualification
503 aout_db_qualified_search(
512 register struct nlist
*sp
= (struct nlist
*)stab
->start
;
513 struct nlist
*ep
= (struct nlist
*)stab
->end
;
514 struct nlist
*fp
= 0;
515 struct nlist
*found_sp
;
516 unsigned long func_top
;
522 if (file
== 0 && sym
== 0)
525 if ((sp
= aout_db_search_name(sp
, ep
, file
, N_TEXT
, &fp
, 0)) == 0)
530 sp
= aout_db_search_name(sp
, ep
, sym
, (line
> 0)? N_FUN
: 0, &fp
,
531 (ret
== (db_sym_t
*)0));
537 if (strncmp(sp
->n_un
.n_name
, sym
, strlen(sym
)) == 0)
540 p
= &sp
->n_un
.n_name
[1];
542 if (*name
== (char *)0) {
546 for (i
= 0; i
< *len
; i
++)
547 if ((*name
)[i
] != p
[i
]) {
558 if (file
&& !aout_db_eq_name(fp
, file
, 0))
561 if (sp
->n_type
== N_FUN
) {
563 * qualfied by function name
564 * search backward because line number entries
565 * for the function are above it in this case.
567 func_top
= sp
->n_value
;
569 /* symbols with the same value may have been mixed up */
572 } while (sp
->n_value
== func_top
);
574 for (sp
--; sp
>= (struct nlist
*)stab
->start
; sp
--) {
575 if (sp
->n_type
!= N_SLINE
)
577 if (sp
->n_value
< func_top
)
579 if (sp
->n_desc
<= line
) {
580 if (found_sp
== 0 || found_sp
->n_desc
< sp
->n_desc
)
582 if (sp
->n_desc
== line
)
586 if (sp
->n_type
!= N_SLINE
|| sp
->n_value
< func_top
)
590 * qualified by only file name
591 * search forward in this case
595 /* symbols with the same value may have been mixed up */
596 func_top
= sp
->n_value
;
599 } while (sp
->n_value
== func_top
);
601 for (sp
++; sp
< ep
; sp
++) {
602 if (sp
->n_type
== N_TEXT
603 && aout_db_is_filename(sp
->n_un
.n_name
))
604 break; /* enter into another file */
605 if (sp
->n_type
== N_SOL
) {
606 in_file
= aout_db_eq_name(sp
, file
, 0);
609 if (!in_file
|| sp
->n_type
!= N_SLINE
)
611 if (sp
->n_desc
<= line
) {
612 if (found_sp
== 0 || found_sp
->n_desc
< sp
->n_desc
)
614 if (sp
->n_desc
== line
)
621 *ret
= (db_sym_t
) sp
;
626 * lookup symbol by name
633 return(db_sym_parse_and_lookup(aout_db_qualified_search
, stab
, symstr
));
637 * lookup (possibly incomplete) symbol by name
640 aout_db_lookup_incomplete(
647 return(db_sym_parse_and_lookup_incomplete(aout_db_qualified_search
,
648 stab
, symstr
, name
, len
, toadd
));
652 * Display possible completion for the symbol
655 aout_db_print_completion(stab
, symstr
)
660 return(db_sym_parse_and_print_completion(aout_db_qualified_print_completion
,
665 aout_db_search_symbol(
668 db_strategy_t strategy
,
669 db_expr_t
*diffp
) /* in/out */
671 db_expr_t diff
= *diffp
;
672 register struct nlist
*symp
= 0;
673 struct nlist
*sp
, *ep
, *cp
;
674 boolean_t first_pass
= FALSE
;
676 sp
= (struct nlist
*)symtab
->start
;
677 ep
= (struct nlist
*)symtab
->end
;
679 if (symtab
->sorted
) {
682 target
.n_value
= (vm_offset_t
)off
;
683 target
.n_un
.n_name
= (char *) 0;
684 target
.n_other
= (char) 0;
685 db_qsort_limit_search((char *)&target
, (char **)&sp
, (char **)&ep
,
686 sizeof(struct nlist
), aout_db_compare_symbols
);
691 for (cp
= ep
-1; cp
>= sp
; cp
--) {
692 if (cp
->n_un
.n_name
== 0)
694 if ((cp
->n_type
& N_STAB
) != 0)
696 if (strategy
== DB_STGY_XTRN
&& (cp
->n_type
& N_EXT
) == 0)
698 if (off
>= cp
->n_value
) {
699 if (off
- cp
->n_value
< diff
) {
700 diff
= off
- cp
->n_value
;
702 if (diff
== 0 && (cp
->n_type
& N_EXT
))
705 else if (off
- cp
->n_value
== diff
) {
708 else if ((symp
->n_type
& N_EXT
) == 0 &&
709 (cp
->n_type
& N_EXT
) != 0)
710 symp
= cp
; /* pick the external symbol */
717 sp
= (struct nlist
*) symtab
->start
;
725 return ((db_sym_t
)symp
);
729 * Return the name and value for a symbol.
732 aout_db_symbol_values(
737 register struct nlist
*sp
;
739 sp
= (struct nlist
*)sym
;
741 *namep
= sp
->n_un
.n_name
;
743 *valuep
= sp
->n_value
;
746 #define X_DB_MAX_DIFF 8 /* maximum allowable diff at the end of line */
747 extern unsigned int db_search_maxoff
; /* maximum acceptable offset */
750 * search symbol by value
753 aout_db_search_by_addr(
762 struct nlist
*sp
, *cp
;
763 register struct nlist
*line_sp
, *func_sp
, *file_sp
, *line_func
;
764 unsigned long func_diff
, line_diff
;
765 boolean_t found_line
= FALSE
;
766 struct nlist
*ep
= (struct nlist
*)stab
->end
;
767 boolean_t first_pass
= FALSE
;
771 * Added init of these two... not sure if it's correct, but
772 * can't be worse than random values.... -- jfriedl@omron.co.jp
774 func_diff
= line_diff
= /*HUGE*/0x0fffffff;
776 line_sp
= func_sp
= file_sp
= line_func
= 0;
781 sp
= (struct nlist
*)stab
->start
;
785 target
.n_value
= (vm_offset_t
)addr
;
786 target
.n_un
.n_name
= (char *) 0;
787 target
.n_other
= (char) 0;
788 db_qsort_limit_search((char *)&target
, (char **)&sp
,
789 (char **)&ep
, sizeof(struct nlist
),
790 aout_db_compare_symbols
);
794 for (cp
= sp
; cp
< ep
; cp
++) {
797 if (cp
->n_value
<= addr
) {
798 if (line_sp
== 0 || line_diff
>= addr
- cp
->n_value
) {
802 line_diff
= (unsigned long)(addr
- cp
->n_value
);
805 if (cp
->n_value
>= addr
&& line_sp
)
809 if ((found_line
|| (line_sp
&& line_diff
< X_DB_MAX_DIFF
))
814 if (cp
->n_value
> addr
)
816 if (file_sp
== 0 || file_sp
->n_value
<= cp
->n_value
)
820 if (aout_db_is_filename(cp
->n_un
.n_name
)) {
821 if (cp
->n_value
> addr
)
823 if (file_sp
== 0 || file_sp
->n_value
<= cp
->n_value
)
825 } else if (cp
->n_value
<= addr
&&
826 (func_sp
== 0 || func_diff
> addr
- cp
->n_value
)) {
828 func_diff
= (unsigned long)(addr
- cp
->n_value
);
832 if (cp
->n_value
<= addr
&&
833 (func_sp
== 0 || func_diff
>= addr
- cp
->n_value
)) {
835 func_diff
= (unsigned long)(addr
- cp
->n_value
);
836 if (func_diff
== 0 && file_sp
&& func_sp
&& line_sp
== 0)
841 if ((cp
->n_value
> addr
) &&
842 (cp
->n_value
- addr
> db_search_maxoff
))
849 if (first_pass
&& (!file_sp
|| !line_sp
|| !func_sp
)) {
852 sp
= (struct nlist
*)stab
->start
;
853 for (; cp
>= sp
; cp
--) {
860 if ((found_line
|| (line_sp
&& line_diff
< X_DB_MAX_DIFF
))
869 if (aout_db_is_filename(cp
->n_un
.n_name
)) {
872 } else if (func_sp
== 0) {
874 func_diff
= (unsigned long)(addr
- cp
->n_value
);
880 func_diff
= (unsigned long)(addr
- cp
->n_value
);
881 if (func_diff
== 0 && file_sp
&& func_sp
886 if (line_sp
&& file_sp
&&
887 addr
- cp
->n_value
> db_search_maxoff
)
896 * XXX - barbou@gr.osf.org
897 * I don't know if that code is useful to something, but it makes the -gline
898 * option of gcc useless.
901 if (line_func
== 0 || func_sp
== 0
902 || line_func
->n_value
!= func_sp
->n_value
)
906 if (line_sp
&& !found_line
) {
912 *diff
= addr
- file_sp
->n_value
;
913 *file
= file_sp
->n_un
.n_name
;
916 *diff
= addr
- line_sp
->n_value
;
917 *line
= line_sp
->n_desc
;
920 *diff
= addr
- func_sp
->n_value
;
921 *func
= (func_sp
->n_un
.n_name
[0] == '_')?
922 func_sp
->n_un
.n_name
+ 1: func_sp
->n_un
.n_name
;
923 if (line_func
&& (line_func
->n_desc
& 0x4000))
924 *args
= line_func
->n_desc
& 0x3ff;
926 return((db_sym_t
) func_sp
);
930 * Find filename and lineno within, given the current pc.
935 __unused db_sym_t sym
,
945 found
= (aout_db_search_by_addr(stab
, (unsigned)pc
, file
, &func
, line
,
948 return(found
&& func
&& *file
);
952 * Initialization routine for a.out files.
957 aout_db_sym_init((char *) &_mh_execute_header
,
958 (char *)0, "mach", (char *)0);
961 #endif /* DB_NO_AOUT */