source: trunk/dll/excputil.c@ 1570

Last change on this file since 1570 was 1544, checked in by Gregg Young, 15 years ago

Changes to fopen and _fsopen to allow FM2 to be loaded in high memory

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