1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 *@@sourcefile debug.c:
33 * this file contains debugging functions for the
34 * exception handlers in except.c.
36 * This code is capable of unwinding the stack from
37 * a given address and trying to get function names
38 * and source line numbers, either from the respective
39 * module's debug code (if present) or from a SYM file,
40 * which is searched for in the directory of the module
41 * or in ?:\OS2\PDPSI\PMDF\WARP4.
43 * This file incorporates code from the following:
44 * -- Marc Fiammante, John Currier, Kim Rasmussen,
45 * Anthony Cruise (EXCEPT3.ZIP package for a generic
46 * exception handling DLL, available at Hobbes).
48 * Usage: All OS/2 programs.
50 * Note: Version numbering in this file relates to XWorkplace version
53 *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
54 *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
56 *@@header "helpers\debug.h"
60 * This file Copyright (C) 1992-99 Ulrich M�ller,
65 * This file is part of the "XWorkplace helpers" source package.
67 * 2009-06-15 published under LGPL3 with Ulrich M�ller permission.
71 //#define DEBUG_SYMDUMP // enable to dump sym file to log
73 //YD commented, since we need unsigned char BYTE!
74 //#define OS2EMX_PLAIN_CHAR
75 //Also gcc char is signed, while most structures requires unsigned data!
76 //Raised limits for all fields!
78 // this is needed for "os2emx.h"; if this is defined,
79 // emx will define PSZ as _signed_ char, otherwise
82 #define INCL_DOSPROCESS
83 #define INCL_DOSMODULEMGR
85 #define INCL_DOSERRORS
92 #define DONT_REPLACE_MALLOC
93 #include "helpers\setup.h" // code generation and debugging options
95 #include "helpers\debug.h"
96 #include "helpers\dosh.h"
102 #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
104 #include <sys\stat.h>
109 #define DWORD unsigned long
112 #define WORD unsigned short
119 *@@category: Helpers\Control program helpers\Exceptions/debugging
120 * See except.c and debug.c.
123 /* ******************************************************************
127 ********************************************************************/
129 // this specifies whether we're dealing with 32-bit code;
130 // this gets changed whenever 16-bit count is detected
131 static BOOL f32bit
= TRUE
;
134 * Global variables for Read32PmDebug:
140 //YD 17/07/06 c++ namespace can generate really long
141 //YD names, use a large buffer!
142 char func_name
[16*1024];
176 "16 bit characters ",
177 "32 bit characters ",
187 "near pointer to 8 bit signed ",
188 "near pointer to 16 bit signed ",
189 "near pointer to 32 bit signed ",
191 "near pointer to 8 bit unsigned ",
192 "near pointer to 16 bit unsigned ",
193 "near pointer to 32 bit unsigned ",
195 "near pointer to 32 bit real ",
196 "near pointer to 64 bit real ",
197 "near pointer to 80 bit real ",
199 "near pointer to 64 bit complex ",
200 "near pointer to 128 bit complex ",
201 "near pointer to 160 bit complex ",
203 "near pointer to 8 bit boolean ",
204 "near pointer to 16 bit boolean ",
205 "near pointer to 32 bit boolean ",
207 "near pointer to 8 bit character ",
208 "near pointer to 16 bit characters",
209 "near pointer to 32 bit characters",
210 "near pointer to void ",
211 "near pointer to 15 bit unsigned ",
212 "near pointer to 24 bit unsigned ",
213 "near pointer to 31 bit unsigned ",
219 "far pointer to 8 bit signed ",
220 "far pointer to 16 bit signed ",
221 "far pointer to 32 bit signed ",
223 "far pointer to 8 bit unsigned ",
224 "far pointer to 16 bit unsigned ",
225 "far pointer to 32 bit unsigned ",
227 "far pointer to 32 bit real ",
228 "far pointer to 64 bit real ",
229 "far pointer to 80 bit real ",
231 "far pointer to 64 bit complex ",
232 "far pointer to 128 bit complex ",
233 "far pointer to 160 bit complex ",
235 "far pointer to 8 bit boolean ",
236 "far pointer to 16 bit boolean ",
237 "far pointer to 32 bit boolean ",
239 "far pointer to 8 bit character ",
240 "far pointer to 16 bit characters ",
241 "far pointer to 32 bit characters ",
242 "far pointer to void ",
243 "far pointer to 15 bit unsigned ",
244 "far pointer to 24 bit unsigned ",
245 "far pointer to 31 bit unsigned ",
248 // Thanks to John Currier:
249 // Do not call 16 bit code in myHandler function to prevent call
250 // to __EDCThunkProlog and problems is guard page exception handling
251 // Also reduce the stack size to 1K for true 16 bit calls.
252 // 16 bit calls thunk will now only occur on fatal exceptions
253 #pragma stack16(1024)
255 // ------------------------------------------------------------------
256 // Last 8 bytes of 16:16 file when CODEVIEW debugging info is present
260 unsigned short dbug
; // 'NB' signature
261 unsigned short ver
; // version
262 unsigned long dfaBase
; // size of codeview info
265 #define DBUGSIG 0x424E
266 #define SSTMODULES 0x0101
267 #define SSTPUBLICS 0x0102
268 #define SSTTYPES 0x0103
269 #define SSTSYMBOLS 0x0104
270 #define SSTSRCLINES 0x0105
271 #define SSTLIBRARIES 0x0106
272 #define SSTSRCLINES2 0x0109
273 #define SSTSRCLINES32 0x010B
275 typedef struct _SYMBASE
277 unsigned short dbug
; // 'NB' signature
278 unsigned short ver
; // version
279 unsigned long lfoDir
; // file offset to dir entries
282 typedef struct _SSDIR
284 unsigned short sst
; // SubSection Type
285 unsigned short modindex
; // Module index number
286 unsigned long lfoStart
; // Start of section
287 unsigned short cb
; // Size of section
290 typedef struct _SSDIR32
292 unsigned short sst
; // SubSection Type
293 unsigned short modindex
; // Module index number
294 unsigned long lfoStart
; // Start of section
295 unsigned long cb
; // Size of section
298 typedef struct _SSMODULE
300 unsigned short csBase
; // code segment base
301 unsigned short csOff
; // code segment offset
302 unsigned short csLen
; // code segment length
303 unsigned short ovrNum
; // overlay number
304 unsigned short indxSS
; // Index into sstLib or 0
305 unsigned short reserved
;
306 BYTE csize
; // size of prefix string
309 typedef struct _SSMOD32
311 unsigned short csBase
; // code segment base
312 unsigned long csOff
; // code segment offset
313 unsigned long csLen
; // code segment length
314 unsigned long ovrNum
; // overlay number
315 unsigned short indxSS
; // Index into sstLib or 0
316 unsigned long reserved
;
317 BYTE csize
; // size of prefix string
320 typedef struct _SSPUBLIC
322 unsigned short offset
;
323 unsigned short segment
;
328 typedef struct _SSPUBLIC32
330 unsigned long offset
;
331 unsigned short segment
;
336 typedef struct _SSLINEENTRY32
338 unsigned short LineNum
;
339 unsigned short FileNum
;
340 unsigned long Offset
;
343 typedef struct _FIRSTLINEENTRY32
345 unsigned short LineNum
;
346 unsigned char entry_type
;
347 unsigned char reserved
;
348 unsigned short numlines
;
349 unsigned short segnum
;
352 typedef struct _SSFILENUM32
354 unsigned long first_displayable
; // Not used
355 unsigned long number_displayable
; // Not used
356 unsigned long file_count
; // number of source files
361 * buffers for Read... funcs.
363 *@@added V0.9.4 (2000-06-15) [umoeller]
366 typedef struct _XDEBUGINFO
368 char szNrFile
[300]; // receives source file
369 char szNrLine
[300]; // receives line number
370 //YD 17/07/06 c++ namespace can generate really long
371 //YD names, use a large buffer!
372 char szNrPub
[16*1024]; // receives function name
374 struct new_seg
*pseg
;
375 struct o32_obj
*pobj
; // flat .EXE object table entry
381 unsigned char *pEntTab
;
382 unsigned long lfaBase
;
388 } XDEBUGINFO
, *PXDEBUGINFO
;
391 USHORT
_THUNK_FUNCTION (Dos16SizeSeg
) ();
392 //APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
393 USHORT
DosSizeSeg (USHORT Seg
, PULONG16 Size
)
396 (_THUNK_PROLOG (2+4);
399 _THUNK_CALL (Dos16SizeSeg
)));
404 /* ******************************************************************
406 * PART 1: ANALYZE DEBUG CODE
408 ********************************************************************/
410 static int Read16CodeView(FILE *LogFile
, PXDEBUGINFO pxdi
, int fh
, int TrapSeg
, int TrapOff
, CHAR
*FileName
);
411 static int Read32PmDebug(FILE *LogFile
, PXDEBUGINFO pxdi
, int fh
, int TrapSeg
, int TrapOff
, CHAR
*FileName
);
414 *@@ WriteAddressInfo:
415 * formats and writes a line into the trap log
418 * This gets called for each line from the
419 * stack dump. At this point, the line in the
420 * trap log already has:
422 + CS:EIP : 000109FF XMLVIEW :0
423 + ^^^ and we write here
424 * After this call, we have.
426 + CS:EIP : 000109FF XMLVIEW :0 xxx.c 123 ConfirmCreate__Fv
427 + ^^^ and we write here
429 *@@added V0.9.12 (2001-05-12) [umoeller]
432 static VOID
WriteDebugInfo(FILE *LogFile
, // in: open log file
433 PXDEBUGINFO pxdi
) // in: debug info
443 *@@ dbgPrintDebugInfo:
444 * this is the main entry point into analyzing debug
447 * This analyzes a given address and tries to find
448 * debug code descriptions for this address. If found,
449 * the information is written to the given log file.
451 * Gets called from dbgPrintStack.
453 * This returns NO_ERROR if the could was successfully
454 * analyzed or something != 0 if we failed.
459 APIRET
dbgPrintDebugInfo(FILE *LogFile
, // out: log file to write to
460 CHAR
*FileName
, // in: EXE/DLL module file name
461 ULONG Object
, // in: trapping object (from DosQueryModFromEIP)
462 ULONG TrapOffset
) // in: trapping address (from DosQueryModFromEIP)
466 static struct exe_hdr OldExeHeader
;
467 static struct new_exe NewExeHeader
;
469 ULONG ulSegment
= Object
+ 1; // segment no. is object no. + 1
472 memset(&xdi
, 0, sizeof(xdi
));
474 // open the module file for reading to analyze the code
475 ModuleFile
= sopen(FileName
, O_RDONLY
| O_BINARY
, SH_DENYNO
);
477 if (ModuleFile
!= -1)
480 // read old Exe header
481 if (read(ModuleFile
, (void*)&OldExeHeader
, 64) == -1L)
483 fprintf(LogFile
, "errno %d reading old exe header\n", errno
);
487 // seek to new Exe header
488 if (lseek(ModuleFile
, (long)E_LFANEW(OldExeHeader
), SEEK_SET
) == -1L)
490 fprintf(LogFile
, "errno %d seeking to new exe header\n", errno
);
494 if (read(ModuleFile
, (void *)&NewExeHeader
, 64) == -1L)
496 fprintf(LogFile
, "errno %d reading new exe header\n", errno
);
501 // check EXE signature
502 if (NE_MAGIC(NewExeHeader
) == E32MAGIC
)
505 * flat 32 executable:
509 // do analysis for 32-bit code
510 if (!(rc
= Read32PmDebug(LogFile
,
516 WriteDebugInfo(LogFile
, &xdi
);
520 // rc !=0 try with DBG file
523 strcpy(FileName
+ strlen(FileName
) - 3, "DBG"); // Build DBG File name
524 ModuleFile
= sopen(FileName
, O_RDONLY
| O_BINARY
, SH_DENYNO
);
525 if (ModuleFile
!= -1)
527 if (!(rc
= Read32PmDebug(LogFile
,
533 WriteDebugInfo(LogFile
, &xdi
);
543 if (NE_MAGIC(NewExeHeader
) == NEMAGIC
)
550 if ((xdi
.pseg
= (struct new_seg
*)calloc(NE_CSEG(NewExeHeader
),
551 sizeof(struct new_seg
)))
554 fprintf(LogFile
, "Out of memory!");
558 if ( lseek(ModuleFile
,
559 E_LFANEW(OldExeHeader
) + NE_SEGTAB(NewExeHeader
),
562 fprintf(LogFile
, "Error %u seeking segment table in %s\n", errno
, FileName
);
570 NE_CSEG(NewExeHeader
) * sizeof(struct new_seg
))
573 fprintf(LogFile
, "Error %u reading segment table from %s\n", errno
, FileName
);
579 if (!(rc
= Read16CodeView(LogFile
,
585 WriteDebugInfo(LogFile
, &xdi
);
590 // rc !=0 try with DBG file
593 strcpy(FileName
+ strlen(FileName
) - 3, "DBG"); // Build DBG File name
594 ModuleFile
= sopen(FileName
,
595 O_RDONLY
| O_BINARY
, SH_DENYNO
);
596 if (ModuleFile
!= -1)
598 if (!(rc
= Read16CodeView(LogFile
,
604 WriteDebugInfo(LogFile
, &xdi
);
614 * Unknown executable:
618 fprintf(LogFile
, "Error, could not find exe signature");
623 } // end if (ModuleFile != -1)
626 fprintf(LogFile
, "Error %d opening module file %s", errno
, FileName
);
630 // return 0; we never get here
638 #define MAX_USERDEFS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
639 #define MAX_POINTERS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
641 USHORT userdef_count
;
642 USHORT pointer_count
;
644 struct one_userdef_rec
649 } one_userdef
[MAX_USERDEFS
];
651 struct one_pointer_rec
657 } one_pointer
[MAX_POINTERS
];
661 * parses 32-bit debug code.
662 * Called from dbgPrintDebugInfo for 32-bit modules.
665 static int Read32PmDebug(FILE *LogFile
, // in: text log file to write to
667 int ModuleFile
, // in: module file opened with sopen()
672 static unsigned int CurrSymSeg
, NrSymbol
,
673 /* offset, */ NrPublic
,
674 NrFile
, NrLine
, /* NrEntry */
676 numlines
/* , line */;
678 static int bytesread
, i
, j
;
679 static SSLINEENTRY32 LineEntry
;
680 static SSFILENUM32 FileInfo
;
681 static FIRSTLINEENTRY32 FirstLine
;
682 static BYTE dump_vars
= FALSE
;
684 static BOOL read_types
;
688 // See if any CODEVIEW info
689 if (lseek(ModuleFile
, -8L, SEEK_END
) == -1)
691 fprintf(LogFile
, "Error %u seeking CodeView table in %s\n", errno
, FileName
);
696 (void *)&G_eodbug
, 8)
699 fprintf(LogFile
, "Error %u reading debug info from %s\n", errno
, FileName
);
702 if (G_eodbug
.dbug
!= DBUGSIG
)
704 // fprintf(LogFile,"\nNo CodeView information stored.\n");
708 if ( (pxdi
->lfaBase
= lseek(ModuleFile
,
709 -(LONG
)G_eodbug
.dfaBase
,
713 fprintf(LogFile
, "Error %u seeking base codeview data in %s\n", errno
, FileName
);
718 (void *)&pxdi
->base
, 8)
721 fprintf(LogFile
, "Error %u reading base codeview data in %s\n", errno
, FileName
);
725 if (lseek(ModuleFile
,
726 pxdi
->base
.lfoDir
- 8 + 4,
730 fprintf(LogFile
, "Error %u seeking dir codeview data in %s\n", errno
, FileName
);
738 fprintf(LogFile
, "Error %u reading dir codeview data in %s\n", errno
, FileName
);
742 // Read dir table into buffer
743 if ( (pxdi
->pDirTab32
= (SSDIR32
*)calloc(numdir
,
747 fprintf(LogFile
, "Out of memory!");
752 (void*)pxdi
->pDirTab32
,
753 numdir
* sizeof(SSDIR32
))
756 fprintf(LogFile
, "Error %u reading codeview dir table from %s\n", errno
, FileName
);
757 free(pxdi
->pDirTab32
);
764 if (pxdi
->pDirTab32
[i
].sst
!= SSTMODULES
)
775 // point to subsection
777 pxdi
->pDirTab32
[i
].lfoStart
+ pxdi
->lfaBase
,
780 (void*)&pxdi
->ssmod32
.csBase
,
784 (unsigned)pxdi
->ssmod32
.csize
);
785 ModIndex
= pxdi
->pDirTab32
[i
].modindex
;
786 ModName
[pxdi
->ssmod32
.csize
] = '\0';
791 while ( (pxdi
->pDirTab32
[i
].modindex
== ModIndex
)
795 // point to subsection
797 pxdi
->pDirTab32
[i
].lfoStart
+ pxdi
->lfaBase
,
800 switch (pxdi
->pDirTab32
[i
].sst
)
804 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
806 bytesread
+= read(ModuleFile
,
807 (void *)&pxdi
->sspub32
.offset
,
808 sizeof(pxdi
->sspub32
));
809 bytesread
+= read(ModuleFile
,
811 (unsigned)pxdi
->sspub32
.csize
);
812 ename
[pxdi
->sspub32
.csize
] = '\0';
813 if ( (pxdi
->sspub32
.segment
== TrapSeg
)
814 && (pxdi
->sspub32
.offset
<= TrapOff
)
815 && (pxdi
->sspub32
.offset
>= NrPublic
)
818 NrPublic
= pubfunc_ofs
= pxdi
->sspub32
.offset
;
820 sprintf(pxdi
->szNrPub
,
822 (pxdi
->sspub32
.type
== 1)
828 // but continue, because there might be a
829 // symbol that comes closer
834 // Read symbols, so we can dump the variables on the stack
836 if (TrapSeg
!= pxdi
->ssmod32
.csBase
)
840 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
842 static USHORT usLength
;
843 static USHORT usLengthSym
;
849 // static ULONG last_addr = 0;
850 //YD 17/07/06 c++ namespace can generate really long
851 //YD names, use a large buffer!
852 static BYTE str
[16*1024];
853 static struct symseg_rec symseg
;
854 static struct symauto_rec symauto
;
855 static struct symproc_rec symproc
;
857 // Read the length of this subentry
858 bytesread
+= read(ModuleFile
, &b1
, 1);
861 bytesread
+= read(ModuleFile
, &b2
, 1);
862 usLength
= ((b1
& 0x7F) << 8) + b2
;
867 ofs
= tell(ModuleFile
);
869 bytesread
+= read(ModuleFile
, &bType
, 1);
874 read(ModuleFile
, &symseg
, sizeof(symseg
));
875 CurrSymSeg
= symseg
.seg_no
;
880 read(ModuleFile
, &symproc
, sizeof(symproc
));
881 if (symproc
.name_len
& 0x80)
883 read(ModuleFile
, &b2
, 1);
884 usLengthSym
= ((symproc
.name_len
& 0x7F) << 8) + b2
;
888 usLengthSym
= symproc
.name_len
;
890 read(ModuleFile
, str
, usLengthSym
);
891 str
[usLengthSym
] = 0;
893 if ((CurrSymSeg
== TrapSeg
) &&
894 (symproc
.offset
<= TrapOff
) &&
895 (symproc
.offset
>= NrSymbol
))
900 NrSymbol
= symproc
.offset
;
901 func_ofs
= symproc
.offset
;
903 strcpy(func_name
, str
);
915 read(ModuleFile
, &symauto
, sizeof(symauto
));
916 read(ModuleFile
, str
, symauto
.name_len
);
917 if (symauto
.name_len
==0x80)
918 printf("symauto.name_len==0x80\n");
919 str
[symauto
.name_len
] = 0;
921 strcpy(autovar_def
[var_ofs
].name
, str
);
922 autovar_def
[var_ofs
].stack_offset
= symauto
.stack_offset
;
923 autovar_def
[var_ofs
].type_idx
= symauto
.type_idx
;
929 bytesread
+= usLength
;
931 lseek(ModuleFile
, ofs
+ usLength
, SEEK_SET
);
936 // if (ModIndex != TrapSeg)
944 while (bytesread
< pxdi
->pDirTab32
[i
].cb
)
946 static struct type_rec type
;
947 static struct type_userdefrec udef
;
948 static struct type_pointerrec point
;
950 static BYTE str
[256];
952 // Read the length of this subentry
953 ofs
= tell(ModuleFile
);
955 read(ModuleFile
, &type
, sizeof(type
));
956 bytesread
+= sizeof(type
);
961 if (userdef_count
>= MAX_USERDEFS
)
964 read(ModuleFile
, &udef
, sizeof(udef
));
965 read(ModuleFile
, str
, udef
.name_len
);
966 str
[udef
.name_len
] = 0;
968 // Insert userdef in table
969 one_userdef
[userdef_count
].idx
= idx
;
970 one_userdef
[userdef_count
].type_index
= udef
.type_index
;
971 memcpy(one_userdef
[userdef_count
].name
,
973 _min(udef
.name_len
+ 1, 32));
974 one_userdef
[userdef_count
].name
[32] = 0;
979 if (pointer_count
>= MAX_POINTERS
)
982 read(ModuleFile
, &point
, sizeof(point
));
983 read(ModuleFile
, str
, point
.name_len
);
984 str
[point
.name_len
] = 0;
986 // Insert userdef in table
987 one_pointer
[pointer_count
].idx
= idx
;
988 one_pointer
[pointer_count
].type_index
= point
.type_index
;
989 memcpy(one_pointer
[pointer_count
].name
,
991 _min(point
.name_len
+ 1, 32));
992 one_pointer
[pointer_count
].name
[32] = 0;
993 one_pointer
[pointer_count
].type_qual
= type
.type_qual
;
1000 bytesread
+= type
.length
;
1002 lseek(ModuleFile
, ofs
+ type
.length
+ 2, SEEK_SET
);
1007 if (TrapSeg
!= pxdi
->ssmod32
.csBase
)
1013 read(ModuleFile
, (void *)&FirstLine
, sizeof(FirstLine
));
1015 if (FirstLine
.LineNum
!= 0)
1017 fprintf(LogFile
, "Missing Line table information\n");
1020 numlines
= FirstLine
.numlines
;
1021 // Other type of data skip 4 more bytes
1022 if (FirstLine
.entry_type
< 4)
1024 read(ModuleFile
, (void *)&lSize
, 4);
1025 if (FirstLine
.entry_type
== 3)
1026 lseek(ModuleFile
, lSize
, SEEK_CUR
);
1029 while (FirstLine
.entry_type
== 3);
1031 for (j
= 0; j
< numlines
; j
++)
1033 switch (FirstLine
.entry_type
)
1036 read(ModuleFile
, (void *)&LineEntry
, sizeof(LineEntry
));
1037 // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
1038 // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
1039 if ( (LineEntry
.LineNum
)
1040 && (LineEntry
.Offset
+ pxdi
->ssmod32
.csOff
1042 && (LineEntry
.Offset
+ pxdi
->ssmod32
.csOff
>= NrLine
)
1045 NrLine
= LineEntry
.Offset
;
1046 NrFile
= LineEntry
.FileNum
;
1047 /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ",
1048 * ssmod32.csBase,LineEntry.Offset,
1049 * LineEntry.LineNum); */
1050 sprintf(pxdi
->szNrLine
, "% 6hu", LineEntry
.LineNum
);
1055 lseek(ModuleFile
, sizeof(struct linlist_rec
), SEEK_CUR
);
1059 lseek(ModuleFile
, sizeof(struct linsourcelist_rec
), SEEK_CUR
);
1063 lseek(ModuleFile
, sizeof(struct filenam_rec
), SEEK_CUR
);
1067 lseek(ModuleFile
, sizeof(struct pathtab_rec
), SEEK_CUR
);
1076 read(ModuleFile
, (void*)&FileInfo
, sizeof(FileInfo
));
1078 for (j
= 1; j
<= FileInfo
.file_count
; j
++)
1081 read(ModuleFile
, (void *)&namelen
, 1);
1082 read(ModuleFile
, (void *)ename
, namelen
);
1086 ename
[namelen
] = '\0';
1087 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
1088 sprintf(pxdi
->szNrFile
, "%11.11s ", ename
);
1092 // strcat(szNrLine,"\n"); avoid new line for empty name fill
1093 strcpy(pxdi
->szNrFile
, "file? ");
1099 } // end while modindex
1100 } // End While i < numdir
1101 free(pxdi
->pDirTab32
);
1107 * parses 16-bit debug code.
1108 * Called from dbgPrintDebugInfo for 16-bit modules.
1111 static int Read16CodeView(FILE *LogFile
, // in: text log file to write to
1118 static unsigned short int offset
,
1123 static int ModIndex
;
1124 static int bytesread
, i
, j
;
1127 // See if any CODEVIEW info
1128 if (lseek(fh
, -8L, SEEK_END
) == -1)
1130 fprintf(LogFile
, "Error %u seeking CodeView table in %s\n", errno
, FileName
);
1134 if (read(fh
, (void *)&G_eodbug
, 8) == -1)
1136 fprintf(LogFile
, "Error %u reading debug info from %s\n", errno
, FileName
);
1139 if (G_eodbug
.dbug
!= DBUGSIG
)
1141 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1145 if ((pxdi
->lfaBase
= lseek(fh
, -(LONG
)G_eodbug
.dfaBase
, SEEK_END
)) == -1L)
1147 fprintf(LogFile
, "Error %u seeking base codeview data in %s\n", errno
, FileName
);
1151 if (read(fh
, (void *)&pxdi
->base
, 8) == -1)
1153 fprintf(LogFile
, "Error %u reading base codeview data in %s\n", errno
, FileName
);
1157 if (lseek(fh
, pxdi
->base
.lfoDir
- 8, SEEK_CUR
) == -1)
1159 fprintf(LogFile
, "Error %u seeking dir codeview data in %s\n", errno
, FileName
);
1163 if (read(fh
, (void *)&numdir
, 2) == -1)
1165 fprintf(LogFile
, "Error %u reading dir codeview data in %s\n", errno
, FileName
);
1169 // Read dir table into buffer
1170 if ((pxdi
->pDirTab
= (SSDIR
*)calloc(numdir
, sizeof(SSDIR
))) == NULL
)
1172 fprintf(LogFile
, "Out of memory!");
1176 if (read(fh
, (void*)pxdi
->pDirTab
, numdir
* sizeof(SSDIR
)) == -1)
1178 fprintf(LogFile
, "Error %u reading codeview dir table from %s\n", errno
, FileName
);
1179 free(pxdi
->pDirTab
);
1186 if (pxdi
->pDirTab
[i
].sst
!= SSTMODULES
)
1193 // point to subsection
1194 lseek(fh
, pxdi
->pDirTab
[i
].lfoStart
+ pxdi
->lfaBase
, SEEK_SET
);
1195 read(fh
, (void *)&pxdi
->ssmod
.csBase
, sizeof(SSMODULE
));
1196 read(fh
, (void *)ModName
, (unsigned)pxdi
->ssmod
.csize
);
1197 ModIndex
= pxdi
->pDirTab
[i
].modindex
;
1198 ModName
[pxdi
->ssmod
.csize
] = '\0';
1200 while (pxdi
->pDirTab
[i
].modindex
== ModIndex
&& i
< numdir
)
1202 // point to subsection
1203 lseek(fh
, pxdi
->pDirTab
[i
].lfoStart
+ pxdi
->lfaBase
, SEEK_SET
);
1204 switch (pxdi
->pDirTab
[i
].sst
)
1208 while (bytesread
< pxdi
->pDirTab
[i
].cb
)
1210 bytesread
+= read(fh
, (void *)&pxdi
->sspub
.offset
, sizeof(pxdi
->sspub
));
1211 bytesread
+= read(fh
, (void *)ename
, (unsigned)pxdi
->sspub
.csize
);
1212 ename
[pxdi
->sspub
.csize
] = '\0';
1213 if ((pxdi
->sspub
.segment
== TrapSeg
) &&
1214 (pxdi
->sspub
.offset
<= TrapOff
) &&
1215 (pxdi
->sspub
.offset
>= NrPublic
))
1217 NrPublic
= pxdi
->sspub
.offset
;
1218 sprintf(pxdi
->szNrPub
, "%s %s (%s) %04hX:%04hX\n",
1219 (pxdi
->sspub
.type
== 1) ? " Abs" : " ", ename
,
1221 pxdi
->sspub
.segment
,
1230 if (TrapSeg
!= pxdi
->ssmod
.csBase
)
1233 read(fh
, (void *)&namelen
, 1);
1234 read(fh
, (void *)ename
, namelen
);
1235 ename
[namelen
] = '\0';
1236 // skip 2 zero bytes
1237 if (pxdi
->pDirTab
[i
].sst
== SSTSRCLINES2
)
1238 read(fh
, (void *)&numlines
, 2);
1239 read(fh
, (void *)&numlines
, 2);
1240 for (j
= 0; j
< numlines
; j
++)
1242 read(fh
, (void *)&line
, 2);
1243 read(fh
, (void *)&offset
, 2);
1244 if (offset
<= TrapOff
&& offset
>= NrLine
)
1247 sprintf(pxdi
->szNrFile
, "% 12.12s ", ename
);
1248 sprintf(pxdi
->szNrLine
, "% 6hu", line
);
1249 /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
1250 * ssmod.csBase,offset,line,ModName,ename); */
1256 } // end while modindex
1257 } // End While i < numdir
1258 free(pxdi
->pDirTab
);
1262 /* ******************************************************************
1264 * PART 2: ANALYZE VARIABLES
1266 ********************************************************************/
1270 * writes a description of a variable type to
1271 * the specified buffer, depending on "type".
1273 *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
1276 static VOID
var_value(void *varptr
, // in: address of the variable on the stack
1277 char *pszBuf
, // out: information
1278 BYTE type
) // in: type; if >= 32, we'll call DosQueryMem
1283 if (DosQueryMem(varptr
, &Size
, &Attr
) != NO_ERROR
)
1285 sprintf(pszBuf
, "type %d, DosQueryMem failed", type
);
1289 if ((Attr
& PAG_READ
) == 0)
1291 sprintf(pszBuf
, "type %d, read-access to value denied", type
);
1296 sprintf(pszBuf
, "%hd", *(signed char*)varptr
);
1298 sprintf(pszBuf
, "%hd", *(signed short*)varptr
);
1300 sprintf(pszBuf
, "%ld", *(signed long*)varptr
);
1302 sprintf(pszBuf
, "%hu", *(BYTE
*) varptr
);
1304 sprintf(pszBuf
, "%hu", *(USHORT
*)varptr
);
1306 sprintf(pszBuf
, "0x%lX (%lu)", *((ULONG
*)varptr
), *((ULONG
*)varptr
));
1308 sprintf(pszBuf
, "%f", *(float*)varptr
);
1310 sprintf(pszBuf
, "%f", *(double*)varptr
);
1311 else if (type
== 10)
1312 sprintf(pszBuf
, "%f", (double)(*(long double*)varptr
));
1313 else if (type
== 16)
1314 sprintf(pszBuf
, "%s", *(char*)varptr
? "TRUE" : "FALSE");
1315 else if (type
== 17)
1316 sprintf(pszBuf
, "%s", *(short*)varptr
? "TRUE" : "FALSE");
1317 else if (type
== 18)
1318 sprintf(pszBuf
, "%s", *(long*)varptr
? "TRUE" : "FALSE");
1319 else if (type
== 20)
1320 sprintf(pszBuf
, "%c", *(char*)varptr
);
1321 else if (type
== 21)
1322 sprintf(pszBuf
, "%hd", (*(short*)varptr
));
1323 else if (type
== 22)
1324 sprintf(pszBuf
, "%ld", *(long*)varptr
);
1325 else if (type
== 23)
1326 sprintf(pszBuf
, "void");
1327 else if (type
>= 32)
1329 sprintf(pszBuf
, "0x%p", (void*)(*(ULONG
*)varptr
));
1330 if (Attr
& PAG_FREE
)
1332 strcat(pszBuf
, " unallocated memory");
1336 if ((Attr
& PAG_COMMIT
) == 0x0U
)
1338 strcat(pszBuf
, " uncommitted");
1340 if ((Attr
& PAG_WRITE
) == 0x0U
)
1342 strcat(pszBuf
, " unwritable");
1344 if ((Attr
& PAG_READ
) == 0x0U
)
1346 strcat(pszBuf
, " unreadable");
1351 sprintf(pszBuf
, "Unknown type %d", type
);
1356 * searches the table of userdef's-
1357 * Return TRUE if found.
1360 static BOOL
search_userdefs(FILE *LogFile
, // in: text log file to write to
1367 pos
< userdef_count
;
1370 if (one_userdef
[pos
].idx
== autovar_def
[var_no
].type_idx
)
1372 if ( (one_userdef
[pos
].type_index
>= 0x80)
1373 // && (one_userdef[pos].type_index <= 0xDA)
1376 static char sszVar3
[500] = "complex";
1377 if (one_userdef
[pos
].type_index
<= 0xDA)
1378 var_value((void*)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1380 one_userdef
[pos
].type_index
- 0x80);
1383 " %- 6ld %- 20.20s %- 33.33s %s (user)\n",
1384 autovar_def
[var_no
].stack_offset
, // stack offset
1385 autovar_def
[var_no
].name
, // identifier
1386 one_userdef
[pos
].name
, // type name
1387 sszVar3
// composed by var_value
1404 static BOOL
search_pointers(FILE *LogFile
, // in: text log file to write to
1409 static BYTE str
[35];
1410 static char sszVar
[500];
1415 ( (pos
< pointer_count
)
1416 && (one_pointer
[pos
].idx
!= autovar_def
[var_no
].type_idx
)
1420 if (pos
< pointer_count
)
1422 if ( (one_pointer
[pos
].type_index
>= 0x80)
1423 && (one_pointer
[pos
].type_index
<= 0xDA)
1426 strcpy(str
, type_name
[one_pointer
[pos
].type_index
- 0x80]);
1428 var_value((void*)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1431 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1432 autovar_def
[var_no
].stack_offset
,
1433 autovar_def
[var_no
].name
,
1440 // If the result isn't a simple type, look for it in the other lists
1442 ( (upos
< userdef_count
)
1443 && (one_userdef
[upos
].idx
!= one_pointer
[pos
].type_index
)
1448 if (upos
< userdef_count
)
1450 strcpy(str
, one_userdef
[upos
].name
);
1452 var_value((void *)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1455 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1456 autovar_def
[var_no
].stack_offset
,
1457 autovar_def
[var_no
].name
,
1464 // if it isn't a userdef, for now give up and just print
1465 // as much as we know
1466 sprintf(str
, "Pointer to type 0x%X", one_pointer
[pos
].type_index
);
1468 var_value((void *)(stackofs
+ autovar_def
[var_no
].stack_offset
),
1471 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1472 autovar_def
[var_no
].stack_offset
,
1473 autovar_def
[var_no
].name
,
1486 *@@ dbgPrintVariables:
1487 * Dumps variables for the specified stack offset
1488 * to the specified log file.
1493 void dbgPrintVariables(FILE *LogFile
, // in: text log file to write to
1497 BOOL AutoVarsFound
= FALSE
;
1499 if (/* 1 || */ func_ofs
== pubfunc_ofs
)
1505 if (AutoVarsFound
== FALSE
)
1507 AutoVarsFound
= TRUE
;
1508 fprintf(LogFile
, " List of auto variables at EBP %p in %s:\n",
1511 fprintf(LogFile
, " Offset Name Type Value \n");
1512 fprintf(LogFile
, " ������ �������������������� ��������������������������������� �����������������\n");
1515 // If it's one of the simple types
1516 if ( (autovar_def
[n
].type_idx
>= 0x80)
1517 && (autovar_def
[n
].type_idx
<= 0xDA)
1520 static char sszVar2
[500];
1522 var_value((void *)(stackofs
+ autovar_def
[n
].stack_offset
),
1524 autovar_def
[n
].type_idx
- 0x80);
1526 fprintf(LogFile
, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
1527 autovar_def
[n
].stack_offset
,
1528 autovar_def
[n
].name
,
1529 type_name
[autovar_def
[n
].type_idx
- 0x80],
1533 { // Complex type, check if we know what it is
1534 if (!search_userdefs(LogFile
, stackofs
, n
))
1536 if (!search_pointers(LogFile
, stackofs
, n
))
1538 fprintf(LogFile
, " %- 6ld %-20.20s 0x%X (unknown)\n",
1539 autovar_def
[n
].stack_offset
,
1540 autovar_def
[n
].name
,
1541 autovar_def
[n
].type_idx
);
1546 /* if (AutoVarsFound == FALSE)
1548 fprintf(LogFile, " No auto variables found in %s.\n", func_name);
1550 fprintf(LogFile
, "\n");
1554 /* ******************************************************************
1556 * PART 3: ANALYZE SYMBOL (.SYM) FILE
1558 ********************************************************************/
1561 *@@ dbgPrintSYMInfo:
1562 * this gets called by dbgPrintStack if dbgPrintDebugInfo
1563 * failed (because no debug code was found) to check if
1564 * maybe a SYM file with the same filename exists and try
1565 * to get the info from there.
1567 * This gets called for every line of the stack
1568 * walk, but only if getting the information from
1569 * the debug code failed, e.g. because no debug code
1570 * was available for an address.
1572 * The file pointer is in the "Source file" column
1573 * every time this gets called.
1577 * Returns 0 if reading the SYM file was successful.
1579 *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
1582 int dbgPrintSYMInfo(FILE *LogFile
, // in: text log file to write to
1583 CHAR
*SymFileName
, // in: SYM file name (can be fully q'fied)
1587 static FILE *SymFile
;
1588 static MAPDEF MapDef
;
1589 static SEGDEF SegDef
;
1590 static SYMDEF32 SymDef32
;
1591 static SYMDEF16 SymDef16
;
1592 static char Buffer
[256];
1593 static int SegNum
, SymNum
, LastVal
;
1594 static unsigned long int SegOffset
,
1595 SymOffset
, SymPtrOffset
;
1598 #ifdef DEBUG_SYMDUMP
1599 fprintf(LogFile
,"Dump of '%s' for object %d\n",SymFileName
,Object
);
1601 SymFile
= fopen(SymFileName
, "rb");
1605 // read in first map definition
1606 fread(&MapDef
, sizeof(MAPDEF
), 1, SymFile
);
1607 #ifdef DEBUG_SYMDUMP
1608 Buffer
[0] = MapDef
.achModName
[0];
1609 fread(&Buffer
[1], 1, MapDef
.cbModName
-1, SymFile
);
1610 Buffer
[MapDef
.cbModName
] = 0x00;
1611 fprintf(LogFile
,"Module name '%s'\n",Buffer
);
1614 SegOffset
= SEGDEFOFFSET(MapDef
);
1615 #ifdef DEBUG_SYMDUMP
1616 fprintf(LogFile
,"SegOffset %0x\n",SegOffset
);
1619 // go thru all segments
1621 SegNum
< MapDef
.cSegs
;
1624 #ifdef DEBUG_SYMDUMP
1625 fprintf(LogFile
,"Scanning segment #%d Offset %08X\n",SegNum
,SegOffset
);
1627 if (fseek(SymFile
, SegOffset
, SEEK_SET
))
1631 // read in segment definition
1632 fread(&SegDef
, sizeof(SEGDEF
), 1, SymFile
);
1633 #ifdef DEBUG_SYMDUMP
1635 if (SegDef
.cbSegName
>0) {
1636 Buffer
[0] = SegDef
.achSegName
[0];
1637 fread(&Buffer
[1], 1, SegDef
.cbSegName
-1, SymFile
);
1638 Buffer
[SegDef
.cbSegName
] = 0x00;
1640 fprintf(LogFile
,"Segment name '%s', number %d, flags %02x\n",Buffer
,SegNum
,SegDef
.bFlags
);
1643 if (SegNum
== Object
)
1645 // stack object found:
1649 // go thru all symbols in this object
1650 #ifdef DEBUG_SYMDUMP
1651 fprintf(LogFile
,"Scanning #%d symbols\n",SegDef
.cSymbols
);
1653 for (SymNum
= 0; SymNum
< SegDef
.cSymbols
; SymNum
++)
1655 SymPtrOffset
=SYMDEFOFFSET(SegOffset
,SegDef
,SymNum
);
1656 fseek(SymFile
,SymPtrOffset
,SEEK_SET
);
1657 fread(&SymOffset
,sizeof(unsigned short int),1,SymFile
);
1658 fseek(SymFile
,SymOffset
+SegOffset
,SEEK_SET
);
1659 if (SegDef
.bFlags
& 0x01)
1662 fread(&SymDef32
, sizeof(SYMDEF32
), 1, SymFile
);
1663 if (SymDef32
.wSymVal
> TrapOffset
)
1667 "between %s + 0x%lX ",
1669 TrapOffset
- LastVal
);
1670 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1671 LINEDEFOFFSET(SegDef)
1673 fprintf(LogFile
, "\n");
1676 LastVal
= SymDef32
.wSymVal
;
1677 Buffer
[0] = SymDef32
.achSymName
[0];
1678 fread(&Buffer
[1], 1, SymDef32
.cbSymName
-1, SymFile
);
1679 Buffer
[SymDef32
.cbSymName
] = 0x00;
1680 #ifdef DEBUG_SYMDUMP
1681 fprintf(LogFile
,"32 Bit Symbol Address %08p <%s> \n",SymDef32
.wSymVal
,Buffer
);
1684 if (SymDef32
.wSymVal
> TrapOffset
)
1686 // symbol found, as above
1691 LastVal
- TrapOffset
);
1692 fprintf(LogFile
, "\n");
1699 fread(&SymDef16
, sizeof(SYMDEF16
), 1, SymFile
);
1700 if (SymDef16
.wSymVal
> TrapOffset
)
1703 "between %s + %lX\n",
1705 TrapOffset
- LastVal
);
1707 LastVal
= SymDef16
.wSymVal
;
1708 Buffer
[0] = SymDef16
.achSymName
[0];
1709 fread(&Buffer
[1], 1, SymDef16
.cbSymName
-1, SymFile
);
1710 Buffer
[SymDef16
.cbSymName
] = 0x00;
1711 if (SymDef16
.wSymVal
> TrapOffset
)
1717 LastVal
- TrapOffset
);
1720 #ifdef DEBUG_SYMDUMP
1721 fprintf(LogFile
,"16 Bit Symbol <%s> Address %p\n",Buffer
,SymDef16
.wSymVal
);
1727 SegOffset
= NEXTSEGDEFOFFSET(SegDef
);
1730 return (0); // no error
1733 /* ******************************************************************
1735 * PART 4: dbgPrintStack
1737 ********************************************************************/
1740 *@@ dbgPrintStackFrame:
1741 * parses and dumps one stack frame.
1742 * Called from excPrintStackFrame.
1744 * This calls dbgPrintDebugInfo and, if
1745 * that fails, dbgPrintSYMInfo.
1747 *@@added V0.9.2 (2000-03-10) [umoeller]
1748 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1749 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1752 BOOL
dbgPrintStackFrame(FILE *LogFile
,
1753 PSZ pszModuleName
, // in: module name (fully q'fied)
1758 // "Source file"... columns
1760 //YD do not use debug info
1761 #define ENABLE_DEBUG_INFO
1762 #ifdef ENABLE_DEBUG_INFO
1763 // first attempt to analyze the debug code
1764 arc
= dbgPrintDebugInfo(LogFile
,
1772 // if no debug code is available, analyze
1773 // the SYM file instead
1774 if (arc
!= NO_ERROR
)
1776 CHAR szSymName
[CCHMAXPATH
];
1777 strcpy(szSymName
, pszModuleName
);
1778 strcpy(szSymName
+ strlen(szSymName
) - 3, "SYM");
1779 arc
= dbgPrintSYMInfo(LogFile
,
1785 // SYM file not found in current directory:
1786 // check the SYM files in the \OS2 directory,
1787 // depending on the OS/2 version level:
1788 CHAR szSymFile2
[CCHMAXPATH
];
1789 PSZ pszFilename
= strrchr(szSymName
, '\\');
1792 PSZ pszVersionDir
= "WARP4";
1795 DosQuerySysInfo(QSV_VERSION_MAJOR
, // 11
1796 QSV_VERSION_MINOR
, // 12
1797 &aulBuf
, sizeof(aulBuf
));
1798 // Warp 3 is reported as 20.30
1799 // Warp 4 is reported as 20.40
1800 // Aurora is reported as 20.45
1802 if (aulBuf
[0] == 20)
1804 if (aulBuf
[1] == 30)
1806 pszVersionDir
= "WARP3";
1807 else if (aulBuf
[1] >= 40)
1808 // Warp 4 or higher:
1809 // (NOTE: Warp 4 FP 13 now returns 45 also,
1810 // but the SYM files are still in the WARP4 directory...)
1811 // V0.9.3 (2000-04-26) [umoeller]
1812 pszVersionDir
= "WARP4";
1817 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1818 doshQueryBootDrive(),
1821 arc
= dbgPrintSYMInfo(LogFile
,
1826 // V0.9.3 (2000-04-26) [umoeller]
1827 if ( (arc
!= 0) // still not found
1828 && (aulBuf
[1] == 45) // and running Aurora or Warp 4 FP13?
1831 // Warp Server for e-Business (aka Warp 4.5):
1832 // we use the SYM files for the UNI kernel,
1833 // I have found no way to find out whether
1834 // we're running on an SMP kernel
1836 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1837 doshQueryBootDrive(),
1840 arc
= dbgPrintSYMInfo(LogFile
,
1848 if (arc
== 2) // file not found
1850 "Cannot find symbol file %s\n",
1854 "Error %lu reading symbol file %s\n",
1859 return (arc
== NO_ERROR
);
1864 * this takes stack data from the TIB and
1865 * context record data structures and tries
1866 * to analyse what the different stack frames
1869 * For each stack frame, this calls dbgPrintDebugInfo,
1870 * and, if that fails, dbgPrintSYMInfo.
1874 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1877 VOID
dbgPrintStack(FILE *LogFile
, // in: text log file to write to
1878 PUSHORT StackBottom
,
1881 PUSHORT ExceptionAddress
)
1883 PUSHORT RetAddr
= 0;
1884 PUSHORT LastEbp
= 0;
1892 static char Name
[CCHMAXPATH
];
1896 BOOL fExceptionAddress
= TRUE
; // Use Exception Addr 1st time thru
1898 // Note: we can't handle stacks bigger than 64K for now...
1899 Sp
= (USHORT
) (((ULONG
) StackBottom
) >> 16);
1903 Ebp
= (PUSHORT
) MAKEULONG(((USHORT
)(ULONG
)Ebp
), Sp
);
1905 fprintf(LogFile
, "\n\nCall stack:\n");
1906 fprintf(LogFile
, " Source Line Nearest\n");
1907 fprintf(LogFile
, " EBP Address Module Obj# File Numbr Public Symbol\n");
1908 fprintf(LogFile
, " �������� ��������- �������� ���� ������������ ����� ������������-\n");
1913 rc
= DosQueryMem((PVOID
) (Ebp
+ 2), &Size
, &Attr
);
1916 fprintf(LogFile
, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG
)Ebp
, rc
);
1919 if (!(Attr
& PAG_COMMIT
))
1921 fprintf(LogFile
, "Invalid EBP %8.8lX (not committed)\n", (ULONG
)Ebp
);
1926 fprintf(LogFile
, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG
)Ebp
);
1930 if (fExceptionAddress
)
1931 RetAddr
= ExceptionAddress
;
1933 RetAddr
= (PUSHORT
) (*((PULONG
) (Ebp
+ 2)));
1935 if (RetAddr
== (PUSHORT
) 0x00000053)
1937 // For some reason there's a "return address" of 0x53 following
1938 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1939 // at the real return address. This has something to do with
1940 // thunking from 32bits to 16bits...
1941 // Serious kludge, and it's probably dependent on versions of C(++)
1942 // runtime or OS, but it works for now!
1944 RetAddr
= (PUSHORT
) (*((PULONG
) (Ebp
+ 2)));
1947 // Get the (possibly) 16bit CS and IP
1948 if (fExceptionAddress
)
1950 Cs
= (USHORT
) (((ULONG
) ExceptionAddress
) >> 16);
1951 Ip
= (USHORT
) (ULONG
) ExceptionAddress
;
1959 // if the return address points to the stack then it's really just
1960 // a pointer to the return address (UGH!).
1961 if ( (USHORT
) (((ULONG
) RetAddr
) >> 16) == Sp
1963 RetAddr
= (PUSHORT
) (*((PULONG
) RetAddr
));
1965 if (Ip
== 0 && *Ebp
== 0)
1967 // End of the stack so these are both shifted by 2 bytes:
1972 // 16bit programs have on the stack:
1974 // where CS may be thunked
1977 // BP IP CS BP CS IP
1978 // 4677 53B5 F7D0 7746 D0F7 B553
1980 // 32bit programs have:
1982 // and you'd have something like this (with SP added) (not
1987 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1989 // So the basic difference is that 32bit programs have a 32bit
1990 // EBP and we can attempt to determine whether we have a 32bit
1991 // EBP by checking to see if its 'selector' is the same as SP.
1992 // Note that this technique limits us to checking stacks < 64K.
1994 // Soooo, if IP (which maps into the same USHORT as the swapped
1995 // stack page in EBP) doesn't point to the stack (i.e. it could
1996 // be a 16bit IP) then see if CS is valid (as is or thunked).
1998 // Note that there's the possibility of a 16bit return address
1999 // that has an offset that's the same as SP so we'll think it's
2000 // a 32bit return address and won't be able to successfully resolve
2004 if (DosSizeSeg(Cs
, &Size
) == NO_ERROR
)
2006 RetAddr
= (USHORT
* _Seg16
) MAKEULONG(Ip
, Cs
);
2009 else if (DosSizeSeg((Cs
<< 3) + 7, &Size
) == NO_ERROR
)
2012 RetAddr
= (USHORT
* _Seg16
) MAKEULONG(Ip
, Cs
);
2023 if (fExceptionAddress
)
2024 fprintf(LogFile
, " Trap -> ");
2026 fprintf(LogFile
, " %8.8lX ", (ULONG
)Ebp
);
2030 fprintf(LogFile
, ":%8.8lX ", (ULONG
)RetAddr
);
2032 fprintf(LogFile
, "%04.04X:%04.04X ", Cs
, Ip
);
2034 // Version check omitted; the following requires
2035 // OS/2 2.10 or later (*UM)
2036 // if (Version[0] >= 20 && Version[1] >= 10)
2038 // Make a 'tick' sound to let the user know we're still alive
2041 Size
= 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
2043 // "Module"/"Object" columns
2044 rc
= DosQueryMem((PVOID
) RetAddr
, &Size
, &Attr
);
2045 if (rc
!= NO_ERROR
|| !(Attr
& PAG_COMMIT
))
2047 fprintf(LogFile
, "Invalid RetAddr: %8.8lX\n", (ULONG
)RetAddr
);
2048 break; // avoid infinite loops
2052 rc
= DosQueryModFromEIP(&hMod
,
2057 if ( (rc
== NO_ERROR
)
2058 // && (ObjNum != -1)
2061 // static char szJunk[_MAX_FNAME];
2062 static char szName
[_MAX_FNAME
];
2064 DosQueryModuleName(hMod
, sizeof(Name
), Name
);
2065 // _splitpath(Name, szJunk, szJunk, szName, szJunk);
2067 // print module and object
2068 fprintf(LogFile
, "%-8s %04lX ", szName
, ObjNum
+ 1);
2070 if (strlen(Name
) > 3)
2072 dbgPrintStackFrame(LogFile
,
2080 "DosQueryModFromEIP failed, returned %lu\n",
2086 && ((*Ebp
+ 1) == 0)
2089 fprintf(LogFile
, "End of call stack\n");
2093 if (!fExceptionAddress
)
2097 Ebp
= (PUSHORT
) MAKEULONG(Bp
, Sp
);
2098 #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2100 Ebp
= (PUSHORT
) *(PULONG
) LastEbp
;
2102 Ebp
= (PUSHORT
) MAKEULONG((*Ebp
), Sp
);
2106 dbgPrintVariables(LogFile
, (ULONG
) Ebp
);
2111 fprintf(LogFile
, "... lost stack chain - new EBP below previous\n");
2116 fExceptionAddress
= FALSE
;
2119 rc
= DosQueryMem((PVOID
) Ebp
, &Size
, &Attr
);
2120 if ((rc
!= NO_ERROR
) || (Size
< 4))
2122 fprintf(LogFile
, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG
)Ebp
);
2127 fprintf(LogFile
, "\n");
2131 *@@ doshQueryBootDrive:
2132 * returns the letter of the boot drive as a
2133 * single (capital) character, which is useful for
2134 * constructing file names using sprintf and such.
2136 *@@changed V0.9.16 (2002-01-13) [umoeller]: optimized
2139 CHAR
doshQueryBootDrive(VOID
)
2141 // this can never change, so query this only once
2142 // V0.9.16 (2002-01-13) [umoeller]
2143 static CHAR cBootDrive
= '\0';
2148 DosQuerySysInfo(QSV_BOOT_DRIVE
, QSV_BOOT_DRIVE
,
2150 sizeof(ulBootDrive
));
2151 cBootDrive
= (CHAR
)ulBootDrive
+ 'A' - 1;
2154 return (cBootDrive
);