~ubuntu-branches/ubuntu/hoary/swig1.3/hoary

« back to all changes in this revision

Viewing changes to Tools/WAD/Wad/signal.c

  • Committer: Bazaar Package Importer
  • Author(s): Thom May
  • Date: 2004-08-02 15:57:10 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040802155710-bm292q1d6x6tw7gc
Tags: 1.3.21-5ubuntu1
Fix linking for ruby, python, perl and tcl bindings

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ----------------------------------------------------------------------------- 
 
2
 * signal.c
 
3
 *
 
4
 *     WAD signal handler. 
 
5
 * 
 
6
 * Author(s) : David Beazley (beazley@cs.uchicago.edu)
 
7
 *
 
8
 * Copyright (C) 2000.  The University of Chicago. 
 
9
 *
 
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.
 
14
 *
 
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.
 
19
 *
 
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
 
23
 * 
 
24
 * See the file COPYING for a complete copy of the LGPL.
 
25
 * ----------------------------------------------------------------------------- */
 
26
 
 
27
#include "wad.h"
 
28
 
 
29
static char cvs[] = "$Header: /cvsroot/SWIG/Tools/WAD/Wad/signal.c,v 1.32 2001/06/24 20:01:03 beazley Exp $";
 
30
 
 
31
extern void wad_stab_debug();
 
32
 
 
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 */
 
35
 
 
36
#ifdef WAD_LINUX
 
37
#ifndef ESP
 
38
#define ESP      7
 
39
#endif
 
40
#ifndef EBP
 
41
#define EBP      6
 
42
#endif
 
43
#ifndef EIP
 
44
#define EIP      14
 
45
#endif
 
46
#ifndef ESI
 
47
#define ESI      5
 
48
#endif
 
49
#ifndef EDI
 
50
#define EDI      4
 
51
#endif
 
52
#ifndef EBX
 
53
#define EBX      8
 
54
#endif
 
55
 
 
56
#endif
 
57
 
 
58
/* Signal handling stack */
 
59
#define STACK_SIZE 4*SIGSTKSZ
 
60
char wad_sig_stack[STACK_SIZE];
 
61
 
 
62
/* This variable is set if the signal handler thinks that the
 
63
   heap has overflowed */
 
64
 
 
65
int wad_heap_overflow = 0;
 
66
 
 
67
static void (*sig_callback)(int signo, WadFrame *data, char *ret) = 0;
 
68
 
 
69
void wad_set_callback(void (*s)(int,WadFrame *,char *ret)) {
 
70
  sig_callback = s;
 
71
}
 
72
 
 
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
 
78
   normally. */
 
79
 
 
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;
 
84
 
 
85
/* Set the return value from another module */
 
86
void wad_set_return_value(long value) {
 
87
  wad_nlr_value = value;
 
88
}
 
89
 
 
90
/* Set the return function */
 
91
void wad_set_return_func(void(*f)(void)) {
 
92
  wad_nlr_func = f;
 
93
}
 
94
 
 
95
#ifdef WAD_SOLARIS
 
96
static void nonlocalret() {
 
97
  long a;
 
98
  
 
99
  a = wad_nlr_value;
 
100
  /* We never call this procedure as a function.  This code
 
101
     causes an immediate return if someone does this */
 
102
 
 
103
  asm("jmp %i7 + 8");
 
104
  asm("restore");
 
105
 
 
106
  /* This is the real entry point */
 
107
  /*  asm(".globl _returnsignal");*/
 
108
  asm(".type   _returnsignal,2");
 
109
  asm("_returnsignal:");
 
110
 
 
111
  while (*nlr_p > 0) {
 
112
    (*nlr_p)--;
 
113
    asm("restore");
 
114
  }
 
115
 
 
116
  asm("sethi %hi(wad_nlr_value), %o0");
 
117
  asm("or %o0, %lo(wad_nlr_value), %o0");
 
118
  asm("ld [%o0], %i0");
 
119
 
 
120
  /* If there is a non-local return function.  We're going to go ahead
 
121
     and transfer control to it */
 
122
  
 
123
  if (wad_nlr_func) 
 
124
    (*wad_nlr_func)();
 
125
 
 
126
  asm("jmp %i7 + 8");
 
127
  asm("restore");
 
128
  asm(".size    _returnsignal,(.-_returnsignal)");
 
129
}
 
