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 Mller,
|
---|
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
|
---|
101 | static BOOL f32bit = TRUE;
|
---|
102 |
|
---|
103 | /*
|
---|
104 | * Global variables for Read32PmDebug:
|
---|
105 | *
|
---|
106 | */
|
---|
107 |
|
---|
108 | ULONG func_ofs;
|
---|
109 | ULONG pubfunc_ofs;
|
---|
110 | char func_name[128];
|
---|
111 | ULONG var_ofs = 0;
|
---|
112 |
|
---|
113 | struct {
|
---|
114 | BYTE name[128];
|
---|
115 | ULONG stack_offset;
|
---|
116 | USHORT type_idx;
|
---|
117 | } autovar_def[100];
|
---|
118 |
|
---|
119 | #pragma pack(1)
|
---|
120 |
|
---|
121 | BYTE *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)
|
---|
226 | struct _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 |
|
---|
243 | typedef 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 |
|
---|
250 | typedef 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 |
|
---|
258 | typedef 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 |
|
---|
266 | typedef 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 |
|
---|
277 | typedef 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 |
|
---|
288 | typedef struct _SSPUBLIC
|
---|
289 | {
|
---|
290 | unsigned short offset;
|
---|
291 | unsigned short segment;
|
---|
292 | unsigned short type;
|
---|
293 | char csize;
|
---|
294 | } SSPUBLIC;
|
---|
295 |
|
---|
296 | typedef struct _SSPUBLIC32
|
---|
297 | {
|
---|
298 | unsigned long offset;
|
---|
299 | unsigned short segment;
|
---|
300 | unsigned short type;
|
---|
301 | char csize;
|
---|
302 | } SSPUBLIC32;
|
---|
303 |
|
---|
304 | typedef struct _SSLINEENTRY32
|
---|
305 | {
|
---|
306 | unsigned short LineNum;
|
---|
307 | unsigned short FileNum;
|
---|
308 | unsigned long Offset;
|
---|
309 | } SSLINEENTRY32;
|
---|
310 |
|
---|
311 | typedef 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 |
|
---|
320 | typedef 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 |
|
---|
334 | typedef 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 |
|
---|
364 | int Read16CodeView(FILE *LogFile, PXDEBUGINFO pxdi, int fh, int TrapSeg, int TrapOff, CHAR *FileName);
|
---|
365 | int 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 |
|
---|
383 | APIRET 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 |
|
---|
548 | char fname[128],
|
---|
549 | ModName[80];
|
---|
550 | char 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 |
|
---|
556 | USHORT userdef_count;
|
---|
557 | USHORT pointer_count;
|
---|
558 |
|
---|
559 | struct one_userdef_rec
|
---|
560 | {
|
---|
561 | USHORT idx;
|
---|
562 | USHORT type_index;
|
---|
563 | BYTE name[33];
|
---|
564 | } one_userdef[MAX_USERDEFS];
|
---|
565 |
|
---|
566 | struct 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 |
|
---|
580 | int 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 |
|
---|
983 | int 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 |
|
---|
1148 | VOID 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 |
|
---|
1232 | BOOL 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 |
|
---|
1276 | BOOL 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 |
|
---|
1365 | void 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 |
|
---|
1454 | int 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 |
|
---|
1590 | BOOL 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 |
|
---|
1708 | VOID 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 |
|
---|