home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / debug.c < prev    next >
C/C++ Source or Header  |  2002-02-21  |  73KB  |  2,037 lines

  1.  
  2. /*
  3.  *@@sourcefile debug.c:
  4.  *      this file contains debugging functions for the
  5.  *      exception handlers in except.c.
  6.  *
  7.  *      This code is capable of unwinding the stack from
  8.  *      a given address and trying to get function names
  9.  *      and source line numbers, either from the respective
  10.  *      module's debug code (if present) or from a SYM file,
  11.  *      which is searched for in the directory of the module
  12.  *      or in ?:\OS2\PDPSI\PMDF\WARP4.
  13.  *
  14.  *      This file incorporates code from the following:
  15.  *      -- Marc Fiammante, John Currier, Kim Rasmussen,
  16.  *         Anthony Cruise (EXCEPT3.ZIP package for a generic
  17.  *         exception handling DLL, available at Hobbes).
  18.  *
  19.  *      Usage: All OS/2 programs.
  20.  *
  21.  *      Note: Version numbering in this file relates to XWorkplace version
  22.  *            numbering.
  23.  *
  24.  *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
  25.  *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
  26.  *
  27.  *@@header "helpers\debug.h"
  28.  */
  29.  
  30. /*
  31.  *      This file Copyright (C) 1992-99 Ulrich Möller,
  32.  *                                      Kim Rasmussen,
  33.  *                                      Marc Fiammante,
  34.  *                                      John Currier,
  35.  *                                      Anthony Cruise.
  36.  *      This file is part of the "XWorkplace helpers" source package.
  37.  *      This is free software; you can redistribute it and/or modify
  38.  *      it under the terms of the GNU General Public License as published
  39.  *      by the Free Software Foundation, in version 2 as it comes in the
  40.  *      "COPYING" file of the XWorkplace main distribution.
  41.  *      This program is distributed in the hope that it will be useful,
  42.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  43.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  44.  *      GNU General Public License for more details.
  45.  */
  46.  
  47. #define OS2EMX_PLAIN_CHAR
  48.     // this is needed for "os2emx.h"; if this is defined,
  49.     // emx will define PSZ as _signed_ char, otherwise
  50.     // as unsigned char
  51.  
  52. #define INCL_DOSPROCESS
  53. #define INCL_DOSMODULEMGR
  54. #define INCL_DOSMISC
  55. #define INCL_DOSERRORS
  56. #include <os2.h>
  57.  
  58. #include <stdlib.h>
  59. #include <stdio.h>
  60. #include <string.h>
  61.  
  62. #define DONT_REPLACE_MALLOC
  63. #include "setup.h"                      // code generation and debugging options
  64.  
  65. #include "helpers\debug.h"
  66. #include "helpers\dosh.h"
  67.  
  68. #pragma hdrstop
  69.  
  70. #include <fcntl.h>
  71. #ifdef __EMX__
  72.     #include <sys\types.h>      // required for sys\stat.h; UM 99-10-22
  73. #endif
  74. #include <sys\stat.h>
  75. #include <share.h>
  76. #include <io.h>
  77.  
  78. #ifndef DWORD
  79. #define DWORD unsigned long
  80. #endif
  81. #ifndef WORD
  82. #define WORD  unsigned short
  83. #endif
  84.  
  85. #pragma stack16(512)
  86. #define HF_STDERR 2
  87.  
  88. /*
  89.  *@@category: Helpers\Control program helpers\Exceptions/debugging
  90.  *      See except.c and debug.c.
  91.  */
  92.  
  93. /* ******************************************************************
  94.  *
  95.  *   Global variables
  96.  *
  97.  ********************************************************************/
  98.  
  99. // this specifies whether we're dealing with 32-bit code;
  100. // this gets changed whenever 16-bit count is detected
  101. static BOOL     f32bit = TRUE;
  102.  
  103. /*
  104.  * Global variables for Read32PmDebug:
  105.  *
  106.  */
  107.  
  108. ULONG           func_ofs;
  109. ULONG           pubfunc_ofs;
  110. char            func_name[128];
  111. ULONG           var_ofs = 0;
  112.  
  113. struct {
  114.     BYTE            name[128];
  115.     ULONG           stack_offset;
  116.     USHORT          type_idx;
  117. } autovar_def[100];
  118.  
  119. #pragma pack(1)
  120.  
  121. BYTE           *type_name[] =
  122. {
  123.     "8 bit signed                     ",
  124.     "16 bit signed                    ",
  125.     "32 bit signed                    ",
  126.     "Unknown (0x83)                   ",
  127.     "8 bit unsigned                   ",
  128.     "16 bit unsigned                  ",
  129.     "32 bit unsigned                  ",
  130.     "Unknown (0x87)                   ",
  131.     "32 bit real                      ",
  132.     "64 bit real                      ",
  133.     "80 bit real                      ",
  134.     "Unknown (0x8B)                   ",
  135.     "64 bit complex                   ",
  136.     "128 bit complex                  ",
  137.     "160 bit complex                  ",
  138.     "Unknown (0x8F)                   ",
  139.     "8 bit boolean                    ",
  140.     "16 bit boolean                   ",
  141.     "32 bit boolean                   ",
  142.     "Unknown (0x93)                   ",
  143.     "8 bit character                  ",
  144.     "16 bit characters                ",
  145.     "32 bit characters                ",
  146.     "void                             ",
  147.     "15 bit unsigned                  ",
  148.     "24 bit unsigned                  ",
  149.     "31 bit unsigned                  ",
  150.     "Unknown (0x9B)                   ",
  151.     "Unknown (0x9C)                   ",
  152.     "Unknown (0x9D)                   ",
  153.     "Unknown (0x9E)                   ",
  154.     "Unknown (0x9F)                   ",
  155.     "near pointer to 8 bit signed     ",
  156.     "near pointer to 16 bit signed    ",
  157.     "near pointer to 32 bit signed    ",
  158.     "Unknown (0xA3)                   ",
  159.     "near pointer to 8 bit unsigned   ",
  160.     "near pointer to 16 bit unsigned  ",
  161.     "near pointer to 32 bit unsigned  ",
  162.     "Unknown (0xA7)                   ",
  163.     "near pointer to 32 bit real      ",
  164.     "near pointer to 64 bit real      ",
  165.     "near pointer to 80 bit real      ",
  166.     "Unknown (0xAB)                   ",
  167.     "near pointer to 64 bit complex   ",
  168.     "near pointer to 128 bit complex  ",
  169.     "near pointer to 160 bit complex  ",
  170.     "Unknown (0xAF)                   ",
  171.     "near pointer to 8 bit boolean    ",
  172.     "near pointer to 16 bit boolean   ",
  173.     "near pointer to 32 bit boolean   ",
  174.     "Unknown (0xB3)                   ",
  175.     "near pointer to 8 bit character  ",
  176.     "near pointer to 16 bit characters",
  177.     "near pointer to 32 bit characters",
  178.     "near pointer to void             ",
  179.     "near pointer to 15 bit unsigned  ",
  180.     "near pointer to 24 bit unsigned  ",
  181.     "near pointer to 31 bit unsigned  ",
  182.     "Unknown (0xBB)                   ",
  183.     "Unknown (0xBC)                   ",
  184.     "Unknown (0xBD)                   ",
  185.     "Unknown (0xBE)                   ",
  186.     "Unknown (0xBF)                   ",
  187.     "far pointer to 8 bit signed      ",
  188.     "far pointer to 16 bit signed     ",
  189.     "far pointer to 32 bit signed     ",
  190.     "Unknown (0xC3)                   ",
  191.     "far pointer to 8 bit unsigned    ",
  192.     "far pointer to 16 bit unsigned   ",
  193.     "far pointer to 32 bit unsigned   ",
  194.     "Unknown (0xC7)                   ",
  195.     "far pointer to 32 bit real       ",
  196.     "far pointer to 64 bit real       ",
  197.     "far pointer to 80 bit real       ",
  198.     "Unknown (0xCB)                   ",
  199.     "far pointer to 64 bit complex    ",
  200.     "far pointer to 128 bit complex   ",
  201.     "far pointer to 160 bit complex   ",
  202.     "Unknown (0xCF)                   ",
  203.     "far pointer to 8 bit boolean     ",
  204.     "far pointer to 16 bit boolean    ",
  205.     "far pointer to 32 bit boolean    ",
  206.     "Unknown (0xD3)                   ",
  207.     "far pointer to 8 bit character   ",
  208.     "far pointer to 16 bit characters ",
  209.     "far pointer to 32 bit characters ",
  210.     "far pointer to void              ",
  211.     "far pointer to 15 bit unsigned   ",
  212.     "far pointer to 24 bit unsigned   ",
  213.     "far pointer to 31 bit unsigned   ",
  214. };
  215.  
  216. // Thanks to John Currier:
  217. // Do not call 16 bit code in myHandler function to prevent call
  218. // to __EDCThunkProlog and problems is guard page exception handling
  219. // Also reduce the stack size to 1K for true 16 bit calls.
  220. // 16 bit calls thunk will now only occur on fatal exceptions
  221. #pragma stack16(1024)
  222.  
  223. // ------------------------------------------------------------------
  224. // Last 8 bytes of 16:16 file when CODEVIEW debugging info is present
  225. #pragma pack(1)
  226. struct _eodbug
  227. {
  228.     unsigned short  dbug;       // 'NB' signature
  229.     unsigned short  ver;        // version
  230.     unsigned long   dfaBase;    // size of codeview info
  231. } G_eodbug;
  232.  
  233. #define         DBUGSIG         0x424E
  234. #define         SSTMODULES      0x0101
  235. #define         SSTPUBLICS      0x0102
  236. #define         SSTTYPES        0x0103
  237. #define         SSTSYMBOLS      0x0104
  238. #define         SSTSRCLINES     0x0105
  239. #define         SSTLIBRARIES    0x0106
  240. #define         SSTSRCLINES2    0x0109
  241. #define         SSTSRCLINES32   0x010B
  242.  
  243. typedef struct _SYMBASE
  244. {
  245.     unsigned short  dbug;       // 'NB' signature
  246.     unsigned short  ver;        // version
  247.     unsigned long   lfoDir;     // file offset to dir entries
  248. } SYMBASE;
  249.  
  250. typedef struct _SSDIR
  251. {
  252.     unsigned short  sst;        // SubSection Type
  253.     unsigned short  modindex;   // Module index number
  254.     unsigned long   lfoStart;   // Start of section
  255.     unsigned short  cb;         // Size of section
  256. } SSDIR;
  257.  
  258. typedef struct _SSDIR32
  259. {
  260.     unsigned short  sst;        // SubSection Type
  261.     unsigned short  modindex;   // Module index number
  262.     unsigned long   lfoStart;   // Start of section
  263.     unsigned long   cb;         // Size of section
  264. } SSDIR32;
  265.  
  266. typedef struct _SSMODULE
  267. {
  268.     unsigned short  csBase;     // code segment base
  269.     unsigned short  csOff;      // code segment offset
  270.     unsigned short  csLen;      // code segment length
  271.     unsigned short  ovrNum;     // overlay number
  272.     unsigned short  indxSS;     // Index into sstLib or 0
  273.     unsigned short  reserved;
  274.     char            csize;      // size of prefix string
  275. } SSMODULE;
  276.  
  277. typedef struct _SSMOD32
  278. {
  279.     unsigned short  csBase;     // code segment base
  280.     unsigned long   csOff;      // code segment offset
  281.     unsigned long   csLen;      // code segment length
  282.     unsigned long   ovrNum;     // overlay number
  283.     unsigned short  indxSS;     // Index into sstLib or 0
  284.     unsigned long   reserved;
  285.     char            csize;      // size of prefix string
  286. } SSMOD32;
  287.  
  288. typedef struct _SSPUBLIC
  289. {
  290.     unsigned short  offset;
  291.     unsigned short  segment;
  292.     unsigned short  type;
  293.     char            csize;
  294. } SSPUBLIC;
  295.  
  296. typedef struct _SSPUBLIC32
  297. {
  298.     unsigned long   offset;
  299.     unsigned short  segment;
  300.     unsigned short  type;
  301.     char            csize;
  302. } SSPUBLIC32;
  303.  
  304. typedef struct _SSLINEENTRY32
  305. {
  306.     unsigned short  LineNum;
  307.     unsigned short  FileNum;
  308.     unsigned long   Offset;
  309. } SSLINEENTRY32;
  310.  
  311. typedef struct _FIRSTLINEENTRY32
  312. {
  313.     unsigned short  LineNum;
  314.     unsigned char   entry_type;
  315.     unsigned char   reserved;
  316.     unsigned short  numlines;
  317.     unsigned short  segnum;
  318. } FIRSTLINEENTRY32;
  319.  
  320. typedef struct _SSFILENUM32
  321. {
  322.     unsigned long   first_displayable;  // Not used
  323.     unsigned long   number_displayable;     // Not used
  324.     unsigned long   file_count; // number of source files
  325. } SSFILENUM32;
  326.  
  327. /*
  328.  *@@ XDEBUGINFO:
  329.  *      buffers for Read... funcs.
  330.  *
  331.  *@@added V0.9.4 (2000-06-15) [umoeller]
  332.  */
  333.  
  334. typedef struct _XDEBUGINFO
  335. {
  336.     char            szNrFile[300];      // receives source file
  337.     char            szNrLine[300];      // receives line number
  338.     char            szNrPub[300];       // receives function name
  339.  
  340.     struct new_seg  *pseg;
  341.     struct o32_obj  *pobj;              // flat .EXE object table entry
  342.  
  343.     SYMBASE         base;
  344.  
  345.     SSDIR           *pDirTab;
  346.     SSDIR32         *pDirTab32;
  347.     unsigned char   *pEntTab;
  348.     unsigned long   lfaBase;
  349.     SSMOD32         ssmod32;
  350.     SSPUBLIC32      sspub32;
  351.  
  352.     SSMODULE        ssmod;
  353.     SSPUBLIC        sspub;
  354. } XDEBUGINFO, *PXDEBUGINFO;
  355.  
  356. #pragma pack()
  357.  
  358. /* ******************************************************************
  359.  *
  360.  *   PART 1: ANALYZE DEBUG CODE
  361.  *
  362.  ********************************************************************/
  363.  
  364. static int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
  365. static int Read32PmDebug(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
  366.  
  367. /*
  368.  *@@ WriteAddressInfo:
  369.  *      formats and writes a line into the trap log
  370.  *      file.
  371.  *
  372.  *      This gets called for each line from the
  373.  *      stack dump. At this point, the line in the
  374.  *      trap log already has:
  375.  *
  376.  +          CS:EIP  : 000109FF  XMLVIEW :0
  377.  +                                          ^^^ and we write here
  378.  *      After this call, we have.
  379.  *
  380.  +          CS:EIP  : 000109FF  XMLVIEW :0  xxx.c  123 ConfirmCreate__Fv
  381.  +                                          ^^^ and we write here
  382.  *
  383.  *@@added V0.9.12 (2001-05-12) [umoeller]
  384.  */
  385.  
  386. static VOID WriteDebugInfo(FILE *LogFile,              // in: open log file
  387.                            PXDEBUGINFO pxdi)           // in: debug info
  388. {
  389.     fprintf(LogFile,
  390.             "%s%s%s",
  391.             pxdi->szNrFile,
  392.             pxdi->szNrLine,
  393.             pxdi->szNrPub);
  394. }
  395.  
  396. /*
  397.  *@@ dbgPrintDebugInfo:
  398.  *      this is the main entry point into analyzing debug
  399.  *      code.
  400.  *
  401.  *      This analyzes a given address and tries to find
  402.  *      debug code descriptions for this address. If found,
  403.  *      the information is written to the given log file.
  404.  *
  405.  *      Gets called from dbgPrintStack.
  406.  *
  407.  *      This returns NO_ERROR if the could was successfully
  408.  *      analyzed or something != 0 if we failed.
  409.  *
  410.  *      New with V0.84.
  411.  */
  412.  
  413. APIRET dbgPrintDebugInfo(FILE *LogFile,         // out: log file to write to
  414.                          CHAR *FileName,        // in: EXE/DLL module file name
  415.                          ULONG Object,          // in: trapping object (from DosQueryModFromEIP)
  416.                          ULONG TrapOffset)      // in: trapping address (from DosQueryModFromEIP)
  417. {
  418.     APIRET                  rc = 0;
  419.     int                     ModuleFile = 0;
  420.     static struct exe_hdr   OldExeHeader;
  421.     static struct new_exe   NewExeHeader;
  422.  
  423.     ULONG                   ulSegment = Object + 1;     // segment no. is object no. + 1
  424.  
  425.     XDEBUGINFO              xdi;
  426.     memset(&xdi, 0, sizeof(xdi));
  427.  
  428.     // open the module file for reading to analyze the code
  429.     ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
  430.  
  431.     if (ModuleFile != -1)
  432.     {
  433.         // file found:
  434.         // read old Exe header
  435.         if (read(ModuleFile, (void*)&OldExeHeader, 64) == -1L)
  436.         {
  437.             fprintf(LogFile, "errno %d reading old exe header\n", errno);
  438.             close(ModuleFile);
  439.             return 2;
  440.         }
  441.         // seek to new Exe header
  442.         if (lseek(ModuleFile, (long)E_LFANEW(OldExeHeader), SEEK_SET) == -1L)
  443.         {
  444.             fprintf(LogFile, "errno %d seeking to new exe header\n", errno);
  445.             close(ModuleFile);
  446.             return 3;
  447.         }
  448.         if (read(ModuleFile, (void *)&NewExeHeader, 64) == -1L)
  449.         {
  450.             fprintf(LogFile, "errno %d reading new exe header\n", errno);
  451.             close(ModuleFile);
  452.             return 4;
  453.         }
  454.  
  455.         // check EXE signature
  456.         if (NE_MAGIC(NewExeHeader) == E32MAGIC)
  457.         {
  458.             /*
  459.              * flat 32 executable:
  460.              *
  461.              */
  462.  
  463.             // do analysis for 32-bit code
  464.             if (!(rc = Read32PmDebug(LogFile,
  465.                                      &xdi,                // output
  466.                                      ModuleFile,
  467.                                      ulSegment,
  468.                                      TrapOffset,
  469.                                      FileName)))
  470.                 WriteDebugInfo(LogFile, &xdi);
  471.  
  472.             close(ModuleFile);
  473.  
  474.             // rc !=0 try with DBG file
  475.             if (rc != 0)
  476.             {
  477.                 strcpy(FileName + strlen(FileName) - 3, "DBG");     // Build DBG File name
  478.                 ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
  479.                 if (ModuleFile != -1)
  480.                 {
  481.                     if (!(rc = Read32PmDebug(LogFile,
  482.                                              &xdi,
  483.                                              ModuleFile,
  484.                                              ulSegment,
  485.                                              TrapOffset,
  486.                                              FileName)))
  487.                         WriteDebugInfo(LogFile, &xdi);
  488.  
  489.                     close(ModuleFile);
  490.                 }
  491.             }
  492.  
  493.             return rc;
  494.         }
  495.         else
  496.         {
  497.             if (NE_MAGIC(NewExeHeader) == NEMAGIC)
  498.             {
  499.                 /*
  500.                  * 16:16 executable:
  501.                  *
  502.                  */
  503.  
  504.                 if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader),
  505.                                                          sizeof(struct new_seg)))
  506.                             == NULL)
  507.                 {
  508.                     fprintf(LogFile, "Out of memory!");
  509.                     close(ModuleFile);
  510.                     return -1;
  511.                 }
  512.                 if (  lseek(ModuleFile,
  513.                             E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader),
  514.                             SEEK_SET) == -1L)
  515.                 {
  516.                     fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName);
  517.                     free(xdi.pseg);
  518.                     close(ModuleFile);
  519.                     return 9;
  520.                 }
  521.  
  522.                 if (read(ModuleFile,
  523.                          (void *)xdi.pseg,
  524.                          NE_CSEG(NewExeHeader) * sizeof(struct new_seg))
  525.                       == -1)
  526.                 {
  527.                     fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName);
  528.                     free(xdi.pseg);
  529.                     close(ModuleFile);
  530.                     return 10;
  531.                 }
  532.  
  533.                 if (!(rc = Read16CodeView(LogFile,
  534.                                           &xdi,
  535.                                           ModuleFile,
  536.                                           ulSegment,
  537.                                           TrapOffset,
  538.                                           FileName)))
  539.                     WriteDebugInfo(LogFile, &xdi);
  540.  
  541.                 free(xdi.pseg);
  542.                 close(ModuleFile);
  543.  
  544.                 // rc !=0 try with DBG file
  545.                 if (rc != 0)
  546.                 {
  547.                     strcpy(FileName + strlen(FileName) - 3, "DBG");     // Build DBG File name
  548.                     ModuleFile = sopen(FileName,
  549.                                        O_RDONLY | O_BINARY, SH_DENYNO);
  550.                     if (ModuleFile != -1)
  551.                     {
  552.                         if (!(rc = Read16CodeView(LogFile,
  553.                                                   &xdi,
  554.                                                   ModuleFile,
  555.                                                   ulSegment,
  556.                                                   TrapOffset,
  557.                                                   FileName)))
  558.                             WriteDebugInfo(LogFile, &xdi);
  559.  
  560.                         close(ModuleFile);
  561.                     }
  562.                 }
  563.                 return rc;
  564.             }
  565.             else
  566.             {
  567.                 /*
  568.                  * Unknown executable:
  569.                  *
  570.                  */
  571.  
  572.                 fprintf(LogFile, "Error, could not find exe signature");
  573.                 close(ModuleFile);
  574.                 return 11;
  575.             }
  576.         }
  577.     } // end if (ModuleFile != -1)
  578.     else
  579.     {
  580.         fprintf(LogFile, "Error %d opening module file %s", errno, FileName);
  581.         return 1;
  582.     }                           // endif
  583.  
  584.     // return 0;        we never get here
  585. }
  586.  
  587. char            fname[128],
  588.                 ModName[80];
  589. char            ename[128],
  590.                 dummy[128];
  591.  
  592. #define MAX_USERDEFS 300        // raised from 150 V0.9.1 (2000-01-30) [umoeller]
  593. #define MAX_POINTERS 300        // raised from 150 V0.9.1 (2000-01-30) [umoeller]
  594.  
  595. USHORT          userdef_count;
  596. USHORT          pointer_count;
  597.  
  598. struct one_userdef_rec
  599. {
  600.     USHORT          idx;
  601.     USHORT          type_index;
  602.     BYTE            name[33];
  603. } one_userdef[MAX_USERDEFS];
  604.  
  605. struct one_pointer_rec
  606. {
  607.     USHORT          idx;
  608.     USHORT          type_index;
  609.     BYTE            type_qual;
  610.     BYTE            name[33];
  611. } one_pointer[MAX_POINTERS];
  612.  
  613. /*
  614.  * Read32PmDebug:
  615.  *      parses 32-bit debug code.
  616.  *      Called from dbgPrintDebugInfo for 32-bit modules.
  617.  */
  618.  
  619. static int Read32PmDebug(FILE *LogFile,        // in: text log file to write to
  620.                          PXDEBUGINFO pxdi,
  621.                          int ModuleFile,       // in: module file opened with sopen()
  622.                          int TrapSeg,
  623.                          int TrapOff,
  624.                          CHAR *FileName)
  625. {
  626.     static unsigned int CurrSymSeg, NrSymbol,
  627.                         /* offset, */ NrPublic,
  628.                         NrFile, NrLine, /* NrEntry */
  629.                         numdir, namelen,
  630.                         numlines /* , line */;
  631.     static int      ModIndex;
  632.     static int      bytesread, i, j;
  633.     static SSLINEENTRY32 LineEntry;
  634.     static SSFILENUM32 FileInfo;
  635.     static FIRSTLINEENTRY32 FirstLine;
  636.     static BYTE     dump_vars = FALSE;
  637.     static USHORT   idx;
  638.     static BOOL     read_types;
  639.     static LONG     lSize;
  640.  
  641.     ModIndex = 0;
  642.     // See if any CODEVIEW info
  643.     if (lseek(ModuleFile, -8L, SEEK_END) == -1)
  644.     {
  645.         fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
  646.         return (18);
  647.     }
  648.  
  649.     if (read(ModuleFile,
  650.              (void *)&G_eodbug, 8)
  651.             == -1)
  652.     {
  653.         fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
  654.         return (19);
  655.     }
  656.     if (G_eodbug.dbug != DBUGSIG)
  657.     {
  658.         // fprintf(LogFile,"\nNo CodeView information stored.\n");
  659.         return (100);
  660.     }
  661.  
  662.     if (    (pxdi->lfaBase = lseek(ModuleFile,
  663.                                    -(LONG)G_eodbug.dfaBase,
  664.                                    SEEK_END))
  665.          == -1L)
  666.     {
  667.         fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
  668.         return (20);
  669.     }
  670.  
  671.     if (read(ModuleFile,
  672.              (void *)&pxdi->base, 8)
  673.         == -1)
  674.     {
  675.         fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
  676.         return (21);
  677.     }
  678.  
  679.     if (lseek(ModuleFile,
  680.               pxdi->base.lfoDir - 8 + 4,
  681.               SEEK_CUR)
  682.         == -1)
  683.     {
  684.         fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
  685.         return (22);
  686.     }
  687.  
  688.     if (read(ModuleFile,
  689.              (void *)&numdir, 4)
  690.         == -1)
  691.     {
  692.         fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
  693.         return (23);
  694.     }
  695.  
  696.     // Read dir table into buffer
  697.     if (    (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
  698.                                              sizeof(SSDIR32)))
  699.         == NULL)
  700.     {
  701.         fprintf(LogFile, "Out of memory!");
  702.         return (-1);
  703.     }
  704.  
  705.     if (read(ModuleFile,
  706.              (void*)pxdi->pDirTab32,
  707.              numdir * sizeof(SSDIR32))
  708.         == -1)
  709.     {
  710.         fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
  711.         free(pxdi->pDirTab32);
  712.         return (24);
  713.     }
  714.  
  715.     i = 0;
  716.     while (i < numdir)
  717.     {
  718.         if (pxdi->pDirTab32[i].sst != SSTMODULES)
  719.         {
  720.             i++;
  721.             continue;
  722.         }
  723.  
  724.         NrPublic = 0x0;
  725.         NrSymbol = 0;
  726.         NrLine = 0x0;
  727.         NrFile = 0x0;
  728.         CurrSymSeg = 0;
  729.         // point to subsection
  730.         lseek(ModuleFile,
  731.               pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
  732.               SEEK_SET);
  733.         read(ModuleFile,
  734.              (void*)&pxdi->ssmod32.csBase,
  735.              sizeof(SSMOD32));
  736.         read(ModuleFile,
  737.              (void*)ModName,
  738.              (unsigned)pxdi->ssmod32.csize);
  739.         ModIndex = pxdi->pDirTab32[i].modindex;
  740.         ModName[pxdi->ssmod32.csize] = '\0';
  741.         i++;
  742.  
  743.         read_types = FALSE;
  744.  
  745.         while (     (pxdi->pDirTab32[i].modindex == ModIndex)
  746.                  && (i < numdir)
  747.               )
  748.         {
  749.             // point to subsection
  750.             lseek(ModuleFile,
  751.                   pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
  752.                   SEEK_SET);
  753.  
  754.             switch (pxdi->pDirTab32[i].sst)
  755.             {
  756.                 case SSTPUBLICS:
  757.                     bytesread = 0;
  758.                     while (bytesread < pxdi->pDirTab32[i].cb)
  759.                     {
  760.                         bytesread += read(ModuleFile,
  761.                                           (void *)&pxdi->sspub32.offset,
  762.                                           sizeof(pxdi->sspub32));
  763.                         bytesread += read(ModuleFile,
  764.                                           (void*)ename,
  765.                                           (unsigned)pxdi->sspub32.csize);
  766.                         ename[pxdi->sspub32.csize] = '\0';
  767.                         if (    (pxdi->sspub32.segment == TrapSeg)
  768.                              && (pxdi->sspub32.offset <= TrapOff)
  769.                              && (pxdi->sspub32.offset >= NrPublic)
  770.                            )
  771.                         {
  772.                             NrPublic = pubfunc_ofs = pxdi->sspub32.offset;
  773.                             read_types = TRUE;
  774.                             sprintf(pxdi->szNrPub,
  775.                                     "%s %s (%s)\n",
  776.                                     (pxdi->sspub32.type == 1)
  777.                                             ? " Abs"
  778.                                             : " ",
  779.                                     ename,
  780.                                     ModName
  781.                                 );
  782.                             // but continue, because there might be a
  783.                             // symbol that comes closer
  784.                         }
  785.                     }
  786.                     break;
  787.  
  788.                 // Read symbols, so we can dump the variables on the stack
  789.                 case SSTSYMBOLS:
  790.                     if (TrapSeg != pxdi->ssmod32.csBase)
  791.                         break;
  792.  
  793.                     bytesread = 0;
  794.                     while (bytesread < pxdi->pDirTab32[i].cb)
  795.                     {
  796.                         static USHORT   usLength;
  797.                         static BYTE     b1,
  798.                                         b2;
  799.                         static BYTE     bType;
  800.                                        // *ptr;
  801.                         static ULONG    ofs;
  802.                         // static ULONG    last_addr = 0;
  803.                         static BYTE     str[256];
  804.                         static struct symseg_rec symseg;
  805.                         static struct symauto_rec symauto;
  806.                         static struct symproc_rec symproc;
  807.  
  808.                         // Read the length of this subentry
  809.                         bytesread += read(ModuleFile, &b1, 1);
  810.                         if (b1 & 0x80)
  811.                         {
  812.                             bytesread += read(ModuleFile, &b2, 1);
  813.                             usLength = ((b1 & 0x7F) << 8) + b2;
  814.                         }
  815.                         else
  816.                             usLength = b1;
  817.  
  818.                         ofs = tell(ModuleFile);
  819.  
  820.                         bytesread += read(ModuleFile, &bType, 1);
  821.  
  822.                         switch (bType)
  823.                         {
  824.                             case SYM_CHANGESEG:
  825.                                 read(ModuleFile, &symseg, sizeof(symseg));
  826.                                 CurrSymSeg = symseg.seg_no;
  827.                                 break;
  828.  
  829.                             case SYM_PROC:
  830.                             case SYM_CPPPROC:
  831.                                 read(ModuleFile, &symproc, sizeof(symproc));
  832.                                 read(ModuleFile, str, symproc.name_len);
  833.                                 str[symproc.name_len] = 0;
  834.  
  835.                                 if ((CurrSymSeg == TrapSeg) &&
  836.                                     (symproc.offset <= TrapOff) &&
  837.                                     (symproc.offset >= NrSymbol))
  838.                                 {
  839.  
  840.                                     dump_vars = TRUE;
  841.                                     var_ofs = 0;
  842.                                     NrSymbol = symproc.offset;
  843.                                     func_ofs = symproc.offset;
  844.  
  845.                                     strcpy(func_name, str);
  846.                                 }
  847.                                 else
  848.                                 {
  849.                                     dump_vars = FALSE;
  850.                                 }
  851.                                 break;
  852.  
  853.                             case SYM_AUTO:
  854.                                 if (!dump_vars)
  855.                                     break;
  856.  
  857.                                 read(ModuleFile, &symauto, sizeof(symauto));
  858.                                 read(ModuleFile, str, symauto.name_len);
  859.                                 str[symauto.name_len] = 0;
  860.  
  861.                                 strcpy(autovar_def[var_ofs].name, str);
  862.                                 autovar_def[var_ofs].stack_offset = symauto.stack_offset;
  863.                                 autovar_def[var_ofs].type_idx = symauto.type_idx;
  864.                                 var_ofs++;
  865.                                 break;
  866.  
  867.                         }
  868.  
  869.                         bytesread += usLength;
  870.  
  871.                         lseek(ModuleFile, ofs + usLength, SEEK_SET);
  872.                     }
  873.                     break;
  874.  
  875.                 case SSTTYPES:
  876.                     // if (ModIndex != TrapSeg)
  877.                     if (!read_types)
  878.                         break;
  879.  
  880.                     bytesread = 0;
  881.                     idx = 0x200;
  882.                     userdef_count = 0;
  883.                     pointer_count = 0;
  884.                     while (bytesread < pxdi->pDirTab32[i].cb)
  885.                     {
  886.                         static struct type_rec type;
  887.                         static struct type_userdefrec udef;
  888.                         static struct type_pointerrec point;
  889.                         static ULONG    ofs;
  890.                         static BYTE     str[256];
  891.  
  892.                         // Read the length of this subentry
  893.                         ofs = tell(ModuleFile);
  894.  
  895.                         read(ModuleFile, &type, sizeof(type));
  896.                         bytesread += sizeof(type);
  897.  
  898.                         switch (type.type)
  899.                         {
  900.                             case TYPE_USERDEF:
  901.                                 if (userdef_count >= MAX_USERDEFS)
  902.                                     break;
  903.  
  904.                                 read(ModuleFile, &udef, sizeof(udef));
  905.                                 read(ModuleFile, str, udef.name_len);
  906.                                 str[udef.name_len] = 0;
  907.  
  908.                                 // Insert userdef in table
  909.                                 one_userdef[userdef_count].idx = idx;
  910.                                 one_userdef[userdef_count].type_index = udef.type_index;
  911.                                 memcpy(one_userdef[userdef_count].name,
  912.                                        str,
  913.                                        _min(udef.name_len + 1, 32));
  914.                                 one_userdef[userdef_count].name[32] = 0;
  915.                                 userdef_count++;
  916.                                 break;
  917.  
  918.                             case TYPE_POINTER:
  919.                                 if (pointer_count >= MAX_POINTERS)
  920.                                     break;
  921.  
  922.                                 read(ModuleFile, &point, sizeof(point));
  923.                                 read(ModuleFile, str, point.name_len);
  924.                                 str[point.name_len] = 0;
  925.  
  926.                                 // Insert userdef in table
  927.                                 one_pointer[pointer_count].idx = idx;
  928.                                 one_pointer[pointer_count].type_index = point.type_index;
  929.                                 memcpy(one_pointer[pointer_count].name,
  930.                                        str,
  931.                                        _min(point.name_len + 1, 32));
  932.                                 one_pointer[pointer_count].name[32] = 0;
  933.                                 one_pointer[pointer_count].type_qual = type.type_qual;
  934.                                 pointer_count++;
  935.                                 break;
  936.                         }
  937.  
  938.                         ++idx;
  939.  
  940.                         bytesread += type.length;
  941.  
  942.                         lseek(ModuleFile, ofs + type.length + 2, SEEK_SET);
  943.                     }
  944.                     break;
  945.  
  946.                 case SSTSRCLINES32:
  947.                     if (TrapSeg != pxdi->ssmod32.csBase)
  948.                         break;
  949.  
  950.                     // read first line
  951.                     do
  952.                     {
  953.                         read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine));
  954.  
  955.                         if (FirstLine.LineNum != 0)
  956.                         {
  957.                             fprintf(LogFile, "Missing Line table information\n");
  958.                             break;
  959.                         }       // endif
  960.                         numlines = FirstLine.numlines;
  961.                         // Other type of data skip 4 more bytes
  962.                         if (FirstLine.entry_type < 4)
  963.                         {
  964.                             read(ModuleFile, (void *)&lSize, 4);
  965.                             if (FirstLine.entry_type == 3)
  966.                                 lseek(ModuleFile, lSize, SEEK_CUR);
  967.                         }
  968.                     }
  969.                     while (FirstLine.entry_type == 3);
  970.  
  971.                     for (j = 0; j < numlines; j++)
  972.                     {
  973.                         switch (FirstLine.entry_type)
  974.                         {
  975.                             case 0:
  976.                                 read(ModuleFile, (void *)&LineEntry, sizeof(LineEntry));
  977.                                 // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
  978.                                 // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
  979.                                 if (    (LineEntry.LineNum)
  980.                                      && (LineEntry.Offset + pxdi->ssmod32.csOff
  981.                                             <= TrapOff)
  982.                                      && (LineEntry.Offset + pxdi->ssmod32.csOff >= NrLine)
  983.                                    )
  984.                                 {
  985.                                     NrLine = LineEntry.Offset;
  986.                                     NrFile = LineEntry.FileNum;
  987.                                     /*pOffset =sprintf(szNrLine,"%04X:%08X  line #%hu ",
  988.                                      * ssmod32.csBase,LineEntry.Offset,
  989.                                      * LineEntry.LineNum); */
  990.                                     sprintf(pxdi->szNrLine, "% 6hu", LineEntry.LineNum);
  991.                                 }
  992.                                 break;
  993.  
  994.                             case 1:
  995.                                 lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR);
  996.                                 break;
  997.  
  998.                             case 2:
  999.                                 lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR);
  1000.                                 break;
  1001.  
  1002.                             case 3:
  1003.                                 lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR);
  1004.                                 break;
  1005.  
  1006.                             case 4:
  1007.                                 lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR);
  1008.                                 break;
  1009.  
  1010.                         }
  1011.                     }
  1012.  
  1013.                     if (NrFile != 0)
  1014.                     {
  1015.                         // file found:
  1016.                         read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo));
  1017.                         namelen = 0;
  1018.                         for (j = 1; j <= FileInfo.file_count; j++)
  1019.                         {
  1020.                             namelen = 0;
  1021.                             read(ModuleFile, (void *)&namelen, 1);
  1022.                             read(ModuleFile, (void *)ename, namelen);
  1023.                             if (j == NrFile)
  1024.                                 break;
  1025.                         }
  1026.                         ename[namelen] = '\0';
  1027.                         //  pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
  1028.                         sprintf(pxdi->szNrFile, "%11.11s ", ename);
  1029.                     }
  1030.                     else
  1031.                     {
  1032.                         // strcat(szNrLine,"\n"); avoid new line for empty name fill
  1033.                         strcpy(pxdi->szNrFile, "file?       ");
  1034.                     } // endif
  1035.                     break;
  1036.             } // end switch
  1037.  
  1038.             i++;
  1039.         } // end while modindex
  1040.     } // End While i < numdir
  1041.     free(pxdi->pDirTab32);
  1042.     return (0);
  1043. }
  1044.  
  1045. /*
  1046.  * Read16CodeView:
  1047.  *      parses 16-bit debug code.
  1048.  *      Called from dbgPrintDebugInfo for 16-bit modules.
  1049.  */
  1050.  
  1051. static int Read16CodeView(FILE *LogFile,       // in: text log file to write to
  1052.                           PXDEBUGINFO pxdi,
  1053.                           int fh,
  1054.                           int TrapSeg,
  1055.                           int TrapOff,
  1056.                           CHAR *FileName)
  1057. {
  1058.     static unsigned short int offset,
  1059.                     NrPublic, NrLine,
  1060.                     numdir,
  1061.                     namelen, numlines,
  1062.                     line;
  1063.     static int      ModIndex;
  1064.     static int      bytesread, i, j;
  1065.  
  1066.     ModIndex = 0;
  1067.     // See if any CODEVIEW info
  1068.     if (lseek(fh, -8L, SEEK_END) == -1)
  1069.     {
  1070.         fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
  1071.         return (18);
  1072.     }
  1073.  
  1074.     if (read(fh, (void *)&G_eodbug, 8) == -1)
  1075.     {
  1076.         fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
  1077.         return (19);
  1078.     }
  1079.     if (G_eodbug.dbug != DBUGSIG)
  1080.     {
  1081.         // fprintf(LogFile,"\nNo CodeView information stored.\n");
  1082.         return (100);
  1083.     }
  1084.  
  1085.     if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
  1086.     {
  1087.         fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
  1088.         return (20);
  1089.     }
  1090.  
  1091.     if (read(fh, (void *)&pxdi->base, 8) == -1)
  1092.     {
  1093.         fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
  1094.         return (21);
  1095.     }
  1096.  
  1097.     if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1)
  1098.     {
  1099.         fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
  1100.         return (22);
  1101.     }
  1102.  
  1103.     if (read(fh, (void *)&numdir, 2) == -1)
  1104.     {
  1105.         fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
  1106.         return (23);
  1107.     }
  1108.  
  1109.     // Read dir table into buffer
  1110.     if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
  1111.     {
  1112.         fprintf(LogFile, "Out of memory!");
  1113.         return (-1);
  1114.     }
  1115.  
  1116.     if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1)
  1117.     {
  1118.         fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
  1119.         free(pxdi->pDirTab);
  1120.         return (24);
  1121.     }
  1122.  
  1123.     i = 0;
  1124.     while (i < numdir)
  1125.     {
  1126.         if (pxdi->pDirTab[i].sst != SSTMODULES)
  1127.         {
  1128.             i++;
  1129.             continue;
  1130.         }
  1131.         NrPublic = 0x0;
  1132.         NrLine = 0x0;
  1133.         // point to subsection
  1134.         lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
  1135.         read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE));
  1136.         read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize);
  1137.         ModIndex = pxdi->pDirTab[i].modindex;
  1138.         ModName[pxdi->ssmod.csize] = '\0';
  1139.         i++;
  1140.         while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir)
  1141.         {
  1142.             // point to subsection
  1143.             lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
  1144.             switch (pxdi->pDirTab[i].sst)
  1145.             {
  1146.                 case SSTPUBLICS:
  1147.                     bytesread = 0;
  1148.                     while (bytesread < pxdi->pDirTab[i].cb)
  1149.                     {
  1150.                         bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub));
  1151.                         bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize);
  1152.                         ename[pxdi->sspub.csize] = '\0';
  1153.                         if ((pxdi->sspub.segment == TrapSeg) &&
  1154.                             (pxdi->sspub.offset <= TrapOff) &&
  1155.                             (pxdi->sspub.offset >= NrPublic))
  1156.                         {
  1157.                             NrPublic = pxdi->sspub.offset;
  1158.                             sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n",
  1159.                                     (pxdi->sspub.type == 1) ? " Abs" : " ", ename,
  1160.                                     ModName, // ()
  1161.                                     pxdi->sspub.segment,
  1162.                                     pxdi->sspub.offset
  1163.                                 );
  1164.                         }
  1165.                     }
  1166.                     break;
  1167.  
  1168.                 case SSTSRCLINES2:
  1169.                 case SSTSRCLINES:
  1170.                     if (TrapSeg != pxdi->ssmod.csBase)
  1171.                         break;
  1172.                     namelen = 0;
  1173.                     read(fh, (void *)&namelen, 1);
  1174.                     read(fh, (void *)ename, namelen);
  1175.                     ename[namelen] = '\0';
  1176.                     // skip 2 zero bytes
  1177.                     if (pxdi->pDirTab[i].sst == SSTSRCLINES2)
  1178.                         read(fh, (void *)&numlines, 2);
  1179.                     read(fh, (void *)&numlines, 2);
  1180.                     for (j = 0; j < numlines; j++)
  1181.                     {
  1182.                         read(fh, (void *)&line, 2);
  1183.                         read(fh, (void *)&offset, 2);
  1184.                         if (offset <= TrapOff && offset >= NrLine)
  1185.                         {
  1186.                             NrLine = offset;
  1187.                             sprintf(pxdi->szNrFile, "% 12.12s ", ename);
  1188.                             sprintf(pxdi->szNrLine, "% 6hu", line);
  1189.                             /*sprintf(szNrLine,"%04hX:%04hX  line #%hu  (%s) (%s)\n",
  1190.                              * ssmod.csBase,offset,line,ModName,ename); */
  1191.                         }
  1192.                     }
  1193.                     break;
  1194.             }                   // end switch
  1195.             i++;
  1196.         }                       // end while modindex
  1197.     }                           // End While i < numdir
  1198.     free(pxdi->pDirTab);
  1199.     return (0);
  1200. }
  1201.  
  1202. /* ******************************************************************
  1203.  *
  1204.  *   PART 2: ANALYZE VARIABLES
  1205.  *
  1206.  ********************************************************************/
  1207.  
  1208. /*
  1209.  * var_value:
  1210.  *      writes a description of a variable type to
  1211.  *      the specified buffer, depending on "type".
  1212.  *
  1213.  *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
  1214.  */
  1215.  
  1216. static VOID var_value(void *varptr,        // in: address of the variable on the stack
  1217.                       char *pszBuf,        // out: information
  1218.                       BYTE type)           // in: type; if >= 32, we'll call DosQueryMem
  1219. {
  1220.     ULONG           Size = 1,
  1221.                     Attr = 0;
  1222.  
  1223.     if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
  1224.     {
  1225.         sprintf(pszBuf, "type %d, DosQueryMem failed", type);
  1226.         return;
  1227.     }
  1228.  
  1229.     if ((Attr & PAG_READ) == 0)
  1230.     {
  1231.         sprintf(pszBuf, "type %d, read-access to value denied", type);
  1232.         return;
  1233.     }
  1234.  
  1235.     if (type == 0)
  1236.         sprintf(pszBuf, "%hd", *(signed char*)varptr);
  1237.     else if (type == 1)
  1238.         sprintf(pszBuf, "%hd", *(signed short*)varptr);
  1239.     else if (type == 2)
  1240.         sprintf(pszBuf, "%ld", *(signed long*)varptr);
  1241.     else if (type == 4)
  1242.         sprintf(pszBuf, "%hu", *(BYTE*) varptr);
  1243.     else if (type == 5)
  1244.         sprintf(pszBuf, "%hu", *(USHORT*)varptr);
  1245.     else if (type == 6)
  1246.         sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
  1247.     else if (type == 8)
  1248.         sprintf(pszBuf, "%f", *(float*)varptr);
  1249.     else if (type == 9)
  1250.         sprintf(pszBuf, "%f", *(double*)varptr);
  1251.     else if (type == 10)
  1252.         sprintf(pszBuf, "%f", (double)(*(long double*)varptr));
  1253.     else if (type == 16)
  1254.         sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
  1255.     else if (type == 17)
  1256.         sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE");
  1257.     else if (type == 18)
  1258.         sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE");
  1259.     else if (type == 20)
  1260.         sprintf(pszBuf, "%c", *(char*)varptr);
  1261.     else if (type == 21)
  1262.         sprintf(pszBuf, "%hd", (*(short*)varptr));
  1263.     else if (type == 22)
  1264.         sprintf(pszBuf, "%ld", *(long*)varptr);
  1265.     else if (type == 23)
  1266.         sprintf(pszBuf, "void");
  1267.     else if (type >= 32)
  1268.     {
  1269.         sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr));
  1270.         if (Attr & PAG_FREE)
  1271.         {
  1272.             strcat(pszBuf, " unallocated memory");
  1273.         }
  1274.         else
  1275.         {
  1276.             if ((Attr & PAG_COMMIT) == 0x0U)
  1277.             {
  1278.                 strcat(pszBuf, " uncommitted");
  1279.             }               // endif
  1280.             if ((Attr & PAG_WRITE) == 0x0U)
  1281.             {
  1282.                 strcat(pszBuf, " unwritable");
  1283.             }               // endif
  1284.             if ((Attr & PAG_READ) == 0x0U)
  1285.             {
  1286.                 strcat(pszBuf, " unreadable");
  1287.             }               // endif
  1288.         }                   // endif
  1289.     }                       // endif
  1290.     else
  1291.         sprintf(pszBuf, "Unknown type %d", type);
  1292. }
  1293.  
  1294. /*
  1295.  * search_userdefs:
  1296.  *      searches the table of userdef's-
  1297.  *      Return TRUE if found.
  1298.  */
  1299.  
  1300. static BOOL search_userdefs(FILE *LogFile,     // in: text log file to write to
  1301.                             ULONG stackofs,
  1302.                             USHORT var_no)
  1303. {
  1304.     USHORT          pos;
  1305.  
  1306.     for (pos = 0;
  1307.          pos < userdef_count;
  1308.          pos++)
  1309.     {
  1310.         if (one_userdef[pos].idx == autovar_def[var_no].type_idx)
  1311.         {
  1312.             if (    (one_userdef[pos].type_index >= 0x80)
  1313.                 // &&  (one_userdef[pos].type_index <= 0xDA)
  1314.                )
  1315.             {
  1316.                 static char sszVar3[500] = "complex";
  1317.                 if (one_userdef[pos].type_index <= 0xDA)
  1318.                     var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
  1319.                               sszVar3,
  1320.                               one_userdef[pos].type_index - 0x80);
  1321.  
  1322.                 fprintf(LogFile,
  1323.                         "     %- 6ld %- 20.20s %- 33.33s %s (user)\n",
  1324.                         autovar_def[var_no].stack_offset,       // stack offset
  1325.                         autovar_def[var_no].name,               // identifier
  1326.                         one_userdef[pos].name,                  // type name
  1327.                         sszVar3                                 // composed by var_value
  1328.                        );
  1329.                 return TRUE;
  1330.             }
  1331.             else
  1332.                 return FALSE;
  1333.         }
  1334.     }
  1335.  
  1336.     return FALSE;
  1337. }
  1338.  
  1339. /*
  1340.  * search_pointers:
  1341.  *
  1342.  */
  1343.  
  1344. static BOOL search_pointers(FILE *LogFile,     // in: text log file to write to
  1345.                             ULONG stackofs,
  1346.                             USHORT var_no)
  1347. {
  1348.     USHORT          pos, upos;
  1349.     static BYTE     str[35];
  1350.     static char     sszVar[500];
  1351.  
  1352.     // BYTE            type_index;
  1353.  
  1354.     for (pos = 0;
  1355.          (   (pos < pointer_count)
  1356.           && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
  1357.          );
  1358.          pos++);
  1359.  
  1360.     if (pos < pointer_count)
  1361.     {
  1362.         if (    (one_pointer[pos].type_index >= 0x80)
  1363.              && (one_pointer[pos].type_index <= 0xDA)
  1364.            )
  1365.         {
  1366.             strcpy(str, type_name[one_pointer[pos].type_index - 0x80]);
  1367.             strcat(str, " *");
  1368.             var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
  1369.                       sszVar,
  1370.                       32);
  1371.             fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
  1372.                     autovar_def[var_no].stack_offset,
  1373.                     autovar_def[var_no].name,
  1374.                     str,
  1375.                     sszVar);
  1376.             return TRUE;
  1377.         }
  1378.         else
  1379.         {
  1380.             // If the result isn't a simple type, look for it in the other lists
  1381.             for (upos = 0;
  1382.                  (   (upos < userdef_count)
  1383.                   && (one_userdef[upos].idx != one_pointer[pos].type_index)
  1384.                  );
  1385.                  upos++)
  1386.                 ;
  1387.  
  1388.             if (upos < userdef_count)
  1389.             {
  1390.                 strcpy(str, one_userdef[upos].name);
  1391.                 strcat(str, " *");
  1392.                 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
  1393.                           sszVar,
  1394.                           32);
  1395.                 fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
  1396.                         autovar_def[var_no].stack_offset,
  1397.                         autovar_def[var_no].name,
  1398.                         str,
  1399.                         sszVar);
  1400.                 return TRUE;
  1401.             }
  1402.             else
  1403.             {
  1404.                 // if it isn't a userdef, for now give up and just print
  1405.                 // as much as we know
  1406.                 sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index);
  1407.  
  1408.                 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
  1409.                           sszVar,
  1410.                           32);
  1411.                 fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
  1412.                         autovar_def[var_no].stack_offset,
  1413.                         autovar_def[var_no].name,
  1414.                         str,
  1415.                         sszVar);
  1416.  
  1417.                 return TRUE;
  1418.             }
  1419.         }
  1420.     }
  1421.  
  1422.     return FALSE;
  1423. }
  1424.  
  1425. /*
  1426.  *@@ dbgPrintVariables:
  1427.  *      Dumps variables for the specified stack offset
  1428.  *      to the specified log file.
  1429.  *
  1430.  *      New with V0.84.
  1431.  */
  1432.  
  1433. void dbgPrintVariables(FILE *LogFile,   // in: text log file to write to
  1434.                        ULONG stackofs)
  1435. {
  1436.     USHORT          n; // , pos;
  1437.     BOOL            AutoVarsFound = FALSE;
  1438.  
  1439.     if (/* 1 || */ func_ofs == pubfunc_ofs)
  1440.     {
  1441.         for (n = 0;
  1442.              n < var_ofs;
  1443.              n++)
  1444.         {
  1445.             if (AutoVarsFound == FALSE)
  1446.             {
  1447.                 AutoVarsFound = TRUE;
  1448.                 fprintf(LogFile, "     List of auto variables at EBP %p in %s:\n",
  1449.                         (PVOID)stackofs,
  1450.                         func_name);
  1451.                 fprintf(LogFile, "     Offset Name                 Type                              Value            \n");
  1452.                 fprintf(LogFile, "     ────── ──────────────────── ───────────────────────────────── ─────────────────\n");
  1453.             }
  1454.  
  1455.             // If it's one of the simple types
  1456.             if (   (autovar_def[n].type_idx >= 0x80)
  1457.                 && (autovar_def[n].type_idx <= 0xDA)
  1458.                 )
  1459.             {
  1460.                 static char sszVar2[500];
  1461.  
  1462.                 var_value((void *)(stackofs + autovar_def[n].stack_offset),
  1463.                           sszVar2,
  1464.                           autovar_def[n].type_idx - 0x80);
  1465.  
  1466.                 fprintf(LogFile, "     %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
  1467.                         autovar_def[n].stack_offset,
  1468.                         autovar_def[n].name,
  1469.                         type_name[autovar_def[n].type_idx - 0x80],
  1470.                         sszVar2);
  1471.             }
  1472.             else
  1473.             {                   // Complex type, check if we know what it is
  1474.                 if (!search_userdefs(LogFile, stackofs, n))
  1475.                 {
  1476.                     if (!search_pointers(LogFile, stackofs, n))
  1477.                     {
  1478.                         fprintf(LogFile, "     %- 6ld %-20.20s 0x%X (unknown)\n",
  1479.                                 autovar_def[n].stack_offset,
  1480.                                 autovar_def[n].name,
  1481.                                 autovar_def[n].type_idx);
  1482.                     }
  1483.                 }
  1484.             }
  1485.         }
  1486.         /* if (AutoVarsFound == FALSE)
  1487.         {
  1488.             fprintf(LogFile, "  No auto variables found in %s.\n", func_name);
  1489.         } */
  1490.         fprintf(LogFile, "\n");
  1491.     }
  1492. }
  1493.  
  1494. /* ******************************************************************
  1495.  *
  1496.  *   PART 3: ANALYZE SYMBOL (.SYM) FILE
  1497.  *
  1498.  ********************************************************************/
  1499.  
  1500. /*
  1501.  *@@ dbgPrintSYMInfo:
  1502.  *      this gets called by dbgPrintStack if dbgPrintDebugInfo
  1503.  *      failed (because no debug code was found) to check if
  1504.  *      maybe a SYM file with the same filename exists and try
  1505.  *      to get the info from there.
  1506.  *
  1507.  *      This gets called for every line of the stack
  1508.  *      walk, but only if getting the information from
  1509.  *      the debug code failed, e.g. because no debug code
  1510.  *      was available for an address.
  1511.  *
  1512.  *      The file pointer is in the "Source file" column
  1513.  *      every time this gets called.
  1514.  *
  1515.  *      New with V0.84.
  1516.  *
  1517.  *      Returns 0 if reading the SYM file was successful.
  1518.  *
  1519.  *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
  1520.  */
  1521.  
  1522. int dbgPrintSYMInfo(FILE *LogFile,      // in: text log file to write to
  1523.                     CHAR *SymFileName,  // in: SYM file name (can be fully q'fied)
  1524.                     ULONG Object,
  1525.                     ULONG TrapOffset)
  1526. {
  1527.     static FILE    *SymFile;
  1528.     static MAPDEF   MapDef;
  1529.     static SEGDEF   SegDef;
  1530.     static SYMDEF32 SymDef32;
  1531.     static SYMDEF16 SymDef16;
  1532.     static char     Buffer[256];
  1533.     static int      SegNum, SymNum, LastVal;
  1534.     static unsigned long int SegOffset,
  1535.                     SymOffset, SymPtrOffset;
  1536.  
  1537.     // open .SYM file
  1538.     SymFile = fopen(SymFileName, "rb");
  1539.     if (SymFile == 0)
  1540.         return (2);
  1541.  
  1542.     // read in first map definition
  1543.     fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
  1544.  
  1545.     SegOffset = SEGDEFOFFSET(MapDef);
  1546.  
  1547.     // go thru all segments
  1548.     for (SegNum = 0;
  1549.          SegNum < MapDef.cSegs;
  1550.          SegNum++)
  1551.     {
  1552.         // printf("Scanning segment #%d Offset %4.4hX\n",SegNum+1,SegOffset);
  1553.         if (fseek(SymFile, SegOffset, SEEK_SET))
  1554.             // seek error
  1555.             return (3);
  1556.  
  1557.         // read in segment definition
  1558.         fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
  1559.         if (SegNum == Object)
  1560.         {
  1561.             // stack object found:
  1562.             Buffer[0] = 0x00;
  1563.             LastVal = 0;
  1564.  
  1565.             // go thru all symbols in this object
  1566.             for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
  1567.             {
  1568.  
  1569.                 // read in symbol offset USHORT
  1570.                 SymPtrOffset = SYMDEFOFFSET(SegOffset, SegDef, SymNum);
  1571.                 fseek(SymFile, SymPtrOffset, SEEK_SET);
  1572.                 fread(&SymOffset, sizeof(unsigned short int), 1, SymFile);
  1573.  
  1574.                 // go to symbol definition
  1575.                 fseek(SymFile, SymOffset + SegOffset, SEEK_SET);
  1576.  
  1577.                 if (SegDef.bFlags & 0x01)
  1578.                 {
  1579.                     // 32-bit symbol:
  1580.                     fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
  1581.                     if (SymDef32.wSymVal > TrapOffset)
  1582.                     {
  1583.                         // symbol found
  1584.                         fprintf(LogFile,
  1585.                                 "between %s + 0x%lX ",
  1586.                                 Buffer,
  1587.                                 TrapOffset - LastVal);
  1588.                         /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
  1589.                                     LINEDEFOFFSET(SegDef)
  1590.                                     ); */
  1591.                         fprintf(LogFile, "\n");
  1592.                     }
  1593.  
  1594.                     LastVal = SymDef32.wSymVal;
  1595.                     Buffer[0] = SymDef32.achSymName[0];
  1596.                     fread(&Buffer[1], 1, SymDef32.cbSymName, SymFile);
  1597.                     Buffer[SymDef32.cbSymName] = 0x00;
  1598.  
  1599.                     if (SymDef32.wSymVal > TrapOffset)
  1600.                     {
  1601.                         // symbol found, as above
  1602.                         fprintf(LogFile,
  1603.                                 "                                     "
  1604.                                 "and %s - 0x%lX ",
  1605.                                 Buffer,
  1606.                                 LastVal - TrapOffset);
  1607.                         fprintf(LogFile, "\n");
  1608.                         break;
  1609.                     }
  1610.                     /*printf("32 Bit Symbol <%s> Address %p\n",Buffer,SymDef32.wSymVal); */
  1611.                 }
  1612.                 else
  1613.                 {
  1614.                     // 16-bit symbol:
  1615.                     fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
  1616.                     if (SymDef16.wSymVal > TrapOffset)
  1617.                     {
  1618.                         fprintf(LogFile,
  1619.                                 "between %s + %lX\n",
  1620.                                 Buffer,
  1621.                                 TrapOffset - LastVal);
  1622.                     }
  1623.                     LastVal = SymDef16.wSymVal;
  1624.                     Buffer[0] = SymDef16.achSymName[0];
  1625.                     fread(&Buffer[1], 1, SymDef16.cbSymName, SymFile);
  1626.                     Buffer[SymDef16.cbSymName] = 0x00;
  1627.                     if (SymDef16.wSymVal > TrapOffset)
  1628.                     {
  1629.                         fprintf(LogFile,
  1630.                                 "                                     "
  1631.                                 "and %s - %lX\n",
  1632.                                 Buffer,
  1633.                                 LastVal - TrapOffset);
  1634.                         break;
  1635.                     }
  1636.                     /*printf("16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal); */
  1637.                 }               // endif
  1638.             }
  1639.             break;
  1640.         }                       // endif
  1641.         SegOffset = NEXTSEGDEFOFFSET(SegDef);
  1642.     }                           // endwhile
  1643.     fclose(SymFile);
  1644.     return (0);         // no error
  1645. }
  1646.  
  1647. /* ******************************************************************
  1648.  *
  1649.  *   PART 4: dbgPrintStack
  1650.  *
  1651.  ********************************************************************/
  1652.  
  1653. /*
  1654.  *@@ dbgPrintStackFrame:
  1655.  *      parses and dumps one stack frame.
  1656.  *      Called from excPrintStackFrame.
  1657.  *
  1658.  *      This calls dbgPrintDebugInfo and, if
  1659.  *      that fails, dbgPrintSYMInfo.
  1660.  *
  1661.  *@@added V0.9.2 (2000-03-10) [umoeller]
  1662.  *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
  1663.  *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
  1664.  */
  1665.  
  1666. BOOL dbgPrintStackFrame(FILE *LogFile,
  1667.                         PSZ pszModuleName,  // in: module name (fully q'fied)
  1668.                         ULONG ulObject,
  1669.                         ULONG ulOffset)
  1670. {
  1671.     APIRET arc = 0;
  1672.     // "Source file"... columns
  1673.  
  1674.     // first attempt to analyze the debug code
  1675.     arc = dbgPrintDebugInfo(LogFile,
  1676.                             pszModuleName,
  1677.                             ulObject,
  1678.                             ulOffset);
  1679.     // if no debug code is available, analyze
  1680.     // the SYM file instead
  1681.     if (arc != NO_ERROR)
  1682.     {
  1683.         CHAR szSymName[CCHMAXPATH];
  1684.         strcpy(szSymName, pszModuleName);
  1685.         strcpy(szSymName + strlen(szSymName) - 3, "SYM");
  1686.         arc = dbgPrintSYMInfo(LogFile,
  1687.                               szSymName,
  1688.                               ulObject,
  1689.                               ulOffset);
  1690.         if (arc != 0)
  1691.         {
  1692.             // SYM file not found in current directory:
  1693.             // check the SYM files in the \OS2 directory,
  1694.             // depending on the OS/2 version level:
  1695.             CHAR szSymFile2[CCHMAXPATH];
  1696.             PSZ  pszFilename = strrchr(szSymName, '\\');
  1697.             if (pszFilename)
  1698.             {
  1699.                 PSZ         pszVersionDir = "WARP4";
  1700.                 ULONG       aulBuf[3];
  1701.  
  1702.                 DosQuerySysInfo(QSV_VERSION_MAJOR,      // 11
  1703.                                 QSV_VERSION_MINOR,      // 12
  1704.                                 &aulBuf, sizeof(aulBuf));
  1705.                 // Warp 3 is reported as 20.30
  1706.                 // Warp 4 is reported as 20.40
  1707.                 // Aurora is reported as 20.45
  1708.  
  1709.                 if (aulBuf[0] == 20)
  1710.                 {
  1711.                     if (aulBuf[1] == 30)
  1712.                         // Warp 3:
  1713.                         pszVersionDir = "WARP3";
  1714.                     else if (aulBuf[1] >= 40)
  1715.                         // Warp 4 or higher:
  1716.                         // (NOTE: Warp 4 FP 13 now returns 45 also,
  1717.                         // but the SYM files are still in the WARP4 directory...)
  1718.                         // V0.9.3 (2000-04-26) [umoeller]
  1719.                         pszVersionDir = "WARP4";
  1720.                 }
  1721.  
  1722.                 pszFilename++;
  1723.                 sprintf(szSymFile2,
  1724.                         "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
  1725.                         doshQueryBootDrive(),
  1726.                         pszVersionDir,
  1727.                         pszFilename);
  1728.                 arc = dbgPrintSYMInfo(LogFile,
  1729.                                       szSymFile2,
  1730.                                       ulObject,
  1731.                                       ulOffset);
  1732.  
  1733.                 // V0.9.3 (2000-04-26) [umoeller]
  1734.                 if (    (arc != 0)  // still not found
  1735.                      && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13?
  1736.                    )
  1737.                 {
  1738.                     // Warp Server for e-Business (aka Warp 4.5):
  1739.                     // we use the SYM files for the UNI kernel,
  1740.                     // I have found no way to find out whether
  1741.                     // we're running on an SMP kernel
  1742.                     sprintf(szSymFile2,
  1743.                             "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
  1744.                             doshQueryBootDrive(),
  1745.                             "WARP45_U",
  1746.                             pszFilename);
  1747.                     arc = dbgPrintSYMInfo(LogFile,
  1748.                                           szSymFile2,
  1749.                                           ulObject,
  1750.                                           ulOffset);
  1751.                 }
  1752.             }
  1753.         }
  1754.  
  1755.         if (arc == 2)       // file not found
  1756.             fprintf(LogFile,
  1757.                     "Cannot find symbol file %s\n",
  1758.                     szSymName);
  1759.         else if (arc != 0)
  1760.             fprintf(LogFile,
  1761.                     "Error %lu reading symbol file %s\n",
  1762.                     arc,
  1763.                     szSymName);
  1764.     }
  1765.  
  1766.     return (arc == NO_ERROR);
  1767. }
  1768.  
  1769. /*
  1770.  *@@ dbgPrintStack:
  1771.  *      this takes stack data from the TIB and
  1772.  *      context record data structures and tries
  1773.  *      to analyse what the different stack frames
  1774.  *      point to.
  1775.  *
  1776.  *      For each stack frame, this calls dbgPrintDebugInfo,
  1777.  *      and, if that fails, dbgPrintSYMInfo.
  1778.  *
  1779.  *      New with V0.84.
  1780.  *
  1781.  *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
  1782.  */
  1783.  
  1784. VOID dbgPrintStack(FILE *LogFile,           // in: text log file to write to
  1785.                    PUSHORT StackBottom,
  1786.                    PUSHORT StackTop,
  1787.                    PUSHORT Ebp,
  1788.                    PUSHORT ExceptionAddress)
  1789. {
  1790.     PUSHORT         RetAddr = 0;
  1791.     PUSHORT         LastEbp = 0;
  1792.     APIRET          rc = 0;
  1793.     ULONG           Size = 0,
  1794.                     Attr = 0;
  1795.     USHORT          Cs = 0,
  1796.                     Ip = 0,
  1797.                     // Bp,
  1798.                     Sp = 0;
  1799.     static char     Name[CCHMAXPATH];
  1800.     HMODULE         hMod = 0;
  1801.     ULONG           ObjNum = 0;
  1802.     ULONG           Offset = 0;
  1803.     BOOL            fExceptionAddress = TRUE;   // Use Exception Addr 1st time thru
  1804.  
  1805.     // Note: we can't handle stacks bigger than 64K for now...
  1806.     Sp = (USHORT) (((ULONG) StackBottom) >> 16);
  1807.     // Bp = ;
  1808.  
  1809.     if (!f32bit)
  1810.         Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
  1811.  
  1812.     fprintf(LogFile, "\n\nCall stack:\n");
  1813.     fprintf(LogFile, "                                        Source    Line      Nearest\n");
  1814.     fprintf(LogFile, "   EBP      Address    Module  Obj#      File     Numbr  Public Symbol\n");
  1815.     fprintf(LogFile, " ────────  ────────-  ──────── ────  ──────────── ─────  ────────────-\n");
  1816.  
  1817.     do
  1818.     {
  1819.         Size = 10;
  1820.         rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
  1821.         if (rc != NO_ERROR)
  1822.         {
  1823.             fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
  1824.             break;
  1825.         }
  1826.         if (!(Attr & PAG_COMMIT))
  1827.         {
  1828.             fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
  1829.             break;
  1830.         }
  1831.         if (Size < 10)
  1832.         {
  1833.             fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
  1834.             break;
  1835.         }
  1836.  
  1837.         if (fExceptionAddress)
  1838.             RetAddr = ExceptionAddress;
  1839.         else
  1840.             RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
  1841.  
  1842.         if (RetAddr == (PUSHORT) 0x00000053)
  1843.         {
  1844.             // For some reason there's a "return address" of 0x53 following
  1845.             // EBP on the stack and we have to adjust EBP by 44 bytes to get
  1846.             // at the real return address.  This has something to do with
  1847.             // thunking from 32bits to 16bits...
  1848.             // Serious kludge, and it's probably dependent on versions of C(++)
  1849.             // runtime or OS, but it works for now!
  1850.             Ebp += 22;
  1851.             RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
  1852.         }
  1853.  
  1854.         // Get the (possibly) 16bit CS and IP
  1855.         if (fExceptionAddress)
  1856.         {
  1857.             Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
  1858.             Ip = (USHORT) (ULONG) ExceptionAddress;
  1859.         }
  1860.         else
  1861.         {
  1862.             Cs = *(Ebp + 2);
  1863.             Ip = *(Ebp + 1);
  1864.         }
  1865.  
  1866.         // if the return address points to the stack then it's really just
  1867.         // a pointer to the return address (UGH!).
  1868.         if (    (USHORT) (((ULONG) RetAddr) >> 16) == Sp
  1869.            )
  1870.             RetAddr = (PUSHORT) (*((PULONG) RetAddr));
  1871.  
  1872.         if (Ip == 0 && *Ebp == 0)
  1873.         {
  1874.             // End of the stack so these are both shifted by 2 bytes:
  1875.             Cs = *(Ebp + 3);
  1876.             Ip = *(Ebp + 2);
  1877.         }
  1878.  
  1879.         // 16bit programs have on the stack:
  1880.         //   BP:IP:CS
  1881.         //   where CS may be thunked
  1882.         //
  1883.         //         in dump                 swapped
  1884.         //    BP        IP   CS          BP   CS   IP
  1885.         //   4677      53B5 F7D0        7746 D0F7 B553
  1886.         //
  1887.         // 32bit programs have:
  1888.         //   EBP:EIP
  1889.         // and you'd have something like this (with SP added) (not
  1890.         // accurate values)
  1891.         //
  1892.         //         in dump               swapped
  1893.         //      EBP       EIP         EBP       EIP
  1894.         //   4677 2900 53B5 F7D0   0029 7746 D0F7 B553
  1895.         //
  1896.         // So the basic difference is that 32bit programs have a 32bit
  1897.         // EBP and we can attempt to determine whether we have a 32bit
  1898.         // EBP by checking to see if its 'selector' is the same as SP.
  1899.         // Note that this technique limits us to checking stacks < 64K.
  1900.         //
  1901.         // Soooo, if IP (which maps into the same USHORT as the swapped
  1902.         // stack page in EBP) doesn't point to the stack (i.e. it could
  1903.         // be a 16bit IP) then see if CS is valid (as is or thunked).
  1904.         //
  1905.         // Note that there's the possibility of a 16bit return address
  1906.         // that has an offset that's the same as SP so we'll think it's
  1907.         // a 32bit return address and won't be able to successfully resolve
  1908.         // its details.
  1909.         if (Ip != Sp)
  1910.         {
  1911.             if (DOS16SIZESEG(Cs, &Size) == NO_ERROR)
  1912.             {
  1913.                 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
  1914.                 f32bit = FALSE;
  1915.             }
  1916.             else if (DOS16SIZESEG((Cs << 3) + 7, &Size) == NO_ERROR)
  1917.             {
  1918.                 Cs = (Cs << 3) + 7;
  1919.                 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
  1920.                 f32bit = FALSE;
  1921.             }
  1922.             else
  1923.                 f32bit = TRUE;
  1924.         }
  1925.         else
  1926.             f32bit = TRUE;
  1927.  
  1928.  
  1929.         // "EBP" column
  1930.         if (fExceptionAddress)
  1931.             fprintf(LogFile, " Trap  ->  ");
  1932.         else
  1933.             fprintf(LogFile, " %8.8lX  ", (ULONG)Ebp);
  1934.  
  1935.         // "Address" column
  1936.         if (f32bit)
  1937.             fprintf(LogFile, ":%8.8lX  ", (ULONG)RetAddr);
  1938.         else
  1939.             fprintf(LogFile, "%04.04X:%04.04X  ", Cs, Ip);
  1940.  
  1941.         // Version check omitted; the following requires
  1942.         // OS/2 2.10 or later (*UM)
  1943.         // if (Version[0] >= 20 && Version[1] >= 10)
  1944.         {
  1945.             // Make a 'tick' sound to let the user know we're still alive
  1946.             DosBeep(2000, 10);
  1947.  
  1948.             Size = 10;    // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
  1949.  
  1950.             // "Module"/"Object" columns
  1951.             rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
  1952.             if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
  1953.             {
  1954.                 fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
  1955.                 break;          // avoid infinite loops
  1956.             }
  1957.             else
  1958.             {
  1959.                 rc = DOSQUERYMODFROMEIP(&hMod,
  1960.                                         &ObjNum,
  1961.                                         sizeof(Name), Name,
  1962.                                         &Offset,
  1963.                                         (PVOID)RetAddr);
  1964.                 if (    (rc == NO_ERROR)
  1965.                      // && (ObjNum != -1)
  1966.                    )
  1967.                 {
  1968.                     // static char     szJunk[_MAX_FNAME];
  1969.                     static char     szName[_MAX_FNAME];
  1970.  
  1971.                     DosQueryModuleName(hMod, sizeof(Name), Name);
  1972.                     // _splitpath(Name, szJunk, szJunk, szName, szJunk);
  1973.  
  1974.                     // print module and object
  1975.                     fprintf(LogFile, "%-8s %04lX  ", szName, ObjNum + 1);
  1976.  
  1977.                     if (strlen(Name) > 3)
  1978.                     {
  1979.                         dbgPrintStackFrame(LogFile,
  1980.                                            Name,
  1981.                                            ObjNum,
  1982.                                            Offset);
  1983.                     }
  1984.                 }
  1985.                 else
  1986.                     fprintf(LogFile,
  1987.                             "DosQueryModFromEIP failed, returned %lu\n",
  1988.                             rc);
  1989.             }
  1990.         }
  1991.  
  1992.         if (    ((*Ebp) == 0)
  1993.              && ((*Ebp + 1) == 0)
  1994.            )
  1995.         {
  1996.             fprintf(LogFile, "End of call stack\n");
  1997.             break;
  1998.         }
  1999.  
  2000.         if (!fExceptionAddress)
  2001.         {
  2002.             LastEbp = Ebp;
  2003. #if 0
  2004.             Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
  2005. #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
  2006.             if (f32bit)
  2007.                 Ebp = (PUSHORT) *(PULONG) LastEbp;
  2008.             else
  2009.                 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
  2010. #endif
  2011.             if (f32bit)
  2012.             {
  2013.                 dbgPrintVariables(LogFile, (ULONG) Ebp);
  2014.             }                   // endif
  2015.  
  2016.             if (Ebp < LastEbp)
  2017.             {
  2018.                 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
  2019.                 break;
  2020.             }
  2021.         }
  2022.         else
  2023.             fExceptionAddress = FALSE;
  2024.  
  2025.         Size = 4;
  2026.         rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
  2027.         if ((rc != NO_ERROR) || (Size < 4))
  2028.         {
  2029.             fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
  2030.             break;
  2031.         }
  2032.     } while (TRUE);
  2033.  
  2034.     fprintf(LogFile, "\n");
  2035. }
  2036.  
  2037.