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

Last change on this file since 13 was 13, checked in by umoeller, 25 years ago

Updates for V0.9.6.

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