*** empty log message ***

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@980 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Dave Beazley 2001-01-02 22:10:07 +00:00
commit a623fa28bc
11 changed files with 243 additions and 47 deletions

View file

@ -182,6 +182,7 @@ extern WadReturnFunc *wad_check_return(const char *name);
#define DEBUG_SIGNAL 0x2000
extern int wad_debug_mode;
extern int wad_heap_overflow;
#ifdef __cplusplus
}

View file

@ -18,9 +18,8 @@ THIS IS EXPERIMENTAL UNSUPPORTED SOFTWARE THAT UTILIZES A HORRIBLE MIX
OF LOW-LEVEL SYSTEMS PROGRAMMING, C, C++, AND ASSEMBLY CODE. IT IS
NOT PORTABLE, IT HAS NOT BEEN RIGOROUSLY TESTED, AND IT MIGHT NOT WORK
AT ALL. PLEASE KEEP AWAY FROM SMALL CHILDREN, PETS, NUCLEAR REACTORS,
AIR-TRAFFIC CONTROL, VOTING MACHINES, AND MEDICAL EQUIPMENT. SIDE
EFFECTS MAY INCLUDE NAUSEA, VOMITING, AND HEADACHE. OTHER THAN THIS,
IT'S PERFECTLY SAFE.
AIR-TRAFFIC CONTROL, AND VOTING MACHINES. SIDE EFFECTS MAY INCLUDE
NAUSEA, VOMITING, AND HEADACHE. OTHER THAN THIS, IT'S PERFECTLY SAFE.
1. Introduction
@ -36,9 +35,12 @@ welcome. Contributions and modifications are even more welcome.
2. Compilation and Installation
WAD is not particularly portable (for obvious reasons). At this time,
only two platforms are supported: SPARC Solaris and i386-Linux. To
build the Solaris version, type 'make solaris'. To build the Linux
version, type 'make linux'.
only two platforms are supported: SPARC Solaris and i386-Linux. Installation
is as follows:
./configure
make
make install
The build process creates the following shared libraries:
@ -137,9 +139,74 @@ WAD_ONESHOT - Disable WAD signal handler after first signal has
been received.
5. Known Limitations
5. Known Problems
6. Documentation
General:
- WAD does not gracefully recover from errors that corrupt the call
stack (i.e., buffer overlow).
- Errors that destroy the process heap may or may not be recoverable
depending on what has been destroyed.
- WAD does not currently support 64 bit applications on any platform.
Solaris:
- No platform specific issues are known at this time.
Linux:
- The interaction of threads and signals are particularly problematic
on this platform and may cause WAD not to work at all. Here are
some specific thread-based problems:
1. WAD causes the program to crash immediately upon startup.
This appears to be caused by a bug in in the implemenation
of sigaction() and the initialization of signals. There is no
known solution.
2. Programs lock up when an error occurs. This is sometimes
caused by a non-working implementation of sigaltstack().
One solution to this is to set the following environment
variable:
setenv WAD_NOSTACK
in which case the WAD signal handler will use the same
stack as the thread/process that generates the error.
3. WAD just crashes altogether and doesn't seem to do anything.
It appears that some versions of Linux threads do *not*
pass CPU context information correctly to signal handlers
defined in threaded programs. There is no known fix to
this at this time.
6. Language dependent issues
If WAD is linked with a normal C/C++ program, errors simply produce a stack trace
that is printed on standard error.
Python:
WAD tries to raise a Python exception and return. At this time, the exception
merely contains a traceback string. However, in future versions, it may be
possible to access a complete exception object.
Tcl:
WAD returns a Tcl and places the stack trace into the Tcl variable $errorInfo.
The wish shell uses this to dump error information.
Perl:
Perl doesn't seem to have a very well-defined exception handling
mechanism. Standard functions tend to just exit. The WAD handler
produces a C stack trace and produces a Perl stack trace using some
code derived from the sigtrap module.
7. Documentation
No official documentation exists at this time. However, the Papers directory contains
two conference papers that describe WAD's design and high-level operation.

View file

