source: trunk/dll/excputil.c@ 1505

Last change on this file since 1505 was 1442, checked in by Gregg Young, 16 years ago

Fixed 2 memory management problems; changes to get FORTIFY build to work again.

  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1
2/* excputil.c - exception handlers
3 $Id: excputil.c 1442 2009-07-14 00:16:38Z 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
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#include "fortify.h"
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{
48 EXCEPTIONREGISTRATIONRECORD regRec = { NULL, NULL };
49 APIRET apiret;
50 THREADDATA *ptd = (THREADDATA*)pvArgs;
51
52# ifdef FORTIFY
53 Fortify_EnterScope();
54 Fortify_BecomeOwner(pvArgs);
55# endif
56
57 regRec.ExceptionHandler = HandleException;
58 apiret = DosSetExceptionHandler(&regRec);
59 if (apiret != NO_ERROR) {
60 Dos_Error(MB_ENTER, apiret, HWND_DESKTOP, pszSrcFile, __LINE__,
61 "DosSetExceptionHandler");
62 }
63
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
72 (*ptd->pfnThread)(ptd->pvArgs); // Invoke thread
73
74 xfree(pvArgs, pszSrcFile, __LINE__);
75
76 if (apiret == NO_ERROR) {
77 apiret = DosUnsetExceptionHandler(&regRec);
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,
98 PVOID pvArgs,
99 PSZ pszSrcFile,
100 UINT uiLineNumber)
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)
108 Runtime_Error(pszSrcFile, uiLineNumber,
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;
130 ULONG ulpid;
131 ULONG ultid;
132 APIRET apiret;
133 HMODULE hmod;
134
135 static unsigned working;
136 static PSZ pszExcpMsg = "Caught exception %lx in process %lx (%lu) thread %u at %.24s";
137
138 // Try to report cascading exceptions in handler only once
139 // This simple test can get confused if multiple threads trap at same time
140 if (++working > 1) {
141 if (working == 2) {
142 DbgMsg(pszSrcFile, __LINE__, "Caught exception %lx at %p while handler active",
143 ex, pContext->ctx_RegEip);
144 }
145 working--;
146 return XCPT_CONTINUE_SEARCH;
147 }
148
149 // Bypass exceptions we don't handle or exceptions we ignore
150 // Keep in sync with exceptq selections since exceptq will ignore anyway
151 if ((pReport->fHandlerFlags & (EH_UNWINDING | EH_NESTED_CALL)) ||
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)
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) {
170 ulpid = 0;
171 ultid = 0;
172 }
173 else {
174 ulpid = ppib->pib_ulpid;
175 ultid = ptib->tib_ptib2->tib2_ultid;
176 }
177
178 DbgMsg(pszSrcFile, __LINE__, pszExcpMsg,
179 ex, ulpid, ulpid, ultid, pszTime);
180
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);
192 else {
193 // DbgMsg(pszSrcFile, __LINE__, "Invoking exceptq handler at %p", pfn);
194 (*pfn)(pReport, pReg, pContext, pv);
195 handled = TRUE;
196 }
197 DosFreeModule(hmod);
198 }
199
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;
225
226 handled = TRUE;
227
228 // Write stack trace to log file - let kernel do popuplog.os2
229 fp = fopen("fm2_trap.log", "a");
230 if (!fp)
231 fp = stderr; // Oh well
232
233 if (fp != stderr) {
234 fputc('\n', fp);
235 fprintf(fp, pszExcpMsg,
236 ex, ulpid, ulpid, ultid, pszTime);
237 fputc('\n', stderr);
238 }
239 fputc('\n', stderr);
240
241 // fixme to support mixed 32-bit/16-bit stacks, 5b = FLAT_CS
242 if (pContext->ctx_SegCs == 0x5b) {
243 is32Bit = TRUE; // Assume 32-bit
244 u.stk32.ulEIP = pContext->ctx_RegEip;
245 u.stk32.ulEBP = pContext->ctx_RegEbp;
246 }
247 else {
248 is32Bit = FALSE;
249 u.stk16.usIP = pContext->ctx_RegEip;
250 u.stk16.usBP = pContext->ctx_RegEbp;
251 }
252
253 // Walk stack frames
254 for (c = 0; c < 100; c++) {
255 if (is32Bit) {
256 ulEIP = u.stk32.ulEIP;
257 ulEBP = u.stk32.ulEBP;
258 }
259 else {
260 ulEIP = ((ULONG) (pContext->ctx_SegCs & ~7) << 13) | u.stk16.usIP;
261 ulEBP = ((ULONG) (pContext->ctx_SegSs & ~7) << 13) | u.stk16.usBP;
262 }
263
264 apiret = DosQueryModFromEIP(&hmod, &ulObjNum, CCHMAXPATH, szFileName,
265 &ulOffset, ulEIP);
266 if (apiret) {
267 ulObjNum = 0;
268 ulOffset = 0;
269 strcpy(szFileName, "n/a");
270 }
271 else
272 ulObjNum++; // Number from 1..n for display
273
274 fprintf(fp, " Stack frame %u @ %lx:%lx %s %lx:%lx\n",
275 c,
276 pContext->ctx_SegCs, ulEIP,
277 szFileName, ulObjNum, ulOffset);
278
279 if (apiret)
280 break;
281
282 if (!ulEBP || ulEBP <= ulOldEBP)
283 break;
284
285 cnt = sizeof(u);
286
287 apiret = DosQueryMem((void*)ulEBP, &cnt, &flags);
288 if (apiret || (flags & (PAG_COMMIT | PAG_READ)) != (PAG_COMMIT | PAG_READ))
289 break; // We are lost
290
291 ulOldEBP = ulEBP;
292 memcpy((void*)&u, (void*)ulEBP, sizeof(u));
293
294 } // for
295
296 if (fp || fp != stderr)
297 fclose(fp);
298
299 } // if !handled
300
301 // DbgMsg(pszSrcFile, __LINE__, "We are going to die now");
302
303 working--;
304
305 return XCPT_CONTINUE_SEARCH; // Let other handlers see exception
306
307}
Note: See TracBrowser for help on using the repository browser.