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