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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1233 - (hide annotations) (download)
Mon Jun 11 13:42:21 2007 UTC (16 years, 10 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 schoenebeck 270 /*************************************************************************
2     *
3 schoenebeck 1233 * $Id: stacktrace.c,v 1.3 2007-06-11 13:42:21 schoenebeck Exp $
4 schoenebeck 270 *
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 schoenebeck 1233 #else
39     # warning "No platform defined, automatic stack trace will fail!"
40 schoenebeck 270 #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 schoenebeck 361 #include <unistd.h>
69 schoenebeck 270 #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 schoenebeck 1233 rc = 0; // success
165 schoenebeck 270 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 schoenebeck 1233 //FIXME: deactivated separate piping of debugger output, as it caused problems in conjunction with threads
451     /*
452 schoenebeck 270 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 schoenebeck 1233 */
475     gotSomething = TRUE; //HACK: to compensate the commented FIXME block above
476    
477 schoenebeck 270 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