1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 *@@sourcefile debug.c:
30 * this file contains debugging functions for the
31 * exception handlers in except.c.
33 * This code is capable of unwinding the stack from
34 * a given address and trying to get function names
35 * and source line numbers, either from the respective
36 * module's debug code (if present) or from a SYM file,
37 * which is searched for in the directory of the module
38 * or in ?:\OS2\PDPSI\PMDF\WARP4.
40 * This file incorporates code from the following:
41 * -- Marc Fiammante, John Currier, Kim Rasmussen,
42 * Anthony Cruise (EXCEPT3.ZIP package for a generic
43 * exception handling DLL, available at Hobbes).
45 * Usage: All OS/2 programs.
47 * Note: Version numbering in this file relates to XWorkplace version
50 *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
51 *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
53 *@@header "helpers\debug.h"
57 * This file Copyright (C) 1992-99 Ulrich M�ller,
62 * This file is part of the "XWorkplace helpers" source package.
64 * 2009-06-15 published under LGPL3 with Ulrich M�ller permission.
68 //#define DEBUG_SYMDUMP // enable to dump sym file to log
70 //YD commented, since we need unsigned char BYTE!
71 //#define OS2EMX_PLAIN_CHAR
72 //Also gcc char is signed, while most structures requires unsigned data!
73 //Raised limits for all fields!
75 // this is needed for "os2emx.h"; if this is defined,
76 // emx will define PSZ as _signed_ char, otherwise
79 #define INCL_DOSPROCESS
80 #define INCL_DOSMODULEMGR
82 #define INCL_DOSERRORS
89 #define DONT_REPLACE_MALLOC
90 #include "helpers\setup.h" // code generation and debugging options
92 #include "helpers\debug.h"
93 #include "helpers\dosh.h"
99 #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
101 #include <sys\stat.h>
106 #define DWORD unsigned long
109 #define WORD unsigned short
116 *@@category: Helpers\Control program helpers\Exceptions/debugging
117 * See except.c and debug.c.
120 /* ******************************************************************
124 ********************************************************************/
126 // this specifies whether we're dealing with 32-bit code;
127 // this gets changed whenever 16-bit count is detected
128 static BOOL f32bit
= TRUE
;
131 * Global variables for Read32PmDebug:
137 //YD 17/07/06 c++ namespace can generate really long
138 //YD names, use a large buffer!
139 char func_name
[16*1024];
173 "16 bit characters ",
174 "32 bit characters ",
184 "near pointer to 8 bit signed ",
185 "near pointer to 16 bit signed ",
186 "near pointer to 32 bit signed ",
188 "near pointer to 8 bit unsigned ",
189 "near pointer to 16 bit unsigned ",
190 "near pointer to 32 bit unsigned ",
192 "near pointer to 32 bit real ",
193 "near pointer to 64 bit real ",
194 "near pointer to 80 bit real ",
196 "near pointer to 64 bit complex ",
197 "near pointer to 128 bit complex ",
198 "near pointer to 160 bit complex ",
200 "near pointer to 8 bit boolean ",
201 "near pointer to 16 bit boolean ",
202 "near pointer to 32 bit boolean ",
204 "near pointer to 8 bit character ",
205 "near pointer to 16 bit characters",
206 "near pointer to 32 bit characters",
207 "near pointer to void ",
208 "near pointer to 15 bit unsigned ",
209 "near pointer to 24 bit unsigned ",
210 "near pointer to 31 bit unsigned ",
216 "far pointer to 8 bit signed ",
217 "far pointer to 16 bit signed ",
218 "far pointer to 32 bit signed ",
220 "far pointer to 8 bit unsigned ",
221 "far pointer to 16 bit unsigned ",
222 "far pointer to 32 bit unsigned ",
224 "far pointer to 32 bit real ",
225 "far pointer to 64 bit real ",
226 "far pointer to 80 bit real ",
228 "far pointer to 64 bit complex ",
229 "far pointer to 128 bit complex ",
230 "far pointer to 160 bit complex ",
232 "far pointer to 8 bit boolean ",
233 "far pointer to 16 bit boolean ",
234 "far pointer to 32 bit boolean ",
236 "far pointer to 8 bit character ",
237 "far pointer to 16 bit characters ",
238 "far pointer to 32 bit characters ",
239 "far pointer to void ",
240 "far pointer to 15 bit unsigned ",
241 "far pointer to 24 bit unsigned ",
242 "far pointer to 31 bit unsigned ",
245 // Thanks to John Currier:
246 // Do not call 16 bit code in myHandler function to prevent call
247 // to __EDCThunkProlog and problems is guard page exception handling
248 // Also reduce the stack size to 1K for true 16 bit calls.
249 // 16 bit calls thunk will now only occur on fatal exceptions
250 #pragma stack16(1024)
252 // ------------------------------------------------------------------
253 // Last 8 bytes of 16:16 file when CODEVIEW debugging info is present
257 unsigned short dbug
; // 'NB' signature
258 unsigned short ver
; // version
259 unsigned long dfaBase
; // size of codeview info
262 #define DBUGSIG 0x424E
263 #define SSTMODULES 0x0101
264 #define SSTPUBLICS 0x0102
265 #define SSTTYPES 0x0103
266 #define SSTSYMBOLS 0x0104
267 #define SSTSRCLINES 0x0105
268 #define SSTLIBRARIES 0x0106
269 #define SSTSRCLINES2 0x0109
270 #define SSTSRCLINES32 0x010B
272 typedef struct _SYMBASE
274 unsigned short dbug
; // 'NB' signature
275 unsigned short ver
; // version
276 unsigned long lfoDir
; // file offset to dir entries
279 typedef struct _SSDIR
281 unsigned short sst
; // SubSection Type
282 unsigned short modindex
; // Module index number
283 unsigned long lfoStart
; // Start of section
284 unsigned short cb
; // Size of section
287 typedef struct _SSDIR32
289 unsigned short sst
; // SubSection Type
290 unsigned short modindex
; // Module index number
291 unsigned long lfoStart
; // Start of section
292 unsigned long cb
; // Size of section
295 typedef struct _SSMODULE
297 unsigned short csBase
; // code segment base
298 unsigned short csOff
; // code segment offset
299 unsigned short csLen
; // code segment length
300 unsigned short ovrNum
; // overlay number
301 unsigned short indxSS
; // Index into sstLib or 0
302 unsigned short reserved
;
303 BYTE csize
; // size of prefix string
306 typedef struct _SSMOD32
308 unsigned short csBase
; // code segment base
309 unsigned long csOff
; // code segment offset
310 unsigned long csLen
; // code segment length
311 unsigned long ovrNum
; // overlay number
312 unsigned short indxSS
; // Index into sstLib or 0
313 unsigned long reserved
;
314 BYTE csize
; // size of prefix string
317 typedef struct _SSPUBLIC
319 unsigned short offset
;
320 unsigned short segment
;
325 typedef struct _SSPUBLIC32
327 unsigned long offset
;
328 unsigned short segment
;
333 typedef struct _SSLINEENTRY32
335 unsigned short LineNum
;
336 unsigned short FileNum
;
337 unsigned long Offset
;
340 typedef struct _FIRSTLINEENTRY32
342 unsigned short LineNum
;
343 unsigned char entry_type
;
344 unsigned char reserved
;
345 unsigned short numlines
;
346 unsigned short segnum
;
349 typedef struct _SSFILENUM32
351 unsigned long first_displayable
; // Not used
352 unsigned long number_displayable
; // Not used
353 unsigned long file_count
; // number of source files
358 * buffers for Read... funcs.
360 *@@added V0.9.4 (2000-06-15) [umoeller]
363 typedef struct _XDEBUGINFO
365 char szNrFile
[300]; // receives source file
366 char szNrLine
[300]; // receives line number
367 //YD 17/07/06 c++ namespace can generate really long
368 //YD names, use a large buffer!
369 char szNrPub
[16*1024]; // receives function name
371 struct new_seg
*pseg
;
372 struct o32_obj
*pobj
; // flat .EXE object table entry
378 unsigned char *pEntTab
;
379 unsigned long lfaBase
;
385 } XDEBUGINFO
, *PXDEBUGINFO
;
388 USHORT
_THUNK_FUNCTION (Dos16SizeSeg
) ();
389 //APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
390 USHORT
DosSizeSeg (USHORT Seg
, PULONG16 Size
)
393 (_THUNK_PROLOG (2+4);
396 _THUNK_CALL (Dos16SizeSeg
)));
401 /* ******************************************************************
403 * PART 1: ANALYZE DEBUG CODE
405 ********************************************************************/
407 static int Read16CodeView(FILE *LogFile
, PXDEBUGINFO pxdi
, int fh
, int TrapSeg
, int TrapOff
, CHAR
*FileName
);
408 static int Read32PmDebug(FILE *LogFile
, PXDEBUGINFO pxdi
, int fh
, int TrapSeg
, int TrapOff
, CHAR
*FileName
);
411 *@@ WriteAddressInfo:
412 * formats and writes a line into the trap log
415 * This gets called for each line from the
416 * stack dump. At this point, the line in the
417 * trap log already has:
419 + CS:EIP : 000109FF XMLVIEW :0
420 + ^^^ and we write here
421 * After this call, we have.
423 + CS:EIP : 000109FF XMLVIEW :0 xxx.c 123 ConfirmCreate__Fv
424 + ^^^ and we write here
426 *@@added V0.9.12 (2001-05-12) [umoeller]
429 static VOID
WriteDebugInfo(FILE *LogFile
, // in: open log file
430 PXDEBUGINFO pxdi
) // in: debug info
440 *@@ dbgPrintDebugInfo:
441 * this is the main entry point into analyzing debug
444 * This analyzes a given address and tries to find
445 * debug code descriptions for this address. If found,
446 * the information is written to the given log file.
448 * Gets called from dbgPrintStack.
450 * This returns NO_ERROR if the could was successfully
451 * analyzed or something != 0 if we failed.
456 APIRET
dbgPrintDebugInfo(FILE *LogFile
, // out: log file to write to
457 CHAR
*FileName
, // in: EXE/DLL module file name
458 ULONG Object
, // in: trapping object (from DosQueryModFromEIP)
459 ULONG TrapOffset
) // in: trapping address (from DosQueryModFromEIP)
463 static struct exe_hdr OldExeHeader
;
464 static struct new_exe NewExeHeader
;
466 ULONG ulSegment
= Object
+ 1; // segment no. is object no. + 1
469 memset(&xdi
, 0, sizeof(xdi
));
471 // open the module file for reading to analyze the code
472 ModuleFile
= sopen(FileName
, O_RDONLY
| O_BINARY
, SH_DENYNO
);
474 if (ModuleFile
!= -1)
477 // read old Exe header
478 if (read(ModuleFile
, (void*)&OldExeHeader
, 64) == -1L)
480 fprintf(LogFile
, "errno %d reading old exe header\n", errno
);
484 // seek to new Exe header
485 if (lseek(ModuleFile
, (long)E_LFANEW(OldExeHeader
), SEEK_SET
) == -1L)
487 fprintf(LogFile
, "errno %d seeking to new exe header\n", errno
);
491 if (read(ModuleFile
, (void *)&NewExeHeader
, 64) == -1L)
493 fprintf(LogFile
, "errno %d reading new exe header\n", errno
);
498 // check EXE signature
499 if (NE_MAGIC(NewExeHeader
) == E32MAGIC
)
502 * flat 32 executable:
506 // do analysis for 32-bit code
507 if (!(rc
= Read32PmDebug(LogFile
,
513 WriteDebugInfo(LogFile
, &xdi
);
517 // rc !=0 try with DBG file
520 strcpy(FileName
+ strlen(FileName
) - 3, "DBG"); // Build DBG File name
521 ModuleFile
= sopen(FileName
, O_RDONLY
| O_BINARY
, SH_DENYNO
);
522 if (ModuleFile
!= -1)
524 if (!(rc
= Read32PmDebug(LogFile
,
530 WriteDebugInfo(LogFile
, &xdi
);
540 if (NE_MAGIC(NewExeHeader
) == NEMAGIC
)
547 if ((xdi
.pseg
= (struct new_seg
*)calloc(NE_CSEG(NewExeHeader
),
548 sizeof(struct new_seg
)))
551 fprintf(LogFile
, "Out of memory!");
555 if ( lseek(ModuleFile
,
556 E_LFANEW(OldExeHeader
) + NE_SEGTAB(NewExeHeader
),
559 fprintf(LogFile
, "Error %u seeking segment table in %s\n", errno
, FileName
);
567 NE_CSEG(NewExeHeader
) * sizeof(struct new_seg
))
570 fprintf(LogFile
, "Error %u reading segment table from %s\n", errno
, FileName
);
576 if (!(rc
= Read16CodeView(LogFile
,
582 WriteDebugInfo(LogFile
, &xdi
);
587 // rc !=0 try with DBG file
590 strcpy(FileName
+ strlen(FileName
) - 3, "DBG"); // Build DBG File name
591 ModuleFile
= sopen(FileName
,
592 O_RDONLY
| O_BINARY
, SH_DENYNO
);
593 if (ModuleFile
!= -1)
595 if (!(rc
= Read16CodeView(LogFile
,
601 WriteDebugInfo(LogFile
, &xdi
);
611 * Unknown executable:
615 fprintf(LogFile
, "Error, could not find exe signature");
620 } // end if (ModuleFile != -1)
623 fprintf(LogFile
, "Error %d opening module file %s", errno
, FileName
);
627 // return 0; we never get here
635 #define MAX_USERDEFS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
636 #define MAX_POINTERS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
638 USHORT userdef_count
;
639 USHORT pointer_count
;
641 struct one_userdef_rec
646 } one_userdef
[MAX_USERDEFS
];
648 struct one_pointer_rec
654 } one_pointer
[MAX_POINTERS
];
658 * parses 32-bit debug code.
659 * Called from dbgPrintDebugInfo for 32-bit modules.
662 static int Read32PmDebug(FILE *LogFile
, // in: text log file to write to
664 int ModuleFile
, // in: module file opened with sopen()
669 static unsigned int CurrSymSeg
, NrSymbol
,
670 /* offset, */ NrPublic
,
671 NrFile
, NrLine
, /* NrEntry */
673 numlines
/* , line */;
675 static int bytesread
, i
, j
;
676 static SSLINEENTRY32 LineEntry
;
677 static SSFILENUM32 FileInfo
;
678 static FIRSTLINEENTRY32 FirstLine
;
679 static BYTE dump_vars
= FALSE
;
681 static BOOL read_types
;
685 // See if any CODEVIEW info
686 if (lseek(ModuleFile
, -8L, SEEK_END
) == -1)
688 fprintf(LogFile
, "Error %u seeking CodeView table in %s\n", errno
, FileName
);
693 (void *)&G_eodbug
, 8)
696 fprintf(LogFile
, "Error %u reading debug info from %s\n", errno
, FileName
);
699 if (G_eodbug
.dbug
!= DBUGSIG
)
701 // fprintf(LogFile,"\nNo CodeView information stored.\n");
705 if ( (pxdi
->lfaBase
= lseek(ModuleFile
,
706 -(LONG
)G_eodbug
.dfaBase
,
710 fprintf(LogFile
, "Error %u seeking base codeview data in %s\n", errno
, FileName
);
715 (void *)&pxdi
->base
, 8)
718 fprintf(LogFile
, "Error %u reading base codeview data in %s\n", errno
, FileName
);
722 if (lseek(ModuleFile
,
723 pxdi
->base
.lfoDir
- 8 + 4,
727 fprintf(LogFile
, "Error %u seeking dir codeview data in %s\n", errno
, FileName
);
735 fprintf(LogFile
, "Error %u reading dir codeview data in %s\n", errno
, FileName
);
739 // Read dir table into buffer
740 if ( (pxdi
->pDirTab32
= (SSDIR32
*)calloc(numdir
,
744 fprintf(LogFile
, "Out of memory!");
749 (void*)pxdi
->pDirTab32
,
750 numdir
* sizeof(SSDIR32
))
753 fprintf(LogFile
, "Error %u reading codeview dir table from %s\n", errno
, FileName
);
754 free(pxdi
->pDirTab32
);
761 if (pxdi
->pDirTab32
[i
].sst
!= SSTMODULES
)
772 // point to subsection
774 pxdi
->pDirTab32
[i
].lfoStart
+ pxdi
->lfaBase
,
777 (void*)&pxdi
->ssmod32
.csBase
,
781 (unsigned)pxdi
->ssmod32
.csize
);
782 ModIndex
= pxdi
->pDirTab32
[i
].modindex
;
783 ModName
[pxdi
->ssmod32
.csize
] = '\0';
788 while ( (pxdi
->pDirTab32
[i
].modindex
== ModIndex
)
792 // point to subsection
794 pxdi
->pDirTab32
[i
].lfoStart
+ pxdi
->lfaBase
,
797 switch (pxdi
->pDirTab32
[i
].sst
)
801 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
803 bytesread
+= read(ModuleFile
,
804 (void *)&pxdi
->sspub32
.offset
,
805 sizeof(pxdi
->sspub32
));
806 bytesread
+= read(ModuleFile
,
808 (unsigned)pxdi
->sspub32
.csize
);
809 ename
[pxdi
->sspub32
.csize
] = '\0';
810 if ( (pxdi
->sspub32
.segment
== TrapSeg
)
811 && (pxdi
->sspub32
.offset
<= TrapOff
)
812 && (pxdi
->sspub32
.offset
>= NrPublic
)
815 NrPublic
= pubfunc_ofs
= pxdi
->sspub32
.offset
;
817 sprintf(pxdi
->szNrPub
,
819 (pxdi
->sspub32
.type
== 1)
825 // but continue, because there might be a
826 // symbol that comes closer
831 // Read symbols, so we can dump the variables on the stack
833 if (TrapSeg
!= pxdi
->ssmod32
.csBase
)
837 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
839 static USHORT usLength
;
840 static USHORT usLengthSym
;
846 // static ULONG last_addr = 0;
847 //YD 17/07/06 c++ namespace can generate really long
848 //YD names, use a large buffer!
849 static BYTE str
[16*1024];
850 static struct symseg_rec symseg
;
851 static struct symauto_rec symauto
;
852 static struct symproc_rec symproc
;
854 // Read the length of this subentry
855 bytesread
+= read(ModuleFile
, &b1
, 1);
858 bytesread
+= read(ModuleFile
, &b2
, 1);
859 usLength
= ((b1
& 0x7F) << 8) + b2
;
864 ofs
= tell(ModuleFile
);
866 bytesread
+= read(ModuleFile
, &bType
, 1);
871 read(ModuleFile
, &symseg
, sizeof(symseg
));
872 CurrSymSeg
= symseg
.seg_no
;
877 read(ModuleFile
, &symproc
, sizeof(symproc
));
878 if (symproc
.name_len
& 0x80)
880 read(ModuleFile
, &b2
, 1);
881 usLengthSym
= ((symproc
.name_len
& 0x7F) << 8) + b2
;
885 usLengthSym
= symproc
.name_len
;
887 read(ModuleFile
, str
, usLengthSym
);
888 str
[usLengthSym
] = 0;
890 if ((CurrSymSeg
== TrapSeg
) &&
891 (symproc
.offset
<= TrapOff
) &&
892 (symproc
.offset
>= NrSymbol
))
897 NrSymbol
= symproc
.offset
;
898 func_ofs
= symproc
.offset
;
900 strcpy(func_name
, str
);
912 read(ModuleFile
, &symauto
, sizeof(symauto
));
913 read(ModuleFile
, str
, symauto
.name_len
);
914 if (symauto
.name_len
==0x80)
915 printf("symauto.name_len==0x80\n");
916 str
[symauto
.name_len
] = 0;
918 strcpy(autovar_def
[var_ofs
].name
, str
);
919 autovar_def
[var_ofs
].stack_offset
= symauto
.stack_offset
;
920 autovar_def
[var_ofs
].type_idx
= symauto
.type_idx
;
926 bytesread
+= usLength
;
928 lseek(ModuleFile
, ofs
+ usLength
, SEEK_SET
);
933 // if (ModIndex != TrapSeg)
941 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
943 static struct type_rec type
;
944 static struct type_userdefrec udef
;
945 static struct type_pointerrec point
;
947 static BYTE str
[256];
949 // Read the length of this subentry
950 ofs
= tell(ModuleFile
);
952 read(ModuleFile
, &type
, sizeof(type
));
953 bytesread
+= sizeof(type
);
958 if (userdef_count
>= MAX_USERDEFS
)
961 read(ModuleFile
, &udef
, sizeof(udef
));
962 read(ModuleFile
, str
, udef
.name_len
);
963 str
[udef
.name_len
] = 0;
965 // Insert userdef in table
966 one_userdef
[userdef_count
].idx
= idx
;
967 one_userdef
[userdef_count
].type_index
= udef
.type_index
;
968 memcpy(one_userdef
[userdef_count
].name
,
970 _min(udef
.name_len
+ 1, 32));
971 one_userdef
[userdef_count
].name
[32] = 0;
976 if (pointer_count
>= MAX_POINTERS
)
979 read(ModuleFile
, &point
, sizeof(point
));
980 read(ModuleFile
, str
, point
.name_len
);
981 str
[point
.name_len
] = 0;
983 // Insert userdef in table
984 one_pointer
[pointer_count
].idx
= idx
;
985 one_pointer
[pointer_count
].type_index
= point
.type_index
;
986 memcpy(one_pointer
[pointer_count
].name
,
988 _min(point
.name_len
+ 1, 32));
989 one_pointer
[pointer_count
].name
[32] = 0;
990 one_pointer
[pointer_count
].type_qual
= type
.type_qual
;
997 bytesread
+= type
.length
;
999 lseek(ModuleFile
, ofs
+ type
.length
+ 2, SEEK_SET
);
1004 if (TrapSeg
!= pxdi
->ssmod32
.csBase
)
1010 read(ModuleFile
, (void *)&FirstLine
, sizeof(FirstLine
));
1012 if (FirstLine
.LineNum
!= 0)
1014 fprintf(LogFile
, "Missing Line table information\n");
1017 numlines
= FirstLine
.numlines
;
1018 // Other type of data skip 4 more bytes
1019 if (FirstLine
.entry_type
< 4)
1021 read(ModuleFile
, (void *)&lSize
, 4);
1022 if (FirstLine
.entry_type
== 3)
1023 lseek(ModuleFile
, lSize
, SEEK_CUR
);
1026 while (FirstLine
.entry_type
== 3);
1028 for (j
= 0; j
< numlines
; j
++)
1030 switch (FirstLine
.entry_type
)
1033 read(ModuleFile
, (void *)&LineEntry
, sizeof(LineEntry
));
1034 // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
1035 // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
1036 if ( (LineEntry
.LineNum
)
1037 && (LineEntry
.Offset
+ pxdi
->ssmod32
.csOff
1039 && (LineEntry
.Offset
+ pxdi
->ssmod32
.csOff
>= NrLine
)
1042 NrLine
= LineEntry
.Offset
;
1043 NrFile
= LineEntry
.FileNum
;
1044 /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ",
1045 * ssmod32.csBase,LineEntry.Offset,
1046 * LineEntry.LineNum); */
1047 sprintf(pxdi
->szNrLine
, "% 6hu", LineEntry
.LineNum
);
1052 lseek(ModuleFile
, sizeof(struct linlist_rec
), SEEK_CUR
);
1056 lseek(ModuleFile
, sizeof(struct linsourcelist_rec
), SEEK_CUR
);
1060 lseek(ModuleFile
, sizeof(struct filenam_rec
), SEEK_CUR
);
1064 lseek(ModuleFile
, sizeof(struct pathtab_rec
), SEEK_CUR
);
1073 read(ModuleFile
, (void*)&FileInfo
, sizeof(FileInfo
));
1075 for (j
= 1; j
<= FileInfo
.file_count
; j
++)
1078 read(ModuleFile
, (void *)&namelen
, 1);
1079 read(ModuleFile
, (void *)ename
, namelen
);
1083 ename
[namelen
] = '\0';
1084 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
1085 sprintf(pxdi
->szNrFile
, "%11.11s ", ename
);
1089 // strcat(szNrLine,"\n"); avoid new line for empty name fill
1090 strcpy(pxdi
->szNrFile
, "file? ");
1096 } // end while modindex
1097 } // End While i < numdir
1098 free(pxdi
->pDirTab32
);
1104 * parses 16-bit debug code.
1105 * Called from dbgPrintDebugInfo for 16-bit modules.
1108 static int Read16CodeView(FILE *LogFile
, // in: text log file to write to
1115 static unsigned short int offset
,
1120 static int ModIndex
;
1121 static int bytesread
, i
, j
;
1124 // See if any CODEVIEW info
1125 if (lseek(fh
, -8L, SEEK_END
) == -1)
1127 fprintf(LogFile
, "Error %u seeking CodeView table in %s\n", errno
, FileName
);
1131 if (read(fh
, (void *)&G_eodbug
, 8) == -1)
1133 fprintf(LogFile
, "Error %u reading debug info from %s\n", errno
, FileName
);
1136 if (G_eodbug
.dbug
!= DBUGSIG
)
1138 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1142 if ((pxdi
->lfaBase
= lseek(fh
, -(LONG
)G_eodbug
.dfaBase
, SEEK_END
)) == -1L)
1144 fprintf(LogFile
, "Error %u seeking base codeview data in %s\n", errno
, FileName
);
1148 if (read(fh
, (void *)&pxdi
->base
, 8) == -1)
1150 fprintf(LogFile
, "Error %u reading base codeview data in %s\n", errno
, FileName
);
1154 if (lseek(fh
, pxdi
->base
.lfoDir
- 8, SEEK_CUR
) == -1)
1156 fprintf(LogFile
, "Error %u seeking dir codeview data in %s\n", errno
, FileName
);
1160 if (read(fh
, (void *)&numdir
, 2) == -1)
1162 fprintf(LogFile
, "Error %u reading dir codeview data in %s\n", errno
, FileName
);
1166 // Read dir table into buffer
1167 if ((pxdi
->pDirTab
= (SSDIR
*)calloc(numdir
, sizeof(SSDIR
))) == NULL
)
1169 fprintf(LogFile
, "Out of memory!");
1173 if (read(fh
, (void*)pxdi
->pDirTab
, numdir
* sizeof(SSDIR
)) == -1)
1175 fprintf(LogFile
, "Error %u reading codeview dir table from %s\n", errno
, FileName
);
1176 free(pxdi
->pDirTab
);
1183 if (pxdi
->pDirTab
[i
].sst
!= SSTMODULES
)
1190 // point to subsection
1191 lseek(fh
, pxdi
->pDirTab
[i
].lfoStart
+ pxdi
->lfaBase
, SEEK_SET
);
1192 read(fh
, (void *)&pxdi
->ssmod
.csBase
, sizeof(SSMODULE
));
1193 read(fh
, (void *)ModName
, (unsigned)pxdi
->ssmod
.csize
);
1194 ModIndex
= pxdi
->pDirTab
[i
].modindex
;
1195 ModName
[pxdi
->ssmod
.csize
] = '\0';
1197 while (pxdi
->pDirTab
[i
].modindex
== ModIndex
&& i
< numdir
)
1199 // point to subsection
1200 lseek(fh
, pxdi
->pDirTab
[i
].lfoStart
+ pxdi
->lfaBase
, SEEK_SET
);
1201 switch (pxdi
->pDirTab
[i
].sst
)
1205 while (bytesread
< pxdi
->pDirTab
[i
].cb
)
1207 bytesread
+= read(fh
, (void *)&pxdi
->sspub
.offset
, sizeof(pxdi
->sspub
));
1208 bytesread
+= read(fh
, (void *)ename
, (unsigned)pxdi
->sspub
.csize
);
1209 ename
[pxdi
->sspub
.csize
] = '\0';
1210 if ((pxdi
->sspub
.segment
== TrapSeg
) &&
1211 (pxdi
->sspub
.offset
<= TrapOff
) &&
1212 (pxdi
->sspub
.offset
>= NrPublic
))
1214 NrPublic
= pxdi
->sspub
.offset
;
1215 sprintf(pxdi
->szNrPub
, "%s %s (%s) %04hX:%04hX\n",
1216 (pxdi
->sspub
.type
== 1) ? " Abs" : " ", ename
,
1218 pxdi
->sspub
.segment
,
1227 if (TrapSeg
!= pxdi
->ssmod
.csBase
)
1230 read(fh
, (void *)&namelen
, 1);
1231 read(fh
, (void *)ename
, namelen
);
1232 ename
[namelen
] = '\0';
1233 // skip 2 zero bytes
1234 if (pxdi
->pDirTab
[i
].sst
== SSTSRCLINES2
)
1235 read(fh
, (void *)&numlines
, 2);
1236 read(fh
, (void *)&numlines
, 2);
1237 for (j
= 0; j
< numlines
; j
++)
1239 read(fh
, (void *)&line
, 2);
1240 read(fh
, (void *)&offset
, 2);
1241 if (offset
<= TrapOff
&& offset
>= NrLine
)
1244 sprintf(pxdi
->szNrFile
, "% 12.12s ", ename
);
1245 sprintf(pxdi
->szNrLine
, "% 6hu", line
);
1246 /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
1247 * ssmod.csBase,offset,line,ModName,ename); */
1253 } // end while modindex
1254 } // End While i < numdir
1255 free(pxdi
->pDirTab
);
1259 /* ******************************************************************
1261 * PART 2: ANALYZE VARIABLES
1263 ********************************************************************/
1267 * writes a description of a variable type to
1268 * the specified buffer, depending on "type".
1270 *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
1273 static VOID
var_value(void *varptr
, // in: address of the variable on the stack
1274 char *pszBuf
, // out: information
1275 BYTE type
) // in: type; if >= 32, we'll call DosQueryMem
1280 if (DosQueryMem(varptr
, &Size
, &Attr
) != NO_ERROR
)
1282 sprintf(pszBuf
, "type %d, DosQueryMem failed", type
);
1286 if ((Attr
& PAG_READ
) == 0)
1288 sprintf(pszBuf
, "type %d, read-access to value denied", type
);
1293 sprintf(pszBuf
, "%hd", *(signed char*)varptr
);
1295 sprintf(pszBuf
, "%hd", *(signed short*)varptr
);
1297 sprintf(pszBuf
, "%ld", *(signed long*)varptr
);
1299 sprintf(pszBuf
, "%hu", *(BYTE
*) varptr
);
1301 sprintf(pszBuf
, "%hu", *(USHORT
*)varptr
);
1303 sprintf(pszBuf
, "0x%lX (%lu)", *((ULONG
*)varptr
), *((ULONG
*)varptr
));
1305 sprintf(pszBuf
, "%f", *(float*)varptr
);
1307 sprintf(pszBuf
, "%f", *(double*)varptr
);
1308 else if (type
== 10)
1309 sprintf(pszBuf
, "%f", (double)(*(long double*)varptr
));
1310 else if (type
== 16)
1311 sprintf(pszBuf
, "%s", *(char*)varptr
? "TRUE" : "FALSE");
1312 else if (type
== 17)
1313 sprintf(pszBuf
, "%s", *(short*)varptr
? "TRUE" : "FALSE");
1314 else if (type
== 18)
1315 sprintf(pszBuf
, "%s", *(long*)varptr
? "TRUE" : "FALSE");
1316 else if (type
== 20)
1317 sprintf(pszBuf
, "%c", *(char*)varptr
);
1318 else if (type
== 21)
1319 sprintf(pszBuf
, "%hd", (*(short*)varptr
));
1320 else if (type
== 22)
1321 sprintf(pszBuf
, "%ld", *(long*)varptr
);
1322 else if (type
== 23)
1323 sprintf(pszBuf
, "void");
1324 else if (type
>= 32)
1326 sprintf(pszBuf
, "0x%p", (void*)(*(ULONG
*)varptr
));
1327 if (Attr
& PAG_FREE
)
1329 strcat(pszBuf
, " unallocated memory");
1333 if ((Attr
& PAG_COMMIT
) == 0x0U
)
1335 strcat(pszBuf
, " uncommitted");
1337 if ((Attr
& PAG_WRITE
) == 0x0U
)
1339 strcat(pszBuf
, " unwritable");
1341 if ((Attr
& PAG_READ
) == 0x0U
)
1343 strcat(pszBuf
, " unreadable");
1348 sprintf(pszBuf
, "Unknown type %d", type
);
1353 * searches the table of userdef's-
1354 * Return TRUE if found.
1357 static BOOL
search_userdefs(FILE *LogFile
, // in: text log file to write to
1364 pos
< userdef_count
;
1367 if (one_userdef
[pos
].idx
== autovar_def
[var_no
].type_idx
)
1369 if ( (one_userdef
[pos
].type_index
>= 0x80)
1370 // && (one_userdef[pos].type_index <= 0xDA)
1373 static char sszVar3
[500] = "complex";
1374 if (one_userdef
[pos
].type_index
<= 0xDA)
1375 var_value((void*)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1377 one_userdef
[pos
].type_index
- 0x80);
1380 " %- 6ld %- 20.20s %- 33.33s %s (user)\n",
1381 autovar_def
[var_no
].stack_offset
, // stack offset
1382 autovar_def
[var_no
].name
, // identifier
1383 one_userdef
[pos
].name
, // type name
1384 sszVar3
// composed by var_value
1401 static BOOL
search_pointers(FILE *LogFile
, // in: text log file to write to
1406 static BYTE str
[35];
1407 static char sszVar
[500];
1412 ( (pos
< pointer_count
)
1413 && (one_pointer
[pos
].idx
!= autovar_def
[var_no
].type_idx
)
1417 if (pos
< pointer_count
)
1419 if ( (one_pointer
[pos
].type_index
>= 0x80)
1420 && (one_pointer
[pos
].type_index
<= 0xDA)
1423 strcpy(str
, type_name
[one_pointer
[pos
].type_index
- 0x80]);
1425 var_value((void*)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1428 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1429 autovar_def
[var_no
].stack_offset
,
1430 autovar_def
[var_no
].name
,
1437 // If the result isn't a simple type, look for it in the other lists
1439 ( (upos
< userdef_count
)
1440 && (one_userdef
[upos
].idx
!= one_pointer
[pos
].type_index
)
1445 if (upos
< userdef_count
)
1447 strcpy(str
, one_userdef
[upos
].name
);
1449 var_value((void *)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1452 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1453 autovar_def
[var_no
].stack_offset
,
1454 autovar_def
[var_no
].name
,
1461 // if it isn't a userdef, for now give up and just print
1462 // as much as we know
1463 sprintf(str
, "Pointer to type 0x%X", one_pointer
[pos
].type_index
);
1465 var_value((void *)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1468 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1469 autovar_def
[var_no
].stack_offset
,
1470 autovar_def
[var_no
].name
,
1483 *@@ dbgPrintVariables:
1484 * Dumps variables for the specified stack offset
1485 * to the specified log file.
1490 void dbgPrintVariables(FILE *LogFile
, // in: text log file to write to
1494 BOOL AutoVarsFound
= FALSE
;
1496 if (/* 1 || */ func_ofs
== pubfunc_ofs
)
1502 if (AutoVarsFound
== FALSE
)
1504 AutoVarsFound
= TRUE
;
1505 fprintf(LogFile
, " List of auto variables at EBP %p in %s:\n",
1508 fprintf(LogFile
, " Offset Name Type Value \n");
1509 fprintf(LogFile
, " ������ �������������������� ��������������������������������� �����������������\n");
1512 // If it's one of the simple types
1513 if ( (autovar_def
[n
].type_idx
>= 0x80)
1514 && (autovar_def
[n
].type_idx
<= 0xDA)
1517 static char sszVar2
[500];
1519 var_value((void *)(stackofs
+ autovar_def
[n
].stack_offset
),
1521 autovar_def
[n
].type_idx
- 0x80);
1523 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
1524 autovar_def
[n
].stack_offset
,
1525 autovar_def
[n
].name
,
1526 type_name
[autovar_def
[n
].type_idx
- 0x80],
1530 { // Complex type, check if we know what it is
1531 if (!search_userdefs(LogFile
, stackofs
, n
))
1533 if (!search_pointers(LogFile
, stackofs
, n
))
1535 fprintf(LogFile
, " %- 6ld %-20.20s 0x%X (unknown)\n",
1536 autovar_def
[n
].stack_offset
,
1537 autovar_def
[n
].name
,
1538 autovar_def
[n
].type_idx
);
1543 /* if (AutoVarsFound == FALSE)
1545 fprintf(LogFile, " No auto variables found in %s.\n", func_name);
1547 fprintf(LogFile
, "\n");
1551 /* ******************************************************************
1553 * PART 3: ANALYZE SYMBOL (.SYM) FILE
1555 ********************************************************************/
1558 *@@ dbgPrintSYMInfo:
1559 * this gets called by dbgPrintStack if dbgPrintDebugInfo
1560 * failed (because no debug code was found) to check if
1561 * maybe a SYM file with the same filename exists and try
1562 * to get the info from there.
1564 * This gets called for every line of the stack
1565 * walk, but only if getting the information from
1566 * the debug code failed, e.g. because no debug code
1567 * was available for an address.
1569 * The file pointer is in the "Source file" column
1570 * every time this gets called.
1574 * Returns 0 if reading the SYM file was successful.
1576 *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
1579 int dbgPrintSYMInfo(FILE *LogFile
, // in: text log file to write to
1580 CHAR
*SymFileName
, // in: SYM file name (can be fully q'fied)
1584 static FILE *SymFile
;
1585 static MAPDEF MapDef
;
1586 static SEGDEF SegDef
;
1587 static SYMDEF32 SymDef32
;
1588 static SYMDEF16 SymDef16
;
1589 static char Buffer
[256];
1590 static int SegNum
, SymNum
, LastVal
;
1591 static unsigned long int SegOffset
,
1592 SymOffset
, SymPtrOffset
;
1595 #ifdef DEBUG_SYMDUMP
1596 fprintf(LogFile
,"Dump of '%s' for object %d\n",SymFileName
,Object
);
1598 SymFile
= fopen(SymFileName
, "rb");
1602 // read in first map definition
1603 fread(&MapDef
, sizeof(MAPDEF
), 1, SymFile
);
1604 #ifdef DEBUG_SYMDUMP
1605 Buffer
[0] = MapDef
.achModName
[0];
1606 fread(&Buffer
[1], 1, MapDef
.cbModName
-1, SymFile
);
1607 Buffer
[MapDef
.cbModName
] = 0x00;
1608 fprintf(LogFile
,"Module name '%s'\n",Buffer
);
1611 SegOffset
= SEGDEFOFFSET(MapDef
);
1612 #ifdef DEBUG_SYMDUMP
1613 fprintf(LogFile
,"SegOffset %0x\n",SegOffset
);
1616 // go thru all segments
1618 SegNum
< MapDef
.cSegs
;
1621 #ifdef DEBUG_SYMDUMP
1622 fprintf(LogFile
,"Scanning segment #%d Offset %08X\n",SegNum
,SegOffset
);
1624 if (fseek(SymFile
, SegOffset
, SEEK_SET
))
1628 // read in segment definition
1629 fread(&SegDef
, sizeof(SEGDEF
), 1, SymFile
);
1630 #ifdef DEBUG_SYMDUMP
1632 if (SegDef
.cbSegName
>0) {
1633 Buffer
[0] = SegDef
.achSegName
[0];
1634 fread(&Buffer
[1], 1, SegDef
.cbSegName
-1, SymFile
);
1635 Buffer
[SegDef
.cbSegName
] = 0x00;
1637 fprintf(LogFile
,"Segment name '%s', number %d, flags %02x\n",Buffer
,SegNum
,SegDef
.bFlags
);
1640 if (SegNum
== Object
)
1642 // stack object found:
1646 // go thru all symbols in this object
1647 #ifdef DEBUG_SYMDUMP
1648 fprintf(LogFile
,"Scanning #%d symbols\n",SegDef
.cSymbols
);
1650 for (SymNum
= 0; SymNum
< SegDef
.cSymbols
; SymNum
++)
1652 SymPtrOffset
=SYMDEFOFFSET(SegOffset
,SegDef
,SymNum
);
1653 fseek(SymFile
,SymPtrOffset
,SEEK_SET
);
1654 fread(&SymOffset
,sizeof(unsigned short int),1,SymFile
);
1655 fseek(SymFile
,SymOffset
+SegOffset
,SEEK_SET
);
1656 if (SegDef
.bFlags
& 0x01)
1659 fread(&SymDef32
, sizeof(SYMDEF32
), 1, SymFile
);
1660 if (SymDef32
.wSymVal
> TrapOffset
)
1664 "between %s + 0x%lX ",
1666 TrapOffset
- LastVal
);
1667 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1668 LINEDEFOFFSET(SegDef)
1670 fprintf(LogFile
, "\n");
1673 LastVal
= SymDef32
.wSymVal
;
1674 Buffer
[0] = SymDef32
.achSymName
[0];
1675 fread(&Buffer
[1], 1, SymDef32
.cbSymName
-1, SymFile
);
1676 Buffer
[SymDef32
.cbSymName
] = 0x00;
1677 #ifdef DEBUG_SYMDUMP
1678 fprintf(LogFile
,"32 Bit Symbol Address %08p <%s> \n",SymDef32
.wSymVal
,Buffer
);
1681 if (SymDef32
.wSymVal
> TrapOffset
)
1683 // symbol found, as above
1688 LastVal
- TrapOffset
);
1689 fprintf(LogFile
, "\n");
1696 fread(&SymDef16
, sizeof(SYMDEF16
), 1, SymFile
);
1697 if (SymDef16
.wSymVal
> TrapOffset
)
1700 "between %s + %lX\n",
1702 TrapOffset
- LastVal
);
1704 LastVal
= SymDef16
.wSymVal
;
1705 Buffer
[0] = SymDef16
.achSymName
[0];
1706 fread(&Buffer
[1], 1, SymDef16
.cbSymName
-1, SymFile
);
1707 Buffer
[SymDef16
.cbSymName
] = 0x00;
1708 if (SymDef16
.wSymVal
> TrapOffset
)
1714 LastVal
- TrapOffset
);
1717 #ifdef DEBUG_SYMDUMP
1718 fprintf(LogFile
,"16 Bit Symbol <%s> Address %p\n",Buffer
,SymDef16
.wSymVal
);
1724 SegOffset
= NEXTSEGDEFOFFSET(SegDef
);
1727 return (0); // no error
1730 /* ******************************************************************
1732 * PART 4: dbgPrintStack
1734 ********************************************************************/
1737 *@@ dbgPrintStackFrame:
1738 * parses and dumps one stack frame.
1739 * Called from excPrintStackFrame.
1741 * This calls dbgPrintDebugInfo and, if
1742 * that fails, dbgPrintSYMInfo.
1744 *@@added V0.9.2 (2000-03-10) [umoeller]
1745 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1746 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1749 BOOL
dbgPrintStackFrame(FILE *LogFile
,
1750 PSZ pszModuleName
, // in: module name (fully q'fied)
1755 // "Source file"... columns
1757 //YD do not use debug info
1758 #define ENABLE_DEBUG_INFO
1759 #ifdef ENABLE_DEBUG_INFO
1760 // first attempt to analyze the debug code
1761 arc
= dbgPrintDebugInfo(LogFile
,
1769 // if no debug code is available, analyze
1770 // the SYM file instead
1771 if (arc
!= NO_ERROR
)
1773 CHAR szSymName
[CCHMAXPATH
];
1774 strcpy(szSymName
, pszModuleName
);
1775 strcpy(szSymName
+ strlen(szSymName
) - 3, "SYM");
1776 arc
= dbgPrintSYMInfo(LogFile
,
1782 // SYM file not found in current directory:
1783 // check the SYM files in the \OS2 directory,
1784 // depending on the OS/2 version level:
1785 CHAR szSymFile2
[CCHMAXPATH
];
1786 PSZ pszFilename
= strrchr(szSymName
, '\\');
1789 PSZ pszVersionDir
= "WARP4";
1792 DosQuerySysInfo(QSV_VERSION_MAJOR
, // 11
1793 QSV_VERSION_MINOR
, // 12
1794 &aulBuf
, sizeof(aulBuf
));
1795 // Warp 3 is reported as 20.30
1796 // Warp 4 is reported as 20.40
1797 // Aurora is reported as 20.45
1799 if (aulBuf
[0] == 20)
1801 if (aulBuf
[1] == 30)
1803 pszVersionDir
= "WARP3";
1804 else if (aulBuf
[1] >= 40)
1805 // Warp 4 or higher:
1806 // (NOTE: Warp 4 FP 13 now returns 45 also,
1807 // but the SYM files are still in the WARP4 directory...)
1808 // V0.9.3 (2000-04-26) [umoeller]
1809 pszVersionDir
= "WARP4";
1814 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1815 doshQueryBootDrive(),
1818 arc
= dbgPrintSYMInfo(LogFile
,
1823 // V0.9.3 (2000-04-26) [umoeller]
1824 if ( (arc
!= 0) // still not found
1825 && (aulBuf
[1] == 45) // and running Aurora or Warp 4 FP13?
1828 // Warp Server for e-Business (aka Warp 4.5):
1829 // we use the SYM files for the UNI kernel,
1830 // I have found no way to find out whether
1831 // we're running on an SMP kernel
1833 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1834 doshQueryBootDrive(),
1837 arc
= dbgPrintSYMInfo(LogFile
,
1845 if (arc
== 2) // file not found
1847 "Cannot find symbol file %s\n",
1851 "Error %lu reading symbol file %s\n",
1856 return (arc
== NO_ERROR
);
1861 * this takes stack data from the TIB and
1862 * context record data structures and tries
1863 * to analyse what the different stack frames
1866 * For each stack frame, this calls dbgPrintDebugInfo,
1867 * and, if that fails, dbgPrintSYMInfo.
1871 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1874 VOID
dbgPrintStack(FILE *LogFile
, // in: text log file to write to
1875 PUSHORT StackBottom
,
1878 PUSHORT ExceptionAddress
)
1880 PUSHORT RetAddr
= 0;
1881 PUSHORT LastEbp
= 0;
1889 static char Name
[CCHMAXPATH
];
1893 BOOL fExceptionAddress
= TRUE
; // Use Exception Addr 1st time thru
1895 // Note: we can't handle stacks bigger than 64K for now...
1896 Sp
= (USHORT
) (((ULONG
) StackBottom
) >> 16);
1900 Ebp
= (PUSHORT
) MAKEULONG(((USHORT
)(ULONG
)Ebp
), Sp
);
1902 fprintf(LogFile
, "\n\nCall stack:\n");
1903 fprintf(LogFile
, " Source Line Nearest\n");
1904 fprintf(LogFile
, " EBP Address Module Obj# File Numbr Public Symbol\n");
1905 fprintf(LogFile
, " �������� ��������- �������� ���� ������������ ����� ������������-\n");
1910 rc
= DosQueryMem((PVOID
) (Ebp
+ 2), &Size
, &Attr
);
1913 fprintf(LogFile
, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG
)Ebp
, rc
);
1916 if (!(Attr
& PAG_COMMIT
))
1918 fprintf(LogFile
, "Invalid EBP %8.8lX (not committed)\n", (ULONG
)Ebp
);
1923 fprintf(LogFile
, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG
)Ebp
);
1927 if (fExceptionAddress
)
1928 RetAddr
= ExceptionAddress
;
1930 RetAddr
= (PUSHORT
) (*((PULONG
) (Ebp
+ 2)));
1932 if (RetAddr
== (PUSHORT
) 0x00000053)
1934 // For some reason there's a "return address" of 0x53 following
1935 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1936 // at the real return address. This has something to do with
1937 // thunking from 32bits to 16bits...
1938 // Serious kludge, and it's probably dependent on versions of C(++)
1939 // runtime or OS, but it works for now!
1941 RetAddr
= (PUSHORT
) (*((PULONG
) (Ebp
+ 2)));
1944 // Get the (possibly) 16bit CS and IP
1945 if (fExceptionAddress
)
1947 Cs
= (USHORT
) (((ULONG
) ExceptionAddress
) >> 16);
1948 Ip
= (USHORT
) (ULONG
) ExceptionAddress
;
1956 // if the return address points to the stack then it's really just
1957 // a pointer to the return address (UGH!).
1958 if ( (USHORT
) (((ULONG
) RetAddr
) >> 16) == Sp
1960 RetAddr
= (PUSHORT
) (*((PULONG
) RetAddr
));
1962 if (Ip
== 0 && *Ebp
== 0)
1964 // End of the stack so these are both shifted by 2 bytes:
1969 // 16bit programs have on the stack:
1971 // where CS may be thunked
1974 // BP IP CS BP CS IP
1975 // 4677 53B5 F7D0 7746 D0F7 B553
1977 // 32bit programs have:
1979 // and you'd have something like this (with SP added) (not
1984 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1986 // So the basic difference is that 32bit programs have a 32bit
1987 // EBP and we can attempt to determine whether we have a 32bit
1988 // EBP by checking to see if its 'selector' is the same as SP.
1989 // Note that this technique limits us to checking stacks < 64K.
1991 // Soooo, if IP (which maps into the same USHORT as the swapped
1992 // stack page in EBP) doesn't point to the stack (i.e. it could
1993 // be a 16bit IP) then see if CS is valid (as is or thunked).
1995 // Note that there's the possibility of a 16bit return address
1996 // that has an offset that's the same as SP so we'll think it's
1997 // a 32bit return address and won't be able to successfully resolve
2001 if (DosSizeSeg(Cs
, &Size
) == NO_ERROR
)
2003 RetAddr
= (USHORT
* _Seg16
) MAKEULONG(Ip
, Cs
);
2006 else if (DosSizeSeg((Cs
<< 3) + 7, &Size
) == NO_ERROR
)
2009 RetAddr
= (USHORT
* _Seg16
) MAKEULONG(Ip
, Cs
);
2020 if (fExceptionAddress
)
2021 fprintf(LogFile
, " Trap -> ");
2023 fprintf(LogFile
, " %8.8lX ", (ULONG
)Ebp
);
2027 fprintf(LogFile
, ":%8.8lX ", (ULONG
)RetAddr
);
2029 fprintf(LogFile
, "%04.04X:%04.04X ", Cs
, Ip
);
2031 // Version check omitted; the following requires
2032 // OS/2 2.10 or later (*UM)
2033 // if (Version[0] >= 20 && Version[1] >= 10)
2035 // Make a 'tick' sound to let the user know we're still alive
2038 Size
= 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
2040 // "Module"/"Object" columns
2041 rc
= DosQueryMem((PVOID
) RetAddr
, &Size
, &Attr
);
2042 if (rc
!= NO_ERROR
|| !(Attr
& PAG_COMMIT
))
2044 fprintf(LogFile
, "Invalid RetAddr: %8.8lX\n", (ULONG
)RetAddr
);
2045 break; // avoid infinite loops
2049 rc
= DosQueryModFromEIP(&hMod
,
2054 if ( (rc
== NO_ERROR
)
2055 // && (ObjNum != -1)
2058 // static char szJunk[_MAX_FNAME];
2059 static char szName
[_MAX_FNAME
];
2061 DosQueryModuleName(hMod
, sizeof(Name
), Name
);
2062 // _splitpath(Name, szJunk, szJunk, szName, szJunk);
2064 // print module and object
2065 fprintf(LogFile
, "%-8s %04lX ", szName
, ObjNum
+ 1);
2067 if (strlen(Name
) > 3)
2069 dbgPrintStackFrame(LogFile
,
2077 "DosQueryModFromEIP failed, returned %lu\n",
2083 && ((*Ebp
+ 1) == 0)
2086 fprintf(LogFile
, "End of call stack\n");
2090 if (!fExceptionAddress
)
2094 Ebp
= (PUSHORT
) MAKEULONG(Bp
, Sp
);
2095 #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2097 Ebp
= (PUSHORT
) *(PULONG
) LastEbp
;
2099 Ebp
= (PUSHORT
) MAKEULONG((*Ebp
), Sp
);
2103 dbgPrintVariables(LogFile
, (ULONG
) Ebp
);
2108 fprintf(LogFile
, "... lost stack chain - new EBP below previous\n");
2113 fExceptionAddress
= FALSE
;
2116 rc
= DosQueryMem((PVOID
) Ebp
, &Size
, &Attr
);
2117 if ((rc
!= NO_ERROR
) || (Size
< 4))
2119 fprintf(LogFile
, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG
)Ebp
);
2124 fprintf(LogFile
, "\n");
2128 *@@ doshQueryBootDrive:
2129 * returns the letter of the boot drive as a
2130 * single (capital) character, which is useful for
2131 * constructing file names using sprintf and such.
2133 *@@changed V0.9.16 (2002-01-13) [umoeller]: optimized
2136 CHAR
doshQueryBootDrive(VOID
)
2138 // this can never change, so query this only once
2139 // V0.9.16 (2002-01-13) [umoeller]
2140 static CHAR cBootDrive
= '\0';
2145 DosQuerySysInfo(QSV_BOOT_DRIVE
, QSV_BOOT_DRIVE
,
2147 sizeof(ulBootDrive
));
2148 cBootDrive
= (CHAR
)ulBootDrive
+ 'A' - 1;
2151 return (cBootDrive
);