merge the formfield patch from ooo-build
[ooovba.git] / sal / osl / os2 / debug.c
blob53a9d23a3a68ff2045b9eb0021184d7067ebacc9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile:$
10 * $Revision:$
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 *@@sourcefile debug.c:
33 * this file contains debugging functions for the
34 * exception handlers in except.c.
36 * This code is capable of unwinding the stack from
37 * a given address and trying to get function names
38 * and source line numbers, either from the respective
39 * module's debug code (if present) or from a SYM file,
40 * which is searched for in the directory of the module
41 * or in ?:\OS2\PDPSI\PMDF\WARP4.
43 * This file incorporates code from the following:
44 * -- Marc Fiammante, John Currier, Kim Rasmussen,
45 * Anthony Cruise (EXCEPT3.ZIP package for a generic
46 * exception handling DLL, available at Hobbes).
48 * Usage: All OS/2 programs.
50 * Note: Version numbering in this file relates to XWorkplace version
51 * numbering.
53 *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
54 *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
56 *@@header "helpers\debug.h"
60 * This file Copyright (C) 1992-99 Ulrich M�ller,
61 * Kim Rasmussen,
62 * Marc Fiammante,
63 * John Currier,
64 * Anthony Cruise.
65 * This file is part of the "XWorkplace helpers" source package.
67 * 2009-06-15 published under LGPL3 with Ulrich M�ller permission.
71 //#define DEBUG_SYMDUMP // enable to dump sym file to log
73 //YD commented, since we need unsigned char BYTE!
74 //#define OS2EMX_PLAIN_CHAR
75 //Also gcc char is signed, while most structures requires unsigned data!
76 //Raised limits for all fields!
78 // this is needed for "os2emx.h"; if this is defined,
79 // emx will define PSZ as _signed_ char, otherwise
80 // as unsigned char
82 #define INCL_DOSPROCESS
83 #define INCL_DOSMODULEMGR
84 #define INCL_DOSMISC
85 #define INCL_DOSERRORS
86 #include <os2.h>
88 #include <stdlib.h>
89 #include <stdio.h>
90 #include <string.h>
92 #define DONT_REPLACE_MALLOC
93 #include "helpers\setup.h" // code generation and debugging options
95 #include "helpers\debug.h"
96 #include "helpers\dosh.h"
98 #pragma hdrstop
100 #include <fcntl.h>
101 #ifdef __EMX__
102 #include <sys\types.h> // required for sys\stat.h; UM 99-10-22
103 #endif
104 #include <sys\stat.h>
105 #include <share.h>
106 #include <io.h>
108 #ifndef DWORD
109 #define DWORD unsigned long
110 #endif
111 #ifndef WORD
112 #define WORD unsigned short
113 #endif
115 #pragma stack16(512)
116 #define HF_STDERR 2
119 *@@category: Helpers\Control program helpers\Exceptions/debugging
120 * See except.c and debug.c.
123 /* ******************************************************************
125 * Global variables
127 ********************************************************************/
129 // this specifies whether we're dealing with 32-bit code;
130 // this gets changed whenever 16-bit count is detected
131 static BOOL f32bit = TRUE;
134 * Global variables for Read32PmDebug:
138 ULONG func_ofs;
139 ULONG pubfunc_ofs;
140 //YD 17/07/06 c++ namespace can generate really long
141 //YD names, use a large buffer!
142 char func_name[16*1024];
143 ULONG var_ofs = 0;
145 struct {
146 BYTE name[128];
147 ULONG stack_offset;
148 USHORT type_idx;
149 } autovar_def[1024];
151 #pragma pack(1)
153 BYTE *type_name[] =
155 "8 bit signed ",
156 "16 bit signed ",
157 "32 bit signed ",
158 "Unknown (0x83) ",
159 "8 bit unsigned ",
160 "16 bit unsigned ",
161 "32 bit unsigned ",
162 "Unknown (0x87) ",
163 "32 bit real ",
164 "64 bit real ",
165 "80 bit real ",
166 "Unknown (0x8B) ",
167 "64 bit complex ",
168 "128 bit complex ",
169 "160 bit complex ",
170 "Unknown (0x8F) ",
171 "8 bit boolean ",
172 "16 bit boolean ",
173 "32 bit boolean ",
174 "Unknown (0x93) ",
175 "8 bit character ",
176 "16 bit characters ",
177 "32 bit characters ",
178 "void ",
179 "15 bit unsigned ",
180 "24 bit unsigned ",
181 "31 bit unsigned ",
182 "Unknown (0x9B) ",
183 "Unknown (0x9C) ",
184 "Unknown (0x9D) ",
185 "Unknown (0x9E) ",
186 "Unknown (0x9F) ",
187 "near pointer to 8 bit signed ",
188 "near pointer to 16 bit signed ",
189 "near pointer to 32 bit signed ",
190 "Unknown (0xA3) ",
191 "near pointer to 8 bit unsigned ",
192 "near pointer to 16 bit unsigned ",
193 "near pointer to 32 bit unsigned ",
194 "Unknown (0xA7) ",
195 "near pointer to 32 bit real ",
196 "near pointer to 64 bit real ",
197 "near pointer to 80 bit real ",
198 "Unknown (0xAB) ",
199 "near pointer to 64 bit complex ",
200 "near pointer to 128 bit complex ",
201 "near pointer to 160 bit complex ",
202 "Unknown (0xAF) ",
203 "near pointer to 8 bit boolean ",
204 "near pointer to 16 bit boolean ",
205 "near pointer to 32 bit boolean ",
206 "Unknown (0xB3) ",
207 "near pointer to 8 bit character ",
208 "near pointer to 16 bit characters",
209 "near pointer to 32 bit characters",
210 "near pointer to void ",
211 "near pointer to 15 bit unsigned ",
212 "near pointer to 24 bit unsigned ",
213 "near pointer to 31 bit unsigned ",
214 "Unknown (0xBB) ",
215 "Unknown (0xBC) ",
216 "Unknown (0xBD) ",
217 "Unknown (0xBE) ",
218 "Unknown (0xBF) ",
219 "far pointer to 8 bit signed ",
220 "far pointer to 16 bit signed ",
221 "far pointer to 32 bit signed ",
222 "Unknown (0xC3) ",
223 "far pointer to 8 bit unsigned ",
224 "far pointer to 16 bit unsigned ",
225 "far pointer to 32 bit unsigned ",
226 "Unknown (0xC7) ",
227 "far pointer to 32 bit real ",
228 "far pointer to 64 bit real ",
229 "far pointer to 80 bit real ",
230 "Unknown (0xCB) ",
231 "far pointer to 64 bit complex ",
232 "far pointer to 128 bit complex ",
233 "far pointer to 160 bit complex ",
234 "Unknown (0xCF) ",
235 "far pointer to 8 bit boolean ",
236 "far pointer to 16 bit boolean ",
237 "far pointer to 32 bit boolean ",
238 "Unknown (0xD3) ",
239 "far pointer to 8 bit character ",
240 "far pointer to 16 bit characters ",
241 "far pointer to 32 bit characters ",
242 "far pointer to void ",
243 "far pointer to 15 bit unsigned ",
244 "far pointer to 24 bit unsigned ",
245 "far pointer to 31 bit unsigned ",
248 // Thanks to John Currier:
249 // Do not call 16 bit code in myHandler function to prevent call
250 // to __EDCThunkProlog and problems is guard page exception handling
251 // Also reduce the stack size to 1K for true 16 bit calls.
252 // 16 bit calls thunk will now only occur on fatal exceptions
253 #pragma stack16(1024)
255 // ------------------------------------------------------------------
256 // Last 8 bytes of 16:16 file when CODEVIEW debugging info is present
257 #pragma pack(1)
258 struct _eodbug
260 unsigned short dbug; // 'NB' signature
261 unsigned short ver; // version
262 unsigned long dfaBase; // size of codeview info
263 } G_eodbug;
265 #define DBUGSIG 0x424E
266 #define SSTMODULES 0x0101
267 #define SSTPUBLICS 0x0102
268 #define SSTTYPES 0x0103
269 #define SSTSYMBOLS 0x0104
270 #define SSTSRCLINES 0x0105
271 #define SSTLIBRARIES 0x0106
272 #define SSTSRCLINES2 0x0109
273 #define SSTSRCLINES32 0x010B
275 typedef struct _SYMBASE
277 unsigned short dbug; // 'NB' signature
278 unsigned short ver; // version
279 unsigned long lfoDir; // file offset to dir entries
280 } SYMBASE;
282 typedef struct _SSDIR
284 unsigned short sst; // SubSection Type
285 unsigned short modindex; // Module index number
286 unsigned long lfoStart; // Start of section
287 unsigned short cb; // Size of section
288 } SSDIR;
290 typedef struct _SSDIR32
292 unsigned short sst; // SubSection Type
293 unsigned short modindex; // Module index number
294 unsigned long lfoStart; // Start of section
295 unsigned long cb; // Size of section
296 } SSDIR32;
298 typedef struct _SSMODULE
300 unsigned short csBase; // code segment base
301 unsigned short csOff; // code segment offset
302 unsigned short csLen; // code segment length
303 unsigned short ovrNum; // overlay number
304 unsigned short indxSS; // Index into sstLib or 0
305 unsigned short reserved;
306 BYTE csize; // size of prefix string
307 } SSMODULE;
309 typedef struct _SSMOD32
311 unsigned short csBase; // code segment base
312 unsigned long csOff; // code segment offset
313 unsigned long csLen; // code segment length
314 unsigned long ovrNum; // overlay number
315 unsigned short indxSS; // Index into sstLib or 0
316 unsigned long reserved;
317 BYTE csize; // size of prefix string
318 } SSMOD32;
320 typedef struct _SSPUBLIC
322 unsigned short offset;
323 unsigned short segment;
324 unsigned short type;
325 BYTE csize;
326 } SSPUBLIC;
328 typedef struct _SSPUBLIC32
330 unsigned long offset;
331 unsigned short segment;
332 unsigned short type;
333 BYTE csize;
334 } SSPUBLIC32;
336 typedef struct _SSLINEENTRY32
338 unsigned short LineNum;
339 unsigned short FileNum;
340 unsigned long Offset;
341 } SSLINEENTRY32;
343 typedef struct _FIRSTLINEENTRY32
345 unsigned short LineNum;
346 unsigned char entry_type;
347 unsigned char reserved;
348 unsigned short numlines;
349 unsigned short segnum;
350 } FIRSTLINEENTRY32;
352 typedef struct _SSFILENUM32
354 unsigned long first_displayable; // Not used
355 unsigned long number_displayable; // Not used
356 unsigned long file_count; // number of source files
357 } SSFILENUM32;
360 *@@ XDEBUGINFO:
361 * buffers for Read... funcs.
363 *@@added V0.9.4 (2000-06-15) [umoeller]
366 typedef struct _XDEBUGINFO
368 char szNrFile[300]; // receives source file
369 char szNrLine[300]; // receives line number
370 //YD 17/07/06 c++ namespace can generate really long
371 //YD names, use a large buffer!
372 char szNrPub[16*1024]; // receives function name
374 struct new_seg *pseg;
375 struct o32_obj *pobj; // flat .EXE object table entry
377 SYMBASE base;
379 SSDIR *pDirTab;
380 SSDIR32 *pDirTab32;
381 unsigned char *pEntTab;
382 unsigned long lfaBase;
383 SSMOD32 ssmod32;
384 SSPUBLIC32 sspub32;
386 SSMODULE ssmod;
387 SSPUBLIC sspub;
388 } XDEBUGINFO, *PXDEBUGINFO;
391 USHORT _THUNK_FUNCTION (Dos16SizeSeg) ();
392 //APIRET16 APIENTRY16 DOS16SIZESEG(USHORT Seg, PULONG16 Size);
393 USHORT DosSizeSeg (USHORT Seg, PULONG16 Size)
395 return ((USHORT)
396 (_THUNK_PROLOG (2+4);
397 _THUNK_SHORT (Seg);
398 _THUNK_FLAT (Size);
399 _THUNK_CALL (Dos16SizeSeg)));
402 #pragma pack()
404 /* ******************************************************************
406 * PART 1: ANALYZE DEBUG CODE
408 ********************************************************************/
410 static int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
411 static int Read32PmDebug(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
414 *@@ WriteAddressInfo:
415 * formats and writes a line into the trap log
416 * file.
418 * This gets called for each line from the
419 * stack dump. At this point, the line in the
420 * trap log already has:
422 + CS:EIP : 000109FF XMLVIEW :0
423 + ^^^ and we write here
424 * After this call, we have.
426 + CS:EIP : 000109FF XMLVIEW :0 xxx.c 123 ConfirmCreate__Fv
427 + ^^^ and we write here
429 *@@added V0.9.12 (2001-05-12) [umoeller]
432 static VOID WriteDebugInfo(FILE *LogFile, // in: open log file
433 PXDEBUGINFO pxdi) // in: debug info
435 fprintf(LogFile,
436 "%s%s%s",
437 pxdi->szNrFile,
438 pxdi->szNrLine,
439 pxdi->szNrPub);
443 *@@ dbgPrintDebugInfo:
444 * this is the main entry point into analyzing debug
445 * code.
447 * This analyzes a given address and tries to find
448 * debug code descriptions for this address. If found,
449 * the information is written to the given log file.
451 * Gets called from dbgPrintStack.
453 * This returns NO_ERROR if the could was successfully
454 * analyzed or something != 0 if we failed.
456 * New with V0.84.
459 APIRET dbgPrintDebugInfo(FILE *LogFile, // out: log file to write to
460 CHAR *FileName, // in: EXE/DLL module file name
461 ULONG Object, // in: trapping object (from DosQueryModFromEIP)
462 ULONG TrapOffset) // in: trapping address (from DosQueryModFromEIP)
464 APIRET rc = 0;
465 int ModuleFile = 0;
466 static struct exe_hdr OldExeHeader;
467 static struct new_exe NewExeHeader;
469 ULONG ulSegment = Object + 1; // segment no. is object no. + 1
471 XDEBUGINFO xdi;
472 memset(&xdi, 0, sizeof(xdi));
474 // open the module file for reading to analyze the code
475 ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
477 if (ModuleFile != -1)
479 // file found:
480 // read old Exe header
481 if (read(ModuleFile, (void*)&OldExeHeader, 64) == -1L)
483 fprintf(LogFile, "errno %d reading old exe header\n", errno);
484 close(ModuleFile);
485 return 2;
487 // seek to new Exe header
488 if (lseek(ModuleFile, (long)E_LFANEW(OldExeHeader), SEEK_SET) == -1L)
490 fprintf(LogFile, "errno %d seeking to new exe header\n", errno);
491 close(ModuleFile);
492 return 3;
494 if (read(ModuleFile, (void *)&NewExeHeader, 64) == -1L)
496 fprintf(LogFile, "errno %d reading new exe header\n", errno);
497 close(ModuleFile);
498 return 4;
501 // check EXE signature
502 if (NE_MAGIC(NewExeHeader) == E32MAGIC)
505 * flat 32 executable:
509 // do analysis for 32-bit code
510 if (!(rc = Read32PmDebug(LogFile,
511 &xdi, // output
512 ModuleFile,
513 ulSegment,
514 TrapOffset,
515 FileName)))
516 WriteDebugInfo(LogFile, &xdi);
518 close(ModuleFile);
520 // rc !=0 try with DBG file
521 if (rc != 0)
523 strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name
524 ModuleFile = sopen(FileName, O_RDONLY | O_BINARY, SH_DENYNO);
525 if (ModuleFile != -1)
527 if (!(rc = Read32PmDebug(LogFile,
528 &xdi,
529 ModuleFile,
530 ulSegment,
531 TrapOffset,
532 FileName)))
533 WriteDebugInfo(LogFile, &xdi);
535 close(ModuleFile);
539 return rc;
541 else
543 if (NE_MAGIC(NewExeHeader) == NEMAGIC)
546 * 16:16 executable:
550 if ((xdi.pseg = (struct new_seg *)calloc(NE_CSEG(NewExeHeader),
551 sizeof(struct new_seg)))
552 == NULL)
554 fprintf(LogFile, "Out of memory!");
555 close(ModuleFile);
556 return -1;
558 if ( lseek(ModuleFile,
559 E_LFANEW(OldExeHeader) + NE_SEGTAB(NewExeHeader),
560 SEEK_SET) == -1L)
562 fprintf(LogFile, "Error %u seeking segment table in %s\n", errno, FileName);
563 free(xdi.pseg);
564 close(ModuleFile);
565 return 9;
568 if (read(ModuleFile,
569 (void *)xdi.pseg,
570 NE_CSEG(NewExeHeader) * sizeof(struct new_seg))
571 == -1)
573 fprintf(LogFile, "Error %u reading segment table from %s\n", errno, FileName);
574 free(xdi.pseg);
575 close(ModuleFile);
576 return 10;
579 if (!(rc = Read16CodeView(LogFile,
580 &xdi,
581 ModuleFile,
582 ulSegment,
583 TrapOffset,
584 FileName)))
585 WriteDebugInfo(LogFile, &xdi);
587 free(xdi.pseg);
588 close(ModuleFile);
590 // rc !=0 try with DBG file
591 if (rc != 0)
593 strcpy(FileName + strlen(FileName) - 3, "DBG"); // Build DBG File name
594 ModuleFile = sopen(FileName,
595 O_RDONLY | O_BINARY, SH_DENYNO);
596 if (ModuleFile != -1)
598 if (!(rc = Read16CodeView(LogFile,
599 &xdi,
600 ModuleFile,
601 ulSegment,
602 TrapOffset,
603 FileName)))
604 WriteDebugInfo(LogFile, &xdi);
606 close(ModuleFile);
609 return rc;
611 else
614 * Unknown executable:
618 fprintf(LogFile, "Error, could not find exe signature");
619 close(ModuleFile);
620 return 11;
623 } // end if (ModuleFile != -1)
624 else
626 fprintf(LogFile, "Error %d opening module file %s", errno, FileName);
627 return 1;
628 } // endif
630 // return 0; we never get here
633 char fname[256],
634 ModName[80];
635 char ename[256],
636 dummy[256];
638 #define MAX_USERDEFS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
639 #define MAX_POINTERS 300 // raised from 150 V0.9.1 (2000-01-30) [umoeller]
641 USHORT userdef_count;
642 USHORT pointer_count;
644 struct one_userdef_rec
646 USHORT idx;
647 USHORT type_index;
648 BYTE name[33];
649 } one_userdef[MAX_USERDEFS];
651 struct one_pointer_rec
653 USHORT idx;
654 USHORT type_index;
655 BYTE type_qual;
656 BYTE name[33];
657 } one_pointer[MAX_POINTERS];
660 * Read32PmDebug:
661 * parses 32-bit debug code.
662 * Called from dbgPrintDebugInfo for 32-bit modules.
665 static int Read32PmDebug(FILE *LogFile, // in: text log file to write to
666 PXDEBUGINFO pxdi,
667 int ModuleFile, // in: module file opened with sopen()
668 int TrapSeg,
669 int TrapOff,
670 CHAR *FileName)
672 static unsigned int CurrSymSeg, NrSymbol,
673 /* offset, */ NrPublic,
674 NrFile, NrLine, /* NrEntry */
675 numdir, namelen,
676 numlines /* , line */;
677 static int ModIndex;
678 static int bytesread, i, j;
679 static SSLINEENTRY32 LineEntry;
680 static SSFILENUM32 FileInfo;
681 static FIRSTLINEENTRY32 FirstLine;
682 static BYTE dump_vars = FALSE;
683 static USHORT idx;
684 static BOOL read_types;
685 static LONG lSize;
687 ModIndex = 0;
688 // See if any CODEVIEW info
689 if (lseek(ModuleFile, -8L, SEEK_END) == -1)
691 fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
692 return (18);
695 if (read(ModuleFile,
696 (void *)&G_eodbug, 8)
697 == -1)
699 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
700 return (19);
702 if (G_eodbug.dbug != DBUGSIG)
704 // fprintf(LogFile,"\nNo CodeView information stored.\n");
705 return (100);
708 if ( (pxdi->lfaBase = lseek(ModuleFile,
709 -(LONG)G_eodbug.dfaBase,
710 SEEK_END))
711 == -1L)
713 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
714 return (20);
717 if (read(ModuleFile,
718 (void *)&pxdi->base, 8)
719 == -1)
721 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
722 return (21);
725 if (lseek(ModuleFile,
726 pxdi->base.lfoDir - 8 + 4,
727 SEEK_CUR)
728 == -1)
730 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
731 return (22);
734 if (read(ModuleFile,
735 (void *)&numdir, 4)
736 == -1)
738 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
739 return (23);
742 // Read dir table into buffer
743 if ( (pxdi->pDirTab32 = (SSDIR32*)calloc(numdir,
744 sizeof(SSDIR32)))
745 == NULL)
747 fprintf(LogFile, "Out of memory!");
748 return (-1);
751 if (read(ModuleFile,
752 (void*)pxdi->pDirTab32,
753 numdir * sizeof(SSDIR32))
754 == -1)
756 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
757 free(pxdi->pDirTab32);
758 return (24);
761 i = 0;
762 while (i < numdir)
764 if (pxdi->pDirTab32[i].sst != SSTMODULES)
766 i++;
767 continue;
770 NrPublic = 0x0;
771 NrSymbol = 0;
772 NrLine = 0x0;
773 NrFile = 0x0;
774 CurrSymSeg = 0;
775 // point to subsection
776 lseek(ModuleFile,
777 pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
778 SEEK_SET);
779 read(ModuleFile,
780 (void*)&pxdi->ssmod32.csBase,
781 sizeof(SSMOD32));
782 read(ModuleFile,
783 (void*)ModName,
784 (unsigned)pxdi->ssmod32.csize);
785 ModIndex = pxdi->pDirTab32[i].modindex;
786 ModName[pxdi->ssmod32.csize] = '\0';
787 i++;
789 read_types = FALSE;
791 while ( (pxdi->pDirTab32[i].modindex == ModIndex)
792 && (i < numdir)
795 // point to subsection
796 lseek(ModuleFile,
797 pxdi->pDirTab32[i].lfoStart + pxdi->lfaBase,
798 SEEK_SET);
800 switch (pxdi->pDirTab32[i].sst)
802 case SSTPUBLICS:
803 bytesread = 0;
804 while (bytesread < pxdi->pDirTab32[i].cb)
806 bytesread += read(ModuleFile,
807 (void *)&pxdi->sspub32.offset,
808 sizeof(pxdi->sspub32));
809 bytesread += read(ModuleFile,
810 (void*)ename,
811 (unsigned)pxdi->sspub32.csize);
812 ename[pxdi->sspub32.csize] = '\0';
813 if ( (pxdi->sspub32.segment == TrapSeg)
814 && (pxdi->sspub32.offset <= TrapOff)
815 && (pxdi->sspub32.offset >= NrPublic)
818 NrPublic = pubfunc_ofs = pxdi->sspub32.offset;
819 read_types = TRUE;
820 sprintf(pxdi->szNrPub,
821 "%s %s (%s)\n",
822 (pxdi->sspub32.type == 1)
823 ? " Abs"
824 : " ",
825 ename,
826 ModName
828 // but continue, because there might be a
829 // symbol that comes closer
832 break;
834 // Read symbols, so we can dump the variables on the stack
835 case SSTSYMBOLS:
836 if (TrapSeg != pxdi->ssmod32.csBase)
837 break;
839 bytesread = 0;
840 while (bytesread < pxdi->pDirTab32[i].cb)
842 static USHORT usLength;
843 static USHORT usLengthSym;
844 static BYTE b1,
846 static BYTE bType;
847 // *ptr;
848 static ULONG ofs;
849 // static ULONG last_addr = 0;
850 //YD 17/07/06 c++ namespace can generate really long
851 //YD names, use a large buffer!
852 static BYTE str[16*1024];
853 static struct symseg_rec symseg;
854 static struct symauto_rec symauto;
855 static struct symproc_rec symproc;
857 // Read the length of this subentry
858 bytesread += read(ModuleFile, &b1, 1);
859 if (b1 & 0x80)
861 bytesread += read(ModuleFile, &b2, 1);
862 usLength = ((b1 & 0x7F) << 8) + b2;
864 else
865 usLength = b1;
867 ofs = tell(ModuleFile);
869 bytesread += read(ModuleFile, &bType, 1);
871 switch (bType)
873 case SYM_CHANGESEG:
874 read(ModuleFile, &symseg, sizeof(symseg));
875 CurrSymSeg = symseg.seg_no;
876 break;
878 case SYM_PROC:
879 case SYM_CPPPROC:
880 read(ModuleFile, &symproc, sizeof(symproc));
881 if (symproc.name_len & 0x80)
883 read(ModuleFile, &b2, 1);
884 usLengthSym = ((symproc.name_len & 0x7F) << 8) + b2;
886 else
888 usLengthSym = symproc.name_len;
890 read(ModuleFile, str, usLengthSym);
891 str[usLengthSym] = 0;
893 if ((CurrSymSeg == TrapSeg) &&
894 (symproc.offset <= TrapOff) &&
895 (symproc.offset >= NrSymbol))
898 dump_vars = TRUE;
899 var_ofs = 0;
900 NrSymbol = symproc.offset;
901 func_ofs = symproc.offset;
903 strcpy(func_name, str);
905 else
907 dump_vars = FALSE;
909 break;
911 case SYM_AUTO:
912 if (!dump_vars)
913 break;
915 read(ModuleFile, &symauto, sizeof(symauto));
916 read(ModuleFile, str, symauto.name_len);
917 if (symauto.name_len==0x80)
918 printf("symauto.name_len==0x80\n");
919 str[symauto.name_len] = 0;
921 strcpy(autovar_def[var_ofs].name, str);
922 autovar_def[var_ofs].stack_offset = symauto.stack_offset;
923 autovar_def[var_ofs].type_idx = symauto.type_idx;
924 var_ofs++;
925 break;
929 bytesread += usLength;
931 lseek(ModuleFile, ofs + usLength, SEEK_SET);
933 break;
935 case SSTTYPES:
936 // if (ModIndex != TrapSeg)
937 if (!read_types)
938 break;
940 bytesread = 0;
941 idx = 0x200;
942 userdef_count = 0;
943 pointer_count = 0;
944 while (bytesread < pxdi->pDirTab32[i].cb)
946 static struct type_rec type;
947 static struct type_userdefrec udef;
948 static struct type_pointerrec point;
949 static ULONG ofs;
950 static BYTE str[256];
952 // Read the length of this subentry
953 ofs = tell(ModuleFile);
955 read(ModuleFile, &type, sizeof(type));
956 bytesread += sizeof(type);
958 switch (type.type)
960 case TYPE_USERDEF:
961 if (userdef_count >= MAX_USERDEFS)
962 break;
964 read(ModuleFile, &udef, sizeof(udef));
965 read(ModuleFile, str, udef.name_len);
966 str[udef.name_len] = 0;
968 // Insert userdef in table
969 one_userdef[userdef_count].idx = idx;
970 one_userdef[userdef_count].type_index = udef.type_index;
971 memcpy(one_userdef[userdef_count].name,
972 str,
973 _min(udef.name_len + 1, 32));
974 one_userdef[userdef_count].name[32] = 0;
975 userdef_count++;
976 break;
978 case TYPE_POINTER:
979 if (pointer_count >= MAX_POINTERS)
980 break;
982 read(ModuleFile, &point, sizeof(point));
983 read(ModuleFile, str, point.name_len);
984 str[point.name_len] = 0;
986 // Insert userdef in table
987 one_pointer[pointer_count].idx = idx;
988 one_pointer[pointer_count].type_index = point.type_index;
989 memcpy(one_pointer[pointer_count].name,
990 str,
991 _min(point.name_len + 1, 32));
992 one_pointer[pointer_count].name[32] = 0;
993 one_pointer[pointer_count].type_qual = type.type_qual;
994 pointer_count++;
995 break;
998 ++idx;
1000 bytesread += type.length;
1002 lseek(ModuleFile, ofs + type.length + 2, SEEK_SET);
1004 break;
1006 case SSTSRCLINES32:
1007 if (TrapSeg != pxdi->ssmod32.csBase)
1008 break;
1010 // read first line
1013 read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine));
1015 if (FirstLine.LineNum != 0)
1017 fprintf(LogFile, "Missing Line table information\n");
1018 break;
1019 } // endif
1020 numlines = FirstLine.numlines;
1021 // Other type of data skip 4 more bytes
1022 if (FirstLine.entry_type < 4)
1024 read(ModuleFile, (void *)&lSize, 4);
1025 if (FirstLine.entry_type == 3)
1026 lseek(ModuleFile, lSize, SEEK_CUR);
1029 while (FirstLine.entry_type == 3);
1031 for (j = 0; j < numlines; j++)
1033 switch (FirstLine.entry_type)
1035 case 0:
1036 read(ModuleFile, (void *)&LineEntry, sizeof(LineEntry));
1037 // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
1038 // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
1039 if ( (LineEntry.LineNum)
1040 && (LineEntry.Offset + pxdi->ssmod32.csOff
1041 <= TrapOff)
1042 && (LineEntry.Offset + pxdi->ssmod32.csOff >= NrLine)
1045 NrLine = LineEntry.Offset;
1046 NrFile = LineEntry.FileNum;
1047 /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ",
1048 * ssmod32.csBase,LineEntry.Offset,
1049 * LineEntry.LineNum); */
1050 sprintf(pxdi->szNrLine, "% 6hu", LineEntry.LineNum);
1052 break;
1054 case 1:
1055 lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR);
1056 break;
1058 case 2:
1059 lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR);
1060 break;
1062 case 3:
1063 lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR);
1064 break;
1066 case 4:
1067 lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR);
1068 break;
1073 if (NrFile != 0)
1075 // file found:
1076 read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo));
1077 namelen = 0;
1078 for (j = 1; j <= FileInfo.file_count; j++)
1080 namelen = 0;
1081 read(ModuleFile, (void *)&namelen, 1);
1082 read(ModuleFile, (void *)ename, namelen);
1083 if (j == NrFile)
1084 break;
1086 ename[namelen] = '\0';
1087 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
1088 sprintf(pxdi->szNrFile, "%11.11s ", ename);
1090 else
1092 // strcat(szNrLine,"\n"); avoid new line for empty name fill
1093 strcpy(pxdi->szNrFile, "file? ");
1094 } // endif
1095 break;
1096 } // end switch
1098 i++;
1099 } // end while modindex
1100 } // End While i < numdir
1101 free(pxdi->pDirTab32);
1102 return (0);
1106 * Read16CodeView:
1107 * parses 16-bit debug code.
1108 * Called from dbgPrintDebugInfo for 16-bit modules.
1111 static int Read16CodeView(FILE *LogFile, // in: text log file to write to
1112 PXDEBUGINFO pxdi,
1113 int fh,
1114 int TrapSeg,
1115 int TrapOff,
1116 CHAR *FileName)
1118 static unsigned short int offset,
1119 NrPublic, NrLine,
1120 numdir,
1121 namelen, numlines,
1122 line;
1123 static int ModIndex;
1124 static int bytesread, i, j;
1126 ModIndex = 0;
1127 // See if any CODEVIEW info
1128 if (lseek(fh, -8L, SEEK_END) == -1)
1130 fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
1131 return (18);
1134 if (read(fh, (void *)&G_eodbug, 8) == -1)
1136 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
1137 return (19);
1139 if (G_eodbug.dbug != DBUGSIG)
1141 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1142 return (100);
1145 if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
1147 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
1148 return (20);
1151 if (read(fh, (void *)&pxdi->base, 8) == -1)
1153 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
1154 return (21);
1157 if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1)
1159 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
1160 return (22);
1163 if (read(fh, (void *)&numdir, 2) == -1)
1165 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
1166 return (23);
1169 // Read dir table into buffer
1170 if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
1172 fprintf(LogFile, "Out of memory!");
1173 return (-1);
1176 if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1)
1178 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
1179 free(pxdi->pDirTab);
1180 return (24);
1183 i = 0;
1184 while (i < numdir)
1186 if (pxdi->pDirTab[i].sst != SSTMODULES)
1188 i++;
1189 continue;
1191 NrPublic = 0x0;
1192 NrLine = 0x0;
1193 // point to subsection
1194 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1195 read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE));
1196 read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize);
1197 ModIndex = pxdi->pDirTab[i].modindex;
1198 ModName[pxdi->ssmod.csize] = '\0';
1199 i++;
1200 while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir)
1202 // point to subsection
1203 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1204 switch (pxdi->pDirTab[i].sst)
1206 case SSTPUBLICS:
1207 bytesread = 0;
1208 while (bytesread < pxdi->pDirTab[i].cb)
1210 bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub));
1211 bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize);
1212 ename[pxdi->sspub.csize] = '\0';
1213 if ((pxdi->sspub.segment == TrapSeg) &&
1214 (pxdi->sspub.offset <= TrapOff) &&
1215 (pxdi->sspub.offset >= NrPublic))
1217 NrPublic = pxdi->sspub.offset;
1218 sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n",
1219 (pxdi->sspub.type == 1) ? " Abs" : " ", ename,
1220 ModName, // ()
1221 pxdi->sspub.segment,
1222 pxdi->sspub.offset
1226 break;
1228 case SSTSRCLINES2:
1229 case SSTSRCLINES:
1230 if (TrapSeg != pxdi->ssmod.csBase)
1231 break;
1232 namelen = 0;
1233 read(fh, (void *)&namelen, 1);
1234 read(fh, (void *)ename, namelen);
1235 ename[namelen] = '\0';
1236 // skip 2 zero bytes
1237 if (pxdi->pDirTab[i].sst == SSTSRCLINES2)
1238 read(fh, (void *)&numlines, 2);
1239 read(fh, (void *)&numlines, 2);
1240 for (j = 0; j < numlines; j++)
1242 read(fh, (void *)&line, 2);
1243 read(fh, (void *)&offset, 2);
1244 if (offset <= TrapOff && offset >= NrLine)
1246 NrLine = offset;
1247 sprintf(pxdi->szNrFile, "% 12.12s ", ename);
1248 sprintf(pxdi->szNrLine, "% 6hu", line);
1249 /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
1250 * ssmod.csBase,offset,line,ModName,ename); */
1253 break;
1254 } // end switch
1255 i++;
1256 } // end while modindex
1257 } // End While i < numdir
1258 free(pxdi->pDirTab);
1259 return (0);
1262 /* ******************************************************************
1264 * PART 2: ANALYZE VARIABLES
1266 ********************************************************************/
1269 * var_value:
1270 * writes a description of a variable type to
1271 * the specified buffer, depending on "type".
1273 *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
1276 static VOID var_value(void *varptr, // in: address of the variable on the stack
1277 char *pszBuf, // out: information
1278 BYTE type) // in: type; if >= 32, we'll call DosQueryMem
1280 ULONG Size = 1,
1281 Attr = 0;
1283 if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
1285 sprintf(pszBuf, "type %d, DosQueryMem failed", type);
1286 return;
1289 if ((Attr & PAG_READ) == 0)
1291 sprintf(pszBuf, "type %d, read-access to value denied", type);
1292 return;
1295 if (type == 0)
1296 sprintf(pszBuf, "%hd", *(signed char*)varptr);
1297 else if (type == 1)
1298 sprintf(pszBuf, "%hd", *(signed short*)varptr);
1299 else if (type == 2)
1300 sprintf(pszBuf, "%ld", *(signed long*)varptr);
1301 else if (type == 4)
1302 sprintf(pszBuf, "%hu", *(BYTE*) varptr);
1303 else if (type == 5)
1304 sprintf(pszBuf, "%hu", *(USHORT*)varptr);
1305 else if (type == 6)
1306 sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
1307 else if (type == 8)
1308 sprintf(pszBuf, "%f", *(float*)varptr);
1309 else if (type == 9)
1310 sprintf(pszBuf, "%f", *(double*)varptr);
1311 else if (type == 10)
1312 sprintf(pszBuf, "%f", (double)(*(long double*)varptr));
1313 else if (type == 16)
1314 sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
1315 else if (type == 17)
1316 sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE");
1317 else if (type == 18)
1318 sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE");
1319 else if (type == 20)
1320 sprintf(pszBuf, "%c", *(char*)varptr);
1321 else if (type == 21)
1322 sprintf(pszBuf, "%hd", (*(short*)varptr));
1323 else if (type == 22)
1324 sprintf(pszBuf, "%ld", *(long*)varptr);
1325 else if (type == 23)
1326 sprintf(pszBuf, "void");
1327 else if (type >= 32)
1329 sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr));
1330 if (Attr & PAG_FREE)
1332 strcat(pszBuf, " unallocated memory");
1334 else
1336 if ((Attr & PAG_COMMIT) == 0x0U)
1338 strcat(pszBuf, " uncommitted");
1339 } // endif
1340 if ((Attr & PAG_WRITE) == 0x0U)
1342 strcat(pszBuf, " unwritable");
1343 } // endif
1344 if ((Attr & PAG_READ) == 0x0U)
1346 strcat(pszBuf, " unreadable");
1347 } // endif
1348 } // endif
1349 } // endif
1350 else
1351 sprintf(pszBuf, "Unknown type %d", type);
1355 * search_userdefs:
1356 * searches the table of userdef's-
1357 * Return TRUE if found.
1360 static BOOL search_userdefs(FILE *LogFile, // in: text log file to write to
1361 ULONG stackofs,
1362 USHORT var_no)
1364 USHORT pos;
1366 for (pos = 0;
1367 pos < userdef_count;
1368 pos++)
1370 if (one_userdef[pos].idx == autovar_def[var_no].type_idx)
1372 if ( (one_userdef[pos].type_index >= 0x80)
1373 // && (one_userdef[pos].type_index <= 0xDA)
1376 static char sszVar3[500] = "complex";
1377 if (one_userdef[pos].type_index <= 0xDA)
1378 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1379 sszVar3,
1380 one_userdef[pos].type_index - 0x80);
1382 fprintf(LogFile,
1383 " %- 6ld %- 20.20s %- 33.33s %s (user)\n",
1384 autovar_def[var_no].stack_offset, // stack offset
1385 autovar_def[var_no].name, // identifier
1386 one_userdef[pos].name, // type name
1387 sszVar3 // composed by var_value
1389 return TRUE;
1391 else
1392 return FALSE;
1396 return FALSE;
1400 * search_pointers:
1404 static BOOL search_pointers(FILE *LogFile, // in: text log file to write to
1405 ULONG stackofs,
1406 USHORT var_no)
1408 USHORT pos, upos;
1409 static BYTE str[35];
1410 static char sszVar[500];
1412 // BYTE type_index;
1414 for (pos = 0;
1415 ( (pos < pointer_count)
1416 && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
1418 pos++);
1420 if (pos < pointer_count)
1422 if ( (one_pointer[pos].type_index >= 0x80)
1423 && (one_pointer[pos].type_index <= 0xDA)
1426 strcpy(str, type_name[one_pointer[pos].type_index - 0x80]);
1427 strcat(str, " *");
1428 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1429 sszVar,
1430 32);
1431 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1432 autovar_def[var_no].stack_offset,
1433 autovar_def[var_no].name,
1434 str,
1435 sszVar);
1436 return TRUE;
1438 else
1440 // If the result isn't a simple type, look for it in the other lists
1441 for (upos = 0;
1442 ( (upos < userdef_count)
1443 && (one_userdef[upos].idx != one_pointer[pos].type_index)
1445 upos++)
1448 if (upos < userdef_count)
1450 strcpy(str, one_userdef[upos].name);
1451 strcat(str, " *");
1452 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1453 sszVar,
1454 32);
1455 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1456 autovar_def[var_no].stack_offset,
1457 autovar_def[var_no].name,
1458 str,
1459 sszVar);
1460 return TRUE;
1462 else
1464 // if it isn't a userdef, for now give up and just print
1465 // as much as we know
1466 sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index);
1468 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1469 sszVar,
1470 32);
1471 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1472 autovar_def[var_no].stack_offset,
1473 autovar_def[var_no].name,
1474 str,
1475 sszVar);
1477 return TRUE;
1482 return FALSE;
1486 *@@ dbgPrintVariables:
1487 * Dumps variables for the specified stack offset
1488 * to the specified log file.
1490 * New with V0.84.
1493 void dbgPrintVariables(FILE *LogFile, // in: text log file to write to
1494 ULONG stackofs)
1496 USHORT n; // , pos;
1497 BOOL AutoVarsFound = FALSE;
1499 if (/* 1 || */ func_ofs == pubfunc_ofs)
1501 for (n = 0;
1502 n < var_ofs;
1503 n++)
1505 if (AutoVarsFound == FALSE)
1507 AutoVarsFound = TRUE;
1508 fprintf(LogFile, " List of auto variables at EBP %p in %s:\n",
1509 (PVOID)stackofs,
1510 func_name);
1511 fprintf(LogFile, " Offset Name Type Value \n");
1512 fprintf(LogFile, " ������ �������������������� ��������������������������������� �����������������\n");
1515 // If it's one of the simple types
1516 if ( (autovar_def[n].type_idx >= 0x80)
1517 && (autovar_def[n].type_idx <= 0xDA)
1520 static char sszVar2[500];
1522 var_value((void *)(stackofs + autovar_def[n].stack_offset),
1523 sszVar2,
1524 autovar_def[n].type_idx - 0x80);
1526 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
1527 autovar_def[n].stack_offset,
1528 autovar_def[n].name,
1529 type_name[autovar_def[n].type_idx - 0x80],
1530 sszVar2);
1532 else
1533 { // Complex type, check if we know what it is
1534 if (!search_userdefs(LogFile, stackofs, n))
1536 if (!search_pointers(LogFile, stackofs, n))
1538 fprintf(LogFile, " %- 6ld %-20.20s 0x%X (unknown)\n",
1539 autovar_def[n].stack_offset,
1540 autovar_def[n].name,
1541 autovar_def[n].type_idx);
1546 /* if (AutoVarsFound == FALSE)
1548 fprintf(LogFile, " No auto variables found in %s.\n", func_name);
1549 } */
1550 fprintf(LogFile, "\n");
1554 /* ******************************************************************
1556 * PART 3: ANALYZE SYMBOL (.SYM) FILE
1558 ********************************************************************/
1561 *@@ dbgPrintSYMInfo:
1562 * this gets called by dbgPrintStack if dbgPrintDebugInfo
1563 * failed (because no debug code was found) to check if
1564 * maybe a SYM file with the same filename exists and try
1565 * to get the info from there.
1567 * This gets called for every line of the stack
1568 * walk, but only if getting the information from
1569 * the debug code failed, e.g. because no debug code
1570 * was available for an address.
1572 * The file pointer is in the "Source file" column
1573 * every time this gets called.
1575 * New with V0.84.
1577 * Returns 0 if reading the SYM file was successful.
1579 *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
1582 int dbgPrintSYMInfo(FILE *LogFile, // in: text log file to write to
1583 CHAR *SymFileName, // in: SYM file name (can be fully q'fied)
1584 ULONG Object,
1585 ULONG TrapOffset)
1587 static FILE *SymFile;
1588 static MAPDEF MapDef;
1589 static SEGDEF SegDef;
1590 static SYMDEF32 SymDef32;
1591 static SYMDEF16 SymDef16;
1592 static char Buffer[256];
1593 static int SegNum, SymNum, LastVal;
1594 static unsigned long int SegOffset,
1595 SymOffset, SymPtrOffset;
1597 // open .SYM file
1598 #ifdef DEBUG_SYMDUMP
1599 fprintf(LogFile,"Dump of '%s' for object %d\n",SymFileName,Object);
1600 #endif
1601 SymFile = fopen(SymFileName, "rb");
1602 if (SymFile == 0)
1603 return (2);
1605 // read in first map definition
1606 fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
1607 #ifdef DEBUG_SYMDUMP
1608 Buffer[0] = MapDef.achModName[0];
1609 fread(&Buffer[1], 1, MapDef.cbModName-1, SymFile);
1610 Buffer[MapDef.cbModName] = 0x00;
1611 fprintf(LogFile,"Module name '%s'\n",Buffer);
1612 #endif
1614 SegOffset = SEGDEFOFFSET(MapDef);
1615 #ifdef DEBUG_SYMDUMP
1616 fprintf(LogFile,"SegOffset %0x\n",SegOffset);
1617 #endif
1619 // go thru all segments
1620 for (SegNum = 0;
1621 SegNum < MapDef.cSegs;
1622 SegNum++)
1624 #ifdef DEBUG_SYMDUMP
1625 fprintf(LogFile,"Scanning segment #%d Offset %08X\n",SegNum,SegOffset);
1626 #endif
1627 if (fseek(SymFile, SegOffset, SEEK_SET))
1628 // seek error
1629 return (3);
1631 // read in segment definition
1632 fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
1633 #ifdef DEBUG_SYMDUMP
1634 Buffer[0] = 0x00;
1635 if (SegDef.cbSegName>0) {
1636 Buffer[0] = SegDef.achSegName[0];
1637 fread(&Buffer[1], 1, SegDef.cbSegName-1, SymFile);
1638 Buffer[SegDef.cbSegName] = 0x00;
1640 fprintf(LogFile,"Segment name '%s', number %d, flags %02x\n",Buffer,SegNum,SegDef.bFlags);
1641 #endif
1643 if (SegNum == Object)
1645 // stack object found:
1646 Buffer[0] = 0x00;
1647 LastVal = 0;
1649 // go thru all symbols in this object
1650 #ifdef DEBUG_SYMDUMP
1651 fprintf(LogFile,"Scanning #%d symbols\n",SegDef.cSymbols);
1652 #endif
1653 for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
1655 SymPtrOffset=SYMDEFOFFSET(SegOffset,SegDef,SymNum);
1656 fseek(SymFile,SymPtrOffset,SEEK_SET);
1657 fread(&SymOffset,sizeof(unsigned short int),1,SymFile);
1658 fseek(SymFile,SymOffset+SegOffset,SEEK_SET);
1659 if (SegDef.bFlags & 0x01)
1661 // 32-bit symbol:
1662 fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
1663 if (SymDef32.wSymVal > TrapOffset)
1665 // symbol found
1666 fprintf(LogFile,
1667 "between %s + 0x%lX ",
1668 Buffer,
1669 TrapOffset - LastVal);
1670 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1671 LINEDEFOFFSET(SegDef)
1672 ); */
1673 fprintf(LogFile, "\n");
1676 LastVal = SymDef32.wSymVal;
1677 Buffer[0] = SymDef32.achSymName[0];
1678 fread(&Buffer[1], 1, SymDef32.cbSymName-1, SymFile);
1679 Buffer[SymDef32.cbSymName] = 0x00;
1680 #ifdef DEBUG_SYMDUMP
1681 fprintf(LogFile,"32 Bit Symbol Address %08p <%s> \n",SymDef32.wSymVal,Buffer);
1682 #endif
1684 if (SymDef32.wSymVal > TrapOffset)
1686 // symbol found, as above
1687 fprintf(LogFile,
1689 "and %s - 0x%lX ",
1690 Buffer,
1691 LastVal - TrapOffset);
1692 fprintf(LogFile, "\n");
1693 break;
1696 else
1698 // 16-bit symbol:
1699 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
1700 if (SymDef16.wSymVal > TrapOffset)
1702 fprintf(LogFile,
1703 "between %s + %lX\n",
1704 Buffer,
1705 TrapOffset - LastVal);
1707 LastVal = SymDef16.wSymVal;
1708 Buffer[0] = SymDef16.achSymName[0];
1709 fread(&Buffer[1], 1, SymDef16.cbSymName-1, SymFile);
1710 Buffer[SymDef16.cbSymName] = 0x00;
1711 if (SymDef16.wSymVal > TrapOffset)
1713 fprintf(LogFile,
1715 "and %s - %lX\n",
1716 Buffer,
1717 LastVal - TrapOffset);
1718 break;
1720 #ifdef DEBUG_SYMDUMP
1721 fprintf(LogFile,"16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal);
1722 #endif
1723 } // endif
1725 break;
1726 } // endif
1727 SegOffset = NEXTSEGDEFOFFSET(SegDef);
1728 } // endwhile
1729 fclose(SymFile);
1730 return (0); // no error
1733 /* ******************************************************************
1735 * PART 4: dbgPrintStack
1737 ********************************************************************/
1740 *@@ dbgPrintStackFrame:
1741 * parses and dumps one stack frame.
1742 * Called from excPrintStackFrame.
1744 * This calls dbgPrintDebugInfo and, if
1745 * that fails, dbgPrintSYMInfo.
1747 *@@added V0.9.2 (2000-03-10) [umoeller]
1748 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1749 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1752 BOOL dbgPrintStackFrame(FILE *LogFile,
1753 PSZ pszModuleName, // in: module name (fully q'fied)
1754 ULONG ulObject,
1755 ULONG ulOffset)
1757 APIRET arc = 0;
1758 // "Source file"... columns
1760 //YD do not use debug info
1761 #define ENABLE_DEBUG_INFO
1762 #ifdef ENABLE_DEBUG_INFO
1763 // first attempt to analyze the debug code
1764 arc = dbgPrintDebugInfo(LogFile,
1765 pszModuleName,
1766 ulObject,
1767 ulOffset);
1768 #else
1769 arc = 1;
1770 #endif
1772 // if no debug code is available, analyze
1773 // the SYM file instead
1774 if (arc != NO_ERROR)
1776 CHAR szSymName[CCHMAXPATH];
1777 strcpy(szSymName, pszModuleName);
1778 strcpy(szSymName + strlen(szSymName) - 3, "SYM");
1779 arc = dbgPrintSYMInfo(LogFile,
1780 szSymName,
1781 ulObject,
1782 ulOffset);
1783 if (arc != 0)
1785 // SYM file not found in current directory:
1786 // check the SYM files in the \OS2 directory,
1787 // depending on the OS/2 version level:
1788 CHAR szSymFile2[CCHMAXPATH];
1789 PSZ pszFilename = strrchr(szSymName, '\\');
1790 if (pszFilename)
1792 PSZ pszVersionDir = "WARP4";
1793 ULONG aulBuf[3];
1795 DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
1796 QSV_VERSION_MINOR, // 12
1797 &aulBuf, sizeof(aulBuf));
1798 // Warp 3 is reported as 20.30
1799 // Warp 4 is reported as 20.40
1800 // Aurora is reported as 20.45
1802 if (aulBuf[0] == 20)
1804 if (aulBuf[1] == 30)
1805 // Warp 3:
1806 pszVersionDir = "WARP3";
1807 else if (aulBuf[1] >= 40)
1808 // Warp 4 or higher:
1809 // (NOTE: Warp 4 FP 13 now returns 45 also,
1810 // but the SYM files are still in the WARP4 directory...)
1811 // V0.9.3 (2000-04-26) [umoeller]
1812 pszVersionDir = "WARP4";
1815 pszFilename++;
1816 sprintf(szSymFile2,
1817 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1818 doshQueryBootDrive(),
1819 pszVersionDir,
1820 pszFilename);
1821 arc = dbgPrintSYMInfo(LogFile,
1822 szSymFile2,
1823 ulObject,
1824 ulOffset);
1826 // V0.9.3 (2000-04-26) [umoeller]
1827 if ( (arc != 0) // still not found
1828 && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13?
1831 // Warp Server for e-Business (aka Warp 4.5):
1832 // we use the SYM files for the UNI kernel,
1833 // I have found no way to find out whether
1834 // we're running on an SMP kernel
1835 sprintf(szSymFile2,
1836 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1837 doshQueryBootDrive(),
1838 "WARP45_U",
1839 pszFilename);
1840 arc = dbgPrintSYMInfo(LogFile,
1841 szSymFile2,
1842 ulObject,
1843 ulOffset);
1848 if (arc == 2) // file not found
1849 fprintf(LogFile,
1850 "Cannot find symbol file %s\n",
1851 szSymName);
1852 else if (arc != 0)
1853 fprintf(LogFile,
1854 "Error %lu reading symbol file %s\n",
1855 arc,
1856 szSymName);
1859 return (arc == NO_ERROR);
1863 *@@ dbgPrintStack:
1864 * this takes stack data from the TIB and
1865 * context record data structures and tries
1866 * to analyse what the different stack frames
1867 * point to.
1869 * For each stack frame, this calls dbgPrintDebugInfo,
1870 * and, if that fails, dbgPrintSYMInfo.
1872 * New with V0.84.
1874 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1877 VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to
1878 PUSHORT StackBottom,
1879 PUSHORT StackTop,
1880 PUSHORT Ebp,
1881 PUSHORT ExceptionAddress)
1883 PUSHORT RetAddr = 0;
1884 PUSHORT LastEbp = 0;
1885 APIRET rc = 0;
1886 ULONG Size = 0,
1887 Attr = 0;
1888 USHORT Cs = 0,
1889 Ip = 0,
1890 // Bp,
1891 Sp = 0;
1892 static char Name[CCHMAXPATH];
1893 HMODULE hMod = 0;
1894 ULONG ObjNum = 0;
1895 ULONG Offset = 0;
1896 BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru
1898 // Note: we can't handle stacks bigger than 64K for now...
1899 Sp = (USHORT) (((ULONG) StackBottom) >> 16);
1900 // Bp = ;
1902 if (!f32bit)
1903 Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
1905 fprintf(LogFile, "\n\nCall stack:\n");
1906 fprintf(LogFile, " Source Line Nearest\n");
1907 fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n");
1908 fprintf(LogFile, " �������� ��������- �������� ���� ������������ ����� ������������-\n");
1912 Size = 10;
1913 rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
1914 if (rc != NO_ERROR)
1916 fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
1917 break;
1919 if (!(Attr & PAG_COMMIT))
1921 fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
1922 break;
1924 if (Size < 10)
1926 fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
1927 break;
1930 if (fExceptionAddress)
1931 RetAddr = ExceptionAddress;
1932 else
1933 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1935 if (RetAddr == (PUSHORT) 0x00000053)
1937 // For some reason there's a "return address" of 0x53 following
1938 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1939 // at the real return address. This has something to do with
1940 // thunking from 32bits to 16bits...
1941 // Serious kludge, and it's probably dependent on versions of C(++)
1942 // runtime or OS, but it works for now!
1943 Ebp += 22;
1944 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1947 // Get the (possibly) 16bit CS and IP
1948 if (fExceptionAddress)
1950 Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
1951 Ip = (USHORT) (ULONG) ExceptionAddress;
1953 else
1955 Cs = *(Ebp + 2);
1956 Ip = *(Ebp + 1);
1959 // if the return address points to the stack then it's really just
1960 // a pointer to the return address (UGH!).
1961 if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp
1963 RetAddr = (PUSHORT) (*((PULONG) RetAddr));
1965 if (Ip == 0 && *Ebp == 0)
1967 // End of the stack so these are both shifted by 2 bytes:
1968 Cs = *(Ebp + 3);
1969 Ip = *(Ebp + 2);
1972 // 16bit programs have on the stack:
1973 // BP:IP:CS
1974 // where CS may be thunked
1976 // in dump swapped
1977 // BP IP CS BP CS IP
1978 // 4677 53B5 F7D0 7746 D0F7 B553
1980 // 32bit programs have:
1981 // EBP:EIP
1982 // and you'd have something like this (with SP added) (not
1983 // accurate values)
1985 // in dump swapped
1986 // EBP EIP EBP EIP
1987 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1989 // So the basic difference is that 32bit programs have a 32bit
1990 // EBP and we can attempt to determine whether we have a 32bit
1991 // EBP by checking to see if its 'selector' is the same as SP.
1992 // Note that this technique limits us to checking stacks < 64K.
1994 // Soooo, if IP (which maps into the same USHORT as the swapped
1995 // stack page in EBP) doesn't point to the stack (i.e. it could
1996 // be a 16bit IP) then see if CS is valid (as is or thunked).
1998 // Note that there's the possibility of a 16bit return address
1999 // that has an offset that's the same as SP so we'll think it's
2000 // a 32bit return address and won't be able to successfully resolve
2001 // its details.
2002 if (Ip != Sp)
2004 if (DosSizeSeg(Cs, &Size) == NO_ERROR)
2006 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
2007 f32bit = FALSE;
2009 else if (DosSizeSeg((Cs << 3) + 7, &Size) == NO_ERROR)
2011 Cs = (Cs << 3) + 7;
2012 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
2013 f32bit = FALSE;
2015 else
2016 f32bit = TRUE;
2018 else
2019 f32bit = TRUE;
2022 // "EBP" column
2023 if (fExceptionAddress)
2024 fprintf(LogFile, " Trap -> ");
2025 else
2026 fprintf(LogFile, " %8.8lX ", (ULONG)Ebp);
2028 // "Address" column
2029 if (f32bit)
2030 fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr);
2031 else
2032 fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip);
2034 // Version check omitted; the following requires
2035 // OS/2 2.10 or later (*UM)
2036 // if (Version[0] >= 20 && Version[1] >= 10)
2038 // Make a 'tick' sound to let the user know we're still alive
2039 DosBeep(2000, 10);
2041 Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
2043 // "Module"/"Object" columns
2044 rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
2045 if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
2047 fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
2048 break; // avoid infinite loops
2050 else
2052 rc = DosQueryModFromEIP(&hMod,
2053 &ObjNum,
2054 sizeof(Name), Name,
2055 &Offset,
2056 (PVOID)RetAddr);
2057 if ( (rc == NO_ERROR)
2058 // && (ObjNum != -1)
2061 // static char szJunk[_MAX_FNAME];
2062 static char szName[_MAX_FNAME];
2064 DosQueryModuleName(hMod, sizeof(Name), Name);
2065 // _splitpath(Name, szJunk, szJunk, szName, szJunk);
2067 // print module and object
2068 fprintf(LogFile, "%-8s %04lX ", szName, ObjNum + 1);
2070 if (strlen(Name) > 3)
2072 dbgPrintStackFrame(LogFile,
2073 Name,
2074 ObjNum,
2075 Offset);
2078 else
2079 fprintf(LogFile,
2080 "DosQueryModFromEIP failed, returned %lu\n",
2081 rc);
2085 if ( ((*Ebp) == 0)
2086 && ((*Ebp + 1) == 0)
2089 fprintf(LogFile, "End of call stack\n");
2090 break;
2093 if (!fExceptionAddress)
2095 LastEbp = Ebp;
2096 #if 0
2097 Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
2098 #else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2099 if (f32bit)
2100 Ebp = (PUSHORT) *(PULONG) LastEbp;
2101 else
2102 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
2103 #endif
2104 if (f32bit)
2106 dbgPrintVariables(LogFile, (ULONG) Ebp);
2107 } // endif
2109 if (Ebp < LastEbp)
2111 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
2112 break;
2115 else
2116 fExceptionAddress = FALSE;
2118 Size = 4;
2119 rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
2120 if ((rc != NO_ERROR) || (Size < 4))
2122 fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
2123 break;
2125 } while (TRUE);
2127 fprintf(LogFile, "\n");
2131 *@@ doshQueryBootDrive:
2132 * returns the letter of the boot drive as a
2133 * single (capital) character, which is useful for
2134 * constructing file names using sprintf and such.
2136 *@@changed V0.9.16 (2002-01-13) [umoeller]: optimized
2139 CHAR doshQueryBootDrive(VOID)
2141 // this can never change, so query this only once
2142 // V0.9.16 (2002-01-13) [umoeller]
2143 static CHAR cBootDrive = '\0';
2145 if (!cBootDrive)
2147 ULONG ulBootDrive;
2148 DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
2149 &ulBootDrive,
2150 sizeof(ulBootDrive));
2151 cBootDrive = (CHAR)ulBootDrive + 'A' - 1;
2154 return (cBootDrive);