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

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

Release 0.9.8 plus some patches.

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