swig/Tools/WAD/Wad/stack.c
Dave Beazley 047feee80d *** empty log message ***
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@938 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-11-08 02:47:07 +00:00

282 lines
7 KiB
C

/* -----------------------------------------------------------------------------
* stack.c
*
* This file is used to unwind the C call stack.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
#include "wad.h"
#include <sys/types.h>
#include <sys/mman.h>
#include <dlfcn.h>
/* Given a stack pointer, this function performs a single level of stack
unwinding */
static void
stack_unwind(unsigned long *sp, unsigned long *pc) {
*pc = *((unsigned long *) *sp+15); /* %i7 - Return address */
*sp = *((unsigned long *) *sp+14); /* %i6 - frame pointer */
}
static void *trace_addr = 0;
static int trace_len = 0;
/* Perform a stack unwinding given the current value of the pc, stack pointer,
and frame pointer. Returns a pointer to a wad exception frame structure
which is actually a large memory mapped file. */
WadFrame *
wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) {
int i;
WadSegment *ws;
WadObject *wo;
WadFrame frame;
WadDebug *wd;
int nlevels;
char framefile[256];
int ffile;
unsigned long p_pc;
unsigned long p_sp;
unsigned long p_lastsp;
int n = 0;
int lastsize = 0;
int firstframe = 1;
/* Open the frame file for output */
sprintf(framefile,"/tmp/wad.%d", getpid());
ffile = open(framefile, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (ffile < 0) {
printf("can't open %s\n", framefile);
return 0;
}
/* Try to do a stack traceback */
nlevels = 0;
p_pc = pc;
p_sp = sp;
while (p_sp) {
/* Add check for stack validity here */
ws = wad_segment_find((char *) p_sp);
if (!ws) {
/* If the stack is bad, we are really hosed here */
break;
}
ws = wad_segment_find((char *) p_pc);
{
int symsize = 0;
int srcsize = 0;
int objsize = 0;
int stacksize = 0;
int argsize = 0;
char *srcname = 0;
char *objname = 0;
char *symname = 0;
int pad = 0;
unsigned long value;
/* Try to load the object file for this address */
if (ws) {
wo = wad_object_load(ws->mappath);
/* Special hack needed for base address */
}
else {
wo = 0;
}
/* Try to find the symbol corresponding to this PC */
if (wo) {
symname = wad_find_symbol(wo, (void *) p_pc, (unsigned long) ws->base, &value);
} else {
symname = 0;
}
/* Build up some information about the exception frame */
frame.frameno = n;
frame.last = 0;
frame.lastsize = lastsize;
frame.pc = p_pc;
frame.sp = p_sp;
frame.nargs = -1;
frame.arg_off = 0;
n++;
if (symname) {
symsize = strlen(symname)+1;
/* Try to gather some debugging information about this symbol */
wd = wad_debug_info(wo,symname, p_pc - (unsigned long) ws->base - value);
if (wd) {
srcname = wd->srcfile;
srcsize = strlen(srcname)+1;
objname = wd->objfile;
objsize = strlen(objname)+1;
frame.nargs = wd->nargs;
if (wd->nargs > 0) {
argsize = sizeof(WadParm)*wd->nargs;
}
/*
if (wd->nargs >=0) {
int i;
printf("%s\n",symname);
for (i = 0; i < wd->nargs; i++) {
printf(" [%d] = '%s', %d, %d\n", i, wd->parms[i].name, wd->parms[i].type, wd->parms[i].value);
}
}
*/
frame.line_number = wd->line_number;
}
}
/* Before unwinding the stack, copy the locals and %o registers from previous frame */
if (!firstframe) {
int i;
long *lsp = (long *) p_lastsp;
for (i = 0; i < 16; i++) {
/* printf("regs[%d] = 0x%x\n", lsp[i]); */
frame.regs[i] = lsp[i];
}
}
firstframe = 0;
/* Determine stack frame size */
p_lastsp = p_sp;
stack_unwind(&p_sp, &p_pc);
if (p_sp) {
stacksize = p_sp - p_lastsp;
} else {
stacksize = 0xffbf0000 - p_lastsp; /* Sick hack alert. Need to get stack top from somewhere */
}
/* Set the frame pointer and stack size */
frame.fp = p_sp;
frame.stack_size = stacksize;
/* Build the exception frame object we'll write */
frame.size = sizeof(WadFrame) + symsize + srcsize + objsize + stacksize + argsize;
pad = 8 - (frame.size % 8);
frame.size += pad;
frame.data[0] = 0;
frame.data[1] = 0;
/* Build up the offsets */
if (!symname) {
frame.sym_off = sizeof(WadFrame) - 8;
frame.src_off = sizeof(WadFrame) - 8;
frame.obj_off = sizeof(WadFrame) - 8;
frame.stack_off = sizeof(WadFrame) + argsize;
frame.arg_off = 0;
} else {
frame.arg_off = sizeof(WadFrame);
frame.stack_off = sizeof(WadFrame) + argsize;
frame.sym_off = frame.stack_off + stacksize;
frame.src_off = frame.sym_off + symsize;
frame.obj_off = frame.src_off + srcsize;
}
write(ffile,&frame,sizeof(WadFrame));
/* Write the argument data */
if (argsize > 0) {
write(ffile, (void *) wd->parms, argsize);
}
/* Write the stack data */
if (stacksize > 0) {
write(ffile, (void *) p_lastsp, stacksize);
}
if (symname) {
write(ffile,symname,symsize);
write(ffile,srcname,srcsize);
write(ffile,objname,objsize);
}
write(ffile,frame.data, pad);
lastsize = frame.size;
if (wo)
wad_object_release(wo);
}
}
/* Write terminator */
frame.size = 0;
frame.last = 1;
frame.lastsize = lastsize;
write(ffile,&frame,sizeof(WadFrame));
close(ffile);
/* mmap the debug file back into memory */
ffile = open(framefile, O_RDONLY, 0644);
trace_len = lseek(ffile,0,SEEK_END);
lseek(ffile,0,SEEK_SET);
trace_addr = mmap(NULL, trace_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, ffile, 0);
close(ffile);
wad_segment_release();
return (WadFrame *) trace_addr;
}
void wad_release_trace() {
char name[256];
munmap(trace_addr, trace_len);
sprintf(name,"/tmp/wad.%d", getpid());
unlink(name);
trace_addr = 0;
trace_len = 0;
}
/* This function steals an argument out of a frame further up the call stack :-) */
long wad_steal_arg(WadFrame *f, char *symbol, int argno, int *error) {
char *fd;
long *regs;
WadFrame *lastf = 0;
fd = (char *) f;
*error = 0;
/* Start searching */
while (f->size) {
if (strcmp(SYMBOL(f),symbol) == 0) {
/* Got a match */
if (lastf) {
regs = STACK(f);
return regs[8+argno];
}
}
lastf = f;
fd = fd + f->size;
f = (WadFrame *) fd;
}
*error = -1;
return 0;
}
long wad_steal_outarg(WadFrame *f, char *symbol, int argno, int *error) {
char *fd;
long *regs;
WadFrame *lastf = 0;
fd = (char *) f;
*error = 0;
/* Start searching */
while (f->size) {
if (strcmp(SYMBOL(f),symbol) == 0) {
/* Got a match */
if (lastf) {
regs = STACK(lastf);
return regs[8+argno];
}
}
lastf = f;
fd = fd + f->size;
f = (WadFrame *) fd;
}
*error = -1;
return 0;
}