source: trunk/dll/excputil.c@ 1331

Last change on this file since 1331 was 1331, checked in by Steven Levine, 17 years ago

Ticket 26: Add exceptq and exception handler support

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