Source code of Windows XP (NT5)
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.

2369 lines
64 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. vrdebug.c
  5. Abstract:
  6. Contains diagnostic/debugging routines for Vdm Redir:
  7. VrDebugInit
  8. VrDiagnosticEntryPoint
  9. VrPrint
  10. VrDumpRealMode16BitRegisters
  11. VrDumpDosMemory
  12. (ConvertFlagsToString)
  13. (GetFlags)
  14. (GrabDosData)
  15. probe_parens
  16. CategoryToIndex
  17. GetRoutineDiagnosticInfo
  18. MergeInfo
  19. DoEntryDiagnostics
  20. GetRegisterOrValue
  21. VrDumpDosMemoryStructure
  22. VrPauseBreak
  23. VrErrorBreak
  24. Author:
  25. Richard L Firth (rfirth) 13-Feb-1992
  26. Notes:
  27. This module allows us to run NTVDM.EXE and breakpoint or dump info based
  28. on an environment variable. Set the __VRDEBUG environment variable depending
  29. on the level and type of diagnostics required from VdmRedir functions. See
  30. vrdebug.h for more info
  31. This is a convenient method of dynamically changing diagnostic/debug
  32. information at run time without having to poke around in memory or start
  33. up NTVDM under NTSD (especially since NTVDM is run by the loader and not
  34. by typing NTVDM<return> at the command prompt. Changing diagnostic settings
  35. requires that NTVDM be shut down, redefine the __VRDEBUG environment
  36. variable(s) and start a dos app. Alternatively, start the dos app in a new
  37. command session after setting the new __VRDEBUG environment variable(s)
  38. Types of things which can be affected by values in environment string:
  39. - Whether a routine breakpoints at entry (and goes into debugger)
  40. - What functions or categories to diagnose
  41. - What to dump at function entry:
  42. x86 registers
  43. DOS memory
  44. DOS stack
  45. DOS structures
  46. Note that currently the order of things at function entry are predefined:
  47. 1. Display function's name
  48. 2. Display x86 registers
  49. 3. Dump DOS stack
  50. 4. Dump DOS memory
  51. 5. Dump DOS structure(s) Currently only 1 structure
  52. 6. Break
  53. Diagnostic information is set up once at NTVDM initialisation for this
  54. session, so the environment information must have been already entered.
  55. There can be 11 __VRDEBUG environment variables: __VRDEBUG and __VRDEBUG0
  56. through __VRDEBUG9. Each string can contain several function/group
  57. specifications of the form:
  58. <function or group name>[(<diagnostic options>)]
  59. The group names are predefined (add a new one if a new group of functions
  60. is added to VdmRedir) and are currently:
  61. MAILSLOT, NAMEPIPE, LANMAN, NETBIOS and DLC
  62. Group names are case insensitive. Function names are case sensitive and
  63. should be entered as they appear in the C code. However, if a case sensitive
  64. search for a function name fails, a secondary case-insensitive search will
  65. be made.
  66. Diagnostic options are case insensitive and are performed in the order shown
  67. above and are the following:
  68. BREAK[()]
  69. Break into the debugger (DbgBreakPoint) when the function is
  70. entered
  71. DISPLAYNAME[()]
  72. Display the function name on entry
  73. DUMPREGS[()]
  74. Dump the x86 16-bit registers on entry to the function
  75. DUMPSTACK[(<number>)]
  76. Dump <number> of DOS stack words (or use DEFAULT_DUMP_STACK_LENGTH)
  77. on entry to the function. This is just a special case of DUMPMEM,
  78. with type set to 'W', and segment:offset set to ss:sp.
  79. DUMPMEM[(<segment>, <offset>, <number>, <type>)]
  80. Dump <number> and <type> of DOS memory (or use DEFAULT_DUMP_MEMORY_LENGTH
  81. and DEFAULT_DUMP_MEMORY_TYPE) at <segment>:<offset>
  82. DUMPSTRUCT[(<seg> <off> <descriptor>)]
  83. Dump the structure addressed by <seg>:<off> (not necessarily segment
  84. and offset registers, can be eg. ax:flags) and descriped by <descriptor>
  85. INFO[()]
  86. Filter for calls to VrPrint - display INFORMATION, WARNING and ERROR
  87. messages
  88. WARN[()]
  89. Filter for calls to VrPrint - display WARNING and ERROR messages
  90. ERROR[()]
  91. Filter for calls to VrPrint - display ERROR messages only
  92. ERRORBREAK[()]
  93. Cause a break into debugger whenever BREAK_ON_ERROR/VrErrorBreak
  94. called
  95. PAUSEBREAK[()]
  96. Cause a break into debuggger whenever BREAK_ON_PAUSE/VrPauseBreak
  97. called
  98. If an option appears without parentheses then its function is turned OFF
  99. for this group or function.
  100. Whitespace between an option and following parentheses is tolerated, but
  101. should not be present.
  102. If an option takes parameters then all required parameters must be present
  103. or the option is ignored.
  104. Where an option takes parameters, commas are tolerated between parameters
  105. but are not necessary. Eg
  106. dumpmem(ds si 32 B)
  107. and
  108. DUMPMEM ( ds, si, 32, b )
  109. and
  110. DumpMem (ds,si,32,B)
  111. are treated as the same (, is just whitespace in this u-grammar).
  112. Where register parameters are required, absolute hex values can be given.
  113. Similarly, where a number parameter is required, a 16-bit register (any
  114. register) definition can be substituted.
  115. Function specifications take precedence over group specifications. So if the
  116. same option is given for a group and a function that belongs to that group
  117. then the options specified in the function entry are used. Any options
  118. specified for the group but not negated by the function are used for the
  119. function also.
  120. When parsing the environment, if the syntax is violated, the current
  121. description is skipped until the next description starts or the end of
  122. the string is found. Eg:
  123. mailslot(break() DLC(break()) DLC(dumpstruct(bx BBBBPPBBBB))
  124. ^ ^
  125. 1 2
  126. In this example, only DLC(break()) is parsed correctly, because there is
  127. a missing right parenthesis at 1 and a missing offset register specification
  128. at 2 (assumes bx is segment register, because that's the syntax)
  129. Revision History:
  130. --*/
  131. #if DBG
  132. #include <stdio.h>
  133. #include <stdlib.h>
  134. #include <stdarg.h>
  135. #include <string.h>
  136. #include <malloc.h>
  137. #include <ctype.h>
  138. #include <nt.h>
  139. #include <ntrtl.h> // ASSERT, DbgPrint
  140. #include <nturtl.h>
  141. #include <windows.h>
  142. #include <softpc.h> // x86 virtual machine definitions
  143. #include <vrdlctab.h>
  144. #include <vdmredir.h>
  145. #include "vrdebug.h"
  146. #ifdef VR_DEBUG_FLAGS
  147. DWORD VrDebugFlags = VR_DEBUG_FLAGS;
  148. #else
  149. DWORD VrDebugFlags = 0;
  150. #endif
  151. #ifdef DBGDBG
  152. #define DbgPrint printf
  153. #endif
  154. #define BYTES_DUMPED_AT_A_TIME 16
  155. //
  156. // private prototypes
  157. //
  158. PRIVATE
  159. VOID
  160. GetRoutineDiagnosticInfo(
  161. IN LPSTR FunctionName,
  162. OUT LPDIAGNOSTIC_INFO Info
  163. );
  164. PRIVATE
  165. DWORD
  166. CategoryToIndex(
  167. IN DWORD Category
  168. );
  169. VOID
  170. MergeInfo(
  171. OUT LPDIAGNOSTIC_INFO Info,
  172. IN LPDIAGNOSTIC_INFO FunctionInfo,
  173. IN LPDIAGNOSTIC_INFO CategoryInfo
  174. );
  175. VOID
  176. DoEntryDiagnostics(
  177. IN LPSTR FunctionName,
  178. IN LPDIAGNOSTIC_INFO Info
  179. );
  180. WORD
  181. GetRegisterOrValue(
  182. IN REGVAL Union
  183. );
  184. PRIVATE
  185. BOOL
  186. ParseString(
  187. IN LPSTR EnvStr
  188. );
  189. PRIVATE
  190. int
  191. probe_parens(
  192. LPSTR str
  193. );
  194. PRIVATE
  195. VOID
  196. apply_controls(
  197. IN DWORD mask,
  198. IN LPFUNCTION_DIAGNOSTIC lpFunc,
  199. IN DWORD on_controls,
  200. IN DWORD off_controls,
  201. IN LPMEMORY_INFO lpMemory,
  202. IN LPMEMORY_INFO lpStack,
  203. IN LPSTRUCT_INFO lpStructure
  204. );
  205. PRIVATE
  206. VOID
  207. apply_diags(
  208. IN LPDIAGNOSTIC_INFO lpDiag,
  209. IN DWORD on_controls,
  210. IN DWORD off_controls,
  211. IN LPMEMORY_INFO lpMemory,
  212. IN LPMEMORY_INFO lpStack,
  213. IN LPSTRUCT_INFO lpStructure
  214. );
  215. PRIVATE
  216. LPFUNCTION_DIAGNOSTIC
  217. FindFuncDiags(
  218. IN LPSTR function_name
  219. );
  220. PRIVATE
  221. LPFUNCTION_DIAGNOSTIC
  222. AllocFuncDiags(
  223. IN LPSTR function_name
  224. );
  225. TOKEN parse_token(LPTIB pTib);
  226. TOKEN peek_token(LPTIB pTib);
  227. LPSTR skip_ws(LPSTR str);
  228. LPSTR search_delim(LPSTR str);
  229. LPSTR extract_token(LPTIB pTib, LPSTR* token_stream);
  230. BOOL IsLexKeyword(LPSTR tokstr, TOKEN* pToken);
  231. BOOL IsLexRegister(LPSTR tokstr, LPREGVAL lpRegVal);
  232. BOOL IsLexNumber(LPSTR tokstr, LPREGVAL lpRegVal);
  233. WORD hex(char hexch);
  234. BOOL IsKeywordToken(TOKEN token);
  235. BOOL IsValidDumpDescriptor(char* str);
  236. BOOL IsValidStructDescriptor(char* str);
  237. PRIVATE
  238. LPSTR
  239. ConvertFlagsToString(
  240. IN WORD FlagsRegister,
  241. OUT LPSTR Buffer
  242. );
  243. PRIVATE
  244. WORD
  245. GetFlags(
  246. VOID
  247. );
  248. PRIVATE
  249. DWORD
  250. GrabDosData(
  251. IN LPBYTE DosMemoryPointer,
  252. IN DWORD DataSize
  253. );
  254. //
  255. // data
  256. //
  257. //
  258. // VrDiagnosticGroups - array of GROUP_DIAGNOSTIC structures in chronological
  259. // order of implementation
  260. //
  261. GROUP_DIAGNOSTIC VrDiagnosticGroups[NUMBER_OF_VR_GROUPS] = {
  262. {ES_MAILSLOT}, // DI_MAILSLOT
  263. {ES_NAMEPIPE}, // DI_NAMEPIPE
  264. {ES_LANMAN}, // DI_LANMAN
  265. {ES_NETBIOS}, // DI_NETBIOS
  266. {ES_DLC} // DI_DLC
  267. };
  268. REGDEF Registers[] = {
  269. "ax", AX,
  270. "bx", BX,
  271. "cx", CX,
  272. "dx", DX,
  273. "si", SI,
  274. "di", DI,
  275. "bp", BP,
  276. "sp", SP,
  277. "cs", CS,
  278. "ds", DS,
  279. "es", ES,
  280. "ss", SS,
  281. "ip", IP,
  282. "fl", FLAGS
  283. };
  284. CONTROL Controls[] = {
  285. DC_BREAK, DM_BREAK,
  286. DC_DISPLAYNAME, DM_DISPLAYNAME,
  287. DC_DLC, 0,
  288. DC_DUMPMEM, DM_DUMPMEM,
  289. DC_DUMPREGS, DM_DUMPREGS,
  290. DC_DUMPSTACK, DM_DUMPSTACK,
  291. DC_DUMPSTRUCT, DM_DUMPSTRUCT,
  292. DC_ERROR, DM_ERROR,
  293. DC_ERRORBREAK, DM_ERRORBREAK,
  294. DC_INFO, DM_INFORMATION,
  295. DC_LANMAN, 0,
  296. DC_MAILSLOT, 0,
  297. DC_NAMEPIPE, 0,
  298. DC_NETBIOS, 0,
  299. DC_PAUSEBREAK, DM_PAUSEBREAK,
  300. DC_WARN, DM_WARNING
  301. };
  302. #define NUMBER_OF_CONTROLS (sizeof(Controls)/Sizeof(Controls[0]))
  303. //
  304. // DiagnosticTokens - alphabetical list of all tokens we can parse from string
  305. // excluding registers, parentheses and numbers
  306. //
  307. DEBUG_TOKEN DiagnosticTokens[] = {
  308. DC_BREAK, TBREAK,
  309. DC_DISPLAYNAME, TDISPLAYNAME,
  310. DC_DLC, TDLC,
  311. DC_DUMPMEM, TDUMPMEM,
  312. DC_DUMPREGS, TDUMPREGS,
  313. DC_DUMPSTACK, TDUMPSTACK,
  314. DC_DUMPSTRUCT, TDUMPSTRUCT,
  315. DC_ERROR, TERROR,
  316. DC_ERRORBREAK, TERRORBREAK,
  317. DC_INFO, TINFO,
  318. DC_LANMAN, TLANMAN,
  319. DC_MAILSLOT, TMAILSLOT,
  320. DC_NAMEPIPE, TNAMEPIPE,
  321. DC_NETBIOS, TNETBIOS,
  322. DC_PAUSEBREAK, TPAUSEBREAK,
  323. DC_WARN, TWARN
  324. };
  325. #define NUMBER_OF_RECOGNIZABLE_TOKENS (sizeof(DiagnosticTokens)/sizeof(DiagnosticTokens[0]))
  326. LPFUNCTION_DIAGNOSTIC FunctionList = NULL;
  327. //
  328. // routines
  329. //
  330. VOID
  331. VrDebugInit(
  332. VOID
  333. )
  334. /*++
  335. Routine Description:
  336. Sets up the Vdm Redir diagnostic/debugging information based on the presence
  337. of the __VRDEBUG environment variable. We actually allow 11 __VRDEBUG
  338. environment variables - __VRDEBUG and __VRDEBUG0 through __VRDEBUG9. This
  339. is to make it easy to provide a lot of diagnostic information
  340. Syntax is __VRDEBUG[0..9]=group|routine(diagnostic controls) *
  341. Where: group is MAILSLOT, NAMEPIPE, LANMAN, NETBIOS, DLC
  342. routine is name of actual routine
  343. diagnostic controls are:
  344. break break on entry to routine
  345. dumpreg dump 16-bit registers on entry to routine (before break)
  346. dumpstack(n) dump n words of DOS stack on entry to routine
  347. dumpstruct(seg, off, descriptor)
  348. Arguments:
  349. None.
  350. Return Value:
  351. None.
  352. --*/
  353. {
  354. char envVar[sizeof(ES_VRDEBUG)+1]; // +1 for '0'..'9'
  355. LPSTR envString;
  356. DWORD i;
  357. LPSTR p;
  358. static BOOL initialized = FALSE;
  359. if (initialized) {
  360. return ;
  361. }
  362. strcpy(envVar, ES_VRDEBUG);
  363. if (envString = getenv(envVar)) {
  364. ParseString(envString);
  365. }
  366. p = strchr(envVar, 0);
  367. *p = '0';
  368. *(p+1) = 0;
  369. for (i=0; i<10; ++i) {
  370. if (envString = getenv(envVar)) {
  371. ParseString(envString);
  372. }
  373. ++*p;
  374. }
  375. initialized = TRUE;
  376. }
  377. LPDIAGNOSTIC_INFO
  378. VrDiagnosticEntryPoint(
  379. IN LPSTR FunctionName,
  380. IN DWORD FunctionCategory,
  381. OUT LPDIAGNOSTIC_INFO Info
  382. )
  383. /*++
  384. Routine Description:
  385. Performs diagnostic processing on entry to routine based on what was
  386. specified in the __VRDEBUG environment variables for this routine. Tries
  387. to perform diagnostics specific to this routine. If can't find specific
  388. function diagnostic control, checks if anything was specified for this
  389. category
  390. Arguments:
  391. FunctionName - string defining procedure's name (eg VrNetUseAdd)
  392. FunctionCategory- which category this function belongs to (eg DG_LANMAN)
  393. Info - pointer to LPDIAGNOSTIC_INFO which will be returned
  394. Return Value:
  395. LPDIAGNOSTIC_INFO - pointer to structure describing diagnostic controls for
  396. THIS ROUTINE
  397. --*/
  398. {
  399. DIAGNOSTIC_INFO function_info;
  400. LPDIAGNOSTIC_INFO category_info;
  401. RtlZeroMemory(&function_info, sizeof(function_info));
  402. GetRoutineDiagnosticInfo(FunctionName, &function_info);
  403. if (FunctionCategory != DG_NONE && FunctionCategory != DG_ALL) {
  404. category_info = &VrDiagnosticGroups[CategoryToIndex(FunctionCategory)].Diagnostic;
  405. } else {
  406. DIAGNOSTIC_INFO null_info;
  407. RtlZeroMemory(&null_info, sizeof(null_info));
  408. category_info = &null_info;
  409. }
  410. MergeInfo(Info, &function_info, category_info);
  411. DoEntryDiagnostics(FunctionName, Info);
  412. return Info;
  413. }
  414. PRIVATE
  415. VOID
  416. GetRoutineDiagnosticInfo(
  417. IN LPSTR FunctionName,
  418. OUT LPDIAGNOSTIC_INFO Info
  419. )
  420. /*++
  421. Routine Description:
  422. Tries to find the diagnostic information for this function. If found,
  423. returns the info, else a DIAGNOSTIC_INFO structure filled with 0s
  424. Arguments:
  425. FunctionName - name of function to find info for
  426. Info - pointer to place to store returned diagnostic info
  427. Return Value:
  428. None.
  429. --*/
  430. {
  431. LPFUNCTION_DIAGNOSTIC pfunc;
  432. if (pfunc = FindFuncDiags(FunctionName)) {
  433. *Info = pfunc->Diagnostic;
  434. } else {
  435. RtlZeroMemory(Info, sizeof(DIAGNOSTIC_INFO));
  436. }
  437. }
  438. PRIVATE
  439. DWORD
  440. CategoryToIndex(
  441. IN DWORD Category
  442. )
  443. /*++
  444. Routine Description:
  445. description-of-function.
  446. Arguments:
  447. Category - a DG_ category
  448. Return Value:
  449. DWORD - offset in VrDiagnosticGroups
  450. --*/
  451. {
  452. DWORD i, bit;
  453. for (i=0, bit=1; bit; bit <<=1, ++i) {
  454. if (Category & bit) {
  455. break;
  456. }
  457. }
  458. return i;
  459. }
  460. VOID
  461. MergeInfo(
  462. OUT LPDIAGNOSTIC_INFO Info,
  463. IN LPDIAGNOSTIC_INFO FunctionInfo,
  464. IN LPDIAGNOSTIC_INFO CategoryInfo
  465. )
  466. /*++
  467. Routine Description:
  468. Creates one DIAGNOSTIC_INFO from one function and one category info structure
  469. Arguments:
  470. Info - place to store merged diagnostic info
  471. FunctionInfo - input function info
  472. CategoryInfo - input category info
  473. Return Value:
  474. None.
  475. --*/
  476. {
  477. RtlZeroMemory(Info, sizeof(DIAGNOSTIC_INFO));
  478. Info->OnControl = (FunctionInfo->OnControl | CategoryInfo->OnControl)
  479. & ~(FunctionInfo->OffControl | CategoryInfo->OffControl);
  480. Info->OffControl = 0;
  481. if (FunctionInfo->OnControl & DM_DUMPSTACK) {
  482. Info->StackInfo = FunctionInfo->StackInfo;
  483. } else if (CategoryInfo->OnControl & DM_DUMPSTACK) {
  484. Info->StackInfo = CategoryInfo->StackInfo;
  485. }
  486. if (FunctionInfo->OnControl & DM_DUMPMEM) {
  487. Info->MemoryInfo = FunctionInfo->MemoryInfo;
  488. } else if (CategoryInfo->OnControl & DM_DUMPMEM) {
  489. Info->MemoryInfo = CategoryInfo->MemoryInfo;
  490. }
  491. if (FunctionInfo->OnControl & DM_DUMPSTRUCT) {
  492. Info->StructInfo = FunctionInfo->StructInfo;
  493. } else if (CategoryInfo->OnControl & DM_DUMPSTRUCT) {
  494. Info->StructInfo = CategoryInfo->StructInfo;
  495. }
  496. }
  497. VOID
  498. DoEntryDiagnostics(
  499. IN LPSTR FunctionName,
  500. IN LPDIAGNOSTIC_INFO Info
  501. )
  502. /*++
  503. Routine Description:
  504. Performs diagnostics at entry to routine as per description in header
  505. Arguments:
  506. FunctionName - name of function calling VrDiagnosticEntryPoint
  507. Info - pointer to DIAGNOSTIC_INFO created in entry point
  508. Return Value:
  509. --*/
  510. {
  511. DWORD control = Info->OnControl;
  512. if (control & DM_DISPLAYNAME) {
  513. DbgPrint("\n%s\n", FunctionName);
  514. }
  515. if (control & DM_DUMPREGS|DM_DUMPREGSDBG) {
  516. VrDumpRealMode16BitRegisters(control & DM_DUMPREGSDBG);
  517. }
  518. if (control & DM_DUMPSTACK) {
  519. VrDumpDosStack(GetRegisterOrValue(Info->StackInfo.DumpCount));
  520. }
  521. if (control & DM_DUMPMEM) {
  522. VrDumpDosMemory(Info->MemoryInfo.DumpType,
  523. GetRegisterOrValue(Info->MemoryInfo.DumpCount),
  524. GetRegisterOrValue(Info->MemoryInfo.Segment),
  525. GetRegisterOrValue(Info->MemoryInfo.Offset)
  526. );
  527. }
  528. if (control & DM_DUMPSTRUCT) {
  529. VrDumpDosMemoryStructure(Info->StructInfo.StructureDescriptor,
  530. GetRegisterOrValue(Info->StructInfo.Segment),
  531. GetRegisterOrValue(Info->StructInfo.Offset)
  532. );
  533. }
  534. if (control & DM_BREAK) {
  535. DbgBreakPoint();
  536. }
  537. }
  538. WORD
  539. GetRegisterOrValue(
  540. IN REGVAL Union
  541. )
  542. /*++
  543. Routine Description:
  544. Given a REGVAL, gets the current register contents described, or the
  545. returns the number in the union
  546. Arguments:
  547. Union -
  548. Return Value:
  549. WORD
  550. --*/
  551. {
  552. if (Union.IsRegister) {
  553. switch (Union.RegOrVal.Register) {
  554. case AX: return getAX();
  555. case BX: return getBX();
  556. case CX: return getCX();
  557. case DX: return getDX();
  558. case SI: return getSI();
  559. case DI: return getDI();
  560. case BP: return getBP();
  561. case SP: return getSP();
  562. case CS: return getCS();
  563. case DS: return getDS();
  564. case ES: return getES();
  565. case SS: return getSS();
  566. case IP: return getIP();
  567. case FLAGS: return GetFlags();
  568. }
  569. }
  570. return Union.RegOrVal.Value;
  571. }
  572. VOID
  573. VrPauseBreak(
  574. LPDIAGNOSTIC_INFO Info
  575. )
  576. /*++
  577. Routine Description:
  578. Breaks into debugger if PAUSEBREAK was specified for this function/group
  579. Arguments:
  580. Info - pointer to DIAGNOSTIC_INFO for calling function
  581. Return Value:
  582. None.
  583. --*/
  584. {
  585. if (Info) {
  586. if (Info->OnControl & DM_PAUSEBREAK) {
  587. DbgPrint("VrPauseBreak()\n");
  588. DbgBreakPoint();
  589. }
  590. }
  591. }
  592. VOID
  593. VrErrorBreak(
  594. LPDIAGNOSTIC_INFO Info
  595. )
  596. /*++
  597. Routine Description:
  598. Breaks into debugger if ERRORBREAK was specified for this function/group
  599. Arguments:
  600. Info - pointer to DIAGNOSTIC_INFO for calling function
  601. Return Value:
  602. None.
  603. --*/
  604. {
  605. if (Info) {
  606. if (Info->OnControl & DM_ERRORBREAK) {
  607. DbgPrint("VrErrorBreak()\n");
  608. DbgBreakPoint();
  609. }
  610. }
  611. }
  612. VOID
  613. VrPrint(
  614. IN DWORD Level,
  615. IN LPDIAGNOSTIC_INFO Context,
  616. IN LPSTR Format,
  617. IN ...
  618. )
  619. /*++
  620. Routine Description:
  621. Displays diagnostic messages to standard diagnostic output, but filters
  622. depending on level of message and required level of output. Only messages
  623. that have a Level >= requested level for this routine/category are output
  624. Arguments:
  625. Level - of message to be displayed (DM_ERROR, DM_WARNING, DM_INFORMATION)
  626. Context - pointer to DIAGNOSTIC_INFO structure with info for this call
  627. Format - printf-style format string
  628. ... - additional value parameters
  629. Return Value:
  630. None.
  631. --*/
  632. {
  633. char print_buffer[256]; // will we need more than this?
  634. va_list list;
  635. if (Context) {
  636. if (Level >= (Context->OnControl & DM_DISPLAY_MASK)) {
  637. va_start(list, Format);
  638. vsprintf(print_buffer, Format, list);
  639. va_end(list);
  640. DbgPrint(print_buffer);
  641. }
  642. }
  643. }
  644. #ifndef DBGDBG
  645. VOID
  646. VrDumpRealMode16BitRegisters(
  647. IN BOOL DebugStyle
  648. )
  649. /*++
  650. Routine Description:
  651. Displays (to standard diagnostic display (ie com port #)) dump of 16-bit
  652. real-mode 80286 registers - gp registers (8), segment registers (4), flags
  653. register (1) instruction pointer register (1)
  654. Arguments:
  655. DebugStyle - determines look of output:
  656. DebugStyle == TRUE:
  657. ax=1111 bx=2222 cx=3333 dx=4444 sp=5555 bp=6666 si=7777 di=8888
  658. ds=aaaa es=bbbb ss=cccc cs=dddd ip=iiii fl fl fl fl fl fl fl fl
  659. DebugStyle == FALSE:
  660. cs:ip=cccc:iiii ss:sp=ssss:pppp bp=bbbb ax=1111 bx=2222 cx=3333 dx=4444
  661. ds:si=dddd:ssss es:di=eeee:dddd flags[ODIxSZxAxPxC]=fl fl fl fl fl fl fl fl
  662. Return Value:
  663. None.
  664. --*/
  665. {
  666. char flags_string[25];
  667. if (DebugStyle) {
  668. DbgPrint(
  669. "ax=%04x bx=%04x cx=%04x dx=%04x sp=%04x bp=%04x si=%04x di=%04x\n"
  670. "ds=%04x es=%04x ss=%04x cs=%04x ip=%04x %s\n\n",
  671. getAX(),
  672. getBX(),
  673. getCX(),
  674. getDX(),
  675. getSP(),
  676. getBP(),
  677. getSI(),
  678. getDI(),
  679. getDS(),
  680. getES(),
  681. getSS(),
  682. getCS(),
  683. getIP(),
  684. ConvertFlagsToString(GetFlags(), flags_string)
  685. );
  686. } else {
  687. DbgPrint(
  688. "cs:ip=%04x:%04x ss:sp=%04x:%04x bp=%04x ax=%04x bx=%04x cx=%04x dx=%04x\n"
  689. "ds:si=%04x:%04x es:di=%04x:%04x flags[ODITSZxAxPxC]=%s\n\n",
  690. getCS(),
  691. getIP(),
  692. getSS(),
  693. getSP(),
  694. getBP(),
  695. getAX(),
  696. getBX(),
  697. getCX(),
  698. getDX(),
  699. getDS(),
  700. getSI(),
  701. getES(),
  702. getDI(),
  703. ConvertFlagsToString(GetFlags(), flags_string)
  704. );
  705. }
  706. }
  707. VOID
  708. VrDumpDosMemory(
  709. BYTE Type,
  710. DWORD Iterations,
  711. WORD Segment,
  712. WORD Offset
  713. )
  714. /*++
  715. Routine Description:
  716. Dumps DOS memory in one of following formats:
  717. Byte 0a
  718. Word 0123
  719. Dword 01234567
  720. Pointer 0abc:1234
  721. Byte format also has memory dumped as ASCII, a la debug
  722. Examples:
  723. Type == 'B':
  724. 1234:5678 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f | ................
  725. Type == 'W':
  726. 1234:5678 0100 0302 0504 0706 0908 0b0a 0d0c 0f0e
  727. Type == 'D':
  728. 1234:5678 03020100 07060504 0b0a0908 0f0e0c0d
  729. Type == 'P':
  730. 1234:5678 0302:0100 0706:0504 0b0a:0908 0f0e:0c0d
  731. Arguments:
  732. Type - of dump - 'B', 'W', 'D' or 'P'
  733. Iterations - number of TYPES of data to dump (NOT number of bytes!)
  734. Segment - WORD describing segment in DOS memory
  735. Offset - WORD describing offset in DOS segment where dump starts
  736. Return Value:
  737. None.
  738. --*/
  739. {
  740. LPSTR dumpStr;
  741. LPBYTE pointer;
  742. DWORD size;
  743. DWORD character;
  744. switch (Type) {
  745. case 'P':
  746. dumpStr = "%04x:%04x ";
  747. size = 4;
  748. break;
  749. case 'D':
  750. dumpStr = "%08x ";
  751. size = 4;
  752. break;
  753. case 'W':
  754. dumpStr = "%04x ";
  755. size = 2;
  756. break;
  757. case 'B':
  758. default:
  759. dumpStr = "%02x ";
  760. size = 1;
  761. }
  762. pointer = LPBYTE_FROM_WORDS(Segment, Offset);
  763. while (Iterations) {
  764. DWORD i;
  765. DWORD weight = BYTES_DUMPED_AT_A_TIME / size;
  766. DWORD numDumps;
  767. DbgPrint("%04x:%04x ", Segment, Offset);
  768. numDumps = Iterations > weight ? weight : Iterations;
  769. for (i=0; i<numDumps; ++i) {
  770. //
  771. // if type is pointer, have to extract 2 word values - first is
  772. // segment, second is offset. However, pointer offset is stored
  773. // before segment, so reverse order
  774. //
  775. if (Type == 'P') {
  776. DbgPrint(dumpStr, GrabDosData(pointer + 4 * i + 2, 2),
  777. GrabDosData(pointer + 4 * i, 2)
  778. );
  779. } else {
  780. DbgPrint(dumpStr, GrabDosData(pointer + size * i, size));
  781. }
  782. }
  783. //
  784. // dump data as ascii if bytes
  785. //
  786. if (size == 1) {
  787. for (i=BYTES_DUMPED_AT_A_TIME - numDumps; i; --i) {
  788. DbgPrint(" ");
  789. }
  790. DbgPrint(" | ");
  791. for (i=0; i<numDumps; ++i) {
  792. //
  793. // BUGBUG - need to modify this for MIPS
  794. //
  795. character = *(pointer + i);
  796. DbgPrint("%c", (character >= 0x20 && character <= 0x7f)
  797. ? character : '.'
  798. );
  799. }
  800. }
  801. DbgPrint("\n");
  802. Iterations -= numDumps;
  803. pointer += numDumps * size;
  804. Offset += BYTES_DUMPED_AT_A_TIME;
  805. }
  806. }
  807. VOID
  808. VrDumpDosMemoryStructure(
  809. IN LPSTR Descriptor,
  810. IN WORD Segment,
  811. IN WORD Offset
  812. )
  813. /*++
  814. Routine Description:
  815. Dumps a structure in Dos memory
  816. Arguments:
  817. Descriptor - String describing the structure
  818. Segment - in Dos memory where structure lives
  819. Offset - in Dos memory where structure lives
  820. Return Value:
  821. None.
  822. --*/
  823. {
  824. LPBYTE bigPointer = LPBYTE_FROM_WORDS(Segment, Offset);
  825. LPBYTE delimptr = strchr(Descriptor, SD_NAMESEP);
  826. char namebuf[MAX_ID_LEN+1];
  827. int len;
  828. BOOL is_sign = FALSE;
  829. char* format;
  830. DWORD value;
  831. if (delimptr) {
  832. // DbgPrint("%.*s\n", (DWORD)delimptr - (DWORD)Descriptor, Descriptor);
  833. len = (DWORD)delimptr - (DWORD)Descriptor;
  834. if (len < sizeof(namebuf)) {
  835. strncpy(namebuf, Descriptor, len);
  836. namebuf[len] = 0;
  837. DbgPrint("Structure %s:\n", namebuf);
  838. Descriptor += len+1;
  839. }
  840. }
  841. while (*Descriptor) {
  842. DbgPrint("%04x:%04x ", Segment, Offset);
  843. delimptr = strchr(Descriptor, SD_DELIM);
  844. if (delimptr) {
  845. len = (DWORD)delimptr - (DWORD)Descriptor;
  846. if (len < sizeof(namebuf)) {
  847. strncpy(namebuf, Descriptor, len);
  848. namebuf[len] = 0;
  849. DbgPrint("%s ", namebuf);
  850. }
  851. Descriptor += len+1;
  852. }
  853. switch (*Descriptor) {
  854. case SD_BYTE :
  855. DbgPrint("%#02x\n", (DWORD)*bigPointer & 0xff);
  856. ++bigPointer;
  857. ++Offset;
  858. break;
  859. case SD_WORD :
  860. DbgPrint("%#04x\n", (DWORD)*(LPWORD)bigPointer & 0xffff);
  861. ++((LPWORD)bigPointer);
  862. Offset += sizeof(WORD);
  863. break;
  864. case SD_DWORD :
  865. DbgPrint("%#08x\n", (DWORD)*(LPDWORD)bigPointer);
  866. ++((LPDWORD)bigPointer);
  867. Offset += sizeof(DWORD);
  868. break;
  869. case SD_POINTER:
  870. DbgPrint("%04x:%04x\n",
  871. (DWORD)*(((LPWORD)bigPointer)+1), (DWORD)*(LPWORD)bigPointer
  872. );
  873. ++((LPDWORD)bigPointer);
  874. Offset += 2 * sizeof(WORD);
  875. break;
  876. case SD_ASCIZ :
  877. DbgPrint("\"%s\"\n",
  878. LPSTR_FROM_WORDS(*(((LPWORD)bigPointer)+1), *(LPWORD)bigPointer)
  879. );
  880. ++((LPDWORD)bigPointer);
  881. Offset += 2 * sizeof(WORD);
  882. break;
  883. case SD_ASCII :
  884. DbgPrint("%04x:%04x \"%s\"\n",
  885. (DWORD)*(((LPWORD)bigPointer)+1), (DWORD)*(LPWORD)bigPointer,
  886. LPSTR_FROM_WORDS(*(((LPWORD)bigPointer)+1), *(LPWORD)bigPointer)
  887. );
  888. ++((LPDWORD)bigPointer);
  889. Offset += 2 * sizeof(WORD);
  890. break;
  891. case SD_CHAR :
  892. DbgPrint("'%c'\n", (DWORD)*bigPointer & 0xff);
  893. ++bigPointer;
  894. ++Offset;
  895. break;
  896. case SD_NUM :
  897. format = is_sign ? "%02d\n" : "%02u\n";
  898. value = is_sign ? (long)*bigPointer : (unsigned long)*bigPointer;
  899. DbgPrint(format, value);
  900. ++bigPointer;
  901. ++Offset;
  902. is_sign = FALSE;
  903. break;
  904. case SD_INT :
  905. format = is_sign ? "%04d\n" : "%04u\n";
  906. value = is_sign ? (long)*(LPWORD)bigPointer : (unsigned long)*(LPWORD)bigPointer;
  907. DbgPrint(format, value);
  908. ++((LPWORD)bigPointer);
  909. Offset += sizeof(WORD);
  910. is_sign = FALSE;
  911. break;
  912. case SD_LONG :
  913. format = is_sign ? "%08d\n" : "%08u\n";
  914. value = is_sign ? (long)*(LPDWORD)bigPointer : (unsigned long)*(LPDWORD)bigPointer;
  915. DbgPrint(format, value);
  916. ++((LPDWORD)bigPointer);
  917. Offset += sizeof(DWORD);
  918. is_sign = FALSE;
  919. break;
  920. case SD_SIGNED :
  921. is_sign = TRUE;
  922. break;
  923. default:
  924. //
  925. // if we somehow got a messed up descriptor, display an error and
  926. // abort the dump
  927. //
  928. DbgPrint("VrDumpDosMemoryStructure: Invalid descriptor: '%s'\n",
  929. Descriptor);
  930. return ;
  931. }
  932. ++Descriptor;
  933. while (*Descriptor == SD_FIELDSEP) {
  934. ++Descriptor;
  935. }
  936. }
  937. }
  938. #endif
  939. //
  940. // private routines
  941. //
  942. PRIVATE
  943. BOOL
  944. ParseString(
  945. IN LPSTR EnvStr
  946. )
  947. /*++
  948. Routine Description:
  949. Given one of the __VRDEBUG environment strings, parse it using BFI algorithm
  950. and collect the debug/diagnostic info. The string will look something like
  951. one of the following:
  952. MAILSLOT(DisplayName, BREAK dumpregs dumpstack(32) dumpstruct(ds si "WWB4PAa"))
  953. Which tells us that for all the mailslot category Vr routines that we run,
  954. on entry, we should display the function's name, dump the 16-bit registers,
  955. dump 32 words of DOS stack, dump a structure addressed by ds:si and having
  956. the following fields:
  957. WORD
  958. WORD
  959. BYTE
  960. BYTE
  961. BYTE
  962. BYTE
  963. POINTER
  964. ASCII string
  965. POINTER+ASCII string
  966. VrNetUseEnum(BREAK INFO)
  967. Which tells us to break into the debugger whenever we run VrNetUseEnum and
  968. that any calls to VrPrint should not filter out any levels of diagnostic
  969. (as opposed to WARN which doesn't display INFO levels or ERROR which doesn't
  970. display WARN or INFO levels of diagnostic messages)
  971. Note: group category names are case INSENSITIVE but specific function names
  972. are case SENSITIVE (because C is). However, if a case-sensitive search for
  973. a function fails to find the required name, a case-insensitive search is
  974. made, just in case the name was incorrectly entered in the environment string
  975. Note also that diagnostic option keywords are case insensitive
  976. Note also also (?) that an empty function specification effectively switches
  977. off all options for that particular function. An empty group specification
  978. similarly cancels all options for that group
  979. Arguments:
  980. EnvStr - string returned from getenv. Assumed to be non-NULL
  981. Return Value:
  982. TRUE if EnvironmentString parsed OK, else FALSE. If FALSE, string may have
  983. been partially parsed
  984. --*/
  985. {
  986. //
  987. // Syntax is: <group or function name>(<diagnostic options>*)*
  988. //
  989. // diagnostic options are cumulative, so if we found
  990. //
  991. // __VRDEBUG0=NAMEPIPE(DISPLAYNAME()) NAMEPIPE(BREAK())
  992. // __VRDEBUG3=NAMEPIPE(DUMPMEM(ds si 32 B))
  993. //
  994. // then we would have DISPLAYNAME, BREAK and DUMPMEM ds, si, 32, 'B' in the
  995. // NAMEPIPE group category entry
  996. //
  997. // If we also have
  998. //
  999. // __VRDEBUG8=VrGetNamedPipeInfo(dumpreg)
  1000. //
  1001. // then when VrDiagnosticEntryPoint was called for VrGetNamedPipeInfo,
  1002. // we would first search for VrGetNamedPipeInfo in the FUNCTION_DIAGNOSTIC
  1003. // list then search for an entry for NAMEPIPE in the GROUP_DIAGNOSTIC array.
  1004. // The info is merged and diagnostics run. Note that if we have something
  1005. // like
  1006. //
  1007. // __VRDEBUG5=VrGetNamedPipeInfo(dumpmem(ds si 32 B))
  1008. // __VRDEBUG6=NAMEPIPE(dumpmem(ds dx 80 w))
  1009. //
  1010. // then dumpmem(ds si 32 B) takes precedence because we assume that the
  1011. // requirement is to override the NAMEPIPE values for this particular
  1012. // function
  1013. //
  1014. TIB tib;
  1015. TOKEN current_token = TUNKNOWN, next_token;
  1016. int parenthesis_depth = 0;
  1017. int n;
  1018. DWORD expecting = EXPECTING_NOTHING;
  1019. #define EXPECTING( x ) (expecting & EXPECTING_##x)
  1020. DWORD off_controls = 0;
  1021. DWORD on_controls = 0;
  1022. DWORD application_mask = DG_MAILSLOT |
  1023. DG_NAMEPIPE |
  1024. DG_LANMAN |
  1025. DG_NETBIOS |
  1026. DG_DLC;
  1027. LPDIAGNOSTIC_INFO pInfo = NULL;
  1028. LPFUNCTION_DIAGNOSTIC pFunc = NULL;
  1029. MEMORY_INFO memory, stack;
  1030. STRUCT_INFO structure;
  1031. int parts_to_collect = 0;
  1032. BOOL already_had_function = FALSE;
  1033. #if DBG
  1034. DbgPrint("\nParseString(\"%s\")\n", EnvStr);
  1035. #endif
  1036. if (n = probe_parens(EnvStr)) {
  1037. DbgPrint("ParseString: Ignoring string due to unbalanced "
  1038. "parentheses (%d level(s))\n", n);
  1039. return FALSE;
  1040. }
  1041. tib.TokenStream = EnvStr;
  1042. RtlZeroMemory(&memory, sizeof(memory));
  1043. RtlZeroMemory(&stack, sizeof(stack));
  1044. RtlZeroMemory(&structure, sizeof(structure));
  1045. while (1) {
  1046. switch (parse_token(&tib)) {
  1047. case TLEFTPAREN:
  1048. #ifdef DBGDBG
  1049. printf("token = TLEFTPAREN\n");
  1050. #endif
  1051. if (!(expecting & EXPECTING_LEFTPAREN)) {
  1052. DbgPrint("ParseString: not expecting left parenthesis\n");
  1053. return FALSE;
  1054. }
  1055. ++parenthesis_depth;
  1056. expecting &= ~EXPECTING_LEFTPAREN;
  1057. break;
  1058. case TRIGHTPAREN:
  1059. #ifdef DBGDBG
  1060. printf("token = TRIGHTPAREN\n");
  1061. #endif
  1062. if (parenthesis_depth < 0) {
  1063. DbgPrint("ParseString: parenthesis level Error in %s\n",
  1064. EnvStr);
  1065. return FALSE;
  1066. }
  1067. if (!(expecting & EXPECTING_RIGHTPAREN)) {
  1068. DbgPrint("ParseString: not expecting right parenthesis\n");
  1069. return FALSE;
  1070. }
  1071. if (parts_to_collect) {
  1072. if (current_token != TDUMPSTACK) {
  1073. DbgPrint("ParseString: expecting register, value or descriptor\n");
  1074. return FALSE;
  1075. } else {
  1076. stack.DumpCount.IsRegister = FALSE;
  1077. stack.DumpCount.RegOrVal.Value = DEFAULT_STACK_DUMP;
  1078. }
  1079. }
  1080. expecting &= EXPECTING_RIGHTPAREN;
  1081. --parenthesis_depth;
  1082. if (!parenthesis_depth) {
  1083. apply_controls(application_mask,
  1084. pFunc,
  1085. on_controls,
  1086. off_controls,
  1087. &memory,
  1088. &stack,
  1089. &structure
  1090. );
  1091. on_controls = 0;
  1092. off_controls = 0;
  1093. application_mask = DG_MAILSLOT |
  1094. DG_NAMEPIPE |
  1095. DG_LANMAN |
  1096. DG_NETBIOS |
  1097. DG_DLC;
  1098. if (pFunc) {
  1099. LPFUNCTION_DIAGNOSTIC listptr;
  1100. if (!FunctionList) {
  1101. FunctionList = pFunc;
  1102. } else if (!already_had_function) {
  1103. for (listptr = FunctionList; listptr->Next; listptr = listptr->Next);
  1104. listptr->Next = pFunc;
  1105. }
  1106. pFunc = NULL;
  1107. }
  1108. expecting = EXPECTING_NOTHING;
  1109. parts_to_collect = 0;
  1110. current_token = TUNKNOWN;
  1111. }
  1112. break;
  1113. case TREGISTER:
  1114. case TNUMBER:
  1115. #ifdef DBGDBG
  1116. printf("token = TREGISTER/TNUMBER\n");
  1117. #endif
  1118. if (!(expecting & EXPECTING_REGVAL)) {
  1119. DbgPrint("ParseString: Not expecting register or value"
  1120. " at this time. Got %s\n", tib.RegValOrId.Id);
  1121. return FALSE;
  1122. }
  1123. if (current_token == TDUMPSTRUCT) {
  1124. if (parts_to_collect == 3) {
  1125. structure.Segment = tib.RegValOrId.RegVal;
  1126. } else if (parts_to_collect == 2) {
  1127. structure.Offset = tib.RegValOrId.RegVal;
  1128. }
  1129. if (--parts_to_collect == 1) {
  1130. expecting &= ~EXPECTING_REGVAL;
  1131. }
  1132. } else if (current_token == TDUMPMEM) {
  1133. if (parts_to_collect == 4) {
  1134. memory.Segment = tib.RegValOrId.RegVal;
  1135. } else if (parts_to_collect == 3) {
  1136. memory.Offset = tib.RegValOrId.RegVal;
  1137. } else if (parts_to_collect == 2) {
  1138. memory.DumpCount = tib.RegValOrId.RegVal;
  1139. }
  1140. if (--parts_to_collect == 1) {
  1141. expecting &= ~EXPECTING_REGVAL;
  1142. }
  1143. } else if (current_token == TDUMPREGS) {
  1144. //
  1145. // REGS(0) => debug-style
  1146. // REGS(!0) => vrdebug-style
  1147. //
  1148. if (tib.RegValOrId.RegVal.RegOrVal.Value) {
  1149. on_controls &= ~DM_DUMPREGSDBG;
  1150. } else {
  1151. on_controls &= ~DM_DUMPREGS;
  1152. }
  1153. expecting &= ~EXPECTING_REGVAL;
  1154. } else {
  1155. stack.DumpCount = tib.RegValOrId.RegVal;
  1156. if (!--parts_to_collect) {
  1157. expecting &= ~EXPECTING_REGVAL;
  1158. }
  1159. }
  1160. break;
  1161. case TEOS:
  1162. #ifdef DBGDBG
  1163. printf("token = TEOS\n");
  1164. #endif
  1165. if (expecting == EXPECTING_NOTHING) {
  1166. apply_controls(application_mask,
  1167. pFunc,
  1168. on_controls,
  1169. off_controls,
  1170. &memory,
  1171. &stack,
  1172. &structure
  1173. );
  1174. if (pFunc) {
  1175. LPFUNCTION_DIAGNOSTIC listptr;
  1176. if (!FunctionList) {
  1177. FunctionList = pFunc;
  1178. } else if (!already_had_function) {
  1179. for (listptr = FunctionList; listptr->Next; listptr = listptr->Next);
  1180. listptr->Next = pFunc;
  1181. }
  1182. pFunc = NULL;
  1183. }
  1184. } else {
  1185. DbgPrint("ParseString: early End-Of-String\n");
  1186. }
  1187. return !expecting && !parenthesis_depth;
  1188. case TUNKNOWN:
  1189. #ifdef DBGDBG
  1190. printf("token = TUNKNOWN\n");
  1191. #endif
  1192. //
  1193. // can be: MEMDESC, STRUCTDESC or function id
  1194. //
  1195. if (current_token == TDUMPMEM) {
  1196. if (parts_to_collect != 1) {
  1197. DbgPrint("ParseString: syntax error\n");
  1198. return FALSE;
  1199. }
  1200. if (!IsValidDumpDescriptor(_strupr(tib.RegValOrId.Id))) {
  1201. DbgPrint("ParseString: Invalid memory dump descriptor:'%s'\n",
  1202. tib.RegValOrId.Id);
  1203. return FALSE;
  1204. }
  1205. memory.DumpType = (BYTE)toupper(*tib.RegValOrId.Id);
  1206. --parts_to_collect;
  1207. } else if (current_token == TDUMPSTRUCT) {
  1208. if (parts_to_collect != 1) {
  1209. DbgPrint("ParseString: syntax error\n");
  1210. return FALSE;
  1211. }
  1212. if (!IsValidStructDescriptor(_strupr(tib.RegValOrId.Id))) {
  1213. DbgPrint("ParseString: Invalid structure dump descriptor:'%s'\n",
  1214. tib.RegValOrId.Id);
  1215. return FALSE;
  1216. }
  1217. strcpy(structure.StructureDescriptor, tib.RegValOrId.Id);
  1218. _strupr(structure.StructureDescriptor);
  1219. --parts_to_collect;
  1220. } else {
  1221. if (!(pFunc = FindFuncDiags(tib.RegValOrId.Id))) {
  1222. pFunc = AllocFuncDiags(tib.RegValOrId.Id);
  1223. already_had_function = FALSE;
  1224. } else {
  1225. already_had_function = TRUE;
  1226. }
  1227. if (!pFunc) {
  1228. DbgPrint("ParseString: out of memory getting struct "
  1229. "for %s. Aborting!\n", tib.RegValOrId.Id);
  1230. return FALSE;
  1231. }
  1232. application_mask = 0; // no groups
  1233. expecting |= EXPECTING_LEFTPAREN;
  1234. }
  1235. break;
  1236. case TBREAK:
  1237. #ifdef DBGDBG
  1238. printf("token = TBREAK\n");
  1239. #endif
  1240. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1241. DbgPrint("ParseString: syntax error\n");
  1242. return FALSE;
  1243. }
  1244. next_token = peek_token(&tib);
  1245. if (next_token == TLEFTPAREN) {
  1246. on_controls |= DM_BREAK;
  1247. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1248. } else if (next_token == TRIGHTPAREN || next_token == TEOS) {
  1249. off_controls |= DM_BREAK;
  1250. } else if (IsKeywordToken(next_token)) {
  1251. off_controls |= DM_BREAK;
  1252. expecting &= EXPECTING_RIGHTPAREN;
  1253. } else {
  1254. DbgPrint("ParseString: bad syntax for BREAK\n");
  1255. return FALSE;
  1256. }
  1257. break;
  1258. case TDISPLAYNAME:
  1259. #ifdef DBGDBG
  1260. printf("token = TDISPLAYMEM\n");
  1261. #endif
  1262. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1263. DbgPrint("ParseString: syntax error\n");
  1264. return FALSE;
  1265. }
  1266. next_token = peek_token(&tib);
  1267. if (peek_token(&tib) == TLEFTPAREN) {
  1268. on_controls |= DM_DISPLAYNAME;
  1269. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1270. } else if (IsKeywordToken(next_token)) {
  1271. off_controls |= DM_DISPLAYNAME;
  1272. expecting &= EXPECTING_RIGHTPAREN;
  1273. } else {
  1274. DbgPrint("ParseString: bad syntax for DISPLAYNAME\n");
  1275. return FALSE;
  1276. }
  1277. break;
  1278. case TDLC:
  1279. #ifdef DBGDBG
  1280. printf("token = TDLC\n");
  1281. #endif
  1282. if (expecting != EXPECTING_NOTHING) {
  1283. DbgPrint("ParseString: syntax error\n");
  1284. return FALSE;
  1285. }
  1286. application_mask = DG_DLC;
  1287. pInfo = &VrDiagnosticGroups[DI_DLC].Diagnostic;
  1288. on_controls = off_controls = 0;
  1289. RtlZeroMemory(&memory, sizeof(memory));
  1290. RtlZeroMemory(&stack, sizeof(stack));
  1291. RtlZeroMemory(&structure, sizeof(structure));
  1292. pFunc = NULL;
  1293. if (peek_token(&tib) == TLEFTPAREN) {
  1294. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1295. } else {
  1296. expecting = EXPECTING_NOTHING;
  1297. }
  1298. break;
  1299. case TDUMPMEM:
  1300. #ifdef DBGDBG
  1301. printf("token = TDUMPMEM\n");
  1302. #endif
  1303. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1304. DbgPrint("ParseString: syntax error\n");
  1305. return FALSE;
  1306. }
  1307. current_token = TDUMPMEM;
  1308. next_token = peek_token(&tib);
  1309. if (peek_token(&tib) == TLEFTPAREN) {
  1310. on_controls |= DM_DUMPMEM;
  1311. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN | EXPECTING_REGVAL;
  1312. parts_to_collect = 4;
  1313. } else if (IsKeywordToken(next_token)) {
  1314. off_controls |= DM_DUMPMEM;
  1315. expecting &= EXPECTING_RIGHTPAREN;
  1316. } else {
  1317. DbgPrint("ParseString: bad syntax for DUMPMEM\n");
  1318. return FALSE;
  1319. }
  1320. break;
  1321. case TDUMPREGS:
  1322. #ifdef DBGDBG
  1323. printf("token = TDUMPREGS\n");
  1324. #endif
  1325. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1326. DbgPrint("ParseString: syntax error\n");
  1327. return FALSE;
  1328. }
  1329. current_token = TDUMPREGS;
  1330. next_token = peek_token(&tib);
  1331. if (next_token == TLEFTPAREN) {
  1332. on_controls |= DM_DUMPREGS|DM_DUMPREGSDBG;
  1333. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN | EXPECTING_REGVAL;
  1334. } else if (IsKeywordToken(next_token)) {
  1335. off_controls |= DM_DUMPREGS;
  1336. expecting &= EXPECTING_RIGHTPAREN;
  1337. } else {
  1338. DbgPrint("ParseString: bad syntax for DUMPREGS\n");
  1339. return FALSE;
  1340. }
  1341. break;
  1342. case TDUMPSTACK:
  1343. #ifdef DBGDBG
  1344. printf("token = TDUMPSTACK\n");
  1345. #endif
  1346. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1347. DbgPrint("ParseString: syntax error\n");
  1348. return FALSE;
  1349. }
  1350. current_token = TDUMPSTACK;
  1351. next_token = peek_token(&tib);
  1352. if (peek_token(&tib) == TLEFTPAREN) {
  1353. on_controls |= DM_DUMPSTACK;
  1354. expecting |= EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN | EXPECTING_REGVAL;
  1355. parts_to_collect = 1;
  1356. } else if (IsKeywordToken(next_token)) {
  1357. off_controls |= DM_DUMPSTACK;
  1358. expecting &= EXPECTING_RIGHTPAREN;
  1359. } else {
  1360. DbgPrint("ParseString: bad syntax for DUMPSTACK\n");
  1361. return FALSE;
  1362. }
  1363. break;
  1364. case TDUMPSTRUCT:
  1365. #ifdef DBGDBG
  1366. printf("token = TDUMPSTRUCT\n");
  1367. #endif
  1368. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1369. DbgPrint("ParseString: syntax error\n");
  1370. return FALSE;
  1371. }
  1372. current_token = TDUMPSTRUCT;
  1373. next_token = peek_token(&tib);
  1374. if (peek_token(&tib) == TLEFTPAREN) {
  1375. on_controls |= DM_DUMPSTRUCT;
  1376. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN | EXPECTING_REGVAL;
  1377. parts_to_collect = 3;
  1378. } else if (IsKeywordToken(next_token)) {
  1379. off_controls |= DM_DUMPSTRUCT;
  1380. expecting &= EXPECTING_RIGHTPAREN;
  1381. } else {
  1382. DbgPrint("ParseString: bad syntax for DUMPSTRUCT\n");
  1383. return FALSE;
  1384. }
  1385. break;
  1386. case TERROR: //aaiegh!
  1387. #ifdef DBGDBG
  1388. printf("token = TERROR\n");
  1389. #endif
  1390. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1391. DbgPrint("ParseString: syntax error\n");
  1392. return FALSE;
  1393. }
  1394. next_token = peek_token(&tib);
  1395. if (peek_token(&tib) == TLEFTPAREN) {
  1396. on_controls |= DM_ERROR;
  1397. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1398. } else if (IsKeywordToken(next_token)) {
  1399. off_controls |= DM_ERROR;
  1400. expecting &= EXPECTING_RIGHTPAREN;
  1401. } else {
  1402. DbgPrint("ParseString: bad syntax for ERROR\n");
  1403. return FALSE;
  1404. }
  1405. break;
  1406. case TERRORBREAK: //phew! But I'd rather have a TBREAK
  1407. #ifdef DBGDBG
  1408. printf("token = TERRORBREAK\n");
  1409. #endif
  1410. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1411. DbgPrint("ParseString: syntax error\n");
  1412. return FALSE;
  1413. }
  1414. next_token = peek_token(&tib);
  1415. if (peek_token(&tib) == TLEFTPAREN) {
  1416. on_controls |= DM_ERRORBREAK;
  1417. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1418. } else if (IsKeywordToken(next_token)) {
  1419. off_controls |= DM_ERRORBREAK;
  1420. expecting &= EXPECTING_RIGHTPAREN;
  1421. } else {
  1422. DbgPrint("ParseString: bad syntax for ERRORBREAK\n");
  1423. return FALSE;
  1424. }
  1425. break;
  1426. case TINFO:
  1427. #ifdef DBGDBG
  1428. printf("token = TINFO\n");
  1429. #endif
  1430. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1431. DbgPrint("ParseString: syntax error\n");
  1432. return FALSE;
  1433. }
  1434. next_token = peek_token(&tib);
  1435. if (peek_token(&tib) == TLEFTPAREN) {
  1436. on_controls |= DM_INFORMATION;
  1437. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1438. } else if (IsKeywordToken(next_token)) {
  1439. off_controls |= DM_INFORMATION;
  1440. expecting &= EXPECTING_RIGHTPAREN;
  1441. } else {
  1442. DbgPrint("ParseString: bad syntax for INFO\n");
  1443. return FALSE;
  1444. }
  1445. break;
  1446. case TLANMAN:
  1447. #ifdef DBGDBG
  1448. printf("token = TLANMAN\n");
  1449. #endif
  1450. if (expecting != EXPECTING_NOTHING) {
  1451. DbgPrint("ParseString: syntax error\n");
  1452. return FALSE;
  1453. }
  1454. application_mask = DG_LANMAN;
  1455. pInfo = &VrDiagnosticGroups[DI_LANMAN].Diagnostic;
  1456. on_controls = off_controls = 0;
  1457. RtlZeroMemory(&memory, sizeof(memory));
  1458. RtlZeroMemory(&stack, sizeof(stack));
  1459. RtlZeroMemory(&structure, sizeof(structure));
  1460. pFunc = NULL;
  1461. if (peek_token(&tib) == TLEFTPAREN) {
  1462. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1463. } else {
  1464. expecting = EXPECTING_NOTHING;
  1465. }
  1466. break;
  1467. case TMAILSLOT:
  1468. #ifdef DBGDBG
  1469. printf("token = TMAILSLOT\n");
  1470. #endif
  1471. if (expecting != EXPECTING_NOTHING) {
  1472. DbgPrint("ParseString: syntax error\n");
  1473. return FALSE;
  1474. }
  1475. application_mask = DG_MAILSLOT;
  1476. pInfo = &VrDiagnosticGroups[DI_MAILSLOT].Diagnostic;
  1477. on_controls = off_controls = 0;
  1478. RtlZeroMemory(&memory, sizeof(memory));
  1479. RtlZeroMemory(&stack, sizeof(stack));
  1480. RtlZeroMemory(&structure, sizeof(structure));
  1481. pFunc = NULL;
  1482. if (peek_token(&tib) == TLEFTPAREN) {
  1483. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1484. } else {
  1485. expecting = EXPECTING_NOTHING;
  1486. }
  1487. break;
  1488. case TNAMEPIPE:
  1489. #ifdef DBGDBG
  1490. printf("token = TNAMEPIPE\n");
  1491. #endif
  1492. if (expecting != EXPECTING_NOTHING) {
  1493. DbgPrint("ParseString: syntax error\n");
  1494. return FALSE;
  1495. }
  1496. application_mask = DG_NAMEPIPE;
  1497. pInfo = &VrDiagnosticGroups[DI_NAMEPIPE].Diagnostic;
  1498. on_controls = off_controls = 0;
  1499. RtlZeroMemory(&memory, sizeof(memory));
  1500. RtlZeroMemory(&stack, sizeof(stack));
  1501. RtlZeroMemory(&structure, sizeof(structure));
  1502. pFunc = NULL;
  1503. if (peek_token(&tib) == TLEFTPAREN) {
  1504. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1505. } else {
  1506. expecting = EXPECTING_NOTHING;
  1507. }
  1508. break;
  1509. case TNETBIOS:
  1510. #ifdef DBGDBG
  1511. printf("token = TNETBIOS\n");
  1512. #endif
  1513. if (expecting != EXPECTING_NOTHING) {
  1514. DbgPrint("ParseString: syntax error\n");
  1515. return FALSE;
  1516. }
  1517. application_mask = DG_NETBIOS;
  1518. pInfo = &VrDiagnosticGroups[DI_NETBIOS].Diagnostic;
  1519. on_controls = off_controls = 0;
  1520. RtlZeroMemory(&memory, sizeof(memory));
  1521. RtlZeroMemory(&stack, sizeof(stack));
  1522. RtlZeroMemory(&structure, sizeof(structure));
  1523. pFunc = NULL;
  1524. if (peek_token(&tib) == TLEFTPAREN) {
  1525. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1526. } else {
  1527. expecting = EXPECTING_NOTHING;
  1528. }
  1529. break;
  1530. case TPAUSEBREAK:
  1531. #ifdef DBGDBG
  1532. printf("token = TPAUSEBREAK\n");
  1533. #endif
  1534. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1535. DbgPrint("ParseString: syntax error\n");
  1536. return FALSE;
  1537. }
  1538. next_token = peek_token(&tib);
  1539. if (peek_token(&tib) == TLEFTPAREN) {
  1540. on_controls |= DM_PAUSEBREAK;
  1541. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1542. } else if (IsKeywordToken(next_token)) {
  1543. off_controls |= DM_PAUSEBREAK;
  1544. expecting &= EXPECTING_RIGHTPAREN;
  1545. } else {
  1546. DbgPrint("ParseString: bad syntax for PAUSEBREAK\n");
  1547. return FALSE;
  1548. }
  1549. break;
  1550. case TWARN:
  1551. #ifdef DBGDBG
  1552. printf("token = TWARN\n");
  1553. #endif
  1554. if ((expecting != EXPECTING_NOTHING) && !(expecting & EXPECTING_RIGHTPAREN)) {
  1555. DbgPrint("ParseString: syntax error\n");
  1556. return FALSE;
  1557. }
  1558. next_token = peek_token(&tib);
  1559. if (peek_token(&tib) == TLEFTPAREN) {
  1560. on_controls |= DM_WARNING;
  1561. expecting = EXPECTING_LEFTPAREN | EXPECTING_RIGHTPAREN;
  1562. } else if (IsKeywordToken(next_token)) {
  1563. off_controls |= DM_WARNING;
  1564. expecting &= EXPECTING_RIGHTPAREN;
  1565. } else {
  1566. DbgPrint("ParseString: bad syntax for WARN\n");
  1567. return FALSE;
  1568. }
  1569. break;
  1570. }
  1571. }
  1572. }
  1573. PRIVATE
  1574. int
  1575. probe_parens(
  1576. LPSTR str
  1577. )
  1578. /*++
  1579. Routine Description:
  1580. Probes env string and returns balance of parentheses. Number of parentheses
  1581. may balance, but string could still break syntax. First line of defence
  1582. Arguments:
  1583. str - pointer to string containing parentheses to check balance for
  1584. Return Value:
  1585. int number of levels by which parentheses don't balance, or 0 if they do.
  1586. -ve number means more right parens than left
  1587. --*/
  1588. {
  1589. int balance = 0;
  1590. while (*str) {
  1591. if (*str == '(') {
  1592. ++balance;
  1593. } else if (*str == ')') {
  1594. --balance;
  1595. }
  1596. ++str;
  1597. }
  1598. return balance;
  1599. }
  1600. PRIVATE
  1601. VOID
  1602. apply_controls(
  1603. IN DWORD mask,
  1604. IN LPFUNCTION_DIAGNOSTIC lpFunc,
  1605. IN DWORD on_controls,
  1606. IN DWORD off_controls,
  1607. IN LPMEMORY_INFO lpMemory,
  1608. IN LPMEMORY_INFO lpStack,
  1609. IN LPSTRUCT_INFO lpStructure
  1610. )
  1611. {
  1612. DWORD bit = 1;
  1613. DWORD index = 0;
  1614. if (on_controls & DM_DUMPSTACK) {
  1615. lpStack->Segment.IsRegister = TRUE;
  1616. lpStack->Segment.RegOrVal.Register = SS;
  1617. lpStack->Offset.IsRegister = TRUE;
  1618. lpStack->Offset.RegOrVal.Register = SP;
  1619. lpStack->DumpType = SD_WORD;
  1620. }
  1621. if (lpFunc) {
  1622. apply_diags(&lpFunc->Diagnostic,
  1623. on_controls,
  1624. off_controls,
  1625. lpMemory,
  1626. lpStack,
  1627. lpStructure
  1628. );
  1629. } else {
  1630. while (bit) {
  1631. if (mask & bit) {
  1632. apply_diags(&VrDiagnosticGroups[index].Diagnostic,
  1633. on_controls,
  1634. off_controls,
  1635. lpMemory,
  1636. lpStack,
  1637. lpStructure
  1638. );
  1639. }
  1640. bit <<= 1;
  1641. ++index;
  1642. }
  1643. }
  1644. }
  1645. PRIVATE
  1646. VOID
  1647. apply_diags(
  1648. IN LPDIAGNOSTIC_INFO lpDiags,
  1649. IN DWORD on_controls,
  1650. IN DWORD off_controls,
  1651. IN LPMEMORY_INFO lpMemory,
  1652. IN LPMEMORY_INFO lpStack,
  1653. IN LPSTRUCT_INFO lpStructure
  1654. )
  1655. {
  1656. lpDiags->OnControl |= on_controls;
  1657. lpDiags->OffControl |= off_controls;
  1658. if (on_controls & DM_DUMPMEM) {
  1659. *(&(lpDiags->MemoryInfo)) = *lpMemory;
  1660. }
  1661. if (on_controls & DM_DUMPSTACK) {
  1662. *(&(lpDiags->StackInfo)) = *lpStack;
  1663. }
  1664. if (on_controls & DM_DUMPSTRUCT) {
  1665. *(&lpDiags->StructInfo) = *lpStructure;
  1666. }
  1667. }
  1668. PRIVATE
  1669. LPFUNCTION_DIAGNOSTIC
  1670. FindFuncDiags(
  1671. IN LPSTR function_name
  1672. )
  1673. {
  1674. LPFUNCTION_DIAGNOSTIC ptr;
  1675. //
  1676. // as promised: search w/ case, then w/o case
  1677. //
  1678. for (ptr = FunctionList; ptr; ptr = ptr->Next) {
  1679. if (!strcmp(function_name, ptr->FunctionName)) {
  1680. return ptr;
  1681. }
  1682. }
  1683. for (ptr = FunctionList; ptr; ptr = ptr->Next) {
  1684. if (!_stricmp(function_name, ptr->FunctionName)) {
  1685. return ptr;
  1686. }
  1687. }
  1688. return NULL;
  1689. }
  1690. PRIVATE
  1691. LPFUNCTION_DIAGNOSTIC
  1692. AllocFuncDiags(
  1693. IN LPSTR function_name
  1694. )
  1695. {
  1696. LPFUNCTION_DIAGNOSTIC result;
  1697. result = calloc(1, sizeof(FUNCTION_DIAGNOSTIC));
  1698. if (result) {
  1699. strcpy(result->FunctionName, function_name);
  1700. }
  1701. return result;
  1702. }
  1703. TOKEN parse_token(LPTIB pTib) {
  1704. LPSTR ptr = pTib->TokenStream;
  1705. TOKEN token;
  1706. ptr = skip_ws(ptr);
  1707. if (!*ptr) {
  1708. token = TEOS;
  1709. } else if (*ptr == '(' ) {
  1710. token = TLEFTPAREN;
  1711. ++ptr;
  1712. } else if (*ptr == ')') {
  1713. token = TRIGHTPAREN;
  1714. ++ptr;
  1715. } else {
  1716. char* tokstr;
  1717. REGVAL regval;
  1718. //
  1719. // got some other type of token. This bit leaves ptr pointing at ws or EOS
  1720. //
  1721. tokstr = extract_token(pTib, &ptr);
  1722. if (IsLexRegister(tokstr, &regval)) {
  1723. token = TREGISTER;
  1724. pTib->RegValOrId.RegVal = regval;
  1725. } else if (IsLexNumber(tokstr, &regval)) {
  1726. token = TNUMBER;
  1727. pTib->RegValOrId.RegVal = regval;
  1728. } else if (!IsLexKeyword(tokstr, &token)){
  1729. token = TUNKNOWN;
  1730. }
  1731. #ifdef DBGDBG
  1732. printf("parse_token: token = %s\n", tokstr);
  1733. #endif
  1734. }
  1735. pTib->TokenStream = ptr; // pointer to next token (if any)
  1736. pTib->Token = token;
  1737. return token;
  1738. }
  1739. TOKEN peek_token(LPTIB pTib) {
  1740. LPSTR ptr;
  1741. TOKEN token;
  1742. //
  1743. // gets next token type, but doesn't update TIB
  1744. //
  1745. ptr = skip_ws(pTib->TokenStream);
  1746. if (!*ptr) {
  1747. return TEOS;
  1748. } else if (*ptr == '(' ) {
  1749. return TLEFTPAREN;
  1750. } else if (*ptr == ')') {
  1751. return TRIGHTPAREN;
  1752. } else {
  1753. char* tokstr;
  1754. REGVAL regval;
  1755. tokstr = extract_token(pTib, &ptr);
  1756. if (IsLexRegister(tokstr, &regval)) {
  1757. return TREGISTER;
  1758. }
  1759. if (IsLexNumber(tokstr, &regval)) {
  1760. return TNUMBER;
  1761. }
  1762. if (IsLexKeyword(tokstr, &token)) {
  1763. return token;
  1764. }
  1765. }
  1766. return TUNKNOWN; // don't require anything else
  1767. }
  1768. LPSTR skip_ws(LPSTR str) {
  1769. while (*str && (*str == ' '|| *str == '\t' || *str == ',')) {
  1770. ++str;
  1771. }
  1772. return str;
  1773. }
  1774. LPSTR search_delim(LPSTR str) {
  1775. // strpbrk(str, " \t,()");
  1776. while (*str
  1777. && !(*str == ' '
  1778. || *str == '\t'
  1779. || *str == ','
  1780. || *str == '('
  1781. || *str == ')'
  1782. )
  1783. ) {
  1784. ++str;
  1785. }
  1786. return str;
  1787. }
  1788. LPSTR extract_token(LPTIB pTib, LPSTR* token_stream) {
  1789. LPSTR ptr;
  1790. DWORD len;
  1791. ptr = search_delim(*token_stream);
  1792. len = (DWORD)ptr - (DWORD)*token_stream;
  1793. if (!len) {
  1794. return NULL;
  1795. }
  1796. strncpy(pTib->RegValOrId.Id, *token_stream, len);
  1797. pTib->RegValOrId.Id[len] = 0;
  1798. *token_stream = ptr;
  1799. return pTib->RegValOrId.Id;
  1800. }
  1801. BOOL IsLexKeyword(LPSTR tokstr, TOKEN* pToken) {
  1802. int i;
  1803. for (i = 0; i < NUMBER_OF_RECOGNIZABLE_TOKENS; ++i) {
  1804. if (!_stricmp(tokstr, DiagnosticTokens[i].TokenString)) {
  1805. *pToken = DiagnosticTokens[i].Token;
  1806. return TRUE;
  1807. }
  1808. }
  1809. return FALSE;
  1810. }
  1811. BOOL IsLexRegister(LPSTR tokstr, LPREGVAL lpRegVal) {
  1812. int i;
  1813. if (strlen(tokstr) == 2) {
  1814. for (i = 0; i < NUMBER_OF_CPU_REGISTERS; ++i) {
  1815. if (!_stricmp(tokstr, Registers[i].RegisterName)) {
  1816. lpRegVal->IsRegister = TRUE;
  1817. lpRegVal->RegOrVal.Register = Registers[i].Register;
  1818. return TRUE;
  1819. }
  1820. }
  1821. }
  1822. return FALSE;
  1823. }
  1824. BOOL IsLexNumber(LPSTR tokstr, LPREGVAL lpRegVal) {
  1825. WORD number = 0;
  1826. BOOL yes = FALSE;
  1827. //
  1828. // go round this loop until no more hex digits. Too bad if we entered 5
  1829. // digits - number will be overflowed and results unpredictable, but its
  1830. // only debug code
  1831. //
  1832. if (!_strnicmp(tokstr, "0x", 2)) {
  1833. tokstr += 2;
  1834. yes = isxdigit(*tokstr);
  1835. while (isxdigit((int)*tokstr)) {
  1836. number = number * (WORD)16 + hex((char)*tokstr);
  1837. ++tokstr;
  1838. }
  1839. } else if (yes = isdigit(*tokstr)) {
  1840. number = (WORD)atoi(tokstr);
  1841. }
  1842. if (yes) {
  1843. lpRegVal->IsRegister = FALSE;
  1844. lpRegVal->RegOrVal.Value = number;
  1845. }
  1846. return yes;
  1847. }
  1848. WORD hex(char hexch) {
  1849. return hexch <= '9' ? (WORD)(hexch - '0')
  1850. : (WORD)(toupper(hexch) - ('0' + ('A' - ('9' + 1))));
  1851. }
  1852. BOOL IsKeywordToken(TOKEN token) {
  1853. return token >= TBREAK && token <= TWARN;
  1854. }
  1855. BOOL IsValidDumpDescriptor(char* str) {
  1856. static char md_chars[] = MD_CHARS;
  1857. if (strlen(str) > 1) {
  1858. return FALSE;
  1859. }
  1860. return strchr(md_chars, *str) != NULL;
  1861. }
  1862. BOOL IsValidStructDescriptor(char* str) {
  1863. static char sd_chars[] = SD_CHARS;
  1864. unsigned len = strlen(str);
  1865. // return (len <= MAX_DESC_LEN) ? (strspn(str, sd_chars) == len) : FALSE;
  1866. return (len <= MAX_DESC_LEN);
  1867. }
  1868. PRIVATE
  1869. LPSTR
  1870. ConvertFlagsToString(
  1871. IN WORD FlagsRegister,
  1872. OUT LPSTR Buffer
  1873. )
  1874. /*++
  1875. Routine Description:
  1876. Given a 16-bit word, interpret bit positions as for x86 Flags register
  1877. and produce descriptive string of flags state (as per debug) eg:
  1878. NV UP DI PL NZ NA PO NC ODItSZxAxPxC = 000000000000b
  1879. OV DN EI NG ZR AC PE CY ODItSZxAxPxC = 111111111111b
  1880. Trap Flag (t) is not dumped since this has no interest for programs which
  1881. are not debuggers or don't examine program execution (ie virtually none)
  1882. Arguments:
  1883. FlagsRegister - 16-bit flags
  1884. Buffer - place to store string. Requires 25 bytes inc \0
  1885. Return Value:
  1886. Address of <Buffer>
  1887. --*/
  1888. {
  1889. static char* flags_states[16][2] = {
  1890. //0 1
  1891. "NC", "CY", // CF (0x0001) - Carry
  1892. "", "", // x (0x0002)
  1893. "PO", "PE", // PF (0x0004) - Parity
  1894. "", "", // x (0x0008)
  1895. "NA", "AC", // AF (0x0010) - Aux (half) carry
  1896. "", "", // x (0x0020)
  1897. "NZ", "ZR", // ZF (0x0040) - Zero
  1898. "PL", "NG", // SF (0x0080) - Sign
  1899. "", "", // TF (0x0100) - Trap (not dumped)
  1900. "DI", "EI", // IF (0x0200) - Interrupt
  1901. "UP", "DN", // DF (0x0400) - Direction
  1902. "NV", "OV", // OF (0x0800) - Overflow
  1903. "", "", // x (0x1000) - (I/O Privilege Level) (not dumped)
  1904. "", "", // x (0x2000) - (I/O Privilege Level) (not dumped)
  1905. "", "", // x (0x4000) - (Nested Task) (not dumped)
  1906. "", "" // x (0x8000)
  1907. };
  1908. int i;
  1909. WORD bit;
  1910. BOOL on;
  1911. *Buffer = 0;
  1912. for (bit=0x0800, i=11; bit; bit >>= 1, --i) {
  1913. on = (BOOL)((FlagsRegister & bit) == bit);
  1914. if (flags_states[i][on][0]) {
  1915. strcat(Buffer, flags_states[i][on]);
  1916. strcat(Buffer, " ");
  1917. }
  1918. }
  1919. return Buffer;
  1920. }
  1921. #ifndef DBGDBG
  1922. PRIVATE
  1923. WORD
  1924. GetFlags(
  1925. VOID
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. Supplies the missing softpc function
  1930. Arguments:
  1931. None.
  1932. Return Value:
  1933. Conglomerates softpc flags into x86 flags word
  1934. --*/
  1935. {
  1936. WORD flags;
  1937. flags = (WORD)getCF();
  1938. flags |= (WORD)getPF() << 2;
  1939. flags |= (WORD)getAF() << 4;
  1940. flags |= (WORD)getZF() << 6;
  1941. flags |= (WORD)getSF() << 7;
  1942. flags |= (WORD)getIF() << 9;
  1943. flags |= (WORD)getDF() << 10;
  1944. flags |= (WORD)getOF() << 11;
  1945. return flags;
  1946. }
  1947. #endif
  1948. PRIVATE
  1949. DWORD
  1950. GrabDosData(
  1951. IN LPBYTE DosMemoryPointer,
  1952. IN DWORD DataSize
  1953. )
  1954. /*++
  1955. Routine Description:
  1956. Reads one basic data element from DOS memory in a certain format (BYTE, WORD
  1957. or DWORD)
  1958. Arguments:
  1959. DosMemoryPointer - Flat 32-bit pointer to place in DOS memory from where
  1960. to read data
  1961. DataSize - size (in bytes) of data to read - 1, 2 or 4
  1962. Return Value:
  1963. DWORD - value read from DOS memory
  1964. --*/
  1965. {
  1966. switch (DataSize) {
  1967. case 1:
  1968. return (DWORD)*DosMemoryPointer;
  1969. case 2:
  1970. return (DWORD)*((LPWORD)DosMemoryPointer);
  1971. case 4:
  1972. return (DWORD)*((LPDWORD)DosMemoryPointer);
  1973. }
  1974. return 0;
  1975. }
  1976. #endif // DBG