130
#endif
 
131
 
 
132
#ifdef WAD_LINUX
 
133
 
 
134
/* Saved values of the machine registers */
 
135
 
 
136
long   wad_saved_esi = 0;
 
137
long   wad_saved_edi = 0;
 
138
long   wad_saved_ebx = 0;
 
139
 
 
140
static void nonlocalret() {
 
141
  asm("_returnsignal:");
 
142
  while (*nlr_p > 0) {
 
143
    (*nlr_p)--;
 
144
    asm("leave");
 
145
  }
 
146
 
 
147
  if (wad_nlr_func) 
 
148
    (*wad_nlr_func)();
 
149
 
 
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");
 
155
  asm("leave");
 
156
  asm("ret");
 
157
}
 
158
 
 
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
 
165
   where they are. 
 
166
 
 
167
   The following heuristic is used:
 
168
 
 
169
   1. Each function starts with a preamble like this which saves the %ebp 
 
170
      register:
 
171
 
 
172
          55 89 e5       --->   push %ebp
 
173
                                mov  %esp, %ebp
 
174
 
 
175
   2. Next, space is allocated for local variables, using one of two schemes:
 
176
 
 
177
          83 ec xx       --->  Less than 256 bytes of local storage
 
178
                ^^^
 
179
                length
 
180
 
 
181
          81 ec xx xx xx xx  --> More than 256 bytes of local storage
 
182
                ^^^^^^^^^^^
 
183
                   length
 
184
 
 
185
   3. After this, a collection of 1-byte stack push op codes might appear
 
186
          
 
187
          56      = pushl %esi
 
188
          57      = pushl %edi
 
189
          53      = pushl %ebx
 
190
 
 
191
 
 
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
 
195
   their proper values.
 
196
*/
 
197
 
 
198
void wad_restore_i386_registers(WadFrame *f, int nlevels) {
 
199
  WadFrame *lastf = f;
 
200
  int       localsize = 0;
 
201
  unsigned char     *pc;
 
202
  unsigned long     *saved;
 
203
  int i, j;
 
204
  int pci;
 
205
  for (i = 0; i <= nlevels; i++, f=f->next) {
 
206
 
 
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)); */
 
210
    if (!pc) continue;
 
211
 
 
212
    /* Look for the standard prologue 0x55 0x89 0xe5 */
 
213
    if ((pc[0] == 0x55) && (pc[1] == 0x89) && (pc[2] == 0xe5)) {
 
214
      /* Determine the size */
 
215
      pci = 3;
 
216
      if ((pc[3] == 0x83) && (pc[4] == 0xec)) {
 
217
        /*      printf("8-bit size\n");*/
 
218
        localsize = (int) pc[5];
 
219
        pci = 6;
 
220
      } 
 
221
      if ((pc[3] == 0x81) && (pc[4] == 0xec)) {
 
222
        /*      printf("32-bit size\n"); */
 
223
        localsize = (int) *((long *) (pc+5));
 
224
        pci = 10;
 
225
      }
 
226
      saved = (long *) (f->fp - localsize - sizeof(long));
 
227
      /*      printf("saved = %x, fp = %x\n", saved, f->fp);
 
228
      printf("localsize = %d\n", localsize);
 
229
      */
 
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); */
 
234
        }
 
235
        else if (pc[pci] == 0x56) {
 
236
          wad_saved_esi = *saved;
 
237
          /*      printf("restored esi = %x\n", wad_saved_esi); */
 
238
        }
 
239
        else if (pc[pci] == 0x53) {
 
240
          wad_saved_ebx = *saved;
 
241
          /*      printf("restored ebx = %x\n", wad_saved_ebx); */
 
242
        }
 
243
        else break;
 
244
      }
 
245
    }
 
246
  }
 
247
}
 
248
 
 
249
#endif
 
250
 
 
251
void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
 
252
  greg_t  *pc;
 
253
  greg_t  *npc;
 
254
  greg_t  *sp;
 
255
  greg_t  *fp;
 
256
#ifdef WAD_LINUX
 
257
  greg_t  *esi;
 
258
  greg_t  *edi;
 
259
  greg_t  *ebx;
 
260
#endif
 
261
 
 
262
  unsigned long   addr;
 
263
  ucontext_t      *context;
 
264
  unsigned long   p_sp;        /* process stack pointer   */
 
