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

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

Major updates; timers, LVM, miscellaneous.

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