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