source: trunk/dll/excputil.c@ 1844

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

Use xDosGetInfoBlocks in HandleException

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