@ -17,3 +17,21 @@ INCLUDE = -I../Include
test:
$(CC) -g -DNEED_MAIN debug.c $(INCLUDE) -L.. $(RPATH).. -lwad -o debug
python:
swig -python debug.i
$(CC) $(CCSHARED) -c -g debug.c debug_wrap.c $(PYINCLUDE)
$(LDSHARED) debug.o debug_wrap.o -L.. $(RPATH).. -lwadpy -o debugmodule.so
tcl:
swig -tcl debug.i
$(CC) $(CCSHARED) -c -g debug.c debug_wrap.c $(TCLINCLUDE)
$(LDSHARED) debug.o debug_wrap.o -L.. $(RPATH).. -lwadtcl -o debug.so
perl:
swig -perl5 debug.i
$(CC) $(CCSHARED) -c -Dbool=char -g debug.c debug_wrap.c $(PERLINCLUDE)
$(LDSHARED) debug.o debug_wrap.o -L.. $(RPATH).. -lwadpl -o debug.so
clean:
rm -f *.so *.o

11
Tools/WAD/Test/debug.i Normal file
View file

@ -0,0 +1,11 @@
%module debug
extern int seg_crash();
extern int bus_crash();
extern int blowheap_crash();
extern int overflow_crash();
extern int abort_crash(int);
extern int math_crash(int x, int y);

32
Tools/WAD/Test/debug.py Normal file
View file

@ -0,0 +1,32 @@
# WAD debugging module for python
import debug
import sys
try:
name = sys.argv[1]
except:
print """
usage: debug.py test
seg - Segmentation fault due to uninitialized pointer.
bus - Bus error.
abort - Failed assertion.
math - Math error.
heap - Blown heap.
overflow - Buffer overflow.
"""
sys.exit(1)
if name == "seg":
debug.seg_crash()
elif name == "bus":
debug.bus_crash()
elif name == "abort":
debug.abort_crash(-2)
elif name == "math":
debug.math_crash(3,0)
elif name == "heap":
debug.blowheap_crash()
elif name == "overflow":
debug.overflow_crash()

21
Tools/WAD/Test/debug.tcl Normal file
View file

@ -0,0 +1,21 @@
# WAD debugging module for Tcl. This should be executed with wish
load ./debug.so
button .b1 -text "Segmentation fault" -command "seg_crash"
button .b2 -text "Bus error" -command "bus_crash"
button .b3 -text "Abort" -command "abort_crash -1"
button .b4 -text "Math" -command "math_crash 3 0"
button .b5 -text "Blow Heap" -command "blowheap_crash"
button .b6 -text "Buffer overflow" -command "overflow_crash"
button .q -text "Quit" -command "exit"
pack .b1 -fill x
pack .b2 -fill x
pack .b3 -fill x
pack .b4 -fill x
pack .b5 -fill x
pack .b6 -fill x
pack .q -fill x

View file

@ -28,7 +28,7 @@ PERLSRCS = wadpl.cxx
PERLOBJS = wadpl.o
# C Compiler
CC = cc -g
CC = cc
CFLAGS =
# C++ Compiler

View file

