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