source: trunk/dll/excputil.c@ 1801

Last change on this file since 1801 was 1801, checked in by Steven Levine, 10 years ago

HandleException: check for ignore before checking for cascade

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