@ -179,22 +179,22 @@ void wad_default_callback(int signo, WadFrame *framedata, char *ret) {
switch(signo) {
case SIGSEGV:
printf("Segmentation fault.\n");
fprintf(stderr,"Segmentation fault.\n");
break;
case SIGBUS:
printf("Bus error.\n");
fprintf(stderr,"Bus error.\n");
break;
case SIGABRT:
printf("Abort.\n");
fprintf(stderr,"Abort.\n");
break;
case SIGFPE:
printf("Floating point exception.\n");
fprintf(stderr,"Floating point exception.\n");
break;
case SIGILL:
printf("Illegal instruction.\n");
fprintf(stderr,"Illegal instruction.\n");
break;
default:
printf("Signal %d\n", signo);
fprintf(stderr,"Signal %d\n", signo);
break;
}
fd = (char *) framedata;
@ -211,12 +211,12 @@ void wad_default_callback(int signo, WadFrame *framedata, char *ret) {
fd = fd - f->lastsize;
f = (WadFrame *) fd;
while (1) {
printf("#%-3d 0x%08x in %s(%s)", f->frameno, f->pc, *(fd + f->sym_off) ? fd+f->sym_off : "?",
fprintf(stderr,"#%-3d 0x%08x in %s(%s)", f->frameno, f->pc, *(fd + f->sym_off) ? fd+f->sym_off : "?",
wad_arg_string(f));
if (strlen(fd+f->src_off)) {
printf(" in '%s'", wad_strip_dir(fd+f->src_off));
fprintf(stderr," in '%s'", wad_strip_dir(fd+f->src_off));
if (f->line_number > 0) {
printf(", line %d", f->line_number);
fprintf(stderr,", line %d", f->line_number);
{
int fd;
fd = open(SRCFILE(f), O_RDONLY);
@ -228,10 +228,10 @@ void wad_default_callback(int signo, WadFrame *framedata, char *ret) {
}
} else {
if (strlen(fd+f->obj_off)) {
printf(" from '%s'", fd+f->obj_off);
fprintf(stderr," from '%s'", fd+f->obj_off);
}
}
printf("\n");
fprintf(stderr,"\n");
if (!f->lastsize) break;
fd = fd - f->lastsize;
f = (WadFrame *) fd;
@ -248,24 +248,24 @@ void wad_default_callback(int signo, WadFrame *framedata, char *ret) {
line = wad_load_source(SRCFILE(fline),first);
if (line) {
printf("\n%s, line %d\n\n", SRCFILE(fline),fline->line_number);
fprintf(stderr,"\n%s, line %d\n\n", SRCFILE(fline),fline->line_number);
for (i = first; i <= last; i++) {
if (i == fline->line_number) printf(" => ");
else printf(" ");
if (i == fline->line_number) fprintf(stderr," => ");
else fprintf(stderr," ");
c = strchr(line,'\n');
if (c) {
*c = 0;
printf("%s\n",line);
fprintf(stderr,"%s\n",line);
*c = '\n';
} else {
printf("%s\n",line);
fprintf(stderr,"%s\n",line);
break;
}
line = c+1;
}
wad_release_source();
printf("\n");
fprintf(stderr,"\n");
}
}
wad_release_trace();
}

View file

@ -30,6 +30,11 @@
#define STACK_SIZE 4*SIGSTKSZ
char wad_sig_stack[STACK_SIZE];
/* This variable is set if the signal handler thinks that the
heap has overflowed */
int wad_heap_overflow = 0;
static wad_stacked_signal = 0;
static void (*sig_callback)(int signo, WadFrame *data, char *ret) = 0;
@ -45,26 +50,26 @@ void wad_set_callback(void (*s)(int,WadFrame *,char *ret)) {
return to the caller as if the function had actually completed
normally. */
int nlr_levels = 0;
volatile int *volatile nlr_p = &nlr_levels;
long nlr_value = 0;
void (*nlr_func)(void) = 0;
int wad_nlr_levels = 0;
static volatile int *volatile nlr_p = &wad_nlr_levels;
long wad_nlr_value = 0;
void (*wad_nlr_func)(void) = 0;
/* Set the return value from another module */
void wad_set_return_value(long value) {
nlr_value = value;
wad_nlr_value = value;
}
/* Set the return function */
void wad_set_return_func(void(*f)(void)) {
nlr_func = f;
wad_nlr_func = f;
}
#ifdef WAD_SOLARIS
static void nonlocalret() {
long a;
a = nlr_value;
a = wad_nlr_value;
/* We never call this procedure as a function. This code
causes an immediate return if someone does this */
@ -81,15 +86,15 @@ static void nonlocalret() {
asm("restore");
}
asm("sethi %hi(nlr_value), %o0");
asm("or %o0, %lo(nlr_value), %o0");
asm("sethi %hi(wad_nlr_value), %o0");
asm("or %o0, %lo(wad_nlr_value), %o0");
asm("ld [%o0], %i0");
/* If there is a non-local return function. We're going to go ahead
and transfer control to it */
if (nlr_func)
(*nlr_func)();
if (wad_nlr_func)
(*wad_nlr_func)();
asm("jmp %i7 + 8");
asm("restore");
@ -105,10 +110,10 @@ static void nonlocalret() {
asm("leave");
}
if (nlr_func)
(*nlr_func)();
if (wad_nlr_func)
(*wad_nlr_func)();
asm("movl nlr_value, %eax");
asm("movl wad_nlr_value, %eax");
asm("leave");
asm("ret");
}
@ -131,17 +136,20 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
WadFrame *frame, *origframe;
char *framedata;
char *retname = 0;
unsigned long current_brk;
nlr_func = 0;
wad_nlr_func = 0;
if (!wad_stacked_signal)
wad_object_init();
context = (ucontext_t *) vcontext;
if (wad_debug_mode & DEBUG_SIGNAL) {
printf("WAD: siginfo = %x, context = %x\n", si, vcontext);
}
current_brk = (long) sbrk(0);
/* Get some information about the current context */
@ -160,6 +168,9 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
/* Get some information out of the signal handler stack */
addr = (unsigned long) si->si_addr;
/* See if this might be a stack overflow */
p_pc = (unsigned long) (*pc);
p_sp = (unsigned long) (*sp);
#ifdef WAD_LINUX
@ -168,6 +179,11 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
#endif
/* printf("fault at address %x, pc = %x, sp = %x, fp = %x\n", addr, p_pc, p_sp, p_fp);*/
if (wad_debug_mode & DEBUG_SIGNAL) {
printf("fault at address %x, pc = %x, sp = %x, fp = %x\n", addr, p_pc, p_sp, p_fp);
}
if (wad_stacked_signal) {
printf("Fault in wad at pc = %x, sp = %x\n", p_pc, p_sp);
exit(1);
@ -180,6 +196,10 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
wad_stacked_signal--;
return;
}
wad_heap_overflow = 0;
if (sig == SIGSEGV) {
if (addr >= current_brk) wad_heap_overflow = 1;
}
if (wad_debug_mode & DEBUG_STACK) {
@ -218,7 +238,7 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
WadReturnFunc *wr = wad_check_return(framedata+frame->sym_off);
if (wr) {
found = 1;
nlr_value = wr->value;
wad_nlr_value = wr->value;
retname = wr->name;
}
framedata = framedata + frame->size;
@ -232,9 +252,9 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
if (found) {
nlr_levels = nlevels - 1;
wad_nlr_levels = nlevels - 1;
} else {
nlr_levels = 0;
wad_nlr_levels = 0;
}
if (sig_callback) {
@ -242,6 +262,7 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
} else {
/* No signal handler defined. Go invoke the default */
wad_default_callback(sig, origframe,retname);
wad_release_trace();
}
if (wad_debug_mode & DEBUG_HOLD) while(1);
@ -252,7 +273,7 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
an alternative piece of code that unwinds the stack and
initiates a non-local return. */
if (nlr_levels > 0) {
if (wad_nlr_levels > 0) {
*(pc) = (greg_t) _returnsignal;
#ifdef WAD_SOLARIS
*(npc) = *(pc) + 4;

View file

@ -211,6 +211,16 @@ static void handler(int signo, WadFrame *frame, char *ret) {
strcat(message,"\n");
}
}
if (wad_heap_overflow) {
write(2, "WAD: Heap overflow detected.\n", 30);
wad_default_callback(signo, frame, ret);
}
/* Note: if the heap is blown, there is a very good chance that this
function will not succeed and we'll dump core. However, the check
above should dump a stack trace to stderr just in case we don't make it
back. */
PyErr_SetString(type, message);
wad_release_trace();
}

View file

@ -42,7 +42,12 @@ static void handler(int signo, WadFrame *frame, char *ret) {
case SIGABRT:
type = (char*)"Abort.";
break;
case SIGFPE:
type = (char*)"Floating point exception.";
break;
default:
type = (char*)"Unknown.";
break;
}
fd = (char *) frame;
@ -118,6 +123,16 @@ static void handler(int signo, WadFrame *frame, char *ret) {
}
}
if (wad_heap_overflow) {
write(2, "WAD: Heap overflow detected.\n", 30);
wad_default_callback(signo, frame, ret);
}
/* Note: if the heap is blown, there is a very good chance that this
function will not succeed and we'll dump core. However, the check
above should dump a stack trace to stderr just in case we don't make it
back. */
/* Try to get the Tcl interpreter through magic */
if (ret) {
interp = (Tcl_Interp *) wad_steal_outarg(frame,ret,1,&err);