#include <mach/boolean.h>
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#ifdef DB_GCC_AOUT
#include <ddb/nlist.h>
#include <i386/stab.h>
#define db_get_aout_symtab(symtab, sp, ep) \
(sp = (struct nlist *)((symtab) + 1), \
ep = (struct nlist *)((char *)sp + *(symtab)))
X_db_sym_init(symtab, esymtab, name)
int * symtab;
char * esymtab;
char * name;
{
register struct nlist *sym_start, *sym_end;
register struct nlist *sp;
register char * strtab;
register int strlen;
db_get_aout_symtab(symtab, sym_start, sym_end);
strtab = (char *)sym_end;
strlen = *(int *)strtab;
if (strtab + ((strlen + sizeof(int) - 1) & ~(sizeof(int)-1))
!= esymtab)
{
db_printf("[ %s symbol table not valid ]\n", name);
return;
}
db_printf("[ preserving %#x bytes of %s symbol table ]\n",
esymtab - (char *)symtab, name);
for (sp = sym_start; sp < sym_end; sp++) {
register int 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;
}
}
db_add_symbol_table(sym_start, sym_end, name, (char *)symtab,
0, 0, 0, FALSE);
}
boolean_t
X_db_is_filename(name)
register char *name;
{
while (*name) {
if (*name == '.') {
if (name[1])
return(TRUE);
}
name++;
}
return(FALSE);
}
boolean_t
X_db_eq_name(sp, name)
struct nlist *sp;
char *name;
{
register char *s1, *s2;
s1 = sp->n_un.n_name;
s2 = name;
if (*s1 == '_' && *s2 && *s2 != '_')
s1++;
while (*s2) {
if (*s1++ != *s2++) {
if (*s2 == 0 && sp->n_un.n_name <= s1 - 2
&& s1[-2] == '.' && s1[-1] == 'o')
return(TRUE);
return(FALSE);
}
}
return(*s1 == 0 || (*s1 == ':' && sp->n_type == N_FUN) ||
(*s1 == '.' && (sp->n_type == N_DATA || sp->n_type == N_BSS)));
}
struct nlist *
X_db_search_name(sp, ep, name, type, fp)
register struct nlist *sp;
struct nlist *ep;
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 && X_db_is_filename(sp->n_un.n_name))
*fp = sp;
if (type) {
if (sp->n_type == type) {
if (X_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 && X_db_eq_name(sp, name)) {
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);
}
struct nlist *
X_db_qualified_search(stab, file, sym, line)
db_symtab_t *stab;
char *file;
char *sym;
int line;
{
register struct nlist *sp = (struct nlist *)stab->start;
struct nlist *ep = (struct nlist *)stab->end;
struct nlist *fp = 0;
struct nlist *found_sp;
unsigned func_top;
boolean_t in_file;
if (file == 0 && sym == 0)
return(0);
if (file) {
if ((sp = X_db_search_name(sp, ep, file, N_TEXT, &fp)) == 0)
return(0);
}
if (sym) {
sp = X_db_search_name(sp, ep, sym, (line > 0)? N_FUN: 0, &fp);
if (sp == 0)
return(0);
}
if (line > 0) {
if (file && !X_db_eq_name(fp, file))
return(0);
found_sp = 0;
if (sp->n_type == N_FUN) {
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(0);
} else {
in_file = TRUE;
for (sp++; sp < ep; sp++) {
if (sp->n_type == N_TEXT
&& X_db_is_filename(sp->n_un.n_name))
break;
if (sp->n_type == N_SOL) {
in_file = X_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(sp);
}
db_sym_t
X_db_lookup(stab, symstr)
db_symtab_t *stab;
char * symstr;
{
register char *p;
register n;
int n_name;
int line_number;
char *file_name = 0;
char *sym_name = 0;
char *component[3];
struct nlist *found = 0;
component[0] = symstr;
component[1] = component[2] = 0;
for (p = symstr, n = 1; *p; p++) {
if (*p == ':') {
if (n >= 3)
break;
*p = 0;
component[n++] = p+1;
}
}
if (*p != 0)
goto out;
line_number = 0;
n_name = n;
p = component[n-1];
if (*p >= '0' && *p <= '9') {
if (n == 1)
goto out;
for (line_number = 0; *p; p++) {
if (*p < '0' || *p > '9')
goto out;
line_number = line_number*10 + *p - '0';
}
n_name--;
} else if (n >= 3)
goto out;
if (n_name == 1) {
if (X_db_is_filename(component[0])) {
file_name = component[0];
sym_name = 0;
} else {
file_name = 0;
sym_name = component[0];
}
} else {
file_name = component[0];
sym_name = component[1];
}
found = X_db_qualified_search(stab, file_name, sym_name, line_number);
out:
while (--n > 1)
component[n][-1] = ':';
return((db_sym_t) found);
}
db_sym_t
X_db_search_symbol(symtab, off, strategy, diffp)
db_symtab_t * symtab;
register
db_addr_t off;
db_strategy_t strategy;
db_expr_t *diffp;
{
register unsigned int diff = *diffp;
register struct nlist *symp = 0;
register 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 (off >= sp->n_value) {
if (off - sp->n_value < diff) {
diff = off - sp->n_value;
symp = sp;
if (diff == 0 && (sp->n_type & N_EXT))
break;
}
else if (off - sp->n_value == diff) {
if (symp == 0)
symp = sp;
else if ((symp->n_type & N_EXT) == 0 &&
(sp->n_type & N_EXT) != 0)
symp = sp;
}
}
}
if (symp == 0) {
*diffp = off;
}
else {
*diffp = diff;
}
return ((db_sym_t)symp);
}
void
X_db_symbol_values(sym, namep, valuep)
db_sym_t sym;
char **namep;
db_expr_t *valuep;
{
register 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
X_db_search_by_addr(stab, addr, file, func, line, diff)
db_symtab_t *stab;
register unsigned addr;
char **file;
char **func;
int *line;
unsigned *diff;
{
register struct nlist *sp;
register struct nlist *line_sp, *func_sp, *file_sp, *line_func;
register 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;
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_TEXT:
if (X_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);
}
boolean_t
X_db_line_at_pc(stab, sym, file, line, pc)
db_symtab_t *stab;
db_sym_t sym;
char **file;
int *line;
db_expr_t pc;
{
char *func;
unsigned diff;
boolean_t found;
found = X_db_search_by_addr(stab,(unsigned)pc,file,&func,line,&diff);
return(found && func && *file);
}
kdb_init()
{
extern char *esym;
extern int end;
if (esym > (char *)&end) {
X_db_sym_init((int *)&end, esym, "mach");
}
}
#include <bootstrap/file_io.h>
#include <vm/vm_kern.h>
read_symtab_from_file(fp, symtab_name)
struct file *fp;
char * symtab_name;
{
vm_size_t resid;
kern_return_t result;
vm_offset_t symoff;
vm_size_t symsize;
vm_offset_t stroff;
vm_size_t strsize;
vm_size_t table_size;
vm_offset_t symtab;
if (!get_symtab(fp, &symoff, &symsize)) {
boot_printf("[ error %d reading %s file header ]\n",
result, symtab_name);
return;
}
stroff = symoff + symsize;
result = read_file(fp, (vm_offset_t)stroff,
(vm_offset_t)&strsize, sizeof(strsize), &resid);
if (result || resid) {
boot_printf("[ no valid symbol table present for %s ]\n",
symtab_name);
return;
}
table_size = sizeof(int) + symsize + strsize;
table_size = (table_size + sizeof(int)-1) & ~(sizeof(int)-1);
result = kmem_alloc_wired(kernel_map, &symtab, table_size);
if (result) {
boot_printf("[ error %d allocating space for %s symbol table ]\n",
result, symtab_name);
return;
}
*(int *)symtab = symsize;
result = read_file(fp, symoff,
symtab + sizeof(int), symsize, &resid);
if (result || resid) {
boot_printf("[ error %d reading %s symbol table ]\n",
result, symtab_name);
return;
}
result = read_file(fp, stroff,
symtab + sizeof(int) + symsize, strsize, &resid);
if (result || resid) {
boot_printf("[ error %d reading %s string table ]\n",
result, symtab_name);
return;
}
X_db_sym_init((int *)symtab,
(char *)(symtab + table_size),
symtab_name);
}
#endif