|
| 1 | +/* |
| 2 | + * This file is part of OpenModelica. |
| 3 | + * |
| 4 | + * Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), |
| 5 | + * c/o Linköpings universitet, Department of Computer and Information Science, |
| 6 | + * SE-58183 Linköping, Sweden. |
| 7 | + * |
| 8 | + * All rights reserved. |
| 9 | + * |
| 10 | + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE |
| 11 | + * GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. |
| 12 | + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES |
| 13 | + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, |
| 14 | + * ACCORDING TO RECIPIENTS CHOICE. |
| 15 | + * |
| 16 | + * The OpenModelica software and the OSMC (Open Source Modelica Consortium) |
| 17 | + * Public License (OSMC-PL) are obtained from OSMC, either from the above |
| 18 | + * address, from the URLs: http://www.openmodelica.org or |
| 19 | + * http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica |
| 20 | + * distribution. GNU version 3 is obtained from: |
| 21 | + * http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: |
| 22 | + * http://www.opensource.org/licenses/BSD-3-Clause. |
| 23 | + * |
| 24 | + * This program is distributed WITHOUT ANY WARRANTY; without even the implied |
| 25 | + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS |
| 26 | + * EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE |
| 27 | + * CONDITIONS OF OSMC-PL. |
| 28 | + * |
| 29 | + */ |
| 30 | + |
| 31 | +/* Stack overflow handling */ |
| 32 | +#include <stdlib.h> |
| 33 | +#include <stdio.h> |
| 34 | +#include <signal.h> |
| 35 | +#include <stdio.h> |
| 36 | +#include <signal.h> |
| 37 | +#include <execinfo.h> |
| 38 | +#include <sys/time.h> |
| 39 | +#include <sys/resource.h> |
| 40 | +#include <assert.h> |
| 41 | +#include <pthread.h> |
| 42 | +#include <setjmp.h> |
| 43 | +#include <ucontext.h> |
| 44 | + |
| 45 | +/* Really 64kB memory for this? Oh well... */ |
| 46 | +#define TRACE_NFRAMES 65536 |
| 47 | +/* If we find a SIGSEGV near the end of the stack, it is probably due to a stack overflow. 64kB for a function frame seems reasonable. */ |
| 48 | +#define LIMIT_FOR_STACK_OVERFLOW 65536 |
| 49 | + |
| 50 | +jmp_buf *mmc_stack_overflow_jumper; |
| 51 | +static void *trace[TRACE_NFRAMES]; |
| 52 | +static int trace_size; |
| 53 | +static int trace_size_skip=0; /* First index we should use; that is skip handler, etc */ |
| 54 | +static void *stackBottom; |
| 55 | +static struct sigaction default_segv_action; |
| 56 | + |
| 57 | +void printStacktraceMessages() { |
| 58 | + int i,j=-1,k; |
| 59 | + char **messages = (char **)NULL; |
| 60 | + messages = backtrace_symbols(trace, trace_size); |
| 61 | + fprintf(stderr,"[bt] Execution path:\n"); |
| 62 | + for (i=trace_size_skip; i<trace_size; ++i) |
| 63 | + { |
| 64 | + if (i<trace_size-1 && trace[i] == trace[i+1]) { |
| 65 | + j=j==-1?i:j; |
| 66 | + } else if (j>=0) { |
| 67 | + k=19-fprintf(stderr,"[bt] #%d..%d", j-trace_size_skip, i-trace_size_skip); |
| 68 | + while (k-->0) fprintf(stderr, " "); |
| 69 | + fprintf(stderr,"%s\n", messages[i]); |
| 70 | + j=-1; |
| 71 | + } else { |
| 72 | + k=19-fprintf(stderr,"[bt] #%d ", i-trace_size_skip); |
| 73 | + while (k-->0) fprintf(stderr, " "); |
| 74 | + fprintf(stderr,"%s\n", messages[i]); |
| 75 | + } |
| 76 | + } |
| 77 | + if (trace_size==TRACE_NFRAMES) { |
| 78 | + fprintf(stderr,"[bt] [...]\n"); |
| 79 | + } |
| 80 | + free(messages); |
| 81 | +} |
| 82 | + |
| 83 | +static inline void setTrace(int numSkip, int numFrames) { |
| 84 | + trace_size = 0; |
| 85 | + trace_size = backtrace(trace, numFrames == 0 ? TRACE_NFRAMES : numFrames > TRACE_NFRAMES ? TRACE_NFRAMES : numFrames); |
| 86 | + trace_size_skip = numSkip; |
| 87 | +} |
| 88 | + |
| 89 | +static sigset_t segvset; |
| 90 | + |
| 91 | +static void handler(int signo, siginfo_t *si, void *ptr) |
| 92 | +{ |
| 93 | + int isStackOverflow; |
| 94 | + ucontext_t *uc = (ucontext_t *)ptr; |
| 95 | + isStackOverflow = si->si_addr < stackBottom && (si->si_addr > stackBottom - LIMIT_FOR_STACK_OVERFLOW); |
| 96 | + if (isStackOverflow) { |
| 97 | + setTrace(3,0); |
| 98 | + sigprocmask(SIG_UNBLOCK, &segvset, NULL); |
| 99 | + longjmp(*mmc_stack_overflow_jumper,1); |
| 100 | + } |
| 101 | + /* This backtrace uses very little stack-space, and segmentation faults we always want to print... */ |
| 102 | + setTrace(3,16); |
| 103 | + write(2, "\nLimited backtrace at point of segmentation fault\n", 50); |
| 104 | + backtrace_symbols_fd(trace+trace_size_skip, trace_size-trace_size_skip, 2); |
| 105 | + sigaction(SIGSEGV, &default_segv_action, 0); |
| 106 | +} |
| 107 | + |
| 108 | +static void getStackBase() { |
| 109 | + struct rlimit rl; |
| 110 | + size_t stackSize = 0; |
| 111 | + pthread_attr_t sattr; |
| 112 | + pthread_attr_init(&sattr); |
| 113 | + pthread_t thread = pthread_self(); |
| 114 | + pthread_getattr_np(thread, &sattr); |
| 115 | + assert(0==getrlimit(RLIMIT_STACK,&rl)); |
| 116 | + stackSize = rl.rlim_cur; |
| 117 | + assert(0==pthread_attr_getstack(&sattr, &stackBottom, &stackSize)); |
| 118 | + assert(stackBottom); |
| 119 | + pthread_attr_destroy(&sattr); |
| 120 | +} |
| 121 | + |
| 122 | +void init_metamodelica_segv_handler() |
| 123 | +{ |
| 124 | + char *stack = (char*)malloc(SIGSTKSZ); |
| 125 | + stack_t ss = { |
| 126 | + .ss_size = SIGSTKSZ, |
| 127 | + .ss_sp = stack, |
| 128 | + }; |
| 129 | + struct sigaction sa = { |
| 130 | + .sa_sigaction = handler, |
| 131 | + .sa_flags = SA_ONSTACK | SA_SIGINFO |
| 132 | + }; |
| 133 | + getStackBase(); |
| 134 | + sigaltstack(&ss, 0); |
| 135 | + sigfillset(&sa.sa_mask); |
| 136 | + sigaction(SIGSEGV, &sa, &default_segv_action); |
| 137 | + sigfillset(&segvset); |
| 138 | +} |
0 commit comments