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
RevLine 
[1331]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
[1332]24// #include <os2.h>
[1331]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
[1332]31#include "excputil.h"
[1331]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{
[1332]47 EXCEPTIONREGISTRATIONRECORD regRec = { NULL, NULL };
[1331]48 APIRET apiret;
49 THREADDATA *ptd = (THREADDATA*)pvArgs;
50
51# ifdef FORTIFY
52 Fortify_EnterScope();
53 Fortify_BecomeOwner(pvArgs);
54# endif
55
[1332]56 regRec.ExceptionHandler = HandleException;
57 apiret = DosSetExceptionHandler(&regRec);
[1331]58 if (apiret != NO_ERROR) {
59 Dos_Error(MB_ENTER, apiret, HWND_DESKTOP, pszSrcFile, __LINE__,
60 "DosSetExceptionHandler");
61 }
62
[1332]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
[1331]71 (*ptd->pfnThread)(ptd->pvArgs); // Invoke thread
72
73 xfree(pvArgs, pszSrcFile, __LINE__);
74
75 if (apiret == NO_ERROR) {
[1332]76 apiret = DosUnsetExceptionHandler(&regRec);
[1331]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,
[1332]97 PVOID pvArgs,
98 PSZ pszSrcFile,
99 UINT uiLineNumber)
[1331]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)
[1332]107 Runtime_Error(pszSrcFile, uiLineNumber,
[1331]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;
[1332]129 ULONG ulpid;
130 ULONG ultid;
[1331]131 APIRET apiret;
[1332]132 HMODULE hmod;
[1331]133
134 static unsigned working;
[1332]135 static PSZ pszExcpMsg = "Caught exception %lx in process %lx (%lu) thread %u at %.24s";
[1331]136
[1332]137 // Try to report cascading exceptions in handler only once
138 // This simple test can get confused if multiple threads trap at same time
[1331]139 if (++working > 1) {
140 if (working == 2) {
[1332]141 DbgMsg(pszSrcFile, __LINE__, "Caught exception %lx at %p while handler active",
[1331]142 ex, pContext->ctx_RegEip);
143 }
144 working--;
145 return XCPT_CONTINUE_SEARCH;
146 }
147
[1332]148 // Bypass exceptions we don't handle or exceptions we ignore
149 // Keep in sync with exceptq selections since exceptq will ignore anyway
[1331]150 if ((pReport->fHandlerFlags & (EH_UNWINDING | EH_NESTED_CALL)) ||
[1332]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)
[1331]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) {
[1332]169 ulpid = 0;
170 ultid = 0;
[1331]171 }
[1332]172 else {
173 ulpid = ppib->pib_ulpid;
174 ultid = ptib->tib_ptib2->tib2_ultid;
175 }
[1331]176
[1332]177 DbgMsg(pszSrcFile, __LINE__, pszExcpMsg,
178 ex, ulpid, ulpid, ultid, pszTime);
[1331]179
[1332]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);
[1331]191 else {
[1332]192 // DbgMsg(pszSrcFile, __LINE__, "Invoking exceptq handler at %p", pfn);
193 (*pfn)(pReport, pReg, pContext, pv);
194 handled = TRUE;
[1331]195 }
[1332]196 DosFreeModule(hmod);
197 }
[1331]198
[1332]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;
[1331]224
[1332]225 handled = TRUE;
[1331]226
[1332]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
[1331]231
[1332]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);
[1331]239
[1332]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;
[1331]257 }
258 else {
[1332]259 ulEIP = ((ULONG) (pContext->ctx_SegCs & ~7) << 13) | u.stk16.usIP;
260 ulEBP = ((ULONG) (pContext->ctx_SegSs & ~7) << 13) | u.stk16.usBP;
[1331]261 }
262
[1332]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
[1331]272
[1332]273 fprintf(fp, " Stack frame %u @ %lx:%lx %s %lx:%lx\n",
274 c,
275 pContext->ctx_SegCs, ulEIP,
276 szFileName, ulObjNum, ulOffset);
[1331]277
[1332]278 if (apiret)
279 break;
[1331]280
[1332]281 if (!ulEBP || ulEBP <= ulOldEBP)
282 break;
[1331]283
[1332]284 cnt = sizeof(u);
[1331]285
[1332]286 apiret = DosQueryMem((void*)ulEBP, &cnt, &flags);
287 if (apiret || (flags & (PAG_COMMIT | PAG_READ)) != (PAG_COMMIT | PAG_READ))
288 break; // We are lost
[1331]289
[1332]290 ulOldEBP = ulEBP;
291 memcpy((void*)&u, (void*)ulEBP, sizeof(u));
[1331]292
[1332]293 } // for
[1331]294
[1332]295 if (fp || fp != stderr)
296 fclose(fp);
[1331]297
[1332]298 } // if !handled
[1331]299
[1332]300 // DbgMsg(pszSrcFile, __LINE__, "We are going to die now");
[1331]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.