*** empty log message ***

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@983 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Dave Beazley 2001-01-03 04:52:00 +00:00
commit 00fe3073ed
8 changed files with 256 additions and 47 deletions

View file

@ -9,7 +9,7 @@ PYINCLUDE = -I/usr/local/include/python2.0
TCLINCLUDE = -I/usr/local/include TCLINCLUDE = -I/usr/local/include
# Location of your Perl installation # Location of your Perl installation
PERLINCLUDE = -I/usr/perl5/5.00503/sun4-solaris/CORE PERLINCLUDE = -I/usr/lib/perl5/5.00503/i386-linux/CORE
all: wad python tcl perl all: wad python tcl perl

View file

@ -6,37 +6,47 @@ University of Chicago
Chicago, IL 60637 Chicago, IL 60637
beazley@cs.uchicago.edu beazley@cs.uchicago.edu
Copyright (C) 2001 Copyright (C) 2000-2001
University of Chicago University of Chicago
All Rights Reserved All Rights Reserved
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!! READ THIS NOW !!!!!!!! !!!!!!!! DISCLAIMER !!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
THIS IS EXPERIMENTAL UNSUPPORTED SOFTWARE THAT UTILIZES A HORRIBLE MIX THIS IS EXPERIMENTAL UNSUPPORTED SOFTWARE THAT UTILIZES A HORRIBLE MIX
OF LOW-LEVEL SYSTEMS PROGRAMMING, C, C++, AND ASSEMBLY CODE. IT IS OF LOW-LEVEL C, C++, AND ASSEMBLY CODE. IT IS NOT PORTABLE, IT HAS
NOT PORTABLE, IT HAS NOT BEEN RIGOROUSLY TESTED, AND IT MIGHT NOT WORK NOT BEEN RIGOROUSLY TESTED, AND IT MIGHT NOT WORK AT ALL. PLEASE KEEP
AT ALL. PLEASE KEEP AWAY FROM SMALL CHILDREN, PETS, NUCLEAR REACTORS, AWAY FROM SMALL CHILDREN, PETS, NUCLEAR REACTORS, AIR-TRAFFIC CONTROL,
AIR-TRAFFIC CONTROL, AND VOTING MACHINES. SIDE EFFECTS MAY INCLUDE AND VOTING MACHINES. SIDE EFFECTS MAY INCLUDE NAUSEA, VOMITING, AND
NAUSEA, VOMITING, AND HEADACHE. OTHER THAN THIS, IT'S PERFECTLY SAFE. HEADACHE. OTHER THAN THIS, IT'S PERFECTLY SAFE.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!! READ THIS FIRST !!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
This software is only known to work on Sun Sparc Solaris 2.8 and recent
i386-Linux systems. In addition, there are numerous issues concerning
the interaction of this software with signal handling, thread
libraries, and compilers. Please read this entire document before
proceeding.
1. Introduction 1. Introduction
WAD is an embedded error-recovery mechanism that attempts to convert WAD is an embedded error-recovery mechanism that attempts to convert
fatal errors such as SIGSEGV, SIGBUS, and SIGFPE into sensible error messages fatal errors such as SIGSEGV, SIGBUS, and SIGFPE into sensible error messages
and exceptions. It is specifically designed to support scripting language and exceptions. It is specifically designed to support scripting language
environments although it can also be used with stand-alone C programs. extension programming although it can also be used with stand-alone C programs.
The primary goal of this system is to explore alternative approaches The primary goal of this system is to explore alternative approaches
to mixed scripting-compiled debugging. Feedback is to mixed scripting-compiled debugging. Feedback is welcome.
welcome. Contributions and modifications are even more welcome. Contributions and modifications are even more welcome.
2. Compilation and Installation 2. Compilation and Installation
WAD is not particularly portable (for obvious reasons). At this time, WAD is not particularly portable (for obvious reasons). At this time,
only two platforms are supported: SPARC Solaris and i386-Linux. Installation only two platforms are supported: Sun Sparc Solaris and i386-Linux.
is as follows: Installation is as follows:
./configure ./configure
make make
@ -61,18 +71,23 @@ to /usr/local/lib (unless you modify the makefile).
Notes: Notes:
- Not all of these libraries are currently available on all platforms. - The Sun version of WAD has only been tested when compiled with the
Most development work has taken place on Solaris. Sun Workshop C/C++ compilers. Although WAD works with other programs
that have been compiled with gcc. If gcc is installed on your
machine, you may want to set the following environment variables:
- You may need to modify the Makefile to point to the installed locations setenv CC cc
of various scripting language libraries. Eventually this will be setenv CXX CC
put under autoconf, but that's for later. ./configure
- Not all of these libraries are currently available on all platforms.
Most development work has taken place on Solaris.
- WAD only supports systems with ELF-format executables and stabs - You may need to modify the Makefile to point to the installed locations
format debugging tables. This is fairly common on many systems. of various scripting language libraries if you have installed
However, it also means that WAD does not work with newer compilers them in non-traditional locations.
and debugging formats such as DWARF2.
3. Using WAD 3. Using WAD
WAD has no functional API nor does it have any command line options so WAD has no functional API nor does it have any command line options so
@ -104,7 +119,8 @@ Segmentation fault.
Due to WAD's experimental nature, a number of debugging modes can be set Due to WAD's experimental nature, a number of debugging modes can be set
through the use of environment variables. These variables control WAD's through the use of environment variables. These variables control WAD's
runtime behavior and cause the system to dump debugging information for runtime behavior and cause the system to dump debugging information for
various stages of error recovery. various stages of error recovery. A lot of this data is pretty ugly and
probably only of interest to you if you are trying to debug WAD itself.
WAD_DEBUG_SEGMENT - Displays information about the virtual memory WAD_DEBUG_SEGMENT - Displays information about the virtual memory
map and mapping of addresses to segments. map and mapping of addresses to segments.
@ -138,8 +154,7 @@ WAD_NOSTACK - Do NOT use an alternative signal handling stack.
WAD_ONESHOT - Disable WAD signal handler after first signal has WAD_ONESHOT - Disable WAD signal handler after first signal has
been received. been received.
5. Platform Specific Issues
5. Known Problems
General: General:
@ -152,9 +167,9 @@ General:
- WAD does not currently support 64 bit applications on any platform. - WAD does not currently support 64 bit applications on any platform.
- If executables have been stripped, their symbol tables might not - If executables have been stripped, their symbol tables might not
have enough information to recover from errors. From a practical have enough information to recover from errors. There is very little
standpoint, there is no reason to strip executables---besides practical point in stripping the interpreter symbol table other
disk is cheap. than saving a little disk space.
Solaris: Solaris:
@ -164,7 +179,7 @@ Linux:
- The interaction of threads and signals are particularly problematic - The interaction of threads and signals are particularly problematic
on this platform and may cause WAD not to work at all. Here are on this platform and may cause WAD not to work at all. Here are
some specific thread-based problems: some specific thread-based problems that may arise:
1. WAD causes the program to crash immediately upon startup. 1. WAD causes the program to crash immediately upon startup.
This appears to be caused by a bug in in the implemenation This appears to be caused by a bug in in the implemenation
@ -172,7 +187,7 @@ Linux:
known solution. known solution.
2. Programs lock up when an error occurs. This is sometimes 2. Programs lock up when an error occurs. This is sometimes
caused by a non-working implementation of sigaltstack(). caused by a broken implementation of sigaltstack().
One solution to this is to set the following environment One solution to this is to set the following environment
variable: variable:
@ -185,10 +200,15 @@ Linux:
It appears that some versions of Linux threads do *not* It appears that some versions of Linux threads do *not*
pass CPU context information correctly to signal handlers pass CPU context information correctly to signal handlers
defined in threaded programs. There is no known fix to defined in threaded programs. There is no known fix to
this at this time. this at this time. Upgrade your system.
- WAD does not work if it is compiled as PIC code. The WAD libraries - WAD does not work if it is compiled as PIC code. The WAD libraries
should be compiled without the -fpic option. should be compiled *without* the -fpic option.
- WAD has to rely upon a heuristic register recovery scheme when it
returns to scripting language interpreters. It seems to
work, but it relies upon a very specific compiler code generation
convention for saving registers in function prologues.
6. Language dependent issues 6. Language dependent issues
@ -213,7 +233,43 @@ mechanism. Standard functions tend to just exit. The WAD handler
produces a C stack trace and produces a Perl stack trace using some produces a C stack trace and produces a Perl stack trace using some
code derived from the sigtrap module. code derived from the sigtrap module.
7. Documentation 7. Testing and Examples
The Tests directory contains some very simple code for testing wad. In the most simple
form, compile the stand-along test program 'debug' as follows:
% cd Tests
% make
% debug
WAD debug program.
Usage: debug type
seg - Fail with an uninitialized pointer.
bus - Fail with a bus error.
abort - Fail with an assertion error.
math - Fail with a math error.
heap - Blow the process heap.
overflow - Buffer overflow on the stack.
% debug seg
WAD debug program.
Segmentation fault.
#2 0x400581eb in __libc_start_main() in 'libc-start.c', line 90
#1 0x08048b61 in main(argc=0x2,argv=0xbffffc54) in 'debug.c', line 85
#0 0x080489d0 in seg_crash() in 'debug.c', line 15
/r0/beazley/Projects/WAD/Test/debug.c, line 15
int seg_crash() {
int *a = 0;
=> *a = 3;
return 1;
}
Additional targets 'make python', 'make tcl', and 'make perl' are also available.
The scripts debug.py, debug.tcl, debug.pl can be used to test these extensions.
8. Documentation
No official documentation exists at this time. However, the Papers directory contains No official documentation exists at this time. However, the Papers directory contains
two conference papers that describe WAD's design and high-level operation. two conference papers that describe WAD's design and high-level operation.

