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