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

Last change on this file since 472 was 441, checked in by pr, 7 years ago

Sync. with trunk.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 71.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-2010 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
1043 free(pxdi->pDirTab32);
1044
1045 return 0;
1046}
1047
1048/*
1049 * Read16CodeView:
1050 * parses 16-bit debug code.
1051 * Called from dbgPrintDebugInfo for 16-bit modules.
1052 */
1053
1054STATIC int Read16CodeView(FILE *LogFile, // in: text log file to write to
1055 PXDEBUGINFO pxdi,
1056 int fh,
1057 int TrapSeg,
1058 int TrapOff,
1059 CHAR *FileName)
1060{
1061 static unsigned short int offset,
1062 NrPublic, NrLine,
1063 numdir,
1064 namelen, numlines,
1065 line;
1066 static int ModIndex;
1067 static int bytesread, i, j;
1068
1069 ModIndex = 0;
1070 // See if any CODEVIEW info
1071 if (lseek(fh, -8L, SEEK_END) == -1)
1072 {
1073 fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
1074 return 18;
1075 }
1076
1077 if (read(fh, (void *)&G_eodbug, 8) == -1)
1078 {
1079 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
1080 return 19;
1081 }
1082 if (G_eodbug.dbug != DBUGSIG)
1083 {
1084 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1085 return 100;
1086 }
1087
1088 if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
1089 {
1090 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
1091 return 20;
1092 }
1093
1094 if (read(fh, (void *)&pxdi->base, 8) == -1)
1095 {
1096 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
1097 return 21;
1098 }
1099
1100 if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1)
1101 {
1102 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
1103 return 22;
1104 }
1105
1106 if (read(fh, (void *)&numdir, 2) == -1)
1107 {
1108 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
1109 return 23;
1110 }
1111
1112 // Read dir table into buffer
1113 if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
1114 {
1115 fprintf(LogFile, "Out of memory!");
1116 return -1;
1117 }
1118
1119 if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1)
1120 {
1121 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
1122 free(pxdi->pDirTab);
1123 return 24;
1124 }
1125
1126 i = 0;
1127 while (i < numdir)
1128 {
1129 if (pxdi->pDirTab[i].sst != SSTMODULES)
1130 {
1131 i++;
1132 continue;
1133 }
1134 NrPublic = 0x0;
1135 NrLine = 0x0;
1136 // point to subsection
1137 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1138 read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE));
1139 read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize);
1140 ModIndex = pxdi->pDirTab[i].modindex;
1141 ModName[pxdi->ssmod.csize] = '\0';
1142 i++;
1143 while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir)
1144 {
1145 // point to subsection
1146 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1147 switch (pxdi->pDirTab[i].sst)
1148 {
1149 case SSTPUBLICS:
1150 bytesread = 0;
1151 while (bytesread < pxdi->pDirTab[i].cb)
1152 {
1153 bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub));
1154 bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize);
1155 ename[pxdi->sspub.csize] = '\0';
1156 if ((pxdi->sspub.segment == TrapSeg) &&
1157 (pxdi->sspub.offset <= TrapOff) &&
1158 (pxdi->sspub.offset >= NrPublic))
1159 {
1160 NrPublic = pxdi->sspub.offset;
1161 sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n",
1162 (pxdi->sspub.type == 1) ? " Abs" : " ", ename,
1163 ModName, // ()
1164 pxdi->sspub.segment,
1165 pxdi->sspub.offset
1166 );
1167 }
1168 }
1169 break;
1170
1171 case SSTSRCLINES2:
1172 case SSTSRCLINES:
1173 if (TrapSeg != pxdi->ssmod.csBase)
1174 break;
1175 namelen = 0;
1176 read(fh, (void *)&namelen, 1);
1177 read(fh, (void *)ename, namelen);
1178 ename[namelen] = '\0';
1179 // skip 2 zero bytes
1180 if (pxdi->pDirTab[i].sst == SSTSRCLINES2)
1181 read(fh, (void *)&numlines, 2);
1182 read(fh, (void *)&numlines, 2);
1183 for (j = 0; j < numlines; j++)
1184 {
1185 read(fh, (void *)&line, 2);
1186 read(fh, (void *)&offset, 2);
1187 if (offset <= TrapOff && offset >= NrLine)
1188 {
1189 NrLine = offset;
1190 sprintf(pxdi->szNrFile, "% 12.12s ", ename);
1191 sprintf(pxdi->szNrLine, "% 6hu", line);
1192 /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
1193 * ssmod.csBase,offset,line,ModName,ename); */
1194 }
1195 }
1196 break;
1197 } // end switch
1198 i++;
1199 } // end while modindex
1200 } // End While i < numdir
1201
1202 free(pxdi->pDirTab);
1203
1204 return 0;
1205}
1206
1207/* ******************************************************************
1208 *
1209 * PART 2: ANALYZE VARIABLES
1210 *
1211 ********************************************************************/
1212
1213/*
1214 * var_value:
1215 * writes a description of a variable type to
1216 * the specified buffer, depending on "type".
1217 *
1218 *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
1219 */
1220
1221STATIC VOID var_value(void *varptr, // in: address of the variable on the stack
1222 char *pszBuf, // out: information
1223 BYTE type) // in: type; if >= 32, we'll call DosQueryMem
1224{
1225 ULONG Size = 1,
1226 Attr = 0;
1227
1228 if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
1229 {
1230 sprintf(pszBuf, "type %d, DosQueryMem failed", type);
1231 return;
1232 }
1233
1234 if ((Attr & PAG_READ) == 0)
1235 {
1236 sprintf(pszBuf, "type %d, read-access to value denied", type);
1237 return;
1238 }
1239
1240 if (type == 0)
1241 sprintf(pszBuf, "%hd", *(signed char*)varptr);
1242 else if (type == 1)
1243 sprintf(pszBuf, "%hd", *(signed short*)varptr);
1244 else if (type == 2)
1245 sprintf(pszBuf, "%ld", *(signed long*)varptr);
1246 else if (type == 4)
1247 sprintf(pszBuf, "%hu", *(BYTE*) varptr);
1248 else if (type == 5)
1249 sprintf(pszBuf, "%hu", *(USHORT*)varptr);
1250 else if (type == 6)
1251 sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
1252 else if (type == 8)
1253 sprintf(pszBuf, "%f", *(float*)varptr);
1254 else if (type == 9)
1255 sprintf(pszBuf, "%f", *(double*)varptr);
1256 else if (type == 10)
1257 sprintf(pszBuf, "%f", (double)(*(long double*)varptr));
1258 else if (type == 16)
1259 sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
1260 else if (type == 17)
1261 sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE");
1262 else if (type == 18)
1263 sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE");
1264 else if (type == 20)
1265 sprintf(pszBuf, "%c", *(char*)varptr);
1266 else if (type == 21)
1267 sprintf(pszBuf, "%hd", (*(short*)varptr));
1268 else if (type == 22)
1269 sprintf(pszBuf, "%ld", *(long*)varptr);
1270 else if (type == 23)
1271 sprintf(pszBuf, "void");
1272 else if (type >= 32)
1273 {
1274 sprintf(pszBuf, "0x%p", (void*)(*(ULONG*)varptr));
1275 if (Attr & PAG_FREE)
1276 {
1277 strcat(pszBuf, " unallocated memory");
1278 }
1279 else
1280 {
1281 if ((Attr & PAG_COMMIT) == 0x0U)
1282 {
1283 strcat(pszBuf, " uncommitted");
1284 } // endif
1285 if ((Attr & PAG_WRITE) == 0x0U)
1286 {
1287 strcat(pszBuf, " unwritable");
1288 } // endif
1289 if ((Attr & PAG_READ) == 0x0U)
1290 {
1291 strcat(pszBuf, " unreadable");
1292 } // endif
1293 } // endif
1294 } // endif
1295 else
1296 sprintf(pszBuf, "Unknown type %d", type);
1297}
1298
1299/*
1300 * search_userdefs:
1301 * searches the table of userdef's-
1302 * Return TRUE if found.
1303 */
1304
1305STATIC BOOL search_userdefs(FILE *LogFile, // in: text log file to write to
1306 ULONG stackofs,
1307 USHORT var_no)
1308{
1309 USHORT pos;
1310
1311 for (pos = 0;
1312 pos < userdef_count;
1313 pos++)
1314 {
1315 if (one_userdef[pos].idx == autovar_def[var_no].type_idx)
1316 {
1317 if ( (one_userdef[pos].type_index >= 0x80)
1318 // && (one_userdef[pos].type_index <= 0xDA)
1319 )
1320 {
1321 static char sszVar3[500] = "complex";
1322 if (one_userdef[pos].type_index <= 0xDA)
1323 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1324 sszVar3,
1325 one_userdef[pos].type_index - 0x80);
1326
1327 fprintf(LogFile,
1328 " %- 6ld %- 20.20s %- 33.33s %s (user)\n",
1329 autovar_def[var_no].stack_offset, // stack offset
1330 autovar_def[var_no].name, // identifier
1331 one_userdef[pos].name, // type name
1332 sszVar3 // composed by var_value
1333 );
1334 return TRUE;
1335 }
1336 else
1337 return FALSE;
1338 }
1339 }
1340
1341 return FALSE;
1342}
1343
1344/*
1345 * search_pointers:
1346 *
1347 */
1348
1349STATIC BOOL search_pointers(FILE *LogFile, // in: text log file to write to
1350 ULONG stackofs,
1351 USHORT var_no)
1352{
1353 USHORT pos, upos;
1354 static BYTE str[35];
1355 static char sszVar[500];
1356
1357 // BYTE type_index;
1358
1359 for (pos = 0;
1360 ( (pos < pointer_count)
1361 && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
1362 );
1363 pos++);
1364
1365 if (pos < pointer_count)
1366 {
1367 if ( (one_pointer[pos].type_index >= 0x80)
1368 && (one_pointer[pos].type_index <= 0xDA)
1369 )
1370 {
1371 strcpy(str, type_name[one_pointer[pos].type_index - 0x80]);
1372 strcat(str, " *");
1373 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1374 sszVar,
1375 32);
1376 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr1)\n",
1377 autovar_def[var_no].stack_offset,
1378 autovar_def[var_no].name,
1379 str,
1380 sszVar);
1381 return TRUE;
1382 }
1383 else
1384 {
1385 // If the result isn't a simple type, look for it in the other lists
1386 for (upos = 0;
1387 ( (upos < userdef_count)
1388 && (one_userdef[upos].idx != one_pointer[pos].type_index)
1389 );
1390 upos++)
1391 ;
1392
1393 if (upos < userdef_count)
1394 {
1395 strcpy(str, one_userdef[upos].name);
1396 strcat(str, " *");
1397 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1398 sszVar,
1399 32);
1400 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr2)\n",
1401 autovar_def[var_no].stack_offset,
1402 autovar_def[var_no].name,
1403 str,
1404 sszVar);
1405 return TRUE;
1406 }
1407 else
1408 {
1409 // if it isn't a userdef, for now give up and just print
1410 // as much as we know
1411 sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index);
1412
1413 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1414 sszVar,
1415 32);
1416 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (ptr3)\n",
1417 autovar_def[var_no].stack_offset,
1418 autovar_def[var_no].name,
1419 str,
1420 sszVar);
1421
1422 return TRUE;
1423 }
1424 }
1425 }
1426
1427 return FALSE;
1428}
1429
1430/*
1431 *@@ dbgPrintVariables:
1432 * Dumps variables for the specified stack offset
1433 * to the specified log file.
1434 *
1435 * New with V0.84.
1436 */
1437
1438void dbgPrintVariables(FILE *LogFile, // in: text log file to write to
1439 ULONG stackofs)
1440{
1441 USHORT n; // , pos;
1442 BOOL AutoVarsFound = FALSE;
1443
1444 if (/* 1 || */ func_ofs == pubfunc_ofs)
1445 {
1446 for (n = 0;
1447 n < var_ofs;
1448 n++)
1449 {
1450 if (AutoVarsFound == FALSE)
1451 {
1452 AutoVarsFound = TRUE;
1453 fprintf(LogFile, " List of auto variables at EBP %p in %s:\n",
1454 (PVOID)stackofs,
1455 func_name);
1456 fprintf(LogFile, " Offset Name Type Value \n");
1457 fprintf(LogFile, " ÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
1458 }
1459
1460 // If it's one of the simple types
1461 if ( (autovar_def[n].type_idx >= 0x80)
1462 && (autovar_def[n].type_idx <= 0xDA)
1463 )
1464 {
1465 static char sszVar2[500];
1466
1467 var_value((void *)(stackofs + autovar_def[n].stack_offset),
1468 sszVar2,
1469 autovar_def[n].type_idx - 0x80);
1470
1471 fprintf(LogFile, " %- 6ld %- 20.20s %- 33.33s %s (simple)\n",
1472 autovar_def[n].stack_offset,
1473 autovar_def[n].name,
1474 type_name[autovar_def[n].type_idx - 0x80],
1475 sszVar2);
1476 }
1477 else
1478 { // Complex type, check if we know what it is
1479 if (!search_userdefs(LogFile, stackofs, n))
1480 {
1481 if (!search_pointers(LogFile, stackofs, n))
1482 {
1483 fprintf(LogFile, " %- 6ld %-20.20s 0x%X (unknown)\n",
1484 autovar_def[n].stack_offset,
1485 autovar_def[n].name,
1486 autovar_def[n].type_idx);
1487 }
1488 }
1489 }
1490 }
1491 /* if (AutoVarsFound == FALSE)
1492 {
1493 fprintf(LogFile, " No auto variables found in %s.\n", func_name);
1494 } */
1495 fprintf(LogFile, "\n");
1496 }
1497}
1498
1499/* ******************************************************************
1500 *
1501 * PART 3: ANALYZE SYMBOL (.SYM) FILE
1502 *
1503 ********************************************************************/
1504
1505/*
1506 *@@ dbgPrintSYMInfo:
1507 * this gets called by dbgPrintStack if dbgPrintDebugInfo
1508 * failed (because no debug code was found) to check if
1509 * maybe a SYM file with the same filename exists and try
1510 * to get the info from there.
1511 *
1512 * This gets called for every line of the stack
1513 * walk, but only if getting the information from
1514 * the debug code failed, e.g. because no debug code
1515 * was available for an address.
1516 *
1517 * The file pointer is in the "Source file" column
1518 * every time this gets called.
1519 *
1520 * New with V0.84.
1521 *
1522 * Returns 0 if reading the SYM file was successful.
1523 *
1524 *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
1525 */
1526
1527int dbgPrintSYMInfo(FILE *LogFile, // in: text log file to write to
1528 CHAR *SymFileName, // in: SYM file name (can be fully q'fied)
1529 ULONG Object,
1530 ULONG TrapOffset)
1531{
1532 static FILE *SymFile;
1533 static MAPDEF MapDef;
1534 static SEGDEF SegDef;
1535 static SYMDEF32 SymDef32;
1536 static SYMDEF16 SymDef16;
1537 static char Buffer[256];
1538 static int SegNum, SymNum, LastVal;
1539 static unsigned long int SegOffset,
1540 SymOffset, SymPtrOffset;
1541
1542 // open .SYM file
1543#ifdef DEBUG_SYMDUMP // V1.0.0 (2002-08-21) [paperino]
1544 fprintf(LogFile,"Dump of '%s' for object %d\n",SymFileName,Object);
1545#endif
1546 SymFile = fopen(SymFileName, "rb");
1547 if (SymFile == 0)
1548 return 2;
1549
1550 // read in first map definition
1551 fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
1552#ifdef DEBUG_SYMDUMP
1553 Buffer[0] = MapDef.achModName[0];
1554 fread(&Buffer[1], 1, MapDef.cbModName-1, SymFile);
1555 Buffer[MapDef.cbModName] = 0x00;
1556 fprintf(LogFile,"Module name '%s'\n",Buffer);
1557#endif
1558
1559 SegOffset = SEGDEFOFFSET(MapDef);
1560#ifdef DEBUG_SYMDUMP
1561 fprintf(LogFile,"SegOffset %0x\n",SegOffset);
1562#endif
1563
1564 // go thru all segments
1565 for (SegNum = 0;
1566 SegNum < MapDef.cSegs;
1567 SegNum++)
1568 {
1569#ifdef DEBUG_SYMDUMP
1570 fprintf(LogFile,"Scanning segment #%d Offset %08X\n",SegNum,SegOffset);
1571#endif
1572 if (fseek(SymFile, SegOffset, SEEK_SET))
1573 // seek error
1574 return 3;
1575
1576 // read in segment definition
1577 fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
1578 Buffer[0] = SegDef.achSegName[0];
1579 fread(&Buffer[1], 1, SegDef.cbSegName-1, SymFile);
1580 Buffer[SegDef.cbSegName] = 0x00;
1581#ifdef DEBUG_SYMDUMP
1582 fprintf(LogFile,"Segment name '%s', number %d, flags %02x\n",Buffer,SegNum,SegDef.bFlags);
1583#endif
1584
1585 if (SegNum == Object)
1586 {
1587 // stack object found:
1588 Buffer[0] = 0x00;
1589 LastVal = 0;
1590
1591 // go thru all symbols in this object
1592#ifdef DEBUG_SYMDUMP
1593 fprintf(LogFile,"Scanning #%d symbols\n",SegDef.cSymbols);
1594#endif
1595 for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
1596 {
1597 // fixed syms > 64 K V1.0.0 (2002-08-21) [paperino]
1598 if (SegDef.bFlags & 0x01)
1599 {
1600 // 32-bit symbol:
1601 fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
1602 if (SymDef32.wSymVal > TrapOffset)
1603 {
1604 // symbol found
1605 fprintf(LogFile,
1606 "between %s + 0x%lX ",
1607 Buffer,
1608 TrapOffset - LastVal);
1609 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1610 LINEDEFOFFSET(SegDef)
1611 ); */
1612 fprintf(LogFile, "\n");
1613 }
1614
1615 LastVal = SymDef32.wSymVal;
1616 Buffer[0] = SymDef32.achSymName[0];
1617 fread(&Buffer[1], 1, SymDef32.cbSymName-1, SymFile);
1618 Buffer[SymDef32.cbSymName] = 0x00;
1619#ifdef DEBUG_SYMDUMP
1620 fprintf(LogFile,"32 Bit Symbol Address %08p <%s> \n",SymDef32.wSymVal,Buffer);
1621#endif
1622
1623 if (SymDef32.wSymVal > TrapOffset)
1624 {
1625 // symbol found, as above
1626 fprintf(LogFile,
1627 " "
1628 "and %s - 0x%lX ",
1629 Buffer,
1630 LastVal - TrapOffset);
1631 fprintf(LogFile, "\n");
1632 break;
1633 }
1634 }
1635 else
1636 {
1637 // 16-bit symbol:
1638 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
1639 if (SymDef16.wSymVal > TrapOffset)
1640 {
1641 fprintf(LogFile,
1642 "between %s + %lX\n",
1643 Buffer,
1644 TrapOffset - LastVal);
1645 }
1646 LastVal = SymDef16.wSymVal;
1647 Buffer[0] = SymDef16.achSymName[0];
1648 fread(&Buffer[1], 1, SymDef16.cbSymName-1, SymFile);
1649 Buffer[SymDef16.cbSymName] = 0x00;
1650 if (SymDef16.wSymVal > TrapOffset)
1651 {
1652 fprintf(LogFile,
1653 " "
1654 "and %s - %lX\n",
1655 Buffer,
1656 LastVal - TrapOffset);
1657 break;
1658 }
1659#ifdef DEBUG_SYMDUMP
1660 fprintf(LogFile,"16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal);
1661#endif
1662 } // endif
1663 }
1664 break;
1665 } // endif
1666 SegOffset = NEXTSEGDEFOFFSET(SegDef);
1667 } // endwhile
1668
1669 fclose(SymFile);
1670
1671 return 0; // no error
1672}
1673
1674/* ******************************************************************
1675 *
1676 * PART 4: dbgPrintStack
1677 *
1678 ********************************************************************/
1679
1680/*
1681 *@@ dbgPrintStackFrame:
1682 * parses and dumps one stack frame.
1683 * Called from excPrintStackFrame.
1684 *
1685 * This calls dbgPrintDebugInfo and, if
1686 * that fails, dbgPrintSYMInfo.
1687 *
1688 *@@added V0.9.2 (2000-03-10) [umoeller]
1689 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1690 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1691 *@@changed V1.0.12 (2017-01-15) [rwalsh]: improve handling for Warp 4.5 SYM files
1692 */
1693
1694BOOL dbgPrintStackFrame(FILE *LogFile,
1695 PSZ pszModuleName, // in: module name (fully q'fied)
1696 ULONG ulObject,
1697 ULONG ulOffset)
1698{
1699 APIRET arc = 0;
1700 PSZ pszFilename;
1701 PSZ pszVersionDir;
1702 ULONG aulBuf[3];
1703 CHAR szSymName[CCHMAXPATH];
1704 CHAR szSymPath[CCHMAXPATH];
1705
1706 // look for .sym in the module's directory
1707 strcpy(szSymName, pszModuleName);
1708 strcpy(szSymName + strlen(szSymName) - 3, "SYM");
1709 if (!dbgPrintSYMInfo(LogFile, szSymName, ulObject, ulOffset))
1710 return TRUE;
1711
1712 pszFilename = strrchr(szSymName, '\\');
1713 if (!pszFilename)
1714 {
1715 fprintf(LogFile, "Cannot find symbol file for %s\n", pszModuleName);
1716 return FALSE;
1717 }
1718 pszFilename++;
1719
1720 // check the SYM files in the \OS2 directory,
1721 // depending on the OS/2 version level:
1722 DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_MINOR,
1723 &aulBuf, sizeof(aulBuf));
1724
1725 // Warp 3 is reported as 20.30
1726 // Warp 4 is reported as 20.40
1727 // WSEB is reported as 20.45
1728 // (NOTE: Warp 4 FP 13 now returns 45 also,
1729 // but the SYM files are still in the WARP4 directory)
1730
1731 // try the directories used by the "real" Warp 4.5 first
1732 if (aulBuf[1] == 45)
1733 {
1734 sprintf(szSymPath, "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1735 doshQueryBootDrive(), "WARP45", pszFilename);
1736 if (!dbgPrintSYMInfo(LogFile, szSymPath, ulObject, ulOffset))
1737 return TRUE;
1738
1739 // use the nbr of processors to decide which directory to search
1740 if (DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
1741 &aulBuf[2], sizeof(aulBuf[2]))
1742 || aulBuf[2] == 1)
1743 pszVersionDir = "WARP45_U";
1744 else
1745 pszVersionDir = "WARP45_S";
1746
1747 sprintf(szSymPath, "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1748 doshQueryBootDrive(), pszVersionDir, pszFilename);
1749 if (!dbgPrintSYMInfo(LogFile, szSymPath, ulObject, ulOffset))
1750 return TRUE;
1751 }
1752
1753 // deal with Warp 3 and Warp4 pre- and post-FP13
1754 if (aulBuf[1] == 30)
1755 pszVersionDir = "WARP3";
1756 else
1757 pszVersionDir = "WARP4";
1758
1759 sprintf(szSymPath, "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1760 doshQueryBootDrive(), pszVersionDir, pszFilename);
1761 arc = dbgPrintSYMInfo(LogFile, szSymPath, ulObject, ulOffset);
1762
1763 if (arc == 2)
1764 fprintf(LogFile, "Cannot find symbol file %s\n",
1765 szSymName);
1766 else if (arc != 0)
1767 fprintf(LogFile, "Error %lu reading symbol file %s\n",
1768 arc, szSymName);
1769
1770 return (arc == NO_ERROR);
1771}
1772
1773/*
1774 *@@ dbgPrintStack:
1775 * this takes stack data from the TIB and
1776 * context record data structures and tries
1777 * to analyse what the different stack frames
1778 * point to.
1779 *
1780 * For each stack frame, this calls dbgPrintDebugInfo,
1781 * and, if that fails, dbgPrintSYMInfo.
1782 *
1783 * New with V0.84.
1784 *
1785 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1786 *@@changed XWP V1.0.9 (2010-04-16) [pr]: fixed module name display bugs
1787 */
1788
1789VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to
1790 PUSHORT StackBottom,
1791 PUSHORT StackTop,
1792 PUSHORT Ebp,
1793 PUSHORT ExceptionAddress)
1794{
1795 PUSHORT RetAddr = 0;
1796 PUSHORT LastEbp = 0;
1797 APIRET rc = 0;
1798 ULONG Size = 0,
1799 Attr = 0;
1800 USHORT Cs = 0,
1801 Ip = 0,
1802 // Bp,
1803 Sp = 0;
1804 char Name[CCHMAXPATH];
1805 HMODULE hMod = 0;
1806 ULONG ObjNum = 0;
1807 ULONG Offset = 0;
1808 BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru
1809
1810 // Note: we can't handle stacks bigger than 64K for now...
1811 Sp = (USHORT) (((ULONG) StackBottom) >> 16);
1812 // Bp = ;
1813
1814 if (!f32bit)
1815 Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
1816
1817 fprintf(LogFile, "\n\nCall stack:\n");
1818 fprintf(LogFile, " Source Line Nearest\n");
1819 fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n");
1820 fprintf(LogFile, " ÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ- ÄÄÄÄÄÄÄÄ ÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ-\n");
1821
1822 do
1823 {
1824 Size = 10;
1825 rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
1826 if (rc != NO_ERROR)
1827 {
1828 fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
1829 break;
1830 }
1831 if (!(Attr & PAG_COMMIT))
1832 {
1833 fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
1834 break;
1835 }
1836 if (Size < 10)
1837 {
1838 fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
1839 break;
1840 }
1841
1842 if (fExceptionAddress)
1843 RetAddr = ExceptionAddress;
1844 else
1845 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1846
1847 if (RetAddr == (PUSHORT) 0x00000053)
1848 {
1849 // For some reason there's a "return address" of 0x53 following
1850 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1851 // at the real return address. This has something to do with
1852 // thunking from 32bits to 16bits...
1853 // Serious kludge, and it's probably dependent on versions of C(++)
1854 // runtime or OS, but it works for now!
1855 Ebp += 22;
1856 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1857 }
1858
1859 // Get the (possibly) 16bit CS and IP
1860 if (fExceptionAddress)
1861 {
1862 Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
1863 Ip = (USHORT) (ULONG) ExceptionAddress;
1864 }
1865 else
1866 {
1867 Cs = *(Ebp + 2);
1868 Ip = *(Ebp + 1);
1869 }
1870
1871 // if the return address points to the stack then it's really just
1872 // a pointer to the return address (UGH!).
1873 if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp
1874 )
1875 RetAddr = (PUSHORT) (*((PULONG) RetAddr));
1876
1877 if (Ip == 0 && *Ebp == 0)
1878 {
1879 // End of the stack so these are both shifted by 2 bytes:
1880 Cs = *(Ebp + 3);
1881 Ip = *(Ebp + 2);
1882 }
1883
1884 // 16bit programs have on the stack:
1885 // BP:IP:CS
1886 // where CS may be thunked
1887 //
1888 // in dump swapped
1889 // BP IP CS BP CS IP
1890 // 4677 53B5 F7D0 7746 D0F7 B553
1891 //
1892 // 32bit programs have:
1893 // EBP:EIP
1894 // and you'd have something like this (with SP added) (not
1895 // accurate values)
1896 //
1897 // in dump swapped
1898 // EBP EIP EBP EIP
1899 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1900 //
1901 // So the basic difference is that 32bit programs have a 32bit
1902 // EBP and we can attempt to determine whether we have a 32bit
1903 // EBP by checking to see if its 'selector' is the same as SP.
1904 // Note that this technique limits us to checking stacks < 64K.
1905 //
1906 // Soooo, if IP (which maps into the same USHORT as the swapped
1907 // stack page in EBP) doesn't point to the stack (i.e. it could
1908 // be a 16bit IP) then see if CS is valid (as is or thunked).
1909 //
1910 // Note that there's the possibility of a 16bit return address
1911 // that has an offset that's the same as SP so we'll think it's
1912 // a 32bit return address and won't be able to successfully resolve
1913 // its details.
1914 if (Ip != Sp)
1915 {
1916 if (DOS16SIZESEG(Cs, &Size) == NO_ERROR)
1917 {
1918 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1919 f32bit = FALSE;
1920 }
1921 else if (DOS16SIZESEG((Cs << 3) + 7, &Size) == NO_ERROR)
1922 {
1923 Cs = (Cs << 3) + 7;
1924 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1925 f32bit = FALSE;
1926 }
1927 else
1928 f32bit = TRUE;
1929 }
1930 else
1931 f32bit = TRUE;
1932
1933
1934 // "EBP" column
1935 if (fExceptionAddress)
1936 fprintf(LogFile, " Trap -> ");
1937 else
1938 fprintf(LogFile, " %8.8lX ", (ULONG)Ebp);
1939
1940 // "Address" column
1941 if (f32bit)
1942 fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr);
1943 else
1944 fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip);
1945
1946 // Version check omitted; the following requires
1947 // OS/2 2.10 or later (*UM)
1948 // if (Version[0] >= 20 && Version[1] >= 10)
1949 {
1950 // Make a 'tick' sound to let the user know we're still alive
1951 DosBeep(2000, 10);
1952
1953 Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
1954
1955 // "Module"/"Object" columns
1956 rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
1957 if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
1958 {
1959 fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
1960 break; // avoid infinite loops
1961 }
1962 else
1963 {
1964 rc = DOSQUERYMODFROMEIP(&hMod,
1965 &ObjNum,
1966 sizeof(Name), Name,
1967 &Offset,
1968 (PVOID)RetAddr);
1969 if ( (rc == NO_ERROR)
1970 // && (ObjNum != -1)
1971 )
1972 {
1973 DosQueryModuleName(hMod, sizeof(Name), Name);
1974 // print module and object
1975 fprintf(LogFile, "%-8s %04lX ", Name, ObjNum + 1);
1976
1977 if (strlen(Name) > 3)
1978 {
1979 // look for embedded debug info;
1980 // if that fails, look for a .sym file
1981 if (dbgPrintDebugInfo(LogFile,
1982 Name,
1983 ObjNum,
1984 Offset))
1985 dbgPrintStackFrame(LogFile,
1986 Name,
1987 ObjNum,
1988 Offset);
1989 }
1990 }
1991 else
1992 fprintf(LogFile,
1993 "DosQueryModFromEIP failed, returned %lu\n",
1994 rc);
1995 }
1996 }
1997
1998 if ( ((*Ebp) == 0)
1999 && ((*Ebp + 1) == 0)
2000 )
2001 {
2002 fprintf(LogFile, "End of call stack\n");
2003 break;
2004 }
2005
2006 if (!fExceptionAddress)
2007 {
2008 LastEbp = Ebp;
2009#if 0
2010 Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
2011#else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
2012 if (f32bit)
2013 Ebp = (PUSHORT) *(PULONG) LastEbp;
2014 else
2015 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
2016#endif
2017 if (f32bit)
2018 {
2019 dbgPrintVariables(LogFile, (ULONG) Ebp);
2020 } // endif
2021
2022 if (Ebp < LastEbp)
2023 {
2024 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
2025 break;
2026 }
2027 }
2028 else
2029 fExceptionAddress = FALSE;
2030
2031 Size = 4;
2032 rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
2033 if ((rc != NO_ERROR) || (Size < 4))
2034 {
2035 fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
2036 break;
2037 }
2038 } while (TRUE);
2039
2040 fprintf(LogFile, "\n");
2041}
2042
Note: See TracBrowser for help on using the repository browser.