source: branches/branch-1-0/src/helpers/debug.c@ 368

Last change on this file since 368 was 229, checked in by umoeller, 23 years ago

Sources as of 1.0.0.

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