update dev300-m58
[ooovba.git] / sal / osl / os2 / debug.c
blob315fed4bad15bb1bd1c7886617fedc5017a88509
1 /*
2 *@@sourcefile debug.c:
3 * this file contains debugging functions for the
4 * exception handlers in except.c.
6 * This code is capable of unwinding the stack from
7 * a given address and trying to get function names
8 * and source line numbers, either from the respective
9 * module's debug code (if present) or from a SYM file,
10 * which is searched for in the directory of the module
11 * or in ?:\OS2\PDPSI\PMDF\WARP4.
13 * This file incorporates code from the following:
14 * -- Marc Fiammante, John Currier, Kim Rasmussen,
15 * Anthony Cruise (EXCEPT3.ZIP package for a generic
16 * exception handling DLL, available at Hobbes).
18 * Usage: All OS/2 programs.
20 * Note: Version numbering in this file relates to XWorkplace version
21 * numbering.
23 *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
24 *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
26 *@@header "helpers\debug.h"
30 * This file Copyright (C) 1992-99 Ulrich M”ller,
31 * Kim Rasmussen,
32 * Marc Fiammante,
33 * John Currier,
34 * Anthony Cruise.
35 * This file is part of the "XWorkplace helpers" source package.
36 * This is free software; you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published
38 * by the Free Software Foundation, in version 2 as it comes in the
39 * "COPYING" file of the XWorkplace main distribution.
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Public License for more details.
46 //#define DEBUG_SYMDUMP // enable to dump sym file to log
48 //YD commented, since we need unsigned char BYTE!
49 //#define OS2EMX_PLAIN_CHAR
50 //Also gcc char is signed, while most structures requires unsigned data!
51 //Raised limits for all fields!
53 // this is needed for "os2emx.h"; if this is defined,
54 // emx will define PSZ as _signed_ char, otherwise
55 // as unsigned char
57 #define INCL_DOSPROCESS
58 #define INCL_DOSMODULEMGR
59 #define INCL_DOSMISC
60 #define INCL_DOSERRORS
61 #include <os2.h>
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <string.h>
67 #define DONT_REPLACE_MALLOC
68 #include "helpers\setup.h" // code generation and debugging options
70 #include "helpers\debug.h"
71 #include "helpers\dosh.h"
73 #pragma hdrstop
75 #include <fcntl.h>
76 #ifdef __EMX__
77 #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
78 #endif
79 #include <sys\stat.h>
80 #include <share.h>
81 #include <io.h>
83 #ifndef DWORD
84 #define DWORD unsigned long
85 #endif
86 #ifndef WORD
87 #define WORD unsigned short
88 #endif
90 #pragma stack16(512)
91 #define HF_STDERR 2
94 *@@category: Helpers\Control program helpers\Exceptions/debugging
95 * See except.c and debug.c.
98 /* ******************************************************************
100 * Global variables
102 ********************************************************************/
104 // this specifies whether we're dealing with 32-bit code;
105 // this gets changed whenever 16-bit count is detected
106 static BOOL f32bit = TRUE;
109 * Global variables for Read32PmDebug:
113 ULONG func_ofs;
114 ULONG pubfunc_ofs;
115 //YD 17/07/06 c++ namespace can generate really long
116 //YD names, use a large buffer!
117 char func_name[16*1024];
118 ULONG var_ofs = 0;
120 struct {
121 BYTE name[128];
122 ULONG stack_offset;
123 USHORT type_idx;
124 } autovar_def[1024];
126 #pragma pack(1)
128 BYTE *type_name[] =
130 "8 bit signed ",
131 "16 bit signed ",
132 "32 bit signed ",
133 "Unknown (0x83) ",
134 "8 bit unsigned ",
135 "16 bit unsigned ",
136 "32 bit unsigned ",
137 "Unknown (0x87) ",
138 "32 bit real ",
139 "64 bit real ",
140 "80 bit real ",
141 "Unknown (0x8B) ",
142 "64 bit complex ",
143 "128 bit complex ",
144 "160 bit complex ",
145 "Unknown (0x8F) ",
146 "8 bit boolean ",
147 "16 bit boolean ",
148 "32 bit boolean ",
149 "Unknown (0x93) ",
150 "8 bit character ",
151 "16 bit characters ",
152 "32 bit characters ",
153 "void ",
154 "15 bit unsigned ",
155 "24 bit unsigned ",
156 "31 bit unsigned ",
157 "Unknown (0x9B) ",
158 "Unknown (0x9C) ",
159 "Unknown (0x9D) ",
160 "Unknown (0x9E) ",
161 "Unknown (0x9F) ",
162 "near pointer to 8 bit signed ",
163 "near pointer to 16 bit signed ",
164 "near pointer to 32 bit signed ",
165 "Unknown (0xA3) ",
166 "near pointer to 8 bit unsigned ",
167 "near pointer to 16 bit unsigned ",
168 "near pointer to 32 bit unsigned ",
169 "Unknown (0xA7) ",
170 "near pointer to 32 bit real ",
171 "near pointer to 64 bit real ",
172 "near pointer to 80 bit real ",
173 "Unknown (0xAB) ",
174 "near pointer to 64 bit complex ",
175 "near pointer to 128 bit complex ",
176 "near pointer to 160 bit complex ",
177 "Unknown (0xAF) ",
178 "near pointer to 8 bit boolean ",
179 "near pointer to 16 bit boolean ",
180 "near pointer to 32 bit boolean ",
181 "Unknown (0xB3) ",
182 "near pointer to 8 bit character ",
183 "near pointer to 16 bit characters",
184 "near pointer to 32 bit characters",
185 "near pointer to void ",
186 "near pointer to 15 bit unsigned ",
187 "near pointer to 24 bit unsigned ",
188 "near pointer to 31 bit unsigned ",
189 "Unknown (0xBB) ",
190 "Unknown (0xBC) ",
191 "Unknown (0xBD) ",
192 "Unknown (0xBE) ",
193 "Unknown (0xBF) ",
194 "far pointer to 8 bit signed ",
195 "far pointer to 16 bit signed ",
196 "far pointer to 32 bit signed ",
197 "Unknown (0xC3) ",
198 "far pointer to 8 bit unsigned ",
199 "far pointer to 16 bit unsigned ",
200 "far pointer to 32 bit unsigned ",
201 "Unknown (0xC7) ",
202 "far pointer to 32 bit real ",
203 "far pointer to 64 bit real ",
204 "far pointer to 80 bit real ",
205 "Unknown (0xCB) ",
206 "far pointer to 64 bit complex ",
207 "far pointer to 128 bit complex ",
208 "far pointer to 160 bit complex ",
209 "Unknown (0xCF) ",
210 "far pointer to 8 bit boolean ",
211 "far pointer to 16 bit boolean ",
212 "far pointer to 32 bit boolean ",
213 "Unknown (0xD3) ",
214 "far pointer to 8 bit character ",
215 "far pointer to 16 bit characters ",
216 "far pointer to 32 bit characters ",
217 "far pointer to void ",
218 "far pointer to 15 bit unsigned ",
219 "far pointer to 24 bit unsigned ",
220 "far pointer to 31 bit unsigned ",
223 // Thanks to John Currier:
224 // Do not call 16 bit code in myHandler function to prevent call
225 // to __EDCThunkProlog and problems is guard page exception handling
226 // Also reduce the stack size to 1K for true 16 bit calls.
227 // 16 bit calls thunk will now only occur on fatal exceptions
228 #pragma stack16(1024)
230 // ------------------------------------------------------------------
231 // Last 8 bytes of 16:16 file when CODEVIEW debugging info is present
232 #pragma pack(1)
233 struct _eodbug
235 unsigned short dbug; // 'NB' signature
236 unsigned short ver; // version
237 unsigned long dfaBase; // size of codeview info
238 } G_eodbug;
240 #define DBUGSIG 0x424E
241 #define SSTMODULES 0x0101
242 #define SSTPUBLICS 0x0102
243 #define SSTTYPES 0x0103
244 #define SSTSYMBOLS 0x0104
245 #define SSTSRCLINES 0x0105
246 #define SSTLIBRARIES 0x0106
247 #define SSTSRCLINES2 0x0109
248 #define SSTSRCLINES32 0x010B
250 typedef struct _SYMBASE
252 unsigned short dbug; // 'NB' signature
253 unsigned short ver; // version
254 unsigned long lfoDir; // file offset to dir entries
255 } SYMBASE;
257 typedef struct _SSDIR
259 unsigned short sst; // SubSection Type
260 unsigned short modindex; // Module index number
261 unsigned long lfoStart; // Start of section
262 unsigned short cb; // Size of section
263 } SSDIR;
265 typedef struct _SSDIR32
267 unsigned short sst; // SubSection Type
268 unsigned short modindex; // Module index number
269 unsigned long lfoStart; // Start of section
270 unsigned long cb; // Size of section
271 } SSDIR32;
273 typedef struct _SSMODULE
275 unsigned short csBase; // code segment base
276 unsigned short csOff; // code segment offset
277 unsigned short csLen; // code segment length
278 unsigned short ovrNum; // overlay number
279 unsigned short indxSS; // Index into sstLib or 0
280 unsigned short reserved;
281 BYTE csize; // size of prefix string
282 } SSMODULE;
284 typedef struct _SSMOD32
286 unsigned short csBase; // code segment base
287 unsigned long csOff; // code segment offset
288 unsigned long csLen; // code segment length
289 unsigned long ovrNum; // overlay number
290 unsigned short indxSS; // Index into sstLib or 0
291 unsigned long reserved;
292 BYTE csize; // size of prefix string
293 } SSMOD32;
295 typedef struct _SSPUBLIC
297 unsigned short offset;
298 unsigned short segment;
299 unsigned short type;
300 BYTE csize;
301 } SSPUBLIC;
303 typedef struct _SSPUBLIC32
305 unsigned long offset;
306 unsigned short segment;
307 unsigned short type;
308 BYTE csize;
309 } SSPUBLIC32;
311 typedef struct _SSLINEENTRY32
313 unsigned short LineNum;
314 unsigned short FileNum;
315 unsigned long Offset;
316 } SSLINEENTRY32;
318 typedef struct _FIRSTLINEENTRY32
320 unsigned short LineNum;
321 unsigned char entry_type;
322 unsigned char reserved;
323 unsigned short numlines;
324 unsigned short segnum;
325 } FIRSTLINEENTRY32;
327 typedef struct _SSFILENUM32
329 unsigned long first_displayable; // Not used
330 unsigned long number_displayable; // Not used
331 unsigned long file_count; // number of source files
332 } SSFILENUM32;
335 *@@ XDEBUGINFO:
336 * buffers for Read... funcs.
338 *@@added V0.9.4 (2000-06-15) [umoeller]
341 typedef struct _XDEBUGINFO
343 char szNrFile[300]; // receives source file
344 char szNrLine[300]; // receives line number
345 //YD 17/07/06 c++ namespace can generate really long
346 //YD names, use a large buffer!
347 char szNrPub[16*1024]; // receives function name
349 struct new_seg *pseg;
350 struct o32_obj *pobj; // flat .EXE object table entry
352 SYMBASE base;
354 SSDIR *pDirTab;
355 SSDIR32 *pDirTab32;
356 unsigned char *pEntTab;
357 unsigned long lfaBase;
358 SSMOD32 ssmod32;
359 SSPUBLIC32 sspub32;
361 SSMODULE ssmod;
362 SSPUBLIC sspub;
363 } XDEBUGINFO, *PXDEBUGINFO;
366 USHORT _THUNK_FUNCTION (Dos16SizeSeg) ();
367 //APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
368 USHORT DosSizeSeg (USHORT Seg, PULONG16 Size)
370 return ((USHORT)
371 (_THUNK_PROLOG (2+4);
372 _THUNK_SHORT (Seg);
373 _THUNK_FLAT (Size);
374 _THUNK_CALL (Dos16SizeSeg)));
377 #pragma pack()
379 /* ******************************************************************
381 * PART 1: ANALYZE DEBUG CODE
383 ********************************************************************/
385 static int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
386 static int Read32PmDebug(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
389 *@@ WriteAddressInfo:
390 * formats and writes a line into the trap log
391 * file.
393 * This gets called for each line from the
394 * stack dump. At this point, the line in the
395 * trap log already has:
397 + CS:EIP : 000109FF XMLVIEW :0
398 + ^^^ and we write here
399 * After this call, we have.
401 + CS:EIP : 000109FF XMLVIEW :0 xxx.c 123 ConfirmCreate__Fv
402 + ^^^ and we write here
404 *@@added V0.9.12 (2001-05-12) [umoeller]
407 static VOID WriteDebugInfo(FILE *LogFile, // in: open log file
408 PXDEBUGINFO pxdi) // in: debug info
410 fprintf(LogFile,
411 "%s%s%s",
412 pxdi->szNrFile,
413 pxdi->szNrLine,
414 pxdi->szNrPub);
418 *@@ dbgPrintDebugInfo:
419 * this is the main entry point into analyzing debug
420 * code.
422 * This analyzes a given address and tries to find
423 * debug code descriptions for this address. If found,
424 * the information is written to the given log file.
426 * Gets called from dbgPrintStack.
428 * This returns NO_ERROR if the could was successfully
429 * analyzed or something != 0 if we failed.
431 * New with V0.84.
434 APIRET dbgPrintDebugInfo(FILE *LogFile, // out: log file to write to
435 CHAR *FileName, // in: EXE/DLL module file name
436 ULONG Object, // in: trapping object (from DosQueryModFromEIP)
437 ULONG TrapOffset) // in: trapping address (from DosQueryModFromEIP)
439 APIRET rc = 0;
440 int ModuleFile = 0;
441 static struct exe_hdr OldExeHeader;
442 static struct new_exe NewExeHeader;
444 ULONG ulSegment = Object + 1; // segment no. is object no. + 1
446 XDEBUGINFO xdi;
447 memset(&xdi, 0, sizeof(xdi));
449 // open the module file for reading to analyze the code
450 ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
452 if (ModuleFile != -1)
454 // file found:
455 // read old Exe header
456 if (read(ModuleFile, (void*)&OldExeHeader, 64) == -1L)
458 fprintf(LogFile, "errno %d reading old exe header\n", errno);
459 close(ModuleFile);
460 return 2;
462 // seek to new Exe header
463 if (lseek(ModuleFile, (long)E_LFANEW(OldExeHeader), SEEK_SET) == -1L)
465 fprintf(LogFile, "errno %d seeking to new exe header\n", errno);
466 close(ModuleFile);
467 return 3;
469 if (read(ModuleFile, (void *)&NewExeHeader, 64) == -1L)
471 fprintf(LogFile, "errno %d reading new exe header\n", errno);
472 close(ModuleFile);
473 return 4;
476 // check EXE signature
477 if (NE_MAGIC(NewExeHeader) == E32MAGIC)
480 * flat 32 executable:
484 // do analysis for 32-bit code
485 if (!(rc = Read32PmDebug(LogFile,
486 &xdi, // output
487 ModuleFile,
488 ulSegment,
489 TrapOffset,
490 FileName)))
491 WriteDebugInfo(LogFile, &xdi);
493 close(ModuleFile);
495 // rc !=0 try with DBG file
496 if (rc != 0)
498 strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name
499 ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
500 if (ModuleFile != -1)
502 if (!(rc = Read32PmDebug(LogFile,
503 &xdi,
504 ModuleFile,
505 ulSegment,
506 TrapOffset,
507 FileName)))
508 WriteDebugInfo(LogFile, &xdi);
510 close(ModuleFile);
514 return rc;
516 else
518 if (NE_MAGIC(NewExeHeader) == NEMAGIC)
521 * 16:16 executable:
525 if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader),
526 sizeof(struct new_seg)))
527 == NULL)
529 fprintf(LogFile, "Out of memory!");
530 close(ModuleFile);
531 return -1;
533 if ( lseek(ModuleFile,
534 E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader),
535 SEEK_SET) == -1L)
537 fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName);
538 free(xdi.pseg);
539 close(ModuleFile);
540 return 9;
543 if (read(ModuleFile,
544 (void *)xdi.pseg,
545 NE_CSEG(NewExeHeader) * sizeof(struct new_seg))
546 == -1)
548 fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName);
549 free(xdi.pseg);
550 close(ModuleFile);
551 return 10;
554 if (!(rc = Read16CodeView(LogFile,
555 &xdi,
556 ModuleFile,
557 ulSegment,
558 TrapOffset,
559 FileName)))
560 WriteDebugInfo(LogFile, &xdi);
562 free(xdi.pseg);
563 close(ModuleFile);
565 // rc !=0 try with DBG file
566 if (rc != 0)
568 strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name
569 ModuleFile = sopen(FileName,
570 O_RDONLY | O_BINARY, SH_DENYNO);
571 if (ModuleFile != -1)
573 if (!(rc = Read16CodeView(LogFile,
574 &xdi,
575 ModuleFile,
576 ulSegment,
577 TrapOffset,
578 FileName)))
579 WriteDebugInfo(LogFile, &xdi);
581 close(ModuleFile);
584 return rc;
586 else
589 * Unknown executable:
593 fprintf(LogFile, "Error, could not find exe signature");
594 close(ModuleFile);
595 return 11;
598 } // end if (ModuleFile != -1)
599 else
601 fprintf(LogFile, "Error %d opening module file %s", errno, FileName);
602 return 1;
603 } // endif
605 // return 0; we never get here
608 char fname[256],
609 ModName[80];
610 char ename[256],
611 dummy[256];
613 #define MAX_USERDEFS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
614 #define MAX_POINTERS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
616 USHORT userdef_count;
617 USHORT pointer_count;
619 struct one_userdef_rec
621 USHORT idx;
622 USHORT type_index;
623 BYTE name[33];
624 } one_userdef[MAX_USERDEFS];
626 struct one_pointer_rec
628 USHORT idx;
629 USHORT type_index;
630 BYTE type_qual;
631 BYTE name[33];
632 } one_pointer[MAX_POINTERS];
635 * Read32PmDebug:
636 * parses 32-bit debug code.
637 * Called from dbgPrintDebugInfo for 32-bit modules.
640 static int Read32PmDebug(FILE *LogFile, // in: text log file to write to
641 PXDEBUGINFO pxdi,
642 int ModuleFile, // in: module file opened with sopen()
643 int TrapSeg,
644 int TrapOff,
645 CHAR *FileName)
647 static unsigned int CurrSymSeg, NrSymbol,
648 /* offset, */ NrPublic,
649 NrFile, NrLine, /* NrEntry */
650 numdir, namelen,
651 numlines /* , line */;
652 static int ModIndex;
653 static int bytesread, i, j;
654 static SSLINEENTRY32 LineEntry;
655 static SSFILENUM32 FileInfo;
656 static FIRSTLINEENTRY32 FirstLine;
657 static BYTE dump_vars = FALSE;
658 static USHORT idx;
659 static BOOL read_types;
660 static LONG lSize;
662 ModIndex = 0;
663 // See if any CODEVIEW info
664 if (lseek(ModuleFile, -8L, SEEK_END) == -1)
666 fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
667 return (18);
670 if (read(ModuleFile,
671 (void *)&G_eodbug, 8)
672 == -1)
674 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
675 return (19);
677 if (G_eodbug.dbug != DBUGSIG)
679 // fprintf(LogFile,"\nNo CodeView information stored.\n");
680 return (100);
683 if ( (pxdi->lfaBase = lseek(ModuleFile,
684 -(LONG)G_eodbug.dfaBase,
685 SEEK_END))
686 == -1L)
688 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
689 return (20);
692 if (read(ModuleFile,
693 (void *)&pxdi->base, 8)
694 == -1)
696 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
697 return (21);
700 if (lseek(ModuleFile,
701 pxdi->base.lfoDir - 8 + 4,
702 SEEK_CUR)
703 == -1)
705 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
706 return (22);
709 if (read(ModuleFile,
710 (void *)&numdir, 4)
711 == -1)
713 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
714 return (23);
717 // Read dir table into buffer
718 if ( (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
719 sizeof(SSDIR32)))
720 == NULL)
722 fprintf(LogFile, "Out of memory!");
723 return (-1);
726 if (read(ModuleFile,
727 (void*)pxdi->pDirTab32,
728 numdir * sizeof(SSDIR32))
729 == -1)
731 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
732 free(pxdi->pDirTab32);
733 return (24);
736 i = 0;
737 while (i < numdir)
739 if (pxdi->pDirTab32[i].sst != SSTMODULES)
741 i++;
742 continue;
745 NrPublic = 0x0;
746 NrSymbol = 0;
747 NrLine = 0x0;
748 NrFile = 0x0;
749 CurrSymSeg = 0;
750 // point to subsection
751 lseek(ModuleFile,
752 pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
753 SEEK_SET);
754 read(ModuleFile,
755 (void*)&pxdi->ssmod32.csBase,
756 sizeof(SSMOD32));
757 read(ModuleFile,
758 (void*)ModName,
759 (unsigned)pxdi->ssmod32.csize);
760 ModIndex = pxdi->pDirTab32[i].modindex;
761 ModName[pxdi->ssmod32.csize] = '\0';
762 i++;
764 read_types = FALSE;
766 while ( (pxdi->pDirTab32[i].modindex == ModIndex)
767 && (i < numdir)
770 // point to subsection
771 lseek(ModuleFile,
772 pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
773 SEEK_SET);
775 switch (pxdi->pDirTab32[i].sst)
777 case SSTPUBLICS:
778 bytesread = 0;
779 while (bytesread < pxdi->pDirTab32[i].cb)
781 bytesread += read(ModuleFile,
782 (void *)&pxdi->sspub32.offset,
783 sizeof(pxdi->sspub32));
784 bytesread += read(ModuleFile,
785 (void*)ename,
786 (unsigned)pxdi->sspub32.csize);
787 ename[pxdi->sspub32.csize] = '\0';
788 if ( (pxdi->sspub32.segment == TrapSeg)
789 && (pxdi->sspub32.offset <= TrapOff)
790 && (pxdi->sspub32.offset >= NrPublic)
793 NrPublic = pubfunc_ofs = pxdi->sspub32.offset;
794 read_types = TRUE;
795 sprintf(pxdi->szNrPub,
796 "%s %s (%s)\n",
797 (pxdi->sspub32.type == 1)
798 ? " Abs"
799 : " ",
800 ename,
801 ModName
803 // but continue, because there might be a
804 // symbol that comes closer
807 break;
809 // Read symbols, so we can dump the variables on the stack
810 case SSTSYMBOLS:
811 if (TrapSeg != pxdi->ssmod32.csBase)
812 break;
814 bytesread = 0;
815 while (bytesread < pxdi->pDirTab32[i].cb)
817 static USHORT usLength;
818 static USHORT usLengthSym;
819 static BYTE b1,
821 static BYTE bType;
822 // *ptr;
823 static ULONG ofs;
824 // static ULONG last_addr = 0;
825 //YD 17/07/06 c++ namespace can generate really long
826 //YD names, use a large buffer!
827 static BYTE str[16*1024];
828 static struct symseg_rec symseg;
829 static struct symauto_rec symauto;
830 static struct symproc_rec symproc;
832 // Read the length of this subentry
833 bytesread += read(ModuleFile, &b1, 1);
834 if (b1 & 0x80)
836 bytesread += read(ModuleFile, &b2, 1);
837 usLength = ((b1 & 0x7F) << 8) + b2;
839 else
840 usLength = b1;
842 ofs = tell(ModuleFile);
844 bytesread += read(ModuleFile, &bType, 1);
846 switch (bType)
848 case SYM_CHANGESEG:
849 read(ModuleFile, &symseg, sizeof(symseg));
850 CurrSymSeg = symseg.seg_no;
851 break;
853 case SYM_PROC:
854 case SYM_CPPPROC:
855 read(ModuleFile, &symproc, sizeof(symproc));
856 if (symproc.name_len & 0x80)
858 read(ModuleFile, &b2, 1);
859 usLengthSym = ((symproc.name_len & 0x7F) << 8) + b2;
861 else
863 usLengthSym = symproc.name_len;
865 read(ModuleFile, str, usLengthSym);
866 str[usLengthSym] = 0;
868 if ((CurrSymSeg == TrapSeg) &&
869 (symproc.offset <= TrapOff) &&
870 (symproc.offset >= NrSymbol))
873 dump_vars = TRUE;
874 var_ofs = 0;
875 NrSymbol = symproc.offset;
876 func_ofs = symproc.offset;
878 strcpy(func_name, str);
880 else
882 dump_vars = FALSE;
884 break;
886 case SYM_AUTO:
887 if (!dump_vars)
888 break;
890 read(ModuleFile, &symauto, sizeof(symauto));
891 read(ModuleFile, str, symauto.name_len);
892 if (symauto.name_len==0x80)
893 printf("symauto.name_len==0x80\n");
894 str[symauto.name_len] = 0;
896 strcpy(autovar_def[var_ofs].name, str);
897 autovar_def[var_ofs].stack_offset = symauto.stack_offset;
898 autovar_def[var_ofs].type_idx = symauto.type_idx;
899 var_ofs++;
900 break;
904 bytesread += usLength;
906 lseek(ModuleFile, ofs + usLength, SEEK_SET);
908 break;
910 case SSTTYPES:
911 // if (ModIndex != TrapSeg)
912 if (!read_types)
913 break;
915 bytesread = 0;
916 idx = 0x200;
917 userdef_count = 0;
918 pointer_count = 0;
919 while (bytesread < pxdi->pDirTab32[i].cb)
921 static struct type_rec type;
922 static struct type_userdefrec udef;
923 static struct type_pointerrec point;
924 static ULONG ofs;
925 static BYTE str[256];
927 // Read the length of this subentry
928 ofs = tell(ModuleFile);
930 read(ModuleFile, &type, sizeof(type));
931 bytesread += sizeof(type);
933 switch (type.type)
935 case TYPE_USERDEF:
936 if (userdef_count >= MAX_USERDEFS)
937 break;
939 read(ModuleFile, &udef, sizeof(udef));
940 read(ModuleFile, str, udef.name_len);
941 str[udef.name_len] = 0;
943 // Insert userdef in table
944 one_userdef[userdef_count].idx = idx;
945 one_userdef[userdef_count].type_index = udef.type_index;
946 memcpy(one_userdef[userdef_count].name,
947 str,
948 _min(udef.name_len + 1, 32));
949 one_userdef[userdef_count].name[32] = 0;
950 userdef_count++;
951 break;
953 case TYPE_POINTER:
954 if (pointer_count >= MAX_POINTERS)
955 break;
957 read(ModuleFile, &point, sizeof(point));
958 read(ModuleFile, str, point.name_len);
959 str[point.name_len] = 0;
961 // Insert userdef in table
962 one_pointer[pointer_count].idx = idx;
963 one_pointer[pointer_count].type_index = point.type_index;
964 memcpy(one_pointer[pointer_count].name,
965 str,
966 _min(point.name_len + 1, 32));
967 one_pointer[pointer_count].name[32] = 0;
968 one_pointer[pointer_count].type_qual = type.type_qual;
969 pointer_count++;
970 break;
973 ++idx;
975 bytesread += type.length;
977 lseek(ModuleFile, ofs + type.length + 2, SEEK_SET);
979 break;
981 case SSTSRCLINES32:
982 if (TrapSeg != pxdi->ssmod32.csBase)
983 break;
985 // read first line
988 read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine));
990 if (FirstLine.LineNum != 0)
992 fprintf(LogFile, "Missing Line table information\n");
993 break;
994 } // endif
995 numlines = FirstLine.numlines;
996 // Other type of data skip 4 more bytes
997 if (FirstLine.entry_type < 4)
999 read(ModuleFile, (void *)&lSize, 4);
1000 if (FirstLine.entry_type == 3)
1001 lseek(ModuleFile, lSize, SEEK_CUR);
1004 while (FirstLine.entry_type == 3);
1006 for (j = 0; j < numlines; j++)
1008 switch (FirstLine.entry_type)
1010 case 0:
1011 read(ModuleFile, (void *)&LineEntry, sizeof(LineEntry));
1012 // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
1013 // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
1014 if ( (LineEntry.LineNum)
1015 && (LineEntry.Offset + pxdi->ssmod32.csOff
1016 <= TrapOff)
1017 && (LineEntry.Offset + pxdi->ssmod32.csOff >= NrLine)
1020 NrLine = LineEntry.Offset;
1021 NrFile = LineEntry.FileNum;
1022 /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ",
1023 * ssmod32.csBase,LineEntry.Offset,
1024 * LineEntry.LineNum); */
1025 sprintf(pxdi->szNrLine, "% 6hu", LineEntry.LineNum);
1027 break;
1029 case 1:
1030 lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR);
1031 break;
1033 case 2:
1034 lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR);
1035 break;
1037 case 3:
1038 lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR);
1039 break;
1041 case 4:
1042 lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR);
1043 break;
1048 if (NrFile != 0)
1050 // file found:
1051 read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo));
1052 namelen = 0;
1053 for (j = 1; j <= FileInfo.file_count; j++)
1055 namelen = 0;
1056 read(ModuleFile, (void *)&namelen, 1);
1057 read(ModuleFile, (void *)ename, namelen);
1058 if (j == NrFile)
1059 break;
1061 ename[namelen] = '\0';
1062 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
1063 sprintf(pxdi->szNrFile, "%11.11s ", ename);
1065 else
1067 // strcat(szNrLine,"\n"); avoid new line for empty name fill
1068 strcpy(pxdi->szNrFile, "file? ");
1069 } // endif
1070 break;
1071 } // end switch
1073 i++;
1074 } // end while modindex
1075 } // End While i < numdir
1076 free(pxdi->pDirTab32);
1077 return (0);
1081 * Read16CodeView:
1082 * parses 16-bit debug code.
1083 * Called from dbgPrintDebugInfo for 16-bit modules.
1086 static int Read16CodeView(FILE *LogFile, // in: text log file to write to
1087 PXDEBUGINFO pxdi,
1088 int fh,
1089 int TrapSeg,
1090 int TrapOff,
1091 CHAR *FileName)
1093 static unsigned short int offset,
1094 NrPublic, NrLine,
1095 numdir,
1096 namelen, numlines,
1097 line;
1098 static int ModIndex;
1099 static int bytesread, i, j;
1101 ModIndex = 0;
1102 // See if any CODEVIEW info
1103 if (lseek(fh, -8L, SEEK_END) == -1)
1105 fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
1106 return (18);
1109 if (read(fh, (void *)&G_eodbug, 8) == -1)
1111 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
1112 return (19);
1114 if (G_eodbug.dbug != DBUGSIG)
1116 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1117 return (100);
1120 if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
1122 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
1123 return (20);
1126 if (read(fh, (void *)&pxdi->base, 8) == -1)
1128 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
1129 return (21);
1132 if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1)
1134 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
1135 return (22);
1138 if (read(fh, (void *)&numdir, 2) == -1)
1140 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
1141 return (23);
1144 // Read dir table into buffer
1145 if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
1147 fprintf(LogFile, "Out of memory!");
1148 return (-1);
1151 if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1)
1153 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
1154 free(pxdi->pDirTab);
1155 return (24);
1158 i = 0;
1159 while (i < numdir)
1161 if (pxdi->pDirTab[i].sst != SSTMODULES)
1163 i++;
1164 continue;
1166 NrPublic = 0x0;
1167 NrLine = 0x0;
1168 // point to subsection
1169 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1170 read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE));
1171 read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize);
1172 ModIndex = pxdi->pDirTab[i].modindex;
1173 ModName[pxdi->ssmod.csize] = '\0';
1174 i++;
1175 while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir)
1177 // point to subsection
1178 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1179 switch (pxdi->pDirTab[i].sst)
1181 case SSTPUBLICS:
1182 bytesread = 0;
1183 while (bytesread < pxdi->pDirTab[i].cb)
1185 bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub));
1186 bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize);
1187 ename[pxdi->sspub.csize] = '\0';
1188 if ((pxdi->sspub.segment == TrapSeg) &&
1189 (pxdi->sspub.offset <= TrapOff) &&
1190 (pxdi->sspub.offset >= NrPublic))
1192 NrPublic = pxdi->sspub.offset;
1193 sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n",
1194 (pxdi->sspub.type == 1) ? " Abs" : " ", ename,
1195 ModName, // ()
1196 pxdi->sspub.segment,
1197 pxdi->sspub.offset
1201 break;
1203 case SSTSRCLINES2:
1204 case SSTSRCLINES:
1205 if (TrapSeg != pxdi->ssmod.csBase)
1206 break;
1207 namelen = 0;
1208 read(fh, (void *)&namelen, 1);
1209 read(fh, (void *)ename, namelen);
1210 ename[namelen] = '\0';
1211 // skip 2 zero bytes
1212 if (pxdi->pDirTab[i].sst == SSTSRCLINES2)
1213 read(fh, (void *)&numlines, 2);
1214 read(fh, (void *)&numlines, 2);
1215 for (j = 0; j < numlines; j++)
1217 read(fh, (void *)&line, 2);
1218 read(fh, (void *)&offset, 2);
1219 if (offset <= TrapOff && offset >= NrLine)
1221 NrLine = offset;
1222 sprintf(pxdi->szNrFile, "% 12.12s ", ename);
1223 sprintf(pxdi->szNrLine, "% 6hu", line);
1224 /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
1225 * ssmod.csBase,offset,line,ModName,ename); */
1228 break;
1229 } // end switch
1230 i++;
1231 } // end while modindex
1232 } // End While i < numdir
1233 free(pxdi->pDirTab);
1234 return (0);
1237 /* ******************************************************************
1239 * PART 2: ANALYZE VARIABLES
1241 ********************************************************************/
1244 * var_value:
1245 * writes a description of a variable type to
1246 * the specified buffer, depending on "type".
1248 *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
1251 static VOID var_value(void *varptr, // in: address of the variable on the stack
1252 char *pszBuf, // out: information
1253 BYTE type) // in: type; if >= 32, we'll call DosQueryMem
1255 ULONG Size = 1,
1256 Attr = 0;
1258 if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
1260 sprintf(pszBuf, "type %d, DosQueryMem failed", type);
1261 return;
1264 if ((Attr & PAG_READ) == 0)
1266 sprintf(pszBuf, "type %d, read-access to value denied", type);
1267 return;
1270 if (type == 0)
1271 sprintf(pszBuf, "%hd", *(signed char*)varptr);
1272 else if (type == 1)
1273 sprintf(pszBuf, "%hd", *(signed short*)varptr);
1274 else if (type == 2)
1275 sprintf(pszBuf, "%ld", *(signed long*)varptr);
1276 else if (type == 4)
1277 sprintf(pszBuf, "%hu", *(BYTE*) varptr);
1278 else if (type == 5)
1279 sprintf(pszBuf, "%hu", *(USHORT*)varptr);
1280 else if (type == 6)
1281 sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
1282 else if (type == 8)
1283 sprintf(pszBuf, "%f", *(float*)varptr);
1284 else if (type == 9)
1285 sprintf(pszBuf, "%f", *(double*)varptr);
1286 else if (type == 10)
1287 sprintf(pszBuf, "%f", (double)(*(long double*)varptr));
1288 else if (type == 16)
1289 sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
1290 else if (type == 17)
1291 sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE");
1292 else if (type == 18)
1293 sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE");
1294 else if (type == 20)
1295 sprintf(pszBuf, "%c", *(char*)varptr);
1296 else if (type == 21)
1297 sprintf(pszBuf, "%hd", (*(short*)varptr));
1298 else if (type == 22)
1299 sprintf(pszBuf, "%ld", *(long*)varptr);
1300 else if (type == 23)
1301 sprintf(pszBuf, "void");
1302 else if (type >= 32)
1304 sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr));
1305 if (Attr & PAG_FREE)
1307 strcat(pszBuf, " unallocated memory");
1309 else
1311 if ((Attr & PAG_COMMIT) == 0x0U)
1313 strcat(pszBuf, " uncommitted");
1314 } // endif
1315 if ((Attr & PAG_WRITE) == 0x0U)
1317 strcat(pszBuf, " unwritable");
1318 } // endif
1319 if ((Attr & PAG_READ) == 0x0U)
1321 strcat(pszBuf, " unreadable");
1322 } // endif
1323 } // endif
1324 } // endif
1325 else
1326 sprintf(pszBuf, "Unknown type %d", type);
1330 * search_userdefs:
1331 * searches the table of userdef's-
1332 * Return TRUE if found.
1335 static BOOL search_userdefs(FILE *LogFile, // in: text log file to write to
1336 ULONG stackofs,
1337 USHORT var_no)
1339 USHORT pos;
1341 for (pos = 0;
1342 pos < userdef_count;
1343 pos++)
1345 if (one_userdef[pos].idx == autovar_def[var_no].type_idx)
1347 if ( (one_userdef[pos].type_index >= 0x80)
1348 // && (one_userdef[pos].type_index <= 0xDA)
1351 static char sszVar3[500] = "complex";
1352 if (one_userdef[pos].type_index <= 0xDA)
1353 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1354 sszVar3,
1355 one_userdef[pos].type_index - 0x80);
1357 fprintf(LogFile,
1358 " %- 6ld %- 20.20s %- 33.33s %s (user)\n",
1359 autovar_def[var_no].stack_offset, // stack offset
1360 autovar_def[var_no].name, // identifier
1361 one_userdef[pos].name, // type name
1362 sszVar3 // composed by var_value
1364 return TRUE;
1366 else
1367 return FALSE;
1371 return FALSE;
1375 * search_pointers:
1379 static BOOL search_pointers(FILE *LogFile, // in: text log file to write to
1380 ULONG stackofs,
1381 USHORT var_no)
1383 USHORT pos, upos;
1384 static BYTE str[35];
1385 static char sszVar[500];
1387 // BYTE type_index;
1389 for (pos = 0;
1390 ( (pos < pointer_count)
1391 && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
1393 pos++);
1395 if (pos < pointer_count)
1397 if ( (one_pointer[pos].type_index >= 0x80)
1398 && (one_pointer[pos].type_index <= 0xDA)
1401 strcpy(str, type_name[one_pointer[pos].type_index - 0x80]);
1402 strcat(str, " *");
1403 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1404 sszVar,
1405 32);
1406 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1407 autovar_def[var_no].stack_offset,
1408 autovar_def[var_no].name,
1409 str,
1410 sszVar);
1411 return TRUE;
1413 else
1415 // If the result isn't a simple type, look for it in the other lists
1416 for (upos = 0;
1417 ( (upos < userdef_count)
1418 && (one_userdef[upos].idx != one_pointer[pos].type_index)
1420 upos++)
1423 if (upos < userdef_count)
1425 strcpy(str, one_userdef[upos].name);
1426 strcat(str, " *");
1427 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1428 sszVar,
1429 32);
1430 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1431 autovar_def[var_no].stack_offset,
1432 autovar_def[var_no].name,
1433 str,
1434 sszVar);
1435 return TRUE;
1437 else
1439 // if it isn't a userdef, for now give up and just print
1440 // as much as we know
1441 sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index);
1443 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1444 sszVar,
1445 32);
1446 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1447 autovar_def[var_no].stack_offset,
1448 autovar_def[var_no].name,
1449 str,
1450 sszVar);
1452 return TRUE;
1457 return FALSE;
1461 *@@ dbgPrintVariables:
1462 * Dumps variables for the specified stack offset
1463 * to the specified log file.
1465 * New with V0.84.
1468 void dbgPrintVariables(FILE *LogFile, // in: text log file to write to
1469 ULONG stackofs)
1471 USHORT n; // , pos;
1472 BOOL AutoVarsFound = FALSE;
1474 if (/* 1 || */ func_ofs == pubfunc_ofs)
1476 for (n = 0;
1477 n < var_ofs;
1478 n++)
1480 if (AutoVarsFound == FALSE)
1482 AutoVarsFound = TRUE;
1483 fprintf(LogFile, " List of auto variables at EBP %p in %s:\n",
1484 (PVOID)stackofs,
1485 func_name);
1486 fprintf(LogFile, " Offset Name Type Value \n");
1487 fprintf(LogFile, " ÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
1490 // If it's one of the simple types
1491 if ( (autovar_def[n].type_idx >= 0x80)
1492 && (autovar_def[n].type_idx <= 0xDA)
1495 static char sszVar2[500];
1497 var_value((void *)(stackofs + autovar_def[n].stack_offset),
1498 sszVar2,
1499 autovar_def[n].type_idx - 0x80);
1501 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
1502 autovar_def[n].stack_offset,
1503 autovar_def[n].name,
1504 type_name[autovar_def[n].type_idx - 0x80],
1505 sszVar2);
1507 else
1508 { // Complex type, check if we know what it is
1509 if (!search_userdefs(LogFile, stackofs, n))
1511 if (!search_pointers(LogFile, stackofs, n))
1513 fprintf(LogFile, " %- 6ld %-20.20s 0x%X (unknown)\n",
1514 autovar_def[n].stack_offset,
1515 autovar_def[n].name,
1516 autovar_def[n].type_idx);
1521 /* if (AutoVarsFound == FALSE)
1523 fprintf(LogFile, " No auto variables found in %s.\n", func_name);
1524 } */
1525 fprintf(LogFile, "\n");
1529 /* ******************************************************************
1531 * PART 3: ANALYZE SYMBOL (.SYM) FILE
1533 ********************************************************************/
1536 *@@ dbgPrintSYMInfo:
1537 * this gets called by dbgPrintStack if dbgPrintDebugInfo
1538 * failed (because no debug code was found) to check if
1539 * maybe a SYM file with the same filename exists and try
1540 * to get the info from there.
1542 * This gets called for every line of the stack
1543 * walk, but only if getting the information from
1544 * the debug code failed, e.g. because no debug code
1545 * was available for an address.
1547 * The file pointer is in the "Source file" column
1548 * every time this gets called.
1550 * New with V0.84.
1552 * Returns 0 if reading the SYM file was successful.
1554 *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
1557 int dbgPrintSYMInfo(FILE *LogFile, // in: text log file to write to
1558 CHAR *SymFileName, // in: SYM file name (can be fully q'fied)
1559 ULONG Object,
1560 ULONG TrapOffset)
1562 static FILE *SymFile;
1563 static MAPDEF MapDef;
1564 static SEGDEF SegDef;
1565 static SYMDEF32 SymDef32;
1566 static SYMDEF16 SymDef16;
1567 static char Buffer[256];
1568 static int SegNum, SymNum, LastVal;
1569 static unsigned long int SegOffset,
1570 SymOffset, SymPtrOffset;
1572 // open .SYM file
1573 #ifdef DEBUG_SYMDUMP
1574 fprintf(LogFile,"Dump of '%s' for object %d\n",SymFileName,Object);
1575 #endif
1576 SymFile = fopen(SymFileName, "rb");
1577 if (SymFile == 0)
1578 return (2);
1580 // read in first map definition
1581 fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
1582 #ifdef DEBUG_SYMDUMP
1583 Buffer[0] = MapDef.achModName[0];
1584 fread(&Buffer[1], 1, MapDef.cbModName-1, SymFile);
1585 Buffer[MapDef.cbModName] = 0x00;
1586 fprintf(LogFile,"Module name '%s'\n",Buffer);
1587 #endif
1589 SegOffset = SEGDEFOFFSET(MapDef);
1590 #ifdef DEBUG_SYMDUMP
1591 fprintf(LogFile,"SegOffset %0x\n",SegOffset);
1592 #endif
1594 // go thru all segments
1595 for (SegNum = 0;
1596 SegNum < MapDef.cSegs;
1597 SegNum++)
1599 #ifdef DEBUG_SYMDUMP
1600 fprintf(LogFile,"Scanning segment #%d Offset %08X\n",SegNum,SegOffset);
1601 #endif
1602 if (fseek(SymFile, SegOffset, SEEK_SET))
1603 // seek error
1604 return (3);
1606 // read in segment definition
1607 fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
1608 #ifdef DEBUG_SYMDUMP
1609 Buffer[0] = 0x00;
1610 if (SegDef.cbSegName>0) {
1611 Buffer[0] = SegDef.achSegName[0];
1612 fread(&Buffer[1], 1, SegDef.cbSegName-1, SymFile);
1613 Buffer[SegDef.cbSegName] = 0x00;
1615 fprintf(LogFile,"Segment name '%s', number %d, flags %02x\n",Buffer,SegNum,SegDef.bFlags);
1616 #endif
1618 if (SegNum == Object)
1620 // stack object found:
1621 Buffer[0] = 0x00;
1622 LastVal = 0;
1624 // go thru all symbols in this object
1625 #ifdef DEBUG_SYMDUMP
1626 fprintf(LogFile,"Scanning #%d symbols\n",SegDef.cSymbols);
1627 #endif
1628 for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
1630 SymPtrOffset=SYMDEFOFFSET(SegOffset,SegDef,SymNum);
1631 fseek(SymFile,SymPtrOffset,SEEK_SET);
1632 fread(&SymOffset,sizeof(unsigned short int),1,SymFile);
1633 fseek(SymFile,SymOffset+SegOffset,SEEK_SET);
1634 if (SegDef.bFlags & 0x01)
1636 // 32-bit symbol:
1637 fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
1638 if (SymDef32.wSymVal > TrapOffset)
1640 // symbol found
1641 fprintf(LogFile,
1642 "between %s + 0x%lX ",
1643 Buffer,
1644 TrapOffset - LastVal);
1645 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1646 LINEDEFOFFSET(SegDef)
1647 ); */
1648 fprintf(LogFile, "\n");
1651 LastVal = SymDef32.wSymVal;
1652 Buffer[0] = SymDef32.achSymName[0];
1653 fread(&Buffer[1], 1, SymDef32.cbSymName-1, SymFile);
1654 Buffer[SymDef32.cbSymName] = 0x00;
1655 #ifdef DEBUG_SYMDUMP
1656 fprintf(LogFile,"32 Bit Symbol Address %08p <%s> \n",SymDef32.wSymVal,Buffer);
1657 #endif
1659 if (SymDef32.wSymVal > TrapOffset)
1661 // symbol found, as above
1662 fprintf(LogFile,
1664 "and %s - 0x%lX ",
1665 Buffer,
1666 LastVal - TrapOffset);
1667 fprintf(LogFile, "\n");
1668 break;
1671 else
1673 // 16-bit symbol:
1674 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
1675 if (SymDef16.wSymVal > TrapOffset)
1677 fprintf(LogFile,
1678 "between %s + %lX\n",
1679 Buffer,
1680 TrapOffset - LastVal);
1682 LastVal = SymDef16.wSymVal;
1683 Buffer[0] = SymDef16.achSymName[0];
1684 fread(&Buffer[1], 1, SymDef16.cbSymName-1, SymFile);
1685 Buffer[SymDef16.cbSymName] = 0x00;
1686 if (SymDef16.wSymVal > TrapOffset)
1688 fprintf(LogFile,
1690 "and %s - %lX\n",
1691 Buffer,
1692 LastVal - TrapOffset);
1693 break;
1695 #ifdef DEBUG_SYMDUMP
1696 fprintf(LogFile,"16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal);
1697 #endif
1698 } // endif
1700 break;
1701 } // endif
1702 SegOffset = NEXTSEGDEFOFFSET(SegDef);
1703 } // endwhile
1704 fclose(SymFile);
1705 return (0); // no error
1708 /* ******************************************************************
1710 * PART 4: dbgPrintStack
1712 ********************************************************************/
1715 *@@ dbgPrintStackFrame:
1716 * parses and dumps one stack frame.
1717 * Called from excPrintStackFrame.
1719 * This calls dbgPrintDebugInfo and, if
1720 * that fails, dbgPrintSYMInfo.
1722 *@@added V0.9.2 (2000-03-10) [umoeller]
1723 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1724 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1727 BOOL dbgPrintStackFrame(FILE *LogFile,
1728 PSZ pszModuleName, // in: module name (fully q'fied)
1729 ULONG ulObject,
1730 ULONG ulOffset)
1732 APIRET arc = 0;
1733 // "Source file"... columns
1735 //YD do not use debug info
1736 #define ENABLE_DEBUG_INFO
1737 #ifdef ENABLE_DEBUG_INFO
1738 // first attempt to analyze the debug code
1739 arc = dbgPrintDebugInfo(LogFile,
1740 pszModuleName,
1741 ulObject,
1742 ulOffset);
1743 #else
1744 arc = 1;
1745 #endif
1747 // if no debug code is available, analyze
1748 // the SYM file instead
1749 if (arc != NO_ERROR)
1751 CHAR szSymName[CCHMAXPATH];
1752 strcpy(szSymName, pszModuleName);
1753 strcpy(szSymName + strlen(szSymName) - 3, "SYM");
1754 arc = dbgPrintSYMInfo(LogFile,
1755 szSymName,
1756 ulObject,
1757 ulOffset);
1758 if (arc != 0)
1760 // SYM file not found in current directory:
1761 // check the SYM files in the \OS2 directory,
1762 // depending on the OS/2 version level:
1763 CHAR szSymFile2[CCHMAXPATH];
1764 PSZ pszFilename = strrchr(szSymName, '\\');
1765 if (pszFilename)
1767 PSZ pszVersionDir = "WARP4";
1768 ULONG aulBuf[3];
1770 DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
1771 QSV_VERSION_MINOR, // 12
1772 &aulBuf, sizeof(aulBuf));
1773 // Warp 3 is reported as 20.30
1774 // Warp 4 is reported as 20.40
1775 // Aurora is reported as 20.45
1777 if (aulBuf[0] == 20)
1779 if (aulBuf[1] == 30)
1780 // Warp 3:
1781 pszVersionDir = "WARP3";
1782 else if (aulBuf[1] >= 40)
1783 // Warp 4 or higher:
1784 // (NOTE: Warp 4 FP 13 now returns 45 also,
1785 // but the SYM files are still in the WARP4 directory...)
1786 // V0.9.3 (2000-04-26) [umoeller]
1787 pszVersionDir = "WARP4";
1790 pszFilename++;
1791 sprintf(szSymFile2,
1792 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1793 doshQueryBootDrive(),
1794 pszVersionDir,
1795 pszFilename);
1796 arc = dbgPrintSYMInfo(LogFile,
1797 szSymFile2,
1798 ulObject,
1799 ulOffset);
1801 // V0.9.3 (2000-04-26) [umoeller]
1802 if ( (arc != 0) // still not found
1803 && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13?
1806 // Warp Server for e-Business (aka Warp 4.5):
1807 // we use the SYM files for the UNI kernel,
1808 // I have found no way to find out whether
1809 // we're running on an SMP kernel
1810 sprintf(szSymFile2,
1811 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1812 doshQueryBootDrive(),
1813 "WARP45_U",
1814 pszFilename);
1815 arc = dbgPrintSYMInfo(LogFile,
1816 szSymFile2,
1817 ulObject,
1818 ulOffset);
1823 if (arc == 2) // file not found
1824 fprintf(LogFile,
1825 "Cannot find symbol file %s\n",
1826 szSymName);
1827 else if (arc != 0)
1828 fprintf(LogFile,
1829 "Error %lu reading symbol file %s\n",
1830 arc,
1831 szSymName);
1834 return (arc == NO_ERROR);
1838 *@@ dbgPrintStack:
1839 * this takes stack data from the TIB and
1840 * context record data structures and tries
1841 * to analyse what the different stack frames
1842 * point to.
1844 * For each stack frame, this calls dbgPrintDebugInfo,
1845 * and, if that fails, dbgPrintSYMInfo.
1847 * New with V0.84.
1849 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1852 VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to
1853 PUSHORT StackBottom,
1854 PUSHORT StackTop,
1855 PUSHORT Ebp,
1856 PUSHORT ExceptionAddress)
1858 PUSHORT RetAddr = 0;
1859 PUSHORT LastEbp = 0;
1860 APIRET rc = 0;
1861 ULONG Size = 0,
1862 Attr = 0;
1863 USHORT Cs = 0,
1864 Ip = 0,
1865 // Bp,
1866 Sp = 0;
1867 static char Name[CCHMAXPATH];
1868 HMODULE hMod = 0;
1869 ULONG ObjNum = 0;
1870 ULONG Offset = 0;
1871 BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru
1873 // Note: we can't handle stacks bigger than 64K for now...
1874 Sp = (USHORT) (((ULONG) StackBottom) >> 16);
1875 // Bp = ;
1877 if (!f32bit)
1878 Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
1880 fprintf(LogFile, "\n\nCall stack:\n");
1881 fprintf(LogFile, " Source Line Nearest\n");
1882 fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n");
1883 fprintf(LogFile, " ÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ- ÄÄÄÄÄÄÄÄ ÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ-\n");
1887 Size = 10;
1888 rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
1889 if (rc != NO_ERROR)
1891 fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
1892 break;
1894 if (!(Attr & PAG_COMMIT))
1896 fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
1897 break;
1899 if (Size < 10)
1901 fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
1902 break;
1905 if (fExceptionAddress)
1906 RetAddr = ExceptionAddress;
1907 else
1908 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1910 if (RetAddr == (PUSHORT) 0x00000053)
1912 // For some reason there's a "return address" of 0x53 following
1913 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1914 // at the real return address. This has something to do with
1915 // thunking from 32bits to 16bits...
1916 // Serious kludge, and it's probably dependent on versions of C(++)
1917 // runtime or OS, but it works for now!
1918 Ebp += 22;
1919 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1922 // Get the (possibly) 16bit CS and IP
1923 if (fExceptionAddress)
1925 Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
1926 Ip = (USHORT) (ULONG) ExceptionAddress;
1928 else
1930 Cs = *(Ebp + 2);
1931 Ip = *(Ebp + 1);
1934 // if the return address points to the stack then it's really just
1935 // a pointer to the return address (UGH!).
1936 if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp
1938 RetAddr = (PUSHORT) (*((PULONG) RetAddr));
1940 if (Ip == 0 && *Ebp == 0)
1942 // End of the stack so these are both shifted by 2 bytes:
1943 Cs = *(Ebp + 3);
1944 Ip = *(Ebp + 2);
1947 // 16bit programs have on the stack:
1948 // BP:IP:CS
1949 // where CS may be thunked
1951 // in dump swapped
1952 // BP IP CS BP CS IP
1953 // 4677 53B5 F7D0 7746 D0F7 B553
1955 // 32bit programs have:
1956 // EBP:EIP
1957 // and you'd have something like this (with SP added) (not
1958 // accurate values)
1960 // in dump swapped
1961 // EBP EIP EBP EIP
1962 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1964 // So the basic difference is that 32bit programs have a 32bit
1965 // EBP and we can attempt to determine whether we have a 32bit
1966 // EBP by checking to see if its 'selector' is the same as SP.
1967 // Note that this technique limits us to checking stacks < 64K.
1969 // Soooo, if IP (which maps into the same USHORT as the swapped
1970 // stack page in EBP) doesn't point to the stack (i.e. it could
1971 // be a 16bit IP) then see if CS is valid (as is or thunked).
1973 // Note that there's the possibility of a 16bit return address
1974 // that has an offset that's the same as SP so we'll think it's
1975 // a 32bit return address and won't be able to successfully resolve
1976 // its details.
1977 if (Ip != Sp)
1979 if (DosSizeSeg(Cs, &Size) == NO_ERROR)
1981 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1982 f32bit = FALSE;
1984 else if (DosSizeSeg((Cs << 3) + 7, &Size) == NO_ERROR)
1986 Cs = (Cs << 3) + 7;
1987 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1988 f32bit = FALSE;
1990 else
1991 f32bit = TRUE;
1993 else
1994 f32bit = TRUE;
1997 // "EBP" column
1998 if (fExceptionAddress)
1999 fprintf(LogFile, " Trap -> ");
2000 else
2001 fprintf(LogFile, " %8.8lX ", (ULONG)Ebp);
2003 // "Address" column
2004 if (f32bit)
2005 fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr);
2006 else
2007 fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip);
2009 // Version check omitted; the following requires
2010 // OS/2 2.10 or later (*UM)
2011 // if (Version[0] >= 20 && Version[1] >= 10)
2013 // Make a 'tick' sound to let the user know we're still alive
2014 DosBeep(2000, 10);
2016 Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
2018 // "Module"/"Object" columns
2019 rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
2020 if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
2022 fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
2023 break; // avoid infinite loops
2025 else
2027 rc = DosQueryModFromEIP(&hMod,
2028 &ObjNum,
2029 sizeof(Name), Name,
2030 &Offset,
2031 (PVOID)RetAddr);
2032 if ( (rc == NO_ERROR)
2033 // && (ObjNum != -1)
2036 // static char szJunk[_MAX_FNAME];
2037 static char szName[_MAX_FNAME];
2039 DosQueryModuleName(hMod, sizeof(Name), Name);
2040 // _splitpath(Name, szJunk, szJunk, szName, szJunk);
2042 // print module and object
2043 fprintf(LogFile, "%-8s %04lX ", szName, ObjNum + 1);
2045 if (strlen(Name) > 3)
2047 dbgPrintStackFrame(LogFile,
2048 Name,
2049 ObjNum,
2050 Offset);
2053 else
2054 fprintf(LogFile,
2055 "DosQueryModFromEIP failed, returned %lu\n",
2056 rc);
2060 if ( ((*Ebp) == 0)
2061 && ((*Ebp + 1) == 0)
2064 fprintf(LogFile, "End of call stack\n");
2065 break;
2068 if (!fExceptionAddress)
2070 LastEbp = Ebp;
2071 #if 0
2072 Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
2073 #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2074 if (f32bit)
2075 Ebp = (PUSHORT) *(PULONG) LastEbp;
2076 else
2077 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
2078 #endif
2079 if (f32bit)
2081 dbgPrintVariables(LogFile, (ULONG) Ebp);
2082 } // endif
2084 if (Ebp < LastEbp)
2086 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
2087 break;
2090 else
2091 fExceptionAddress = FALSE;
2093 Size = 4;
2094 rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
2095 if ((rc != NO_ERROR) || (Size < 4))
2097 fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
2098 break;
2100 } while (TRUE);
2102 fprintf(LogFile, "\n");
2106 *@@ doshQueryBootDrive:
2107 * returns the letter of the boot drive as a
2108 * single (capital) character, which is useful for
2109 * constructing file names using sprintf and such.
2111 *@@changed V0.9.16 (2002-01-13) [umoeller]: optimized
2114 CHAR doshQueryBootDrive(VOID)
2116 // this can never change, so query this only once
2117 // V0.9.16 (2002-01-13) [umoeller]
2118 static CHAR cBootDrive = '\0';
2120 if (!cBootDrive)
2122 ULONG ulBootDrive;
2123 DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
2124 &ulBootDrive,
2125 sizeof(ulBootDrive));
2126 cBootDrive = (CHAR)ulBootDrive + 'A' - 1;
2129 return (cBootDrive);