265
  unsigned long   p_pc;        /* Process program counter */
 
266
  unsigned long   p_fp;        /* Process frame pointer   */
 
267
  int      nlevels = 0;
 
268
  int      found = 0;
 
269
  void     _returnsignal();
 
270
  WadFrame  *frame, *origframe;
 
271
  char      *framedata;
 
272
  char      *retname = 0;
 
273
  unsigned long current_brk;
 
274
 
 
275
  /* Reset all of the signals while running WAD */
 
276
  wad_signal_clear();
 
277
 
 
278
  wad_nlr_func = 0;
 
279
 
 
280
  context = (ucontext_t *) vcontext;
 
281
 
 
282
  wad_printf("WAD: Collecting debugging information...\n");
 
283
 
 
284
  /* Read the segments */
 
285
  if (wad_segment_read() < 0) {
 
286
    wad_printf("WAD: Unable to read segment map\n");
 
287
    return;
 
288
  }
 
289
 
 
290
  if (wad_debug_mode & DEBUG_SIGNAL) {
 
291
    wad_printf("WAD: siginfo = %x, context = %x\n", si, vcontext);
 
292
  }
 
293
  
 
294
  current_brk = (long) sbrk(0);
 
295
 
 
296
  /* Get some information about the current context */
 
297
 
 
298
#ifdef WAD_SOLARIS
 
299
  pc = &((context->uc_mcontext).gregs[REG_PC]);
 
300
  npc = &((context->uc_mcontext).gregs[REG_nPC]);
 
301
  sp = &((context->uc_mcontext).gregs[REG_SP]);
 
302
#endif
 
303
 
 
304
#ifdef WAD_LINUX
 
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]);       
 
311
  
 
312
  wad_saved_esi = (unsigned long) (*esi);
 
313
  wad_saved_edi = (unsigned long) (*edi);
 
314
  wad_saved_ebx = (unsigned long) (*ebx);
 
315
 
 
316
  /*  printf("esi = %x, edi = %x, ebx = %x\n", wad_saved_esi, wad_saved_edi, wad_saved_ebx); */
 
317
 
 
318
  /*   printf("&sp = %x, &pc = %x\n", sp, pc); */
 
319
#endif
 
320
  
 
321
  /* Get some information out of the signal handler stack */
 
322
  addr = (unsigned long) si->si_addr;
 
323
 
 
324
  /* See if this might be a stack overflow */
 
325
 
 
326
  p_pc = (unsigned long) (*pc);
 
327
  p_sp = (unsigned long) (*sp);
 
328
#ifdef WAD_LINUX
 
329
  p_fp = (unsigned long) (*fp);
 
330
#endif
 
331
#ifdef WAD_SOLARIS
 
332
  p_fp = (unsigned long) *(((long *) p_sp) + 14);
 
333
#endif
 
334
  
 
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);
 
337
  }
 
338
  frame = wad_stack_trace(p_pc, p_sp, p_fp);
 
339
 
 
340
  if (!frame) {
 
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");
 
344
    wad_signal_clear();
 
345
    return;
 
346
  }
 
347
 
 
348
  {
 
349
    WadFrame *f = frame;
 
350
    while (f) {
 
351
      wad_find_object(f);
 
352
      wad_find_symbol(f);
 
353
      f = f->next;
 
354
    }
 
355
    f = frame;
 
356
    while (f) {
 
357
      wad_find_debug(f);
 
358
      wad_build_vars(f);
 
359
      f = f->next;
 
360
    }
 
361
  }
 
362
  wad_heap_overflow = 0;
 
363
  if (sig == SIGSEGV) {
 
364
    if (addr >= current_brk) wad_heap_overflow = 1;
 
365
  }
 
366
 
 
367
  wad_stack_debug(frame);
 
368
 
 
369
  /* Generate debugging strings */
 
370
  wad_debug_make_strings(frame);
 
371
  
 
372
  wad_stab_debug();
 
373
 
 
374
  /* Walk the exception frames and try to find a return point */
 
375
  origframe = frame;
 
376
  while (frame) {
 
377
    WadReturnFunc *wr = wad_check_return(frame->sym_name);
 
378
    if (wr) {
 
379
      found = 1;
 
380
      wad_nlr_value = wr->value;
 
381
      retname = wr->name;
 
382
    }
 
383
    if (found) {
 
384
      frame->last = 1;   /* Cut off top of the stack trace */
 
385
      break;
 
386
    }
 
387
    frame = frame->next;
 
388
    nlevels++;
 
389
  }
 