View file

@ -6,6 +6,3 @@ extern int blowheap_crash();
extern int overflow_crash(); extern int overflow_crash();
extern int abort_crash(int); extern int abort_crash(int);
extern int math_crash(int x, int y); extern int math_crash(int x, int y);

View file

@ -2,14 +2,18 @@
load ./debug.so load ./debug.so
message .t -text "This program tests various program faults. Note: Not all of these errors can be gracefully handled."
button .b1 -text "Segmentation fault" -command "seg_crash" button .b1 -text "Segmentation fault" -command "seg_crash"
button .b2 -text "Bus error" -command "bus_crash" button .b2 -text "Bus error (not on Linux)" -command "bus_crash"
button .b3 -text "Abort" -command "abort_crash -1" button .b3 -text "Abort" -command "abort_crash -1"
button .b4 -text "Math" -command "math_crash 3 0" button .b4 -text "Math" -command "math_crash 3 0"
button .b5 -text "Blow Heap" -command "blowheap_crash" button .b5 -text "Blow Heap" -command "blowheap_crash"
button .b6 -text "Buffer overflow" -command "overflow_crash" button .b6 -text "Buffer overflow" -command "overflow_crash"
button .q -text "Quit" -command "exit" button .q -text "Quit" -command "exit"
pack .t -fill x
pack .b1 -fill x pack .b1 -fill x
pack .b2 -fill x pack .b2 -fill x
pack .b3 -fill x pack .b3 -fill x

