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.

2232 lines
53 KiB

  1. /*** ntexpr.cpp - expression evaluator for NT debugger
  2. *
  3. * Copyright <C> 1990-2001, Microsoft Corporation
  4. *
  5. * Purpose:
  6. * With the current command line at *g_CurCmd, parse
  7. * and evaluate the next expression.
  8. *
  9. * Revision History:
  10. *
  11. * [-] 18-Apr-1990 Richk Created - split from ntcmd.c.
  12. *
  13. *************************************************************************/
  14. #include "ntsdp.hpp"
  15. struct Res
  16. {
  17. char chRes[3];
  18. ULONG classRes;
  19. ULONG valueRes;
  20. };
  21. Res g_Reserved[] =
  22. {
  23. { 'o', 'r', '\0', LOGOP_CLASS, LOGOP_OR },
  24. { 'b', 'y', '\0', UNOP_CLASS, UNOP_BY },
  25. { 'w', 'o', '\0', UNOP_CLASS, UNOP_WO },
  26. { 'd', 'w', 'o', UNOP_CLASS, UNOP_DWO },
  27. { 'q', 'w', 'o', UNOP_CLASS, UNOP_QWO },
  28. { 'h', 'i', '\0', UNOP_CLASS, UNOP_HI },
  29. { 'm', 'o', 'd', MULOP_CLASS, MULOP_MOD },
  30. { 'x', 'o', 'r', LOGOP_CLASS, LOGOP_XOR },
  31. { 'a', 'n', 'd', LOGOP_CLASS, LOGOP_AND },
  32. { 'p', 'o', 'i', UNOP_CLASS, UNOP_POI },
  33. { 'n', 'o', 't', UNOP_CLASS, UNOP_NOT },
  34. { 'l', 'o', 'w', UNOP_CLASS, UNOP_LOW },
  35. { 'v', 'a', 'l', UNOP_CLASS, UNOP_VAL }
  36. };
  37. Res g_X86Reserved[] =
  38. {
  39. { 'e', 'a', 'x', REG_CLASS, X86_EAX },
  40. { 'e', 'b', 'x', REG_CLASS, X86_EBX },
  41. { 'e', 'c', 'x', REG_CLASS, X86_ECX },
  42. { 'e', 'd', 'x', REG_CLASS, X86_EDX },
  43. { 'e', 'b', 'p', REG_CLASS, X86_EBP },
  44. { 'e', 's', 'p', REG_CLASS, X86_ESP },
  45. { 'e', 'i', 'p', REG_CLASS, X86_EIP },
  46. { 'e', 's', 'i', REG_CLASS, X86_ESI },
  47. { 'e', 'd', 'i', REG_CLASS, X86_EDI },
  48. { 'e', 'f', 'l', REG_CLASS, X86_EFL }
  49. };
  50. #define RESERVESIZE (sizeof(g_Reserved) / sizeof(Res))
  51. #define X86_RESERVESIZE (sizeof(g_X86Reserved) / sizeof(Res))
  52. char * g_X86SegRegs[] =
  53. {
  54. "cs", "ds", "es", "fs", "gs", "ss"
  55. };
  56. #define X86_SEGREGSIZE (sizeof(g_X86SegRegs) / sizeof(char *))
  57. ULONG g_SavedClass;
  58. LONG64 g_SavedValue;
  59. PSTR g_SavedCommand;
  60. TYPES_INFO g_ExprTypeInfo;
  61. ULONG64 g_LastExpressionValue;
  62. BOOL g_AllowUnresolvedSymbols;
  63. ULONG g_NumUnresolvedSymbols;
  64. BOOL g_ForcePositiveNumber;
  65. // Syms in a expression evaluate to values rather than address
  66. BOOL g_TypedExpr;
  67. PCSTR g_ExprDesc;
  68. USHORT g_AddrExprType;
  69. ADDR g_TempAddr;
  70. ULONG
  71. PeekToken(
  72. PLONG64 pvalue
  73. );
  74. ULONG
  75. GetTokenSym(
  76. PLONG64 pvalue
  77. );
  78. ULONG
  79. NextToken(
  80. PLONG64 pvalue
  81. );
  82. ULONG
  83. GetRegToken(
  84. PCHAR str,
  85. PULONG64 value
  86. );
  87. void
  88. AcceptToken(
  89. void
  90. );
  91. ULONG64
  92. GetCommonExpression(
  93. VOID
  94. );
  95. LONG64
  96. GetExpr(
  97. void
  98. );
  99. LONG64
  100. GetLRterm(
  101. void
  102. );
  103. LONG64
  104. GetLterm(
  105. void
  106. );
  107. LONG64
  108. GetShiftTerm(
  109. void
  110. );
  111. LONG64
  112. GetAterm(
  113. void
  114. );
  115. LONG64
  116. GetMterm(
  117. void
  118. );
  119. LONG64
  120. GetTerm(
  121. void
  122. );
  123. LONG64
  124. GetTypedExpression(
  125. void
  126. );
  127. BOOL
  128. GetSymValue(
  129. PSTR Symbol,
  130. PULONG64 pValue
  131. );
  132. ULONG
  133. GetRegToken(
  134. char *str,
  135. PULONG64 value
  136. )
  137. /*++
  138. Routine Description:
  139. Arguments:
  140. Return Value:
  141. --*/
  142. {
  143. if ((*value = RegIndexFromName(str)) != REG_ERROR)
  144. {
  145. return REG_CLASS;
  146. }
  147. else
  148. {
  149. *value = BADREG;
  150. return ERROR_CLASS;
  151. }
  152. }
  153. void
  154. ForceAddrExpression(ULONG SegReg, PADDR Address, ULONG64 Value)
  155. {
  156. DESCRIPTOR64 DescBuf, *Desc = NULL;
  157. *Address = g_TempAddr;
  158. // Rewriting the offset may change flat address so
  159. // be sure to recompute it later.
  160. Off(*Address) = Value;
  161. // If it wasn't an explicit address expression
  162. // force it to be an address
  163. if (!(g_AddrExprType & ~INSTR_POINTER))
  164. {
  165. g_AddrExprType = Address->type =
  166. g_X86InVm86 ? ADDR_V86 : (g_X86InCode16 ? ADDR_16 : ADDR_FLAT);
  167. if (g_AddrExprType != ADDR_FLAT &&
  168. SegReg < SEGREG_COUNT &&
  169. g_Machine->GetSegRegDescriptor(SegReg, &DescBuf) == S_OK)
  170. {
  171. PCROSS_PLATFORM_CONTEXT ScopeContext =
  172. GetCurrentScopeContext();
  173. if (ScopeContext)
  174. {
  175. g_Machine->PushContext(ScopeContext);
  176. }
  177. Address->seg = (USHORT)
  178. GetRegVal32(g_Machine->GetSegRegNum(SegReg));
  179. Desc = &DescBuf;
  180. if (ScopeContext)
  181. {
  182. g_Machine->PopContext();
  183. }
  184. }
  185. else
  186. {
  187. Address->seg = 0;
  188. }
  189. }
  190. else if fnotFlat(*Address)
  191. {
  192. // This case (i.e., g_AddrExprType && !flat) results from
  193. // an override (i.e., %,,&, or #) being used but no segment
  194. // being specified to force a flat address computation.
  195. Type(*Address) = g_AddrExprType;
  196. Address->seg = 0;
  197. if (SegReg < SEGREG_COUNT)
  198. {
  199. // test flag for IP or EIP as register argument
  200. // if so, use CS as default register
  201. if (fInstrPtr(*Address))
  202. {
  203. SegReg = SEGREG_CODE;
  204. }
  205. if (g_Machine->GetSegRegDescriptor(SegReg, &DescBuf) == S_OK)
  206. {
  207. PCROSS_PLATFORM_CONTEXT ScopeContext =
  208. GetCurrentScopeContext();
  209. if (ScopeContext)
  210. {
  211. g_Machine->PushContext(ScopeContext);
  212. }
  213. Address->seg = (USHORT)
  214. GetRegVal32(g_Machine->GetSegRegNum(SegReg));
  215. Desc = &DescBuf;
  216. if (ScopeContext)
  217. {
  218. g_Machine->PopContext();
  219. }
  220. }
  221. }
  222. }
  223. // Force sign-extension of 32-bit flat addresses.
  224. if (Address->type == ADDR_FLAT && !g_Machine->m_Ptr64)
  225. {
  226. Off(*Address) = EXTEND64(Off(*Address));
  227. }
  228. // Force an updated flat address to be computed.
  229. NotFlat(*Address);
  230. ComputeFlatAddress(Address, Desc);
  231. }
  232. PADDR
  233. GetAddrExprDesc(
  234. ULONG SegReg,
  235. PCSTR Desc,
  236. PADDR Address
  237. )
  238. {
  239. NotFlat(*Address);
  240. // Evaluate a normal expression and then
  241. // force the result to be an address.
  242. if (Desc == NULL)
  243. {
  244. Desc = "Address expression missing from";
  245. }
  246. ULONG64 Value = GetExprDesc(Desc);
  247. ForceAddrExpression(SegReg, Address, Value);
  248. g_ExprDesc = NULL;
  249. return Address;
  250. }
  251. ULONG64
  252. GetExprDesc(PCSTR ExprDesc)
  253. {
  254. if (ExprDesc != NULL)
  255. {
  256. g_ExprDesc = ExprDesc;
  257. }
  258. else
  259. {
  260. g_ExprDesc = "Numeric expression missing from";
  261. }
  262. ULONG64 Value = GetCommonExpression();
  263. g_LastExpressionValue = Value;
  264. g_ExprDesc = NULL;
  265. return Value;
  266. }
  267. ULONG64
  268. GetTermExprDesc(PCSTR ExprDesc)
  269. {
  270. if (ExprDesc != NULL)
  271. {
  272. g_ExprDesc = ExprDesc;
  273. }
  274. else
  275. {
  276. g_ExprDesc = "Numeric value missing from";
  277. }
  278. g_SavedClass = INVALID_CLASS;
  279. ULONG64 Value = GetTerm();
  280. g_ExprDesc = NULL;
  281. return Value;
  282. }
  283. /*** GetCommonExpression - read and evaluate expression
  284. *
  285. * Purpose:
  286. * From the current command line position at g_CurCmd,
  287. * read and evaluate the next possible expression.
  288. *
  289. *************************************************************************/
  290. ULONG64
  291. GetCommonExpression(VOID)
  292. {
  293. CHAR ch;
  294. g_SavedClass = INVALID_CLASS;
  295. ch = PeekChar();
  296. switch(ch)
  297. {
  298. case '&':
  299. g_CurCmd++;
  300. g_AddrExprType = ADDR_V86;
  301. break;
  302. case '#':
  303. g_CurCmd++;
  304. g_AddrExprType = ADDR_16;
  305. break;
  306. case '%':
  307. g_CurCmd++;
  308. g_AddrExprType = ADDR_FLAT;
  309. break;
  310. default:
  311. g_AddrExprType = ADDR_NONE;
  312. break;
  313. }
  314. PeekChar();
  315. return (ULONG64)GetExpr();
  316. }
  317. /*** GetExpr - Get expression
  318. *
  319. * Purpose:
  320. * Parse logical-terms separated by logical operators into
  321. * expression value.
  322. *
  323. * Input:
  324. * g_CurCmd - present command line position
  325. *
  326. * Returns:
  327. * long value of logical result.
  328. *
  329. * Exceptions:
  330. * error exit: SYNTAX - bad expression or premature end-of-line
  331. *
  332. * Notes:
  333. * may be called recursively.
  334. * <expr> = <lterm> [<logic-op> <lterm>]*
  335. * <logic-op> = AND (&), OR (|), XOR (^)
  336. *
  337. *************************************************************************/
  338. LONG64
  339. GetExpr (
  340. void
  341. )
  342. {
  343. LONG64 value1;
  344. LONG64 value2;
  345. ULONG opclass;
  346. LONG64 opvalue;
  347. //dprintf("LONG64 GetExpr ()\n");
  348. value1 = GetLRterm();
  349. while ((opclass = PeekToken(&opvalue)) == LOGOP_CLASS) {
  350. AcceptToken();
  351. value2 = GetLRterm();
  352. switch (opvalue) {
  353. case LOGOP_AND:
  354. value1 &= value2;
  355. break;
  356. case LOGOP_OR:
  357. value1 |= value2;
  358. break;
  359. case LOGOP_XOR:
  360. value1 ^= value2;
  361. break;
  362. default:
  363. error(SYNTAX);
  364. }
  365. }
  366. return value1;
  367. }
  368. /*** GetLRterm - get logical relational term
  369. *
  370. * Purpose:
  371. * Parse logical-terms separated by logical relational
  372. * operators into the expression value.
  373. *
  374. * Input:
  375. * g_CurCmd - present command line position
  376. *
  377. * Returns:
  378. * long value of logical result.
  379. *
  380. * Exceptions:
  381. * error exit: SYNTAX - bad expression or premature end-of-line
  382. *
  383. * Notes:
  384. * may be called recursively.
  385. * <expr> = <lterm> [<rel-logic-op> <lterm>]*
  386. * <logic-op> = '==' or '=', '!=', '>', '<'
  387. *
  388. *************************************************************************/
  389. LONG64
  390. GetLRterm (
  391. void
  392. )
  393. {
  394. LONG64 value1;
  395. LONG64 value2;
  396. ULONG opclass;
  397. LONG64 opvalue;
  398. //dprintf("LONG64 GetLRterm ()\n");
  399. value1 = GetLterm();
  400. while ((opclass = PeekToken(&opvalue)) == LRELOP_CLASS) {
  401. AcceptToken();
  402. value2 = GetLterm();
  403. switch (opvalue) {
  404. case LRELOP_EQ:
  405. value1 = (value1 == value2);
  406. break;
  407. case LRELOP_NE:
  408. value1 = (value1 != value2);
  409. break;
  410. case LRELOP_LT:
  411. value1 = (value1 < value2);
  412. break;
  413. case LRELOP_GT:
  414. value1 = (value1 > value2);
  415. break;
  416. default:
  417. error(SYNTAX);
  418. }
  419. }
  420. return value1;
  421. }
  422. /*** GetLterm - get logical term
  423. *
  424. * Purpose:
  425. * Parse shift-terms separated by shift operators into
  426. * logical term value.
  427. *
  428. * Input:
  429. * g_CurCmd - present command line position
  430. *
  431. * Returns:
  432. * long value of sum.
  433. *
  434. * Exceptions:
  435. * error exit: SYNTAX - bad logical term or premature end-of-line
  436. *
  437. * Notes:
  438. * may be called recursively.
  439. * <lterm> = <sterm> [<shift-op> <sterm>]*
  440. * <shift-op> = <<, >>, >>>
  441. *
  442. *************************************************************************/
  443. LONG64
  444. GetLterm (
  445. void
  446. )
  447. {
  448. LONG64 value1 = GetShiftTerm();
  449. LONG64 value2;
  450. ULONG opclass;
  451. LONG64 opvalue;
  452. //dprintf("LONG64 GetLterm ()\n");
  453. while ((opclass = PeekToken(&opvalue)) == SHIFT_CLASS) {
  454. AcceptToken();
  455. value2 = GetShiftTerm();
  456. switch (opvalue) {
  457. case SHIFT_LEFT:
  458. value1 <<= value2;
  459. break;
  460. case SHIFT_RIGHT_LOGICAL:
  461. value1 = (LONG64)((ULONG64)value1 >> value2);
  462. break;
  463. case SHIFT_RIGHT_ARITHMETIC:
  464. value1 >>= value2;
  465. break;
  466. default:
  467. error(SYNTAX);
  468. }
  469. }
  470. return value1;
  471. }
  472. /*** GetShiftTerm - get logical term
  473. *
  474. * Purpose:
  475. * Parse additive-terms separated by additive operators into
  476. * shift term value.
  477. *
  478. * Input:
  479. * g_CurCmd - present command line position
  480. *
  481. * Returns:
  482. * long value of sum.
  483. *
  484. * Exceptions:
  485. * error exit: SYNTAX - bad shift term or premature end-of-line
  486. *
  487. * Notes:
  488. * may be called recursively.
  489. * <sterm> = <aterm> [<add-op> <aterm>]*
  490. * <add-op> = +, -
  491. *
  492. *************************************************************************/
  493. LONG64
  494. GetShiftTerm (
  495. void
  496. )
  497. {
  498. LONG64 value1 = GetAterm();
  499. LONG64 value2;
  500. ULONG opclass;
  501. LONG64 opvalue;
  502. BOOL faddr = (BOOL) (g_AddrExprType != ADDR_NONE);
  503. //dprintf("LONG64 GetShifTerm ()\n");
  504. while ((opclass = PeekToken(&opvalue)) == ADDOP_CLASS) {
  505. AcceptToken();
  506. value2 = GetAterm();
  507. if (!faddr && g_AddrExprType) {
  508. LONG64 tmp = value1;
  509. value1 = value2;
  510. value2 = tmp;
  511. }
  512. if (g_AddrExprType & ~INSTR_POINTER)
  513. {
  514. switch (opvalue) {
  515. case ADDOP_PLUS:
  516. AddrAdd(&g_TempAddr,value2);
  517. value1 += value2;
  518. break;
  519. case ADDOP_MINUS:
  520. AddrSub(&g_TempAddr,value2);
  521. value1 -= value2;
  522. break;
  523. default:
  524. error(SYNTAX);
  525. }
  526. } else {
  527. switch (opvalue) {
  528. case ADDOP_PLUS:
  529. value1 += value2;
  530. break;
  531. case ADDOP_MINUS:
  532. value1 -= value2;
  533. break;
  534. default:
  535. error(SYNTAX);
  536. }
  537. }
  538. }
  539. return value1;
  540. }
  541. /*** GetAterm - get additive term
  542. *
  543. * Purpose:
  544. * Parse multiplicative-terms separated by multipicative operators
  545. * into additive term value.
  546. *
  547. * Input:
  548. * g_CurCmd - present command line position
  549. *
  550. * Returns:
  551. * long value of product.
  552. *
  553. * Exceptions:
  554. * error exit: SYNTAX - bad additive term or premature end-of-line
  555. *
  556. * Notes:
  557. * may be called recursively.
  558. * <aterm> = <mterm> [<mult-op> <mterm>]*
  559. * <mult-op> = *, /, MOD (%)
  560. *
  561. *************************************************************************/
  562. LONG64
  563. GetAterm (
  564. void
  565. )
  566. {
  567. LONG64 value1;
  568. LONG64 value2;
  569. ULONG opclass;
  570. LONG64 opvalue;
  571. //dprintf("LONG64 GetAterm ()\n");
  572. value1 = GetMterm();
  573. while ((opclass = PeekToken(&opvalue)) == MULOP_CLASS)
  574. {
  575. AcceptToken();
  576. value2 = GetMterm();
  577. switch (opvalue)
  578. {
  579. case MULOP_MULT:
  580. value1 *= value2;
  581. break;
  582. case MULOP_DIVIDE:
  583. if (value2 == 0)
  584. {
  585. error(OPERAND);
  586. }
  587. value1 /= value2;
  588. break;
  589. case MULOP_MOD:
  590. if (value2 == 0)
  591. {
  592. error(OPERAND);
  593. }
  594. value1 %= value2;
  595. break;
  596. case MULOP_SEG:
  597. PDESCRIPTOR64 pdesc;
  598. DESCRIPTOR64 desc;
  599. pdesc = NULL;
  600. if (g_AddrExprType != ADDR_NONE)
  601. {
  602. Type(g_TempAddr) = g_AddrExprType;
  603. }
  604. else
  605. {
  606. // We don't know what kind of address this is
  607. // Let's try to figure it out.
  608. if (g_X86InVm86)
  609. {
  610. g_AddrExprType = Type(g_TempAddr) = ADDR_V86;
  611. }
  612. else if (g_Target->GetSelDescriptor
  613. (g_Machine, g_CurrentProcess->CurrentThread->Handle,
  614. (ULONG)value1, &desc) != S_OK)
  615. {
  616. error(BADSEG);
  617. }
  618. else
  619. {
  620. g_AddrExprType = Type(g_TempAddr) =
  621. (desc.Flags & X86_DESC_DEFAULT_BIG) ?
  622. ADDR_1632 : ADDR_16;
  623. pdesc = &desc;
  624. }
  625. }
  626. g_TempAddr.seg = (USHORT)value1;
  627. g_TempAddr.off = value2;
  628. ComputeFlatAddress(&g_TempAddr, pdesc);
  629. value1 = value2;
  630. break;
  631. default:
  632. error(SYNTAX);
  633. }
  634. }
  635. return value1;
  636. }
  637. /*** GetMterm - get multiplicative term
  638. *
  639. * Purpose:
  640. * Parse basic-terms optionally prefaced by one or more
  641. * unary operators into a multiplicative term.
  642. *
  643. * Input:
  644. * g_CurCmd - present command line position
  645. *
  646. * Returns:
  647. * long value of multiplicative term.
  648. *
  649. * Exceptions:
  650. * error exit: SYNTAX - bad multiplicative term or premature end-of-line
  651. *
  652. * Notes:
  653. * may be called recursively.
  654. * <mterm> = [<unary-op>] <term> | <unary-op> <mterm>
  655. * <unary-op> = <add-op>, ~ (NOT), BY, WO, DW, HI, LOW
  656. *
  657. *************************************************************************/
  658. LONG64
  659. GetMterm (
  660. void
  661. )
  662. {
  663. LONG64 value;
  664. ULONG opclass;
  665. LONG64 opvalue;
  666. ULONG size = 0;
  667. //dprintf("LONG64 GetMterm ()\n");
  668. if ((opclass = PeekToken(&opvalue)) == UNOP_CLASS ||
  669. opclass == ADDOP_CLASS)
  670. {
  671. AcceptToken();
  672. if (opvalue == UNOP_VAL)
  673. {
  674. // Do not use default expression handler for type expressions.
  675. value = GetTypedExpression();
  676. }
  677. else
  678. {
  679. value = GetMterm();
  680. }
  681. switch (opvalue)
  682. {
  683. case UNOP_NOT:
  684. value = !value;
  685. break;
  686. case UNOP_BY:
  687. size = 1;
  688. break;
  689. case UNOP_WO:
  690. size = 2;
  691. break;
  692. case UNOP_DWO:
  693. size = 4;
  694. break;
  695. case UNOP_POI:
  696. size = 0xFFFF;
  697. break;
  698. case UNOP_QWO:
  699. size = 8;
  700. break;
  701. case UNOP_LOW:
  702. value &= 0xffff;
  703. break;
  704. case UNOP_HI:
  705. value = (ULONG)value >> 16;
  706. break;
  707. case ADDOP_PLUS:
  708. break;
  709. case ADDOP_MINUS:
  710. value = -value;
  711. break;
  712. case UNOP_VAL:
  713. break;
  714. default:
  715. error(SYNTAX);
  716. }
  717. if (size)
  718. {
  719. ADDR CurAddr;
  720. NotFlat(CurAddr);
  721. ForceAddrExpression(SEGREG_COUNT, &CurAddr, value);
  722. value = 0;
  723. //
  724. // For pointers, call read pointer so we read the correct size
  725. // and sign extend.
  726. //
  727. if (size == 0xFFFF)
  728. {
  729. if (g_Target->ReadPointer(g_Machine,
  730. Flat(CurAddr),
  731. (PULONG64)&value) != S_OK)
  732. {
  733. error(MEMORY);
  734. }
  735. }
  736. else
  737. {
  738. if (GetMemString(&CurAddr, &value, size) != size)
  739. {
  740. error(MEMORY);
  741. }
  742. }
  743. // We've looked up an arbitrary value so we can
  744. // no longer consider this an address expression.
  745. g_AddrExprType = ADDR_NONE;
  746. }
  747. }
  748. else
  749. {
  750. value = GetTerm();
  751. }
  752. return value;
  753. }
  754. /*** GetTerm - get basic term
  755. *
  756. * Purpose:
  757. * Parse numeric, variable, or register name into a basic
  758. * term value.
  759. *
  760. * Input:
  761. * g_CurCmd - present command line position
  762. *
  763. * Returns:
  764. * long value of basic term.
  765. *
  766. * Exceptions:
  767. * error exit: SYNTAX - empty basic term or premature end-of-line
  768. *
  769. * Notes:
  770. * may be called recursively.
  771. * <term> = ( <expr> ) | <register-value> | <number> | <variable>
  772. * <register-value> = @<register-name>
  773. *
  774. *************************************************************************/
  775. LONG64
  776. GetTerm (
  777. void
  778. )
  779. {
  780. LONG64 value;
  781. ULONG opclass;
  782. LONG64 opvalue;
  783. //dprintf("LONG64 GetTerm ()\n");
  784. opclass = GetTokenSym(&opvalue);
  785. if (opclass == LPAREN_CLASS)
  786. {
  787. value = GetExpr();
  788. if (GetTokenSym(&opvalue) != RPAREN_CLASS)
  789. {
  790. error(SYNTAX);
  791. }
  792. }
  793. else if (opclass == LBRACK_CLASS)
  794. {
  795. value = GetExpr();
  796. if (GetTokenSym(&opvalue) != RBRACK_CLASS)
  797. {
  798. error(SYNTAX);
  799. }
  800. }
  801. else if (opclass == REG_CLASS)
  802. {
  803. if ((g_EffMachine == IMAGE_FILE_MACHINE_I386 &&
  804. (opvalue == X86_EIP || opvalue == X86_IP)) ||
  805. (g_EffMachine == IMAGE_FILE_MACHINE_AMD64 &&
  806. (opvalue == AMD64_RIP || opvalue == AMD64_EIP ||
  807. opvalue == AMD64_IP)))
  808. {
  809. g_AddrExprType |= INSTR_POINTER;
  810. }
  811. PCROSS_PLATFORM_CONTEXT ScopeContext = GetCurrentScopeContext();
  812. if (ScopeContext)
  813. {
  814. g_Machine->PushContext(ScopeContext);
  815. }
  816. value = GetRegVal64((ULONG)opvalue);
  817. if (ScopeContext)
  818. {
  819. g_Machine->PopContext();
  820. }
  821. }
  822. else if (opclass == NUMBER_CLASS ||
  823. opclass == SYMBOL_CLASS ||
  824. opclass == LINE_CLASS)
  825. {
  826. value = opvalue;
  827. }
  828. else
  829. {
  830. ReportError(SYNTAX, &g_ExprDesc);
  831. }
  832. return value;
  833. }
  834. /*** GetRange - parse address range specification
  835. *
  836. * Purpose:
  837. * With the current command line position, parse an
  838. * address range specification. Forms accepted are:
  839. * <start-addr> - starting address with default length
  840. * <start-addr> <end-addr> - inclusive address range
  841. * <start-addr> l<count> - starting address with item count
  842. *
  843. * Input:
  844. * g_CurCmd - present command line location
  845. * size - nonzero - (for data) size in bytes of items to list
  846. * specification will be "length" type with
  847. * *fLength forced to TRUE.
  848. * zero - (for instructions) specification either "length"
  849. * or "range" type, no size assumption made.
  850. *
  851. * Output:
  852. * *addr - starting address of range
  853. * *value - if *fLength = TRUE, count of items (forced if size != 0)
  854. * FALSE, ending address of range
  855. * (*addr and *value unchanged if no second argument in command)
  856. *
  857. * Returns:
  858. * A value of TRUE is returned if no length is specified, or a length
  859. * or an ending address is specified and size is not zero. Otherwise,
  860. * a value of FALSE is returned.
  861. *
  862. * Exceptions:
  863. * error exit:
  864. * SYNTAX - expression error
  865. * BADRANGE - if ending address before starting address
  866. *
  867. *************************************************************************/
  868. BOOL
  869. GetRange (
  870. PADDR addr,
  871. PULONG64 value,
  872. ULONG size,
  873. ULONG SegReg
  874. )
  875. {
  876. CHAR ch;
  877. PSTR psz;
  878. ADDR EndRange;
  879. BOOL fL = FALSE;
  880. BOOL fLength;
  881. BOOL fSpace = FALSE;
  882. PeekChar(); // skip leading whitespace first
  883. // Pre-parse the line, look for a " L"
  884. for (psz = g_CurCmd; *psz; psz++)
  885. {
  886. if ((*psz == 'L' || *psz == 'l') && fSpace)
  887. {
  888. fL = TRUE;
  889. *psz = '\0';
  890. break;
  891. }
  892. else if (*psz == ';')
  893. {
  894. break;
  895. }
  896. fSpace = (BOOL)(*psz == ' ');
  897. }
  898. fLength = TRUE;
  899. if ((ch = PeekChar()) != '\0' && ch != ';')
  900. {
  901. GetAddrExpression(SegReg, addr);
  902. if (((ch = PeekChar()) != '\0' && ch != ';') || fL)
  903. {
  904. if (!fL)
  905. {
  906. GetAddrExpression(SegReg, &EndRange);
  907. if (AddrGt(*addr, EndRange))
  908. {
  909. error(BADRANGE);
  910. }
  911. if (size)
  912. {
  913. *value = AddrDiff(EndRange, *addr) / size + 1;
  914. }
  915. else
  916. {
  917. *value = Flat(EndRange);
  918. fLength = FALSE;
  919. }
  920. }
  921. else
  922. {
  923. g_CurCmd = psz + 1;
  924. *value = GetExprDesc("Length of range missing from");
  925. *psz = 'l';
  926. // If the length is huge assume the user made
  927. // some kind of mistake.
  928. if (*value > 1000000)
  929. {
  930. error(BADRANGE);
  931. }
  932. }
  933. }
  934. }
  935. return fLength;
  936. }
  937. /*** PeekChar - peek the next non-white-space character
  938. *
  939. * Purpose:
  940. * Return the next non-white-space character and update
  941. * g_CurCmd to point to it.
  942. *
  943. * Input:
  944. * g_CurCmd - present command line position.
  945. *
  946. * Returns:
  947. * next non-white-space character
  948. *
  949. *************************************************************************/
  950. CHAR
  951. PeekChar (
  952. void
  953. )
  954. {
  955. CHAR ch;
  956. do
  957. {
  958. ch = *g_CurCmd++;
  959. } while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
  960. g_CurCmd--;
  961. return ch;
  962. }
  963. /*** PeekToken - peek the next command line token
  964. *
  965. * Purpose:
  966. * Return the next command line token, but do not advance
  967. * the g_CurCmd pointer.
  968. *
  969. * Input:
  970. * g_CurCmd - present command line position.
  971. *
  972. * Output:
  973. * *pvalue - optional value of token
  974. * Returns:
  975. * class of token
  976. *
  977. * Notes:
  978. * g_SavedClass, g_SavedValue, and g_SavedCommand saves the token getting
  979. * state for future peeks. To get the next token, a GetToken or
  980. * AcceptToken call must first be made.
  981. *
  982. *************************************************************************/
  983. ULONG
  984. PeekToken (
  985. PLONG64 pvalue
  986. )
  987. {
  988. PSTR Temp;
  989. //dprintf("ULONG PeekToken (PLONG64 pvalue)\n");
  990. // Get next class and value, but do not
  991. // move g_CurCmd, but save it in g_SavedCommand.
  992. // Do not report any error condition.
  993. if (g_SavedClass == INVALID_CLASS)
  994. {
  995. Temp = g_CurCmd;
  996. g_SavedClass = NextToken(&g_SavedValue);
  997. g_SavedCommand = g_CurCmd;
  998. g_CurCmd = Temp;
  999. if (g_SavedClass == ADDOP_CLASS && g_SavedValue == ADDOP_PLUS)
  1000. {
  1001. g_ForcePositiveNumber = TRUE;
  1002. }
  1003. else
  1004. {
  1005. g_ForcePositiveNumber = FALSE;
  1006. }
  1007. }
  1008. *pvalue = g_SavedValue;
  1009. return g_SavedClass;
  1010. }
  1011. /*** AcceptToken - accept any peeked token
  1012. *
  1013. * Purpose:
  1014. * To reset the PeekToken saved variables so the next PeekToken
  1015. * will get the next token in the command line.
  1016. *
  1017. * Input:
  1018. * None.
  1019. *
  1020. * Output:
  1021. * None.
  1022. *
  1023. *************************************************************************/
  1024. void
  1025. AcceptToken (
  1026. void
  1027. )
  1028. {
  1029. //dprintf("void AcceptToken (void)\n");
  1030. g_SavedClass = INVALID_CLASS;
  1031. g_CurCmd = g_SavedCommand;
  1032. }
  1033. /*** GetToken - peek and accept the next token
  1034. *
  1035. * Purpose:
  1036. * Combines the functionality of PeekToken and AcceptToken
  1037. * to return the class and optional value of the next token
  1038. * as well as updating the command pointer g_CurCmd.
  1039. *
  1040. * Input:
  1041. * g_CurCmd - present command string pointer
  1042. *
  1043. * Output:
  1044. * *pvalue - pointer to the token value optionally set.
  1045. * Returns:
  1046. * class of the token read.
  1047. *
  1048. * Notes:
  1049. * An illegal token returns the value of ERROR_CLASS with *pvalue
  1050. * being the error number, but produces no actual error.
  1051. *
  1052. *************************************************************************/
  1053. ULONG
  1054. GetTokenSym (
  1055. PLONG64 pvalue
  1056. )
  1057. {
  1058. ULONG opclass;
  1059. //dprintf("ULONG GetTokenSym (PLONG pvalue)\n");
  1060. if (g_SavedClass != INVALID_CLASS)
  1061. {
  1062. opclass = g_SavedClass;
  1063. g_SavedClass = INVALID_CLASS;
  1064. *pvalue = g_SavedValue;
  1065. g_CurCmd = g_SavedCommand;
  1066. }
  1067. else
  1068. {
  1069. opclass = NextToken(pvalue);
  1070. }
  1071. if (opclass == ERROR_CLASS)
  1072. {
  1073. error((ULONG)*pvalue);
  1074. }
  1075. return opclass;
  1076. }
  1077. struct DISPLAY_AMBIGUOUS_SYMBOLS
  1078. {
  1079. PSTR Module;
  1080. MachineInfo* Machine;
  1081. };
  1082. BOOL CALLBACK
  1083. DisplayAmbiguousSymbols(
  1084. PSYMBOL_INFO SymInfo,
  1085. ULONG Size,
  1086. PVOID UserContext
  1087. )
  1088. {
  1089. DISPLAY_AMBIGUOUS_SYMBOLS* Context =
  1090. (DISPLAY_AMBIGUOUS_SYMBOLS*)UserContext;
  1091. if (IgnoreEnumeratedSymbol(Context->Machine, SymInfo))
  1092. {
  1093. return TRUE;
  1094. }
  1095. dprintf("Matched: %s %s!%s",
  1096. FormatAddr64(SymInfo->Address), Context->Module, SymInfo->Name);
  1097. ShowSymbolInfo(SymInfo);
  1098. dprintf("\n");
  1099. return TRUE;
  1100. }
  1101. ULONG
  1102. EvalSymbol(PSTR Name, PULONG64 Value)
  1103. {
  1104. if (g_CurrentProcess == NULL)
  1105. {
  1106. return INVALID_CLASS;
  1107. }
  1108. if (g_TypedExpr)
  1109. {
  1110. if (GetSymValue(Name, Value))
  1111. {
  1112. return SYMBOL_CLASS;
  1113. }
  1114. else
  1115. {
  1116. return INVALID_CLASS;
  1117. }
  1118. }
  1119. ULONG Count;
  1120. PDEBUG_IMAGE_INFO Image;
  1121. if (!(Count = GetOffsetFromSym(Name, Value, &Image)))
  1122. {
  1123. // If a valid module name was given we can assume
  1124. // the user really intended this as a symbol reference
  1125. // and return a not-found error rather than letting
  1126. // the text be checked for other kinds of matches.
  1127. if (Image != NULL)
  1128. {
  1129. *Value = VARDEF;
  1130. return ERROR_CLASS;
  1131. }
  1132. else
  1133. {
  1134. return INVALID_CLASS;
  1135. }
  1136. }
  1137. if (Count == 1)
  1138. {
  1139. // Found an unambiguous match.
  1140. Type(g_TempAddr) = ADDR_FLAT | FLAT_COMPUTED;
  1141. Flat(g_TempAddr) = Off(g_TempAddr) = *Value;
  1142. g_AddrExprType = Type(g_TempAddr);
  1143. return SYMBOL_CLASS;
  1144. }
  1145. //
  1146. // Multiple matches were found so the name is ambiguous.
  1147. // Enumerate the instances and display them.
  1148. //
  1149. Image = GetImageByOffset(g_CurrentProcess, *Value);
  1150. if (Image != NULL)
  1151. {
  1152. DISPLAY_AMBIGUOUS_SYMBOLS Context;
  1153. char FoundSymbol[MAX_SYMBOL_LEN];
  1154. ULONG64 Disp;
  1155. // The symbol found may not have exactly the name
  1156. // passed in due to prefixing or other modifications.
  1157. // Look up the actual name found.
  1158. GetSymbolStdCall(*Value, FoundSymbol, sizeof(FoundSymbol),
  1159. &Disp, NULL);
  1160. Context.Module = Image->ModuleName;
  1161. Context.Machine =
  1162. MachineTypeInfo(ModuleMachineType(g_CurrentProcess,
  1163. Image->BaseOfImage));
  1164. if (Context.Machine == NULL)
  1165. {
  1166. Context.Machine = g_Machine;
  1167. }
  1168. SymEnumSymbols(g_CurrentProcess->Handle, Image->BaseOfImage,
  1169. FoundSymbol, DisplayAmbiguousSymbols, &Context);
  1170. }
  1171. *Value = AMBIGUOUS;
  1172. return ERROR_CLASS;
  1173. }
  1174. /*** NextToken - process the next token
  1175. *
  1176. * Purpose:
  1177. * Parse the next token from the present command string.
  1178. * After skipping any leading white space, first check for
  1179. * any single character tokens or register variables. If
  1180. * no match, then parse for a number or variable. If a
  1181. * possible variable, check the reserved word list for operators.
  1182. *
  1183. * Input:
  1184. * g_CurCmd - pointer to present command string
  1185. *
  1186. * Output:
  1187. * *pvalue - optional value of token returned
  1188. * g_CurCmd - updated to point past processed token
  1189. * Returns:
  1190. * class of token returned
  1191. *
  1192. * Notes:
  1193. * An illegal token returns the value of ERROR_CLASS with *pvalue
  1194. * being the error number, but produces no actual error.
  1195. *
  1196. *************************************************************************/
  1197. ULONG
  1198. NextToken (
  1199. PLONG64 pvalue
  1200. )
  1201. {
  1202. ULONG base = g_DefaultRadix;
  1203. BOOL allowSignExtension;
  1204. CHAR chSymbol[MAX_SYMBOL_LEN];
  1205. CHAR chSymbolString[MAX_SYMBOL_LEN];
  1206. CHAR chPreSym[9];
  1207. ULONG cbSymbol = 0;
  1208. BOOL fNumber = TRUE;
  1209. BOOL fSymbol = TRUE;
  1210. BOOL fForceReg = FALSE;
  1211. BOOL fForceSym = FALSE;
  1212. ULONG errNumber = 0;
  1213. CHAR ch;
  1214. CHAR chlow;
  1215. CHAR chtemp;
  1216. CHAR limit1 = '9';
  1217. CHAR limit2 = '9';
  1218. BOOL fDigit = FALSE;
  1219. ULONG64 value = 0;
  1220. ULONG64 tmpvalue;
  1221. ULONG index;
  1222. PDEBUG_IMAGE_INFO pImage;
  1223. PSTR CmdSave;
  1224. IMAGEHLP_MODULE64 mi;
  1225. BOOL UseDeferred;
  1226. BOOL WasDigit;
  1227. ULONG off32;
  1228. ULONG SymClass;
  1229. // do sign extension for kernel only
  1230. allowSignExtension = IS_KERNEL_TARGET();
  1231. PeekChar();
  1232. ch = *g_CurCmd++;
  1233. chlow = (CHAR)tolower(ch);
  1234. // Check to see if we're at a symbol prefix followed by
  1235. // a symbol character. Symbol prefixes often contain
  1236. // characters meaningful in other ways in expressions so
  1237. // this check must be performed before the specific expression
  1238. // character checks below.
  1239. if (g_Machine != NULL &&
  1240. g_Machine->m_SymPrefix != NULL &&
  1241. chlow == g_Machine->m_SymPrefix[0] &&
  1242. (g_Machine->m_SymPrefixLen == 1 ||
  1243. !strncmp(g_CurCmd, g_Machine->m_SymPrefix + 1,
  1244. g_Machine->m_SymPrefixLen - 1)))
  1245. {
  1246. CHAR ChNext = *(g_CurCmd + g_Machine->m_SymPrefixLen - 1);
  1247. CHAR ChNextLow = (CHAR)tolower(ChNext);
  1248. if (ChNextLow == '_' ||
  1249. (ChNextLow >= 'a' && ChNextLow <= 'z'))
  1250. {
  1251. // A symbol character followed the prefix so assume it's
  1252. // a symbol.
  1253. cbSymbol = g_Machine->m_SymPrefixLen;
  1254. DBG_ASSERT(cbSymbol <= sizeof(chPreSym));
  1255. g_CurCmd--;
  1256. memcpy(chPreSym, g_CurCmd, g_Machine->m_SymPrefixLen);
  1257. memcpy(chSymbol, g_CurCmd, g_Machine->m_SymPrefixLen);
  1258. g_CurCmd += g_Machine->m_SymPrefixLen + 1;
  1259. ch = ChNext;
  1260. chlow = ChNextLow;
  1261. fForceSym = TRUE;
  1262. fForceReg = FALSE;
  1263. fNumber = FALSE;
  1264. goto ProbableSymbol;
  1265. }
  1266. }
  1267. // test for special character operators and register variable
  1268. switch (chlow)
  1269. {
  1270. case '\0':
  1271. case ';':
  1272. g_CurCmd--;
  1273. return EOL_CLASS;
  1274. case '+':
  1275. *pvalue = ADDOP_PLUS;
  1276. return ADDOP_CLASS;
  1277. case '-':
  1278. *pvalue = ADDOP_MINUS;
  1279. return ADDOP_CLASS;
  1280. case '*':
  1281. *pvalue = MULOP_MULT;
  1282. return MULOP_CLASS;
  1283. case '/':
  1284. *pvalue = MULOP_DIVIDE;
  1285. return MULOP_CLASS;
  1286. case '%':
  1287. *pvalue = MULOP_MOD;
  1288. return MULOP_CLASS;
  1289. case '&':
  1290. *pvalue = LOGOP_AND;
  1291. return LOGOP_CLASS;
  1292. case '|':
  1293. *pvalue = LOGOP_OR;
  1294. return LOGOP_CLASS;
  1295. case '^':
  1296. *pvalue = LOGOP_XOR;
  1297. return LOGOP_CLASS;
  1298. case '=':
  1299. if (*g_CurCmd == '=')
  1300. {
  1301. g_CurCmd++;
  1302. }
  1303. *pvalue = LRELOP_EQ;
  1304. return LRELOP_CLASS;
  1305. case '>':
  1306. if (*g_CurCmd == '>')
  1307. {
  1308. g_CurCmd++;
  1309. if (*g_CurCmd == '>')
  1310. {
  1311. g_CurCmd++;
  1312. *pvalue = SHIFT_RIGHT_ARITHMETIC;
  1313. }
  1314. else
  1315. {
  1316. *pvalue = SHIFT_RIGHT_LOGICAL;
  1317. }
  1318. return SHIFT_CLASS;
  1319. }
  1320. *pvalue = LRELOP_GT;
  1321. return LRELOP_CLASS;
  1322. case '<':
  1323. if (*g_CurCmd == '<')
  1324. {
  1325. g_CurCmd++;
  1326. *pvalue = SHIFT_LEFT;
  1327. return SHIFT_CLASS;
  1328. }
  1329. *pvalue = LRELOP_LT;
  1330. return LRELOP_CLASS;
  1331. case '!':
  1332. if (*g_CurCmd != '=')
  1333. {
  1334. break;
  1335. }
  1336. g_CurCmd++;
  1337. *pvalue = LRELOP_NE;
  1338. return LRELOP_CLASS;
  1339. case '~':
  1340. *pvalue = UNOP_NOT;
  1341. return UNOP_CLASS;
  1342. case '(':
  1343. return LPAREN_CLASS;
  1344. case ')':
  1345. return RPAREN_CLASS;
  1346. case '[':
  1347. return LBRACK_CLASS;
  1348. case ']':
  1349. return RBRACK_CLASS;
  1350. case '.':
  1351. g_Machine->GetPC(&g_TempAddr);
  1352. *pvalue = Flat(g_TempAddr);
  1353. g_AddrExprType = Type(g_TempAddr);
  1354. return NUMBER_CLASS;
  1355. case ':':
  1356. *pvalue = MULOP_SEG;
  1357. return MULOP_CLASS;
  1358. }
  1359. // Look for source line expressions. Because source file names
  1360. // can contain a lot of expression characters which are meaningful
  1361. // to the lexer the whole expression is enclosed in ` characters.
  1362. // This makes them easy to identify and scan.
  1363. if (chlow == '`')
  1364. {
  1365. ULONG FoundLine;
  1366. // Scan forward for closing `
  1367. CmdSave = g_CurCmd;
  1368. while (*g_CurCmd != '`' && *g_CurCmd != ';' && *g_CurCmd != 0)
  1369. {
  1370. g_CurCmd++;
  1371. }
  1372. if (*g_CurCmd == ';' || *g_CurCmd == 0)
  1373. {
  1374. *pvalue = SYNTAX;
  1375. return ERROR_CLASS;
  1376. }
  1377. *g_CurCmd = 0;
  1378. FoundLine = GetOffsetFromLine(CmdSave, &value);
  1379. *g_CurCmd++ = '`';
  1380. if (FoundLine == LINE_NOT_FOUND && g_AllowUnresolvedSymbols)
  1381. {
  1382. g_NumUnresolvedSymbols++;
  1383. FoundLine = LINE_FOUND;
  1384. value = 0;
  1385. }
  1386. if (FoundLine == LINE_FOUND)
  1387. {
  1388. *pvalue = value;
  1389. Type(g_TempAddr) = ADDR_FLAT | FLAT_COMPUTED;
  1390. Flat(g_TempAddr) = Off(g_TempAddr) = value;
  1391. g_AddrExprType = Type(g_TempAddr);
  1392. return LINE_CLASS;
  1393. }
  1394. else
  1395. {
  1396. *pvalue = NOTFOUND;
  1397. return ERROR_CLASS;
  1398. }
  1399. }
  1400. // special prefixes - '@' for register - '!' for symbol
  1401. if (chlow == '@' || chlow == '!')
  1402. {
  1403. fForceReg = (BOOL)(chlow == '@');
  1404. fForceSym = (BOOL)!fForceReg;
  1405. fNumber = FALSE;
  1406. ch = *g_CurCmd++;
  1407. chlow = (CHAR)tolower(ch);
  1408. }
  1409. // if string is followed by '!', but not '!=',
  1410. // then it is a module name and treat as text
  1411. CmdSave = g_CurCmd;
  1412. WasDigit = FALSE;
  1413. while ((chlow >= 'a' && chlow <= 'z') ||
  1414. (chlow >= '0' && chlow <= '9') ||
  1415. (WasDigit && chlow == '`') ||
  1416. (chlow == '_') || (chlow == '$') || (chlow == '~'))
  1417. {
  1418. WasDigit = (chlow >= '0' && chlow <= '9') ||
  1419. (chlow >= 'a' && chlow <= 'f');
  1420. chlow = (CHAR)tolower(*g_CurCmd);
  1421. g_CurCmd++;
  1422. }
  1423. // treat as symbol if a nonnull string is followed by '!',
  1424. // but not '!='
  1425. if (chlow == '!' && *g_CurCmd != '=' && CmdSave != g_CurCmd)
  1426. {
  1427. fNumber = FALSE;
  1428. }
  1429. g_CurCmd = CmdSave;
  1430. chlow = (CHAR)tolower(ch); // ch was NOT modified
  1431. if (fNumber)
  1432. {
  1433. if (chlow == '\'')
  1434. {
  1435. *pvalue = 0;
  1436. while (TRUE)
  1437. {
  1438. ch = *g_CurCmd++;
  1439. if (!ch)
  1440. {
  1441. *pvalue = SYNTAX;
  1442. return ERROR_CLASS;
  1443. }
  1444. if (ch == '\'')
  1445. {
  1446. if (*g_CurCmd != '\'')
  1447. {
  1448. break;
  1449. }
  1450. ch = *g_CurCmd++;
  1451. }
  1452. else if (ch == '\\')
  1453. {
  1454. ch = *g_CurCmd++;
  1455. }
  1456. *pvalue = (*pvalue << 8) | ch;
  1457. }
  1458. return NUMBER_CLASS;
  1459. }
  1460. // if first character is a decimal digit, it cannot
  1461. // be a symbol. leading '0' implies octal, except
  1462. // a leading '0x' implies hexadecimal.
  1463. if (chlow >= '0' && chlow <= '9')
  1464. {
  1465. if (fForceReg)
  1466. {
  1467. *pvalue = SYNTAX;
  1468. return ERROR_CLASS;
  1469. }
  1470. fSymbol = FALSE;
  1471. if (chlow == '0')
  1472. {
  1473. //
  1474. // too many people type in leading 0x so we can't use it to
  1475. // deal with sign extension.
  1476. //
  1477. ch = *g_CurCmd++;
  1478. chlow = (CHAR)tolower(ch);
  1479. if (chlow == 'n')
  1480. {
  1481. base = 10;
  1482. ch = *g_CurCmd++;
  1483. chlow = (CHAR)tolower(ch);
  1484. fDigit = TRUE;
  1485. }
  1486. else if (chlow == 't')
  1487. {
  1488. base = 8;
  1489. ch = *g_CurCmd++;
  1490. chlow = (CHAR)tolower(ch);
  1491. fDigit = TRUE;
  1492. }
  1493. else if (chlow == 'x')
  1494. {
  1495. base = 16;
  1496. ch = *g_CurCmd++;
  1497. chlow = (CHAR)tolower(ch);
  1498. fDigit = TRUE;
  1499. }
  1500. else if (chlow == 'y')
  1501. {
  1502. base = 2;
  1503. ch = *g_CurCmd++;
  1504. chlow = (CHAR)tolower(ch);
  1505. fDigit = TRUE;
  1506. }
  1507. else
  1508. {
  1509. // Leading zero is used only to imply a positive value
  1510. // that shouldn't get sign extended.
  1511. fDigit = TRUE;
  1512. }
  1513. }
  1514. }
  1515. // a number can start with a letter only if base is
  1516. // hexadecimal and it is a hexadecimal digit 'a'-'f'.
  1517. else if ((chlow < 'a' || chlow > 'f') || base != 16)
  1518. {
  1519. fNumber = FALSE;
  1520. }
  1521. // set limit characters for the appropriate base.
  1522. if (base == 2)
  1523. {
  1524. limit1 = '1';
  1525. }
  1526. else if (base == 8)
  1527. {
  1528. limit1 = '7';
  1529. }
  1530. else if (base == 16)
  1531. {
  1532. limit2 = 'f';
  1533. }
  1534. }
  1535. ProbableSymbol:
  1536. // perform processing while character is a letter,
  1537. // digit, underscore, tilde or dollar-sign.
  1538. while ((chlow >= 'a' && chlow <= 'z') ||
  1539. (chlow >= '0' && chlow <= '9') ||
  1540. (fDigit && base == 16 && chlow == '`') ||
  1541. (chlow == '_') || (chlow == '$') || (chlow == '~'))
  1542. {
  1543. // if possible number, test if within proper range,
  1544. // and if so, accumulate sum.
  1545. if (fNumber)
  1546. {
  1547. if ((chlow >= '0' && chlow <= limit1) ||
  1548. (chlow >= 'a' && chlow <= limit2))
  1549. {
  1550. fDigit = TRUE;
  1551. tmpvalue = value * base;
  1552. if (tmpvalue < value)
  1553. {
  1554. errNumber = OVERFLOW;
  1555. }
  1556. chtemp = (CHAR)(chlow - '0');
  1557. if (chtemp > 9)
  1558. {
  1559. chtemp -= 'a' - '0' - 10;
  1560. }
  1561. value = tmpvalue + (ULONG64)chtemp;
  1562. if (value < tmpvalue)
  1563. {
  1564. errNumber = OVERFLOW;
  1565. }
  1566. }
  1567. else if (fDigit && chlow == '`')
  1568. {
  1569. //
  1570. // if ` character is seen, disallow sign extension
  1571. //
  1572. allowSignExtension = FALSE;
  1573. }
  1574. else
  1575. {
  1576. fNumber = FALSE;
  1577. errNumber = SYNTAX;
  1578. }
  1579. }
  1580. if (fSymbol)
  1581. {
  1582. if (cbSymbol < sizeof(chPreSym))
  1583. {
  1584. chPreSym[cbSymbol] = chlow;
  1585. }
  1586. if (cbSymbol < MAX_SYMBOL_LEN - 1)
  1587. {
  1588. chSymbol[cbSymbol++] = ch;
  1589. }
  1590. }
  1591. ch = *g_CurCmd++;
  1592. if (g_TypedExpr)
  1593. {
  1594. if (ch == '.')
  1595. {
  1596. chSymbol[cbSymbol++] = ch;
  1597. ch = *g_CurCmd++;
  1598. }
  1599. else if (ch == '-' && *g_CurCmd == '>')
  1600. {
  1601. chSymbol[cbSymbol++] = ch;
  1602. ch = *g_CurCmd++;
  1603. chSymbol[cbSymbol++] = ch;
  1604. ch = *g_CurCmd++;
  1605. }
  1606. }
  1607. chlow = (CHAR)tolower(ch);
  1608. }
  1609. // back up pointer to first character after token.
  1610. g_CurCmd--;
  1611. if (cbSymbol < sizeof(chPreSym))
  1612. {
  1613. chPreSym[cbSymbol] = '\0';
  1614. }
  1615. if (g_EffMachine == IMAGE_FILE_MACHINE_I386 ||
  1616. g_EffMachine == IMAGE_FILE_MACHINE_AMD64)
  1617. {
  1618. //
  1619. // catch segment overrides here
  1620. //
  1621. if (!fForceReg && ch == ':')
  1622. {
  1623. for (index = 0; index < X86_SEGREGSIZE; index++)
  1624. {
  1625. if (!strncmp(chPreSym, g_X86SegRegs[index], 2))
  1626. {
  1627. fForceReg = TRUE;
  1628. fSymbol = FALSE;
  1629. break;
  1630. }
  1631. }
  1632. }
  1633. }
  1634. // if fForceReg, check for register name and return
  1635. // success or failure
  1636. if (fForceReg)
  1637. {
  1638. return GetRegToken(chPreSym, (PULONG64)pvalue);
  1639. }
  1640. // test if number
  1641. if (fNumber && !errNumber && fDigit)
  1642. {
  1643. if (allowSignExtension && !g_ForcePositiveNumber &&
  1644. ((value >> 32) == 0))
  1645. {
  1646. *pvalue = (LONG)value;
  1647. }
  1648. else
  1649. {
  1650. *pvalue = value;
  1651. }
  1652. return NUMBER_CLASS;
  1653. }
  1654. // next test for reserved word and symbol string
  1655. if (fSymbol && !fForceReg)
  1656. {
  1657. // check lowercase string in chPreSym for text operator
  1658. // or register name.
  1659. // otherwise, return symbol value from name in chSymbol.
  1660. if (!fForceSym && (cbSymbol == 2 || cbSymbol == 3))
  1661. {
  1662. for (index = 0; index < RESERVESIZE; index++)
  1663. {
  1664. if (!strncmp(chPreSym, g_Reserved[index].chRes, 3))
  1665. {
  1666. *pvalue = g_Reserved[index].valueRes;
  1667. return g_Reserved[index].classRes;
  1668. }
  1669. }
  1670. if (g_EffMachine == IMAGE_FILE_MACHINE_I386 ||
  1671. g_EffMachine == IMAGE_FILE_MACHINE_AMD64)
  1672. {
  1673. for (index = 0; index < X86_RESERVESIZE; index++)
  1674. {
  1675. if (!strncmp(chPreSym,
  1676. g_X86Reserved[index].chRes, 3))
  1677. {
  1678. *pvalue = g_X86Reserved[index].valueRes;
  1679. return g_X86Reserved[index].classRes;
  1680. }
  1681. }
  1682. }
  1683. }
  1684. // start processing string as symbol
  1685. chSymbol[cbSymbol] = '\0';
  1686. // test if symbol is a module name (followed by '!')
  1687. // if so, get next token and treat as symbol
  1688. if (PeekChar() == '!')
  1689. {
  1690. // chSymbolString holds the name of the symbol to be searched.
  1691. // chSymbol holds the symbol image file name.
  1692. g_CurCmd++;
  1693. ch = PeekChar();
  1694. g_CurCmd++;
  1695. // Scan prefix if one is present.
  1696. if (g_Machine != NULL &&
  1697. g_Machine->m_SymPrefix != NULL &&
  1698. ch == g_Machine->m_SymPrefix[0] &&
  1699. (g_Machine->m_SymPrefixLen == 1 ||
  1700. !strncmp(g_CurCmd, g_Machine->m_SymPrefix + 1,
  1701. g_Machine->m_SymPrefixLen - 1)))
  1702. {
  1703. cbSymbol = g_Machine->m_SymPrefixLen;
  1704. memcpy(chSymbolString, g_CurCmd - 1,
  1705. g_Machine->m_SymPrefixLen);
  1706. g_CurCmd += g_Machine->m_SymPrefixLen - 1;
  1707. ch = *g_CurCmd++;
  1708. }
  1709. else
  1710. {
  1711. cbSymbol = 0;
  1712. }
  1713. while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
  1714. (ch >= '0' && ch <= '9') || (ch == '_') || (ch == '$'))
  1715. {
  1716. chSymbolString[cbSymbol++] = ch;
  1717. ch = *g_CurCmd++;
  1718. if (g_TypedExpr)
  1719. {
  1720. if (ch == '.')
  1721. {
  1722. chSymbolString[cbSymbol++] = ch;
  1723. ch = *g_CurCmd++;
  1724. }
  1725. else if (ch == '-' && *g_CurCmd == '>')
  1726. {
  1727. chSymbolString[cbSymbol++] = ch;
  1728. ch = *g_CurCmd++;
  1729. chSymbolString[cbSymbol++] = ch;
  1730. ch = *g_CurCmd++;
  1731. }
  1732. }
  1733. }
  1734. chSymbolString[cbSymbol] = '\0';
  1735. g_CurCmd--;
  1736. if (cbSymbol == 0)
  1737. {
  1738. *pvalue = SYNTAX;
  1739. return ERROR_CLASS;
  1740. }
  1741. strcat( chSymbol, "!" );
  1742. strcat( chSymbol, chSymbolString );
  1743. SymClass = EvalSymbol(chSymbol, &value);
  1744. if (SymClass != INVALID_CLASS)
  1745. {
  1746. *pvalue = value;
  1747. return SymClass;
  1748. }
  1749. }
  1750. else
  1751. {
  1752. if (cbSymbol == 0)
  1753. {
  1754. *pvalue = SYNTAX;
  1755. return ERROR_CLASS;
  1756. }
  1757. SymClass = EvalSymbol(chSymbol, &value);
  1758. if (SymClass != INVALID_CLASS)
  1759. {
  1760. *pvalue = value;
  1761. return SymClass;
  1762. }
  1763. //
  1764. // Quick test for register names too
  1765. //
  1766. if (!fForceSym &&
  1767. (tmpvalue = GetRegToken(chPreSym,
  1768. (PULONG64)pvalue)) != ERROR_CLASS)
  1769. {
  1770. return (ULONG)tmpvalue;
  1771. }
  1772. }
  1773. //
  1774. // symbol is undefined.
  1775. // if a possible hex number, do not set the error type
  1776. //
  1777. if (!fNumber)
  1778. {
  1779. errNumber = VARDEF;
  1780. }
  1781. }
  1782. //
  1783. // last chance, undefined symbol and illegal number,
  1784. // so test for register, will handle old format
  1785. //
  1786. if (!fForceSym &&
  1787. (tmpvalue = GetRegToken(chPreSym,
  1788. (PULONG64)pvalue)) != ERROR_CLASS)
  1789. {
  1790. return (ULONG)tmpvalue;
  1791. }
  1792. if (g_AllowUnresolvedSymbols)
  1793. {
  1794. g_NumUnresolvedSymbols++;
  1795. *pvalue = 0;
  1796. Type(g_TempAddr) = ADDR_FLAT | FLAT_COMPUTED;
  1797. Flat(g_TempAddr) = Off(g_TempAddr) = *pvalue;
  1798. g_AddrExprType = Type(g_TempAddr);
  1799. return SYMBOL_CLASS;
  1800. }
  1801. //
  1802. // no success, so set error message and return
  1803. //
  1804. *pvalue = (ULONG64)errNumber;
  1805. return ERROR_CLASS;
  1806. }
  1807. LONG64
  1808. EvaluateSourceExpression(
  1809. PCHAR pExpr
  1810. )
  1811. {
  1812. BOOL sav = g_TypedExpr;
  1813. PSTR savPch = g_CurCmd;
  1814. g_TypedExpr = TRUE;
  1815. g_CurCmd = pExpr;
  1816. ULONG64 res;
  1817. __try
  1818. {
  1819. res = GetExpression();
  1820. }
  1821. __except(CommandExceptionFilter(GetExceptionInformation()))
  1822. {
  1823. res = 0;
  1824. }
  1825. g_CurCmd = savPch;
  1826. g_TypedExpr = sav;
  1827. return res;
  1828. }
  1829. /*
  1830. Inputs
  1831. g_CurCmd - points to start of typed expression
  1832. Must be ([*|&] Sym[(.->)Field])
  1833. Outputs
  1834. Evaluates typed expression and returns value
  1835. */
  1836. LONG64
  1837. GetTypedExpression(
  1838. void
  1839. )
  1840. {
  1841. ULONG64 Value=0;
  1842. BOOL AddrOf=FALSE, ValueAt=FALSE;
  1843. CHAR c;
  1844. static CHAR Name[MAX_NAME], Field[MAX_NAME];
  1845. c = PeekChar();
  1846. switch (c)
  1847. {
  1848. case '(':
  1849. g_CurCmd++;
  1850. Value = GetTypedExpression();
  1851. c = PeekChar();
  1852. if (c != ')')
  1853. {
  1854. error(SYNTAX);
  1855. return 0;
  1856. }
  1857. ++g_CurCmd;
  1858. return Value;
  1859. case '&':
  1860. // Get Offset/Address
  1861. // AddrOf = TRUE;
  1862. // g_CurCmd++;
  1863. // PeekChar();
  1864. break;
  1865. case '*':
  1866. default:
  1867. break;
  1868. }
  1869. #if 0
  1870. ULONG i=0;
  1871. ValueAt = TRUE;
  1872. g_CurCmd++;
  1873. PeekChar();
  1874. break;
  1875. c = PeekChar();
  1876. while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
  1877. (c >= '0' && c <= '9') || (c == '_') || (c == '$') ||
  1878. (c == '!')) {
  1879. // Sym Name
  1880. Name[i++] = c;
  1881. c = *++g_CurCmd;
  1882. }
  1883. Name[i]=0;
  1884. if (c=='.')
  1885. {
  1886. ++g_CurCmd;
  1887. } else if (c=='-' && *++g_CurCmd == '>')
  1888. {
  1889. ++g_CurCmd;
  1890. }
  1891. i=0;
  1892. c = PeekChar();
  1893. while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
  1894. (c >= '0' && c <= '9') || (c == '_') || (c == '$') ||
  1895. (c == '.') || (c == '-') || (c == '>')) {
  1896. Field[i++]= c;
  1897. c = *++g_CurCmd;
  1898. }
  1899. Field[i]=0;
  1900. SYM_DUMP_PARAM Sym = {0};
  1901. FIELD_INFO FieldInfo ={0};
  1902. Sym.size = sizeof(SYM_DUMP_PARAM);
  1903. Sym.sName = (PUCHAR) Name;
  1904. Sym.Options = DBG_DUMP_NO_PRINT;
  1905. if (Field[0])
  1906. {
  1907. Sym.nFields = 1;
  1908. Sym.Fields = &FieldInfo;
  1909. FieldInfo.fName = (PUCHAR) Field;
  1910. if (AddrOf)
  1911. {
  1912. FieldInfo.fOptions |= DBG_DUMP_FIELD_RETURN_ADDRESS;
  1913. }
  1914. } else if (AddrOf)
  1915. {
  1916. PUCHAR pch = g_CurCmd;
  1917. g_CurCmd = &Name[0];
  1918. Value = GetMterm();
  1919. g_CurCmd = pch;
  1920. return Value;
  1921. } else
  1922. {
  1923. Sym.Options |= DBG_DUMP_GET_SIZE_ONLY;
  1924. }
  1925. ULONG Status=0;
  1926. ULONG Size = SymbolTypeDump(0, NULL, &Sym, &Status);
  1927. if (!Status)
  1928. {
  1929. if (!Field[0] && (Size <= sizeof (Value)))
  1930. {
  1931. // Call routine again to read value
  1932. Sym.Options |= DBG_DUMP_COPY_TYPE_DATA;
  1933. Sym.Context = (PVOID) &Value;
  1934. if ((SymbolTypeDump(0, NULL, &Sym, &Status) == 8) && (Size == 4))
  1935. {
  1936. Value = (ULONG) Value;
  1937. }
  1938. } else if (Field[0] && (FieldInfo.size <= sizeof(ULONG64)))
  1939. {
  1940. Value = FieldInfo.address;
  1941. } else // too big
  1942. {
  1943. Value = 0;
  1944. }
  1945. }
  1946. #endif
  1947. AddrOf = g_TypedExpr;
  1948. g_TypedExpr = TRUE;
  1949. Value = GetMterm();
  1950. g_TypedExpr = AddrOf;
  1951. return Value;
  1952. }
  1953. /*
  1954. Evaluate the value in symbol expression Symbol
  1955. */
  1956. BOOL
  1957. GetSymValue(
  1958. PSTR Symbol,
  1959. PULONG64 pValue
  1960. )
  1961. {
  1962. TYPES_INFO_ALL Typ;
  1963. if (GetExpressionTypeInfo(Symbol, &Typ)) {
  1964. if (Typ.Flags) {
  1965. if (Typ.Flags & IMAGEHLP_SYMBOL_INFO_VALUEPRESENT) {
  1966. *pValue = Typ.Value;
  1967. return TRUE;
  1968. }
  1969. TranslateAddress(Typ.Flags, Typ.Register, &Typ.Address, &Typ.Value);
  1970. if (Typ.Value && (Typ.Flags & SYMF_REGISTER)) {
  1971. *pValue = Typ.Value;
  1972. return TRUE;
  1973. }
  1974. }
  1975. if (Symbol[0] == '&') {
  1976. *pValue = Typ.Address;
  1977. return TRUE;
  1978. } else if (Typ.Size <= sizeof(*pValue)) {
  1979. ULONG64 Val = 0;
  1980. ULONG cb;
  1981. if (g_Target->ReadVirtual(Typ.Address, &Val, Typ.Size, &cb) == S_OK) {
  1982. *pValue = Val;
  1983. return TRUE;
  1984. }
  1985. }
  1986. }
  1987. *pValue = 0;
  1988. return FALSE;
  1989. }