1 /* GRT stack implementation for Win32 using fibers.
2 Copyright (C) 2005 - 2014 Tristan Gingold.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <gnu.org/licenses>.
16
17 As a special exception, if other files instantiate generics from this
18 unit, or you link this unit with other files to produce an executable,
19 this unit does not by itself cause the resulting executable to be
20 covered by the GNU General Public License. This exception does not
21 however invalidate any other reasons why the executable file might be
22 covered by the GNU Public License.
23 */
24
25 #include <windows.h>
26 #include <winbase.h>
27 #include <dbghelp.h>
28 #include <stdio.h>
29 #include <setjmp.h>
30 #include <assert.h>
31 #include <excpt.h>
32
33 #include "grt_itf.h"
34
35 static int run_env_en;
36 static jmp_buf run_env;
37
38 static EXCEPTION_DISPOSITION
39 ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
40 void *EstablisherFrame,
41 struct _CONTEXT* ContextRecord,
42 void *DispatcherContext);
43
44 struct exception_registration
45 {
46 struct exception_registration *prev;
47 void *handler;
48 };
49
50 /* Save bactktrace from CTXT to BT, the first SKIP frames are skipped.
51 We need to use StackWalk64 as apparently CaptureStackBackTrace doesn't
52 work over JIT'ed code. I suppose it checks whether PC belongs to the text
53 section of an image. */
54
55 static void
get_bt_from_context(struct backtrace_addrs * bt,CONTEXT * ctxt,int skip)56 get_bt_from_context (struct backtrace_addrs *bt, CONTEXT *ctxt, int skip)
57 {
58 STACKFRAME64 frame;
59 unsigned mach;
60
61 bt->size = 0;
62 bt->skip = 0;
63 memset (&frame, 0, sizeof (frame));
64
65 #ifdef __i386__
66 mach = IMAGE_FILE_MACHINE_I386;
67
68 frame.AddrPC.Offset = ctxt->Eip;
69 frame.AddrPC.Mode = AddrModeFlat;
70 frame.AddrFrame.Offset = ctxt->Ebp;
71 frame.AddrFrame.Mode = AddrModeFlat;
72 frame.AddrStack.Offset = ctxt->Esp;
73 frame.AddrStack.Mode = AddrModeFlat;
74
75 #elif defined (__x86_64__)
76 mach = IMAGE_FILE_MACHINE_AMD64;
77
78 frame.AddrPC.Offset = ctxt->Rip;
79 frame.AddrPC.Mode = AddrModeFlat;
80 frame.AddrFrame.Offset = ctxt->Rsp;
81 frame.AddrFrame.Mode = AddrModeFlat;
82 frame.AddrStack.Offset = ctxt->Rsp;
83 frame.AddrStack.Mode = AddrModeFlat;
84
85 #else
86 # warning "platform not supported"
87 return;
88 #endif
89
90 while (bt->size < sizeof (bt->addrs) / sizeof (bt->addrs[0]))
91 {
92 if (skip > 0)
93 skip--;
94 else
95 bt->addrs[bt->size++] = (void *) frame.AddrPC.Offset;
96
97 if (!StackWalk64 (mach, GetCurrentProcess (), GetCurrentThread (),
98 &frame, ctxt, NULL, NULL, NULL, NULL))
99 break;
100 }
101 }
102
103 static EXCEPTION_DISPOSITION
ghdl_SEH_handler(struct _EXCEPTION_RECORD * ExceptionRecord,void * EstablisherFrame,struct _CONTEXT * ContextRecord,void * DispatcherContext)104 ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
105 void *EstablisherFrame,
106 struct _CONTEXT* ContextRecord,
107 void *DispatcherContext)
108 {
109 struct backtrace_addrs bt;
110 const char *msg = "";
111
112 switch (ExceptionRecord->ExceptionCode)
113 {
114 case EXCEPTION_ACCESS_VIOLATION:
115 /* Pc is ExceptionRecord->ExceptionAddress. */
116 get_bt_from_context (&bt, ContextRecord, 1);
117 grt_null_access_error (&bt);
118 break;
119
120 case EXCEPTION_FLT_DENORMAL_OPERAND:
121 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
122 case EXCEPTION_FLT_INVALID_OPERATION:
123 case EXCEPTION_FLT_OVERFLOW:
124 case EXCEPTION_FLT_STACK_CHECK:
125 case EXCEPTION_FLT_UNDERFLOW:
126 msg = "floating point error";
127 break;
128
129 case EXCEPTION_INT_DIVIDE_BY_ZERO:
130 msg = "division by 0";
131 break;
132
133 case EXCEPTION_INT_OVERFLOW:
134 get_bt_from_context (&bt, ContextRecord, 1);
135 grt_overflow_error (&bt);
136 break;
137
138 case EXCEPTION_STACK_OVERFLOW:
139 msg = "stack overflow";
140 break;
141
142 default:
143 msg = "unknown reason";
144 break;
145 }
146
147 /* FIXME: is it correct? */
148 fprintf (stderr, "exception raised: %s\n", msg);
149
150 __ghdl_maybe_return_via_longjump (1);
151 return 0; /* This is never reached, avoid compiler warning */
152 }
153
154 void
__ghdl_maybe_return_via_longjump(int val)155 __ghdl_maybe_return_via_longjump (int val)
156 {
157 if (run_env_en)
158 longjmp (run_env, val);
159 }
160
161 int
__ghdl_run_through_longjump(int (* func)(void))162 __ghdl_run_through_longjump (int (*func)(void))
163 {
164 int res;
165
166 #ifdef __i386__
167 /* Install an SEH handler. */
168 struct exception_registration er;
169 struct exception_registration *prev;
170
171 /* Get current handler. */
172 asm volatile ("mov %%fs:(0),%0" : "=r" (prev));
173
174 /* Build regisration. */
175 er.prev = prev;
176 er.handler = ghdl_SEH_handler;
177
178 /* Register. */
179 asm volatile ("mov %0,%%fs:(0)" : : "r" (&er));
180 #endif
181
182 run_env_en = 1;
183 res = setjmp (run_env);
184 if (res == 0)
185 res = (*func)();
186 run_env_en = 0;
187
188 #ifdef __i386__
189 /* Restore. */
190 asm volatile ("mov %0,%%fs:(0)" : : "r" (prev));
191 #endif
192
193 return res;
194 }
195
196 void
grt_save_backtrace(struct backtrace_addrs * bt,int skip)197 grt_save_backtrace (struct backtrace_addrs *bt, int skip)
198 {
199 /* FIXME
200 testsuite/gna/issue635 fails on GitHub Actions when executed with
201 LLVM backend on MINGW64 (MSYS2). GHDL returns '3', instead of '0'.
202 This dummy printf fixes it, surprisingly.
203 See https://github.com/ghdl/ghdl/pull/1516
204 */
205 printf("");
206
207 CONTEXT ctxt;
208
209 RtlCaptureContext (&ctxt);
210 get_bt_from_context (bt, &ctxt, skip + 1);
211 }
212
213 #include <math.h>
214
acosh(double x)215 double acosh (double x)
216 {
217 return log (x + sqrt (x*x - 1));
218 }
219
asinh(double x)220 double asinh (double x)
221 {
222 return log (x + sqrt (x*x + 1));
223 }
224
atanh(double x)225 double atanh (double x)
226 {
227 return log ((1 + x) / (1 - x)) / 2;
228 }
229
230 #ifndef WITH_GNAT_RUN_TIME
__gnat_raise_storage_error(void)231 void __gnat_raise_storage_error(void)
232 {
233 abort ();
234 }
235
__gnat_raise_program_error(void)236 void __gnat_raise_program_error(void)
237 {
238 abort ();
239 }
240 #endif
241