|
|
GNU Mach 1.5
/*
* Mach Operating System
* Copyright (c) 1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or [email protected]
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* Author: David B. Golub, Carnegie Mellon University
* Date: 7/90
*/
#if MACH_KDB
/*
* Symbol table routines for a.out format files.
*/
#include <string.h>
#include <mach/std_types.h>
#include <machine/db_machdep.h> /* data types */
#include <ddb/db_output.h>
#include <ddb/db_sym.h>
#include <ddb/db_aout.h>
#ifndef DB_NO_AOUT
#include <ddb/nlist.h> /* a.out symbol table */
#include <ddb/stab.h>
#define private static
/*
* An a.out symbol table as loaded into the kernel debugger:
*
* symtab -> size of symbol entries, in bytes
* sp -> first symbol entry
* ...
* ep -> last symbol entry + 1
* strtab == start of string table
* size of string table in bytes,
* including this word
* -> strings
*/
/*
* Find pointers to the start and end of the symbol entries,
* given a pointer to the start of the symbol table.
*/
#define db_get_aout_symtab(symtab, sp, ep) \
(sp = (struct nlist *)((vm_offset_t *)(symtab) + 1), \
ep = (struct nlist *)((char *)sp + *((int*)symtab)))
boolean_t
aout_db_sym_init(
char * symtab, /* pointer to start of symbol table */
char * esymtab, /* pointer to end of string table,
for checking - may be rounded up to
integer boundary */
char * name,
char * task_addr) /* use for this task only */
{
struct nlist *sym_start, *sym_end;
struct nlist *sp;
char * strtab;
int strlen;
char * estrtab;
db_get_aout_symtab(symtab, sym_start, sym_end);
strtab = (char *)sym_end;
strlen = *(int *)strtab;
estrtab = strtab + strlen;
#define round_to_size(x) \
(((vm_offset_t)(x) + sizeof(vm_size_t) - 1) & ~(sizeof(vm_size_t) - 1))
if (round_to_size(estrtab) != round_to_size(esymtab)) {
db_printf("[ %s symbol table not valid ]\n", name);
return (FALSE);
}
#undef round_to_size
for (sp = sym_start; sp < sym_end; sp++) {
long strx;
strx = sp->n_un.n_strx;
if (strx != 0) {
if (strx > strlen) {
db_printf("Bad string table index (%#x)\n", strx);
sp->n_un.n_name = 0;
continue;
}
sp->n_un.n_name = strtab + strx;
}
}
if (db_add_symbol_table(SYMTAB_AOUT,
(char *)sym_start,
(char *)sym_end,
name,
symtab,
task_addr))
{
/* Successfully added symbol table */
db_printf("[ preserving %d bytes of %s symbol table ]\n",
esymtab - (char *)symtab, name);
return TRUE;
}
else
return FALSE;
}
/*
* check file name or not (check xxxx.x pattern)
*/
private boolean_t __attribute__ ((pure))
aout_db_is_filename(name)
const char *name;
{
while (*name) {
if (*name == '.') {
if (name[1])
return(TRUE);
}
name++;
}
return(FALSE);
}
/*
* special name comparison routine with a name in the symbol table entry
*/
private boolean_t __attribute__ ((pure))
aout_db_eq_name(sp, name)
const struct nlist *sp;
const char *name;
{
const char *s1, *s2;
s1 = sp->n_un.n_name;
s2 = name;
if (*s1 == '_' && *s2 && *s2 != '_')
s1++;
while (*s2) {
if (*s1++ != *s2++) {
/*
* check .c .o file name comparison case
*/
if (*s2 == 0 && sp->n_un.n_name <= s1 - 2
&& s1[-2] == '.' && s1[-1] == 'o')
return(TRUE);
return(FALSE);
}
}
/*
* do special check for
* xxx:yyy for N_FUN
* xxx.ttt for N_DATA and N_BSS
*/
return(*s1 == 0 || (*s1 == ':' && sp->n_type == N_FUN) ||
(*s1 == '.' && (sp->n_type == N_DATA || sp->n_type == N_BSS)));
}
/*
* search a symbol table with name and type
* fp(in,out): last found text file name symbol entry
*/
private struct nlist *
aout_db_search_name(sp, ep, name, type, fp)
struct nlist *sp;
const struct nlist *ep;
const char *name;
int type;
struct nlist **fp;
{
struct nlist *file_sp = *fp;
struct nlist *found_sp = 0;
for ( ; sp < ep; sp++) {
if (sp->n_type == N_TEXT && aout_db_is_filename(sp->n_un.n_name))
*fp = sp;
if (type) {
if (sp->n_type == type) {
if (aout_db_eq_name(sp, name))
return(sp);
}
if (sp->n_type == N_SO)
*fp = sp;
continue;
}
if (sp->n_type & N_STAB)
continue;
if (sp->n_un.n_name && aout_db_eq_name(sp, name)) {
/*
* In case of qaulified search by a file,
* return it immediately with some check.
* Otherwise, search external one
*/
if (file_sp) {
if ((file_sp == *fp) || (sp->n_type & N_EXT))
return(sp);
} else if (sp->n_type & N_EXT)
return(sp);
else
found_sp = sp;
}
}
return(found_sp);
}
/*
* search a symbol with file, func and line qualification
*/
private db_sym_t
aout_db_qualified_search(stab, file, sym, line)
db_symtab_t *stab;
const char *file;
const char *sym;
int line;
{
struct nlist *sp = (struct nlist *)stab->start;
struct nlist *ep = (struct nlist *)stab->end;
struct nlist *fp = 0;
struct nlist *found_sp;
unsigned long func_top;
boolean_t in_file;
if (file == 0 && sym == 0)
return(DB_SYM_NULL);
if (file) {
if ((sp = aout_db_search_name(sp, ep, file, N_TEXT, &fp)) == 0)
return(DB_SYM_NULL);
}
if (sym) {
sp = aout_db_search_name(sp, ep, sym, (line > 0)? N_FUN: 0, &fp);
if (sp == 0)
return(DB_SYM_NULL);
}
if (line > 0) {
if (file && !aout_db_eq_name(fp, file))
return(DB_SYM_NULL);
found_sp = 0;
if (sp->n_type == N_FUN) {
/*
* qualified by function name
* search backward because line number entries
* for the function are above it in this case.
*/
func_top = sp->n_value;
for (sp--; sp >= (struct nlist *)stab->start; sp--) {
if (sp->n_type != N_SLINE)
continue;
if (sp->n_value < func_top)
break;
if (sp->n_desc <= line) {
if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
found_sp = sp;
if (sp->n_desc == line)
break;
}
}
if (sp->n_type != N_SLINE || sp->n_value < func_top)
return(DB_SYM_NULL);
} else {
/*
* qualified by only file name
* search forward in this case
*/
in_file = TRUE;
for (sp++; sp < ep; sp++) {
if (sp->n_type == N_TEXT
&& aout_db_is_filename(sp->n_un.n_name))
break; /* enter into another file */
if (sp->n_type == N_SOL) {
in_file = aout_db_eq_name(sp, file);
continue;
}
if (!in_file || sp->n_type != N_SLINE)
continue;
if (sp->n_desc <= line) {
if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
found_sp = sp;
if (sp->n_desc == line)
break;
}
}
}
sp = found_sp;
}
return((db_sym_t) sp);
}
/*
* lookup symbol by name
*/
db_sym_t
aout_db_lookup(
db_symtab_t *stab,
char * symstr)
{
return(db_sym_parse_and_lookup(aout_db_qualified_search, stab, symstr));
}
db_sym_t
aout_db_search_symbol(
db_symtab_t * symtab,
db_addr_t off,
db_strategy_t strategy,
db_expr_t *diffp) /* in/out */
{
unsigned long diff = *diffp;
struct nlist *symp = 0;
struct nlist *sp, *ep;
sp = (struct nlist *)symtab->start;
ep = (struct nlist *)symtab->end;
for (; sp < ep; sp++) {
if (sp->n_un.n_name == 0)
continue;
if ((sp->n_type & N_STAB) != 0)
continue;
if (strategy == DB_STGY_XTRN && (sp->n_type & N_EXT) == 0)
continue;
if (off >= sp->n_value) {
unsigned int type = sp->n_type;
if (type == N_FN) continue;
if (off - sp->n_value < diff) {
diff = off - sp->n_value;
symp = sp;
if (diff == 0 && (type & N_EXT))
break;
}
else if (off - sp->n_value == diff) {
if (symp == 0)
symp = sp;
else if ((symp->n_type & N_EXT) == 0 &&
(type & N_EXT) != 0)
symp = sp; /* pick the external symbol */
}
}
}
if (symp == 0) {
*diffp = off;
}
else {
*diffp = diff;
}
return ((db_sym_t)symp);
}
/*
* Return the name and value for a symbol.
*/
void
aout_db_symbol_values(
db_symtab_t *stab,
db_sym_t sym,
char **namep,
db_expr_t *valuep)
{
struct nlist *sp;
sp = (struct nlist *)sym;
if (namep)
*namep = sp->n_un.n_name;
if (valuep)
*valuep = sp->n_value;
}
#define X_DB_MAX_DIFF 8 /* maximum allowable diff at the end of line */
/*
* search symbol by value
*/
private boolean_t
aout_db_search_by_addr(stab, addr, file, func, line, diff)
const db_symtab_t *stab;
vm_offset_t addr;
char **file;
char **func;
int *line;
unsigned long *diff;
{
struct nlist *sp;
struct nlist *line_sp, *func_sp, *file_sp, *line_func;
vm_size_t func_diff, line_diff;
boolean_t found_line = FALSE;
struct nlist *ep = (struct nlist *)stab->end;
line_sp = func_sp = file_sp = line_func = 0;
*file = *func = 0;
*line = 0;
func_diff = line_diff = ~0;
for (sp = (struct nlist *)stab->start; sp < ep; sp++) {
switch(sp->n_type) {
case N_SLINE:
if (sp->n_value <= addr) {
if (line_sp == 0 || line_diff >= addr - sp->n_value) {
if (line_func)
line_func = 0;
line_sp = sp;
line_diff = addr - sp->n_value;
}
}
if (sp->n_value >= addr && line_sp)
found_line = TRUE;
continue;
case N_FUN:
if ((found_line || (line_sp && line_diff < X_DB_MAX_DIFF))
&& line_func == 0)
line_func = sp;
continue;
case N_SO:
if (sp->n_value > addr)
continue;
if (file_sp == 0 || file_sp->n_value <= sp->n_value)
file_sp = sp;
continue;
case N_TEXT:
if (aout_db_is_filename(sp->n_un.n_name)) {
if (sp->n_value > addr)
continue;
if (file_sp == 0 || file_sp->n_value <= sp->n_value)
file_sp = sp;
} else if (sp->n_value <= addr &&
(func_sp == 0 || func_diff > addr - sp->n_value)) {
func_sp = sp;
func_diff = addr - sp->n_value;
}
continue;
case N_TEXT|N_EXT:
if (sp->n_value <= addr &&
(func_sp == 0 || func_diff >= addr - sp->n_value)) {
func_sp = sp;
func_diff = addr - sp->n_value;
if (func_diff == 0 && file_sp && func_sp)
break;
}
default:
continue;
}
break;
}
if (line_sp) {
if (line_func == 0 || func_sp == 0
|| line_func->n_value != func_sp->n_value)
line_sp = 0;
}
if (file_sp) {
*diff = addr - file_sp->n_value;
*file = file_sp->n_un.n_name;
}
if (func_sp) {
*diff = addr - func_sp->n_value;
*func = (func_sp->n_un.n_name[0] == '_')?
func_sp->n_un.n_name + 1: func_sp->n_un.n_name;
}
if (line_sp) {
*diff = addr - line_sp->n_value;
*line = line_sp->n_desc;
}
return(file_sp || func_sp || line_sp);
}
/*
* Find filename and lineno within, given the current pc.
*/
boolean_t
aout_db_line_at_pc(stab, sym, file, line, pc)
db_symtab_t *stab;
db_sym_t sym;
char **file;
int *line;
db_addr_t pc;
{
char *func;
unsigned long diff;
boolean_t found;
found = aout_db_search_by_addr(stab, pc, file, &func, line, &diff);
return(found && func && *file);
}
#endif /* DB_NO_AOUT */
#endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.