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
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,
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
57 #define INCL_DOSPROCESS
58 #define INCL_DOSMODULEMGR
60 #define INCL_DOSERRORS
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"
77 #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
84 #define DWORD unsigned long
87 #define WORD unsigned short
94 *@@category: Helpers\Control program helpers\Exceptions/debugging
95 * See except.c and debug.c.
98 /* ******************************************************************
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:
115 //YD 17/07/06 c++ namespace can generate really long
116 //YD names, use a large buffer!
117 char func_name
[16*1024];
151 "16 bit characters ",
152 "32 bit characters ",
162 "near pointer to 8 bit signed ",
163 "near pointer to 16 bit signed ",
164 "near pointer to 32 bit signed ",
166 "near pointer to 8 bit unsigned ",
167 "near pointer to 16 bit unsigned ",
168 "near pointer to 32 bit unsigned ",
170 "near pointer to 32 bit real ",
171 "near pointer to 64 bit real ",
172 "near pointer to 80 bit real ",
174 "near pointer to 64 bit complex ",
175 "near pointer to 128 bit complex ",
176 "near pointer to 160 bit complex ",
178 "near pointer to 8 bit boolean ",
179 "near pointer to 16 bit boolean ",
180 "near pointer to 32 bit boolean ",
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 ",
194 "far pointer to 8 bit signed ",
195 "far pointer to 16 bit signed ",
196 "far pointer to 32 bit signed ",
198 "far pointer to 8 bit unsigned ",
199 "far pointer to 16 bit unsigned ",
200 "far pointer to 32 bit unsigned ",
202 "far pointer to 32 bit real ",
203 "far pointer to 64 bit real ",
204 "far pointer to 80 bit real ",
206 "far pointer to 64 bit complex ",
207 "far pointer to 128 bit complex ",
208 "far pointer to 160 bit complex ",
210 "far pointer to 8 bit boolean ",
211 "far pointer to 16 bit boolean ",
212 "far pointer to 32 bit boolean ",
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
235 unsigned short dbug
; // 'NB' signature
236 unsigned short ver
; // version
237 unsigned long dfaBase
; // size of codeview info
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
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
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
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
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
295 typedef struct _SSPUBLIC
297 unsigned short offset
;
298 unsigned short segment
;
303 typedef struct _SSPUBLIC32
305 unsigned long offset
;
306 unsigned short segment
;
311 typedef struct _SSLINEENTRY32
313 unsigned short LineNum
;
314 unsigned short FileNum
;
315 unsigned long Offset
;
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
;
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
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
356 unsigned char *pEntTab
;
357 unsigned long lfaBase
;
363 } XDEBUGINFO
, *PXDEBUGINFO
;
366 USHORT
_THUNK_FUNCTION (Dos16SizeSeg
) ();
367 //APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
368 USHORT
DosSizeSeg (USHORT Seg
, PULONG16 Size
)
371 (_THUNK_PROLOG (2+4);
374 _THUNK_CALL (Dos16SizeSeg
)));
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
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
418 *@@ dbgPrintDebugInfo:
419 * this is the main entry point into analyzing debug
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.
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)
441 static struct exe_hdr OldExeHeader
;
442 static struct new_exe NewExeHeader
;
444 ULONG ulSegment
= Object
+ 1; // segment no. is object no. + 1
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)
455 // read old Exe header
456 if (read(ModuleFile
, (void*)&OldExeHeader
, 64) == -1L)
458 fprintf(LogFile
, "errno %d reading old exe header\n", errno
);
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
);
469 if (read(ModuleFile
, (void *)&NewExeHeader
, 64) == -1L)
471 fprintf(LogFile
, "errno %d reading new exe header\n", errno
);
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
,
491 WriteDebugInfo(LogFile
, &xdi
);
495 // rc !=0 try with DBG file
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
,
508 WriteDebugInfo(LogFile
, &xdi
);
518 if (NE_MAGIC(NewExeHeader
) == NEMAGIC
)
525 if ((xdi
.pseg
= (struct new_seg
*)calloc(NE_CSEG(NewExeHeader
),
526 sizeof(struct new_seg
)))
529 fprintf(LogFile
, "Out of memory!");
533 if ( lseek(ModuleFile
,
534 E_LFANEW(OldExeHeader
) + NE_SEGTAB(NewExeHeader
),
537 fprintf(LogFile
, "Error %u seeking segment table in %s\n", errno
, FileName
);
545 NE_CSEG(NewExeHeader
) * sizeof(struct new_seg
))
548 fprintf(LogFile
, "Error %u reading segment table from %s\n", errno
, FileName
);
554 if (!(rc
= Read16CodeView(LogFile
,
560 WriteDebugInfo(LogFile
, &xdi
);
565 // rc !=0 try with DBG file
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
,
579 WriteDebugInfo(LogFile
, &xdi
);
589 * Unknown executable:
593 fprintf(LogFile
, "Error, could not find exe signature");
598 } // end if (ModuleFile != -1)
601 fprintf(LogFile
, "Error %d opening module file %s", errno
, FileName
);
605 // return 0; we never get here
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
624 } one_userdef
[MAX_USERDEFS
];
626 struct one_pointer_rec
632 } one_pointer
[MAX_POINTERS
];
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
642 int ModuleFile
, // in: module file opened with sopen()
647 static unsigned int CurrSymSeg
, NrSymbol
,
648 /* offset, */ NrPublic
,
649 NrFile
, NrLine
, /* NrEntry */
651 numlines
/* , line */;
653 static int bytesread
, i
, j
;
654 static SSLINEENTRY32 LineEntry
;
655 static SSFILENUM32 FileInfo
;
656 static FIRSTLINEENTRY32 FirstLine
;
657 static BYTE dump_vars
= FALSE
;
659 static BOOL read_types
;
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
);
671 (void *)&G_eodbug
, 8)
674 fprintf(LogFile
, "Error %u reading debug info from %s\n", errno
, FileName
);
677 if (G_eodbug
.dbug
!= DBUGSIG
)
679 // fprintf(LogFile,"\nNo CodeView information stored.\n");
683 if ( (pxdi
->lfaBase
= lseek(ModuleFile
,
684 -(LONG
)G_eodbug
.dfaBase
,
688 fprintf(LogFile
, "Error %u seeking base codeview data in %s\n", errno
, FileName
);
693 (void *)&pxdi
->base
, 8)
696 fprintf(LogFile
, "Error %u reading base codeview data in %s\n", errno
, FileName
);
700 if (lseek(ModuleFile
,
701 pxdi
->base
.lfoDir
- 8 + 4,
705 fprintf(LogFile
, "Error %u seeking dir codeview data in %s\n", errno
, FileName
);
713 fprintf(LogFile
, "Error %u reading dir codeview data in %s\n", errno
, FileName
);
717 // Read dir table into buffer
718 if ( (pxdi
->pDirTab32
= (SSDIR32
*)calloc(numdir
,
722 fprintf(LogFile
, "Out of memory!");
727 (void*)pxdi
->pDirTab32
,
728 numdir
* sizeof(SSDIR32
))
731 fprintf(LogFile
, "Error %u reading codeview dir table from %s\n", errno
, FileName
);
732 free(pxdi
->pDirTab32
);
739 if (pxdi
->pDirTab32
[i
].sst
!= SSTMODULES
)
750 // point to subsection
752 pxdi
->pDirTab32
[i
].lfoStart
+ pxdi
->lfaBase
,
755 (void*)&pxdi
->ssmod32
.csBase
,
759 (unsigned)pxdi
->ssmod32
.csize
);
760 ModIndex
= pxdi
->pDirTab32
[i
].modindex
;
761 ModName
[pxdi
->ssmod32
.csize
] = '\0';
766 while ( (pxdi
->pDirTab32
[i
].modindex
== ModIndex
)
770 // point to subsection
772 pxdi
->pDirTab32
[i
].lfoStart
+ pxdi
->lfaBase
,
775 switch (pxdi
->pDirTab32
[i
].sst
)
779 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
781 bytesread
+= read(ModuleFile
,
782 (void *)&pxdi
->sspub32
.offset
,
783 sizeof(pxdi
->sspub32
));
784 bytesread
+= read(ModuleFile
,
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
;
795 sprintf(pxdi
->szNrPub
,
797 (pxdi
->sspub32
.type
== 1)
803 // but continue, because there might be a
804 // symbol that comes closer
809 // Read symbols, so we can dump the variables on the stack
811 if (TrapSeg
!= pxdi
->ssmod32
.csBase
)
815 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
817 static USHORT usLength
;
818 static USHORT usLengthSym
;
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);
836 bytesread
+= read(ModuleFile
, &b2
, 1);
837 usLength
= ((b1
& 0x7F) << 8) + b2
;
842 ofs
= tell(ModuleFile
);
844 bytesread
+= read(ModuleFile
, &bType
, 1);
849 read(ModuleFile
, &symseg
, sizeof(symseg
));
850 CurrSymSeg
= symseg
.seg_no
;
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
;
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
))
875 NrSymbol
= symproc
.offset
;
876 func_ofs
= symproc
.offset
;
878 strcpy(func_name
, str
);
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
;
904 bytesread
+= usLength
;
906 lseek(ModuleFile
, ofs
+ usLength
, SEEK_SET
);
911 // if (ModIndex != TrapSeg)
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
;
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
);
936 if (userdef_count
>= MAX_USERDEFS
)
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
,
948 _min(udef
.name_len
+ 1, 32));
949 one_userdef
[userdef_count
].name
[32] = 0;
954 if (pointer_count
>= MAX_POINTERS
)
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
,
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
;
975 bytesread
+= type
.length
;
977 lseek(ModuleFile
, ofs
+ type
.length
+ 2, SEEK_SET
);
982 if (TrapSeg
!= pxdi
->ssmod32
.csBase
)
988 read(ModuleFile
, (void *)&FirstLine
, sizeof(FirstLine
));
990 if (FirstLine
.LineNum
!= 0)
992 fprintf(LogFile
, "Missing Line table information\n");
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
)
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
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
);
1030 lseek(ModuleFile
, sizeof(struct linlist_rec
), SEEK_CUR
);
1034 lseek(ModuleFile
, sizeof(struct linsourcelist_rec
), SEEK_CUR
);
1038 lseek(ModuleFile
, sizeof(struct filenam_rec
), SEEK_CUR
);
1042 lseek(ModuleFile
, sizeof(struct pathtab_rec
), SEEK_CUR
);
1051 read(ModuleFile
, (void*)&FileInfo
, sizeof(FileInfo
));
1053 for (j
= 1; j
<= FileInfo
.file_count
; j
++)
1056 read(ModuleFile
, (void *)&namelen
, 1);
1057 read(ModuleFile
, (void *)ename
, namelen
);
1061 ename
[namelen
] = '\0';
1062 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
1063 sprintf(pxdi
->szNrFile
, "%11.11s ", ename
);
1067 // strcat(szNrLine,"\n"); avoid new line for empty name fill
1068 strcpy(pxdi
->szNrFile
, "file? ");
1074 } // end while modindex
1075 } // End While i < numdir
1076 free(pxdi
->pDirTab32
);
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
1093 static unsigned short int offset
,
1098 static int ModIndex
;
1099 static int bytesread
, i
, j
;
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
);
1109 if (read(fh
, (void *)&G_eodbug
, 8) == -1)
1111 fprintf(LogFile
, "Error %u reading debug info from %s\n", errno
, FileName
);
1114 if (G_eodbug
.dbug
!= DBUGSIG
)
1116 // fprintf(LogFile,"\nNo CodeView information stored.\n");
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
);
1126 if (read(fh
, (void *)&pxdi
->base
, 8) == -1)
1128 fprintf(LogFile
, "Error %u reading base codeview data in %s\n", errno
, FileName
);
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
);
1138 if (read(fh
, (void *)&numdir
, 2) == -1)
1140 fprintf(LogFile
, "Error %u reading dir codeview data in %s\n", errno
, FileName
);
1144 // Read dir table into buffer
1145 if ((pxdi
->pDirTab
= (SSDIR
*)calloc(numdir
, sizeof(SSDIR
))) == NULL
)
1147 fprintf(LogFile
, "Out of memory!");
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
);
1161 if (pxdi
->pDirTab
[i
].sst
!= SSTMODULES
)
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';
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
)
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
,
1196 pxdi
->sspub
.segment
,
1205 if (TrapSeg
!= pxdi
->ssmod
.csBase
)
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
)
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); */
1231 } // end while modindex
1232 } // End While i < numdir
1233 free(pxdi
->pDirTab
);
1237 /* ******************************************************************
1239 * PART 2: ANALYZE VARIABLES
1241 ********************************************************************/
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
1258 if (DosQueryMem(varptr
, &Size
, &Attr
) != NO_ERROR
)
1260 sprintf(pszBuf
, "type %d, DosQueryMem failed", type
);
1264 if ((Attr
& PAG_READ
) == 0)
1266 sprintf(pszBuf
, "type %d, read-access to value denied", type
);
1271 sprintf(pszBuf
, "%hd", *(signed char*)varptr
);
1273 sprintf(pszBuf
, "%hd", *(signed short*)varptr
);
1275 sprintf(pszBuf
, "%ld", *(signed long*)varptr
);
1277 sprintf(pszBuf
, "%hu", *(BYTE
*) varptr
);
1279 sprintf(pszBuf
, "%hu", *(USHORT
*)varptr
);
1281 sprintf(pszBuf
, "0x%lX (%lu)", *((ULONG
*)varptr
), *((ULONG
*)varptr
));
1283 sprintf(pszBuf
, "%f", *(float*)varptr
);
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");
1311 if ((Attr
& PAG_COMMIT
) == 0x0U
)
1313 strcat(pszBuf
, " uncommitted");
1315 if ((Attr
& PAG_WRITE
) == 0x0U
)
1317 strcat(pszBuf
, " unwritable");
1319 if ((Attr
& PAG_READ
) == 0x0U
)
1321 strcat(pszBuf
, " unreadable");
1326 sprintf(pszBuf
, "Unknown type %d", type
);
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
1342 pos
< userdef_count
;
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
),
1355 one_userdef
[pos
].type_index
- 0x80);
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
1379 static BOOL
search_pointers(FILE *LogFile
, // in: text log file to write to
1384 static BYTE str
[35];
1385 static char sszVar
[500];
1390 ( (pos
< pointer_count
)
1391 && (one_pointer
[pos
].idx
!= autovar_def
[var_no
].type_idx
)
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]);
1403 var_value((void*)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1406 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1407 autovar_def
[var_no
].stack_offset
,
1408 autovar_def
[var_no
].name
,
1415 // If the result isn't a simple type, look for it in the other lists
1417 ( (upos
< userdef_count
)
1418 && (one_userdef
[upos
].idx
!= one_pointer
[pos
].type_index
)
1423 if (upos
< userdef_count
)
1425 strcpy(str
, one_userdef
[upos
].name
);
1427 var_value((void *)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1430 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1431 autovar_def
[var_no
].stack_offset
,
1432 autovar_def
[var_no
].name
,
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
),
1446 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1447 autovar_def
[var_no
].stack_offset
,
1448 autovar_def
[var_no
].name
,
1461 *@@ dbgPrintVariables:
1462 * Dumps variables for the specified stack offset
1463 * to the specified log file.
1468 void dbgPrintVariables(FILE *LogFile
, // in: text log file to write to
1472 BOOL AutoVarsFound
= FALSE
;
1474 if (/* 1 || */ func_ofs
== pubfunc_ofs
)
1480 if (AutoVarsFound
== FALSE
)
1482 AutoVarsFound
= TRUE
;
1483 fprintf(LogFile
, " List of auto variables at EBP %p in %s:\n",
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
),
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],
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);
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.
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)
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
;
1573 #ifdef DEBUG_SYMDUMP
1574 fprintf(LogFile
,"Dump of '%s' for object %d\n",SymFileName
,Object
);
1576 SymFile
= fopen(SymFileName
, "rb");
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
);
1589 SegOffset
= SEGDEFOFFSET(MapDef
);
1590 #ifdef DEBUG_SYMDUMP
1591 fprintf(LogFile
,"SegOffset %0x\n",SegOffset
);
1594 // go thru all segments
1596 SegNum
< MapDef
.cSegs
;
1599 #ifdef DEBUG_SYMDUMP
1600 fprintf(LogFile
,"Scanning segment #%d Offset %08X\n",SegNum
,SegOffset
);
1602 if (fseek(SymFile
, SegOffset
, SEEK_SET
))
1606 // read in segment definition
1607 fread(&SegDef
, sizeof(SEGDEF
), 1, SymFile
);
1608 #ifdef DEBUG_SYMDUMP
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
);
1618 if (SegNum
== Object
)
1620 // stack object found:
1624 // go thru all symbols in this object
1625 #ifdef DEBUG_SYMDUMP
1626 fprintf(LogFile
,"Scanning #%d symbols\n",SegDef
.cSymbols
);
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)
1637 fread(&SymDef32
, sizeof(SYMDEF32
), 1, SymFile
);
1638 if (SymDef32
.wSymVal
> TrapOffset
)
1642 "between %s + 0x%lX ",
1644 TrapOffset
- LastVal
);
1645 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1646 LINEDEFOFFSET(SegDef)
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
);
1659 if (SymDef32
.wSymVal
> TrapOffset
)
1661 // symbol found, as above
1666 LastVal
- TrapOffset
);
1667 fprintf(LogFile
, "\n");
1674 fread(&SymDef16
, sizeof(SYMDEF16
), 1, SymFile
);
1675 if (SymDef16
.wSymVal
> TrapOffset
)
1678 "between %s + %lX\n",
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
)
1692 LastVal
- TrapOffset
);
1695 #ifdef DEBUG_SYMDUMP
1696 fprintf(LogFile
,"16 Bit Symbol <%s> Address %p\n",Buffer
,SymDef16
.wSymVal
);
1702 SegOffset
= NEXTSEGDEFOFFSET(SegDef
);
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)
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
,
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
,
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
, '\\');
1767 PSZ pszVersionDir
= "WARP4";
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)
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";
1792 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1793 doshQueryBootDrive(),
1796 arc
= dbgPrintSYMInfo(LogFile
,
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
1811 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1812 doshQueryBootDrive(),
1815 arc
= dbgPrintSYMInfo(LogFile
,
1823 if (arc
== 2) // file not found
1825 "Cannot find symbol file %s\n",
1829 "Error %lu reading symbol file %s\n",
1834 return (arc
== NO_ERROR
);
1839 * this takes stack data from the TIB and
1840 * context record data structures and tries
1841 * to analyse what the different stack frames
1844 * For each stack frame, this calls dbgPrintDebugInfo,
1845 * and, if that fails, dbgPrintSYMInfo.
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
,
1856 PUSHORT ExceptionAddress
)
1858 PUSHORT RetAddr
= 0;
1859 PUSHORT LastEbp
= 0;
1867 static char Name
[CCHMAXPATH
];
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);
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");
1888 rc
= DosQueryMem((PVOID
) (Ebp
+ 2), &Size
, &Attr
);
1891 fprintf(LogFile
, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG
)Ebp
, rc
);
1894 if (!(Attr
& PAG_COMMIT
))
1896 fprintf(LogFile
, "Invalid EBP %8.8lX (not committed)\n", (ULONG
)Ebp
);
1901 fprintf(LogFile
, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG
)Ebp
);
1905 if (fExceptionAddress
)
1906 RetAddr
= ExceptionAddress
;
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!
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
;
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:
1947 // 16bit programs have on the stack:
1949 // where CS may be thunked
1952 // BP IP CS BP CS IP
1953 // 4677 53B5 F7D0 7746 D0F7 B553
1955 // 32bit programs have:
1957 // and you'd have something like this (with SP added) (not
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
1979 if (DosSizeSeg(Cs
, &Size
) == NO_ERROR
)
1981 RetAddr
= (USHORT
* _Seg16
) MAKEULONG(Ip
, Cs
);
1984 else if (DosSizeSeg((Cs
<< 3) + 7, &Size
) == NO_ERROR
)
1987 RetAddr
= (USHORT
* _Seg16
) MAKEULONG(Ip
, Cs
);
1998 if (fExceptionAddress
)
1999 fprintf(LogFile
, " Trap -> ");
2001 fprintf(LogFile
, " %8.8lX ", (ULONG
)Ebp
);
2005 fprintf(LogFile
, ":%8.8lX ", (ULONG
)RetAddr
);
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
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
2027 rc
= DosQueryModFromEIP(&hMod
,
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
,
2055 "DosQueryModFromEIP failed, returned %lu\n",
2061 && ((*Ebp
+ 1) == 0)
2064 fprintf(LogFile
, "End of call stack\n");
2068 if (!fExceptionAddress
)
2072 Ebp
= (PUSHORT
) MAKEULONG(Bp
, Sp
);
2073 #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2075 Ebp
= (PUSHORT
) *(PULONG
) LastEbp
;
2077 Ebp
= (PUSHORT
) MAKEULONG((*Ebp
), Sp
);
2081 dbgPrintVariables(LogFile
, (ULONG
) Ebp
);
2086 fprintf(LogFile
, "... lost stack chain - new EBP below previous\n");
2091 fExceptionAddress
= FALSE
;
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
);
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';
2123 DosQuerySysInfo(QSV_BOOT_DRIVE
, QSV_BOOT_DRIVE
,
2125 sizeof(ulBootDrive
));
2126 cBootDrive
= (CHAR
)ulBootDrive
+ 'A' - 1;
2129 return (cBootDrive
);