source: trunk/dll/excputil.c@ 1570

Last change on this file since 1570 was 1544, checked in by Gregg Young, 15 years ago

Changes to fopen and _fsopen to allow FM2 to be loaded in high memory

  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1
2/* excputil.c - exception handlers
3 $Id: excputil.c 1544 2010-09-30 13:00:59Z gyoung $
4
5 Copyright (c) 2008 Steven H. Levine
6
7 Write to exceptq .trp file or ?:\fm2_trap.log
8 where ? is boot volume
9
10 06 Dec 08 SHL Baseline (Ticket #26)
11
12*/
13
14#include <stdio.h> // fprintf
15#include <string.h> // strcpy
16#include <time.h> // tm
17#include <process.h> // _beginthread
18
19#define INCL_DOSMODULEMGR // DosQueryModFromEIP
20#define INCL_DOSPROCESS // PPIB PTIB
21#define INCL_DOSEXCEPTIONS // XCTP_...
22#define INCL_DOSMISC // DosDumpProcess?
23#define INCL_DOSERRORS // NO_ERROR
24// #include <os2.h>
25
26#include "wrappers.h" // xmalloc xfree
27#include "errutil.h" // Dos_Error Runtime_Error
28#include "fm3str.h" // IDS_COULDNTSTARTTHREADTEXT
29#include "strutil.h" // GetPString
30
31#include "excputil.h"
32#include "fortify.h"
33
34static PSZ pszSrcFile = __FILE__;
35
36typedef struct {
37 VOID (*pfnThread)(PVOID);
38 PVOID *pvArgs;
39} THREADDATA;
40
41/**
42 * Wrapper thread that installs exception handler and invokes
43 * function passed to xbeginthread
44 */
45
46static VOID WrapperThread(PVOID pvArgs)
47{
48 EXCEPTIONREGISTRATIONRECORD regRec = { NULL, NULL };
49 APIRET apiret;
50 THREADDATA *ptd = (THREADDATA*)pvArgs;
51
52# ifdef FORTIFY
53 Fortify_EnterScope();
54 Fortify_BecomeOwner(pvArgs);
55# endif
56
57 regRec.ExceptionHandler = HandleException;
58 apiret = DosSetExceptionHandler(&regRec);
59 if (apiret != NO_ERROR) {
60 Dos_Error(MB_ENTER, apiret, HWND_DESKTOP, pszSrcFile, __LINE__,
61 "DosSetExceptionHandler");
62 }
63
64#if 0 // 11 Dec 08 SHL fixme tobe gone - debug
65 {
66 static UINT when;
67 if (++when == 2)
68 *(char*)0 = 0;
69 }
70#endif
71
72 (*ptd->pfnThread)(ptd->pvArgs); // Invoke thread
73
74 xfree(pvArgs, pszSrcFile, __LINE__);
75
76 if (apiret == NO_ERROR) {
77 apiret = DosUnsetExceptionHandler(&regRec);
78 if (apiret != NO_ERROR) {
79 Dos_Error(MB_ENTER, apiret, HWND_DESKTOP, pszSrcFile, __LINE__,
80 "DosUnsetExceptionHandler");
81 }
82 }
83
84# ifdef FORTIFY
85 Fortify_LeaveScope();
86# endif
87
88 // Time to disappear
89
90}
91
92/**
93 * _beginthread wrapper which supplies exception handler support
94 */
95
96int xbeginthread(VOID (*pfnThread)(PVOID),
97 UINT cStackBytes,
98 PVOID pvArgs,
99 PSZ pszSrcFile,
100 UINT uiLineNumber)
101{
102 int rc;
103 THREADDATA *ptd = (THREADDATA *)xmalloc(sizeof(THREADDATA), pszSrcFile, __LINE__);
104 ptd->pfnThread = pfnThread;
105 ptd->pvArgs = pvArgs;
106 rc = _beginthread(WrapperThread, NULL, cStackBytes, ptd);
107 if (rc == -1)
108 Runtime_Error(pszSrcFile, uiLineNumber,
109 GetPString(IDS_COULDNTSTARTTHREADTEXT));
110 return rc;
111}
112
113/**
114 * Handle exception
115 * Calls exceptq if available or handles internally
116 */
117
118ULONG HandleException(PEXCEPTIONREPORTRECORD pReport,
119 PEXCEPTIONREGISTRATIONRECORD pReg,
120 PCONTEXTRECORD pContext,
121 PVOID pv)
122{
123 BOOL handled = FALSE;
124 ULONG ex = pReport->ExceptionNum;
125 time_t now;
126 struct tm *ptm;
127 char *pszTime;
128 PIB *ppib;
129 TIB *ptib;
130 ULONG ulpid;
131 ULONG ultid;
132 APIRET apiret;
133 HMODULE hmod;
134
135 static unsigned working;
136 static PSZ pszExcpMsg = "Caught exception %lx in process %lx (%lu) thread %u at %.24s";
137
138 // Try to report cascading exceptions in handler only once
139 // This simple test can get confused if multiple threads trap at same time
140 if (++working > 1) {
141 if (working == 2) {
142 DbgMsg(pszSrcFile, __LINE__, "Caught exception %lx at %p while handler active",
143 ex, pContext->ctx_RegEip);
144 }
145 working--;
146 return XCPT_CONTINUE_SEARCH;
147 }
148
149 // Bypass exceptions we don't handle or exceptions we ignore
150 // Keep in sync with exceptq selections since exceptq will ignore anyway
151 if ((pReport->fHandlerFlags & (EH_UNWINDING | EH_NESTED_CALL)) ||
152 (ex & XCPT_SEVERITY_CODE) != XCPT_FATAL_EXCEPTION ||
153 ex == XCPT_ASYNC_PROCESS_TERMINATE ||
154 ex == XCPT_PROCESS_TERMINATE ||
155 ex == XCPT_UNWIND ||
156 ex == XCPT_SIGNAL ||
157 ex == XCPT_BREAKPOINT ||
158 ex == XCPT_SINGLE_STEP)
159 {
160 working--;
161 return XCPT_CONTINUE_SEARCH;
162 }
163
164 now = time(NULL);
165 ptm = localtime(&now);
166 pszTime = asctime(ptm);
167
168 apiret = DosGetInfoBlocks(&ptib, &ppib);
169 if (apiret) {
170 ulpid = 0;
171 ultid = 0;
172 }
173 else {
174 ulpid = ppib->pib_ulpid;
175 ultid = ptib->tib_ptib2->tib2_ultid;
176 }
177
178 DbgMsg(pszSrcFile, __LINE__, pszExcpMsg,
179 ex, ulpid, ulpid, ultid, pszTime);
180
181 // Report errors with DbgMsg, Dos_Error unsafe here
182 apiret = DosLoadModule (0, 0, "exceptq" ,&hmod);
183 if (apiret) {
184 if (apiret != ERROR_FILE_NOT_FOUND)
185 DbgMsg(pszSrcFile, __LINE__, "DosLoadModule(exceptq) reported error %u", apiret);
186 }
187 else {
188 ERR pfn;
189 apiret = DosQueryProcAddr(hmod, 0, "MYHANDLER", (PFN*)&pfn);
190 if (apiret)
191 DbgMsg(pszSrcFile, __LINE__, "DosQueryProcAddr(MYHANDLER) reported error %u", apiret);
192 else {
193 // DbgMsg(pszSrcFile, __LINE__, "Invoking exceptq handler at %p", pfn);
194 (*pfn)(pReport, pReg, pContext, pv);
195 handled = TRUE;
196 }
197 DosFreeModule(hmod);
198 }
199
200 // If exceptq not available use local handler
201 if (!handled) {
202 union {
203 struct {
204 ULONG ulEBP;
205 ULONG ulEIP;
206 } stk32;
207 struct {
208 USHORT usBP;
209 USHORT usIP;
210 USHORT usCS; // > 1 and < 0xfff
211 } stk16;
212 } u;
213 ULONG ulObjNum;
214 ULONG ulOffset;
215 ULONG ulEIP;
216 ULONG ulEBP;
217 CHAR szFileName[CCHMAXPATH];
218 BOOL is32Bit;
219 APIRET apiret;
220 ULONG flags;
221 ULONG cnt;
222 ULONG ulOldEBP = 0;
223 INT c;
224 FILE* fp;
225 CHAR *modea = "a";
226
227 handled = TRUE;
228
229 // Write stack trace to log file - let kernel do popuplog.os2
230 fp = xfopen("fm2_trap.log", modea, pszSrcFile, __LINE__, TRUE);
231 if (!fp)
232 fp = stderr; // Oh well
233
234 if (fp != stderr) {
235 fputc('\n', fp);
236 fprintf(fp, pszExcpMsg,
237 ex, ulpid, ulpid, ultid, pszTime);
238 fputc('\n', stderr);
239 }
240 fputc('\n', stderr);
241
242 // fixme to support mixed 32-bit/16-bit stacks, 5b = FLAT_CS
243 if (pContext->ctx_SegCs == 0x5b) {
244 is32Bit = TRUE; // Assume 32-bit
245 u.stk32.ulEIP = pContext->ctx_RegEip;
246 u.stk32.ulEBP = pContext->ctx_RegEbp;
247 }
248 else {
249 is32Bit = FALSE;
250 u.stk16.usIP = (SHORT) pContext->ctx_RegEip;
251 u.stk16.usBP = (SHORT) pContext->ctx_RegEbp;
252 }
253
254 // Walk stack frames
255 for (c = 0; c < 100; c++) {
256 if (is32Bit) {
257 ulEIP = u.stk32.ulEIP;
258 ulEBP = u.stk32.ulEBP;
259 }
260 else {
261 ulEIP = ((ULONG) (pContext->ctx_SegCs & ~7) << 13) | u.stk16.usIP;
262 ulEBP = ((ULONG) (pContext->ctx_SegSs & ~7) << 13) | u.stk16.usBP;
263 }
264
265 apiret = DosQueryModFromEIP(&hmod, &ulObjNum, CCHMAXPATH, szFileName,
266 &ulOffset, ulEIP);
267 if (apiret) {
268 ulObjNum = 0;
269 ulOffset = 0;
270 strcpy(szFileName, "n/a");
271 }
272 else
273 ulObjNum++; // Number from 1..n for display
274
275 fprintf(fp, " Stack frame %u @ %lx:%lx %s %lx:%lx\n",
276 c,
277 pContext->ctx_SegCs, ulEIP,
278 szFileName, ulObjNum, ulOffset);
279
280 if (apiret)
281 break;
282
283 if (!ulEBP || ulEBP <= ulOldEBP)
284 break;
285
286 cnt = sizeof(u);
287
288 apiret = DosQueryMem((void*)ulEBP, &cnt, &flags);
289 if (apiret || (flags & (PAG_COMMIT | PAG_READ)) != (PAG_COMMIT | PAG_READ))
290 break; // We are lost
291
292 ulOldEBP = ulEBP;
293 memcpy((void*)&u, (void*)ulEBP, sizeof(u));
294
295 } // for
296
297 if (fp || fp != stderr)
298 fclose(fp);
299
300 } // if !handled
301
302 // DbgMsg(pszSrcFile, __LINE__, "We are going to die now");
303
304 working--;
305
306 return XCPT_CONTINUE_SEARCH; // Let other handlers see exception
307
308}
Note: See TracBrowser for help on using the repository browser.