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