*** 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:
parent
81c9d3f57e
commit
a623fa28bc
11 changed files with 243 additions and 47 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
11
Tools/WAD/Test/debug.i
Normal 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
32
Tools/WAD/Test/debug.py
Normal 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
21
Tools/WAD/Test/debug.tcl
Normal 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
|
||||
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ PERLSRCS = wadpl.cxx
|
|||
PERLOBJS = wadpl.o
|
||||
|
||||
# C Compiler
|
||||
CC = cc -g
|
||||
CC = cc
|
||||
CFLAGS =
|
||||
|
||||
# C++ Compiler
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue