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

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

Initial checkin of helpers code which used to be in WarpIN.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 70.4 KB
Line 
1
2/*
3 *@@sourcefile debug.c:
4 * this file contains debugging functions for the
5 * exception handlers in except.c.
6 *
7 * This code is capable of unwinding the stack from
8 * a given address and trying to get function names
9 * and source line numbers, either from the respective
10 * module's debug code (if present) or from a SYM file,
11 * which is searched for in the directory of the module
12 * or in ?:\OS2\PDPSI\PMDF\WARP4.
13 *
14 * This file incorporates code from the following:
15 * -- Marc Fiammante, John Currier, Kim Rasmussen,
16 * Anthony Cruise (EXCEPT3.ZIP package for a generic
17 * exception handling DLL, available at Hobbes).
18 *
19 * Usage: All OS/2 programs.
20 *
21 * Note: Version numbering in this file relates to XWorkplace version
22 * numbering.
23 *
24 *@@changed V0.9.0 [umoeller]: made some declarations C++-compatible
25 *@@changed V0.9.1 (2000-01-30) [umoeller]: greatly cleaned up this file
26 *
27 *@@header "helpers\debug.h"
28 */
29
30/*
31 * This file Copyright (C) 1992-99 Ulrich M”ller,
32 * Kim Rasmussen,
33 * Marc Fiammante,
34 * John Currier,
35 * Anthony Cruise.
36 * This file is part of the XWorkplace 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, "%s %s (%s, seg %04X : ofs %08X\n",
703 (pxdi->sspub32.type == 1) ? " Abs" : " ",
704 ename,
705 ModName, // ()
706 pxdi->sspub32.segment,
707 pxdi->sspub32.offset
708 );
709 // but continue, because there might be a
710 // symbol that comes closer
711 }
712 }
713 break;
714
715 // Read symbols, so we can dump the variables on the stack
716 case SSTSYMBOLS:
717 if (TrapSeg != pxdi->ssmod32.csBase)
718 break;
719
720 bytesread = 0;
721 while (bytesread < pxdi->pDirTab32[i].cb)
722 {
723 static USHORT usLength;
724 static BYTE b1,
725 b2;
726 static BYTE bType;
727 // *ptr;
728 static ULONG ofs;
729 // static ULONG last_addr = 0;
730 static BYTE str[256];
731 static struct symseg_rec symseg;
732 static struct symauto_rec symauto;
733 static struct symproc_rec symproc;
734
735 // Read the length of this subentry
736 bytesread += read(ModuleFile, &b1, 1);
737 if (b1 & 0x80)
738 {
739 bytesread += read(ModuleFile, &b2, 1);
740 usLength = ((b1 & 0x7F) << 8) + b2;
741 }
742 else
743 usLength = b1;
744
745 ofs = tell(ModuleFile);
746
747 bytesread += read(ModuleFile, &bType, 1);
748
749 switch (bType)
750 {
751 case SYM_CHANGESEG:
752 read(ModuleFile, &symseg, sizeof(symseg));
753 CurrSymSeg = symseg.seg_no;
754 break;
755
756 case SYM_PROC:
757 case SYM_CPPPROC:
758 read(ModuleFile, &symproc, sizeof(symproc));
759 read(ModuleFile, str, symproc.name_len);
760 str[symproc.name_len] = 0;
761
762 if ((CurrSymSeg == TrapSeg) &&
763 (symproc.offset <= TrapOff) &&
764 (symproc.offset >= NrSymbol))
765 {
766
767 dump_vars = TRUE;
768 var_ofs = 0;
769 NrSymbol = symproc.offset;
770 func_ofs = symproc.offset;
771
772 strcpy(func_name, str);
773 }
774 else
775 {
776 dump_vars = FALSE;
777 }
778 break;
779
780 case SYM_AUTO:
781 if (!dump_vars)
782 break;
783
784 read(ModuleFile, &symauto, sizeof(symauto));
785 read(ModuleFile, str, symauto.name_len);
786 str[symauto.name_len] = 0;
787
788 strcpy(autovar_def[var_ofs].name, str);
789 autovar_def[var_ofs].stack_offset = symauto.stack_offset;
790 autovar_def[var_ofs].type_idx = symauto.type_idx;
791 var_ofs++;
792 break;
793
794 }
795
796 bytesread += usLength;
797
798 lseek(ModuleFile, ofs + usLength, SEEK_SET);
799 }
800 break;
801
802 case SSTTYPES:
803 // if (ModIndex != TrapSeg)
804 if (!read_types)
805 break;
806
807 bytesread = 0;
808 idx = 0x200;
809 userdef_count = 0;
810 pointer_count = 0;
811 while (bytesread < pxdi->pDirTab32[i].cb)
812 {
813 static struct type_rec type;
814 static struct type_userdefrec udef;
815 static struct type_pointerrec point;
816 static ULONG ofs;
817 static BYTE str[256];
818
819 // Read the length of this subentry
820 ofs = tell(ModuleFile);
821
822 read(ModuleFile, &type, sizeof(type));
823 bytesread += sizeof(type);
824
825 switch (type.type)
826 {
827 case TYPE_USERDEF:
828 if (userdef_count >= MAX_USERDEFS)
829 break;
830
831 read(ModuleFile, &udef, sizeof(udef));
832 read(ModuleFile, str, udef.name_len);
833 str[udef.name_len] = 0;
834
835 // Insert userdef in table
836 one_userdef[userdef_count].idx = idx;
837 one_userdef[userdef_count].type_index = udef.type_index;
838 memcpy(one_userdef[userdef_count].name,
839 str,
840 _min(udef.name_len + 1, 32));
841 one_userdef[userdef_count].name[32] = 0;
842 userdef_count++;
843 break;
844
845 case TYPE_POINTER:
846 if (pointer_count >= MAX_POINTERS)
847 break;
848
849 read(ModuleFile, &point, sizeof(point));
850 read(ModuleFile, str, point.name_len);
851 str[point.name_len] = 0;
852
853 // Insert userdef in table
854 one_pointer[pointer_count].idx = idx;
855 one_pointer[pointer_count].type_index = point.type_index;
856 memcpy(one_pointer[pointer_count].name,
857 str,
858 _min(point.name_len + 1, 32));
859 one_pointer[pointer_count].name[32] = 0;
860 one_pointer[pointer_count].type_qual = type.type_qual;
861 pointer_count++;
862 break;
863 }
864
865 ++idx;
866
867 bytesread += type.length;
868
869 lseek(ModuleFile, ofs + type.length + 2, SEEK_SET);
870 }
871 break;
872
873 case SSTSRCLINES32:
874 if (TrapSeg != pxdi->ssmod32.csBase)
875 break;
876
877 // read first line
878 do
879 {
880 read(ModuleFile, (void *)&FirstLine, sizeof(FirstLine));
881
882 if (FirstLine.LineNum != 0)
883 {
884 fprintf(LogFile, "Missing Line table information\n");
885 break;
886 } // endif
887 numlines = FirstLine.numlines;
888 // Other type of data skip 4 more bytes
889 if (FirstLine.entry_type < 4)
890 {
891 read(ModuleFile, (void *)&lSize, 4);
892 if (FirstLine.entry_type == 3)
893 lseek(ModuleFile, lSize, SEEK_CUR);
894 }
895 }
896 while (FirstLine.entry_type == 3);
897
898 for (j = 0; j < numlines; j++)
899 {
900 switch (FirstLine.entry_type)
901 {
902 case 0:
903 read(ModuleFile, (void *)&LineEntry, sizeof(LineEntry));
904 // Changed by Kim Rasmussen 26/06 1996 to ignore linenumber 0
905 // if (LineEntry.Offset+ssmod32.csOff<=TrapOff && LineEntry.Offset+ssmod32.csOff>=NrLine) {
906 if ( (LineEntry.LineNum)
907 && (LineEntry.Offset + pxdi->ssmod32.csOff
908 <= TrapOff)
909 && (LineEntry.Offset + pxdi->ssmod32.csOff >= NrLine)
910 )
911 {
912 NrLine = LineEntry.Offset;
913 NrFile = LineEntry.FileNum;
914 /*pOffset =sprintf(szNrLine,"%04X:%08X line #%hu ",
915 * ssmod32.csBase,LineEntry.Offset,
916 * LineEntry.LineNum); */
917 sprintf(pxdi->szNrLine, "% 6hu", LineEntry.LineNum);
918 }
919 break;
920
921 case 1:
922 lseek(ModuleFile, sizeof(struct linlist_rec), SEEK_CUR);
923 break;
924
925 case 2:
926 lseek(ModuleFile, sizeof(struct linsourcelist_rec), SEEK_CUR);
927 break;
928
929 case 3:
930 lseek(ModuleFile, sizeof(struct filenam_rec), SEEK_CUR);
931 break;
932
933 case 4:
934 lseek(ModuleFile, sizeof(struct pathtab_rec), SEEK_CUR);
935 break;
936
937 }
938 }
939
940 if (NrFile != 0)
941 {
942 // file found:
943 read(ModuleFile, (void*)&FileInfo, sizeof(FileInfo));
944 namelen = 0;
945 for (j = 1; j <= FileInfo.file_count; j++)
946 {
947 namelen = 0;
948 read(ModuleFile, (void *)&namelen, 1);
949 read(ModuleFile, (void *)ename, namelen);
950 if (j == NrFile)
951 break;
952 }
953 ename[namelen] = '\0';
954 // pOffset=sprintf(szNrLine+pOffset," (%s) (%s)\n",ename,ModName);
955 sprintf(pxdi->szNrFile, "%11.11s ", ename);
956 }
957 else
958 {
959 // strcat(szNrLine,"\n"); avoid new line for empty name fill
960 strcpy(pxdi->szNrFile, "file? ");
961 } // endif
962 break;
963 } // end switch
964
965 i++;
966 } // end while modindex
967 } // End While i < numdir
968 free(pxdi->pDirTab32);
969 return (0);
970}
971
972/*
973 * Read16CodeView:
974 * parses 16-bit debug code.
975 * Called from dbgPrintDebugInfo for 16-bit modules.
976 */
977
978int Read16CodeView(FILE *LogFile, // in: text log file to write to
979 PXDEBUGINFO pxdi,
980 int fh,
981 int TrapSeg,
982 int TrapOff,
983 CHAR *FileName)
984{
985 static unsigned short int offset,
986 NrPublic, NrLine,
987 numdir,
988 namelen, numlines,
989 line;
990 static int ModIndex;
991 static int bytesread, i, j;
992
993 ModIndex = 0;
994 // See if any CODEVIEW info
995 if (lseek(fh, -8L, SEEK_END) == -1)
996 {
997 fprintf(LogFile, "Error %u seeking CodeView table in %s\n", errno, FileName);
998 return (18);
999 }
1000
1001 if (read(fh, (void *)&G_eodbug, 8) == -1)
1002 {
1003 fprintf(LogFile, "Error %u reading debug info from %s\n", errno, FileName);
1004 return (19);
1005 }
1006 if (G_eodbug.dbug != DBUGSIG)
1007 {
1008 // fprintf(LogFile,"\nNo CodeView information stored.\n");
1009 return (100);
1010 }
1011
1012 if ((pxdi->lfaBase = lseek(fh, -(LONG)G_eodbug.dfaBase, SEEK_END)) == -1L)
1013 {
1014 fprintf(LogFile, "Error %u seeking base codeview data in %s\n", errno, FileName);
1015 return (20);
1016 }
1017
1018 if (read(fh, (void *)&pxdi->base, 8) == -1)
1019 {
1020 fprintf(LogFile, "Error %u reading base codeview data in %s\n", errno, FileName);
1021 return (21);
1022 }
1023
1024 if (lseek(fh, pxdi->base.lfoDir - 8, SEEK_CUR) == -1)
1025 {
1026 fprintf(LogFile, "Error %u seeking dir codeview data in %s\n", errno, FileName);
1027 return (22);
1028 }
1029
1030 if (read(fh, (void *)&numdir, 2) == -1)
1031 {
1032 fprintf(LogFile, "Error %u reading dir codeview data in %s\n", errno, FileName);
1033 return (23);
1034 }
1035
1036 // Read dir table into buffer
1037 if ((pxdi->pDirTab = (SSDIR*)calloc(numdir, sizeof(SSDIR))) == NULL)
1038 {
1039 fprintf(LogFile, "Out of memory!");
1040 return (-1);
1041 }
1042
1043 if (read(fh, (void*)pxdi->pDirTab, numdir * sizeof(SSDIR)) == -1)
1044 {
1045 fprintf(LogFile, "Error %u reading codeview dir table from %s\n", errno, FileName);
1046 free(pxdi->pDirTab);
1047 return (24);
1048 }
1049
1050 i = 0;
1051 while (i < numdir)
1052 {
1053 if (pxdi->pDirTab[i].sst != SSTMODULES)
1054 {
1055 i++;
1056 continue;
1057 }
1058 NrPublic = 0x0;
1059 NrLine = 0x0;
1060 // point to subsection
1061 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1062 read(fh, (void *)&pxdi->ssmod.csBase, sizeof(SSMODULE));
1063 read(fh, (void *)ModName, (unsigned)pxdi->ssmod.csize);
1064 ModIndex = pxdi->pDirTab[i].modindex;
1065 ModName[pxdi->ssmod.csize] = '\0';
1066 i++;
1067 while (pxdi->pDirTab[i].modindex == ModIndex && i < numdir)
1068 {
1069 // point to subsection
1070 lseek(fh, pxdi->pDirTab[i].lfoStart + pxdi->lfaBase, SEEK_SET);
1071 switch (pxdi->pDirTab[i].sst)
1072 {
1073 case SSTPUBLICS:
1074 bytesread = 0;
1075 while (bytesread < pxdi->pDirTab[i].cb)
1076 {
1077 bytesread += read(fh, (void *)&pxdi->sspub.offset, sizeof(pxdi->sspub));
1078 bytesread += read(fh, (void *)ename, (unsigned)pxdi->sspub.csize);
1079 ename[pxdi->sspub.csize] = '\0';
1080 if ((pxdi->sspub.segment == TrapSeg) &&
1081 (pxdi->sspub.offset <= TrapOff) &&
1082 (pxdi->sspub.offset >= NrPublic))
1083 {
1084 NrPublic = pxdi->sspub.offset;
1085 sprintf(pxdi->szNrPub, "%s %s (%s) %04hX:%04hX\n",
1086 (pxdi->sspub.type == 1) ? " Abs" : " ", ename,
1087 ModName, // ()
1088 pxdi->sspub.segment,
1089 pxdi->sspub.offset
1090 );
1091 }
1092 }
1093 break;
1094
1095 case SSTSRCLINES2:
1096 case SSTSRCLINES:
1097 if (TrapSeg != pxdi->ssmod.csBase)
1098 break;
1099 namelen = 0;
1100 read(fh, (void *)&namelen, 1);
1101 read(fh, (void *)ename, namelen);
1102 ename[namelen] = '\0';
1103 // skip 2 zero bytes
1104 if (pxdi->pDirTab[i].sst == SSTSRCLINES2)
1105 read(fh, (void *)&numlines, 2);
1106 read(fh, (void *)&numlines, 2);
1107 for (j = 0; j < numlines; j++)
1108 {
1109 read(fh, (void *)&line, 2);
1110 read(fh, (void *)&offset, 2);
1111 if (offset <= TrapOff && offset >= NrLine)
1112 {
1113 NrLine = offset;
1114 sprintf(pxdi->szNrFile, "% 12.12s ", ename);
1115 sprintf(pxdi->szNrLine, "% 6hu", line);
1116 /*sprintf(szNrLine,"%04hX:%04hX line #%hu (%s) (%s)\n",
1117 * ssmod.csBase,offset,line,ModName,ename); */
1118 }
1119 }
1120 break;
1121 } // end switch
1122 i++;
1123 } // end while modindex
1124 } // End While i < numdir
1125 free(pxdi->pDirTab);
1126 return (0);
1127}
1128
1129/* ******************************************************************
1130 * *
1131 * PART 2: ANALYZE VARIABLES *
1132 * *
1133 ********************************************************************/
1134
1135/*
1136 * var_value:
1137 * writes a description of a variable type to
1138 * the specified buffer, depending on "type".
1139 *
1140 *@@changed V0.9.1 (2000-01-30) [umoeller]: changed prototype to use external buffer
1141 */
1142
1143VOID var_value(void *varptr, // in: address of the variable on the stack
1144 char *pszBuf, // out: information
1145 BYTE type) // in: type; if >= 32, we'll call DosQueryMem
1146{
1147 ULONG Size = 1,
1148 Attr = 0;
1149
1150 if (DosQueryMem(varptr, &Size, &Attr) != NO_ERROR)
1151 {
1152 sprintf(pszBuf, "type %d, DosQueryMem failed", type);
1153 return;
1154 }
1155
1156 if ((Attr & PAG_READ) == 0)
1157 {
1158 sprintf(pszBuf, "type %d, read-access to value denied", type);
1159 return;
1160 }
1161
1162 if (type == 0)
1163 sprintf(pszBuf, "%hd", *(signed char*)varptr);
1164 else if (type == 1)
1165 sprintf(pszBuf, "%hd", *(signed short*)varptr);
1166 else if (type == 2)
1167 sprintf(pszBuf, "%ld", *(signed long*)varptr);
1168 else if (type == 4)
1169 sprintf(pszBuf, "%hu", *(BYTE*) varptr);
1170 else if (type == 5)
1171 sprintf(pszBuf, "%hu", *(USHORT*)varptr);
1172 else if (type == 6)
1173 sprintf(pszBuf, "0x%lX (%lu)", *((ULONG*)varptr), *((ULONG*)varptr));
1174 else if (type == 8)
1175 sprintf(pszBuf, "%f", *(float*)varptr);
1176 else if (type == 9)
1177 sprintf(pszBuf, "%f", *(double*)varptr);
1178 else if (type == 10)
1179 sprintf(pszBuf, "%f", *(long double*)varptr);
1180 else if (type == 16)
1181 sprintf(pszBuf, "%s", *(char*)varptr ? "TRUE" : "FALSE");
1182 else if (type == 17)
1183 sprintf(pszBuf, "%s", *(short*)varptr ? "TRUE" : "FALSE");
1184 else if (type == 18)
1185 sprintf(pszBuf, "%s", *(long*)varptr ? "TRUE" : "FALSE");
1186 else if (type == 20)
1187 sprintf(pszBuf, "%c", *(char*)varptr);
1188 else if (type == 21)
1189 sprintf(pszBuf, "%lc", *(short*)varptr);
1190 else if (type == 22)
1191 sprintf(pszBuf, "%lc", *(long*)varptr);
1192 else if (type == 23)
1193 sprintf(pszBuf, "void");
1194 else if (type >= 32)
1195 {
1196 sprintf(pszBuf, "0x%p", *(ULONG *) varptr);
1197 if (Attr & PAG_FREE)
1198 {
1199 strcat(pszBuf, " unallocated memory");
1200 }
1201 else
1202 {
1203 if ((Attr & PAG_COMMIT) == 0x0U)
1204 {
1205 strcat(pszBuf, " uncommitted");
1206 } // endif
1207 if ((Attr & PAG_WRITE) == 0x0U)
1208 {
1209 strcat(pszBuf, " unwritable");
1210 } // endif
1211 if ((Attr & PAG_READ) == 0x0U)
1212 {
1213 strcat(pszBuf, " unreadable");
1214 } // endif
1215 } // endif
1216 } // endif
1217 else
1218 sprintf(pszBuf, "Unknown type %d", type);
1219}
1220
1221/*
1222 * search_userdefs:
1223 * searches the table of userdef's-
1224 * Return TRUE if found.
1225 */
1226
1227BOOL search_userdefs(FILE *LogFile, // in: text log file to write to
1228 ULONG stackofs,
1229 USHORT var_no)
1230{
1231 USHORT pos;
1232
1233 for (pos = 0;
1234 pos < userdef_count;
1235 pos++)
1236 {
1237 if (one_userdef[pos].idx == autovar_def[var_no].type_idx)
1238 {
1239 if ( (one_userdef[pos].type_index >= 0x80)
1240 // && (one_userdef[pos].type_index <= 0xDA)
1241 )
1242 {
1243 static char sszVar3[500] = "complex";
1244 if (one_userdef[pos].type_index <= 0xDA)
1245 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1246 sszVar3,
1247 one_userdef[pos].type_index - 0x80);
1248
1249 fprintf(LogFile, " %- 6d %- 20.20s %- 33.33s %s (user)\n",
1250 autovar_def[var_no].stack_offset, // stack offset
1251 autovar_def[var_no].name, // identifier
1252 one_userdef[pos].name, // type name
1253 sszVar3 // composed by var_value
1254 );
1255 return TRUE;
1256 }
1257 else
1258 return FALSE;
1259 }
1260 }
1261
1262 return FALSE;
1263}
1264
1265/*
1266 * search_pointers:
1267 *
1268 */
1269
1270BOOL search_pointers(FILE *LogFile, // in: text log file to write to
1271 ULONG stackofs,
1272 USHORT var_no)
1273{
1274 USHORT pos, upos;
1275 static BYTE str[35];
1276 static char sszVar[500];
1277
1278 // BYTE type_index;
1279
1280 for (pos = 0;
1281 ( (pos < pointer_count)
1282 && (one_pointer[pos].idx != autovar_def[var_no].type_idx)
1283 );
1284 pos++);
1285
1286 if (pos < pointer_count)
1287 {
1288 if ( (one_pointer[pos].type_index >= 0x80)
1289 && (one_pointer[pos].type_index <= 0xDA)
1290 )
1291 {
1292 strcpy(str, type_name[one_pointer[pos].type_index - 0x80]);
1293 strcat(str, " *");
1294 var_value((void*)(stackofs + autovar_def[var_no].stack_offset),
1295 sszVar,
1296 32);
1297 fprintf(LogFile, " %- 6d %- 20.20s %- 33.33s %s (ptr1)\n",
1298 autovar_def[var_no].stack_offset,
1299 autovar_def[var_no].name,
1300 str,
1301 sszVar);
1302 return TRUE;
1303 }
1304 else
1305 {
1306 // If the result isn't a simple type, look for it in the other lists
1307 for (upos = 0;
1308 ( (upos < userdef_count)
1309 && (one_userdef[upos].idx != one_pointer[pos].type_index)
1310 );
1311 upos++)
1312 ;
1313
1314 if (upos < userdef_count)
1315 {
1316 strcpy(str, one_userdef[upos].name);
1317 strcat(str, " *");
1318 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1319 sszVar,
1320 32);
1321 fprintf(LogFile, " %- 6d %- 20.20s %- 33.33s %s (ptr2)\n",
1322 autovar_def[var_no].stack_offset,
1323 autovar_def[var_no].name,
1324 str,
1325 sszVar);
1326 return TRUE;
1327 }
1328 else
1329 {
1330 // if it isn't a userdef, for now give up and just print
1331 // as much as we know
1332 sprintf(str, "Pointer to type 0x%X", one_pointer[pos].type_index);
1333
1334 var_value((void *)(stackofs + autovar_def[var_no].stack_offset),
1335 sszVar,
1336 32);
1337 fprintf(LogFile, " %- 6d %- 20.20s %- 33.33s %s (ptr3)\n",
1338 autovar_def[var_no].stack_offset,
1339 autovar_def[var_no].name,
1340 str,
1341 sszVar);
1342
1343 return TRUE;
1344 }
1345 }
1346 }
1347
1348 return FALSE;
1349}
1350
1351/*
1352 *@@ dbgPrintVariables:
1353 * Dumps variables for the specified stack offset
1354 * to the specified log file.
1355 *
1356 * New with V0.84.
1357 */
1358
1359void dbgPrintVariables(FILE *LogFile, // in: text log file to write to
1360 ULONG stackofs)
1361{
1362 USHORT n; // , pos;
1363 BOOL AutoVarsFound = FALSE;
1364
1365 if (/* 1 || */ func_ofs == pubfunc_ofs)
1366 {
1367 for (n = 0;
1368 n < var_ofs;
1369 n++)
1370 {
1371 if (AutoVarsFound == FALSE)
1372 {
1373 AutoVarsFound = TRUE;
1374 fprintf(LogFile, " List of auto variables at EBP %p in %s:\n", stackofs, func_name);
1375 fprintf(LogFile, " Offset Name Type Value \n");
1376 fprintf(LogFile, " ÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n");
1377 }
1378
1379 // If it's one of the simple types
1380 if ( (autovar_def[n].type_idx >= 0x80)
1381 && (autovar_def[n].type_idx <= 0xDA)
1382 )
1383 {
1384 static char sszVar2[500];
1385
1386 var_value((void *)(stackofs + autovar_def[n].stack_offset),
1387 sszVar2,
1388 autovar_def[n].type_idx - 0x80);
1389
1390 fprintf(LogFile, " %- 6d %- 20.20s %- 33.33s %s (simple)\n",
1391 autovar_def[n].stack_offset,
1392 autovar_def[n].name,
1393 type_name[autovar_def[n].type_idx - 0x80],
1394 sszVar2);
1395 }
1396 else
1397 { // Complex type, check if we know what it is
1398 if (!search_userdefs(LogFile, stackofs, n))
1399 {
1400 if (!search_pointers(LogFile, stackofs, n))
1401 {
1402 fprintf(LogFile, " %- 6d %-20.20s 0x%X (unknown)\n",
1403 autovar_def[n].stack_offset,
1404 autovar_def[n].name,
1405 autovar_def[n].type_idx);
1406 }
1407 }
1408 }
1409 }
1410 /* if (AutoVarsFound == FALSE)
1411 {
1412 fprintf(LogFile, " No auto variables found in %s.\n", func_name);
1413 } */
1414 fprintf(LogFile, "\n");
1415 }
1416}
1417
1418/* ******************************************************************
1419 * *
1420 * PART 3: ANALYZE SYMBOL (.SYM) FILE *
1421 * *
1422 ********************************************************************/
1423
1424/*
1425 *@@ dbgPrintSYMInfo:
1426 * this gets called by dbgPrintStack if dbgPrintDebugInfo
1427 * failed (because no debug code was found) to check if
1428 * maybe a SYM file with the same filename exists and try
1429 * to get the info from there.
1430 *
1431 * This gets called for every line of the stack
1432 * walk, but only if getting the information from
1433 * the debug code failed, e.g. because no debug code
1434 * was available for an address.
1435 *
1436 * The file pointer is in the "Source file" column
1437 * every time this gets called.
1438 *
1439 * New with V0.84.
1440 *
1441 * Returns 0 if reading the SYM file was successful.
1442 *
1443 *@@changed V0.9.1 (2000-01-30) [umoeller]: added return code; this used to be VOID
1444 */
1445
1446int dbgPrintSYMInfo(FILE *LogFile, // in: text log file to write to
1447 CHAR *SymFileName, // in: SYM file name (can be fully q'fied)
1448 ULONG Object,
1449 ULONG TrapOffset)
1450{
1451 static FILE *SymFile;
1452 static MAPDEF MapDef;
1453 static SEGDEF SegDef;
1454 static SYMDEF32 SymDef32;
1455 static SYMDEF16 SymDef16;
1456 static char Buffer[256];
1457 static int SegNum, SymNum, LastVal;
1458 static unsigned long int SegOffset,
1459 SymOffset, SymPtrOffset;
1460
1461 // open .SYM file
1462 SymFile = fopen(SymFileName, "rb");
1463 if (SymFile == 0)
1464 return (2);
1465
1466 // read in first map definition
1467 fread(&MapDef, sizeof(MAPDEF), 1, SymFile);
1468
1469 SegOffset = SEGDEFOFFSET(MapDef);
1470
1471 // go thru all segments
1472 for (SegNum = 0;
1473 SegNum < MapDef.cSegs;
1474 SegNum++)
1475 {
1476 // printf("Scanning segment #%d Offset %4.4hX\n",SegNum+1,SegOffset);
1477 if (fseek(SymFile, SegOffset, SEEK_SET))
1478 // seek error
1479 return (3);
1480
1481 // read in segment definition
1482 fread(&SegDef, sizeof(SEGDEF), 1, SymFile);
1483 if (SegNum == Object)
1484 {
1485 // stack object found:
1486 Buffer[0] = 0x00;
1487 LastVal = 0;
1488
1489 // go thru all symbols in this object
1490 for (SymNum = 0; SymNum < SegDef.cSymbols; SymNum++)
1491 {
1492
1493 // read in symbol offset USHORT
1494 SymPtrOffset = SYMDEFOFFSET(SegOffset, SegDef, SymNum);
1495 fseek(SymFile, SymPtrOffset, SEEK_SET);
1496 fread(&SymOffset, sizeof(unsigned short int), 1, SymFile);
1497
1498 // go to symbol definition
1499 fseek(SymFile, SymOffset + SegOffset, SEEK_SET);
1500
1501 if (SegDef.bFlags & 0x01)
1502 {
1503 // 32-bit symbol:
1504 fread(&SymDef32, sizeof(SYMDEF32), 1, SymFile);
1505 if (SymDef32.wSymVal > TrapOffset)
1506 {
1507 // symbol found
1508 fprintf(LogFile, "between %s + 0x%X ", Buffer, TrapOffset - LastVal);
1509 fprintf(LogFile, "(ppLineDef: 0x%lX) ",
1510 LINEDEFOFFSET(SegDef)
1511 );
1512 fprintf(LogFile, "\n");
1513 }
1514
1515 LastVal = SymDef32.wSymVal;
1516 Buffer[0] = SymDef32.achSymName[0];
1517 fread(&Buffer[1], 1, SymDef32.cbSymName, SymFile);
1518 Buffer[SymDef32.cbSymName] = 0x00;
1519
1520 if (SymDef32.wSymVal > TrapOffset)
1521 {
1522 // symbol found, as above
1523 fprintf(LogFile, " "
1524 "and %s - 0x%X ", Buffer, LastVal - TrapOffset);
1525 fprintf(LogFile, "\n");
1526 break;
1527 }
1528 /*printf("32 Bit Symbol <%s> Address %p\n",Buffer,SymDef32.wSymVal); */
1529 }
1530 else
1531 {
1532 // 16-bit symbol:
1533 fread(&SymDef16, sizeof(SYMDEF16), 1, SymFile);
1534 if (SymDef16.wSymVal > TrapOffset)
1535 {
1536 fprintf(LogFile, "between %s + %X\n",
1537 Buffer,
1538 TrapOffset - LastVal);
1539 }
1540 LastVal = SymDef16.wSymVal;
1541 Buffer[0] = SymDef16.achSymName[0];
1542 fread(&Buffer[1], 1, SymDef16.cbSymName, SymFile);
1543 Buffer[SymDef16.cbSymName] = 0x00;
1544 if (SymDef16.wSymVal > TrapOffset)
1545 {
1546 fprintf(LogFile, " "
1547 "and %s - %X\n",
1548 Buffer,
1549 LastVal - TrapOffset);
1550 break;
1551 }
1552 /*printf("16 Bit Symbol <%s> Address %p\n",Buffer,SymDef16.wSymVal); */
1553 } // endif
1554 }
1555 break;
1556 } // endif
1557 SegOffset = NEXTSEGDEFOFFSET(SegDef);
1558 } // endwhile
1559 fclose(SymFile);
1560 return (0); // no error
1561}
1562
1563/* ******************************************************************
1564 * *
1565 * PART 4: dbgPrintStack *
1566 * *
1567 ********************************************************************/
1568
1569/*
1570 *@@ dbgPrintStackFrame:
1571 * parses and dumps one stack frame.
1572 * Called from excPrintStackFrame.
1573 *
1574 * This calls dbgPrintDebugInfo and, if
1575 * that fails, dbgPrintSYMInfo.
1576 *
1577 *@@added V0.9.2 (2000-03-10) [umoeller]
1578 *@@changed V0.9.3 (2000-04-10) [umoeller]: added support for non-Warp 4 SYM files
1579 *@@changed V0.9.3 (2000-04-26) [umoeller]: this broke Warp 4 FP 13, fixed
1580 */
1581
1582BOOL dbgPrintStackFrame(FILE *LogFile,
1583 PSZ pszModuleName, // in: module name (fully q'fied)
1584 ULONG ulObject,
1585 ULONG ulOffset)
1586{
1587 APIRET arc = 0;
1588 // "Source file"... columns
1589
1590 // first attempt to analyze the debug code
1591 arc = dbgPrintDebugInfo(LogFile,
1592 pszModuleName,
1593 ulObject,
1594 ulOffset);
1595 // if no debug code is available, analyze
1596 // the SYM file instead
1597 if (arc != NO_ERROR)
1598 {
1599 CHAR szSymName[CCHMAXPATH];
1600 strcpy(szSymName, pszModuleName);
1601 strcpy(szSymName + strlen(szSymName) - 3, "SYM");
1602 arc = dbgPrintSYMInfo(LogFile,
1603 szSymName,
1604 ulObject,
1605 ulOffset);
1606 if (arc != 0)
1607 {
1608 // SYM file not found in current directory:
1609 // check the SYM files in the \OS2 directory,
1610 // depending on the OS/2 version level:
1611 CHAR szSymFile2[CCHMAXPATH];
1612 PSZ pszFilename = strrchr(szSymName, '\\');
1613 if (pszFilename)
1614 {
1615 PSZ pszVersionDir = "WARP4";
1616 ULONG aulBuf[3];
1617
1618 DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
1619 QSV_VERSION_MINOR, // 12
1620 &aulBuf, sizeof(aulBuf));
1621 // Warp 3 is reported as 20.30
1622 // Warp 4 is reported as 20.40
1623 // Aurora is reported as 20.45
1624
1625 if (aulBuf[0] == 20)
1626 {
1627 if (aulBuf[1] == 30)
1628 // Warp 3:
1629 pszVersionDir = "WARP3";
1630 else if (aulBuf[1] >= 40)
1631 // Warp 4 or higher:
1632 // (NOTE: Warp 4 FP 13 now returns 45 also,
1633 // but the SYM files are still in the WARP4 directory...)
1634 // V0.9.3 (2000-04-26) [umoeller]
1635 pszVersionDir = "WARP4";
1636 /* else if (aulBuf[1] == 45)
1637 // Warp Server for e-Business (aka Warp 4.5):
1638 // we use the SYM files for the UNI kernel,
1639 // I have found no way to find out whether
1640 // we're running on an SMP kernel
1641 pszVersionDir = "WARP45_U"; */
1642 }
1643
1644 pszFilename++;
1645 sprintf(szSymFile2,
1646 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1647 doshQueryBootDrive(),
1648 pszVersionDir,
1649 pszFilename);
1650 arc = dbgPrintSYMInfo(LogFile,
1651 szSymFile2,
1652 ulObject,
1653 ulOffset);
1654
1655 // V0.9.3 (2000-04-26) [umoeller]
1656 if ( (arc != 0) // still not found
1657 && (aulBuf[1] == 45) // and running Aurora or Warp 4 FP13?
1658 )
1659 {
1660 // Warp Server for e-Business (aka Warp 4.5):
1661 // we use the SYM files for the UNI kernel,
1662 // I have found no way to find out whether
1663 // we're running on an SMP kernel
1664 sprintf(szSymFile2,
1665 "%c:\\OS2\\PDPSI\\PMDF\\%s\\%s",
1666 doshQueryBootDrive(),
1667 "WARP45_U",
1668 pszFilename);
1669 arc = dbgPrintSYMInfo(LogFile,
1670 szSymFile2,
1671 ulObject,
1672 ulOffset);
1673 }
1674 }
1675 }
1676
1677 if (arc == 2) // file not found
1678 fprintf(LogFile,
1679 "Cannot find symbol file %s\n",
1680 szSymName);
1681 else if (arc != 0)
1682 fprintf(LogFile,
1683 "Error %d reading symbol file %s\n",
1684 arc,
1685 szSymName);
1686 }
1687
1688 return (arc == NO_ERROR);
1689}
1690
1691/*
1692 *@@ dbgPrintStack:
1693 * this takes stack data from the TIB and
1694 * context record data structures and tries
1695 * to analyse what the different stack frames
1696 * point to.
1697 *
1698 * For each stack frame, this calls dbgPrintDebugInfo,
1699 * and, if that fails, dbgPrintSYMInfo.
1700 *
1701 * New with V0.84.
1702 *
1703 *@@changed V0.9.2 (2000-03-08) [umoeller]: now searching OS2\PDPSI\PMDF for SYM files also
1704 */
1705
1706VOID dbgPrintStack(FILE *LogFile, // in: text log file to write to
1707 PUSHORT StackBottom,
1708 PUSHORT StackTop,
1709 PUSHORT Ebp,
1710 PUSHORT ExceptionAddress)
1711{
1712 PUSHORT RetAddr = 0;
1713 PUSHORT LastEbp = 0;
1714 APIRET rc = 0;
1715 ULONG Size = 0,
1716 Attr = 0;
1717 USHORT Cs = 0,
1718 Ip = 0,
1719 // Bp,
1720 Sp = 0;
1721 static char Name[CCHMAXPATH];
1722 HMODULE hMod = 0;
1723 ULONG ObjNum = 0;
1724 ULONG Offset = 0;
1725 BOOL fExceptionAddress = TRUE; // Use Exception Addr 1st time thru
1726
1727 // Note: we can't handle stacks bigger than 64K for now...
1728 Sp = (USHORT) (((ULONG) StackBottom) >> 16);
1729 // Bp = ;
1730
1731 if (!f32bit)
1732 Ebp = (PUSHORT) MAKEULONG(((USHORT)(ULONG)Ebp), Sp);
1733
1734 fprintf(LogFile, "\n\nCall stack:\n");
1735 fprintf(LogFile, " Source Line Nearest\n");
1736 fprintf(LogFile, " EBP Address Module Obj# File Numbr Public Symbol\n");
1737 fprintf(LogFile, " ÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ- ÄÄÄÄÄÄÄÄ ÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄ-\n");
1738
1739 do
1740 {
1741 Size = 10;
1742 rc = DosQueryMem((PVOID) (Ebp + 2), &Size, &Attr);
1743 if (rc != NO_ERROR)
1744 {
1745 fprintf(LogFile, "Invalid EBP %8.8p (DosQueryMem returned %d)\n", Ebp, rc);
1746 break;
1747 }
1748 if (!(Attr & PAG_COMMIT))
1749 {
1750 fprintf(LogFile, "Invalid EBP %8.8p (not committed)\n", Ebp);
1751 break;
1752 }
1753 if (Size < 10)
1754 {
1755 fprintf(LogFile, "Invalid EBP %8.8p (mem block size < 10)\n", Ebp);
1756 break;
1757 }
1758
1759 if (fExceptionAddress)
1760 RetAddr = ExceptionAddress;
1761 else
1762 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1763
1764 if (RetAddr == (PUSHORT) 0x00000053)
1765 {
1766 // For some reason there's a "return address" of 0x53 following
1767 // EBP on the stack and we have to adjust EBP by 44 bytes to get
1768 // at the real return address. This has something to do with
1769 // thunking from 32bits to 16bits...
1770 // Serious kludge, and it's probably dependent on versions of C(++)
1771 // runtime or OS, but it works for now!
1772 Ebp += 22;
1773 RetAddr = (PUSHORT) (*((PULONG) (Ebp + 2)));
1774 }
1775
1776 // Get the (possibly) 16bit CS and IP
1777 if (fExceptionAddress)
1778 {
1779 Cs = (USHORT) (((ULONG) ExceptionAddress) >> 16);
1780 Ip = (USHORT) (ULONG) ExceptionAddress;
1781 }
1782 else
1783 {
1784 Cs = *(Ebp + 2);
1785 Ip = *(Ebp + 1);
1786 }
1787
1788 // if the return address points to the stack then it's really just
1789 // a pointer to the return address (UGH!).
1790 if ( (USHORT) (((ULONG) RetAddr) >> 16) == Sp
1791 )
1792 RetAddr = (PUSHORT) (*((PULONG) RetAddr));
1793
1794 if (Ip == 0 && *Ebp == 0)
1795 {
1796 // End of the stack so these are both shifted by 2 bytes:
1797 Cs = *(Ebp + 3);
1798 Ip = *(Ebp + 2);
1799 }
1800
1801 // 16bit programs have on the stack:
1802 // BP:IP:CS
1803 // where CS may be thunked
1804 //
1805 // in dump swapped
1806 // BP IP CS BP CS IP
1807 // 4677 53B5 F7D0 7746 D0F7 B553
1808 //
1809 // 32bit programs have:
1810 // EBP:EIP
1811 // and you'd have something like this (with SP added) (not
1812 // accurate values)
1813 //
1814 // in dump swapped
1815 // EBP EIP EBP EIP
1816 // 4677 2900 53B5 F7D0 0029 7746 D0F7 B553
1817 //
1818 // So the basic difference is that 32bit programs have a 32bit
1819 // EBP and we can attempt to determine whether we have a 32bit
1820 // EBP by checking to see if its 'selector' is the same as SP.
1821 // Note that this technique limits us to checking stacks < 64K.
1822 //
1823 // Soooo, if IP (which maps into the same USHORT as the swapped
1824 // stack page in EBP) doesn't point to the stack (i.e. it could
1825 // be a 16bit IP) then see if CS is valid (as is or thunked).
1826 //
1827 // Note that there's the possibility of a 16bit return address
1828 // that has an offset that's the same as SP so we'll think it's
1829 // a 32bit return address and won't be able to successfully resolve
1830 // its details.
1831 if (Ip != Sp)
1832 {
1833 if (DOS16SIZESEG(Cs, &Size) == NO_ERROR)
1834 {
1835 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1836 f32bit = FALSE;
1837 }
1838 else if (DOS16SIZESEG((Cs << 3) + 7, &Size) == NO_ERROR)
1839 {
1840 Cs = (Cs << 3) + 7;
1841 RetAddr = (USHORT * _Seg16) MAKEULONG(Ip, Cs);
1842 f32bit = FALSE;
1843 }
1844 else
1845 f32bit = TRUE;
1846 }
1847 else
1848 f32bit = TRUE;
1849
1850
1851 // "EBP" column
1852 if (fExceptionAddress)
1853 fprintf(LogFile, " Trap -> ");
1854 else
1855 fprintf(LogFile, " %8.8p ", Ebp);
1856
1857 // "Address" column
1858 if (f32bit)
1859 fprintf(LogFile, ":%8.8p ", RetAddr);
1860 else
1861 fprintf(LogFile, "%04.04X:%04.04X ", Cs, Ip);
1862
1863 // Version check omitted; the following requires
1864 // OS/2 2.10 or later (*UM)
1865 // if (Version[0] >= 20 && Version[1] >= 10)
1866 {
1867 // Make a 'tick' sound to let the user know we're still alive
1868 DosBeep(2000, 10);
1869
1870 Size = 10; // Inserted by Kim Rasmussen 26/06 1996 to avoid error 87 when Size is 0
1871
1872 // "Module"/"Object" columns
1873 rc = DosQueryMem((PVOID) RetAddr, &Size, &Attr);
1874 if (rc != NO_ERROR || !(Attr & PAG_COMMIT))
1875 {
1876 fprintf(LogFile, "Invalid RetAddr: %8.8p\n", RetAddr);
1877 break; // avoid infinite loops
1878 }
1879 else
1880 {
1881 rc = DOSQUERYMODFROMEIP(&hMod,
1882 &ObjNum,
1883 sizeof(Name), Name,
1884 &Offset,
1885 (PVOID)RetAddr);
1886 if ( (rc == NO_ERROR)
1887 // && (ObjNum != -1)
1888 )
1889 {
1890 // static char szJunk[_MAX_FNAME];
1891 static char szName[_MAX_FNAME];
1892
1893 DosQueryModuleName(hMod, sizeof(Name), Name);
1894 // _splitpath(Name, szJunk, szJunk, szName, szJunk);
1895
1896 // print module and object
1897 fprintf(LogFile, "%-8s %04X ", szName, ObjNum + 1);
1898
1899 if (strlen(Name) > 3)
1900 {
1901 dbgPrintStackFrame(LogFile,
1902 Name,
1903 ObjNum,
1904 Offset);
1905 }
1906 }
1907 else
1908 fprintf(LogFile,
1909 "DosQueryModFromEIP failed, returned %d\n",
1910 rc);
1911 }
1912 }
1913
1914 if ( ((*Ebp) == 0)
1915 && ((*Ebp + 1) == 0)
1916 )
1917 {
1918 fprintf(LogFile, "End of call stack\n");
1919 break;
1920 }
1921
1922 if (!fExceptionAddress)
1923 {
1924 LastEbp = Ebp;
1925#if 0
1926 Ebp = (PUSHORT) MAKEULONG(Bp, Sp);
1927#else // Inserted by Kim Rasmussen 26/06 1996 to allow big stacks
1928 if (f32bit)
1929 Ebp = (PUSHORT) *(PULONG) LastEbp;
1930 else
1931 Ebp = (PUSHORT) MAKEULONG((*Ebp), Sp);
1932#endif
1933 if (f32bit)
1934 {
1935 dbgPrintVariables(LogFile, (ULONG) Ebp);
1936 } // endif
1937
1938 if (Ebp < LastEbp)
1939 {
1940 fprintf(LogFile, "... lost stack chain - new EBP below previous\n");
1941 break;
1942 }
1943 }
1944 else
1945 fExceptionAddress = FALSE;
1946
1947 Size = 4;
1948 rc = DosQueryMem((PVOID) Ebp, &Size, &Attr);
1949 if ((rc != NO_ERROR) || (Size < 4))
1950 {
1951 fprintf(LogFile, "... lost stack chain - invalid EBP: %8.8p\n", Ebp);
1952 break;
1953 }
1954 } while (TRUE);
1955
1956 fprintf(LogFile, "\n");
1957}
1958
Note: See TracBrowser for help on using the repository browser.