]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_aout.c
7c02d170cd297cad5c8c54936c751b76a23bae38
[apple/xnu.git] / osfmk / ddb / db_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 * @OSF_COPYRIGHT@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
32 *
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
38 *
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53 /*
54 */
55 /*
56 * Author: David B. Golub, Carnegie Mellon University
57 * Date: 7/90
58 */
59 /*
60 * Symbol table routines for a.out format files.
61 */
62 #include <mach/boolean.h>
63 #include <mach/std_types.h>
64 #include <machine/db_machdep.h> /* data types */
65 #include <string.h> /* For strcpy(), strcmp() */
66 #include <ddb/db_aout.h>
67 #include <ddb/db_output.h> /* For db_printf() */
68 #include <ddb/db_sym.h>
69
70 #ifndef DB_NO_AOUT
71
72 #include <ddb/nlist.h> /* a.out symbol table */
73 #include <ddb/stab.h>
74
75 #define private static
76
77 private int aout_db_order_symbols(char *, char *);
78 private int aout_db_compare_symbols(char *, char *);
79 private boolean_t aout_db_is_filename(char *);
80 private boolean_t aout_db_eq_name(struct nlist *, char *, int);
81
82 /*
83 * An a.out symbol table as loaded into the kernel debugger:
84 *
85 * symtab -> size of symbol entries, in bytes
86 * sp -> first symbol entry
87 * ...
88 * ep -> last symbol entry + 1
89 * strtab == start of string table
90 * size of string table in bytes,
91 * including this word
92 * -> strings
93 */
94
95 /*
96 * Find pointers to the start and end of the symbol entries,
97 * given a pointer to the start of the symbol table.
98 */
99 #define db_get_aout_symtab(symtab, sp, ep) \
100 (sp = (struct nlist *)(((vm_offset_t *)(symtab)) + 1), \
101 ep = (struct nlist *)((char *)sp + *((int *)(symtab))))
102
103 char *db_sorting_sym_end;
104
105 private int
106 aout_db_order_symbols(
107 char *s1,
108 char *s2)
109 {
110 struct nlist *sym1 = (struct nlist *) s1;
111 struct nlist *sym2 = (struct nlist *) s2;
112
113 if (sym1->n_value != sym2->n_value)
114 return (sym1->n_value - sym2->n_value);
115 else {
116 return (sym1->n_un.n_name - sym2->n_un.n_name);
117 }
118 }
119
120 private int
121 aout_db_compare_symbols(
122 char *sym1,
123 char *sym2)
124 {
125 return (((struct nlist *) sym1)->n_value -
126 ((struct nlist *) sym2)->n_value);
127 }
128
129 int db_sorting_limit = 50000;
130
131 boolean_t
132 aout_db_sym_init(
133 char * symtab, /* pointer to start of symbol table */
134 char * esymtab, /* pointer to end of string table,
135 for checking - may be rounded up to
136 integer boundary */
137 char * name,
138 char * task_addr) /* use for this task only */
139 {
140 struct nlist *sym_start, *sym_end, *dbsym_start, *dbsym_end;
141 struct nlist *sp;
142 char *strtab, *dbstrtab;
143 int strlen;
144 char *estrtab, *dbestrtab;
145 unsigned long minsym = ~0;
146 unsigned long maxsym = 0;
147 boolean_t sorted;
148 boolean_t sorting;
149 extern boolean_t getsymtab(char *,
150 vm_offset_t *, int *,
151 vm_offset_t *, vm_size_t *);
152 int nsyms;
153
154
155 if (!getsymtab(symtab,
156 (vm_offset_t *)&sym_start, &nsyms,
157 (vm_offset_t *)&strtab, (vm_size_t *)&strlen)) {
158 return(FALSE);
159 }
160 sym_end = sym_start + nsyms;
161 estrtab = strtab + strlen;
162
163 /*
164 * We haven't actually started up VM yet, so we can just steal some pages to
165 * make a working copy of the symbols and strings
166 */
167
168 dbsym_start = (struct nlist *)pmap_steal_memory(((unsigned int)sym_end - (unsigned int)sym_start + 4096) & -4096); /* Get space for symbols */
169 dbstrtab = (char *)pmap_steal_memory(((unsigned int)estrtab - (unsigned int)strtab + 4096) & -4096); /* Get space for strings */
170
171 bcopy((char *)sym_start, (char *)dbsym_start, (unsigned int)sym_end - (unsigned int)sym_start); /* Copy symbols */
172 bcopy(strtab, dbstrtab, (unsigned int)estrtab - (unsigned int)strtab); /* Copy strings */
173
174 dbsym_end = dbsym_start + nsyms;
175 dbestrtab = dbstrtab + strlen;
176
177 sorting = ((dbsym_end - dbsym_start) < db_sorting_limit);
178
179 for (sp = dbsym_start; sp < dbsym_end; sp++) {
180 register long strx;
181 strx = sp->n_un.n_strx;
182 if (strx != 0) {
183 if (strx > strlen) {
184 sp->n_un.n_name = 0;
185 continue;
186 }
187 sp->n_un.n_name = dbstrtab + strx;
188 }
189 if (sp->n_type != N_ABS) {
190 if (sp->n_value > 0 && sp->n_value < minsym)
191 minsym = sp->n_value;
192 if (sp->n_value > maxsym)
193 maxsym = sp->n_value;
194 }
195 }
196
197 if (maxsym < minsym)
198 minsym = maxsym = 0;
199
200 if (sorting) {
201 db_qsort((char *) dbsym_start, dbsym_end - dbsym_start,
202 sizeof (struct nlist), aout_db_order_symbols);
203 sorted = TRUE;
204 } else
205 sorted = FALSE;
206
207 if (db_add_symbol_table(SYMTAB_AOUT,
208 (char*)dbsym_start,
209 (char*)dbsym_end,
210 name,
211 0,
212 task_addr,
213 minsym,
214 maxsym,
215 sorted))
216 {
217 /* Successfully added symbol table */
218
219 pmap_protect(kernel_pmap,
220 (vm_offset_t) dbsym_start, (vm_offset_t) dbsym_end,
221 VM_PROT_READ|VM_PROT_WRITE);
222 pmap_protect(kernel_pmap,
223 (vm_offset_t) dbstrtab, (vm_offset_t) dbestrtab,
224 VM_PROT_READ|VM_PROT_WRITE);
225 return TRUE;
226 }
227 return FALSE;
228 }
229
230 /*
231 * This KLUDGE offsets the n_values of a copied symbol table
232 */
233 void db_clone_offsetXXX(char *, long);
234 void
235 db_clone_offsetXXX(char * symtab, long offset)
236 {
237 register struct nlist *sym_start, *sym_end, *sp;
238
239 db_get_aout_symtab((int *)symtab, sym_start, sym_end);
240
241 for (sp = sym_start; sp < sym_end; sp++)
242 if (sp->n_type != N_ABS)
243 sp->n_value += offset;
244 }
245 /* end KLUDGE */
246
247 /*
248 * check file name or not (check xxxx.x pattern)
249 */
250 private boolean_t
251 aout_db_is_filename(char *name)
252 {
253 while (*name) {
254 if (*name == '.') {
255 if (name[1])
256 return(TRUE);
257 }
258 name++;
259 }
260 return(FALSE);
261 }
262
263 /*
264 * special name comparison routine with a name in the symbol table entry
265 */
266 private boolean_t
267 aout_db_eq_name(
268 struct nlist *sp,
269 char *name,
270 int incomplete)
271 {
272 register char *s1, *s2;
273
274 s1 = sp->n_un.n_name;
275 s2 = name;
276 #ifndef __NO_UNDERSCORES__
277 if (*s1 == '_' && *s2 && *s2 != '_')
278 s1++;
279 #endif /* __NO_UNDERSCORES__ */
280 while (*s2) {
281 if (*s1++ != *s2++) {
282 /*
283 * check .c .o file name comparison case
284 */
285 if (*s2 == 0 && sp->n_un.n_name <= s1 - 2
286 && s1[-2] == '.' && s1[-1] == 'o')
287 return(TRUE);
288 return(FALSE);
289 }
290 }
291 if (incomplete)
292 return(TRUE);
293 /*
294 * do special check for
295 * xxx:yyy for N_FUN
296 * xxx.ttt for N_DATA and N_BSS
297 */
298 return(*s1 == 0 || (*s1 == ':' && sp->n_type == N_FUN) ||
299 (*s1 == '.' && (sp->n_type == N_DATA || sp->n_type == N_BSS)));
300 }
301
302 /*
303 * search a symbol table with name and type
304 * fp(in,out): last found text file name symbol entry
305 */
306 private struct nlist *
307 aout_db_search_name(
308 struct nlist *sp,
309 struct nlist *ep,
310 char *name,
311 int type,
312 struct nlist **fp,
313 int incomplete)
314 {
315 struct nlist *file_sp = *fp;
316 struct nlist *found_sp = 0;
317
318 for ( ; sp < ep; sp++) {
319 if (sp->n_other)
320 sp->n_other = 0;
321 if (sp->n_type == N_TEXT && aout_db_is_filename(sp->n_un.n_name))
322 *fp = sp;
323 if (type) {
324 if (sp->n_type == type) {
325 /* dwm_debug: b26 name, mk6 added last param */
326 if (aout_db_eq_name(sp, name, 0))
327 return(sp);
328 }
329 if (sp->n_type == N_SO)
330 *fp = sp;
331 continue;
332 }
333 if (sp->n_type & N_STAB)
334 continue;
335 if (sp->n_un.n_name && aout_db_eq_name(sp, name, incomplete)) {
336 /*
337 * In case of qaulified search by a file,
338 * return it immediately with some check.
339 * Otherwise, search external one
340 */
341 if (file_sp) {
342 if ((file_sp == *fp) || (sp->n_type & N_EXT))
343 return(sp);
344 } else if ((sp->n_type & N_EXT) ||
345 (incomplete && !aout_db_is_filename(sp->n_un.n_name)))
346 return(sp);
347 else
348 found_sp = sp;
349 }
350 }
351 return(found_sp);
352 }
353
354 /*
355 * Print sorted possible completions for a symbol.
356 * Use n_other field to mark completion symbols in order
357 * to speed up sort.
358 */
359 int
360 aout_db_qualified_print_completion(
361 db_symtab_t *stab,
362 char *sym)
363 {
364 struct nlist *sp;
365 struct nlist *sp1;
366 struct nlist *ep;
367 struct nlist *ep1;
368 struct nlist *fp = 0;
369 int symlen;
370 int nsym = 0;
371 struct nlist *cur;
372 struct nlist *new;
373 char *fname;
374 int func;
375 int line;
376
377 sp = aout_db_search_name((struct nlist *)stab->start,
378 (struct nlist *)stab->end,
379 sym, 0, &fp, 1);
380 if (sp == (struct nlist *)0)
381 return 0;
382
383 symlen = strlen(sym);
384 cur = sp;
385 while (cur) {
386 if (strncmp(cur->n_un.n_name, sym, symlen) == 0)
387 cur->n_other = 1;
388 else
389 cur->n_other = 2;
390 ep = cur;
391 cur = aout_db_search_name(cur + 1, (struct nlist *)stab->end,
392 sym, 0, &fp, 1);
393 }
394
395 sp1 = sp;
396 for (;;) {
397 new = cur = sp;
398 while (++cur <= ep)
399 if (cur->n_other) {
400 if (sp1 == sp)
401 sp1 = cur;
402 if (strcmp(&cur->n_un.n_name[cur->n_other - 1],
403 &new->n_un.n_name[new->n_other - 1]) < 0)
404 new = cur;
405 else
406 ep1 = cur;
407 }
408
409 func = line = 0;
410 if ((new->n_type & N_EXT) == 0) {
411 for (cur = new - 1; cur > (struct nlist *)stab->start; cur--) {
412 if (cur->n_type == N_SO ||
413 (stab->sorted && cur->n_value < new->n_value))
414 break;
415 if (line == 0 &&
416 cur->n_type == N_SLINE &&
417 cur->n_value == new->n_value)
418 line = cur->n_desc;
419 if (func == 0 &&
420 cur->n_type == N_FUN &&
421 cur->n_value == new->n_value)
422 func = 1;
423 }
424
425 if (cur->n_type == N_SO)
426 fname = cur->n_un.n_name;
427 else
428 fname = (char *)0;
429
430 if (line == 0 || func == 0)
431 for (cur = new + 1;
432 cur < (struct nlist *)stab->end; cur++) {
433 if (cur->n_type == N_SO ||
434 (stab->sorted && cur->n_value > new->n_value))
435 break;
436 if (line == 0 &&
437 cur->n_type == N_SLINE &&
438 cur->n_value == new->n_value) {
439 line = cur->n_desc;
440 if (func)
441 break;
442 }
443 if (func == 0 &&
444 cur->n_type == N_FUN &&
445 cur->n_value == new->n_value) {
446 func = 1;
447 if (line)
448 break;
449 }
450 }
451 } else {
452 fname = (char *)0;
453 for (cur = new - 1; cur > (struct nlist *)stab->start; cur--) {
454 if (cur->n_type == N_SO ||
455 (stab->sorted && cur->n_value < new->n_value))
456 break;
457 if (func == 0 &&
458 cur->n_type == N_FUN &&
459 cur->n_value == new->n_value)
460 func = 1;
461 }
462 if (func == 0)
463 for (cur = new + 1;
464 cur < (struct nlist *)stab->end; cur++) {
465 if (cur->n_type == N_SO ||
466 (stab->sorted && cur->n_value > new->n_value))
467 break;
468 if (cur->n_type == N_FUN &&
469 cur->n_value == new->n_value) {
470 func = 1;
471 break;
472 }
473 }
474 }
475
476 db_sym_print_completion(stab, &new->n_un.n_name[new->n_other - 1],
477 func, fname, line);
478 nsym++;
479 new->n_other = 0;
480
481 if (new == sp) {
482 if (sp1 == sp)
483 break;
484 sp = sp1;
485 } else if (new == sp1)
486 sp1 = sp;
487
488 if (new == ep)
489 ep = ep1;
490 }
491 return nsym;
492 }
493
494 /*
495 * search a (possibly incomplete) symbol with file, func and line qualification
496 */
497 private int
498 aout_db_qualified_search(
499 db_symtab_t *stab,
500 char *file,
501 char *sym,
502 int line,
503 db_sym_t *ret,
504 char **name,
505 int *len)
506 {
507 register struct nlist *sp = (struct nlist *)stab->start;
508 struct nlist *ep = (struct nlist *)stab->end;
509 struct nlist *fp = 0;
510 struct nlist *found_sp;
511 unsigned long func_top;
512 boolean_t in_file;
513 int nsym = 0;
514 int i;
515 char *p;
516
517 if (file == 0 && sym == 0)
518 return(0);
519 if (file) {
520 if ((sp = aout_db_search_name(sp, ep, file, N_TEXT, &fp, 0)) == 0)
521 return(0);
522 }
523 if (sym) {
524 for (;;) {
525 sp = aout_db_search_name(sp, ep, sym, (line > 0)? N_FUN: 0, &fp,
526 (ret == (db_sym_t *)0));
527 if (sp == 0)
528 return(nsym);
529 if (ret)
530 break;
531
532 if (strncmp(sp->n_un.n_name, sym, strlen(sym)) == 0)
533 p = sp->n_un.n_name;
534 else
535 p = &sp->n_un.n_name[1];
536
537 if (*name == (char *)0) {
538 *name = p;
539 *len = strlen(p);
540 } else {
541 for (i = 0; i < *len; i++)
542 if ((*name)[i] != p[i]) {
543 *len = i;
544 break;
545 }
546 }
547
548 nsym++;
549 sp++;
550 }
551 }
552 if (line > 0) {
553 if (file && !aout_db_eq_name(fp, file, 0))
554 return(0);
555 found_sp = 0;
556 if (sp->n_type == N_FUN) {
557 /*
558 * qualfied by function name
559 * search backward because line number entries
560 * for the function are above it in this case.
561 */
562 func_top = sp->n_value;
563 if (stab->sorted) {
564 /* symbols with the same value may have been mixed up */
565 do {
566 sp++;
567 } while (sp->n_value == func_top);
568 }
569 for (sp--; sp >= (struct nlist *)stab->start; sp--) {
570 if (sp->n_type != N_SLINE)
571 continue;
572 if (sp->n_value < func_top)
573 break;
574 if (sp->n_desc <= line) {
575 if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
576 found_sp = sp;
577 if (sp->n_desc == line)
578 break;
579 }
580 }
581 if (sp->n_type != N_SLINE || sp->n_value < func_top)
582 return(0);
583 } else {
584 /*
585 * qualified by only file name
586 * search forward in this case
587 */
588 in_file = TRUE;
589 if (stab->sorted) {
590 /* symbols with the same value may have been mixed up */
591 func_top = sp->n_value;
592 do {
593 sp--;
594 } while (sp->n_value == func_top);
595 }
596 for (sp++; sp < ep; sp++) {
597 if (sp->n_type == N_TEXT
598 && aout_db_is_filename(sp->n_un.n_name))
599 break; /* enter into another file */
600 if (sp->n_type == N_SOL) {
601 in_file = aout_db_eq_name(sp, file, 0);
602 continue;
603 }
604 if (!in_file || sp->n_type != N_SLINE)
605 continue;
606 if (sp->n_desc <= line) {
607 if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
608 found_sp = sp;
609 if (sp->n_desc == line)
610 break;
611 }
612 }
613 }
614 sp = found_sp;
615 }
616 *ret = (db_sym_t) sp;
617 return(1);
618 }
619
620 /*
621 * lookup symbol by name
622 */
623 db_sym_t
624 aout_db_lookup(
625 db_symtab_t *stab,
626 char * symstr)
627 {
628 return(db_sym_parse_and_lookup(aout_db_qualified_search, stab, symstr));
629 }
630
631 /*
632 * lookup (possibly incomplete) symbol by name
633 */
634 int
635 aout_db_lookup_incomplete(
636 db_symtab_t *stab,
637 char * symstr,
638 char ** name,
639 int *len,
640 int *toadd)
641 {
642 return(db_sym_parse_and_lookup_incomplete(aout_db_qualified_search,
643 stab, symstr, name, len, toadd));
644 }
645
646 /*
647 * Display possible completion for the symbol
648 */
649 int
650 aout_db_print_completion(stab, symstr)
651 db_symtab_t *stab;
652 char * symstr;
653 {
654
655 return(db_sym_parse_and_print_completion(aout_db_qualified_print_completion,
656 stab, symstr));
657 }
658
659 db_sym_t
660 aout_db_search_symbol(
661 db_symtab_t *symtab,
662 db_addr_t off,
663 db_strategy_t strategy,
664 db_expr_t *diffp) /* in/out */
665 {
666 register unsigned long diff = *diffp;
667 register struct nlist *symp = 0;
668 struct nlist *sp, *ep, *cp;
669 boolean_t first_pass = FALSE;
670
671 sp = (struct nlist *)symtab->start;
672 ep = (struct nlist *)symtab->end;
673
674 if (symtab->sorted) {
675 struct nlist target;
676
677 target.n_value = off;
678 target.n_un.n_name = (char *) 0;
679 target.n_other = (char) 0;
680 db_qsort_limit_search((char *) &target, (char **) &sp, (char **) &ep,
681 sizeof (struct nlist), aout_db_compare_symbols);
682 first_pass = TRUE;
683 }
684
685 try_again:
686 for (cp = ep-1; cp >= sp; cp--) {
687 if (cp->n_un.n_name == 0)
688 continue;
689 if ((cp->n_type & N_STAB) != 0)
690 continue;
691 if (strategy == DB_STGY_XTRN && (cp->n_type & N_EXT) == 0)
692 continue;
693 if (off >= cp->n_value) {
694 if (off - cp->n_value < diff) {
695 diff = off - cp->n_value;
696 symp = cp;
697 if (diff == 0 && (cp->n_type & N_EXT))
698 break;
699 }
700 else if (off - cp->n_value == diff) {
701 if (symp == 0)
702 symp = cp;
703 else if ((symp->n_type & N_EXT) == 0 &&
704 (cp->n_type & N_EXT) != 0)
705 symp = cp; /* pick the external symbol */
706 }
707 }
708 }
709 if (symp == 0) {
710 if (first_pass) {
711 first_pass = FALSE;
712 sp = (struct nlist *) symtab->start;
713 goto try_again;
714 }
715 *diffp = off;
716 }
717 else {
718 *diffp = diff;
719 }
720 return ((db_sym_t)symp);
721 }
722
723 /*
724 * Return the name and value for a symbol.
725 */
726 void
727 aout_db_symbol_values(
728 db_sym_t sym,
729 char **namep,
730 db_expr_t *valuep)
731 {
732 register struct nlist *sp;
733
734 sp = (struct nlist *)sym;
735 if (namep)
736 *namep = sp->n_un.n_name;
737 if (valuep)
738 *valuep = sp->n_value;
739 }
740
741 #define X_DB_MAX_DIFF 8 /* maximum allowable diff at the end of line */
742 extern int db_search_maxoff; /* maximum acceptable offset */
743
744 /*
745 * search symbol by value
746 */
747 db_sym_t
748 aout_db_search_by_addr(
749 db_symtab_t *stab,
750 db_addr_t addr,
751 char **file,
752 char **func,
753 int *line,
754 db_expr_t *diff,
755 int *args)
756 {
757 struct nlist *sp, *cp;
758 register struct nlist *line_sp, *func_sp, *file_sp, *line_func;
759 unsigned long func_diff, line_diff;
760 boolean_t found_line = FALSE;
761 struct nlist *ep = (struct nlist *)stab->end;
762 boolean_t first_pass = FALSE;
763
764 /*
765 * 92-May-16
766 * Added init of these two... not sure if it's correct, but
767 * can't be worse than random values.... -- jfriedl@omron.co.jp
768 */
769 func_diff = line_diff = /*HUGE*/0x0fffffff;
770
771 line_sp = func_sp = file_sp = line_func = 0;
772 *file = *func = 0;
773 *line = 0;
774 *args = -1;
775
776 sp = (struct nlist *)stab->start;
777 if (stab->sorted) {
778 struct nlist target;
779
780 target.n_value = addr;
781 target.n_un.n_name = (char *) 0;
782 target.n_other = (char) 0;
783 db_qsort_limit_search((char *) &target, (char **) &sp,
784 (char **) &ep, sizeof (struct nlist),
785 aout_db_compare_symbols);
786 first_pass = TRUE;
787 }
788
789 for (cp = sp; cp < ep; cp++) {
790 switch(cp->n_type) {
791 case N_SLINE:
792 if (cp->n_value <= addr) {
793 if (line_sp == 0 || line_diff >= addr - cp->n_value) {
794 if (line_func)
795 line_func = 0;
796 line_sp = cp;
797 line_diff = addr - cp->n_value;
798 }
799 }
800 if (cp->n_value >= addr && line_sp)
801 found_line = TRUE;
802 continue;
803 case N_FUN:
804 if ((found_line || (line_sp && line_diff < X_DB_MAX_DIFF))
805 && line_func == 0)
806 line_func = cp;
807 continue;
808 case N_SO:
809 if (cp->n_value > addr)
810 continue;
811 if (file_sp == 0 || file_sp->n_value <= cp->n_value)
812 file_sp = cp;
813 continue;
814 case N_TEXT:
815 if (aout_db_is_filename(cp->n_un.n_name)) {
816 if (cp->n_value > addr)
817 continue;
818 if (file_sp == 0 || file_sp->n_value <= cp->n_value)
819 file_sp = cp;
820 } else if (cp->n_value <= addr &&
821 (func_sp == 0 || func_diff > addr - cp->n_value)) {
822 func_sp = cp;
823 func_diff = addr - cp->n_value;
824 }
825 continue;
826 case N_TEXT|N_EXT:
827 if (cp->n_value <= addr &&
828 (func_sp == 0 || func_diff >= addr - cp->n_value)) {
829 func_sp = cp;
830 func_diff = addr - cp->n_value;
831 if (func_diff == 0 && file_sp && func_sp && line_sp == 0)
832 break;
833 }
834 default:
835 if (stab->sorted) {
836 if ((cp->n_value > addr) &&
837 (cp->n_value - addr > db_search_maxoff))
838 break;
839 }
840 continue;
841 }
842 break;
843 }
844 if (first_pass && (!file_sp || !line_sp || !func_sp)) {
845 first_pass = FALSE;
846 cp = sp;
847 sp = (struct nlist *)stab->start;
848 for (; cp >= sp; cp--) {
849 switch(cp->n_type) {
850 case N_SLINE:
851 if (line_sp)
852 found_line = TRUE;
853 continue;
854 case N_FUN:
855 if ((found_line || (line_sp && line_diff < X_DB_MAX_DIFF))
856 && line_func == 0)
857 line_func = cp;
858 continue;
859 case N_SO:
860 if (file_sp == 0)
861 file_sp = cp;
862 continue;
863 case N_TEXT:
864 if (aout_db_is_filename(cp->n_un.n_name)) {
865 if (file_sp == 0)
866 file_sp = cp;
867 } else if (func_sp == 0) {
868 func_sp = cp;
869 func_diff = addr - cp->n_value;
870 }
871 continue;
872 case N_TEXT|N_EXT:
873 if (func_sp == 0) {
874 func_sp = cp;
875 func_diff = addr - cp->n_value;
876 if (func_diff == 0 && file_sp && func_sp
877 && line_sp == 0)
878 break;
879 }
880 default:
881 if (line_sp && file_sp &&
882 addr - cp->n_value > db_search_maxoff)
883 break;
884 continue;
885 }
886 break;
887 }
888 }
889 #if 0
890 /*
891 * XXX - barbou@gr.osf.org
892 * I don't know if that code is useful to something, but it makes the -gline
893 * option of gcc useless.
894 */
895 if (line_sp) {
896 if (line_func == 0 || func_sp == 0
897 || line_func->n_value != func_sp->n_value)
898 line_sp = 0;
899 }
900 #else
901 if (line_sp && !found_line) {
902 line_sp = 0;
903 }
904 #endif
905 *diff = 0;
906 if (file_sp) {
907 *diff = addr - file_sp->n_value;
908 *file = file_sp->n_un.n_name;
909 }
910 if (line_sp) {
911 *diff = addr - line_sp->n_value;
912 *line = line_sp->n_desc;
913 }
914 if (func_sp) {
915 *diff = addr - func_sp->n_value;
916 *func = (func_sp->n_un.n_name[0] == '_')?
917 func_sp->n_un.n_name + 1: func_sp->n_un.n_name;
918 if (line_func && (line_func->n_desc & 0x4000))
919 *args = line_func->n_desc & 0x3ff;
920 }
921 return((db_sym_t) func_sp);
922 }
923
924 /*
925 * Find filename and lineno within, given the current pc.
926 */
927 boolean_t
928 aout_db_line_at_pc(
929 db_symtab_t *stab,
930 db_sym_t sym,
931 char **file,
932 int *line,
933 db_expr_t pc)
934 {
935 char *func;
936 db_expr_t diff;
937 boolean_t found;
938 int args;
939
940 found = (aout_db_search_by_addr(stab, (unsigned)pc, file, &func, line,
941 &diff, &args)
942 != DB_SYM_NULL);
943 return(found && func && *file);
944 }
945
946 /*
947 * Initialization routine for a.out files.
948 */
949 void
950 aout_db_init(void)
951 {
952 extern struct mach_header _mh_execute_header;
953
954 aout_db_sym_init((char *) &_mh_execute_header,
955 (char *)0, "mach", (char *)0);
956 }
957
958 #endif /* DB_NO_AOUT */