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