Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
19 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* RIP.C - */
  4. /* */
  5. /* Debugging Support Routines */
  6. /* */
  7. /****************************************************************************/
  8. #include "kernel.h"
  9. #include "newexe.h"
  10. #ifdef WOW
  11. // Note: The functions in this file were moved to the _MISCTEXT code segment
  12. // because _TEXT was exceeding the 64K segment limit a-craigj
  13. LPSTR htoa(LPSTR, WORD);
  14. LPSTR htoa0(LPSTR, WORD);
  15. LPSTR FAR far_htoa0(LPSTR, WORD);
  16. #pragma alloc_text(_MISCTEXT,far_htoa0)
  17. #pragma alloc_text(_MISCTEXT,htoa0)
  18. #pragma alloc_text(_MISCTEXT,htoa)
  19. #endif
  20. #if KDEBUG
  21. #include "logerror.h"
  22. #define API _far _pascal _loadds
  23. extern unsigned int DebugOptions;
  24. /* Defines for debug strings in STRINGS.ASM. */
  25. #define DS_LOADFAIL 0
  26. #define DS_NEWINSTLOADFAIL 1
  27. #define DS_RESLOADERR 2
  28. #define DS_CRLF 3
  29. #define DS_FATALEXITCODE 4
  30. #define DS_STACKOVERFLOW 5
  31. #define DS_STACKTRACE 6
  32. #define DS_ABORTBREAKIGNORE 7
  33. #define DS_INVALIDBPCHAIN 8
  34. #define DS_COLON 9
  35. #define DS_REENTERFATALEXIT 10
  36. #ifndef WOW
  37. LPSTR htoa(LPSTR, WORD);
  38. LPSTR htoa0(LPSTR, WORD);
  39. #endif
  40. char DebugRead(void);
  41. void DoAbort(void);
  42. void EnterBreak(int);
  43. HANDLE FAR GetExeHead(void);
  44. #ifdef WOW
  45. LONG NEAR PASCAL LSHL(WORD, int);
  46. #pragma alloc_text(_MISCTEXT,LSHL)
  47. int FAR DebugWrite(LPSTR, int);
  48. int FAR OpenSymFile(LPSTR);
  49. void FAR GetSymFileName(HANDLE, LPSTR);
  50. int FAR FarValidatePointer(LPSTR);
  51. BOOL FAR PASCAL IsCodeSelector(WORD);
  52. #else
  53. LONG PASCAL LSHL(WORD, int);
  54. int OpenSymFile(LPSTR);
  55. void GetSymFileName(HANDLE, LPSTR);
  56. int ValidatePointer(LPSTR);
  57. BOOL PASCAL IsCodeSelector(WORD);
  58. #endif
  59. WORD (far PASCAL *FatalExitProc)(WORD, WORD);
  60. int FAR FatalExitC(WORD);
  61. void FAR FatalAppExit(WORD, LPSTR);
  62. #ifdef WOW
  63. int FAR KernelError(int errCode, LPSTR lpmsg1, LPSTR lpmsg2);
  64. static char far *GetModName(char far *exeName);
  65. void API GetProcName(FARPROC lpfn, LPSTR lpch, int cch);
  66. WORD far *NextFrame(WORD far *lpFrame);
  67. void StackWalk(WORD arg);
  68. #pragma alloc_text(_MISCTEXT,KernelError)
  69. #pragma alloc_text(_MISCTEXT,GetModName)
  70. #pragma alloc_text(_MISCTEXT,GetProcName)
  71. #pragma alloc_text(_MISCTEXT,NextFrame)
  72. #pragma alloc_text(_MISCTEXT,StackWalk)
  73. #endif // WOW
  74. /* Debug Symbol Table Structures:
  75. *
  76. * For each symbol table (map): (MAPDEF)
  77. * -------------------------------------------------------------------------------------------------
  78. * | map_ptr | lsa | pgm_ent | abs_cnt | abs_ptr | seg_cnt | seg_ptr | nam_max | nam_len | name... |
  79. * -------------------------------------------------------------------------------------------------
  80. */
  81. typedef struct tagMAPDEF
  82. {
  83. unsigned map_ptr; /* 16 bit ptr to next map (0 if end) */
  84. unsigned lsa ; /* 16 bit Load Segment address */
  85. unsigned pgm_ent; /* 16 bit entry point segment value */
  86. int abs_cnt; /* 16 bit count of constants in map */
  87. unsigned abs_ptr; /* 16 bit ptr to constant chain */
  88. int seg_cnt; /* 16 bit count of segments in map */
  89. unsigned seg_ptr; /* 16 bit ptr to segment chain */
  90. char nam_max; /* 8 bit Maximum Symbol name length */
  91. char nam_len; /* 8 bit Symbol table name length */
  92. }
  93. MAPDEF;
  94. typedef struct tagMAPEND
  95. {
  96. unsigned chnend; /* end of map chain (0) */
  97. char rel; /* release */
  98. char ver; /* version */
  99. }
  100. MAPEND;
  101. /* For each segment/group within a symbol table: (SEGDEF)
  102. * --------------------------------------------------------------
  103. * | nxt_seg | sym_cnt | sym_ptr | seg_lsa | name_len | name... |
  104. * --------------------------------------------------------------
  105. */
  106. typedef struct tagSEGDEF
  107. {
  108. unsigned nxt_seg; /* 16 bit ptr to next segment(0 if end) */
  109. int sym_cnt; /* 16 bit count of symbols in sym list */
  110. unsigned sym_ptr; /* 16 bit ptr to symbol list */
  111. unsigned seg_lsa; /* 16 bit Load Segment address */
  112. unsigned seg_in0; /* 16 bit instance 0 physical address */
  113. unsigned seg_in1; /* 16 bit instance 1 physical address */
  114. unsigned seg_in2; /* 16 bit instance 2 physical address */
  115. unsigned seg_in3; /* 16 bit instance 3 physical address */
  116. unsigned seg_lin; /* 16 bit ptr to line number record */
  117. char seg_ldd; /* 8 bit boolean 0 if seg not loaded */
  118. char seg_cin; /* 8 bit current instance */
  119. char nam_len; /* 8 bit Segment name length */
  120. }
  121. SEGDEF;
  122. typedef SEGDEF FAR *LPSEGDEF;
  123. /* Followed by a list of SYMDEF's..
  124. * for each symbol within a segment/group: (SYMDEF)
  125. * -------------------------------
  126. * | sym_val | nam_len | name... |
  127. * -------------------------------
  128. */
  129. typedef struct tagSYMDEF
  130. {
  131. unsigned sym_val; /* 16 bit symbol addr or const */
  132. char nam_len; /* 8 bit symbol name length */
  133. }
  134. SYMDEF;
  135. typedef struct tagRIPINFO
  136. {
  137. char symName[128];
  138. LPSTR pSymName;
  139. DWORD symFPos;
  140. int symFH;
  141. }
  142. RIPINFO;
  143. typedef RIPINFO FAR *LPRIPINFO;
  144. /*--------------------------------------------------------------------------*/
  145. /* */
  146. /* KernelError() - */
  147. /* */
  148. /*--------------------------------------------------------------------------*/
  149. /* Print out the module name, the message which 'lpmsg1' points to, and the
  150. * value of 'lpmsg2' in hex. Then call FatalExit.
  151. */
  152. int FAR KernelError(int errCode, LPSTR lpmsg1, LPSTR lpmsg2) {
  153. int n;
  154. char buf[16];
  155. LPSTR pbuf;
  156. WORD hExe;
  157. WORD pfileinfo;
  158. struct new_exe far *pExe;
  159. /* Write out 'lpmsg1'. */
  160. if (lpmsg1)
  161. DebugWrite(lpmsg1, 0);
  162. /* Is the second pointer non-NULL? */
  163. if (lpmsg2)
  164. {
  165. /* Is the segment value non-NULL? */
  166. if ( (hExe = (WORD)((DWORD)lpmsg2 >> 16))
  167. #ifdef WOW
  168. && FarValidatePointer(lpmsg2) )
  169. #else
  170. && ValidatePointer(lpmsg2) )
  171. #endif
  172. {
  173. /* Does it point anywhere inside a New EXE Header? */
  174. pExe = (struct new_exe far *)((DWORD)hExe << 16);
  175. if (pExe->ne_magic == NEMAGIC)
  176. {
  177. /* Write out the module name (1st in the resident names table).*/
  178. pbuf = (LPSTR)(((DWORD)hExe << 16) | pExe->ne_restab);
  179. if (n = (int)((BYTE)*pbuf++))
  180. {
  181. DebugWrite(pbuf, n);
  182. DebugWrite(GetDebugString(DS_COLON), 0);
  183. }
  184. /* Is the offset NULL? */
  185. if (!LOWORD(lpmsg2))
  186. {
  187. /* Get the pointer to the full-path name which we stuck in
  188. * the checksum a long time ago.
  189. */
  190. if (pfileinfo = NE_PFILEINFO(*pExe))
  191. (DWORD)lpmsg2 |= (DWORD)pfileinfo;
  192. else
  193. {
  194. pExe = (struct new_exe far *)((DWORD)GetExeHead() << 16);
  195. pfileinfo = NE_PFILEINFO(*pExe);
  196. lpmsg2 = (LPSTR)(((DWORD)hExe << 16) | pfileinfo);
  197. }
  198. lpmsg2 += 8; /* HERE???? */
  199. }
  200. }
  201. /* Write out the full-path name. */
  202. pbuf = lpmsg2;
  203. n = 0;
  204. while ((BYTE)*pbuf++ >= ' ')
  205. n++;
  206. if (n && n < 64)
  207. DebugWrite(lpmsg2, n);
  208. }
  209. /* Write out the second pointer in hex. */
  210. pbuf = (LPSTR)buf;
  211. *pbuf++ = ' ';
  212. pbuf = htoa(pbuf, HIWORD(lpmsg2));
  213. *pbuf++ = ':';
  214. pbuf = htoa(pbuf, LOWORD(lpmsg2));
  215. *pbuf++ = '\r';
  216. *pbuf++ = '\n';
  217. *pbuf++ = 0;
  218. DebugWrite((LPSTR)buf, 0);
  219. }
  220. /* Print errCode and dump the stack. */
  221. return FatalExitC(errCode);
  222. }
  223. static char far *GetModName(char far *exeName) {
  224. int delim, dot, len, i;
  225. delim = 0;
  226. dot = 0;
  227. for (i=0; i<80 && exeName[i]; i++) {
  228. if (exeName[i] == '.')
  229. dot = i;
  230. if (exeName[i] == ':' || exeName[i] == '\\')
  231. delim = i+1;
  232. }
  233. if (!dot) dot = i;
  234. len = dot - delim;
  235. for (i=0; i<len; i++)
  236. exeName[i] = exeName[i+delim];
  237. exeName[len] = 0;
  238. return exeName+len;
  239. } /* GetModName */
  240. /*--------------------------------------------------------------------------*/
  241. /* */
  242. /* FindSegSyms() - */
  243. /* */
  244. /*--------------------------------------------------------------------------*/
  245. #ifdef WOW
  246. int FindSegSyms(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD CSvalue);
  247. #pragma alloc_text(_MISCTEXT,FindSegSyms)
  248. #endif
  249. int FindSegSyms(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD CSvalue) {
  250. HANDLE hExe;
  251. struct new_exe far *pExe;
  252. struct new_seg1 far *pSeg;
  253. MAPDEF MapDef;
  254. MAPEND MapEnd;
  255. LPSTR pFileName;
  256. BYTE c;
  257. int i;
  258. int j;
  259. WORD seg_ptr;
  260. if (lpRipInfo->symFH != -1)
  261. {
  262. _lclose(lpRipInfo->symFH);
  263. lpRipInfo->symFH = -1;
  264. }
  265. hExe = GetExeHead();
  266. while (hExe)
  267. {
  268. pExe = (struct new_exe far *)((DWORD)hExe << 16);
  269. pSeg = (struct new_seg1 far *)(((DWORD)hExe << 16) | pExe->ne_segtab);
  270. for (i=0; i < pExe->ne_cseg; i++, pSeg++)
  271. {
  272. #if 1
  273. if (HIWORD(GlobalHandleNoRIP((HANDLE)pSeg->ns_handle)) == CSvalue)
  274. #else
  275. if (MyLock((HANDLE)pSeg->ns_handle) == CSvalue)
  276. #endif
  277. {
  278. lpRipInfo->pSymName = (LPSTR)lpRipInfo->symName;
  279. GetSymFileName(hExe, lpRipInfo->pSymName);
  280. if ((lpRipInfo->symFH = OpenSymFile(lpRipInfo->pSymName)) != -1)
  281. {
  282. _lread(lpRipInfo->symFH, (LPSTR)&MapDef, sizeof(MAPDEF));
  283. _lread(lpRipInfo->symFH, lpRipInfo->pSymName, (int)((BYTE)MapDef.nam_len));
  284. if (i > MapDef.seg_cnt) /* Too much assembly */
  285. goto ModName;
  286. lpRipInfo->pSymName += MapDef.nam_len;
  287. *lpRipInfo->pSymName++ = '!';
  288. *lpRipInfo->pSymName = 0;
  289. seg_ptr = (WORD)MapDef.seg_ptr;
  290. _llseek(lpRipInfo->symFH, -(long)sizeof(MAPEND), 2);
  291. _lread(lpRipInfo->symFH, (LPSTR)&MapEnd, sizeof(MAPEND));
  292. if (MapEnd.ver != 3) goto ModName;
  293. j = i + 1;
  294. while (j--)
  295. {
  296. if (MapEnd.rel >= 10)
  297. _llseek(lpRipInfo->symFH, LSHL(seg_ptr, 4), 0);
  298. else
  299. _llseek(lpRipInfo->symFH, (long)seg_ptr, 0);
  300. _lread( lpRipInfo->symFH, (LPSTR)lpSegDef, sizeof(*lpSegDef));
  301. seg_ptr = (WORD)lpSegDef->nxt_seg;
  302. }
  303. _lread(lpRipInfo->symFH, lpRipInfo->pSymName, (int)((BYTE)lpSegDef->nam_len));
  304. lpRipInfo->pSymName += lpSegDef->nam_len;
  305. *lpRipInfo->pSymName++ = ':';
  306. *lpRipInfo->pSymName = 0;
  307. lpRipInfo->symFPos = (DWORD)_llseek(lpRipInfo->symFH, 0L, 1);
  308. return(TRUE);
  309. } /* if opened file */
  310. ModName:
  311. /* Put Module on line: USER(0033)XXXX:XXXX */
  312. GetSymFileName(hExe, lpRipInfo->symName);
  313. lpRipInfo->pSymName = GetModName(lpRipInfo->symName);
  314. *lpRipInfo->pSymName++ = '(';
  315. lpRipInfo->pSymName = htoa0(lpRipInfo->pSymName, i+1);
  316. *lpRipInfo->pSymName++ = ')';
  317. *lpRipInfo->pSymName = 0;
  318. goto TermName;
  319. }
  320. }
  321. hExe = (HANDLE)NE_PNEXTEXE(*pExe);
  322. }
  323. lpRipInfo->pSymName = lpRipInfo->symName;
  324. TermName: /* Add segment:offset to line */
  325. lpRipInfo->pSymName = htoa((LPSTR)lpRipInfo->pSymName, CSvalue);
  326. *lpRipInfo->pSymName++ = ':';
  327. *lpRipInfo->pSymName = 0;
  328. if (lpRipInfo->symFH != -1) {
  329. _lclose(lpRipInfo->symFH);
  330. lpRipInfo->symFH = -1;
  331. }
  332. return(FALSE);
  333. }
  334. /*--------------------------------------------------------------------------*/
  335. /* */
  336. /* FindSymbol() - */
  337. /* */
  338. /*--------------------------------------------------------------------------*/
  339. #ifdef WOW
  340. int FindSymbol(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD offset);
  341. #pragma alloc_text(_MISCTEXT,FindSymbol)
  342. #endif
  343. int FindSymbol(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD offset) {
  344. WORD i;
  345. DWORD symPos, curPos;
  346. LPSTR s;
  347. SYMDEF SymDef;
  348. if (lpRipInfo->symFH != -1)
  349. {
  350. curPos = symPos = (DWORD)_llseek(lpRipInfo->symFH, (long)lpRipInfo->symFPos, 0);
  351. i = (WORD)lpSegDef->sym_cnt;
  352. while (i--)
  353. {
  354. _lread(lpRipInfo->symFH, (LPSTR)&SymDef, sizeof(SYMDEF));
  355. if ((WORD)SymDef.sym_val > offset)
  356. break;
  357. symPos = curPos;
  358. curPos = _llseek(lpRipInfo->symFH, (long)SymDef.nam_len, 1);
  359. }
  360. _llseek(lpRipInfo->symFH, (long)symPos, 0);
  361. _lread(lpRipInfo->symFH, (LPSTR)&SymDef, sizeof(SYMDEF));
  362. s = lpRipInfo->pSymName;
  363. _lread(lpRipInfo->symFH, s, (int)((BYTE)SymDef.nam_len));
  364. s += SymDef.nam_len;
  365. if ((WORD)SymDef.sym_val < offset)
  366. {
  367. *s++ = '+';
  368. s = htoa0(s, offset - SymDef.sym_val);
  369. }
  370. *s = 0;
  371. return(TRUE);
  372. }
  373. s = htoa(lpRipInfo->pSymName, offset);
  374. *s = 0;
  375. return(FALSE);
  376. }
  377. void API GetProcName(FARPROC lpfn, LPSTR lpch, int cch)
  378. {
  379. RIPINFO RipInfo;
  380. SEGDEF SegDef;
  381. static char lastName[128] = "test";
  382. static FARPROC lastfn = 0;
  383. if (lastfn == lpfn) { /* cache last symbol name looked up */
  384. lstrcpy(RipInfo.symName, lastName);
  385. } else {
  386. RipInfo.pSymName = 0L;
  387. RipInfo.symFH = -1;
  388. FindSegSyms((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, HIWORD(lpfn));
  389. FindSymbol((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, LOWORD(lpfn));
  390. if (RipInfo.symFH != -1) {
  391. _lclose(RipInfo.symFH);
  392. RipInfo.symFH = -1;
  393. }
  394. lstrcpy(lastName, RipInfo.symName);
  395. lastfn = lpfn;
  396. }
  397. if (cch > 1)
  398. {
  399. if (cch > sizeof(RipInfo.symName))
  400. cch = sizeof(RipInfo.symName);
  401. RipInfo.symName[cch-1] = 0;
  402. lstrcpy(lpch, RipInfo.symName);
  403. }
  404. }
  405. /*--------------------------------------------------------------------------*/
  406. /* */
  407. /* NextFrame() - */
  408. /* */
  409. /*--------------------------------------------------------------------------*/
  410. WORD far *NextFrame(WORD far *lpFrame) {
  411. WORD w;
  412. /* Force BP even. */
  413. w = *lpFrame & 0xFFFE;
  414. /* Are we at the end of the BP chain? */
  415. if (w)
  416. {
  417. /* BPs should decrease as we move down the chain. */
  418. if (w <= LOWORD(lpFrame))
  419. goto BadBP;
  420. /* Are we above the top of the stack (SS:000A contains pStackTop)? */
  421. lpFrame = (WORD far *)(((DWORD)lpFrame & 0xFFFF0000L) | 0x0A);
  422. if (w < *lpFrame++)
  423. goto BadBP;
  424. /* Are we below the bottom of the stack (SS:000C contains pStackMin)? */
  425. if (w > *++lpFrame)
  426. goto BadBP;
  427. /* Return the address of the next BP. */
  428. return((WORD far *)(((DWORD)lpFrame & 0xFFFF0000L) | w));
  429. }
  430. else
  431. return((WORD far *)0L);
  432. BadBP:
  433. DebugWrite(GetDebugString(DS_INVALIDBPCHAIN), 0);
  434. return((WORD far *)0L);
  435. }
  436. /*--------------------------------------------------------------------------*/
  437. /* */
  438. /* StackWalk() - */
  439. /* */
  440. /*--------------------------------------------------------------------------*/
  441. void StackWalk(WORD arg) {
  442. /* WORD arg; /* NOTE: 'arg' is only used as a pointer into the frame. */
  443. /* If we subtract 2 words from 'arg's location, we */
  444. /* get the address of the previous frame's BP!!! */
  445. WORD far *lpFrame;
  446. WORD wCurBP;
  447. WORD wCurRetOffset;
  448. WORD curCS;
  449. RIPINFO RipInfo;
  450. SEGDEF SegDef;
  451. RipInfo.pSymName = 0L;
  452. RipInfo.symFH = -1;
  453. /* Have 'lpFrame' point to the previous frame's BP. */
  454. lpFrame = &arg - 2;
  455. curCS = 0;
  456. while (lpFrame = NextFrame(lpFrame))
  457. {
  458. /* Get the next BP. Stop if it is zero. */
  459. wCurBP = *lpFrame;
  460. if (!wCurBP)
  461. break;
  462. /* Get the current frame's return address offset. */
  463. wCurRetOffset = lpFrame[1];
  464. /* Have we changed code segments (Far call && Different CS)? */
  465. if (((wCurBP & 1) || IsCodeSelector(lpFrame[2])) && (curCS != lpFrame[2]))
  466. {
  467. /* Yes, get the new segment's name. */
  468. curCS = lpFrame[2];
  469. FindSegSyms((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, curCS);
  470. }
  471. /* Move back to the address of the actual call instruction. */
  472. if ((wCurBP & 1) || IsCodeSelector(lpFrame[2]))
  473. /* Near or Far call? */
  474. wCurRetOffset -= 5;
  475. else
  476. wCurRetOffset -= 3;
  477. FindSymbol((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, wCurRetOffset);
  478. DebugWrite((LPSTR)RipInfo.symName, 0);
  479. DebugWrite(GetDebugString(DS_CRLF), 0);
  480. }
  481. if (RipInfo.symFH != -1)
  482. _lclose(RipInfo.symFH);
  483. }
  484. #ifndef WOW
  485. /*--------------------------------------------------------------------------*/
  486. /* */
  487. /* FatalExit() - */
  488. /* */
  489. /*--------------------------------------------------------------------------*/
  490. /* Debugging version. Retail version in RIPAUX.ASM. */
  491. /* Kernel DS setup by prolog code */
  492. int FAR FatalExitC(WORD errCode) { /* return 1 to break execution */
  493. char c;
  494. char buf[7];
  495. LPSTR pbuf;
  496. int rep=0;
  497. /* This calls the TOOLHELP RIP hook */
  498. if ( FatalExitProc )
  499. {
  500. _asm
  501. {
  502. push errCode
  503. push bp
  504. call DWORD PTR FatalExitProc
  505. or ax,ax
  506. jz NoReturn
  507. }
  508. return 0;
  509. _asm NoReturn:;
  510. }
  511. #if 0
  512. static BOOL fInsideFatalExit = FALSE;
  513. if (fInsideFatalExit)
  514. {
  515. DebugWrite(GetDebugString(DS_REENTERFATALEXIT), 0);
  516. return 0;
  517. }
  518. fInsideFatalExit = TRUE;
  519. #endif
  520. ReRip:
  521. /* Display "FatalExit Code =" */
  522. DebugWrite(GetDebugString(DS_FATALEXITCODE), 0);
  523. /* Did the stack overflow? */
  524. if (errCode == -1)
  525. DebugWrite(GetDebugString(DS_STACKOVERFLOW), 0);
  526. else
  527. {
  528. /* Display the error code in hex. */
  529. pbuf = (LPSTR)buf;
  530. *pbuf++ = '0';
  531. *pbuf++ = 'x';
  532. pbuf = htoa(pbuf, (WORD)errCode);
  533. *pbuf++ = 0;
  534. DebugWrite((LPSTR)buf, 0);
  535. }
  536. /* Display the Stack Trace. */
  537. if (rep /* || (DebugOptions & DBO_RIP_STACK) */) {
  538. DebugWrite(GetDebugString(DS_STACKTRACE), 0);
  539. StackWalk(0);
  540. }
  541. while (TRUE)
  542. {
  543. /* Display "Abort, Break, Ignore" */
  544. DebugWrite(GetDebugString(DS_ABORTBREAKIGNORE), 0);
  545. /* Get and process the user's response. */
  546. c = DebugRead();
  547. DebugWrite(GetDebugString(DS_CRLF), 0);
  548. if (c >= 'a' && c <= 'z')
  549. c += 'A' - 'a';
  550. switch (c)
  551. {
  552. case 'A':
  553. DoAbort();
  554. case 'B':
  555. /* fInsideFatalExit = FALSE; */
  556. /* EnterBreak(2); */
  557. return 1;
  558. case 0 :
  559. case 'I':
  560. /* fInsideFatalExit = FALSE; */
  561. return 0;
  562. case 'X':
  563. case 'E':
  564. FatalAppExit(0, "Terminating Application");
  565. break;
  566. case ' ':
  567. case 13:
  568. rep = 1;
  569. goto ReRip;
  570. default:
  571. ;
  572. }
  573. }
  574. }
  575. #endif // ifndef WOW
  576. #endif // if KDEBUG
  577. /*--------------------------------------------------------------------------*/
  578. /* */
  579. /* htoa() - */
  580. /* */
  581. /*--------------------------------------------------------------------------*/
  582. /* Converts 'w' into a hex string in 's'. */
  583. LPSTR htoa(s, w)
  584. LPSTR s;
  585. WORD w;
  586. {
  587. int i;
  588. char c;
  589. i = 4;
  590. s += i;
  591. while (i--)
  592. {
  593. c = (char)(w & (WORD)0x000F);
  594. w >>= 4;
  595. if (c > 9)
  596. c += 'A' - 10;
  597. else
  598. c += '0';
  599. *--s = c;
  600. }
  601. return(s+4);
  602. }
  603. /* skip leading 0's */
  604. LPSTR htoa0(LPSTR s, WORD w)
  605. {
  606. int i;
  607. char c;
  608. int flag = 0;
  609. i = 4;
  610. while (i--)
  611. {
  612. c = (char)((w>>12) & (WORD)0x000F);
  613. w <<= 4;
  614. if (c > 9)
  615. c += 'A' - 10;
  616. else
  617. c += '0';
  618. if (c > '0' || flag || !i) {
  619. *s++ = c;
  620. flag = 1;
  621. }
  622. }
  623. return s;
  624. }
  625. LPSTR FAR far_htoa0( LPSTR s, WORD w)
  626. {
  627. return htoa0( s, w);
  628. }