/[svn]/linuxsampler/trunk/src/common/stacktrace.c
ViewVC logotype

Contents of /linuxsampler/trunk/src/common/stacktrace.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1233 - (show annotations) (download)
Mon Jun 11 13:42:21 2007 UTC (16 years, 9 months ago) by schoenebeck
File MIME type: text/plain
File size: 18467 byte(s)
* minor fix in our automatic stack trace mechanism on crashes, the
  main process did not wait for the stack trace process to finish
  and thus killed the whole application before the stack trace was
  completely shown on the console

1 /*************************************************************************
2 *
3 * $Id: stacktrace.c,v 1.3 2007-06-11 13:42:21 schoenebeck Exp $
4 *
5 * Copyright (c) 1998 by Bjorn Reese <breese@mail1.stofanet.dk>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 ************************************************************************
17 *
18 * 1999/08/19 - breese
19 * - Cleaned up the interface
20 *
21 * 1999/08/06 - breese
22 * - Added U_STACK_TRACE for HP/UX
23 *
24 * 1999/01/24 - breese
25 * - Added GCC_DumpStack
26 *
27 * 1998/12/21 - breese
28 * - Fixed include files and arguments for waitpid()
29 * - Made an AIX workaround for waitpid() exiting with EINTR
30 * - Added a missing 'quit' command for OSF dbx
31 *
32 ************************************************************************/
33
34 #if defined(unix) || defined(__unix) || defined(__xlC__)
35 # define PLATFORM_UNIX
36 #elif defined(WIN32) || defined(_WIN32)
37 # define PLATFORM_WIN32
38 #else
39 # warning "No platform defined, automatic stack trace will fail!"
40 #endif
41
42 #if defined(_AIX) || defined(__xlC__)
43 # define PLATFORM_AIX
44 #elif defined(__FreeBSD__)
45 # define PLATFORM_FREEBSD
46 #elif defined(hpux) || defined(__hpux) || defined(_HPUX_SOURCE)
47 # define PLATFORM_HPUX
48 #elif defined(sgi) || defined(mips) || defined(_SGI_SOURCE)
49 # define PLATFORM_IRIX
50 #elif defined(__osf__)
51 # define PLATFORM_OSF
52 #elif defined(M_I386) || defined(_SCO_DS) || defined(_SCO_C_DIALECT)
53 # define PLATFORM_SCO
54 #elif defined(sun) || defined(__sun__) || defined(__SUNPRO_C)
55 # if defined(__SVR4) || defined(__svr4__)
56 # define PLATFORM_SOLARIS
57 # endif
58 #endif
59
60 /* ANSI C includes */
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <stdarg.h>
64 #include <string.h>
65 #include <limits.h>
66 #include <errno.h>
67 #include <signal.h>
68 #include <unistd.h>
69 #if defined(PLATFORM_UNIX)
70 # include <unistd.h>
71 # include <sys/types.h>
72 # include <sys/wait.h>
73 # if defined(PLATFORM_IRIX) && defined(USE_BUILTIN)
74 /* Compile with -DUSE_BUILTIN and -lexc */
75 # include <libexc.h>
76 # elif defined(PLATFORM_HPUX) && defined(USE_BUILTIN)
77 /* Compile with -DUSE_BUILTIN and -lcl */
78 extern void U_STACK_TRACE(void);
79 # endif
80 #endif
81
82 #include "stacktrace.h"
83
84 #ifndef FALSE
85 # define FALSE (0 == 1)
86 # define TRUE (! FALSE)
87 #endif
88
89 #define SYS_ERROR -1
90
91 #ifndef EXIT_SUCCESS
92 # define EXIT_SUCCESS 0
93 #endif
94 #ifndef EXIT_FAILURE
95 # define EXIT_FAILURE 1
96 #endif
97
98 #define MAX_BUFFER_SIZE 512
99 #if defined(__GNUC__)
100 /* Change the code if ADDRESSLIST_SIZE is increased */
101 # define ADDRESSLIST_SIZE 20
102 #endif
103
104 /*************************************************************************
105 * Globals
106 *
107 * We cannot pass custom arguments to signal handlers so we store
108 * them as global variables (but limit their scope to this file.)
109 */
110 static const char *global_progname;
111 static int global_output = STDOUT_FILENO;
112
113
114 #if defined(PLATFORM_UNIX)
115 /*************************************************************************
116 * my_pclose [private]
117 */
118 static void my_pclose(int fd, int pid)
119 {
120 close(fd);
121 /* Make sure the the child process has terminated */
122 (void)kill(pid, SIGTERM);
123 }
124
125 /*************************************************************************
126 * my_popen [private]
127 */
128 static int my_popen(const char *command, pid_t *pid)
129 {
130 int rc;
131 //int pipefd[2];
132
133 //FIXME: deactivated separate piping of debugger output, as it caused problems in conjunction with threads
134 //rc = pipe(pipefd);
135 rc = SYS_ERROR;
136 //if (SYS_ERROR != rc)
137 {
138 *pid = fork();
139 switch (*pid)
140 {
141 case SYS_ERROR:
142 //rc = SYS_ERROR;
143 //close(pipefd[0]);
144 //close(pipefd[1]);
145 break;
146
147 case 0: /* Child */
148 //close(pipefd[0]);
149 //close(STDOUT_FILENO);
150 //close(STDERR_FILENO);
151 //dup2(pipefd[1], STDOUT_FILENO);
152 //dup2(pipefd[1], STDERR_FILENO);
153 /*
154 * The System() call assumes that /bin/sh is
155 * always available, and so will we.
156 */
157 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
158 _exit(EXIT_FAILURE);
159 break;
160
161 default: /* Parent */
162 //close(pipefd[1]);
163 //rc = pipefd[0];
164 rc = 0; // success
165 break;
166 } /* switch */
167 }
168 return rc;
169 }
170
171 /*************************************************************************
172 * my_getline [private]
173 */
174 static int my_getline(int fd, char *buffer, int max)
175 {
176 char c;
177 int i = 0;
178
179 do {
180 if (read(fd, &c, 1) < 1)
181 return 0;
182 if (i < max)
183 buffer[i++] = c;
184 } while (c != '\n');
185 buffer[i] = (char)0;
186 return i;
187 }
188
189 /*************************************************************************
190 * GCC_DumpStack [private]
191 *
192 *
193 * This code is still experimental.
194 *
195 * Stackbased arrays are used to prevent allocating from the heap.
196 * Warning: sprintf/sscanf are not ASync safe. They were used for
197 * convenience.
198 *
199 * 'nm' is used because it is most widespread
200 * GNU: nm [-B]
201 * Solaris: nm -x -p
202 * IRIX: nm -x -B (but __builtin_return_address() always returns NULL)
203 * AIX: nm -x -B
204 * OSF/1: nm -B
205 * SCO/OpenServer: nm -x -p
206 * HP/UX nm -x -p
207 */
208
209 #if defined(__GNUC__) && defined(USE_BUILTIN)
210
211 typedef struct {
212 unsigned long realAddress;
213 unsigned long closestAddress;
214 char name[MAX_BUFFER_SIZE + 1];
215 char type;
216 } address_T;
217
218
219 static void GCC_DumpStack(void)
220 {
221 int i;
222 void *p = &p; /* dummy start value */
223 address_T syms[ADDRESSLIST_SIZE + 1];
224 char buffer[MAX_BUFFER_SIZE];
225 int fd;
226 pid_t pid;
227 unsigned long addr;
228 unsigned long highestAddress;
229 unsigned long lowestAddress;
230 char type;
231 char *pname;
232 char name[MAX_BUFFER_SIZE];
233 int number;
234
235 for (i = 0; p; i++)
236 {
237 /*
238 * This is based on code by Steve Coleman <steve.colemanjhuapl.edu>
239 *
240 * __builtin_return_address() only accepts a constant as argument.
241 */
242 switch (i)
243 {
244 case 0:
245 p = __builtin_return_address(0);
246 break;
247 case 1:
248 p = __builtin_return_address(1);
249 break;
250 case 2:
251 p = __builtin_return_address(2);
252 break;
253 case 3:
254 p = __builtin_return_address(3);
255 break;
256 case 4:
257 p = __builtin_return_address(4);
258 break;
259 case 5:
260 p = __builtin_return_address(5);
261 break;
262 case 6:
263 p = __builtin_return_address(6);
264 break;
265 case 7:
266 p = __builtin_return_address(7);
267 break;
268 case 8:
269 p = __builtin_return_address(8);
270 break;
271 case 9:
272 p = __builtin_return_address(9);
273 break;
274 case 10:
275 p = __builtin_return_address(10);
276 break;
277 case 11:
278 p = __builtin_return_address(11);
279 break;
280 case 12:
281 p = __builtin_return_address(12);
282 break;
283 case 13:
284 p = __builtin_return_address(13);
285 break;
286 case 14:
287 p = __builtin_return_address(14);
288 break;
289 case 15:
290 p = __builtin_return_address(15);
291 break;
292 case 16:
293 p = __builtin_return_address(16);
294 break;
295 case 17:
296 p = __builtin_return_address(17);
297 break;
298 case 18:
299 p = __builtin_return_address(18);
300 break;
301 case 19:
302 p = __builtin_return_address(19);
303 break;
304 default:
305 /* Change ADDRESSLIST_SIZE if more are added */
306 p = NULL;
307 break;
308 }
309 if ((p) && (i < ADDRESSLIST_SIZE))
310 {
311 syms[i].realAddress = (unsigned long)p;
312 syms[i].closestAddress = 0;
313 syms[i].name[0] = (char)0;
314 syms[i].type = ' ';
315 }
316 else
317 {
318 syms[i].realAddress = 0;
319 break; /* for */
320 }
321 } /* for */
322
323
324 /* First find out if we are using GNU or vendor nm */
325 number = 0;
326 strcpy(buffer, "nm -V 2>/dev/null | grep GNU | wc -l");
327 fd = my_popen(buffer, &pid);
328 if (SYS_ERROR != fd)
329 {
330 if (my_getline(fd, buffer, sizeof(buffer)))
331 {
332 sscanf(buffer, "%d", &number);
333 }
334 my_pclose(fd, pid);
335 }
336 if (number == 0) /* vendor nm */
337 {
338 # if defined(PLATFORM_SOLARIS) || defined(PLATFORM_SCO) || defined(PLATFORM_HPUX)
339 strcpy(buffer, "nm -x -p ");
340 # elif defined(PLATFORM_AIX) || defined(PLATFORM_IRIX) || defined(PLATFORM_OSF)
341 strcpy(buffer, "nm -x -B ");
342 # else
343 strcpy(buffer, "nm -B ");
344 # endif
345 }
346 else /* GNU nm */
347 strcpy(buffer, "nm -B ");
348 strcat(buffer, global_progname);
349
350 lowestAddress = ULONG_MAX;
351 highestAddress = 0;
352 fd = my_popen(buffer, &pid);
353 if (SYS_ERROR != fd)
354 {
355 while (my_getline(fd, buffer, sizeof(buffer)))
356 {
357 if (buffer[0] == '\n')
358 continue;
359 if (3 == sscanf(buffer, "%lx %c %s", &addr, &type, name))
360 {
361 if ((type == 't') || type == 'T')
362 {
363 if (addr == 0)
364 continue; /* while */
365 if (addr < lowestAddress)
366 lowestAddress = addr;
367 if (addr > highestAddress)
368 highestAddress = addr;
369 for (i = 0; syms[i].realAddress != 0; i++)
370 {
371 if ((addr <= syms[i].realAddress) &&
372 (addr > syms[i].closestAddress))
373 {
374 syms[i].closestAddress = addr;
375 strncpy(syms[i].name, name, MAX_BUFFER_SIZE);
376 syms[i].name[MAX_BUFFER_SIZE] = (char)0;
377 syms[i].type = type;
378 }
379 }
380 }
381 }
382 }
383 my_pclose(fd, pid);
384
385 for (i = 0; syms[i].realAddress != 0; i++)
386 {
387 if ((syms[i].name[0] == (char)0) ||
388 (syms[i].realAddress <= lowestAddress) ||
389 (syms[i].realAddress >= highestAddress))
390 {
391 sprintf(buffer, "[%d] 0x%08lx ???\n", i, syms[i].realAddress);
392 }
393 else
394 {
395 sprintf(buffer, "[%d] 0x%08lx <%s + 0x%lx> %c\n",
396 i,
397 syms[i].realAddress,
398 syms[i].name,
399 syms[i].realAddress - syms[i].closestAddress,
400 syms[i].type);
401 }
402 write(global_output, buffer, strlen(buffer));
403 }
404 }
405 }
406 #endif
407
408 /*************************************************************************
409 * DumpStack [private]
410 */
411 static int DumpStack(char *format, ...)
412 {
413 int gotSomething = FALSE;
414 int fd;
415 pid_t pid;
416 int status = EXIT_FAILURE;
417 int rc;
418 va_list args;
419 char *buffer;
420 char cmd[MAX_BUFFER_SIZE];
421 char buf[MAX_BUFFER_SIZE];
422
423 /*
424 * Please note that vsprintf() is not ASync safe (ie. cannot safely
425 * be used from a signal handler.) If this proves to be a problem
426 * then the cmd string can be built by more basic functions such as
427 * strcpy, strcat, and a homemade integer-to-ascii function.
428 */
429 va_start(args, format);
430 vsprintf(cmd, format, args);
431 va_end(args);
432
433 fd = my_popen(cmd, &pid);
434 if (SYS_ERROR != fd)
435 {
436 /*
437 * Wait for the child to exit. This must be done
438 * to make the debugger attach successfully.
439 * The output from the debugger is buffered on
440 * the pipe.
441 *
442 * AIX needs the looping hack
443 */
444 do
445 {
446 rc = waitpid(pid, &status, 0);
447 }
448 while ((SYS_ERROR == rc) && (EINTR == errno));
449
450 //FIXME: deactivated separate piping of debugger output, as it caused problems in conjunction with threads
451 /*
452 if ((WIFEXITED(status)) && (WEXITSTATUS(status) == EXIT_SUCCESS))
453 {
454 while (my_getline(fd, buf, sizeof(buf)))
455 {
456 buffer = buf;
457 if (! gotSomething)
458 {
459 write(global_output, "Output from ",
460 strlen("Output from "));
461 strtok(cmd, " ");
462 write(global_output, cmd, strlen(cmd));
463 write(global_output, "\n", strlen("\n"));
464 gotSomething = TRUE;
465 }
466 if ('\n' == buf[strlen(buf)-1])
467 {
468 buf[strlen(buf)-1] = (char)0;
469 }
470 write(global_output, buffer, strlen(buffer));
471 write(global_output, "\n", strlen("\n"));
472 }
473 }
474 */
475 gotSomething = TRUE; //HACK: to compensate the commented FIXME block above
476
477 my_pclose(fd, pid);
478 }
479 return gotSomething;
480 }
481 #endif /* PLATFORM_UNIX */
482
483 /*************************************************************************
484 * StackTrace
485 */
486 void StackTrace(void)
487 {
488 #if defined(PLATFORM_UNIX)
489 /*
490 * In general dbx seems to do a better job than gdb.
491 *
492 * Different dbx implementations require different flags/commands.
493 */
494
495 # if defined(PLATFORM_AIX)
496
497 if (DumpStack("dbx -a %d 2>/dev/null <<EOF\n"
498 "where\n"
499 "detach\n"
500 "EOF\n",
501 (int)getpid()))
502 return;
503
504 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
505 "set prompt\n"
506 "where\n"
507 "detach\n"
508 "quit\n"
509 "EOF\n",
510 global_progname, (int)getpid()))
511 return;
512
513 # elif defined(PLATFORM_FREEBSD)
514
515 /*
516 * FreeBSD insists on sending a SIGSTOP to the process we
517 * attach to, so we let the debugger send a SIGCONT to that
518 * process after we have detached.
519 */
520 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
521 "set prompt\n"
522 "where\n"
523 "detach\n"
524 "shell kill -CONT %d\n"
525 "quit\n"
526 "EOF\n",
527 global_progname, (int)getpid(), (int)getpid()))
528 return;
529
530 # elif defined(PLATFORM_HPUX)
531
532 /*
533 * HP decided to call their debugger xdb.
534 *
535 * This does not seem to work properly yet. The debugger says
536 * "Note: Stack traces may not be possible until you are
537 * stopped in user code." on HP-UX 09.01
538 *
539 * -L = line-oriented interface.
540 * "T [depth]" gives a stacktrace with local variables.
541 * The final "y" is confirmation to the quit command.
542 */
543
544 if (DumpStack("xdb -P %d -L %s 2>&1 <<EOF\n"
545 "T 50\n"
546 "q\ny\n"
547 "EOF\n",
548 (int)getpid(), global_progname))
549 return;
550
551 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
552 "set prompt\n"
553 "where\n"
554 "detach\n"
555 "quit\n"
556 "EOF\n",
557 global_progname, (int)getpid()))
558 return;
559
560 # if defined(PLATFORM_HPUX) && defined(USE_BUILTIN)
561 U_STACK_TRACE();
562 return;
563 # endif
564
565 # elif defined(PLATFORM_IRIX)
566
567 /*
568 * "set $page=0" drops hold mode
569 * "dump ." displays the contents of the variables
570 */
571 if (DumpStack("dbx -p %d 2>/dev/null <<EOF\n"
572 "set \\$page=0\n"
573 "where\n"
574 # if !defined(__GNUC__)
575 /* gcc does not generate this information */
576 "dump .\n"
577 # endif
578 "detach\n"
579 "EOF\n",
580 (int)getpid()))
581 return;
582
583 # if defined(USE_BUILTIN)
584 if (trace_back_stack_and_print())
585 return;
586 # endif
587
588 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
589 "set prompt\n"
590 "echo --- Stacktrace\\n\n"
591 "where\n"
592 "echo --- Symbols\\n\n"
593 "frame 5\n" /* Skip signal handler frames */
594 "set \\$x = 50\n"
595 "while (\\$x)\n" /* Print local variables for each frame */
596 "info locals\n"
597 "up\n"
598 "set \\$x--\n"
599 "end\n"
600 "echo ---\\n\n"
601 "detach\n"
602 "quit\n"
603 "EOF\n",
604 global_progname, (int)getpid()))
605 return;
606
607 # elif defined(PLATFORM_OSF)
608
609 if (DumpStack("dbx -pid %d %s 2>/dev/null <<EOF\n"
610 "where\n"
611 "detach\n"
612 "quit\n"
613 "EOF\n",
614 (int)getpid(), global_progname))
615 return;
616
617 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
618 "set prompt\n"
619 "where\n"
620 "detach\n"
621 "quit\n"
622 "EOF\n",
623 global_progname, (int)getpid()))
624 return;
625
626 # elif defined(PLATFORM_SCO)
627
628 /*
629 * SCO OpenServer dbx is like a catch-22. The 'detach' command
630 * depends on whether ptrace(S) support detaching or not. If it
631 * is supported then 'detach' must be used, otherwise the process
632 * will be killed upon dbx exit. If it isn't supported then 'detach'
633 * will cause the process to be killed. We do not want it to be
634 * killed.
635 *
636 * Out of two evils, the omission of 'detach' was chosen because
637 * it worked on our system.
638 */
639 if (DumpStack("dbx %s %d 2>/dev/null <<EOF\n"
640 "where\n"
641 "quit\nEOF\n",
642 global_progname, (int)getpid()))
643 return;
644
645 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
646 "set prompt\n"
647 "where\n"
648 "detach\n"
649 "quit\n"
650 "EOF\n",
651 global_progname, (int)getpid()))
652 return;
653
654 # elif defined(PLATFORM_SOLARIS)
655
656 if (DumpStack("dbx %s %d 2>/dev/null <<EOF\n"
657 "where\n"
658 "detach\n"
659 "EOF\n",
660 global_progname, (int)getpid()))
661 return;
662
663 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
664 "set prompt\n"
665 "echo --- Stacktrace\\n\n"
666 "where\n"
667 "echo --- Symbols\\n\n"
668 "frame 5\n" /* Skip signal handler frames */
669 "set \\$x = 50\n"
670 "while (\\$x)\n" /* Print local variables for each frame */
671 "info locals\n"
672 "up\n"
673 "set \\$x--\n"
674 "end\n"
675 "echo ---\\n\n"
676 "detach\n"
677 "quit\n"
678 "EOF\n",
679 global_progname, (int)getpid()))
680 return;
681
682 if (DumpStack("/usr/proc/bin/pstack %d",
683 (int)getpid()))
684 return;
685
686 /*
687 * Other Unices (AIX, HPUX, SCO) also have adb, but
688 * they seem unable to attach to a running process.
689 */
690 if (DumpStack("adb %s 2>&1 <<EOF\n"
691 "0t%d:A\n" /* Attach to pid */
692 "\\$c\n" /* print stacktrace */
693 ":R\n" /* Detach */
694 "\\$q\n" /* Quit */
695 "EOF\n",
696 global_progname, (int)getpid()))
697 return;
698
699 # else /* All other Unix platforms */
700
701 /*
702 * TODO: SCO/UnixWare 7 must be something like (not tested)
703 * debug -i c <pid> <<EOF\nstack -f 4\nquit\nEOF\n
704 */
705
706 # if !defined(__GNUC__)
707 if (DumpStack("dbx %s %d 2>/dev/null <<EOF\n"
708 "where\n"
709 "detach\n"
710 "EOF\n",
711 global_progname, (int)getpid()))
712 return;
713 # endif
714
715 if (DumpStack("gdb -q %s %d 2>/dev/null <<EOF\n"
716 "set prompt\n"
717 "echo --- Stacktrace\\n\n"
718 "where\n"
719 "echo --- Symbols\\n\n"
720 "frame 4\n"
721 "set \\$x = 50\n"
722 "while (\\$x)\n" /* Print local variables for each frame */
723 "info locals\n"
724 "up\n"
725 "set \\$x--\n"
726 "end\n"
727 "echo ---\\n\n"
728 "detach\n"
729 "quit\n"
730 "EOF\n",
731 global_progname, (int)getpid()))
732 return;
733
734 # endif
735
736 # if defined(__GNUC__) && defined(USE_BUILTIN)
737
738 GCC_DumpStack();
739
740 # endif
741
742 write(global_output,
743 "No debugger found\n", strlen("No debugger found\n"));
744
745 #elif defined(PLATFORM_WIN32)
746 /* Use StackWalk() */
747 #endif
748 }
749
750 /*************************************************************************
751 * StackTraceInit
752 */
753 void StackTraceInit(const char *in_name, int in_handle)
754 {
755 global_progname = in_name;
756 global_output = (in_handle == -1) ? STDOUT_FILENO : in_handle;
757 }
758
759
760 /*************************************************************************
761 * test
762 */
763 #if defined(STANDALONE)
764
765 void CrashHandler(int sig)
766 {
767 /* Reinstall default handler to prevent race conditions */
768 signal(sig, SIG_DFL);
769 /* Print the stack trace */
770 StackTrace();
771 /* And exit because we may have corrupted the internal
772 * memory allocation lists. Use abort() if we want to
773 * generate a core dump. */
774 _exit(EXIT_FAILURE);
775 }
776
777
778 void Crash(void)
779 {
780 /* Force a crash */
781 strcpy(NULL, "");
782 }
783
784 int main(int argc, char *argv[])
785 {
786 struct sigaction sact;
787
788 StackTraceInit(argv[0], -1);
789
790 sigemptyset(&sact.sa_mask);
791 sact.sa_flags = 0;
792 sact.sa_handler = CrashHandler;
793 sigaction(SIGSEGV, &sact, NULL);
794 sigaction(SIGBUS, &sact, NULL);
795
796 Crash();
797 return EXIT_SUCCESS;
798 }
799 #endif

  ViewVC Help
Powered by ViewVC