summaryrefslogtreecommitdiff
path: root/sal/osl/os2/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/os2/debug.c')
-rw-r--r--sal/osl/os2/debug.c2152
1 files changed, 2152 insertions, 0 deletions
diff --git a/sal/osl/os2/debug.c b/sal/osl/os2/debug.c
new file mode 100644
index 000000000000..f2d0f915f375
--- /dev/null
+++ b/sal/osl/os2/debug.c
@@ -0,0 +1,2152 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+/*
+ *@@sourcefile debug.c:
+ * this file contains debugging functions for the
+ * exception handlers in except.c.
+ *
+ * This code is capable of unwinding the stack from
+ * a given address and trying to get function names
+ * and source line numbers, either from the respective
+ * module's debug code (if present) or from a SYM file,
+ * which is searched for in the directory of the module
+ * or in ?:\OS2\PDPSI\PMDF\WARP4.
+ *
+ * This file incorporates code from the following:
+ * -- Marc Fiammante, John Currier, Kim Rasmussen,
+ * Anthony Cruise (EXCEPT3.ZIP package for a generic
+ * exception handling DLL, available at Hobbes).
+ *
+ * Usage: All OS/2 programs.
+ *
+ * Note: Version numbering in this file relates to XWorkplace version
+ * numbering.
+ *
+ *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
+ *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
+ *
+ *@@header "helpers\debug.h"
+ */
+
+/*
+ * This file Copyright (C) 1992-99 Ulrich M�ller,
+ * Kim Rasmussen,
+ * Marc Fiammante,
+ * John Currier,
+ * Anthony Cruise.
+ * This file is part of the "XWorkplace helpers" source package.
+ *
+ * 2009-06-15 published under LGPL3 with Ulrich M�ller permission.
+ *
+ */
+
+//#define DEBUG_SYMDUMP // enable to dump sym file to log
+
+//YD commented, since we need unsigned char BYTE!
+//#define OS2EMX_PLAIN_CHAR
+//Also gcc char is signed, while most structures requires unsigned data!
+//Raised limits for all fields!
+
+ // this is needed for "os2emx.h"; if this is defined,
+ // emx will define PSZ as _signed_ char, otherwise
+ // as unsigned char
+
+#define INCL_DOSPROCESS
+#define INCL_DOSMODULEMGR
+#define INCL_DOSMISC
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define DONT_REPLACE_MALLOC
+#include "helpers\setup.h" // code generation and debugging options
+
+#include "helpers\debug.h"
+#include "helpers\dosh.h"
+
+#pragma hdrstop
+
+#include <fcntl.h>
+#ifdef __EMX__
+ #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
+#endif
+#include <sys\stat.h>
+#include <share.h>
+#include <io.h>
+
+#ifndef DWORD
+#define DWORD unsigned long
+#endif
+#ifndef WORD
+#define WORD unsigned short
+#endif
+
+#pragma stack16(512)
+#define HF_STDERR 2
+
+/*
+ *@@category: Helpers\Control program helpers\Exceptions/debugging
+ * See except.c and debug.c.
+ */
+
+/* ******************************************************************
+ *
+ * Global variables
+ *
+ ********************************************************************/
+
+// this specifies whether we're dealing with 32-bit code;
+// this gets changed whenever 16-bit count is detected
+static BOOL f32bit = TRUE;
+
+/*
+ * Global variables for Read32PmDebug:
+ *
+ */
+
+ULONG func_ofs;
+ULONG pubfunc_ofs;
+//YD 17/07/06 c++ namespace can generate really long
+//YD names, use a large buffer!
+char func_name[16*1024];
+ULONG var_ofs = 0;
+
+struct {
+ BYTE name[128];
+ ULONG stack_offset;
+ USHORT type_idx;
+} autovar_def[1024];
+
+#pragma pack(1)
+
+BYTE *type_name[] =
+{
+ "8 bit signed ",
+ "16 bit signed ",
+ "32 bit signed ",
+ "Unknown (0x83) ",
+ "8 bit unsigned ",
+ "16 bit unsigned ",
+ "32 bit unsigned ",
+ "Unknown (0x87) ",
+ "32 bit real ",
+ "64 bit real ",
+ "80 bit real ",
+ "Unknown (0x8B) ",
+ "64 bit complex ",
+ "128 bit complex ",
+ "160 bit complex ",
+ "Unknown (0x8F) ",
+ "8 bit boolean ",
+ "16 bit boolean ",
+ "32 bit boolean ",
+ "Unknown (0x93) ",
+ "8 bit character ",
+ "16 bit characters ",
+ "32 bit characters ",
+ "void ",
+ "15 bit unsigned ",
+ "24 bit unsigned ",
+ "31 bit unsigned ",
+ "Unknown (0x9B) ",
+ "Unknown (0x9C) ",
+ "Unknown (0x9D) ",
+ "Unknown (0x9E) ",
+ "Unknown (0x9F) ",
+ "near pointer to 8 bit signed ",
+ "near pointer to 16 bit signed ",
+ "near pointer to 32 bit signed ",
+ "Unknown (0xA3) ",
+ "near pointer to 8 bit unsigned ",
+ "near pointer to 16 bit unsigned ",
+ "near pointer to 32 bit unsigned ",
+ "Unknown (0xA7) ",
+ "near pointer to 32 bit real ",
+ "near pointer to 64 bit real ",
+ "near pointer to 80 bit real ",
+ "Unknown (0xAB) ",
+ "near pointer to 64 bit complex ",
+ "near pointer to 128 bit complex ",
+ "near pointer to 160 bit complex ",
+ "Unknown (0xAF) ",
+ "near pointer to 8 bit boolean ",
+ "near pointer to 16 bit boolean ",
+ "near pointer to 32 bit boolean ",
+ "Unknown (0xB3) ",
+ "near pointer to 8 bit character ",
+ "near pointer to 16 bit characters",
+ "near pointer to 32 bit characters",
+ "near pointer to void ",
+ "near pointer to 15 bit unsigned ",
+ "near pointer to 24 bit unsigned ",
+ "near pointer to 31 bit unsigned ",
+ "Unknown (0xBB) ",
+ "Unknown (0xBC) ",
+ "Unknown (0xBD) ",
+ "Unknown (0xBE) ",
+ "Unknown (0xBF) ",
+ "far pointer to 8 bit signed ",
+ "far pointer to 16 bit signed ",
+ "far pointer to 32 bit signed ",
+ "Unknown (0xC3) ",
+ "far pointer to 8 bit unsigned ",
+ "far pointer to 16 bit unsigned ",
+ "far pointer to 32 bit unsigned ",
+ "Unknown (0xC7) ",
+ "far pointer to 32 bit real ",
+ "far pointer to 64 bit real ",
+ "far pointer to 80 bit real ",
+ "Unknown (0xCB) ",
+ "far pointer to 64 bit complex ",
+ "far pointer to 128 bit complex ",
+ "far pointer to 160 bit complex ",
+ "Unknown (0xCF) ",
+ "far pointer to 8 bit boolean ",
+ "far pointer to 16 bit boolean ",
+ "far pointer to 32 bit boolean ",
+ "Unknown (0xD3) ",
+ "far pointer to 8 bit character ",
+ "far pointer to 16 bit characters ",
+ "far pointer to 32 bit characters ",
+ "far pointer to void ",
+ "far pointer to 15 bit unsigned ",
+ "far pointer to 24 bit unsigned ",
+ "far pointer to 31 bit unsigned ",
+};
+
+// Thanks to John Currier:
+// Do not call 16 bit code in myHandler function to prevent call
+// to __EDCThunkProlog and problems is guard page exception handling
+// Also reduce the stack size to 1K for true 16 bit calls.
+// 16 bit calls thunk will now only occur on fatal exceptions
+#pragma stack16(1024)
+
+// ------------------------------------------------------------------
+// Last 8 bytes of 16:16 file when CODEVIEW debugging info is present
+#pragma pack(1)
+struct _eodbug
+{
+ unsigned short dbug; // 'NB' signature
+ unsigned short ver; // version
+ unsigned long dfaBase; // size of codeview info
+} G_eodbug;
+
+#define DBUGSIG 0x424E
+#define SSTMODULES 0x0101
+#define SSTPUBLICS 0x0102
+#define SSTTYPES 0x0103
+#define SSTSYMBOLS 0x0104
+#define SSTSRCLINES 0x0105
+#define SSTLIBRARIES 0x0106
+#define SSTSRCLINES2 0x0109
+#define SSTSRCLINES32 0x010B
+
+typedef struct _SYMBASE
+{
+ unsigned short dbug; // 'NB' signature
+ unsigned short ver; // version
+ unsigned long lfoDir; // file offset to dir entries
+} SYMBASE;
+
+typedef struct _SSDIR
+{
+ unsigned short sst; // SubSection Type
+ unsigned short modindex; // Module index number
+ unsigned long lfoStart; // Start of section
+ unsigned short cb; // Size of section
+} SSDIR;
+
+typedef struct _SSDIR32
+{
+ unsigned short sst; // SubSection Type
+ unsigned short modindex; // Module index number
+ unsigned long lfoStart; // Start of section
+ unsigned long cb; // Size of section
+} SSDIR32;
+
+typedef struct _SSMODULE
+{
+ unsigned short csBase; // code segment base
+ unsigned short csOff; // code segment offset
+ unsigned short csLen; // code segment length
+ unsigned short ovrNum; // overlay number
+ unsigned short indxSS; // Index into sstLib or 0
+ unsigned short reserved;
+ BYTE csize; // size of prefix string
+} SSMODULE;
+
+typedef struct _SSMOD32
+{
+ unsigned short csBase; // code segment base
+ unsigned long csOff; // code segment offset
+ unsigned long csLen; // code segment length
+ unsigned long ovrNum; // overlay number
+ unsigned short indxSS; // Index into sstLib or 0
+ unsigned long reserved;
+ BYTE csize; // size of prefix string
+} SSMOD32;
+
+typedef struct _SSPUBLIC
+{
+ unsigned short offset;
+ unsigned short segment;
+ unsigned short type;
+ BYTE csize;
+} SSPUBLIC;
+
+typedef struct _SSPUBLIC32
+{
+ unsigned long offset;
+ unsigned short segment;
+ unsigned short type;
+ BYTE csize;
+} SSPUBLIC32;
+
+typedef struct _SSLINEENTRY32
+{
+ unsigned short LineNum;
+ unsigned short FileNum;
+ unsigned long Offset;
+} SSLINEENTRY32;
+
+typedef struct _FIRSTLINEENTRY32
+{
+ unsigned short LineNum;
+ unsigned char entry_type;
+ unsigned char reserved;
+ unsigned short numlines;
+ unsigned short segnum;
+} FIRSTLINEENTRY32;
+
+typedef struct _SSFILENUM32
+{
+ unsigned long first_displayable; // Not used
+ unsigned long number_displayable; // Not used
+ unsigned long file_count; // number of source files
+} SSFILENUM32;
+
+/*
+ *@@ XDEBUGINFO:
+ * buffers for Read... funcs.
+ *
+ *@@added V0.9.4 (2000-06-15) [umoeller]
+ */
+
+typedef struct _XDEBUGINFO
+{
+ char szNrFile[300]; // receives source file
+ char szNrLine[300]; // receives line number
+ //YD 17/07/06 c++ namespace can generate really long
+ //YD names, use a large buffer!
+ char szNrPub[16*1024]; // receives function name
+
+ struct new_seg *pseg;
+ struct o32_obj *pobj; // flat .EXE object table entry
+
+ SYMBASE base;
+
+ SSDIR *pDirTab;
+ SSDIR32 *pDirTab32;
+ unsigned char *pEntTab;
+ unsigned long lfaBase;
+ SSMOD32 ssmod32;
+ SSPUBLIC32 sspub32;
+
+ SSMODULE ssmod;
+ SSPUBLIC sspub;
+} XDEBUGINFO, *PXDEBUGINFO;
+
+
+USHORT _THUNK_FUNCTION (Dos16SizeSeg) ();
+//APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
+USHORT DosSizeSeg (USHORT Seg, PULONG16 Size)
+{
+ return ((USHORT)
+ (_THUNK_PROLOG (2+4);
+ _THUNK_SHORT (Seg);
+ _THUNK_FLAT (Size);
+ _THUNK_CALL (Dos16SizeSeg)));
+}
+
+#pragma pack()
+
+/* ******************************************************************
+ *
+ * PART 1: ANALYZE DEBUG CODE
+ *
+ ********************************************************************/
+
+static int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
+static int Read32PmDebug(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
+
+/*
+ *@@ WriteAddressInfo:
+ * formats and writes a line into the trap log
+ * file.
+ *
+ * This gets called for each line from the
+ * stack dump. At this point, the line in the
+ * trap log already has:
+ *
+ + CS:EIP : 000109FF XMLVIEW :0
+ + ^^^ and we write here
+ * After this call, we have.
+ *
+ + CS:EIP : 000109FF XMLVIEW :0 xxx.c 123 ConfirmCreate__Fv
+ + ^^^ and we write here
+ *
+ *@@added V0.9.12 (2001-05-12) [umoeller]
+ */
+
+static VOID WriteDebugInfo(FILE *LogFile, // in: open log file
+ PXDEBUGINFO pxdi) // in: debug info
+{
+ fprintf(LogFile,
+ "%s%s%s",
+ pxdi->szNrFile,
+ pxdi->szNrLine,
+ pxdi->szNrPub);
+}
+
+/*
+ *@@ dbgPrintDebugInfo:
+ * this is the main entry point into analyzing debug
+ * code.
+ *
+ * This analyzes a given address and tries to find
+ * debug code descriptions for this address. If found,
+ * the information is written to the given log file.
+ *
+ * Gets called from dbgPrintStack.
+ *
+ * This returns NO_ERROR if the could was successfully
+ * analyzed or something != 0 if we failed.
+ *
+ * New with V0.84.
+ */
+
+APIRET dbgPrintDebugInfo(FILE *LogFile, // out: log file to write to
+ CHAR *FileName, // in: EXE/DLL module file name
+ ULONG Object, // in: trapping object (from DosQueryModFromEIP)
+ ULONG TrapOffset) // in: trapping address (from DosQueryModFromEIP)
+{
+ APIRET rc = 0;
+ int ModuleFile = 0;
+ static struct exe_hdr OldExeHeader;
+ static struct new_exe NewExeHeader;
+
+ ULONG ulSegment = Object + 1; // segment no. is object no. + 1
+
+ XDEBUGINFO xdi;
+ memset(&xdi, 0, sizeof(xdi));
+
+ // open the module file for reading to analyze the code
+ ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
+
+ if (ModuleFile != -1)
+ {
+ // file found:
+ // read old Exe header
+ if (read(ModuleFile, (void*)&OldExeHeader, 64) == -1L)
+ {
+ fprintf(LogFile, "errno %d reading old exe header\n", errno);
+ close(ModuleFile);
+ return 2;
+ }
+ // seek to new Exe header
+ if (lseek(ModuleFile, (long)E_LFANEW(OldExeHeader), SEEK_SET) == -1L)
+ {
+ fprintf(LogFile, "errno %d seeking to new exe header\n", errno);
+ close(ModuleFile);
+ return 3;
+ }
+ if (read(ModuleFile, (void *)&NewExeHeader, 64) == -1L)
+ {
+ fprintf(LogFile, "errno %d reading new exe header\n", errno);
+ close(ModuleFile);
+ return 4;
+ }
+
+ // check EXE signature
+ if (NE_MAGIC(NewExeHeader) == E32MAGIC)
+ {
+ /*
+ * flat 32 executable:
+ *
+ */
+
+ // do analysis for 32-bit code
+ if (!(rc = Read32PmDebug(LogFile,
+ &xdi, // output
+ ModuleFile,
+ ulSegment,
+ TrapOffset,
+ FileName)))
+ WriteDebugInfo(LogFile, &xdi);
+
+ close(ModuleFile);
+
+ // rc !=0 try with DBG file
+ if (rc != 0)
+ {
+ strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name
+ ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
+ if (ModuleFile != -1)
+ {
+ if (!(rc = Read32PmDebug(LogFile,
+ &xdi,
+ ModuleFile,
+ ulSegment,
+ TrapOffset,
+ FileName)))
+ WriteDebugInfo(LogFile, &xdi);
+
+ close(ModuleFile);
+ }
+ }
+
+ return rc;
+ }
+ else
+ {
+ if (NE_MAGIC(NewExeHeader) == NEMAGIC)
+ {
+ /*
+ * 16:16 executable:
+ *
+ */
+
+ if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader),
+ sizeof(struct new_seg)))
+ == NULL)
+ {
+ fprintf(LogFile, "Out of memory!");
+ close(ModuleFile);
+ return -1;
+ }
+ if ( lseek(ModuleFile,
+ E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader),
+ SEEK_SET) == -1L)
+ {
+ fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName);
+ free(xdi.pseg);
+ close(ModuleFile);
+ return 9;
+ }
+
+ if (read(ModuleFile,
+ (void *)xdi.pseg,
+ NE_CSEG(NewExeHeader) * sizeof(struct new_seg))
+ == -1)
+ {
+ fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName);
+ free(xdi.pseg);
+ close(ModuleFile);
+ return 10;
+ }
+
+ if (!(rc = Read16CodeView(LogFile,
+ &xdi,
+ ModuleFile,
+ ulSegment,
+ TrapOffset,
+ FileName)))
+ WriteDebugInfo(LogFile, &xdi);
+
+ free(xdi.pseg);
+ close(ModuleFile);
+
+ // rc !=0 try with DBG file
+ if (rc != 0)
+ {
+ strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name
+ ModuleFile = sopen(FileName,
+ O_RDONLY | O_BINARY, SH_DENYNO);
+ if (ModuleFile != -1)
+ {
+ if (!(rc = Read16CodeView(LogFile,
+ &xdi,
+ ModuleFile,
+ ulSegment,
+ TrapOffset,
+ FileName)))
+ WriteDebugInfo(LogFile, &xdi);
+
+ close(ModuleFile);
+ }
+ }
+ return rc;
+ }
+ else
+ {
+ /*
+ * Unknown executable:
+ *
+ */
+
+ fprintf(LogFile, "Error, could not find exe signature");
+ close(ModuleFile);
+ return 11;
+ }
+ }
+ } // end if (ModuleFile != -1)
+ else
+ {
+ fprintf(LogFile, "Error %d opening module file %s", errno, FileName);
+ return 1;
+ } // endif
+
+ // return 0; we never get here
+}
+
+char fname[256],
+ ModName[80];
+char ename[256],
+ dummy[256];
+
+#define MAX_USERDEFS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
+#define MAX_POINTERS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
+
+USHORT userdef_count;
+USHORT pointer_count;
+
+struct one_userdef_rec
+{
+ USHORT idx;
+ USHORT type_index;
+ BYTE name[33];
+} one_userdef[MAX_USERDEFS];
+
+struct one_pointer_rec
+{
+ USHORT idx;
+ USHORT type_index;
+ BYTE type_qual;
+ BYTE name[33];
+} one_pointer[MAX_POINTERS];
+
+/*
+ * Read32PmDebug:
+ * parses 32-bit debug code.
+ * Called from dbgPrintDebugInfo for 32-bit modules.
+ */
+
+static int Read32PmDebug(FILE *LogFile, // in: text log file to write to
+ PXDEBUGINFO pxdi,
+ int ModuleFile, // in: module file opened with sopen()
+ int TrapSeg,
+ int TrapOff,
+ CHAR *FileName)
+{
+ static unsigned int CurrSymSeg, NrSymbol,
+ /* offset, */ NrPublic,
+ NrFile, NrLine, /* NrEntry */
+ numdir, namelen,
+ numlines /* , line */;
+ static int ModIndex;
+ static int bytesread, i, j;
+ static SSLINEENTRY32 LineEntry;
+ static SSFILENUM32 FileInfo;
+ static FIRSTLINEENTRY32 FirstLine;
+ static BYTE dump_vars = FALSE;
+ static USHORT idx;
+ static BOOL read_types;
+ static LONG lSize;
+
+ ModIndex = 0;
+ // See if any CODEVIEW info
+ if (lseek(ModuleFile, -8L, SEEK_END) == -1)
+ {
+ fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
+ return (18);
+ }
+
+ if (read(ModuleFile,
+ (void *)&G_eodbug, 8)
+ == -1)
+ {
+ fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
+ return (19);
+ }
+ if (G_eodbug.dbug != DBUGSIG)
+ {
+ // fprintf(LogFile,"\nNo CodeView information stored.\n");
+ return (100);
+ }
+
+ if ( (pxdi->lfaBase = lseek(ModuleFile,
+ -(LONG)G_eodbug.dfaBase,
+ SEEK_END))
+ == -1L)
+ {
+ fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
+ return (20);
+ }
+
+ if (read(ModuleFile,
+ (void *)&pxdi->base, 8)
+ == -1)
+ {
+ fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
+ return (21);
+ }
+
+ if (lseek(ModuleFile,
+ pxdi->base.lfoDir - 8 + 4,
+ SEEK_CUR)
+ == -1)
+ {
+ fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
+ return (22);
+ }
+
+ if (read(ModuleFile,
+ (void *)&numdir, 4)
+ == -1)
+ {
+ fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
+ return (23);
+ }
+
+ // Read dir table into buffer
+ if ( (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
+ sizeof(SSDIR32)))
+ == NULL)
+ {
+ fprintf(LogFile, "Out of memory!");
+ return (-1);
+ }
+
+ if (read(ModuleFile,
+ (void*)pxdi->pDirTab32,
+ numdir * sizeof(SSDIR32))
+ == -1)
+ {
+ fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
+ free(pxdi->pDirTab32);
+ return (24);
+ }
+
+ i = 0;
+ while (i < numdir)
+ {
+ if (pxdi->pDirTab32[i].sst != SSTMODULES)
+ {
+ i++;
+ continue;
+ }
+
+ NrPublic = 0x0;
+ NrSymbol = 0;
+ NrLine = 0x0;
+ NrFile = 0x0;
+ CurrSymSeg = 0;
+ // point to subsection
+ lseek(ModuleFile,
+ pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
+ SEEK_SET);
+ read(ModuleFile,
+ (void*)&pxdi->ssmod32.csBase,
+ sizeof(SSMOD32));
+ read(ModuleFile,
+ (void*)ModName,
+ (unsigned)pxdi->ssmod32.csize);
+ ModIndex = pxdi->pDirTab32[i].modindex;
+ ModName[pxdi->ssmod32.csize] = '\0';
+ i++;
+
+ read_types = FALSE;
+
+ while ( (pxdi->pDirTab32[i].modindex == ModIndex)
+ && (i < numdir)
+ )
+ {
+ // point to subsection
+ lseek(ModuleFile,
+ pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
+ SEEK_SET);
+
+ switch (pxdi->pDirTab32[i].sst)
+ {
+ case SSTPUBLICS:
+ bytesread = 0;
+ while (bytesread < pxdi->pDirTab32[i].cb)
+ {
+ bytesread += read(ModuleFile,
+ (void *)&pxdi->sspub32.offset,
+ sizeof(pxdi->sspub32));
+ bytesread += read(ModuleFile,
+ (void*)ename,
+ (unsigned)pxdi->sspub32.csize);
+ ename[pxdi->sspub32.csize] = '\0';
+ if ( (pxdi->sspub32.segment == TrapSeg)
+ && (pxdi->sspub32.offset <= TrapOff)
+ && (pxdi->sspub32.offset >= NrPublic)
+ )
+ {
+ NrPublic = pubfunc_ofs = pxdi->sspub32.offset;
+ read_types = TRUE;
+ sprintf(pxdi->szNrPub,
+ "%s %s (%s)\n",
+ (pxdi->sspub32.type == 1)
+ ? " Abs"
+ : " ",
+ ename,
+ ModName
+ );
+ // but continue, because there might be a
+ // symbol that comes closer
+ }
+ }
+ break;
+
+ // Read symbols, so we can dump the variables on the stack
+ case SSTSYMBOLS:
+ if (TrapSeg != pxdi->ssmod32.csBase)
+ break;
+
+ bytesread = 0;
+ while (bytesread < pxdi->pDirTab32[i].cb)
+ {
+ static USHORT usLength;
+ static USHORT usLengthSym;
+ static BYTE b1,
+ b2;
+ static BYTE bType;
+ // *ptr;
+ static ULONG ofs;
+ // static ULONG last_addr = 0;
+ //YD 17/07/06 c++ namespace can generate really long
+ //YD names, use a large buffer!
+ static BYTE str[16*1024];
+ static struct symseg_rec symseg;
+ static struct symauto_rec symauto;
+ static struct symproc_rec symproc;
+
+ // Read the length of this subentry
+ bytesread += read(ModuleFile, &b1, 1);
+ if (b1 & 0x80)
+ {
+ bytesread += read(ModuleFile, &b2, 1);
+ usLength = ((b1 & 0x7F) << 8) + b2;
+ }
+ else
+ usLength = b1;
+
+ ofs = tell(ModuleFile);
+
+ bytesread += read(ModuleFile, &bType, 1);
+
+ switch (bType)
+ {
+ case SYM_CHANGESEG:
+ read(ModuleFile, &symseg, sizeof(symseg));
+ CurrSymSeg = symseg.seg_no;
+ break;
+
+ case SYM_PROC:
+ case SYM_CPPPROC:
+ read(ModuleFile, &symproc, sizeof(symproc));
+ if (symproc.name_len & 0x80)
+ {
+ read(ModuleFile, &b2, 1);
+ usLengthSym = ((symproc.name_len & 0x7F) << 8) + b2;
+ }
+ else
+ {
+ usLengthSym = symproc.name_len;
+ }
+ read(ModuleFile, str, usLengthSym);
+ str[usLengthSym] = 0;
+
+ if ((CurrSymSeg == TrapSeg) &&
+ (symproc.offset <= TrapOff) &&
+ (symproc.offset >= NrSymbol))
+ {
+
+ dump_vars = TRUE;
+ var_ofs = 0;
+ NrSymbol = symproc.offset;
+ func_ofs = symproc.offset;
+
+ strcpy(func_name, str);
+ }
+ else
+ {
+ dump_vars = FALSE;
+ }
+ break;
+
+ case SYM_AUTO:
+ if (!dump_vars)
+ break;
+
+ read(ModuleFile, &symauto, sizeof(symauto));
+ read(ModuleFile, str, symauto.name_len);
+ if (symauto.name_len==0x80)
+ printf("symauto.name_len==0x80\n");
+ str[symauto.name_len] = 0;
+
+ strcpy(autovar_def[var_ofs].name, str);
+ autovar_def[var_ofs].stack_offset = symauto.stack_offset;
+ autovar_def[var_ofs].type_idx = symauto.type_idx;
+ var_ofs++;
+ break;
+
+ }
+
+ bytesread += usLength;
+
+ lseek(ModuleFile, ofs + usLength, SEEK_SET);
+ }
+ break;
+
+ case SSTTYPES:
+ // if (ModIndex != TrapSeg)
+ if (!read_types)
+ break;
+
+ bytesread = 0;
+ idx = 0x200;
+ userdef_count = 0;
+ pointer_count = 0;
+ while (bytesread < pxdi->pDirTab32[i].cb)
+ {
+ static struct type_rec type;
+ static struct type_userdefrec udef;
+ static struct type_pointerrec point;
+ static ULONG ofs;
+ static BYTE str[256];
+
+ // Read the length of this subentry
+ ofs = tell(ModuleFile);
+
+ read(ModuleFile, &type, sizeof(type));
+ bytesread += sizeof(type);
+
+ switch (type.type)
+ {
+ case TYPE_USERDEF:
+ if (userdef_count >= MAX_USERDEFS)
+ break;
+
+ read(ModuleFile, &udef, sizeof(udef));
+ read(ModuleFile, str, udef.name_len);
+ str[udef.name_len] = 0;
+
+ // Insert userdef in table
+ one_userdef[userdef_count].idx = idx;
+ one_userdef[userdef_count].type_index = udef.type_index;
+ memcpy(one_userdef[userdef_count].name,
+ str,
+ _min(udef.name_len + 1, 32));
+ one_userdef[userdef_count].name[32] = 0;
+ userdef_count++;
+ break;
+
+ case TYPE_POINTER:
+ if (pointer_count >= MAX_POINTERS)
+ break;
+
+ read(ModuleFile, &point, sizeof(point));
+ read(ModuleFile, str, point.name_len);
+ str[point.name_len] = 0;
+
+ // Insert userdef in table
+ one_pointer[pointer_count].idx = idx;
+ one_pointer[pointer_count].type_index = point.type_index;
+ memcpy(one_pointer[pointer_count].name,
+ str,
+ _min(point.name_len + 1, 32));
+ one_pointer[pointer_count].name[32] = 0;
+ one_pointer[pointer_count].type_qual = type.type_qual;
+ pointer_count++;
+ break;
+ }
+
+ ++idx;
+
+ bytesread += type.length;
+
+ lseek(ModuleFile, ofs + type.length + 2, SEEK_SET);
+ }
+ break;
+
+ case SSTSRCLINES32:
+ if (TrapSeg != pxdi->ssmod32.csBase)
+ break;
+
+ // read first line
+ do
+ {
+ read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine));
+
+ if (FirstLine.LineNum != 0)
+ {
+ fprintf(LogFile, "Missing Line table information\n");
+ break;
+ } // endif
+ numlines = FirstLine.numlines;
+ // Other type of data skip 4 more bytes
+ if (FirstLine.entry_type < 4)
+ {
+ read(ModuleFile, (void *)&lSize, 4);
+ if (FirstLine.entry_type == 3)
+ lseek(ModuleFile, lSize, SEEK_CUR);
+ }
+ }
+ while (FirstLine.entry_type == 3);
+
+ for (j = 0; j < numlines; j++)
+ {
+ switch (FirstLine.entry_type)
+ {
+ case 0:
+ read(ModuleFile, (void *)&LineEntry, sizeof(LineEntry));
+ // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
+ // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
+ if ( (LineEntry.LineNum)
+ && (LineEntry.Offset + pxdi->ssmod32.csOff
+ <= TrapOff)
+ && (LineEntry.Offset + pxdi->ssmod32.csOff >= NrLine)
+ )
+ {
+ NrLine = LineEntry.Offset;
+ NrFile = LineEntry.FileNum;
+ /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ",
+ * ssmod32.csBase,LineEntry.Offset,
+ * LineEntry.LineNum); */
+ sprintf(pxdi->szNrLine, "% 6hu", LineEntry.LineNum);
+ }
+ break;
+
+ case 1:
+ lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR);
+ break;
+
+ case 2:
+ lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR);
+ break;
+
+ case 3:
+ lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR);
+ break;
+
+ case 4:
+ lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR);
+ break;
+
+ }
+ }
+
+ if (NrFile != 0)
+ {
+ // file found:
+ read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo));
+ namelen = 0;
+ for (j = 1; j <= FileInfo.file_count; j++)
+ {
+ namelen = 0;
+ read(ModuleFile, (void *)&namelen, 1);
+ read(ModuleFile, (void *)ename, namelen);
+ if (j == NrFile)
+ break;
+ }
+ ename[namelen] = '\0';
+ // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
+ sprintf(pxdi->szNrFile, "%11.11s ", ename);
+ }
+ else
+ {
+ // strcat(szNrLine,"\n"); avoid new line for empty name fill
+ strcpy(pxdi->szNrFile, "file? ");
+ } // endif
+ break;
+ } // end switch
+
+ i++;
+ } // end while modindex
+ } // End While i < numdir
+ free(pxdi->pDirTab32);
+ return (0);
+}
+
+/*
+ * Read16CodeView:
+ * parses 16-bit debug code.
+ * Called from dbgPrintDebugInfo for 16-bit modules.
+ */
+
+static int Read16CodeView(FILE *LogFile, // in: text log file to write to
+ PXDEBUGINFO pxdi,
+ int fh,
+ int TrapSeg,
+ int TrapOff,
+ CHAR *FileName)
+{
+ static unsigned short int offset,
+ NrPublic, NrLine,
+ numdir,
+ namelen, numlines,
+ line;
+ static int ModIndex;
+ static int bytesread, i, j;
+
+ ModIndex = 0;
+ // See if any CODEVIEW info
+ if (lseek(fh, -8L, SEEK_END) == -1)
+ {
+ fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
+ return (18);
+ }
+
+ if (read(fh, (void *)&G_eodbug, 8) == -1)
+ {
+ fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
+ return (19);
+ }
+ if (G_eodbug.dbug != DBUGSIG)
+ {
+ // fprintf(LogFile,"\nNo CodeView information stored.\n");
+ return (100);
+ }
+
+ if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
+ {
+ fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
+ return (20);
+ }
+
+ if (read(fh, (void *)&pxdi->base, 8) == -1)
+ {
+ fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
+ return (21);
+ }
+
+ if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1)
+ {
+ fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
+ return (22);
+ }
+
+ if (read(fh, (void *)&numdir, 2) == -1)
+ {
+ fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
+ return (23);
+ }
+
+ // Read dir table into buffer
+ if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
+ {
+ fprintf(LogFile, "Out of memory!");
+ return (-1);
+ }
+
+ if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1)
+ {
+ fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
+ free(pxdi->pDirTab);
+ return (24);
+ }
+
+ i = 0;
+ while (i < numdir)
+ {
+ if (pxdi->pDirTab[i].sst != SSTMODULES)
+ {
+ i++;
+ continue;
+ }
+ NrPublic = 0x0;
+ NrLine = 0x0;
+ // point to subsection
+ lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
+ read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE));
+ read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize);
+ ModIndex = pxdi->pDirTab[i].modindex;
+ ModName[pxdi->ssmod.csize] = '\0';
+ i++;
+ while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir)
+ {
+ // point to subsection
+ lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
+ switch (pxdi->pDirTab[i].sst)
+ {
+ case SSTPUBLICS:
+ bytesread = 0;
+ while (bytesread < pxdi->pDirTab[i].cb)
+ {
+ bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub));
+ bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize);
+ ename[pxdi->sspub.csize] = '\0';
+ if ((pxdi->sspub.segment == TrapSeg) &&
+ (pxdi->sspub.offset <= TrapOff) &&
+ (pxdi->sspub.offset >= NrPublic))
+ {
+ NrPublic = pxdi->sspub.offset;
+ sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n",
+ (pxdi->sspub.type == 1) ? " Abs" : " ", ename,
+ ModName, // ()
+ pxdi->sspub.segment,
+ pxdi->sspub.offset
+ );
+ }
+ }
+ break;
+
+ case SSTSRCLINES2:
+ case SSTSRCLINES:
+ if (TrapSeg != pxdi->ssmod.csBase)
+ break;
+ namelen = 0;
+ read(fh, (void *)&namelen, 1);
+ read(fh, (void *)ename, namelen);
+ ename[namelen] = '\0';
+ // skip 2 zero bytes
+ if (pxdi->pDirTab[i].sst == SSTSRCLINES2)
+ read(fh, (void *)&numlines, 2);
+ read(fh, (void *)&numlines, 2);
+ for (j = 0; j < numlines; j++)
+ {
+ read(fh, (void *)&line, 2);
+ read(fh, (void *)&offset, 2);
+ if (offset <= TrapOff && offset >= NrLine)
+ {
+ NrLine = offset;
+ sprintf(pxdi->szNrFile, "% 12.12s ", ename);
+ sprintf(pxdi->szNrLine, "% 6hu", line);
+ /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
+ * ssmod.csBase,offset,line,ModName,ename); */
+ }
+ }
+ break;
+ } // end switch
+ i++;
+ } // end while modindex
+ } // End While i < numdir
+ free(pxdi->pDirTab);
+ return (0);
+}
+
+/* ******************************************************************
+ *
+ * PART 2: ANALYZE VARIABLES
+ *
+ ********************************************************************/
+
+/*
+ * var_value:
+ * writes a description of a variable type to
+ * the specified buffer, depending on "type".
+ *
+ *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
+ */
+
+static VOID var_value(void *varptr, // in: address of the variable on the stack
+ char *pszBuf, // out: information
+ BYTE type) // in: type; if >= 32, we'll call DosQueryMem
+{
+ ULONG Size = 1,
+ Attr = 0;
+
+ if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
+ {
+ sprintf(pszBuf, "type %d, DosQueryMem failed", type);
+ return;
+ }
+
+ if ((Attr & PAG_READ) == 0)
+ {
+ sprintf(pszBuf, "type %d, read-access to value denied", type);
+ return;
+ }
+
+ if (type == 0)
+ sprintf(pszBuf, "%hd", *(signed char*)varptr);
+ else if (type == 1)
+ sprintf(pszBuf, "%hd", *(signed short*)varptr);
+ else if (type == 2)
+ sprintf(pszBuf, "%ld", *(signed long*)varptr);
+ else if (type == 4)
+ sprintf(pszBuf, "%hu", *(BYTE*) varptr);
+ else if (type == 5)
+ sprintf(pszBuf, "%hu", *(USHORT*)varptr);
+ else if (type == 6)
+ sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
+ else if (type == 8)
+ sprintf(pszBuf, "%f", *(float*)varptr);
+ else if (type == 9)
+ sprintf(pszBuf, "%f", *(double*)varptr);
+ else if (type == 10)
+ sprintf(pszBuf, "%f", (double)(*(long double*)varptr));
+ else if (type == 16)
+ sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
+ else if (type == 17)
+ sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE");
+ else if (type == 18)
+ sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE");
+ else if (type == 20)
+ sprintf(pszBuf, "%c", *(char*)varptr);
+ else if (type == 21)
+ sprintf(pszBuf, "%hd", (*(short*)varptr));
+ else if (type == 22)
+ sprintf(pszBuf, "%ld", *(long*)varptr);
+ else if (type == 23)
+ sprintf(pszBuf, "void");
+ else if (type >= 32)
+ {
+ sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr));
+ if (Attr & PAG_FREE)
+ {
+ strcat(pszBuf, " unallocated memory");
+ }
+ else
+ {
+ if ((Attr & PAG_COMMIT) == 0x0U)
+ {
+ strcat(pszBuf, " uncommitted");
+ } // endif
+ if ((Attr & PAG_WRITE) == 0x0U)
+ {
+ strcat(pszBuf, " unwritable");
+ } // endif
+ if ((Attr & PAG_READ) == 0x0U)
+ {
+ strcat(pszBuf, " unreadable");
+ } // endif
+ } // endif
+ } // endif
+ else
+ sprintf(pszBuf, "Unknown type %d", type);
+}
+
+/*
+ * search_userdefs:
+ * searches the table of userdef's-
+ * Return TRUE if found.
+ */
+
+static BOOL search_userdefs(FILE *LogFile, // in: text log file to write to
+ ULONG stackofs,
+ USHORT var_no)
+{
+ USHORT pos;
+
+ for (pos = 0;
+ pos < userdef_count;
+ pos++)
+ {
+ if (one_userdef[pos].idx == autovar_def[var_no].type_idx)
+ {
+ if ( (one_userdef[pos].type_index >= 0x80)
+ // && (one_userdef[pos].type_index <= 0xDA)
+ )
+ {
+ static char sszVar3[500] = "complex";
+ if (one_userdef[pos].type_index <= 0xDA)
+ var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
+ sszVar3,
+ one_userdef[pos].type_index - 0x80);
+
+ fprintf(LogFile,
+ " %- 6ld %- 20.20s %- 33.33s %s (user)\n",
+ autovar_def[var_no].stack_offset, // stack offset
+ autovar_def[var_no].name, // identifier
+ one_userdef[pos].name, // type name
+ sszVar3 // composed by var_value
+ );
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * search_pointers:
+ *
+ */
+
+static BOOL search_pointers(FILE *LogFile, // in: text log file to write to
+ ULONG stackofs,
+ USHORT var_no)
+{
+ USHORT pos, upos;
+ static BYTE str[35];
+ static char sszVar[500];
+
+ // BYTE type_index;
+
+ for (pos = 0;
+ ( (pos < pointer_count)
+ && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
+ );
+ pos++);
+
+ if (pos < pointer_count)
+ {
+ if ( (one_pointer[pos].type_index >= 0x80)
+ && (one_pointer[pos].type_index <= 0xDA)
+ )
+ {
+ strcpy(str, type_name[one_pointer[pos].type_index - 0x80]);
+ strcat(str, " *");
+ var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
+ sszVar,
+ 32);
+ fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
+ autovar_def[var_no].stack_offset,
+ autovar_def[var_no].name,
+ str,
+ sszVar);
+ return TRUE;
+ }
+ else
+ {
+ // If the result isn't a simple type, look for it in the other lists
+ for (upos = 0;
+ ( (upos < userdef_count)
+ && (one_userdef[upos].idx != one_pointer[pos].type_index)
+ );
+ upos++)
+ ;
+
+ if (upos < userdef_count)
+ {
+ strcpy(str, one_userdef[upos].name);
+ strcat(str, " *");
+ var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
+ sszVar,
+ 32);
+ fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
+ autovar_def[var_no].stack_offset,
+ autovar_def[var_no].name,
+ str,
+ sszVar);
+ return TRUE;
+ }
+ else
+ {
+ // if it isn't a userdef, for now give up and just print
+ // as much as we know
+ sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index);
+
+ var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
+ sszVar,
+ 32);
+ fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
+ autovar_def[var_no].stack_offset,
+ autovar_def[var_no].name,
+ str,
+ sszVar);
+
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ *@@ dbgPrintVariables:
+ * Dumps variables for the specified stack offset
+ * to the specified log file.
+ *
+ * New with V0.84.
+ */
+
+void dbgPrintVariables(FILE *LogFile, // in: text log file to write to
+ ULONG stackofs)
+{
+ USHORT n; // , pos;
+ BOOL AutoVarsFound = FALSE;
+
+ if (/* 1 || */ func_ofs == pubfunc_ofs)
+ {
+ for (n = 0;
+ n < var_ofs;
+ n++)
+ {
+ if (AutoVarsFound == FALSE)
+ {
+ AutoVarsFound = TRUE;
+ fprintf(LogFile, " List of auto variables at EBP %p in %s:\n",
+ (PVOID)stackofs,
+ func_name);
+ fprintf(LogFile, " Offset Name Type Value \n");
+ fprintf(LogFile, " ������ �������������������� ��������������������������������� �����������������\n");
+ }
+
+ // If it's one of the simple types
+ if ( (autovar_def[n].type_idx >= 0x80)
+ && (autovar_def[n].type_idx <= 0xDA)
+ )
+ {
+ static char sszVar2[500];
+
+ var_value((void *)(stackofs + autovar_def[n].stack_offset),
+ sszVar2,
+ autovar_def[n].type_idx - 0x80);
+
+ fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
+ autovar_def[n].stack_offset,
+ autovar_def[n].name,
+ type_name[autovar_def[n].type_idx - 0x80],
+ sszVar2);
+ }
+ else
+ { // Complex type, check if we know what it is
+ if (!search_userdefs(LogFile, stackofs, n))
+ {
+ if (!search_pointers(LogFile, stackofs, n))
+ {
+ fprintf(LogFile, " %- 6ld %-20.20s 0x%X (unknown)\n",
+ autovar_def[n].stack_offset,
+ autovar_def[n].name,
+ autovar_def[n].type_idx);
+ }
+ }
+ }
+ }
+ /* if (AutoVarsFound == FALSE)
+ {
+ fprintf(LogFile, " No auto variables found in %s.\n", func_name);
+ } */
+ fprintf(LogFile, "\n");
+ }
+}
+
+/* ******************************************************************
+ *
+ * PART 3: ANALYZE SYMBOL (.SYM) FILE
+ *
+ ********************************************************************/
+
+/*
+ *@@ dbgPrintSYMInfo:
+ * this gets called by dbgPrintStack if dbgPrintDebugInfo
+ * failed (because no debug code was found) to check if
+ * maybe a SYM file with the same filename exists and try
+ * to get the info from there.
+ *
+ * This gets called for every line of the stack
+ * walk, but only if getting the information from
+ * the debug code failed, e.g. because no debug code
+ * was available for an address.
+ *
+ * The file pointer is in the "Source file" column
+ * every time this gets called.
+ *
+ * New with V0.84.
+ *
+ * Returns 0 if reading the SYM file was successful.
+ *
+ *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
+ */
+
+int dbgPrintSYMInfo(FILE *LogFile, // in: text log file to write to
+ CHAR *SymFileName, // in: SYM file name (can be fully q'fied)
+ ULONG Object,
+ ULONG TrapOffset)
+{
+ static FILE *SymFile;
+ static MAPDEF MapDef;
+ static SEGDEF SegDef;
+ static SYMDEF32 SymDef32;
+ static SYMDEF16 SymDef16;
+ static char Buffer[256];
+ static int SegNum, SymNum, LastVal;
+ static unsigned long int SegOffset,
+ SymOffset, SymPtrOffset;
+
+ // open .SYM file
+#ifdef DEBUG_SYMDUMP
+ fprintf(LogFile,"Dump of '%s' for object %d\n",SymFileName,Object);
+#endif
+ SymFile = fopen(SymFileName, "rb");
+ if (SymFile == 0)
+ return (2);
+
+ // read in first map definition
+ fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
+#ifdef DEBUG_SYMDUMP
+ Buffer[0] = MapDef.achModName[0];
+ fread(&Buffer[1], 1, MapDef.cbModName-1, SymFile);
+ Buffer[MapDef.cbModName] = 0x00;
+ fprintf(LogFile,"Module name '%s'\n",Buffer);
+#endif
+
+ SegOffset = SEGDEFOFFSET(MapDef);
+#ifdef DEBUG_SYMDUMP
+ fprintf(LogFile,"SegOffset %0x\n",SegOffset);
+#endif
+
+ // go thru all segments
+ for (SegNum = 0;
+ SegNum < MapDef.cSegs;
+ SegNum++)
+ {
+#ifdef DEBUG_SYMDUMP
+ fprintf(LogFile,"Scanning segment #%d Offset %08X\n",SegNum,SegOffset);
+#endif
+ if (fseek(SymFile, SegOffset, SEEK_SET))
+ // seek error
+ return (3);
+
+ // read in segment definition
+ fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
+#ifdef DEBUG_SYMDUMP
+ Buffer[0] = 0x00;
+ if (SegDef.cbSegName>0) {
+ Buffer[0] = SegDef.achSegName[0];
+ fread(&Buffer[1], 1, SegDef.cbSegName-1, SymFile);
+ Buffer[SegDef.cbSegName] = 0x00;
+ }
+ fprintf(LogFile,"Segment name '%s', number %d, flags %02x\n",Buffer,SegNum,SegDef.bFlags);
+#endif
+
+ if (SegNum == Object)
+ {
+ // stack object found:
+ Buffer[0] = 0x00;
+ LastVal = 0;
+
+ // go thru all symbols in this object
+#ifdef DEBUG_SYMDUMP
+ fprintf(LogFile,"Scanning #%d symbols\n",SegDef.cSymbols);
+#endif
+ for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
+ {
+ SymPtrOffset=SYMDEFOFFSET(SegOffset,SegDef,SymNum);
+ fseek(SymFile,SymPtrOffset,SEEK_SET);
+ fread(&SymOffset,sizeof(unsigned short int),1,SymFile);
+ fseek(SymFile,SymOffset+SegOffset,SEEK_SET);
+ if (SegDef.bFlags & 0x01)
+ {
+ // 32-bit symbol:
+ fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
+ if (SymDef32.wSymVal > TrapOffset)
+ {
+ // symbol found
+ fprintf(LogFile,
+ "between %s + 0x%lX ",
+ Buffer,
+ TrapOffset - LastVal);
+ /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
+ LINEDEFOFFSET(SegDef)
+ ); */
+ fprintf(LogFile, "\n");
+ }
+
+ LastVal = SymDef32.wSymVal;
+ Buffer[0] = SymDef32.achSymName[0];
+ fread(&Buffer[1], 1, SymDef32.cbSymName-1, SymFile);
+ Buffer[SymDef32.cbSymName] = 0x00;
+#ifdef DEBUG_SYMDUMP
+ fprintf(LogFile,"32 Bit Symbol Address %08p <%s> \n",SymDef32.wSymVal,Buffer);
+#endif
+
+ if (SymDef32.wSymVal > TrapOffset)
+ {
+ // symbol found, as above
+ fprintf(LogFile,
+ " "
+ "and %s - 0x%lX ",
+ Buffer,
+ LastVal - TrapOffset);
+ fprintf(LogFile, "\n");
+ break;
+ }
+ }
+ else
+ {
+ // 16-bit symbol:
+ fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
+ if (SymDef16.wSymVal > TrapOffset)
+ {
+ fprintf(LogFile,
+ "between %s + %lX\n",
+ Buffer,
+ TrapOffset - LastVal);
+ }
+ LastVal = SymDef16.wSymVal;
+ Buffer[0] = SymDef16.achSymName[0];
+ fread(&Buffer[1], 1, SymDef16.cbSymName-1, SymFile);
+ Buffer[SymDef16.cbSymName] = 0x00;
+ if (SymDef16.wSymVal > TrapOffset)
+ {
+ fprintf(LogFile,
+ " "
+ "and %s - %lX\n",
+ Buffer,
+ LastVal - TrapOffset);
+ break;
+ }
+#ifdef DEBUG_SYMDUMP
+ fprintf(LogFile,"16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal);
+#endif
+ } // endif
+ }
+ break;
+ } // endif
+ SegOffset = NEXTSEGDEFOFFSET(SegDef);
+ } // endwhile
+ fclose(SymFile);
+ return (0); // no error
+}
+
+/* ******************************************************************
+ *
+ * PART 4: dbgPrintStack
+ *
+ ********************************************************************/
+
+/*
+ *@@ dbgPrintStackFrame:
+ * parses and dumps one stack frame.
+ * Called from excPrintStackFrame.
+ *
+ * This calls dbgPrintDebugInfo and, if
+ * that fails, dbgPrintSYMInfo.
+ *
+ *@@added V0.9.2 (2000-03-10) [umoeller]
+ *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
+ *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
+ */
+
+BOOL dbgPrintStackFrame(FILE *LogFile,
+ PSZ pszModuleName, // in: module name (fully q'fied)
+ ULONG ulObject,
+ ULONG ulOffset)
+{
+ APIRET arc = 0;
+ // "Source file"... columns
+
+//YD do not use debug info
+#define ENABLE_DEBUG_INFO
+#ifdef ENABLE_DEBUG_INFO
+ // first attempt to analyze the debug code
+ arc = dbgPrintDebugInfo(LogFile,
+ pszModuleName,
+ ulObject,
+ ulOffset);
+#else
+ arc = 1;
+#endif
+
+ // if no debug code is available, analyze
+ // the SYM file instead
+ if (arc != NO_ERROR)
+ {
+ CHAR szSymName[CCHMAXPATH];
+ strcpy(szSymName, pszModuleName);
+ strcpy(szSymName + strlen(szSymName) - 3, "SYM");
+ arc = dbgPrintSYMInfo(LogFile,
+ szSymName,
+ ulObject,
+ ulOffset);
+ if (arc != 0)
+ {
+ // SYM file not found in current directory:
+ // check the SYM files in the \OS2 directory,
+ // depending on the OS/2 version level:
+ CHAR szSymFile2[CCHMAXPATH];
+ PSZ pszFilename = strrchr(szSymName, '\\');
+ if (pszFilename)
+ {
+ PSZ pszVersionDir = "WARP4";
+ ULONG aulBuf[3];
+
+ DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
+ QSV_VERSION_MINOR, // 12
+ &aulBuf, sizeof(aulBuf));
+ // Warp 3 is reported as 20.30
+ // Warp 4 is reported as 20.40
+ // Aurora is reported as 20.45
+
+ if (aulBuf[0] == 20)
+ {
+ if (aulBuf[1] == 30)
+ // Warp 3:
+ pszVersionDir = "WARP3";
+ else if (aulBuf[1] >= 40)
+ // Warp 4 or higher:
+ // (NOTE: Warp 4 FP 13 now returns 45 also,
+ // but the SYM files are still in the WARP4 directory...)
+ // V0.9.3 (2000-04-26) [umoeller]
+ pszVersionDir = "WARP4";
+ }
+
+ pszFilename++;
+ sprintf(szSymFile2,
+ "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
+ doshQueryBootDrive(),
+ pszVersionDir,
+ pszFilename);
+ arc = dbgPrintSYMInfo(LogFile,
+ szSymFile2,
+ ulObject,
+ ulOffset);
+
+ // V0.9.3 (2000-04-26) [umoeller]
+ if ( (arc != 0) // still not found
+ && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13?
+ )
+ {
+ // Warp Server for e-Business (aka Warp 4.5):
+ // we use the SYM files for the UNI kernel,
+ // I have found no way to find out whether
+ // we're running on an SMP kernel
+ sprintf(szSymFile2,
+ "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
+ doshQueryBootDrive(),
+ "WARP45_U",
+ pszFilename);
+ arc = dbgPrintSYMInfo(LogFile,
+ szSymFile2,
+ ulObject,
+ ulOffset);
+ }
+ }
+ }
+
+ if (arc == 2) // file not found
+ fprintf(LogFile,
+ "Cannot find symbol file %s\n",
+ szSymName);
+ else if (arc != 0)
+ fprintf(LogFile,
+ "Error %lu reading symbol file %s\n",
+ arc,
+ szSymName);
+ }
+
+ return (arc == NO_ERROR);
+}
+
+/*
+ *@@ dbgPrintStack:
+ * this takes stack data from the TIB and
+ * context record data structures and tries
+ * to analyse what the different stack frames
+ * point to.
+ *
+ * For each stack frame, this calls dbgPrintDebugInfo,
+ * and, if that fails, dbgPrintSYMInfo.
+ *
+ * New with V0.84.
+ *
+ *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
+ */
+
+VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to
+ PUSHORT StackBottom,
+ PUSHORT StackTop,
+ PUSHORT Ebp,
+ PUSHORT ExceptionAddress)
+{
+ PUSHORT RetAddr = 0;
+ PUSHORT LastEbp = 0;
+ APIRET rc = 0;
+ ULONG Size = 0,
+ Attr = 0;
+ USHORT Cs = 0,
+ Ip = 0,
+ // Bp,
+ Sp = 0;
+ static char Name[CCHMAXPATH];
+ HMODULE hMod = 0;
+ ULONG ObjNum = 0;
+ ULONG Offset = 0;
+ BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru
+
+ // Note: we can't handle stacks bigger than 64K for now...
+ Sp = (USHORT) (((ULONG) StackBottom) >> 16);
+ // Bp = ;
+
+ if (!f32bit)
+ Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
+
+ fprintf(LogFile, "\n\nCall stack:\n");
+ fprintf(LogFile, " Source Line Nearest\n");
+ fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n");
+ fprintf(LogFile, " �������� ��������- �������� ���� ������������ ����� ������������-\n");
+
+ do
+ {
+ Size = 10;
+ rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
+ if (rc != NO_ERROR)
+ {
+ fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
+ break;
+ }
+ if (!(Attr & PAG_COMMIT))
+ {
+ fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
+ break;
+ }
+ if (Size < 10)
+ {
+ fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
+ break;
+ }
+
+ if (fExceptionAddress)
+ RetAddr = ExceptionAddress;
+ else
+ RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
+
+ if (RetAddr == (PUSHORT) 0x00000053)
+ {
+ // For some reason there's a "return address" of 0x53 following
+ // EBP on the stack and we have to adjust EBP by 44 bytes to get
+ // at the real return address. This has something to do with
+ // thunking from 32bits to 16bits...
+ // Serious kludge, and it's probably dependent on versions of C(++)
+ // runtime or OS, but it works for now!
+ Ebp += 22;
+ RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
+ }
+
+ // Get the (possibly) 16bit CS and IP
+ if (fExceptionAddress)
+ {
+ Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
+ Ip = (USHORT) (ULONG) ExceptionAddress;
+ }
+ else
+ {
+ Cs = *(Ebp + 2);
+ Ip = *(Ebp + 1);
+ }
+
+ // if the return address points to the stack then it's really just
+ // a pointer to the return address (UGH!).
+ if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp
+ )
+ RetAddr = (PUSHORT) (*((PULONG) RetAddr));
+
+ if (Ip == 0 && *Ebp == 0)
+ {
+ // End of the stack so these are both shifted by 2 bytes:
+ Cs = *(Ebp + 3);
+ Ip = *(Ebp + 2);
+ }
+
+ // 16bit programs have on the stack:
+ // BP:IP:CS
+ // where CS may be thunked
+ //
+ // in dump swapped
+ // BP IP CS BP CS IP
+ // 4677 53B5 F7D0 7746 D0F7 B553
+ //
+ // 32bit programs have:
+ // EBP:EIP
+ // and you'd have something like this (with SP added) (not
+ // accurate values)
+ //
+ // in dump swapped
+ // EBP EIP EBP EIP
+ // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
+ //
+ // So the basic difference is that 32bit programs have a 32bit
+ // EBP and we can attempt to determine whether we have a 32bit
+ // EBP by checking to see if its 'selector' is the same as SP.
+ // Note that this technique limits us to checking stacks < 64K.
+ //
+ // Soooo, if IP (which maps into the same USHORT as the swapped
+ // stack page in EBP) doesn't point to the stack (i.e. it could
+ // be a 16bit IP) then see if CS is valid (as is or thunked).
+ //
+ // Note that there's the possibility of a 16bit return address
+ // that has an offset that's the same as SP so we'll think it's
+ // a 32bit return address and won't be able to successfully resolve
+ // its details.
+ if (Ip != Sp)
+ {
+ if (DosSizeSeg(Cs, &Size) == NO_ERROR)
+ {
+ RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
+ f32bit = FALSE;
+ }
+ else if (DosSizeSeg((Cs << 3) + 7, &Size) == NO_ERROR)
+ {
+ Cs = (Cs << 3) + 7;
+ RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
+ f32bit = FALSE;
+ }
+ else
+ f32bit = TRUE;
+ }
+ else
+ f32bit = TRUE;
+
+
+ // "EBP" column
+ if (fExceptionAddress)
+ fprintf(LogFile, " Trap -> ");
+ else
+ fprintf(LogFile, " %8.8lX ", (ULONG)Ebp);
+
+ // "Address" column
+ if (f32bit)
+ fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr);
+ else
+ fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip);
+
+ // Version check omitted; the following requires
+ // OS/2 2.10 or later (*UM)
+ // if (Version[0] >= 20 && Version[1] >= 10)
+ {
+ // Make a 'tick' sound to let the user know we're still alive
+ DosBeep(2000, 10);
+
+ Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
+
+ // "Module"/"Object" columns
+ rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
+ if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
+ {
+ fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
+ break; // avoid infinite loops
+ }
+ else
+ {
+ rc = DosQueryModFromEIP(&hMod,
+ &ObjNum,
+ sizeof(Name), Name,
+ &Offset,
+ (PVOID)RetAddr);
+ if ( (rc == NO_ERROR)
+ // && (ObjNum != -1)
+ )
+ {
+ // static char szJunk[_MAX_FNAME];
+ static char szName[_MAX_FNAME];
+
+ DosQueryModuleName(hMod, sizeof(Name), Name);
+ // _splitpath(Name, szJunk, szJunk, szName, szJunk);
+
+ // print module and object
+ fprintf(LogFile, "%-8s %04lX ", szName, ObjNum + 1);
+
+ if (strlen(Name) > 3)
+ {
+ dbgPrintStackFrame(LogFile,
+ Name,
+ ObjNum,
+ Offset);
+ }
+ }
+ else
+ fprintf(LogFile,
+ "DosQueryModFromEIP failed, returned %lu\n",
+ rc);
+ }
+ }
+
+ if ( ((*Ebp) == 0)
+ && ((*Ebp + 1) == 0)
+ )
+ {
+ fprintf(LogFile, "End of call stack\n");
+ break;
+ }
+
+ if (!fExceptionAddress)
+ {
+ LastEbp = Ebp;
+#if 0
+ Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
+#else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
+ if (f32bit)
+ Ebp = (PUSHORT) *(PULONG) LastEbp;
+ else
+ Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
+#endif
+ if (f32bit)
+ {
+ dbgPrintVariables(LogFile, (ULONG) Ebp);
+ } // endif
+
+ if (Ebp < LastEbp)
+ {
+ fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
+ break;
+ }
+ }
+ else
+ fExceptionAddress = FALSE;
+
+ Size = 4;
+ rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
+ if ((rc != NO_ERROR) || (Size < 4))
+ {
+ fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
+ break;
+ }
+ } while (TRUE);
+
+ fprintf(LogFile, "\n");
+}
+
+/*
+ *@@ doshQueryBootDrive:
+ * returns the letter of the boot drive as a
+ * single (capital) character, which is useful for
+ * constructing file names using sprintf and such.
+ *
+ *@@changed V0.9.16 (2002-01-13) [umoeller]: optimized
+ */
+
+CHAR doshQueryBootDrive(VOID)
+{
+ // this can never change, so query this only once
+ // V0.9.16 (2002-01-13) [umoeller]
+ static CHAR cBootDrive = '\0';
+
+ if (!cBootDrive)
+ {
+ ULONG ulBootDrive;
+ DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
+ &ulBootDrive,
+ sizeof(ulBootDrive));
+ cBootDrive = (CHAR)ulBootDrive + 'A' - 1;
+ }
+
+ return (cBootDrive);
+}