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