PageRenderTime 82ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/sal/osl/os2/debug.c

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