View file

@ -10,7 +10,7 @@
WADSRCS = return.c default.c stack.c stab.c elf.c object.c init.c segment.c signal.c WADSRCS = return.c default.c stack.c stab.c elf.c object.c init.c segment.c signal.c
WADOBJS = return.o default.o stack.o stab.o elf.o object.o signal.o segment.o init.o WADOBJS = return.o default.o stack.o stab.o elf.o object.o signal.o segment.o init.o
INCLUDE = -I../Include -I. $(SINCLUDE) INCLUDE = -I../Include -I. $(SINCLUDE)
WADOPT = -DWAD_SOLARIS WADOPT = -DWAD_LINUX
# Location of your Python installation # Location of your Python installation
PYINCLUDE = -I/usr/local/include/python2.0 PYINCLUDE = -I/usr/local/include/python2.0
@ -23,21 +23,21 @@ TCLSRCS = wadtcl.cxx
TCLOBJS = wadtcl.o TCLOBJS = wadtcl.o
# Location of your Perl installation # Location of your Perl installation
PERLINCLUDE = -I/usr/perl5/5.00503/sun4-solaris/CORE PERLINCLUDE = -I/usr/lib/perl5/5.00503/i386-linux/CORE
PERLSRCS = wadpl.cxx PERLSRCS = wadpl.cxx
PERLOBJS = wadpl.o PERLOBJS = wadpl.o
# C Compiler # C Compiler
CC = cc CC = gcc
CFLAGS = # CFLAGS = #-fpic
# C++ Compiler # C++ Compiler
CXX = CC CXX = c++
CXXFLAGS = #-Kpic CXXFLAGS = #-fpic
# Linking options # Linking options
CLINK = CLINK =
CXXLINK = CC -G CXXLINK = g++ -shared
# Rules for creation of a .o file from .cxx # Rules for creation of a .o file from .cxx
.SUFFIXES: .cxx .SUFFIXES: .cxx

View file

