1
/* -----------------------------------------------------------------------------
6
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
8
* Copyright (C) 2000. The University of Chicago.
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public
12
* License as published by the Free Software Foundation; either
13
* version 2.1 of the License, or (at your option) any later version.
15
* This library is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this library; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
* See the file COPYING for a complete copy of the LGPL.
25
* ----------------------------------------------------------------------------- */
29
static char cvs[] = "$Header: /cvsroot/SWIG/Tools/WAD/Wad/signal.c,v 1.32 2001/06/24 20:01:03 beazley Exp $";
31
extern void wad_stab_debug();
33
/* For some odd reason, certain linux distributions do not seem to define the
34
register constants in a way that is easily accessible to us. This is a hack */
58
/* Signal handling stack */
59
#define STACK_SIZE 4*SIGSTKSZ
60
char wad_sig_stack[STACK_SIZE];
62
/* This variable is set if the signal handler thinks that the
63
heap has overflowed */
65
int wad_heap_overflow = 0;
67
static void (*sig_callback)(int signo, WadFrame *data, char *ret) = 0;
69
void wad_set_callback(void (*s)(int,WadFrame *,char *ret)) {
73
/* This bit of nastiness is used to make a non-local return from the
74
signal handler to a configurable location on the call stack. In a nutshell,
75
this works by repeatedly calling "restore" to roll back the
76
register windows and stack pointer. Then we fake a return value and
77
return to the caller as if the function had actually completed
80
int wad_nlr_levels = 0;
81
static volatile int *volatile nlr_p = &wad_nlr_levels;
82
long wad_nlr_value = 0;
83
void (*wad_nlr_func)(void) = 0;
85
/* Set the return value from another module */
86
void wad_set_return_value(long value) {
87
wad_nlr_value = value;
90
/* Set the return function */
91
void wad_set_return_func(void(*f)(void)) {
96
static void nonlocalret() {
100
/* We never call this procedure as a function. This code
101
causes an immediate return if someone does this */
106
/* This is the real entry point */
107
/* asm(".globl _returnsignal");*/
108
asm(".type _returnsignal,2");
109
asm("_returnsignal:");
116
asm("sethi %hi(wad_nlr_value), %o0");
117
asm("or %o0, %lo(wad_nlr_value), %o0");
118
asm("ld [%o0], %i0");
120
/* If there is a non-local return function. We're going to go ahead
121
and transfer control to it */
128
asm(".size _returnsignal,(.-_returnsignal)");
134
/* Saved values of the machine registers */
136
long wad_saved_esi = 0;
137
long wad_saved_edi = 0;
138
long wad_saved_ebx = 0;
140
static void nonlocalret() {
141
asm("_returnsignal:");
150
/* Restore the registers */
151
asm("movl wad_saved_esi, %esi");
152
asm("movl wad_saved_edi, %edi");
153
asm("movl wad_saved_ebx, %ebx");
154
asm("movl wad_nlr_value, %eax");
159
/* This function uses a heuristic to restore the callee-save registers on i386.
160
According to the Linux Assembly HOWTO, the %esi, %edi, %ebx, and %ebp registers
161
are callee-saved. All others are caller saved. To restore the callee-save
162
registers, we use the fact that the C compiler saves the callee-save registers
163
(if any) at the beginning of function execution. Therefore, we can scan the
164
instructions at the start of each function in the stack trace to try and find
167
The following heuristic is used:
169
1. Each function starts with a preamble like this which saves the %ebp
172
55 89 e5 ---> push %ebp
175
2. Next, space is allocated for local variables, using one of two schemes:
177
83 ec xx ---> Less than 256 bytes of local storage
181
81 ec xx xx xx xx --> More than 256 bytes of local storage
185
3. After this, a collection of 1-byte stack push op codes might appear
192
Based on the size of local variable storage and the order in which
193
the %esi, %edi, and %ebx registers are pushed on the stack, we can
194
determine where in memory the registers are saved and restore them to
198
void wad_restore_i386_registers(WadFrame *f, int nlevels) {
202
unsigned long *saved;
205
for (i = 0; i <= nlevels; i++, f=f->next) {
207
/* This gets the starting instruction for the stack frame */
208
pc = (unsigned char *) f->sym_base;
209
/* printf("pc = %x, base = %x, %s\n", f->pc, f->sym_base, SYMBOL(f)); */
212
/* Look for the standard prologue 0x55 0x89 0xe5 */
213
if ((pc[0] == 0x55) && (pc[1] == 0x89) && (pc[2] == 0xe5)) {
214
/* Determine the size */
216
if ((pc[3] == 0x83) && (pc[4] == 0xec)) {
217
/* printf("8-bit size\n");*/
218
localsize = (int) pc[5];
221
if ((pc[3] == 0x81) && (pc[4] == 0xec)) {
222
/* printf("32-bit size\n"); */
223
localsize = (int) *((long *) (pc+5));
226
saved = (long *) (f->fp - localsize - sizeof(long));
227
/* printf("saved = %x, fp = %x\n", saved, f->fp);
228
printf("localsize = %d\n", localsize);
230
for (j = 0; j < 3; j++, saved--, pci++) {
231
if (pc[pci] == 0x57) {
232
wad_saved_edi = *saved;
233
/* printf("restored edi = %x\n", wad_saved_edi); */
235
else if (pc[pci] == 0x56) {
236
wad_saved_esi = *saved;
237
/* printf("restored esi = %x\n", wad_saved_esi); */
239
else if (pc[pci] == 0x53) {
240
wad_saved_ebx = *saved;
241
/* printf("restored ebx = %x\n", wad_saved_ebx); */
251
void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
264
unsigned long p_sp; /* process stack pointer */
265
unsigned long p_pc; /* Process program counter */
266
unsigned long p_fp; /* Process frame pointer */
269
void _returnsignal();
270
WadFrame *frame, *origframe;
273
unsigned long current_brk;
275
/* Reset all of the signals while running WAD */
280
context = (ucontext_t *) vcontext;
282
wad_printf("WAD: Collecting debugging information...\n");
284
/* Read the segments */
285
if (wad_segment_read() < 0) {
286
wad_printf("WAD: Unable to read segment map\n");
290
if (wad_debug_mode & DEBUG_SIGNAL) {
291
wad_printf("WAD: siginfo = %x, context = %x\n", si, vcontext);
294
current_brk = (long) sbrk(0);
296
/* Get some information about the current context */
299
pc = &((context->uc_mcontext).gregs[REG_PC]);
300
npc = &((context->uc_mcontext).gregs[REG_nPC]);
301
sp = &((context->uc_mcontext).gregs[REG_SP]);
305
sp = &((context->uc_mcontext).gregs[ESP]); /* Top of stack */
306
fp = &((context->uc_mcontext).gregs[EBP]); /* Stack base - frame pointer */
307
pc = &((context->uc_mcontext).gregs[EIP]); /* Current instruction */
308
esi = &((context->uc_mcontext).gregs[ESI]);
309
edi = &((context->uc_mcontext).gregs[EDI]);
310
ebx = &((context->uc_mcontext).gregs[EBX]);
312
wad_saved_esi = (unsigned long) (*esi);
313
wad_saved_edi = (unsigned long) (*edi);
314
wad_saved_ebx = (unsigned long) (*ebx);
316
/* printf("esi = %x, edi = %x, ebx = %x\n", wad_saved_esi, wad_saved_edi, wad_saved_ebx); */
318
/* printf("&sp = %x, &pc = %x\n", sp, pc); */
321
/* Get some information out of the signal handler stack */
322
addr = (unsigned long) si->si_addr;
324
/* See if this might be a stack overflow */
326
p_pc = (unsigned long) (*pc);
327
p_sp = (unsigned long) (*sp);
329
p_fp = (unsigned long) (*fp);
332
p_fp = (unsigned long) *(((long *) p_sp) + 14);
335
if (wad_debug_mode & DEBUG_SIGNAL) {
336
wad_printf("fault at address %x, pc = %x, sp = %x, fp = %x\n", addr, p_pc, p_sp, p_fp);
338
frame = wad_stack_trace(p_pc, p_sp, p_fp);
341
/* We're really hosed. Not possible to generate a stack trace */
342
wad_printf("WAD: Unable to generate stack trace.\n");
343
wad_printf("WAD: Maybe the call stack has been corrupted by buffer overflow.\n");
362
wad_heap_overflow = 0;
363
if (sig == SIGSEGV) {
364
if (addr >= current_brk) wad_heap_overflow = 1;
367
wad_stack_debug(frame);
369
/* Generate debugging strings */
370
wad_debug_make_strings(frame);
374
/* Walk the exception frames and try to find a return point */
377
WadReturnFunc *wr = wad_check_return(frame->sym_name);
380
wad_nlr_value = wr->value;
384
frame->last = 1; /* Cut off top of the stack trace */
393
wad_nlr_levels = nlevels - 1;
395
wad_restore_i386_registers(origframe, wad_nlr_levels);
404
/* Before we do anything with callbacks, we are going
405
to attempt to dump a wad-core */
409
static int already = 0;
410
fd = open("wadtrace",O_WRONLY | O_CREAT | (already*O_APPEND) | ((already==0)*O_TRUNC),0666);
412
wad_dump_trace(fd,sig,origframe,retname);
419
(*sig_callback)(sig,origframe,retname);
421
/* No signal handler defined. Go invoke the default */
423
wad_default_callback(sig, origframe,retname);
426
if (wad_debug_mode & DEBUG_HOLD) while(1);
428
/* If we found a function to which we should return, we jump to
429
an alternative piece of code that unwinds the stack and
430
initiates a non-local return. */
432
if (wad_nlr_levels >= 0) {
433
*(pc) = (greg_t) _returnsignal;
437
if (!(wad_debug_mode & DEBUG_ONESHOT)) {
446
/* -----------------------------------------------------------------------------
449
* Resets the signal handler.
450
* ----------------------------------------------------------------------------- */
452
void wad_signal_init() {
453
struct sigaction newvec;
454
static stack_t sigstk;
455
static int initstack = 0;
457
if (wad_debug_mode & DEBUG_INIT) {
458
wad_printf("WAD: Initializing signal handler.\n");
460
/* This is buggy in Linux and threads. disabled by default */
465
/* Set up an alternative stack */
467
sigstk.ss_sp = (char *) wad_sig_stack;
468
sigstk.ss_size = STACK_SIZE;
470
if (!(wad_debug_mode & DEBUG_NOSTACK)) {
471
if (sigaltstack(&sigstk, (stack_t*)0) < 0) {
472
perror("sigaltstack");
479
sigemptyset(&newvec.sa_mask);
480
sigaddset(&newvec.sa_mask, SIGSEGV);
481
sigaddset(&newvec.sa_mask, SIGBUS);
482
sigaddset(&newvec.sa_mask, SIGABRT);
483
sigaddset(&newvec.sa_mask, SIGILL);
484
sigaddset(&newvec.sa_mask, SIGFPE);
485
newvec.sa_flags = SA_SIGINFO;
487
if (wad_debug_mode & DEBUG_ONESHOT) {
488
newvec.sa_flags |= SA_RESETHAND;
491
if (!(wad_debug_mode & DEBUG_NOSTACK)) {
492
newvec.sa_flags |= SA_ONSTACK;
495
newvec.sa_sigaction = ((void (*)(int,siginfo_t *, void *)) wad_signalhandler);
496
if (sigaction(SIGSEGV, &newvec, NULL) < 0) goto werror;
497
if (sigaction(SIGBUS, &newvec, NULL) < 0) goto werror;
498
if (sigaction(SIGABRT, &newvec, NULL) < 0) goto werror;
499
if (sigaction(SIGFPE, &newvec, NULL) < 0) goto werror;
500
if (sigaction(SIGILL, &newvec, NULL) < 0) goto werror;
504
wad_printf("WAD: Couldn't install signal handler!\n");
507
/* -----------------------------------------------------------------------------
509
* ----------------------------------------------------------------------------- */
511
void wad_signal_clear() {
512
signal(SIGSEGV, SIG_DFL);
513
signal(SIGBUS, SIG_DFL);
514
signal(SIGILL, SIG_DFL);
515
signal(SIGFPE, SIG_DFL);
516
signal(SIGABRT, SIG_DFL);