source: trunk/src/kernel32/exceptstackdump.cpp@ 21610

Last change on this file since 21610 was 21610, checked in by dmik, 14 years ago

kernel32: Fixed: Parsing .SYM files when printing the stack trace in debug mode was not thread safe which caused garbage and nested crashes.

File size: 14.2 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 <os2.h> //No wrappers needed
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(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, SymFile);
160 Buffer[SymDef32.cbSymName] = 0x00;
161// dprintf(("%s\n", Buffer));
162#ifdef RAS
163 strncpy(Info, Buffer, cbInfo);
164#else
165 strcpy (Info, Buffer);
166#endif
167 rc = TRUE;
168 break;
169 }
170 }
171 else
172 {
173 //SvL: If it's an exact match, then the app put a procedure
174 // address on the stack; ignore that
175 if (LastVal == TrapOffset) {
176 break;
177 }
178 }
179
180 if (SymDef32.wSymVal > TrapOffset)
181 {
182 // symbol found
183#ifdef RAS
184 snprintf(Info, cbInfo, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
185#else
186 sprintf(Info, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
187#endif
188 }
189 LastVal = SymDef32.wSymVal;
190 Buffer[0] = SymDef32.achSymName[0];
191 fread(&Buffer[1], 1, SymDef32.cbSymName, SymFile);
192 Buffer[SymDef32.cbSymName] = 0x00;
193
194 if (SymDef32.wSymVal > TrapOffset)
195 {
196 // symbol found, as above
197#ifdef RAS
198 snprintf(&Info[strlen(Info)], cbInfo - strlen(Info), " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
199#else
200 sprintf(&Info[strlen(Info)], " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
201#endif
202 rc = TRUE;
203 break;
204 }
205 /*printf("32 Bit Symbol <%s> Address %p",Buffer,SymDef32.wSymVal); */
206#ifdef FIX64KLIMIT
207 SymOffset += sizeof (SYMDEF32) + SymDef32.cbSymName - 1;
208#endif
209 }
210 else
211 {
212 // 16-bit symbol:
213 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
214
215 if (fExactMatch)
216 {
217 if (SymDef16.wSymVal == TrapOffset)
218 {
219 Buffer[0] = SymDef16.achSymName[0];
220 fread(&Buffer[1], 1, SymDef16.cbSymName, SymFile);
221 Buffer[SymDef16.cbSymName] = 0x00;
222// dprintf(("%s\n", Buffer));
223#ifdef RAS
224 strncpy(Info, Buffer, cbInfo);
225#else
226 strcpy (Info, Buffer);
227#endif
228 rc = TRUE;
229 break;
230 }
231 }
232 else
233 {
234 //SvL: If it's an exact match, then the app put a procedure
235 // address on the stack; ignore that
236 if (LastVal == TrapOffset) {
237 break;
238 }
239 }
240
241 if (SymDef16.wSymVal > TrapOffset)
242 {
243#ifdef RAS
244 snprintf(Info, cbInfo, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
245#else
246 sprintf(Info, "between %s + 0x%X", Buffer, TrapOffset - LastVal);
247#endif
248 }
249 LastVal = SymDef16.wSymVal;
250 Buffer[0] = SymDef16.achSymName[0];
251 fread(&Buffer[1], 1, SymDef16.cbSymName, SymFile);
252 Buffer[SymDef16.cbSymName] = 0x00;
253 if (SymDef16.wSymVal > TrapOffset)
254 {
255#ifdef RAS
256 snprintf(&Info[strlen(Info)], cbInfo - strlen(Info), " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
257#else
258 sprintf(&Info[strlen(Info)], " and %s - 0x%X\n", Buffer, LastVal - TrapOffset);
259#endif
260 rc = TRUE;
261 break;
262 }
263 /*printf("16 Bit Symbol <%s> Address %p",Buffer,SymDef16.wSymVal); */
264#ifdef FIX64KLIMIT
265 SymOffset += sizeof (SYMDEF16) + SymDef16.cbSymName - 1;
266#endif
267 } // endif
268 }
269#ifdef FIX64KLIMIT
270 if (SymNum < SegDef.cSymbols)
271 {
272#endif
273 break;
274#ifdef FIX64KLIMIT
275 }
276#endif
277 } // endif
278 SegOffset = NEXTSEGDEFOFFSET(SegDef);
279 } // endwhile
280endofprintsym:
281 if(SymFile) fclose(SymFile);
282// if(rc == FALSE) dprintf(("\n"));
283 if(rc == FALSE) strcpy (Info, "\n");
284 return rc;
285}
286BOOL dbgPrintSYMInfo(CHAR * SymFileName, ULONG Object, ULONG TrapOffset,
287 BOOL fExactMatch)
288{
289 static char szInfo[256];
290 BOOL rc = dbgGetSYMInfo (SymFileName, Object, TrapOffset,
291 szInfo, sizeof (szInfo), fExactMatch);
292 dprintf(("%s", szInfo));
293 return rc;
294}
295//******************************************************************************
296//******************************************************************************
297void dbgPrintStack(PEXCEPTIONREPORTRECORD pERepRec,
298 PEXCEPTIONREGISTRATIONRECORD pERegRec,
299 PCONTEXTRECORD pCtxRec,
300 PVOID p)
301{
302 ULONG Size, Attr, hMod, ObjNum, Offset, addr;
303 APIRET rc;
304 PTIB ptib = NULL;
305 PPIB ppib = NULL;
306 CHAR Name[CCHMAXPATH] = "unknown";
307 ULONG *stacktop, *stackbase;
308 UCHAR instr;
309 static BOOL fEntered = FALSE;
310
311 if(DosGetInfoBlocks(&ptib, &ppib) || ptib == NULL) {
312 return;
313 }
314 if(fEntered == TRUE) {
315 return;
316 }
317
318 fEntered = TRUE;
319
320 stacktop = (ULONG *)ptib->tib_pstacklimit - 4;
321 stackbase = (ULONG *)ptib->tib_pstack;
322 if(pCtxRec->ctx_RegEsp < (ULONG)stacktop && pCtxRec->ctx_RegEsp > (ULONG)stackbase)
323 {
324 stackbase = (ULONG *)pCtxRec->ctx_RegEsp;
325 }
326 else
327 if(pCtxRec->ctx_RegEbp < (ULONG)stacktop && pCtxRec->ctx_RegEbp > (ULONG)stackbase)
328 {
329 stackbase = (ULONG *)pCtxRec->ctx_RegEbp;
330 }
331 else stackbase = (ULONG *)getESP();
332
333 dprintf(("** BEGIN STACK DUMP **\n"));
334 while(stacktop > stackbase)
335 {
336 Size = 10;
337 rc = DosQueryMem((PVOID) (stacktop), &Size, &Attr);
338 if(rc != NO_ERROR || !(Attr & PAG_COMMIT) || (Size < 4))
339 {
340 break;
341 }
342
343 addr = *stacktop;
344 Size = 16;
345 rc = DosQueryMem((PVOID) (*stacktop-16), &Size, &Attr);
346 if(rc != NO_ERROR || ((Attr & (PAG_EXECUTE|PAG_READ|PAG_COMMIT)) != (PAG_EXECUTE|PAG_READ|PAG_COMMIT)) || (Size < 16)) {
347// dprintf(("skiploop %x (rc %x, Attr %x Size %d)\n", *stacktop, rc, Attr, Size));
348 if(WinExe && WinExe->insideModule(addr) && WinExe->insideModuleCode(addr)) {
349 sprintf(Name, "%s", WinExe->getModuleName());
350 dprintf(("%-13s at 0x%08x\n", Name, addr));
351 }
352 else {
353 Win32DllBase *dll = Win32DllBase::findModuleByAddr(addr);
354 if(dll && dll->insideModuleCode(addr)) {
355 sprintf(Name, "%s", dll->getModuleName());
356 dprintf(("%-13s at 0x%08x\n", Name, addr));
357 }
358 }
359
360 goto skiploop;
361 }
362#if 0
363 instr = *(UCHAR *)(((ULONG)*stacktop) - 5);
364 if(instr == 0xE8) {//call with displacement
365 addr = *(ULONG *)(((ULONG)*stacktop)-4);
366 addr+= (((ULONG)*stacktop)-5);
367 }
368// else {
369// if(*(UCHAR *)(((ULONG)*stacktop) - 6) == 0xff) {
370// modrm = *(UCHAR *)(((ULONG)*stacktop) - 5);
371// }
372 else
373#endif
374 addr = *stacktop;
375
376 rc = DosQueryModFromEIP(&hMod, &ObjNum, sizeof(Name),
377 Name, &Offset, addr);
378 if(rc == NO_ERROR && ObjNum != -1)
379 {
380 DosQueryModuleName(hMod, sizeof(Name), Name);
381
382 int namelen = strlen(Name);
383 if(namelen > 3)
384 {
385 if(addr > (ULONG)ptib->tib_pstacklimit || addr < (ULONG)ptib->tib_pstack) {
386 // print module and object
387 dprintf(("%-13s %04X at 0x%08x ", OSLibStripPath(Name), ObjNum + 1, addr));
388
389 strcpy(Name + namelen - 3, "SYM");
390 dbgPrintSYMInfo(Name, ObjNum, Offset, FALSE);
391 }
392 }
393 else
394 {
395 dprintf(("*Unknown* at %x\n", addr));
396 }
397 }
398 else {
399 if(WinExe && WinExe->insideModule(addr) && WinExe->insideModuleCode(addr)) {
400 sprintf(Name, "%s", WinExe->getModuleName());
401 dprintf(("%-13s at 0x%08x\n", Name, addr));
402 }
403 else {
404 Win32DllBase *dll = Win32DllBase::findModuleByAddr(addr);
405 if(dll && dll->insideModuleCode(addr)) {
406 sprintf(Name, "%s", dll->getModuleName());
407 dprintf(("%-13s at 0x%08x\n", Name, addr));
408 }
409 }
410// dprintf(("unknown %x at 0x%x\n", stacktop, addr));
411 }
412skiploop:
413 stacktop -= 1;
414 } //while
415
416 addr = pCtxRec->ctx_RegEip;
417 if(WinExe && WinExe->insideModule(addr) && WinExe->insideModuleCode(addr)) {
418 sprintf(Name, "%s", WinExe->getModuleName());
419 dprintf(("%-13s at 0x%08x\n", Name, addr));
420 }
421 else {
422 Win32DllBase *dll = Win32DllBase::findModuleByAddr(addr);
423 if(dll && dll->insideModuleCode(addr)) {
424 sprintf(Name, "%s", dll->getModuleName());
425 dprintf(("%-13s at 0x%08x\n", Name, addr));
426 }
427 }
428
429 dprintf(("** END OF STACK DUMP **\n"));
430 fEntered = FALSE;
431}
432//******************************************************************************
433//******************************************************************************
Note: See TracBrowser for help on using the repository browser.