source: trunk/src/kernel32/exceptstackdump.cpp

Last change on this file was 22042, checked in by dmik, 13 years ago

kernel32: Serialize stack trace logging on crashes to make sure it's not mixed with other entries.

File size: 14.7 KB
Line 
1/* $Id: exceptstackdump.cpp,v 1.5 2002-05-10 14:55:11 sandervl Exp $ */
2/*
3 * Stack dump code
4 *
5 * Based on XFolder's stack dumping facility:
6 * Copyright (C) 1992-99 Ulrich M”ller,
7 * Kim Rasmussen,
8 * Marc Fiammante,
9 * John Currier,
10 * Anthony Cruise.
11 *
12 */
13
14#define INCL_MISC
15#define INCL_BASE
16#include <os2wrap.h> //Odin32 OS/2 api wrappers
17#include <stdio.h>
18#include <string.h>
19#include <misc.h>
20#include "exceptstackdump.h"
21#include "exceptutil.h"
22#include "asmutil.h"
23#include "oslibmisc.h"
24#include "winexebase.h"
25#include "windllbase.h"
26
27#include <_ras.h>
28
29#define DBG_LOCALLOG DBG_exceptstackdump
30#include "dbglocal.h"
31
32int SYSTEM EXPORT WriteLogNoEOL(const char *tekst, ...);
33
34#define FIX64KLIMIT
35
36#undef dprintf
37#ifdef RAS
38# ifdef DEBUG
39# define dprintf(a) RasLogNoEOL a; if(DbgEnabledKERNEL32[DBG_LOCALLOG] == 1) WriteLogNoEOL a
40# else
41# define dprintf(a) RasLogNoEOL a;
42# endif
43#else
44# ifdef DEBUG
45# define dprintf(a) if(DbgEnabledKERNEL32[DBG_LOCALLOG] == 1) WriteLogNoEOL a
46# else
47# define dprintf(a)
48# endif
49#endif
50
51/* ******************************************************************
52 * *
53 * PART 3: ANALYZE SYMBOL (.SYM) FILE *
54 * *
55 ********************************************************************/
56
57/*
58 *@@ dbgPrintSYMInfo:
59 * this gets called by dbgPrintStack to check if a SYM
60 * file with the same filename exists and try to
61 * get the info from there.
62 *
63 * This gets called for every line of the stack
64 * walk, but only if getting the information from
65 * the debug code failed, e.g. because no debug code
66 * was available.
67 * The file pointer is in the "Source file" column
68 * every time.
69 *
70 * New with V0.84.
71 */
72
73BOOL dbgGetSYMInfo(CHAR * SymFileName, ULONG Object, ULONG TrapOffset,
74 CHAR *Info, ULONG cbInfo, BOOL fExactMatch)
75{
76 FILE *SymFile;
77 MAPDEF MapDef;
78 SEGDEF SegDef;
79 SEGDEF *pSegDef;
80 SYMDEF32 SymDef32;
81 SYMDEF16 SymDef16;
82 char Buffer[256];
83 int SegNum, SymNum, LastVal;
84 unsigned long int SegOffset,
85 SymOffset, SymPtrOffset;
86 int rc = FALSE;
87
88 // open .SYM file
89 SymFile = fopen(SymFileName, "rb");
90 if (SymFile == 0)
91 {
92// dprintf(("Could not open symbol file %s", SymFileName));
93 goto endofprintsym;
94 } // endif
95
96 // read in first map definition
97 fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
98
99 SegOffset = SEGDEFOFFSET(MapDef);
100
101 // go thru all segments
102 for (SegNum = 0; SegNum < MapDef.cSegs; SegNum++)
103 {
104 // printf("Scanning segment #%d Offset %4.4hX",SegNum+1,SegOffset);
105 if (fseek(SymFile, SegOffset, SEEK_SET))
106 {
107// dprintf(("Seek error."));
108 goto endofprintsym;
109 }
110
111 // read in segment definition
112 fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
113 if (SegNum == Object)
114 {
115 // stack object found:
116 Buffer[0] = 0x00;
117 LastVal = 0;
118
119#ifdef FIX64KLIMIT
120 // Custom build dll's SYM file is much greater than 64K.
121 // SYM file structures use 16 bit offsets in the file and
122 // therefore these offsets can't be directly used as they
123 // are overflowed.
124 // Some offsets like segment definition offsets are
125 // paragraph (*16) ones and will overflow for an 1 meg file.
126 // In particular this affects SYMbol searching algorithm
127 // used here.
128 // With the #ifdef it will be changed to so we will
129 // extract symbol by symbol from the file instead of using
130 // symbol table that is far further 64K fence.
131
132 // Offset of first symbol
133 SymOffset = sizeof (SEGDEF) - 1 + SegDef.cbSegName;
134#endif
135
136 // go thru all symbols in this object
137 for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
138 {
139#ifndef FIX64KLIMIT
140 // read in symbol offset USHORT
141 SymPtrOffset = SYMDEFOFFSET(SegOffset, SegDef, SymNum);
142 fseek(SymFile, SymPtrOffset, SEEK_SET);
143 fread(&SymOffset, sizeof(unsigned short int), 1, SymFile);
144#endif
145
146 // go to symbol definition
147 fseek(SymFile, SymOffset + SegOffset, SEEK_SET);
148
149 if (SegDef.bFlags & 0x01)
150 {
151 // 32-bit symbol:
152 fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
153
154 if (fExactMatch)
155 {
156 if (SymDef32.wSymVal == TrapOffset)
157 {
158 Buffer[0] = SymDef32.achSymName[0];
159 fread(&Buffer[1], 1, SymDef32.cbSymName - 1, SymFile);
160 Buffer[SymDef32.cbSymName] = 0x00;
161// dprintf(("%s\n", Buffer));
162#if defined(RAS) || defined(__GNUC__)
163 strncpy(Info, Buffer, cbInfo);
164 strncat(Info, "\n", cbInfo);
165#else
166 strcpy (Info, Buffer);
167 strcat(Info, "\n");
168#endif
169 rc = TRUE;
170 break;
171 }
172 }
173 else
174 {
175 //SvL: If it's an exact match, then the app put a procedure
176 // address on the stack; ignore that
177 if (LastVal == TrapOffset) {
178 break;
179 }
180 }
181
182 if (SymDef32.wSymVal > TrapOffset)
183 {
184 // symbol found
185#if defined(RAS) || defined(__GNUC__)
186 snprintf(Info, cbInfo, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
187#else
188 sprintf(Info, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
189#endif
190 }
191 LastVal = SymDef32.wSymVal;
192 Buffer[0] = SymDef32.achSymName[0];
193 fread(&Buffer[1], 1, SymDef32.cbSymName, SymFile);
194 Buffer[SymDef32.cbSymName] = 0x00;
195
196 if (SymDef32.wSymVal > TrapOffset)
197 {
198 // symbol found, as above
199#if defined(RAS) || defined(__GNUC__)
200 snprintf(&Info[strlen(Info)], cbInfo - strlen(Info), " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
201#else
202 sprintf(&Info[strlen(Info)], " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
203#endif
204 rc = TRUE;
205 break;
206 }
207 /*printf("32 Bit Symbol <%s> Address %p",Buffer,SymDef32.wSymVal); */
208#ifdef FIX64KLIMIT
209 SymOffset += sizeof (SYMDEF32) + SymDef32.cbSymName - 1;
210#endif
211 }
212 else
213 {
214 // 16-bit symbol:
215 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
216
217 if (fExactMatch)
218 {
219 if (SymDef16.wSymVal == TrapOffset)
220 {
221 Buffer[0] = SymDef16.achSymName[0];
222 fread(&Buffer[1], 1, SymDef16.cbSymName - 1, SymFile);
223 Buffer[SymDef16.cbSymName] = 0x00;
224// dprintf(("%s\n", Buffer));
225#if defined(RAS) || defined(__GNUC__)
226 strncpy(Info, Buffer, cbInfo);
227 strncat(Info, "\n", cbInfo);
228#else
229 strcpy (Info, Buffer);
230 strcat(Info, "\n");
231#endif
232 rc = TRUE;
233 break;
234 }
235 }
236 else
237 {
238 //SvL: If it's an exact match, then the app put a procedure
239 // address on the stack; ignore that
240 if (LastVal == TrapOffset) {
241 break;
242 }
243 }
244
245 if (SymDef16.wSymVal > TrapOffset)
246 {
247#if defined(RAS) || defined(__GNUC__)
248 snprintf(Info, cbInfo, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
249#else
250 sprintf(Info, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
251#endif
252 }
253 LastVal = SymDef16.wSymVal;
254 Buffer[0] = SymDef16.achSymName[0];
255 fread(&Buffer[1], 1, SymDef16.cbSymName, SymFile);
256 Buffer[SymDef16.cbSymName] = 0x00;
257 if (SymDef16.wSymVal > TrapOffset)
258 {
259#if defined(RAS) || defined(__GNUC__)
260 snprintf(&Info[strlen(Info)], cbInfo - strlen(Info), " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
261#else
262 sprintf(&Info[strlen(Info)], " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
263#endif
264 rc = TRUE;
265 break;
266 }
267 /*printf("16 Bit Symbol <%s> Address %p",Buffer,SymDef16.wSymVal); */
268#ifdef FIX64KLIMIT
269 SymOffset += sizeof (SYMDEF16) + SymDef16.cbSymName - 1;
270#endif
271 } // endif
272 }
273#ifdef FIX64KLIMIT
274 if (SymNum < SegDef.cSymbols)
275 {
276#endif
277 break;
278#ifdef FIX64KLIMIT
279 }
280#endif
281 } // endif
282 SegOffset = NEXTSEGDEFOFFSET(SegDef);
283 } // endwhile
284endofprintsym:
285 if(SymFile) fclose(SymFile);
286// if(rc == FALSE) dprintf(("\n"));
287 if(rc == FALSE) strcpy (Info, "\n");
288 return rc;
289}
290BOOL dbgPrintSYMInfo(CHAR * SymFileName, ULONG Object, ULONG TrapOffset,
291 BOOL fExactMatch)
292{
293 static char szInfo[256];
294 BOOL rc = dbgGetSYMInfo (SymFileName, Object, TrapOffset,
295 szInfo, sizeof (szInfo), fExactMatch);
296 dprintf(("%s", szInfo));
297 return rc;
298}
299//******************************************************************************
300//******************************************************************************
301void dbgPrintStack(PEXCEPTIONREPORTRECORD pERepRec,
302 PEXCEPTIONREGISTRATIONRECORD pERegRec,
303 PCONTEXTRECORD pCtxRec,
304 PVOID p)
305{
306 ULONG Size, Attr, hMod, ObjNum, Offset, addr;
307 APIRET rc;
308 PTIB ptib = NULL;
309 PPIB ppib = NULL;
310 CHAR Name[CCHMAXPATH] = "unknown";
311 ULONG *stacktop, *stackbase;
312 UCHAR instr;
313 static BOOL fEntered = FALSE;
314
315 if(DosGetInfoBlocks(&ptib, &ppib) || ptib == NULL) {
316 return;
317 }
318 if(fEntered == TRUE) {
319 return;
320 }
321
322 // make sure the stack trace is not intermixed with other log entries
323 dprintfLock();
324
325 fEntered = TRUE;
326
327 stacktop = (ULONG *)ptib->tib_pstacklimit - 4;
328 stackbase = (ULONG *)ptib->tib_pstack;
329 if(pCtxRec->ctx_RegEsp < (ULONG)stacktop && pCtxRec->ctx_RegEsp > (ULONG)stackbase)
330 {
331 stackbase = (ULONG *)pCtxRec->ctx_RegEsp;
332 }
333 else
334 if(pCtxRec->ctx_RegEbp < (ULONG)stacktop && pCtxRec->ctx_RegEbp > (ULONG)stackbase)
335 {
336 stackbase = (ULONG *)pCtxRec->ctx_RegEbp;
337 }
338 else stackbase = (ULONG *)getESP();
339
340 dprintf(("** BEGIN STACK DUMP **\n"));
341 while(stacktop > stackbase)
342 {
343 Size = 10;
344 rc = DosQueryMem((PVOID) (stacktop), &Size, &Attr);
345 if(rc != NO_ERROR || !(Attr & PAG_COMMIT) || (Size < 4))
346 {
347 break;
348 }
349
350 addr = *stacktop;
351 Size = 16;
352 rc = DosQueryMem((PVOID) (*stacktop-16), &Size, &Attr);
353 if(rc != NO_ERROR || ((Attr & (PAG_EXECUTE|PAG_READ|PAG_COMMIT)) != (PAG_EXECUTE|PAG_READ|PAG_COMMIT)) || (Size < 16)) {
354// dprintf(("skiploop %x (rc %x, Attr %x Size %d)\n", *stacktop, rc, Attr, Size));
355 if(WinExe && WinExe->insideModule(addr) && WinExe->insideModuleCode(addr)) {
356 sprintf(Name, "%s", WinExe->getModuleName());
357 dprintf(("%-13s at 0x%08x\n", Name, addr));
358 }
359 else {
360 Win32DllBase *dll = Win32DllBase::findModuleByAddr(addr);
361 if(dll && dll->insideModuleCode(addr)) {
362 sprintf(Name, "%s", dll->getModuleName());
363 dprintf(("%-13s at 0x%08x\n", Name, addr));
364 }
365 }
366
367 goto skiploop;
368 }
369#if 0
370 instr = *(UCHAR *)(((ULONG)*stacktop) - 5);
371 if(instr == 0xE8) {//call with displacement
372 addr = *(ULONG *)(((ULONG)*stacktop)-4);
373 addr+= (((ULONG)*stacktop)-5);
374 }
375// else {
376// if(*(UCHAR *)(((ULONG)*stacktop) - 6) == 0xff) {
377// modrm = *(UCHAR *)(((ULONG)*stacktop) - 5);
378// }
379 else
380#endif
381 addr = *stacktop;
382
383 rc = DosQueryModFromEIP(&hMod, &ObjNum, sizeof(Name),
384 Name, &Offset, addr);
385 if(rc == NO_ERROR && ObjNum != -1)
386 {
387 DosQueryModuleName(hMod, sizeof(Name), Name);
388
389 int namelen = strlen(Name);
390 if(namelen > 3)
391 {
392 if(addr > (ULONG)ptib->tib_pstacklimit || addr < (ULONG)ptib->tib_pstack) {
393 // print module and object
394 dprintf(("%-13s %04X at 0x%08x ", OSLibStripPath(Name), ObjNum + 1, addr));
395
396 strcpy(Name + namelen - 3, "SYM");
397 dbgPrintSYMInfo(Name, ObjNum, Offset, FALSE);
398 }
399 }
400 else
401 {
402 dprintf(("*Unknown* at %x\n", addr));
403 }
404 }
405 else {
406 if(WinExe && WinExe->insideModule(addr) && WinExe->insideModuleCode(addr)) {
407 sprintf(Name, "%s", WinExe->getModuleName());
408 dprintf(("%-13s at 0x%08x\n", Name, addr));
409 }
410 else {
411 Win32DllBase *dll = Win32DllBase::findModuleByAddr(addr);
412 if(dll && dll->insideModuleCode(addr)) {
413 sprintf(Name, "%s", dll->getModuleName());
414 dprintf(("%-13s at 0x%08x\n", Name, addr));
415 }
416 }
417// dprintf(("unknown %x at 0x%x\n", stacktop, addr));
418 }
419skiploop:
420 stacktop -= 1;
421 } //while
422
423 addr = pCtxRec->ctx_RegEip;
424 if(WinExe && WinExe->insideModule(addr) && WinExe->insideModuleCode(addr)) {
425 sprintf(Name, "%s", WinExe->getModuleName());
426 dprintf(("%-13s at 0x%08x\n", Name, addr));
427 }
428 else {
429 Win32DllBase *dll = Win32DllBase::findModuleByAddr(addr);
430 if(dll && dll->insideModuleCode(addr)) {
431 sprintf(Name, "%s", dll->getModuleName());
432 dprintf(("%-13s at 0x%08x\n", Name, addr));
433 }
434 }
435
436 dprintf(("** END OF STACK DUMP **\n"));
437 fEntered = FALSE;
438
439 dprintfUnlock();
440}
441//******************************************************************************
442//******************************************************************************
Note: See TracBrowser for help on using the repository browser.