source: trunk/dll/excputil.c@ 1707

Last change on this file since 1707 was 1707, checked in by Steven Levine, 12 years ago

Support git, svn, hg etc. version control metadata directory excludes

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