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

Last change on this file since 86 was 68, checked in by umoeller, 24 years ago

Lotsa fixes from the last two weeks.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 71.0 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
364int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
365int 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
386VOID 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
619int 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
1051int 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
1216VOID 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
1300BOOL 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
1344BOOL 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, "between %s + 0x%lX ", Buffer, TrapOffset - LastVal);
1585 /* fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1586 LINEDEFOFFSET(SegDef)
1587 ); */
1588 fprintf(LogFile, "\n");
1589 }
1590
1591 LastVal = SymDef32.wSymVal;
1592 Buffer[0] = SymDef32.achSymName[0];
1593 fread(&Buffer[1], 1, SymDef32.cbSymName, SymFile);
1594 Buffer[SymDef32.cbSymName] = 0x00;
1595
1596 if (SymDef32.wSymVal > TrapOffset)
1597 {
1598 // symbol found, as above
1599 fprintf(LogFile, " "
1600 "and %s - 0x%lX ", Buffer, LastVal - TrapOffset);
1601 fprintf(LogFile, "\n");
1602 break;
1603 }
1604 /*printf("32 Bit Symbol <%s> Address %p\n",Buffer,SymDef32.wSymVal); */
1605 }
1606 else
1607 {
1608 // 16-bit symbol:
1609 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
1610 if (SymDef16.wSymVal > TrapOffset)
1611 {
1612 fprintf(LogFile, "between %s + %lX\n",
1613 Buffer,
1614 TrapOffset - LastVal);
1615 }
1616 LastVal = SymDef16.wSymVal;
1617 Buffer[0] = SymDef16.achSymName[0];
1618 fread(&Buffer[1], 1, SymDef16.cbSymName, SymFile);
1619 Buffer[SymDef16.cbSymName] = 0x00;
1620 if (SymDef16.wSymVal > TrapOffset)
1621 {
1622 fprintf(LogFile, " "
1623 "and %s - %lX\n",
1624 Buffer,
1625 LastVal - TrapOffset);
1626 break;
1627 }
1628 /*printf("16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal); */
1629 } // endif
1630 }
1631 break;
1632 } // endif
1633 SegOffset = NEXTSEGDEFOFFSET(SegDef);
1634 } // endwhile
1635 fclose(SymFile);
1636 return (0); // no error
1637}
1638
1639/* ******************************************************************
1640 *
1641 * PART 4: dbgPrintStack
1642 *
1643 ********************************************************************/
1644
1645/*
1646 *@@ dbgPrintStackFrame:
1647 * parses and dumps one stack frame.
1648 * Called from excPrintStackFrame.
1649 *
1650 * This calls dbgPrintDebugInfo and, if
1651 * that fails, dbgPrintSYMInfo.
1652 *
1653 *@@added V0.9.2 (2000-03-10) [umoeller]
1654 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1655 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1656 */
1657
1658BOOL dbgPrintStackFrame(FILE *LogFile,
1659 PSZ pszModuleName, // in: module name (fully q'fied)
1660 ULONG ulObject,
1661 ULONG ulOffset)
1662{
1663 APIRET arc = 0;
1664 // "Source file"... columns
1665
1666 // first attempt to analyze the debug code
1667 arc = dbgPrintDebugInfo(LogFile,
1668 pszModuleName,
1669 ulObject,
1670 ulOffset);
1671 // if no debug code is available, analyze
1672 // the SYM file instead
1673 if (arc != NO_ERROR)
1674 {
1675 CHAR szSymName[CCHMAXPATH];
1676 strcpy(szSymName, pszModuleName);
1677 strcpy(szSymName + strlen(szSymName) - 3, "SYM");
1678 arc = dbgPrintSYMInfo(LogFile,
1679 szSymName,
1680 ulObject,
1681 ulOffset);
1682 if (arc != 0)
1683 {
1684 // SYM file not found in current directory:
1685 // check the SYM files in the \OS2 directory,
1686 // depending on the OS/2 version level:
1687 CHAR szSymFile2[CCHMAXPATH];
1688 PSZ pszFilename = strrchr(szSymName, '\\');
1689 if (pszFilename)
1690 {
1691 PSZ pszVersionDir = "WARP4";
1692 ULONG aulBuf[3];
1693
1694 DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
1695 QSV_VERSION_MINOR, // 12
1696 &aulBuf, sizeof(aulBuf));
1697 // Warp 3 is reported as 20.30
1698 // Warp 4 is reported as 20.40
1699 // Aurora is reported as 20.45
1700
1701 if (aulBuf[0] == 20)
1702 {
1703 if (aulBuf[1] == 30)
1704 // Warp 3:
1705 pszVersionDir = "WARP3";
1706 else if (aulBuf[1] >= 40)
1707 // Warp 4 or higher:
1708 // (NOTE: Warp 4 FP 13 now returns 45 also,
1709 // but the SYM files are still in the WARP4 directory...)
1710 // V0.9.3 (2000-04-26) [umoeller]
1711 pszVersionDir = "WARP4";
1712 }
1713
1714 pszFilename++;
1715 sprintf(szSymFile2,
1716 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1717 doshQueryBootDrive(),
1718 pszVersionDir,
1719 pszFilename);
1720 arc = dbgPrintSYMInfo(LogFile,
1721 szSymFile2,
1722 ulObject,
1723 ulOffset);
1724
1725 // V0.9.3 (2000-04-26) [umoeller]
1726 if ( (arc != 0) // still not found
1727 && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13?
1728 )
1729 {
1730 // Warp Server for e-Business (aka Warp 4.5):
1731 // we use the SYM files for the UNI kernel,
1732 // I have found no way to find out whether
1733 // we're running on an SMP kernel
1734 sprintf(szSymFile2,
1735 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1736 doshQueryBootDrive(),
1737 "WARP45_U",
1738 pszFilename);
1739 arc = dbgPrintSYMInfo(LogFile,
1740 szSymFile2,
1741 ulObject,
1742 ulOffset);
1743 }
1744 }
1745 }
1746
1747 if (arc == 2) // file not found
1748 fprintf(LogFile,
1749 "Cannot find symbol file %s\n",
1750 szSymName);
1751 else if (arc != 0)
1752 fprintf(LogFile,
1753 "Error %lu reading symbol file %s\n",
1754 arc,
1755 szSymName);
1756 }
1757
1758 return (arc == NO_ERROR);
1759}
1760
1761/*
1762 *@@ dbgPrintStack:
1763 * this takes stack data from the TIB and
1764 * context record data structures and tries
1765 * to analyse what the different stack frames
1766 * point to.
1767 *
1768 * For each stack frame, this calls dbgPrintDebugInfo,
1769 * and, if that fails, dbgPrintSYMInfo.
1770 *
1771 * New with V0.84.
1772 *
1773 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1774 */
1775
1776VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to
1777 PUSHORT StackBottom,
1778 PUSHORT StackTop,
1779 PUSHORT Ebp,
1780 PUSHORT ExceptionAddress)
1781{
1782 PUSHORT RetAddr = 0;
1783 PUSHORT LastEbp = 0;
1784 APIRET rc = 0;
1785 ULONG Size = 0,
1786 Attr = 0;
1787 USHORT Cs = 0,
1788 Ip = 0,
1789 // Bp,
1790 Sp = 0;
1791 static char Name[CCHMAXPATH];
1792 HMODULE hMod = 0;
1793 ULONG ObjNum = 0;
1794 ULONG Offset = 0;
1795 BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru
1796
1797 // Note: we can't handle stacks bigger than 64K for now...
1798 Sp = (USHORT) (((ULONG) StackBottom) >> 16);
1799 // Bp = ;
1800
1801 if (!f32bit)
1802 Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
1803
1804 fprintf(LogFile, "\n\nCall stack:\n");
1805 fprintf(LogFile, " Source Line Nearest\n");
1806 fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n");
1807 fprintf(LogFile, " ÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ- ÄÄÄÄÄÄÄÄ ÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ-\n");
1808
1809 do
1810 {
1811 Size = 10;
1812 rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
1813 if (rc != NO_ERROR)
1814 {
1815 fprintf(LogFile, "Invalid EBP %8.8lX (DosQueryMem returned %lu)\n", (ULONG)Ebp, rc);
1816 break;
1817 }
1818 if (!(Attr & PAG_COMMIT))
1819 {
1820 fprintf(LogFile, "Invalid EBP %8.8lX (not committed)\n", (ULONG)Ebp);
1821 break;
1822 }
1823 if (Size < 10)
1824 {
1825 fprintf(LogFile, "Invalid EBP %8.8lX (mem block size < 10)\n", (ULONG)Ebp);
1826 break;
1827 }
1828
1829 if (fExceptionAddress)
1830 RetAddr = ExceptionAddress;
1831 else
1832 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1833
1834 if (RetAddr == (PUSHORT) 0x00000053)
1835 {
1836 // For some reason there's a "return address" of 0x53 following
1837 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1838 // at the real return address. This has something to do with
1839 // thunking from 32bits to 16bits...
1840 // Serious kludge, and it's probably dependent on versions of C(++)
1841 // runtime or OS, but it works for now!
1842 Ebp += 22;
1843 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1844 }
1845
1846 // Get the (possibly) 16bit CS and IP
1847 if (fExceptionAddress)
1848 {
1849 Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
1850 Ip = (USHORT) (ULONG) ExceptionAddress;
1851 }
1852 else
1853 {
1854 Cs = *(Ebp + 2);
1855 Ip = *(Ebp + 1);
1856 }
1857
1858 // if the return address points to the stack then it's really just
1859 // a pointer to the return address (UGH!).
1860 if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp
1861 )
1862 RetAddr = (PUSHORT) (*((PULONG) RetAddr));
1863
1864 if (Ip == 0 && *Ebp == 0)
1865 {
1866 // End of the stack so these are both shifted by 2 bytes:
1867 Cs = *(Ebp + 3);
1868 Ip = *(Ebp + 2);
1869 }
1870
1871 // 16bit programs have on the stack:
1872 // BP:IP:CS
1873 // where CS may be thunked
1874 //
1875 // in dump swapped
1876 // BP IP CS BP CS IP
1877 // 4677 53B5 F7D0 7746 D0F7 B553
1878 //
1879 // 32bit programs have:
1880 // EBP:EIP
1881 // and you'd have something like this (with SP added) (not
1882 // accurate values)
1883 //
1884 // in dump swapped
1885 // EBP EIP EBP EIP
1886 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1887 //
1888 // So the basic difference is that 32bit programs have a 32bit
1889 // EBP and we can attempt to determine whether we have a 32bit
1890 // EBP by checking to see if its 'selector' is the same as SP.
1891 // Note that this technique limits us to checking stacks < 64K.
1892 //
1893 // Soooo, if IP (which maps into the same USHORT as the swapped
1894 // stack page in EBP) doesn't point to the stack (i.e. it could
1895 // be a 16bit IP) then see if CS is valid (as is or thunked).
1896 //
1897 // Note that there's the possibility of a 16bit return address
1898 // that has an offset that's the same as SP so we'll think it's
1899 // a 32bit return address and won't be able to successfully resolve
1900 // its details.
1901 if (Ip != Sp)
1902 {
1903 if (DOS16SIZESEG(Cs, &Size) == NO_ERROR)
1904 {
1905 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1906 f32bit = FALSE;
1907 }
1908 else if (DOS16SIZESEG((Cs << 3) + 7, &Size) == NO_ERROR)
1909 {
1910 Cs = (Cs << 3) + 7;
1911 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1912 f32bit = FALSE;
1913 }
1914 else
1915 f32bit = TRUE;
1916 }
1917 else
1918 f32bit = TRUE;
1919
1920
1921 // "EBP" column
1922 if (fExceptionAddress)
1923 fprintf(LogFile, " Trap -> ");
1924 else
1925 fprintf(LogFile, " %8.8lX ", (ULONG)Ebp);
1926
1927 // "Address" column
1928 if (f32bit)
1929 fprintf(LogFile, ":%8.8lX ", (ULONG)RetAddr);
1930 else
1931 fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip);
1932
1933 // Version check omitted; the following requires
1934 // OS/2 2.10 or later (*UM)
1935 // if (Version[0] >= 20 && Version[1] >= 10)
1936 {
1937 // Make a 'tick' sound to let the user know we're still alive
1938 DosBeep(2000, 10);
1939
1940 Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
1941
1942 // "Module"/"Object" columns
1943 rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
1944 if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
1945 {
1946 fprintf(LogFile, "Invalid RetAddr: %8.8lX\n", (ULONG)RetAddr);
1947 break; // avoid infinite loops
1948 }
1949 else
1950 {
1951 rc = DOSQUERYMODFROMEIP(&hMod,
1952 &ObjNum,
1953 sizeof(Name), Name,
1954 &Offset,
1955 (PVOID)RetAddr);
1956 if ( (rc == NO_ERROR)
1957 // && (ObjNum != -1)
1958 )
1959 {
1960 // static char szJunk[_MAX_FNAME];
1961 static char szName[_MAX_FNAME];
1962
1963 DosQueryModuleName(hMod, sizeof(Name), Name);
1964 // _splitpath(Name, szJunk, szJunk, szName, szJunk);
1965
1966 // print module and object
1967 fprintf(LogFile, "%-8s %04lX ", szName, ObjNum + 1);
1968
1969 if (strlen(Name) > 3)
1970 {
1971 dbgPrintStackFrame(LogFile,
1972 Name,
1973 ObjNum,
1974 Offset);
1975 }
1976 }
1977 else
1978 fprintf(LogFile,
1979 "DosQueryModFromEIP failed, returned %lu\n",
1980 rc);
1981 }
1982 }
1983
1984 if ( ((*Ebp) == 0)
1985 && ((*Ebp + 1) == 0)
1986 )
1987 {
1988 fprintf(LogFile, "End of call stack\n");
1989 break;
1990 }
1991
1992 if (!fExceptionAddress)
1993 {
1994 LastEbp = Ebp;
1995#if 0
1996 Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
1997#else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
1998 if (f32bit)
1999 Ebp = (PUSHORT) *(PULONG) LastEbp;
2000 else
2001 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
2002#endif
2003 if (f32bit)
2004 {
2005 dbgPrintVariables(LogFile, (ULONG) Ebp);
2006 } // endif
2007
2008 if (Ebp < LastEbp)
2009 {
2010 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
2011 break;
2012 }
2013 }
2014 else
2015 fExceptionAddress = FALSE;
2016
2017 Size = 4;
2018 rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
2019 if ((rc != NO_ERROR) || (Size < 4))
2020 {
2021 fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8lX\n", (ULONG)Ebp);
2022 break;
2023 }
2024 } while (TRUE);
2025
2026 fprintf(LogFile, "\n");
2027}
2028
Note: See TracBrowser for help on using the repository browser.