390
  
 
391
 
 
392
  if (found) {
 
393
    wad_nlr_levels = nlevels - 1;
 
394
#ifdef WAD_LINUX
 
395
    wad_restore_i386_registers(origframe, wad_nlr_levels);
 
396
#endif
 
397
  } else {
 
398
    wad_nlr_levels = -1;
 
399
  }
 
400
 
 
401
  wad_string_debug();
 
402
  wad_memory_debug();
 
403
 
 
404
  /* Before we do anything with callbacks, we are going
 
405
     to attempt to dump a wad-core */
 
406
  
 
407
  {
 
408
    int fd;
 
409
    static int already = 0;
 
410
    fd = open("wadtrace",O_WRONLY | O_CREAT | (already*O_APPEND) | ((already==0)*O_TRUNC),0666);
 
411
    if (fd > 0) {
 
412
      wad_dump_trace(fd,sig,origframe,retname);
 
413
      close(fd);
 
414
      already=1;
 
415
    }
 
416
  }
 
417
 
 
418
  if (sig_callback) {
 
419
    (*sig_callback)(sig,origframe,retname);
 
420
  } else {
 
421
    /* No signal handler defined.  Go invoke the default */
 
422
 
 
423
    wad_default_callback(sig, origframe,retname);
 
424
  }
 
425
 
 
426
  if (wad_debug_mode & DEBUG_HOLD) while(1);
 
427
 
 
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. */
 
431
 
 
432
  if (wad_nlr_levels >= 0) {
 
433
    *(pc) = (greg_t) _returnsignal;
 
434
#ifdef WAD_SOLARIS
 
435
    *(npc) = *(pc) + 4;
 
436
#endif
 
437
    if (!(wad_debug_mode & DEBUG_ONESHOT)) {
 
438
      wad_signal_init();
 
439
    }
 
440
    return;
 
441
  }
 
442
  exit(1);
 
443
}
 
444
 
 
445
 
 
446
/* -----------------------------------------------------------------------------
 
447
 * wad_signal_init()
 
448
 *
 
449
 * Resets the signal handler.
 
450
 * ----------------------------------------------------------------------------- */
 
451
 
 
452
void wad_signal_init() {
 
453
  struct sigaction newvec;
 
454
  static stack_t  sigstk;
 
455
  static int      initstack = 0;
 
456
 
 
457
  if (wad_debug_mode & DEBUG_INIT) {
 
458
    wad_printf("WAD: Initializing signal handler.\n");
 
459
  }
 
460
  /* This is buggy in Linux and threads.  disabled by default */
 
461
 
 
462
#ifndef WAD_LINUX
 
463
 
 
464
  if (!initstack) {
 
465
    /* Set up an alternative stack */
 
466
    
 
467
    sigstk.ss_sp = (char *) wad_sig_stack;
 
468
    sigstk.ss_size = STACK_SIZE;
 
469
    sigstk.ss_flags = 0;
 
470
    if (!(wad_debug_mode & DEBUG_NOSTACK)) {
 
471
      if (sigaltstack(&sigstk, (stack_t*)0) < 0) {
 
472
        perror("sigaltstack");
 
473
      }
 
474
    }
 
475
    initstack=1;
 
476
  }
 
477
#endif
 
478
 
 
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;
 
486
 
 
487
  if (wad_debug_mode & DEBUG_ONESHOT) {
 
488
    newvec.sa_flags |= SA_RESETHAND;
 
489
  }
 
490
#ifndef WAD_LINUX
 
491
  if (!(wad_debug_mode & DEBUG_NOSTACK)) {
 
492
    newvec.sa_flags |= SA_ONSTACK;
 
493
  } 
 
494
#endif
 
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;
 
501
  
 
502
  return;
 
503
 werror:
 
504
  wad_printf("WAD: Couldn't install signal handler!\n");
 
505
}
 
506
 
 
507
/* -----------------------------------------------------------------------------
 
508
 * clear signals 
 
509
 * ----------------------------------------------------------------------------- */
 
510
 
 
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);  
 
517
}
 
518
 
 
519
 
 
520