@ -24,6 +24,16 @@
#ifndef EIP #ifndef EIP
#define EIP 14 #define EIP 14
#endif #endif
#ifndef ESI
#define ESI 5
#endif
#ifndef EDI
#define EDI 4
#endif
#ifndef EBX
#define EBX 8
#endif
#endif #endif
/* Signal handling stack */ /* Signal handling stack */
@ -103,6 +113,13 @@ static void nonlocalret() {
#endif #endif
#ifdef WAD_LINUX #ifdef WAD_LINUX
/* Saved values of the machine registers */
long wad_saved_esi = 0;
long wad_saved_edi = 0;
long wad_saved_ebx = 0;
static void nonlocalret() { static void nonlocalret() {
asm("_returnsignal:"); asm("_returnsignal:");
while (*nlr_p > 0) { while (*nlr_p > 0) {
@ -113,10 +130,107 @@ static void nonlocalret() {
if (wad_nlr_func) if (wad_nlr_func)
(*wad_nlr_func)(); (*wad_nlr_func)();
/* Restore the registers */
asm("movl wad_saved_esi, %esi");
asm("movl wad_saved_edi, %edi");
asm("movl wad_saved_ebx, %ebx");
asm("movl wad_nlr_value, %eax"); asm("movl wad_nlr_value, %eax");
asm("leave"); asm("leave");
asm("ret"); asm("ret");
} }
/* This function uses a heuristic to restore the callee-save registers on i386.
According to the Linux Assembly HOWTO, the %esi, %edi, %ebx, and %ebp registers
are callee-saved. All others are caller saved. To restore the callee-save
registers, we use the fact that the C compiler saves the callee-save registers
(if any) at the beginning of function execution. Therefore, we can scan the
instructions at the start of each function in the stack trace to try and find
where they are.
The following heuristic is used:
1. Each function starts with a preamble like this which saves the %ebp
register:
55 89 e5 ---> push %ebp
mov %esp, %ebp
2. Next, space is allocated for local variables, using one of two schemes:
83 ec xx ---> Less than 256 bytes of local storage
^^^
length
81 ec xx xx xx xx --> More than 256 bytes of local storage
^^^^^^^^^^^
length
3. After this, a collection of 1-byte stack push op codes might appear
56 = pushl %esi
57 = pushl %edi
53 = pushl %ebx
Based on the size of local variable storage and the order in which
the %esi, %edi, and %ebx registers are pushed on the stack, we can
determine where in memory the registers are saved and restore them to
their proper values.
*/
void wad_restore_i386_registers(WadFrame *f, int nlevels) {
WadFrame *lastf = f;
char *fd = (char *) f;
int localsize = 0;
unsigned char *pc;
unsigned long *saved;
int i, j;
int pci;
for (i = 0; i <= nlevels; i++) {
/* This gets the starting instruction for the stack frame */
pc = (unsigned char *) f->sym_base;
/* printf("pc = %x, base = %x, %s\n", f->pc, f->sym_base, SYMBOL(f)); */
/* Look for the standard prologue 0x55 0x89 0xe5 */
if ((pc[0] == 0x55) && (pc[1] == 0x89) && (pc[2] == 0xe5)) {
/* Determine the size */
pci = 3;
if ((pc[3] == 0x83) && (pc[4] == 0xec)) {
/* printf("8-bit size\n");*/
localsize = (int) pc[5];
pci = 6;
}
if ((pc[3] == 0x81) && (pc[4] == 0xec)) {
/* printf("32-bit size\n"); */
localsize = (int) *((long *) (pc+5));
pci = 10;
}
saved = (long *) (f->fp - localsize - sizeof(long));
/* printf("saved = %x, fp = %x\n", saved, f->fp);
printf("localsize = %d\n", localsize);
*/
for (j = 0; j < 3; j++, saved--, pci++) {
if (pc[pci] == 0x57) {
wad_saved_edi = *saved;
/* printf("restored edi = %x\n", wad_saved_edi); */
}
else if (pc[pci] == 0x56) {
wad_saved_esi = *saved;
/* printf("restored esi = %x\n", wad_saved_esi); */
}
else if (pc[pci] == 0x53) {
wad_saved_ebx = *saved;
/* printf("restored ebx = %x\n", wad_saved_ebx); */
}
else break;
}
}
fd += f->size;
f = (WadFrame *) fd;
}
}
#endif #endif
void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) { void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
@ -124,6 +238,11 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
greg_t *npc; greg_t *npc;
greg_t *sp; greg_t *sp;
greg_t *fp; greg_t *fp;
#ifdef WAD_LINUX
greg_t *esi;
greg_t *edi;
greg_t *ebx;
#endif
unsigned long addr; unsigned long addr;
ucontext_t *context; ucontext_t *context;
@ -163,6 +282,16 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
sp = &((context->uc_mcontext).gregs[ESP]); /* Top of stack */ sp = &((context->uc_mcontext).gregs[ESP]); /* Top of stack */
fp = &((context->uc_mcontext).gregs[EBP]); /* Stack base - frame pointer */ fp = &((context->uc_mcontext).gregs[EBP]); /* Stack base - frame pointer */
pc = &((context->uc_mcontext).gregs[EIP]); /* Current instruction */ pc = &((context->uc_mcontext).gregs[EIP]); /* Current instruction */
esi = &((context->uc_mcontext).gregs[ESI]);
edi = &((context->uc_mcontext).gregs[EDI]);
ebx = &((context->uc_mcontext).gregs[EBX]);
wad_saved_esi = (unsigned long) (*esi);
wad_saved_edi = (unsigned long) (*edi);
wad_saved_ebx = (unsigned long) (*ebx);
/* printf("esi = %x, edi = %x, ebx = %x\n", wad_saved_esi, wad_saved_edi, wad_saved_ebx); */
/* printf("&sp = %x, &pc = %x\n", sp, pc); */ /* printf("&sp = %x, &pc = %x\n", sp, pc); */
#endif #endif
@ -214,7 +343,7 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
printf(" sp = %x\n", frame->sp); printf(" sp = %x\n", frame->sp);
printf(" fp = %x\n", frame->fp); printf(" fp = %x\n", frame->fp);
printf(" size = %x\n", frame->stack_size); printf(" size = %x\n", frame->stack_size);
printf(" pc = %x\n", frame->pc); printf(" pc = %x (base = %x)\n", frame->pc, frame->sym_base);
printf(" symbol = '%s'\n", SYMBOL(frame)); printf(" symbol = '%s'\n", SYMBOL(frame));
printf(" srcfile = '%s'\n", SRCFILE(frame)); printf(" srcfile = '%s'\n", SRCFILE(frame));
printf(" objfile = '%s'\n", OBJFILE(frame)); printf(" objfile = '%s'\n", OBJFILE(frame));
@ -253,6 +382,9 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
if (found) { if (found) {
wad_nlr_levels = nlevels - 1; wad_nlr_levels = nlevels - 1;
#ifdef WAD_LINUX
wad_restore_i386_registers(origframe, wad_nlr_levels);
#endif
} else { } else {
wad_nlr_levels = 0; wad_nlr_levels = 0;
} }

View file

@ -136,6 +136,7 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) {
/* if (symname) symname = wad_cplus_demangle(&wsym); */ /* if (symname) symname = wad_cplus_demangle(&wsym); */
value = wsym.value; value = wsym.value;
/* Build up some information about the exception frame */ /* Build up some information about the exception frame */
frame.frameno = n; frame.frameno = n;
@ -145,6 +146,7 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) {
frame.sp = p_sp; frame.sp = p_sp;
frame.nargs = -1; frame.nargs = -1;
frame.arg_off = 0; frame.arg_off = 0;
frame.sym_base = value + (long) ws->base;
n++; n++;
if (symname) { if (symname) {
symsize = strlen(symname)+1; symsize = strlen(symname)+1;
@ -322,8 +324,14 @@ long wad_steal_outarg(WadFrame *f, char *symbol, int argno, int *error) {
if (strcmp(SYMBOL(f),symbol) == 0) { if (strcmp(SYMBOL(f),symbol) == 0) {
/* Got a match */ /* Got a match */
if (lastf) { if (lastf) {
#ifdef WAD_SOLARIS
regs = STACK(lastf); regs = STACK(lastf);
return regs[8+argno]; return regs[8+argno];
#endif
#ifdef WAD_LINUX
regs = STACK(f);
return regs[argno+2];
#endif
} }
} }
lastf = f; lastf = f;
@ -334,3 +342,9 @@ long wad_steal_outarg(WadFrame *f, char *symbol, int argno, int *error) {
return 0; return 0;
} }

View file

@ -47,7 +47,6 @@ static void handler(int signo, WadFrame *frame, char *ret) {
break; break;
default: default:
type = (char*)"Unknown."; type = (char*)"Unknown.";
break; break;
} }
fd = (char *) frame; fd = (char *) frame;
@ -73,7 +72,14 @@ static void handler(int signo, WadFrame *frame, char *ret) {
if (f->line_number > 0) { if (f->line_number > 0) {
sprintf(temp,", line %d", f->line_number); sprintf(temp,", line %d", f->line_number);
strcat(message,temp); strcat(message,temp);
fline = f; {
int fd;
fd = open(SRCFILE(f), O_RDONLY);
if (fd > 0) {
fline = f;
}
close(fd);
}
} }
} else { } else {
if (strlen(fd+f->obj_off)) { if (strlen(fd+f->obj_off)) {