PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/wad-0-2-1/SWIG/Tools/WAD/Wad/signal.c

#
C | 520 lines | 313 code | 85 blank | 122 comment | 61 complexity | 6cd16ad447ddb6b1ed34fd1a874ea3af MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
  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. #include "wad.h"
  27. static char cvs[] = "$Header$";
  28. extern void wad_stab_debug();
  29. /* For some odd reason, certain linux distributions do not seem to define the
  30. register constants in a way that is easily accessible to us. This is a hack */
  31. #ifdef WAD_LINUX
  32. #ifndef ESP
  33. #define ESP 7
  34. #endif
  35. #ifndef EBP
  36. #define EBP 6
  37. #endif
  38. #ifndef EIP
  39. #define EIP 14
  40. #endif
  41. #ifndef ESI
  42. #define ESI 5
  43. #endif
  44. #ifndef EDI
  45. #define EDI 4
  46. #endif
  47. #ifndef EBX
  48. #define EBX 8
  49. #endif
  50. #endif
  51. /* Signal handling stack */
  52. #define STACK_SIZE 4*SIGSTKSZ
  53. char wad_sig_stack[STACK_SIZE];
  54. /* This variable is set if the signal handler thinks that the
  55. heap has overflowed */
  56. int wad_heap_overflow = 0;
  57. static void (*sig_callback)(int signo, WadFrame *data, char *ret) = 0;
  58. void wad_set_callback(void (*s)(int,WadFrame *,char *ret)) {
  59. sig_callback = s;
  60. }
  61. /* This bit of nastiness is used to make a non-local return from the
  62. signal handler to a configurable location on the call stack. In a nutshell,
  63. this works by repeatedly calling "restore" to roll back the
  64. register windows and stack pointer. Then we fake a return value and
  65. return to the caller as if the function had actually completed
  66. normally. */
  67. int wad_nlr_levels = 0;
  68. static volatile int *volatile nlr_p = &wad_nlr_levels;
  69. long wad_nlr_value = 0;
  70. void (*wad_nlr_func)(void) = 0;
  71. /* Set the return value from another module */
  72. void wad_set_return_value(long value) {
  73. wad_nlr_value = value;
  74. }
  75. /* Set the return function */
  76. void wad_set_return_func(void(*f)(void)) {
  77. wad_nlr_func = f;
  78. }
  79. #ifdef WAD_SOLARIS
  80. static void nonlocalret() {
  81. long a;
  82. a = wad_nlr_value;
  83. /* We never call this procedure as a function. This code
  84. causes an immediate return if someone does this */
  85. asm("jmp %i7 + 8");
  86. asm("restore");
  87. /* This is the real entry point */
  88. /* asm(".globl _returnsignal");*/
  89. asm(".type _returnsignal,2");
  90. asm("_returnsignal:");
  91. while (*nlr_p > 0) {
  92. (*nlr_p)--;
  93. asm("restore");
  94. }
  95. asm("sethi %hi(wad_nlr_value), %o0");
  96. asm("or %o0, %lo(wad_nlr_value), %o0");
  97. asm("ld [%o0], %i0");
  98. /* If there is a non-local return function. We're going to go ahead
  99. and transfer control to it */
  100. if (wad_nlr_func)
  101. (*wad_nlr_func)();
  102. asm("jmp %i7 + 8");
  103. asm("restore");
  104. asm(".size _returnsignal,(.-_returnsignal)");
  105. }
  106. #endif
  107. #ifdef WAD_LINUX
  108. /* Saved values of the machine registers */
  109. long wad_saved_esi = 0;
  110. long wad_saved_edi = 0;
  111. long wad_saved_ebx = 0;
  112. static void nonlocalret() {
  113. asm("_returnsignal:");
  114. while (*nlr_p > 0) {
  115. (*nlr_p)--;
  116. asm("leave");
  117. }
  118. if (wad_nlr_func)
  119. (*wad_nlr_func)();
  120. /* Restore the registers */
  121. asm("movl wad_saved_esi, %esi");
  122. asm("movl wad_saved_edi, %edi");
  123. asm("movl wad_saved_ebx, %ebx");
  124. asm("movl wad_nlr_value, %eax");
  125. asm("leave");
  126. asm("ret");
  127. }
  128. /* This function uses a heuristic to restore the callee-save registers on i386.
  129. According to the Linux Assembly HOWTO, the %esi, %edi, %ebx, and %ebp registers
  130. are callee-saved. All others are caller saved. To restore the callee-save
  131. registers, we use the fact that the C compiler saves the callee-save registers
  132. (if any) at the beginning of function execution. Therefore, we can scan the
  133. instructions at the start of each function in the stack trace to try and find
  134. where they are.
  135. The following heuristic is used:
  136. 1. Each function starts with a preamble like this which saves the %ebp
  137. register:
  138. 55 89 e5 ---> push %ebp
  139. mov %esp, %ebp
  140. 2. Next, space is allocated for local variables, using one of two schemes:
  141. 83 ec xx ---> Less than 256 bytes of local storage
  142. ^^^
  143. length
  144. 81 ec xx xx xx xx --> More than 256 bytes of local storage
  145. ^^^^^^^^^^^
  146. length
  147. 3. After this, a collection of 1-byte stack push op codes might appear
  148. 56 = pushl %esi
  149. 57 = pushl %edi
  150. 53 = pushl %ebx
  151. Based on the size of local variable storage and the order in which
  152. the %esi, %edi, and %ebx registers are pushed on the stack, we can
  153. determine where in memory the registers are saved and restore them to
  154. their proper values.
  155. */
  156. void wad_restore_i386_registers(WadFrame *f, int nlevels) {
  157. WadFrame *lastf = f;
  158. int localsize = 0;
  159. unsigned char *pc;
  160. unsigned long *saved;
  161. int i, j;
  162. int pci;
  163. for (i = 0; i <= nlevels; i++, f=f->next) {
  164. /* This gets the starting instruction for the stack frame */
  165. pc = (unsigned char *) f->sym_base;
  166. /* printf("pc = %x, base = %x, %s\n", f->pc, f->sym_base, SYMBOL(f)); */
  167. if (!pc) continue;
  168. /* Look for the standard prologue 0x55 0x89 0xe5 */
  169. if ((pc[0] == 0x55) && (pc[1] == 0x89) && (pc[2] == 0xe5)) {
  170. /* Determine the size */
  171. pci = 3;
  172. if ((pc[3] == 0x83) && (pc[4] == 0xec)) {
  173. /* printf("8-bit size\n");*/
  174. localsize = (int) pc[5];
  175. pci = 6;
  176. }
  177. if ((pc[3] == 0x81) && (pc[4] == 0xec)) {
  178. /* printf("32-bit size\n"); */
  179. localsize = (int) *((long *) (pc+5));
  180. pci = 10;
  181. }
  182. saved = (long *) (f->fp - localsize - sizeof(long));
  183. /* printf("saved = %x, fp = %x\n", saved, f->fp);
  184. printf("localsize = %d\n", localsize);
  185. */
  186. for (j = 0; j < 3; j++, saved--, pci++) {
  187. if (pc[pci] == 0x57) {
  188. wad_saved_edi = *saved;
  189. /* printf("restored edi = %x\n", wad_saved_edi); */
  190. }
  191. else if (pc[pci] == 0x56) {
  192. wad_saved_esi = *saved;
  193. /* printf("restored esi = %x\n", wad_saved_esi); */
  194. }
  195. else if (pc[pci] == 0x53) {
  196. wad_saved_ebx = *saved;
  197. /* printf("restored ebx = %x\n", wad_saved_ebx); */
  198. }
  199. else break;
  200. }
  201. }
  202. }
  203. }
  204. #endif
  205. void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) {
  206. greg_t *pc;
  207. greg_t *npc;
  208. greg_t *sp;
  209. greg_t *fp;
  210. #ifdef WAD_LINUX
  211. greg_t *esi;
  212. greg_t *edi;
  213. greg_t *ebx;
  214. #endif
  215. unsigned long addr;
  216. ucontext_t *context;
  217. unsigned long p_sp; /* process stack pointer */
  218. unsigned long p_pc; /* Process program counter */
  219. unsigned long p_fp; /* Process frame pointer */
  220. int nlevels = 0;
  221. int found = 0;
  222. void _returnsignal();
  223. WadFrame *frame, *origframe;
  224. char *framedata;
  225. char *retname = 0;
  226. unsigned long current_brk;
  227. /* Reset all of the signals while running WAD */
  228. wad_signal_clear();
  229. wad_nlr_func = 0;
  230. context = (ucontext_t *) vcontext;
  231. wad_printf("WAD: Collecting debugging information...\n");
  232. /* Read the segments */
  233. if (wad_segment_read() < 0) {
  234. wad_printf("WAD: Unable to read segment map\n");
  235. return;
  236. }
  237. if (wad_debug_mode & DEBUG_SIGNAL) {
  238. wad_printf("WAD: siginfo = %x, context = %x\n", si, vcontext);
  239. }
  240. current_brk = (long) sbrk(0);
  241. /* Get some information about the current context */
  242. #ifdef WAD_SOLARIS
  243. pc = &((context->uc_mcontext).gregs[REG_PC]);
  244. npc = &((context->uc_mcontext).gregs[REG_nPC]);
  245. sp = &((context->uc_mcontext).gregs[REG_SP]);
  246. #endif
  247. #ifdef WAD_LINUX
  248. sp = &((context->uc_mcontext).gregs[ESP]); /* Top of stack */
  249. fp = &((context->uc_mcontext).gregs[EBP]); /* Stack base - frame pointer */
  250. pc = &((context->uc_mcontext).gregs[EIP]); /* Current instruction */
  251. esi = &((context->uc_mcontext).gregs[ESI]);
  252. edi = &((context->uc_mcontext).gregs[EDI]);
  253. ebx = &((context->uc_mcontext).gregs[EBX]);
  254. wad_saved_esi = (unsigned long) (*esi);
  255. wad_saved_edi = (unsigned long) (*edi);
  256. wad_saved_ebx = (unsigned long) (*ebx);
  257. /* printf("esi = %x, edi = %x, ebx = %x\n", wad_saved_esi, wad_saved_edi, wad_saved_ebx); */
  258. /* printf("&sp = %x, &pc = %x\n", sp, pc); */
  259. #endif
  260. /* Get some information out of the signal handler stack */
  261. addr = (unsigned long) si->si_addr;
  262. /* See if this might be a stack overflow */
  263. p_pc = (unsigned long) (*pc);
  264. p_sp = (unsigned long) (*sp);
  265. #ifdef WAD_LINUX
  266. p_fp = (unsigned long) (*fp);
  267. #endif
  268. #ifdef WAD_SOLARIS
  269. p_fp = (unsigned long) *(((long *) p_sp) + 14);
  270. #endif
  271. if (wad_debug_mode & DEBUG_SIGNAL) {
  272. wad_printf("fault at address %x, pc = %x, sp = %x, fp = %x\n", addr, p_pc, p_sp, p_fp);
  273. }
  274. frame = wad_stack_trace(p_pc, p_sp, p_fp);
  275. if (!frame) {
  276. /* We're really hosed. Not possible to generate a stack trace */
  277. wad_printf("WAD: Unable to generate stack trace.\n");
  278. wad_printf("WAD: Maybe the call stack has been corrupted by buffer overflow.\n");
  279. wad_signal_clear();
  280. return;
  281. }
  282. {
  283. WadFrame *f = frame;
  284. while (f) {
  285. wad_find_object(f);
  286. wad_find_symbol(f);
  287. f = f->next;
  288. }
  289. f = frame;
  290. while (f) {
  291. wad_find_debug(f);
  292. wad_build_vars(f);
  293. f = f->next;
  294. }
  295. }
  296. wad_heap_overflow = 0;
  297. if (sig == SIGSEGV) {
  298. if (addr >= current_brk) wad_heap_overflow = 1;
  299. }
  300. wad_stack_debug(frame);
  301. /* Generate debugging strings */
  302. wad_debug_make_strings(frame);
  303. wad_stab_debug();
  304. /* Walk the exception frames and try to find a return point */
  305. origframe = frame;
  306. while (frame) {
  307. WadReturnFunc *wr = wad_check_return(frame->sym_name);
  308. if (wr) {
  309. found = 1;
  310. wad_nlr_value = wr->value;
  311. retname = wr->name;
  312. }
  313. if (found) {
  314. frame->last = 1; /* Cut off top of the stack trace */
  315. break;
  316. }
  317. frame = frame->next;
  318. nlevels++;
  319. }
  320. if (found) {
  321. wad_nlr_levels = nlevels - 1;
  322. #ifdef WAD_LINUX
  323. wad_restore_i386_registers(origframe, wad_nlr_levels);
  324. #endif
  325. } else {
  326. wad_nlr_levels = -1;
  327. }
  328. wad_string_debug();
  329. wad_memory_debug();
  330. /* Before we do anything with callbacks, we are going
  331. to attempt to dump a wad-core */
  332. {
  333. int fd;
  334. static int already = 0;
  335. fd = open("wadtrace",O_WRONLY | O_CREAT | (already*O_APPEND) | ((already==0)*O_TRUNC),0666);
  336. if (fd > 0) {
  337. wad_dump_trace(fd,sig,origframe,retname);
  338. close(fd);
  339. already=1;
  340. }
  341. }
  342. if (sig_callback) {
  343. (*sig_callback)(sig,origframe,retname);
  344. } else {
  345. /* No signal handler defined. Go invoke the default */
  346. wad_default_callback(sig, origframe,retname);
  347. }
  348. if (wad_debug_mode & DEBUG_HOLD) while(1);
  349. /* If we found a function to which we should return, we jump to
  350. an alternative piece of code that unwinds the stack and
  351. initiates a non-local return. */
  352. if (wad_nlr_levels >= 0) {
  353. *(pc) = (greg_t) _returnsignal;
  354. #ifdef WAD_SOLARIS
  355. *(npc) = *(pc) + 4;
  356. #endif
  357. if (!(wad_debug_mode & DEBUG_ONESHOT)) {
  358. wad_signal_init();
  359. }
  360. return;
  361. }
  362. exit(1);
  363. }
  364. /* -----------------------------------------------------------------------------
  365. * wad_signal_init()
  366. *
  367. * Resets the signal handler.
  368. * ----------------------------------------------------------------------------- */
  369. void wad_signal_init() {
  370. struct sigaction newvec;
  371. static stack_t sigstk;
  372. static int initstack = 0;
  373. if (wad_debug_mode & DEBUG_INIT) {
  374. wad_printf("WAD: Initializing signal handler.\n");
  375. }
  376. /* This is buggy in Linux and threads. disabled by default */
  377. #ifndef WAD_LINUX
  378. if (!initstack) {
  379. /* Set up an alternative stack */
  380. sigstk.ss_sp = (char *) wad_sig_stack;
  381. sigstk.ss_size = STACK_SIZE;
  382. sigstk.ss_flags = 0;
  383. if (!(wad_debug_mode & DEBUG_NOSTACK)) {
  384. if (sigaltstack(&sigstk, (stack_t*)0) < 0) {
  385. perror("sigaltstack");
  386. }
  387. }
  388. initstack=1;
  389. }
  390. #endif
  391. sigemptyset(&newvec.sa_mask);
  392. sigaddset(&newvec.sa_mask, SIGSEGV);
  393. sigaddset(&newvec.sa_mask, SIGBUS);
  394. sigaddset(&newvec.sa_mask, SIGABRT);
  395. sigaddset(&newvec.sa_mask, SIGILL);
  396. sigaddset(&newvec.sa_mask, SIGFPE);
  397. newvec.sa_flags = SA_SIGINFO;
  398. if (wad_debug_mode & DEBUG_ONESHOT) {
  399. newvec.sa_flags |= SA_RESETHAND;
  400. }
  401. #ifndef WAD_LINUX
  402. if (!(wad_debug_mode & DEBUG_NOSTACK)) {
  403. newvec.sa_flags |= SA_ONSTACK;
  404. }
  405. #endif
  406. newvec.sa_sigaction = ((void (*)(int,siginfo_t *, void *)) wad_signalhandler);
  407. if (sigaction(SIGSEGV, &newvec, NULL) < 0) goto werror;
  408. if (sigaction(SIGBUS, &newvec, NULL) < 0) goto werror;
  409. if (sigaction(SIGABRT, &newvec, NULL) < 0) goto werror;
  410. if (sigaction(SIGFPE, &newvec, NULL) < 0) goto werror;
  411. if (sigaction(SIGILL, &newvec, NULL) < 0) goto werror;
  412. return;
  413. werror:
  414. wad_printf("WAD: Couldn't install signal handler!\n");
  415. }
  416. /* -----------------------------------------------------------------------------
  417. * clear signals
  418. * ----------------------------------------------------------------------------- */
  419. void wad_signal_clear() {
  420. signal(SIGSEGV, SIG_DFL);
  421. signal(SIGBUS, SIG_DFL);
  422. signal(SIGILL, SIG_DFL);
  423. signal(SIGFPE, SIG_DFL);
  424. signal(SIGABRT, SIG_DFL);
  425. }