source: trunk/src/kernel32/oslibexcept.cpp@ 21999

Last change on this file since 21999 was 21999, checked in by dmik, 13 years ago

kernel32: Make SEH work in OS/2 context.

See #82 for details.

File size: 12.3 KB
Line 
1/* $Id: oslibexcept.cpp,v 1.7 2001-06-04 21:18:40 sandervl Exp $ */
2/*
3 * Exception handler util. procedures
4 *
5 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
6 *
7 */
8#define INCL_BASE
9#define INCL_DOSEXCEPTIONS
10#define INCL_DOSMEMMGR
11#define INCL_DOSPROCESS
12#include <os2wrap.h> //Odin32 OS/2 api wrappers
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <win32type.h>
17#include <misc.h>
18#include <exceptions.h>
19#include <wprocess.h>
20
21#include "oslibexcept.h"
22
23#define DBG_LOCALLOG DBG_oslibexcept
24#include "dbglocal.h"
25
26/**
27 * Converts the OS/2 exception information to the Win32 exception information.
28 *
29 * Returns TRUE on succes and FALSE otherwise.
30 */
31BOOL APIENTRY OSLibConvertExceptionInfo(PEXCEPTIONREPORTRECORD pReportRec,
32 PCONTEXTRECORD pContextRec,
33 PWINEXCEPTION_RECORD pWinReportRec,
34 PWINCONTEXT pWinContextRec,
35 TEB *pWinTEB)
36{
37 memset(pWinReportRec, 0, sizeof(*pWinReportRec));
38 memcpy(pWinReportRec, pReportRec, sizeof(*pReportRec));
39
40 switch (pReportRec->ExceptionNum)
41 {
42 case XCPT_FLOAT_DENORMAL_OPERAND:
43 pWinReportRec->ExceptionCode = EXCEPTION_FLT_DENORMAL_OPERAND;
44 break;
45 case XCPT_FLOAT_DIVIDE_BY_ZERO:
46 pWinReportRec->ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
47 break;
48 case XCPT_FLOAT_INEXACT_RESULT:
49 pWinReportRec->ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
50 break;
51 case XCPT_FLOAT_INVALID_OPERATION:
52 pWinReportRec->ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
53 break;
54 case XCPT_FLOAT_OVERFLOW:
55 pWinReportRec->ExceptionCode = EXCEPTION_FLT_OVERFLOW;
56 break;
57 case XCPT_FLOAT_STACK_CHECK:
58 pWinReportRec->ExceptionCode = EXCEPTION_FLT_STACK_CHECK;
59 break;
60 case XCPT_FLOAT_UNDERFLOW:
61 pWinReportRec->ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
62 break;
63 case XCPT_INTEGER_DIVIDE_BY_ZERO:
64 pWinReportRec->ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
65 break;
66 case XCPT_INTEGER_OVERFLOW:
67 pWinReportRec->ExceptionCode = EXCEPTION_INT_OVERFLOW;
68 break;
69 case XCPT_PRIVILEGED_INSTRUCTION:
70 pWinReportRec->ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
71 break;
72 case XCPT_BREAKPOINT:
73 pWinReportRec->ExceptionCode = EXCEPTION_BREAKPOINT;
74 break;
75 case XCPT_SINGLE_STEP:
76 pWinReportRec->ExceptionCode = EXCEPTION_SINGLE_STEP;
77 break;
78 case XCPT_ARRAY_BOUNDS_EXCEEDED:
79 pWinReportRec->ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
80 break;
81 case XCPT_DATATYPE_MISALIGNMENT:
82 pWinReportRec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
83 break;
84 case XCPT_ILLEGAL_INSTRUCTION:
85 pWinReportRec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
86 break;
87 case XCPT_INVALID_LOCK_SEQUENCE:
88 pWinReportRec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
89 break;
90 case XCPT_GUARD_PAGE_VIOLATION:
91 pWinReportRec->ExceptionCode = EXCEPTION_GUARD_PAGE;
92 break;
93 case XCPT_UNABLE_TO_GROW_STACK:
94 pWinReportRec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
95 break;
96 case XCPT_IN_PAGE_ERROR:
97 pWinReportRec->ExceptionCode = EXCEPTION_IN_PAGE_ERROR;
98 break;
99 case XCPT_ACCESS_VIOLATION:
100 pWinReportRec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
101 break;
102 default: // no other exceptions should be dispatched to win32 apps
103 return FALSE;
104 }
105
106 // TODO:
107 // According to the Wine folks the flags are the same in OS/2 and win32
108 // Let's assume for now the rest is identical as well
109
110 // copy context record info
111 memset(pWinContextRec, 0, sizeof(*pWinContextRec));
112 if (pContextRec->ContextFlags & CONTEXT_CONTROL)
113 {
114 pWinContextRec->ContextFlags |= WINCONTEXT_CONTROL;
115 pWinContextRec->Ebp = pContextRec->ctx_RegEbp;
116 pWinContextRec->Eip = pContextRec->ctx_RegEip;
117 pWinContextRec->SegCs = pContextRec->ctx_SegCs;
118 pWinContextRec->EFlags = pContextRec->ctx_EFlags;
119 pWinContextRec->Esp = pContextRec->ctx_RegEsp;
120 pWinContextRec->SegSs = pContextRec->ctx_SegSs;
121 }
122 if (pContextRec->ContextFlags & CONTEXT_INTEGER)
123 {
124 pWinContextRec->ContextFlags |= WINCONTEXT_INTEGER;
125 pWinContextRec->Edi = pContextRec->ctx_RegEdi;
126 pWinContextRec->Esi = pContextRec->ctx_RegEsi;
127 pWinContextRec->Ebx = pContextRec->ctx_RegEbx;
128 pWinContextRec->Edx = pContextRec->ctx_RegEdx;
129 pWinContextRec->Ecx = pContextRec->ctx_RegEcx;
130 pWinContextRec->Eax = pContextRec->ctx_RegEax;
131 }
132
133 if (pContextRec->ContextFlags & CONTEXT_SEGMENTS)
134 {
135 pWinContextRec->ContextFlags |= WINCONTEXT_SEGMENTS;
136 pWinContextRec->SegGs = pContextRec->ctx_SegGs;
137 // set Wn32 TEB if we run in switch FS mode
138 if (pWinTEB)
139 pWinContextRec->SegFs = pWinTEB->teb_sel;
140 else
141 pWinContextRec->SegFs = pContextRec->ctx_SegFs;
142 pWinContextRec->SegEs = pContextRec->ctx_SegEs;
143 pWinContextRec->SegDs = pContextRec->ctx_SegDs;
144 }
145
146 if (pContextRec->ContextFlags & CONTEXT_FLOATING_POINT)
147 {
148 pWinContextRec->ContextFlags |= WINCONTEXT_FLOATING_POINT;
149 //TODO: First 7 dwords the same?
150 memcpy(&pWinContextRec->FloatSave,
151 pContextRec->ctx_env, sizeof(pContextRec->ctx_env));
152 memcpy(&pWinContextRec->FloatSave.RegisterArea,
153 pContextRec->ctx_stack, sizeof(pContextRec->ctx_stack));
154 }
155
156 return TRUE;
157}
158
159/**
160 * Converts the Win32 exception handler result to the OS/2 exception handler
161 * result.
162 *
163 * Returns TRUE if the OS/2 exception handler result should be
164 * XCPT_CONTINUE_EXECUTION and FALSE otherwise.
165 */
166BOOL APIENTRY OSLibConvertExceptionResult(ULONG rc,
167 PWINCONTEXT pWinContextRec,
168 PCONTEXTRECORD pContextRec)
169{
170 if (rc != ExceptionContinueExecution)
171 {
172 dprintf(("Win32 exception handler returned %x", rc));
173 return FALSE;
174 }
175
176 dprintf(("Win32 exception handler returned ExceptionContinueExecution"));
177
178 if (pWinContextRec->ContextFlags & WINCONTEXT_CONTROL)
179 {
180 pContextRec->ctx_RegEbp = pWinContextRec->Ebp;
181 pContextRec->ctx_RegEip = pWinContextRec->Eip;
182 pContextRec->ctx_SegCs = pWinContextRec->SegCs;
183 pContextRec->ctx_EFlags = pWinContextRec->EFlags;
184 pContextRec->ctx_RegEsp = pWinContextRec->Esp;
185 pContextRec->ctx_SegSs = pWinContextRec->SegSs;
186 }
187
188 if (pWinContextRec->ContextFlags & WINCONTEXT_INTEGER)
189 {
190 pContextRec->ctx_RegEdi = pWinContextRec->Edi;
191 pContextRec->ctx_RegEsi = pWinContextRec->Esi;
192 pContextRec->ctx_RegEbx = pWinContextRec->Ebx;
193 pContextRec->ctx_RegEdx = pWinContextRec->Edx;
194 pContextRec->ctx_RegEcx = pWinContextRec->Ecx;
195 pContextRec->ctx_RegEax = pWinContextRec->Eax;
196 }
197
198#if 0
199 // This is not a good idea
200 if (pWinContextRec->ContextFlags & WINCONTEXT_SEGMENTS)
201 {
202 pContextRec->ctx_SegGs = pWinContextRec->SegGs;
203 pContextRec->ctx_SegFs = pWinContextRec->SegFs;
204 pContextRec->ctx_SegEs = pWinContextRec->SegEs;
205 pContextRec->ctx_SegDs = pWinContextRec->SegDs;
206 }
207#endif
208
209 if (pWinContextRec->ContextFlags & WINCONTEXT_FLOATING_POINT)
210 {
211 //TODO: First 7 dwords the same?
212 memcpy(pContextRec->ctx_env, &pWinContextRec->FloatSave,
213 sizeof(pContextRec->ctx_env));
214 memcpy(pContextRec->ctx_stack, &pWinContextRec->FloatSave.RegisterArea,
215 sizeof(pContextRec->ctx_stack));
216 }
217
218 if (pContextRec->ContextFlags & CONTEXT_CONTROL) /* check flags */
219 dprintf((" SS:ESP=%04x:%08x EFLAGS=%08x\n",
220 pContextRec->ctx_SegSs,
221 pContextRec->ctx_RegEsp,
222 pContextRec->ctx_EFlags));
223 dprintf((" CS:EIP=%04x:%08x EBP =%08x\n",
224 pContextRec->ctx_SegCs,
225 pContextRec->ctx_RegEip,
226 pContextRec->ctx_RegEbp));
227
228 if (pContextRec->ContextFlags & CONTEXT_INTEGER) /* check flags */
229 dprintf((" EAX=%08x EBX=%08x ESI=%08x\n",
230 pContextRec->ctx_RegEax,
231 pContextRec->ctx_RegEbx,
232 pContextRec->ctx_RegEsi));
233 dprintf((" ECX=%08x EDX=%08x EDI=%08x\n",
234 pContextRec->ctx_RegEcx,
235 pContextRec->ctx_RegEdx,
236 pContextRec->ctx_RegEdi));
237
238 if (pContextRec->ContextFlags & CONTEXT_SEGMENTS) /* check flags */
239 dprintf((" DS=%04x ES=%08x"
240 " FS=%04x GS=%04x\n",
241 pContextRec->ctx_SegDs,
242 pContextRec->ctx_SegEs,
243 pContextRec->ctx_SegFs,
244 pContextRec->ctx_SegGs));
245
246 if (pContextRec->ContextFlags & CONTEXT_FLOATING_POINT) /* check flags */
247 {
248 ULONG ulCounter; /* temporary local counter for fp stack */
249
250 dprintf((" Env[0]=%08x Env[1]=%08x Env[2]=%08x Env[3]=%08x\n",
251 pContextRec->ctx_env[0],
252 pContextRec->ctx_env[1],
253 pContextRec->ctx_env[2],
254 pContextRec->ctx_env[3]));
255
256 dprintf((" Env[4]=%08x Env[5]=%08x Env[6]=%08x\n",
257 pContextRec->ctx_env[4],
258 pContextRec->ctx_env[5],
259 pContextRec->ctx_env[6]));
260
261 for (ulCounter = 0;
262 ulCounter < 8; /* see TOOLKIT\INCLUDE\BSEEXPT.H, _CONTEXT structure */
263 ulCounter ++)
264 dprintf((" FP-Stack[%u] losig=%08x hisig=%08x signexp=%04x\n",
265 ulCounter,
266 pContextRec->ctx_stack[0].losig,
267 pContextRec->ctx_stack[0].hisig,
268 pContextRec->ctx_stack[0].signexp));
269 }
270
271 return TRUE;
272}
273
274/**
275 * Dispatches OS/2 exception to win32 handler.
276 *
277 * Returns TRUE if the Win32 exception handler returned
278 * ExceptionContinueExecution and FALSE otherwise.
279 */
280BOOL APIENTRY OSLibDispatchExceptionWin32(PEXCEPTIONREPORTRECORD pReportRec,
281 PEXCEPTIONREGISTRATIONRECORD pRegistrationRec,
282 PCONTEXTRECORD pContextRec, PVOID p)
283{
284 WINEXCEPTION_RECORD winReportRec;
285 WINCONTEXT winContextRec;
286
287 ULONG rc;
288
289 TEB *pWinTEB = GetThreadTEB();
290
291 OSLibConvertExceptionInfo(pReportRec, pContextRec,
292 &winReportRec, &winContextRec, pWinTEB);
293
294 // It doesn't seem correct if we dispatch real exceptions to win32 apps
295 // Some just call RtlUnwind and continue as if they were processing an
296 // exception thrown by C++ code. (instead of real OS exception)
297
298 // We need to reset FS to its original (Win32) value, otherwise we'll likely
299 // fuck up the Win32 exception handlers. They could end up using the wrong
300 // exception chain if they access FS:[0] directly.
301 DWORD oldsel = SetReturnFS(pWinTEB->teb_sel);
302
303 switch(pReportRec->ExceptionNum)
304 {
305 case XCPT_FLOAT_DENORMAL_OPERAND:
306 case XCPT_FLOAT_DIVIDE_BY_ZERO:
307 case XCPT_FLOAT_INEXACT_RESULT:
308 case XCPT_FLOAT_INVALID_OPERATION:
309 case XCPT_FLOAT_OVERFLOW:
310 case XCPT_FLOAT_STACK_CHECK:
311 case XCPT_FLOAT_UNDERFLOW:
312 rc = RtlDispatchException(&winReportRec, &winContextRec);
313 break;
314
315 case XCPT_ACCESS_VIOLATION:
316 rc = RtlDispatchException(&winReportRec, &winContextRec);
317 break;
318
319 case XCPT_ILLEGAL_INSTRUCTION:
320 case XCPT_PRIVILEGED_INSTRUCTION:
321 case XCPT_INTEGER_DIVIDE_BY_ZERO:
322 case XCPT_UNABLE_TO_GROW_STACK:
323 case XCPT_GUARD_PAGE_VIOLATION:
324#ifndef DEBUG
325 case XCPT_BREAKPOINT:
326#endif
327 rc = RtlDispatchException(&winReportRec, &winContextRec);
328 break;
329
330#ifdef DEBUG
331 case XCPT_BREAKPOINT:
332#endif
333 case XCPT_INTEGER_OVERFLOW:
334 case XCPT_SINGLE_STEP:
335 case XCPT_ARRAY_BOUNDS_EXCEEDED:
336 case XCPT_DATATYPE_MISALIGNMENT:
337 case XCPT_INVALID_LOCK_SEQUENCE:
338 case XCPT_IN_PAGE_ERROR:
339 default:
340 SetFS(oldsel); //restore FS
341 return FALSE; //let's not dispatch those for now
342 }
343
344 SetFS(oldsel); //restore FS
345
346 return OSLibConvertExceptionResult(rc, &winContextRec, pContextRec);
347}
Note: See TracBrowser for help on using the repository browser.