source: trunk/src/helpers/debug.c@ 209

Last change on this file since 209 was 142, checked in by umoeller, 24 years ago

misc. updates

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