]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/db_gcc_aout.c
xnu-1228.tar.gz
[apple/xnu.git] / osfmk / i386 / db_gcc_aout.c
1 /*
2 * Copyright (c) 2000 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 * COPYRIGHT NOTICE
30 *
31 * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
32 *
33 * Permission is hereby granted to use, copy, modify and freely distribute
34 * the software in this file and its documentation for any purpose without
35 * fee, provided that the above copyright notice appears in all copies and
36 * that both the copyright notice and this permission notice appear in
37 * supporting documentation. Further, provided that the name of Open
38 * Software Foundation, Inc. ("OSF") not be used in advertising or
39 * publicity pertaining to distribution of the software without prior
40 * written permission from OSF. OSF makes no representations about the
41 * suitability of this software for any purpose. It is provided "as is"
42 * without express or implied warranty.
43 */
44 /*
45 * HISTORY
46 *
47 * Revision 1.1.1.1 1998/09/22 21:05:36 wsanchez
48 * Import of Mac OS X kernel (~semeria)
49 *
50 * Revision 1.1.1.1 1998/03/07 02:25:37 wsanchez
51 * Import of OSF Mach kernel (~mburg)
52 *
53 * Revision 1.2.2.3 1994/01/28 17:23:00 chasb
54 * Expand Copyrights
55 * [1994/01/27 19:40:16 chasb]
56 *
57 * Revision 1.2.2.2 1993/06/09 02:27:36 gm
58 * Added to OSF/1 R1.3 from NMK15.0.
59 * [1993/06/02 21:04:03 jeffc]
60 *
61 * Revision 1.2 1993/04/19 16:13:10 devrcs
62 * pick up file_io.h from bootstrap directory
63 * [1993/02/27 15:01:09 david]
64 *
65 * Added new arguments and a missing one to db_add_symbol_table
66 * [barbou@gr.osf.org]
67 * [92/12/03 bernadat]
68 *
69 * Added gcc symbol table handling based on db_aout.c (Revsion 2.4)
70 * [91/07/31 tak]
71 *
72 * Revision 1.1 1992/09/30 02:02:23 robert
73 * Initial revision
74 *
75 * $EndLog$
76 */
77 /* CMU_HIST */
78 /*
79 * Revision 2.1 91/07/31 13:13:51 jeffreyh
80 * Created.
81 *
82 * 31-Jul-91 Jeffrey Heller (tak) at Open Software Foundation
83 * Added gcc symbol table handling based on db_aout.c (Revsion 2.4)
84 *
85 */
86 /* CMU_ENDHIST */
87 /*
88 * Mach Operating System
89 * Copyright (c) 1991,1990 Carnegie Mellon University
90 * All Rights Reserved.
91 *
92 * Permission to use, copy, modify and distribute this software and its
93 * documentation is hereby granted, provided that both the copyright
94 * notice and this permission notice appear in all copies of the
95 * software, derivative works or modified versions, and any portions
96 * thereof, and that both notices appear in supporting documentation.
97 *
98 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
99 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
100 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
101 *
102 * Carnegie Mellon requests users of this software to return to
103 *
104 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
105 * School of Computer Science
106 * Carnegie Mellon University
107 * Pittsburgh PA 15213-3890
108 *
109 * any improvements or extensions that they make and grant Carnegie Mellon
110 * the rights to redistribute these changes.
111 */
112 /*
113 */
114 /*
115 * Symbol table routines for a.out format files.
116 */
117
118 #include <mach/boolean.h>
119 #include <machine/db_machdep.h> /* data types */
120 #include <ddb/db_sym.h>
121
122 #ifdef DB_GCC_AOUT
123
124 #include <ddb/nlist.h> /* a.out symbol table */
125 #include <i386/stab.h>
126
127 /*
128 * An a.out symbol table as loaded into the kernel debugger:
129 *
130 * symtab -> size of symbol entries, in bytes
131 * sp -> first symbol entry
132 * ...
133 * ep -> last symbol entry + 1
134 * strtab == start of string table
135 * size of string table in bytes,
136 * including this word
137 * -> strings
138 */
139
140 /*
141 * Find pointers to the start and end of the symbol entries,
142 * given a pointer to the start of the symbol table.
143 */
144 #define db_get_aout_symtab(symtab, sp, ep) \
145 (sp = (struct nlist *)((symtab) + 1), \
146 ep = (struct nlist *)((char *)sp + *(symtab)))
147
148 X_db_sym_init(symtab, esymtab, name)
149 int * symtab; /* pointer to start of symbol table */
150 char * esymtab; /* pointer to end of string table,
151 for checking - rounded up to integer
152 boundary */
153 char * name;
154 {
155 register struct nlist *sym_start, *sym_end;
156 register struct nlist *sp;
157 register char * strtab;
158 register int strlen;
159
160 db_get_aout_symtab(symtab, sym_start, sym_end);
161
162 strtab = (char *)sym_end;
163 strlen = *(int *)strtab;
164
165 if (strtab + ((strlen + sizeof(int) - 1) & ~(sizeof(int)-1))
166 != esymtab)
167 {
168 db_printf("[ %s symbol table not valid ]\n", name);
169 return;
170 }
171
172 db_printf("[ preserving %#x bytes of %s symbol table ]\n",
173 esymtab - (char *)symtab, name);
174
175 for (sp = sym_start; sp < sym_end; sp++) {
176 register int strx;
177 strx = sp->n_un.n_strx;
178 if (strx != 0) {
179 if (strx > strlen) {
180 db_printf("Bad string table index (%#x)\n", strx);
181 sp->n_un.n_name = 0;
182 continue;
183 }
184 sp->n_un.n_name = strtab + strx;
185 }
186 }
187
188 db_add_symbol_table(sym_start, sym_end, name, (char *)symtab,
189 0, 0, 0, FALSE);
190 }
191
192 /*
193 * check file name or not (check xxxx.x pattern)
194 */
195 boolean_t
196 X_db_is_filename(name)
197 register char *name;
198 {
199 while (*name) {
200 if (*name == '.') {
201 if (name[1])
202 return(TRUE);
203 }
204 name++;
205 }
206 return(FALSE);
207 }
208
209 /*
210 * special name comparison routine with a name in the symbol table entry
211 */
212 boolean_t
213 X_db_eq_name(sp, name)
214 struct nlist *sp;
215 char *name;
216 {
217 register char *s1, *s2;
218
219 s1 = sp->n_un.n_name;
220 s2 = name;
221 if (*s1 == '_' && *s2 && *s2 != '_')
222 s1++;
223 while (*s2) {
224 if (*s1++ != *s2++) {
225 /*
226 * check .c .o file name comparison case
227 */
228 if (*s2 == 0 && sp->n_un.n_name <= s1 - 2
229 && s1[-2] == '.' && s1[-1] == 'o')
230 return(TRUE);
231 return(FALSE);
232 }
233 }
234 /*
235 * do special check for
236 * xxx:yyy for N_FUN
237 * xxx.ttt for N_DATA and N_BSS
238 */
239 return(*s1 == 0 || (*s1 == ':' && sp->n_type == N_FUN) ||
240 (*s1 == '.' && (sp->n_type == N_DATA || sp->n_type == N_BSS)));
241 }
242
243 /*
244 * search a symbol table with name and type
245 * fp(in,out): last found text file name symbol entry
246 */
247 struct nlist *
248 X_db_search_name(sp, ep, name, type, fp)
249 register struct nlist *sp;
250 struct nlist *ep;
251 char *name;
252 int type;
253 struct nlist **fp;
254 {
255 struct nlist *file_sp = *fp;
256 struct nlist *found_sp = 0;
257
258 for ( ; sp < ep; sp++) {
259 if (sp->n_type == N_TEXT && X_db_is_filename(sp->n_un.n_name))
260 *fp = sp;
261 if (type) {
262 if (sp->n_type == type) {
263 if (X_db_eq_name(sp, name))
264 return(sp);
265 }
266 if (sp->n_type == N_SO)
267 *fp = sp;
268 continue;
269 }
270 if (sp->n_type & N_STAB)
271 continue;
272 if (sp->n_un.n_name && X_db_eq_name(sp, name)) {
273 /*
274 * In case of qaulified search by a file,
275 * return it immediately with some check.
276 * Otherwise, search external one
277 */
278 if (file_sp) {
279 if ((file_sp == *fp) || (sp->n_type & N_EXT))
280 return(sp);
281 } else if (sp->n_type & N_EXT)
282 return(sp);
283 else
284 found_sp = sp;
285 }
286 }
287 return(found_sp);
288 }
289
290 /*
291 * search a symbol with file, func and line qualification
292 */
293 struct nlist *
294 X_db_qualified_search(stab, file, sym, line)
295 db_symtab_t *stab;
296 char *file;
297 char *sym;
298 int line;
299 {
300 register struct nlist *sp = (struct nlist *)stab->start;
301 struct nlist *ep = (struct nlist *)stab->end;
302 struct nlist *fp = 0;
303 struct nlist *found_sp;
304 unsigned func_top;
305 boolean_t in_file;
306
307 if (file == 0 && sym == 0)
308 return(0);
309 if (file) {
310 if ((sp = X_db_search_name(sp, ep, file, N_TEXT, &fp)) == 0)
311 return(0);
312 }
313 if (sym) {
314 sp = X_db_search_name(sp, ep, sym, (line > 0)? N_FUN: 0, &fp);
315 if (sp == 0)
316 return(0);
317 }
318 if (line > 0) {
319 if (file && !X_db_eq_name(fp, file))
320 return(0);
321 found_sp = 0;
322 if (sp->n_type == N_FUN) {
323 /*
324 * qualfied by function name
325 * search backward because line number entries
326 * for the function are above it in this case.
327 */
328 func_top = sp->n_value;
329 for (sp--; sp >= (struct nlist *)stab->start; sp--) {
330 if (sp->n_type != N_SLINE)
331 continue;
332 if (sp->n_value < func_top)
333 break;
334 if (sp->n_desc <= line) {
335 if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
336 found_sp = sp;
337 if (sp->n_desc == line)
338 break;
339 }
340 }
341 if (sp->n_type != N_SLINE || sp->n_value < func_top)
342 return(0);
343 } else {
344 /*
345 * qualified by only file name
346 * search forward in this case
347 */
348 in_file = TRUE;
349 for (sp++; sp < ep; sp++) {
350 if (sp->n_type == N_TEXT
351 && X_db_is_filename(sp->n_un.n_name))
352 break; /* enter into another file */
353 if (sp->n_type == N_SOL) {
354 in_file = X_db_eq_name(sp, file);
355 continue;
356 }
357 if (!in_file || sp->n_type != N_SLINE)
358 continue;
359 if (sp->n_desc <= line) {
360 if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
361 found_sp = sp;
362 if (sp->n_desc == line)
363 break;
364 }
365 }
366 }
367 sp = found_sp;
368 }
369 return(sp);
370 }
371
372 /*
373 * lookup symbol by name
374 */
375 db_sym_t
376 X_db_lookup(stab, symstr)
377 db_symtab_t *stab;
378 char * symstr;
379 {
380 register char *p;
381 register n;
382 int n_name;
383 int line_number;
384 char *file_name = 0;
385 char *sym_name = 0;
386 char *component[3];
387 struct nlist *found = 0;
388
389 /*
390 * disassemble component: [file_name:]symbol[:line_nubmer]
391 */
392 component[0] = symstr;
393 component[1] = component[2] = 0;
394 for (p = symstr, n = 1; *p; p++) {
395 if (*p == ':') {
396 if (n >= 3)
397 break;
398 *p = 0;
399 component[n++] = p+1;
400 }
401 }
402 if (*p != 0)
403 goto out;
404 line_number = 0;
405 n_name = n;
406 p = component[n-1];
407 if (*p >= '0' && *p <= '9') {
408 if (n == 1)
409 goto out;
410 for (line_number = 0; *p; p++) {
411 if (*p < '0' || *p > '9')
412 goto out;
413 line_number = line_number*10 + *p - '0';
414 }
415 n_name--;
416 } else if (n >= 3)
417 goto out;
418 if (n_name == 1) {
419 if (X_db_is_filename(component[0])) {
420 file_name = component[0];
421 sym_name = 0;
422 } else {
423 file_name = 0;
424 sym_name = component[0];
425 }
426 } else {
427 file_name = component[0];
428 sym_name = component[1];
429 }
430 found = X_db_qualified_search(stab, file_name, sym_name, line_number);
431
432 out:
433 while (--n > 1)
434 component[n][-1] = ':';
435 return((db_sym_t) found);
436 }
437
438 db_sym_t
439 X_db_search_symbol(symtab, off, strategy, diffp)
440 db_symtab_t * symtab;
441 register
442 db_addr_t off;
443 db_strategy_t strategy;
444 db_expr_t *diffp; /* in/out */
445 {
446 register unsigned int diff = *diffp;
447 register struct nlist *symp = 0;
448 register struct nlist *sp, *ep;
449
450 sp = (struct nlist *)symtab->start;
451 ep = (struct nlist *)symtab->end;
452
453 for (; sp < ep; sp++) {
454 if (sp->n_un.n_name == 0)
455 continue;
456 if ((sp->n_type & N_STAB) != 0)
457 continue;
458 if (off >= sp->n_value) {
459 if (off - sp->n_value < diff) {
460 diff = off - sp->n_value;
461 symp = sp;
462 if (diff == 0 && (sp->n_type & N_EXT))
463 break;
464 }
465 else if (off - sp->n_value == diff) {
466 if (symp == 0)
467 symp = sp;
468 else if ((symp->n_type & N_EXT) == 0 &&
469 (sp->n_type & N_EXT) != 0)
470 symp = sp; /* pick the external symbol */
471 }
472 }
473 }
474 if (symp == 0) {
475 *diffp = off;
476 }
477 else {
478 *diffp = diff;
479 }
480 return ((db_sym_t)symp);
481 }
482
483 /*
484 * Return the name and value for a symbol.
485 */
486 void
487 X_db_symbol_values(sym, namep, valuep)
488 db_sym_t sym;
489 char **namep;
490 db_expr_t *valuep;
491 {
492 register struct nlist *sp;
493
494 sp = (struct nlist *)sym;
495 if (namep)
496 *namep = sp->n_un.n_name;
497 if (valuep)
498 *valuep = sp->n_value;
499 }
500
501 #define X_DB_MAX_DIFF 8 /* maximum allowable diff at the end of line */
502
503 /*
504 * search symbol by value
505 */
506 X_db_search_by_addr(stab, addr, file, func, line, diff)
507 db_symtab_t *stab;
508 register unsigned addr;
509 char **file;
510 char **func;
511 int *line;
512 unsigned *diff;
513 {
514 register struct nlist *sp;
515 register struct nlist *line_sp, *func_sp, *file_sp, *line_func;
516 register func_diff, line_diff;
517 boolean_t found_line = FALSE;
518 struct nlist *ep = (struct nlist *)stab->end;
519
520 line_sp = func_sp = file_sp = line_func = 0;
521 *file = *func = 0;
522 *line = 0;
523 for (sp = (struct nlist *)stab->start; sp < ep; sp++) {
524 switch(sp->n_type) {
525 case N_SLINE:
526 if (sp->n_value <= addr) {
527 if (line_sp == 0 || line_diff >= addr - sp->n_value) {
528 if (line_func)
529 line_func = 0;
530 line_sp = sp;
531 line_diff = addr - sp->n_value;
532 }
533 }
534 if (sp->n_value >= addr && line_sp)
535 found_line = TRUE;
536 continue;
537 case N_FUN:
538 if ((found_line || (line_sp && line_diff < X_DB_MAX_DIFF))
539 && line_func == 0)
540 line_func = sp;
541 continue;
542 case N_TEXT:
543 if (X_db_is_filename(sp->n_un.n_name)) {
544 if (sp->n_value > addr)
545 continue;
546 if (file_sp == 0 || file_sp->n_value < sp->n_value)
547 file_sp = sp;
548 } else if (sp->n_value <= addr &&
549 (func_sp == 0 || func_diff > addr - sp->n_value)) {
550 func_sp = sp;
551 func_diff = addr - sp->n_value;
552 }
553 continue;
554 case N_TEXT|N_EXT:
555 if (sp->n_value <= addr &&
556 (func_sp == 0 || func_diff >= addr - sp->n_value)) {
557 func_sp = sp;
558 func_diff = addr - sp->n_value;
559 if (func_diff == 0 && file_sp && func_sp)
560 break;
561 }
562 default:
563 continue;
564 }
565 break;
566 }
567 if (line_sp) {
568 if (line_func == 0 || func_sp == 0
569 || line_func->n_value != func_sp->n_value)
570 line_sp = 0;
571 }
572 if (file_sp) {
573 *diff = addr - file_sp->n_value;
574 *file = file_sp->n_un.n_name;
575 }
576 if (func_sp) {
577 *diff = addr - func_sp->n_value;
578 *func = (func_sp->n_un.n_name[0] == '_')?
579 func_sp->n_un.n_name + 1: func_sp->n_un.n_name;
580 }
581 if (line_sp) {
582 *diff = addr - line_sp->n_value;
583 *line = line_sp->n_desc;
584 }
585 return(file_sp || func_sp || line_sp);
586 }
587
588 /* ARGSUSED */
589 boolean_t
590 X_db_line_at_pc(stab, sym, file, line, pc)
591 db_symtab_t *stab;
592 db_sym_t sym;
593 char **file;
594 int *line;
595 db_expr_t pc;
596 {
597 char *func;
598 unsigned diff;
599 boolean_t found;
600
601 found = X_db_search_by_addr(stab,(unsigned)pc,file,&func,line,&diff);
602 return(found && func && *file);
603 }
604
605 /*
606 * Initialization routine for a.out files.
607 */
608 kdb_init()
609 {
610 extern char *esym;
611 extern int end;
612
613 if (esym > (char *)&end) {
614 X_db_sym_init((int *)&end, esym, "mach");
615 }
616 }
617
618 /*
619 * Read symbol table from file.
620 * (should be somewhere else)
621 */
622 #include <bootstrap/file_io.h>
623 #include <vm/vm_kern.h>
624
625 read_symtab_from_file(fp, symtab_name)
626 struct file *fp;
627 char * symtab_name;
628 {
629 vm_size_t resid;
630 kern_return_t result;
631 vm_offset_t symoff;
632 vm_size_t symsize;
633 vm_offset_t stroff;
634 vm_size_t strsize;
635 vm_size_t table_size;
636 vm_offset_t symtab;
637
638 if (!get_symtab(fp, &symoff, &symsize)) {
639 boot_printf("[ error %d reading %s file header ]\n",
640 result, symtab_name);
641 return;
642 }
643
644 stroff = symoff + symsize;
645 result = read_file(fp, (vm_offset_t)stroff,
646 (vm_offset_t)&strsize, sizeof(strsize), &resid);
647 if (result || resid) {
648 boot_printf("[ no valid symbol table present for %s ]\n",
649 symtab_name);
650 return;
651 }
652
653 table_size = sizeof(int) + symsize + strsize;
654 table_size = (table_size + sizeof(int)-1) & ~(sizeof(int)-1);
655
656 result = kmem_alloc_wired(kernel_map, &symtab, table_size);
657 if (result) {
658 boot_printf("[ error %d allocating space for %s symbol table ]\n",
659 result, symtab_name);
660 return;
661 }
662
663 *(int *)symtab = symsize;
664
665 result = read_file(fp, symoff,
666 symtab + sizeof(int), symsize, &resid);
667 if (result || resid) {
668 boot_printf("[ error %d reading %s symbol table ]\n",
669 result, symtab_name);
670 return;
671 }
672
673 result = read_file(fp, stroff,
674 symtab + sizeof(int) + symsize, strsize, &resid);
675 if (result || resid) {
676 boot_printf("[ error %d reading %s string table ]\n",
677 result, symtab_name);
678 return;
679 }
680
681 X_db_sym_init((int *)symtab,
682 (char *)(symtab + table_size),
683 symtab_name);
684
685 }
686
687 #endif /* DB_GCC_AOUT */