source: trunk/dll/excputil.c@ 1332

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

Ticket 26: Clean up output. Add logic to support thread 1.

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