merged tag ooo/DEV300_m102
[LibreOffice.git] / sal / osl / os2 / debug.c
blobf2d0f915f37563945abdcec01eb17355ae2fdf06
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
48 * numbering.
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,
58 * Kim Rasmussen,
59 * Marc Fiammante,
60 * John Currier,
61 * Anthony Cruise.
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
77 // as unsigned char
79 #define INCL_DOSPROCESS
80 #define INCL_DOSMODULEMGR
81 #define INCL_DOSMISC
82 #define INCL_DOSERRORS
83 #include <os2.h>
85 #include <stdlib.h>
86 #include <stdio.h>
87 #include <string.h>
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"
95 #pragma hdrstop
97 #include <fcntl.h>
98 #ifdef __EMX__
99 #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
100 #endif
101 #include <sys\stat.h>
102 #include <share.h>
103 #include <io.h>
105 #ifndef DWORD
106 #define DWORD unsigned long
107 #endif
108 #ifndef WORD
109 #define WORD unsigned short
110 #endif
112 #pragma stack16(512)
113 #define HF_STDERR 2
116 *@@category: Helpers\Control program helpers\Exceptions/debugging
117 * See except.c and debug.c.
120 /* ******************************************************************
122 * Global variables
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:
135 ULONG func_ofs;
136 ULONG pubfunc_ofs;
137 //YD 17/07/06 c++ namespace can generate really long
138 //YD names, use a large buffer!
139 char func_name[16*1024];
140 ULONG var_ofs = 0;
142 struct {
143 BYTE name[128];
144 ULONG stack_offset;
145 USHORT type_idx;
146 } autovar_def[1024];
148 #pragma pack(1)
150 BYTE *type_name[] =
152 "8 bit signed ",
153 "16 bit signed ",
154 "32 bit signed ",
155 "Unknown (0x83) ",
156 "8 bit unsigned ",
157 "16 bit unsigned ",
158 "32 bit unsigned ",
159 "Unknown (0x87) ",
160 "32 bit real ",
161 "64 bit real ",
162 "80 bit real ",
163 "Unknown (0x8B) ",
164 "64 bit complex ",
165 "128 bit complex ",
166 "160 bit complex ",
167 "Unknown (0x8F) ",
168 "8 bit boolean ",
169 "16 bit boolean ",
170 "32 bit boolean ",
171 "Unknown (0x93) ",
172 "8 bit character ",
173 "16 bit characters ",
174 "32 bit characters ",
175 "void ",
176 "15 bit unsigned ",
177 "24 bit unsigned ",
178 "31 bit unsigned ",
179 "Unknown (0x9B) ",
180 "Unknown (0x9C) ",
181 "Unknown (0x9D) ",
182 "Unknown (0x9E) ",
183 "Unknown (0x9F) ",
184 "near pointer to 8 bit signed ",
185 "near pointer to 16 bit signed ",
186 "near pointer to 32 bit signed ",
187 "Unknown (0xA3) ",
188 "near pointer to 8 bit unsigned ",
189 "near pointer to 16 bit unsigned ",
190 "near pointer to 32 bit unsigned ",
191 "Unknown (0xA7) ",
192 "near pointer to 32 bit real ",
193 "near pointer to 64 bit real ",
194 "near pointer to 80 bit real ",
195 "Unknown (0xAB) ",
196 "near pointer to 64 bit complex ",
197 "near pointer to 128 bit complex ",
198 "near pointer to 160 bit complex ",
199 "Unknown (0xAF) ",
200 "near pointer to 8 bit boolean ",
201 "near pointer to 16 bit boolean ",
202 "near pointer to 32 bit boolean ",
203 "Unknown (0xB3) ",
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 ",
211 "Unknown (0xBB) ",
212 "Unknown (0xBC) ",
213 "Unknown (0xBD) ",
214 "Unknown (0xBE) ",
215 "Unknown (0xBF) ",
216 "far pointer to 8 bit signed ",
217 "far pointer to 16 bit signed ",
218 "far pointer to 32 bit signed ",
219 "Unknown (0xC3) ",
220 "far pointer to 8 bit unsigned ",
221 "far pointer to 16 bit unsigned ",
222 "far pointer to 32 bit unsigned ",
223 "Unknown (0xC7) ",
224 "far pointer to 32 bit real ",
225 "far pointer to 64 bit real ",
226 "far pointer to 80 bit real ",
227 "Unknown (0xCB) ",
228 "far pointer to 64 bit complex ",
229 "far pointer to 128 bit complex ",
230 "far pointer to 160 bit complex ",
231 "Unknown (0xCF) ",
232 "far pointer to 8 bit boolean ",
233 "far pointer to 16 bit boolean ",
234 "far pointer to 32 bit boolean ",
235 "Unknown (0xD3) ",
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
254 #pragma pack(1)
255 struct _eodbug
257 unsigned short dbug; // 'NB' signature
258 unsigned short ver; // version
259 unsigned long dfaBase; // size of codeview info
260 } G_eodbug;
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
277 } SYMBASE;
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
285 } SSDIR;
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
293 } SSDIR32;
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
304 } SSMODULE;
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
315 } SSMOD32;
317 typedef struct _SSPUBLIC
319 unsigned short offset;
320 unsigned short segment;
321 unsigned short type;
322 BYTE csize;
323 } SSPUBLIC;
325 typedef struct _SSPUBLIC32
327 unsigned long offset;
328 unsigned short segment;
329 unsigned short type;
330 BYTE csize;
331 } SSPUBLIC32;
333 typedef struct _SSLINEENTRY32
335 unsigned short LineNum;
336 unsigned short FileNum;
337 unsigned long Offset;
338 } SSLINEENTRY32;
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;
347 } FIRSTLINEENTRY32;
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
354 } SSFILENUM32;
357 *@@ XDEBUGINFO:
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
374 SYMBASE base;
376 SSDIR *pDirTab;
377 SSDIR32 *pDirTab32;
378 unsigned char *pEntTab;
379 unsigned long lfaBase;
380 SSMOD32 ssmod32;
381 SSPUBLIC32 sspub32;
383 SSMODULE ssmod;
384 SSPUBLIC sspub;
385 } XDEBUGINFO, *PXDEBUGINFO;
388 USHORT _THUNK_FUNCTION (Dos16SizeSeg) ();
389 //APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
390 USHORT DosSizeSeg (USHORT Seg, PULONG16 Size)
392 return ((USHORT)
393 (_THUNK_PROLOG (2+4);
394 _THUNK_SHORT (Seg);
395 _THUNK_FLAT (Size);
396 _THUNK_CALL (Dos16SizeSeg)));
399 #pragma pack()
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
413 * file.
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
432 fprintf(LogFile,
433 "%s%s%s",
434 pxdi->szNrFile,
435 pxdi->szNrLine,
436 pxdi->szNrPub);
440 *@@ dbgPrintDebugInfo:
441 * this is the main entry point into analyzing debug
442 * code.
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.
453 * New with V0.84.
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)
461 APIRET rc = 0;
462 int ModuleFile = 0;
463 static struct exe_hdr OldExeHeader;
464 static struct new_exe NewExeHeader;
466 ULONG ulSegment = Object + 1; // segment no. is object no. + 1
468 XDEBUGINFO xdi;
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)
476 // file found:
477 // read old Exe header
478 if (read(ModuleFile, (void*)&OldExeHeader, 64) == -1L)
480 fprintf(LogFile, "errno %d reading old exe header\n", errno);
481 close(ModuleFile);
482 return 2;
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);
488 close(ModuleFile);
489 return 3;
491 if (read(ModuleFile, (void *)&NewExeHeader, 64) == -1L)
493 fprintf(LogFile, "errno %d reading new exe header\n", errno);
494 close(ModuleFile);
495 return 4;
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,
508 &xdi, // output
509 ModuleFile,
510 ulSegment,
511 TrapOffset,
512 FileName)))
513 WriteDebugInfo(LogFile, &xdi);
515 close(ModuleFile);
517 // rc !=0 try with DBG file
518 if (rc != 0)
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,
525 &xdi,
526 ModuleFile,
527 ulSegment,
528 TrapOffset,
529 FileName)))
530 WriteDebugInfo(LogFile, &xdi);
532 close(ModuleFile);
536 return rc;
538 else
540 if (NE_MAGIC(NewExeHeader) == NEMAGIC)
543 * 16:16 executable:
547 if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader),
548 sizeof(struct new_seg)))
549 == NULL)
551 fprintf(LogFile, "Out of memory!");
552 close(ModuleFile);
553 return -1;
555 if ( lseek(ModuleFile,
556 E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader),
557 SEEK_SET) == -1L)
559 fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName);
560 free(xdi.pseg);
561 close(ModuleFile);
562 return 9;
565 if (read(ModuleFile,
566 (void *)xdi.pseg,
567 NE_CSEG(NewExeHeader) * sizeof(struct new_seg))
568 == -1)
570 fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName);
571 free(xdi.pseg);
572 close(ModuleFile);
573 return 10;
576 if (!(rc = Read16CodeView(LogFile,
577 &xdi,
578 ModuleFile,
579 ulSegment,
580 TrapOffset,
581 FileName)))
582 WriteDebugInfo(LogFile, &xdi);
584 free(xdi.pseg);
585 close(ModuleFile);
587 // rc !=0 try with DBG file
588 if (rc != 0)
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,
596 &xdi,
597 ModuleFile,
598 ulSegment,
599 TrapOffset,
600 FileName)))
601 WriteDebugInfo(LogFile, &xdi);
603 close(ModuleFile);
606 return rc;
608 else
611 * Unknown executable:
615 fprintf(LogFile, "Error, could not find exe signature");
616 close(ModuleFile);
617 return 11;
620 } // end if (ModuleFile != -1)
621 else
623 fprintf(LogFile, "Error %d opening module file %s", errno, FileName);
624 return 1;
625 } // endif
627 // return 0; we never get here
630 char fname[256],
631 ModName[80];
632 char ename[256],
633 dummy[256];
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
643 USHORT idx;
644 USHORT type_index;
645 BYTE name[33];
646 } one_userdef[MAX_USERDEFS];
648 struct one_pointer_rec
650 USHORT idx;
651 USHORT type_index;
652 BYTE type_qual;
653 BYTE name[33];
654 } one_pointer[MAX_POINTERS];
657 * Read32PmDebug:
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
663 PXDEBUGINFO pxdi,
664 int ModuleFile, // in: module file opened with sopen()
665 int TrapSeg,
666 int TrapOff,
667 CHAR *FileName)
669 static unsigned int CurrSymSeg, NrSymbol,
670 /* offset, */ NrPublic,
671 NrFile, NrLine, /* NrEntry */
672 numdir, namelen,
673 numlines /* , line */;
674 static int ModIndex;
675 static int bytesread, i, j;
676 static SSLINEENTRY32 LineEntry;
677 static SSFILENUM32 FileInfo;
678 static FIRSTLINEENTRY32 FirstLine;
679 static BYTE dump_vars = FALSE;
680 static USHORT idx;
681 static BOOL read_types;
682 static LONG lSize;
684 ModIndex = 0;
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);
689 return (18);
692 if (read(ModuleFile,
693 (void *)&G_eodbug, 8)
694 == -1)
696 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
697 return (19);
699 if (G_eodbug.dbug != DBUGSIG)
701 // fprintf(LogFile,"\nNo CodeView information stored.\n");
702 return (100);
705 if ( (pxdi->lfaBase = lseek(ModuleFile,
706 -(LONG)G_eodbug.dfaBase,
707 SEEK_END))
708 == -1L)
710 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
711 return (20);
714 if (read(ModuleFile,
715 (void *)&pxdi->base, 8)
716 == -1)
718 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
719 return (21);
722 if (lseek(ModuleFile,
723 pxdi->base.lfoDir - 8 + 4,
724 SEEK_CUR)
725 == -1)
727 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
728 return (22);
731 if (read(ModuleFile,
732 (void *)&numdir, 4)
733 == -1)
735 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
736 return (23);
739 // Read dir table into buffer
740 if ( (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
741 sizeof(SSDIR32)))
742 == NULL)
744 fprintf(LogFile, "Out of memory!");
745 return (-1);
748 if (read(ModuleFile,
749 (void*)pxdi->pDirTab32,
750 numdir * sizeof(SSDIR32))
751 == -1)
753 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
754 free(pxdi->pDirTab32);
755 return (24);
758 i = 0;
759 while (i < numdir)
761 if (pxdi->pDirTab32[i].sst != SSTMODULES)
763 i++;
764 continue;
767 NrPublic = 0x0;
768 NrSymbol = 0;
769 NrLine = 0x0;
770 NrFile = 0x0;
771 CurrSymSeg = 0;
772 // point to subsection
773 lseek(ModuleFile,
774 pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
775 SEEK_SET);
776 read(ModuleFile,
777 (void*)&pxdi->ssmod32.csBase,
778 sizeof(SSMOD32));
779 read(ModuleFile,
780 (void*)ModName,
781 (unsigned)pxdi->ssmod32.csize);
782 ModIndex = pxdi->pDirTab32[i].modindex;
783 ModName[pxdi->ssmod32.csize] = '\0';
784 i++;
786 read_types = FALSE;
788 while ( (pxdi->pDirTab32[i].modindex == ModIndex)
789 && (i < numdir)
792 // point to subsection
793 lseek(ModuleFile,
794 pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
795 SEEK_SET);
797 switch (pxdi->pDirTab32[i].sst)
799 case SSTPUBLICS:
800 bytesread = 0;
801 while (bytesread < pxdi->pDirTab32[i].cb)
803 bytesread += read(ModuleFile,
804 (void *)&pxdi->sspub32.offset,
805 sizeof(pxdi->sspub32));
806 bytesread += read(ModuleFile,
807 (void*)ename,
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;
816 read_types = TRUE;
817 sprintf(pxdi->szNrPub,
818 "%s %s (%s)\n",
819 (pxdi->sspub32.type == 1)
820 ? " Abs"
821 : " ",
822 ename,
823 ModName
825 // but continue, because there might be a
826 // symbol that comes closer
829 break;
831 // Read symbols, so we can dump the variables on the stack
832 case SSTSYMBOLS:
833 if (TrapSeg != pxdi->ssmod32.csBase)
834 break;
836 bytesread = 0;
837 while (bytesread < pxdi->pDirTab32[i].cb)
839 static USHORT usLength;
840 static USHORT usLengthSym;
841 static BYTE b1,
843 static BYTE bType;
844 // *ptr;
845 static ULONG ofs;
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);
856 if (b1 & 0x80)
858 bytesread += read(ModuleFile, &b2, 1);
859 usLength = ((b1 & 0x7F) << 8) + b2;
861 else
862 usLength = b1;
864 ofs = tell(ModuleFile);
866 bytesread += read(ModuleFile, &bType, 1);
868 switch (bType)
870 case SYM_CHANGESEG:
871 read(ModuleFile, &symseg, sizeof(symseg));
872 CurrSymSeg = symseg.seg_no;
873 break;
875 case SYM_PROC:
876 case SYM_CPPPROC:
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;
883 else
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))
895 dump_vars = TRUE;
896 var_ofs = 0;
897 NrSymbol = symproc.offset;
898 func_ofs = symproc.offset;
900 strcpy(func_name, str);
902 else
904 dump_vars = FALSE;
906 break;
908 case SYM_AUTO:
909 if (!dump_vars)
910 break;
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;
921 var_ofs++;
922 break;
926 bytesread += usLength;
928 lseek(ModuleFile, ofs + usLength, SEEK_SET);
930 break;
932 case SSTTYPES:
933 // if (ModIndex != TrapSeg)
934 if (!read_types)
935 break;
937 bytesread = 0;
938 idx = 0x200;
939 userdef_count = 0;
940 pointer_count = 0;
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;
946 static ULONG ofs;
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);
955 switch (type.type)
957 case TYPE_USERDEF:
958 if (userdef_count >= MAX_USERDEFS)
959 break;
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,
969 str,
970 _min(udef.name_len + 1, 32));
971 one_userdef[userdef_count].name[32] = 0;
972 userdef_count++;
973 break;
975 case TYPE_POINTER:
976 if (pointer_count >= MAX_POINTERS)
977 break;
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,
987 str,
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;
991 pointer_count++;
992 break;
995 ++idx;
997 bytesread += type.length;
999 lseek(ModuleFile, ofs + type.length + 2, SEEK_SET);
1001 break;
1003 case SSTSRCLINES32:
1004 if (TrapSeg != pxdi->ssmod32.csBase)
1005 break;
1007 // read first line
1010 read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine));
1012 if (FirstLine.LineNum != 0)
1014 fprintf(LogFile, "Missing Line table information\n");
1015 break;
1016 } // endif
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)
1032 case 0:
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
1038 <= TrapOff)
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);
1049 break;
1051 case 1:
1052 lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR);
1053 break;
1055 case 2:
1056 lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR);
1057 break;
1059 case 3:
1060 lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR);
1061 break;
1063 case 4:
1064 lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR);
1065 break;
1070 if (NrFile != 0)
1072 // file found:
1073 read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo));
1074 namelen = 0;
1075 for (j = 1; j <= FileInfo.file_count; j++)
1077 namelen = 0;
1078 read(ModuleFile, (void *)&namelen, 1);
1079 read(ModuleFile, (void *)ename, namelen);
1080 if (j == NrFile)
1081 break;
1083 ename[namelen] = '\0';
1084 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
1085 sprintf(pxdi->szNrFile, "%11.11s ", ename);
1087 else
1089 // strcat(szNrLine,"\n"); avoid new line for empty name fill
1090 strcpy(pxdi->szNrFile, "file? ");
1091 } // endif
1092 break;
1093 } // end switch
1095 i++;
1096 } // end while modindex
1097 } // End While i < numdir
1098 free(pxdi->pDirTab32);
1099 return (0);
1103 * Read16CodeView:
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
1109 PXDEBUGINFO pxdi,
1110 int fh,
1111 int TrapSeg,
1112 int TrapOff,
1113 CHAR *FileName)
1115 static unsigned short int offset,
1116 NrPublic, NrLine,
1117 numdir,
1118 namelen, numlines,
1119 line;
1120 static int ModIndex;
1121 static int bytesread, i, j;
1123 ModIndex = 0;
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);
1128 return (18);
1131 if (read(fh, (void *)&G_eodbug, 8) == -1)
1133 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
1134 return (19);
1136 if (G_eodbug.dbug != DBUGSIG)
1138 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1139 return (100);
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);
1145 return (20);
1148 if (read(fh, (void *)&pxdi->base, 8) == -1)
1150 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
1151 return (21);
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);
1157 return (22);
1160 if (read(fh, (void *)&numdir, 2) == -1)
1162 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
1163 return (23);
1166 // Read dir table into buffer
1167 if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
1169 fprintf(LogFile, "Out of memory!");
1170 return (-1);
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);
1177 return (24);
1180 i = 0;
1181 while (i < numdir)
1183 if (pxdi->pDirTab[i].sst != SSTMODULES)
1185 i++;
1186 continue;
1188 NrPublic = 0x0;
1189 NrLine = 0x0;
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';
1196 i++;
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)
1203 case SSTPUBLICS:
1204 bytesread = 0;
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,
1217 ModName, // ()
1218 pxdi->sspub.segment,
1219 pxdi->sspub.offset
1223 break;
1225 case SSTSRCLINES2:
1226 case SSTSRCLINES:
1227 if (TrapSeg != pxdi->ssmod.csBase)
1228 break;
1229 namelen = 0;
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)
1243 NrLine = offset;
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); */
1250 break;
1251 } // end switch
1252 i++;
1253 } // end while modindex
1254 } // End While i < numdir
1255 free(pxdi->pDirTab);
1256 return (0);
1259 /* ******************************************************************
1261 * PART 2: ANALYZE VARIABLES
1263 ********************************************************************/
1266 * var_value:
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
1277 ULONG Size = 1,
1278 Attr = 0;
1280 if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
1282 sprintf(pszBuf, "type %d, DosQueryMem failed", type);
1283 return;
1286 if ((Attr & PAG_READ) == 0)
1288 sprintf(pszBuf, "type %d, read-access to value denied", type);
1289 return;
1292 if (type == 0)
1293 sprintf(pszBuf, "%hd", *(signed char*)varptr);
1294 else if (type == 1)
1295 sprintf(pszBuf, "%hd", *(signed short*)varptr);
1296 else if (type == 2)
1297 sprintf(pszBuf, "%ld", *(signed long*)varptr);
1298 else if (type == 4)
1299 sprintf(pszBuf, "%hu", *(BYTE*) varptr);
1300 else if (type == 5)
1301 sprintf(pszBuf, "%hu", *(USHORT*)varptr);
1302 else if (type == 6)
1303 sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
1304 else if (type == 8)
1305 sprintf(pszBuf, "%f", *(float*)varptr);
1306 else if (type == 9)
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");
1331 else
1333 if ((Attr & PAG_COMMIT) == 0x0U)
1335 strcat(pszBuf, " uncommitted");
1336 } // endif
1337 if ((Attr & PAG_WRITE) == 0x0U)
1339 strcat(pszBuf, " unwritable");
1340 } // endif
1341 if ((Attr & PAG_READ) == 0x0U)
1343 strcat(pszBuf, " unreadable");
1344 } // endif
1345 } // endif
1346 } // endif
1347 else
1348 sprintf(pszBuf, "Unknown type %d", type);
1352 * search_userdefs:
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
1358 ULONG stackofs,
1359 USHORT var_no)
1361 USHORT pos;
1363 for (pos = 0;
1364 pos < userdef_count;
1365 pos++)
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),
1376 sszVar3,
1377 one_userdef[pos].type_index - 0x80);
1379 fprintf(LogFile,
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
1386 return TRUE;
1388 else
1389 return FALSE;
1393 return FALSE;
1397 * search_pointers:
1401 static BOOL search_pointers(FILE *LogFile, // in: text log file to write to
1402 ULONG stackofs,
1403 USHORT var_no)
1405 USHORT pos, upos;
1406 static BYTE str[35];
1407 static char sszVar[500];
1409 // BYTE type_index;
1411 for (pos = 0;
1412 ( (pos < pointer_count)
1413 && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
1415 pos++);
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]);
1424 strcat(str, " *");
1425 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1426 sszVar,
1427 32);
1428 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1429 autovar_def[var_no].stack_offset,
1430 autovar_def[var_no].name,
1431 str,
1432 sszVar);
1433 return TRUE;
1435 else
1437 // If the result isn't a simple type, look for it in the other lists
1438 for (upos = 0;
1439 ( (upos < userdef_count)
1440 && (one_userdef[upos].idx != one_pointer[pos].type_index)
1442 upos++)
1445 if (upos < userdef_count)
1447 strcpy(str, one_userdef[upos].name);
1448 strcat(str, " *");
1449 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1450 sszVar,
1451 32);
1452 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1453 autovar_def[var_no].stack_offset,
1454 autovar_def[var_no].name,
1455 str,
1456 sszVar);
1457 return TRUE;
1459 else
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),
1466 sszVar,
1467 32);
1468 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1469 autovar_def[var_no].stack_offset,
1470 autovar_def[var_no].name,
1471 str,
1472 sszVar);
1474 return TRUE;
1479 return FALSE;
1483 *@@ dbgPrintVariables:
1484 * Dumps variables for the specified stack offset
1485 * to the specified log file.
1487 * New with V0.84.
1490 void dbgPrintVariables(FILE *LogFile, // in: text log file to write to
1491 ULONG stackofs)
1493 USHORT n; // , pos;
1494 BOOL AutoVarsFound = FALSE;
1496 if (/* 1 || */ func_ofs == pubfunc_ofs)
1498 for (n = 0;
1499 n < var_ofs;
1500 n++)
1502 if (AutoVarsFound == FALSE)
1504 AutoVarsFound = TRUE;
1505 fprintf(LogFile, " List of auto variables at EBP %p in %s:\n",
1506 (PVOID)stackofs,
1507 func_name);
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),
1520 sszVar2,
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],
1527 sszVar2);
1529 else
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);
1546 } */
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.
1572 * New with V0.84.
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)
1581 ULONG Object,
1582 ULONG TrapOffset)
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;
1594 // open .SYM file
1595 #ifdef DEBUG_SYMDUMP
1596 fprintf(LogFile,"Dump of '%s' for object %d\n",SymFileName,Object);
1597 #endif
1598 SymFile = fopen(SymFileName, "rb");
1599 if (SymFile == 0)
1600 return (2);
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);
1609 #endif
1611 SegOffset = SEGDEFOFFSET(MapDef);
1612 #ifdef DEBUG_SYMDUMP
1613 fprintf(LogFile,"SegOffset %0x\n",SegOffset);
1614 #endif
1616 // go thru all segments
1617 for (SegNum = 0;
1618 SegNum < MapDef.cSegs;
1619 SegNum++)
1621 #ifdef DEBUG_SYMDUMP
1622 fprintf(LogFile,"Scanning segment #%d Offset %08X\n",SegNum,SegOffset);
1623 #endif
1624 if (fseek(SymFile, SegOffset, SEEK_SET))
1625 // seek error
1626 return (3);
1628 // read in segment definition
1629 fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
1630 #ifdef DEBUG_SYMDUMP
1631 Buffer[0] = 0x00;
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);
1638 #endif
1640 if (SegNum == Object)
1642 // stack object found:
1643 Buffer[0] = 0x00;
1644 LastVal = 0;
1646 // go thru all symbols in this object
1647 #ifdef DEBUG_SYMDUMP
1648 fprintf(LogFile,"Scanning #%d symbols\n",SegDef.cSymbols);
1649 #endif
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)
1658 // 32-bit symbol:
1659 fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
1660 if (SymDef32.wSymVal > TrapOffset)
1662 // symbol found
1663 fprintf(LogFile,
1664 "between %s + 0x%lX ",
1665 Buffer,
1666 TrapOffset - LastVal);
1667 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1668 LINEDEFOFFSET(SegDef)
1669 ); */
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);
1679 #endif
1681 if (SymDef32.wSymVal > TrapOffset)
1683 // symbol found, as above
1684 fprintf(LogFile,
1686 "and %s - 0x%lX ",
1687 Buffer,
1688 LastVal - TrapOffset);
1689 fprintf(LogFile, "\n");
1690 break;
1693 else
1695 // 16-bit symbol:
1696 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
1697 if (SymDef16.wSymVal > TrapOffset)
1699 fprintf(LogFile,
1700 "between %s + %lX\n",
1701 Buffer,
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)
1710 fprintf(LogFile,
1712 "and %s - %lX\n",
1713 Buffer,
1714 LastVal - TrapOffset);
1715 break;
1717 #ifdef DEBUG_SYMDUMP
1718 fprintf(LogFile,"16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal);
1719 #endif
1720 } // endif
1722 break;
1723 } // endif
1724 SegOffset = NEXTSEGDEFOFFSET(SegDef);
1725 } // endwhile
1726 fclose(SymFile);
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)
1751 ULONG ulObject,
1752 ULONG ulOffset)
1754 APIRET arc = 0;
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,
1762 pszModuleName,
1763 ulObject,
1764 ulOffset);
1765 #else
1766 arc = 1;
1767 #endif
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,
1777 szSymName,
1778 ulObject,
1779 ulOffset);
1780 if (arc != 0)
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, '\\');
1787 if (pszFilename)
1789 PSZ pszVersionDir = "WARP4";
1790 ULONG aulBuf[3];
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)
1802 // Warp 3:
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";
1812 pszFilename++;
1813 sprintf(szSymFile2,
1814 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1815 doshQueryBootDrive(),
1816 pszVersionDir,
1817 pszFilename);
1818 arc = dbgPrintSYMInfo(LogFile,
1819 szSymFile2,
1820 ulObject,
1821 ulOffset);
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
1832 sprintf(szSymFile2,
1833 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1834 doshQueryBootDrive(),
1835 "WARP45_U",
1836 pszFilename);
1837 arc = dbgPrintSYMInfo(LogFile,
1838 szSymFile2,
1839 ulObject,
1840 ulOffset);
1845 if (arc == 2) // file not found
1846 fprintf(LogFile,
1847 "Cannot find symbol file %s\n",
1848 szSymName);
1849 else if (arc != 0)
1850 fprintf(LogFile,
1851 "Error %lu reading symbol file %s\n",
1852 arc,
1853 szSymName);
1856 return (arc == NO_ERROR);
1860 *@@ dbgPrintStack:
1861 * this takes stack data from the TIB and
1862 * context record data structures and tries
1863 * to analyse what the different stack frames
1864 * point to.
1866 * For each stack frame, this calls dbgPrintDebugInfo,
1867 * and, if that fails, dbgPrintSYMInfo.
1869 * New with V0.84.
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,
1876 PUSHORT StackTop,
1877 PUSHORT Ebp,
1878 PUSHORT ExceptionAddress)
1880 PUSHORT RetAddr = 0;
1881 PUSHORT LastEbp = 0;
1882 APIRET rc = 0;
1883 ULONG Size = 0,
1884 Attr = 0;
1885 USHORT Cs = 0,
1886 Ip = 0,
1887 // Bp,
1888 Sp = 0;
1889 static char Name[CCHMAXPATH];
1890 HMODULE hMod = 0;
1891 ULONG ObjNum = 0;
1892 ULONG Offset = 0;
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);
1897 // Bp = ;
1899 if (!f32bit)
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");
1909 Size = 10;
1910 rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
1911 if (rc != NO_ERROR)
1913 fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
1914 break;
1916 if (!(Attr & PAG_COMMIT))
1918 fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
1919 break;
1921 if (Size < 10)
1923 fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
1924 break;
1927 if (fExceptionAddress)
1928 RetAddr = ExceptionAddress;
1929 else
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!
1940 Ebp += 22;
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;
1950 else
1952 Cs = *(Ebp + 2);
1953 Ip = *(Ebp + 1);
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:
1965 Cs = *(Ebp + 3);
1966 Ip = *(Ebp + 2);
1969 // 16bit programs have on the stack:
1970 // BP:IP:CS
1971 // where CS may be thunked
1973 // in dump swapped
1974 // BP IP CS BP CS IP
1975 // 4677 53B5 F7D0 7746 D0F7 B553
1977 // 32bit programs have:
1978 // EBP:EIP
1979 // and you'd have something like this (with SP added) (not
1980 // accurate values)
1982 // in dump swapped
1983 // EBP EIP EBP EIP
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
1998 // its details.
1999 if (Ip != Sp)
2001 if (DosSizeSeg(Cs, &Size) == NO_ERROR)
2003 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
2004 f32bit = FALSE;
2006 else if (DosSizeSeg((Cs << 3) + 7, &Size) == NO_ERROR)
2008 Cs = (Cs << 3) + 7;
2009 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
2010 f32bit = FALSE;
2012 else
2013 f32bit = TRUE;
2015 else
2016 f32bit = TRUE;
2019 // "EBP" column
2020 if (fExceptionAddress)
2021 fprintf(LogFile, " Trap -> ");
2022 else
2023 fprintf(LogFile, " %8.8lX ", (ULONG)Ebp);
2025 // "Address" column
2026 if (f32bit)
2027 fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr);
2028 else
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
2036 DosBeep(2000, 10);
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
2047 else
2049 rc = DosQueryModFromEIP(&hMod,
2050 &ObjNum,
2051 sizeof(Name), Name,
2052 &Offset,
2053 (PVOID)RetAddr);
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,
2070 Name,
2071 ObjNum,
2072 Offset);
2075 else
2076 fprintf(LogFile,
2077 "DosQueryModFromEIP failed, returned %lu\n",
2078 rc);
2082 if ( ((*Ebp) == 0)
2083 && ((*Ebp + 1) == 0)
2086 fprintf(LogFile, "End of call stack\n");
2087 break;
2090 if (!fExceptionAddress)
2092 LastEbp = Ebp;
2093 #if 0
2094 Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
2095 #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2096 if (f32bit)
2097 Ebp = (PUSHORT) *(PULONG) LastEbp;
2098 else
2099 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
2100 #endif
2101 if (f32bit)
2103 dbgPrintVariables(LogFile, (ULONG) Ebp);
2104 } // endif
2106 if (Ebp < LastEbp)
2108 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
2109 break;
2112 else
2113 fExceptionAddress = FALSE;
2115 Size = 4;
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);
2120 break;
2122 } while (TRUE);
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';
2142 if (!cBootDrive)
2144 ULONG ulBootDrive;
2145 DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
2146 &ulBootDrive,
2147 sizeof(ulBootDrive));
2148 cBootDrive = (CHAR)ulBootDrive + 'A' - 1;
2151 return (cBootDrive);