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.

2302 lines
49 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Functions dealing with memory access, such as reading, writing,
  4. // dumping and entering.
  5. //
  6. // Copyright (C) Microsoft Corporation, 1997-2001.
  7. //
  8. //----------------------------------------------------------------------------
  9. #include "ntsdp.hpp"
  10. ULONG64 EXPRLastDump = 0L;
  11. ADDR g_DumpDefault; // default dump address
  12. /*** GetProcessMemString - get memory string values
  13. *
  14. * Purpose:
  15. * To read a string of a specified length with the memory
  16. * values selected. Break reads across page boundaries -
  17. * multiples of the page size.
  18. *
  19. * Input:
  20. * Addr - offset of memory to start reading
  21. * Value - pointer to byte string to set with memory values
  22. *
  23. * Output:
  24. * bytes at Value set if read successful
  25. *
  26. * Returns:
  27. * number of bytes actually read
  28. *
  29. *************************************************************************/
  30. ULONG
  31. GetProcessMemString (
  32. PPROCESS_INFO Process,
  33. PADDR Addr,
  34. PVOID Value,
  35. ULONG Length
  36. )
  37. {
  38. ULONG cTotalBytesRead = 0;
  39. if (fFlat(*Addr) || fInstrPtr(*Addr))
  40. {
  41. PPROCESS_INFO OldCur = g_CurrentProcess;
  42. g_CurrentProcess = Process;
  43. if (g_Target->ReadVirtual(Flat(*Addr), Value, Length,
  44. &cTotalBytesRead) != S_OK)
  45. {
  46. cTotalBytesRead = 0;
  47. }
  48. g_CurrentProcess = OldCur;
  49. }
  50. return cTotalBytesRead;
  51. }
  52. /*** SetProcessMemString - set memory string values
  53. *
  54. * Purpose:
  55. * To write a string of a specified length with the memory
  56. * values selected.
  57. *
  58. * Input:
  59. * Addr - offset of memory to start writing
  60. * Value - pointer to byte string to set with memory values
  61. *
  62. * Output:
  63. * bytes at Value set if write successful
  64. *
  65. * Returns:
  66. * number of bytes actually write
  67. *
  68. *************************************************************************/
  69. ULONG
  70. SetProcessMemString (
  71. PPROCESS_INFO Process,
  72. PADDR Addr,
  73. PVOID Value,
  74. ULONG Length
  75. )
  76. {
  77. ULONG cTotalBytesWritten = 0;
  78. if (fFlat(*Addr) || fInstrPtr(*Addr))
  79. {
  80. PPROCESS_INFO OldCur = g_CurrentProcess;
  81. g_CurrentProcess = Process;
  82. if (g_Target->WriteVirtual(Flat(*Addr), Value, Length,
  83. &cTotalBytesWritten) != S_OK)
  84. {
  85. cTotalBytesWritten = 0;
  86. }
  87. g_CurrentProcess = OldCur;
  88. }
  89. return cTotalBytesWritten;
  90. }
  91. BOOL
  92. CALLBACK
  93. LocalSymbolEnumerator(
  94. PSYMBOL_INFO pSymInfo,
  95. ULONG Size,
  96. PVOID Context
  97. )
  98. {
  99. ULONG64 Value = pSymInfo->Register, Address = pSymInfo->Address;
  100. TranslateAddress(pSymInfo->Flags, pSymInfo->Register, &Address, &Value);
  101. VerbOut("%s ", FormatAddr64(Address));
  102. dprintf("%15s = ", pSymInfo->Name);
  103. if (pSymInfo->Flags & SYMF_REGISTER)
  104. {
  105. dprintf( "%I64x\n",
  106. Value
  107. );
  108. }
  109. else
  110. {
  111. if (!DumpSingleValue(pSymInfo))
  112. {
  113. dprintf("??");
  114. }
  115. dprintf("\n");
  116. }
  117. if (CheckUserInterrupt())
  118. {
  119. return FALSE;
  120. }
  121. return TRUE;
  122. }
  123. //----------------------------------------------------------------------------
  124. //
  125. // parseDumpCommand
  126. //
  127. // Parses memory dump commands.
  128. //
  129. //----------------------------------------------------------------------------
  130. void
  131. parseDumpCommand(
  132. void
  133. )
  134. {
  135. CHAR ch;
  136. ULONG64 count;
  137. ULONG size;
  138. ULONG offset;
  139. BOOL DumpSymbols;
  140. static CHAR s_DumpPrimary = 'b';
  141. static CHAR s_DumpSecondary = ' ';
  142. ch = (CHAR)tolower(*g_CurCmd);
  143. if (ch == 'a' || ch == 'b' || ch == 'c' || ch == 'd' ||
  144. ch == 'f' || ch == 'g' || ch == 'l' || ch == 'u' ||
  145. ch == 'w' || ch == 's' || ch == 'q' || ch == 't' ||
  146. ch == 'v' || ch == 'y' || ch == 'p')
  147. {
  148. if (ch == 'd' || ch == 's')
  149. {
  150. s_DumpPrimary = *g_CurCmd;
  151. }
  152. else if (ch == 'p')
  153. {
  154. // 'p' maps to the effective pointer size dump.
  155. s_DumpPrimary = g_Machine->m_Ptr64 ? 'q' : 'd';
  156. }
  157. else
  158. {
  159. s_DumpPrimary = ch;
  160. }
  161. g_CurCmd++;
  162. s_DumpSecondary = ' ';
  163. if (s_DumpPrimary == 'd' || s_DumpPrimary == 'q')
  164. {
  165. if (*g_CurCmd == 's')
  166. {
  167. s_DumpSecondary = *g_CurCmd++;
  168. }
  169. }
  170. else if (s_DumpPrimary == 'l')
  171. {
  172. if (*g_CurCmd == 'b')
  173. {
  174. s_DumpSecondary = *g_CurCmd++;
  175. }
  176. }
  177. else if (s_DumpPrimary == 'y')
  178. {
  179. if (*g_CurCmd == 'b' || *g_CurCmd == 'd')
  180. {
  181. s_DumpSecondary = *g_CurCmd++;
  182. }
  183. }
  184. }
  185. switch (s_DumpPrimary)
  186. {
  187. case 'a':
  188. count = 384;
  189. GetRange(&g_DumpDefault, &count, 1, SEGREG_DATA);
  190. fnDumpAsciiMemory(&g_DumpDefault, (ULONG)count);
  191. break;
  192. case 'b':
  193. count = 128;
  194. GetRange(&g_DumpDefault, &count, 1, SEGREG_DATA);
  195. fnDumpByteMemory(&g_DumpDefault, (ULONG)count);
  196. break;
  197. case 'c':
  198. count = 32;
  199. GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
  200. fnDumpDwordAndCharMemory(&g_DumpDefault, (ULONG)count);
  201. break;
  202. case 'd':
  203. count = 32;
  204. DumpSymbols = s_DumpSecondary == 's';
  205. GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
  206. fnDumpDwordMemory(&g_DumpDefault, (ULONG)count, DumpSymbols);
  207. break;
  208. case 'D':
  209. count = 15;
  210. GetRange(&g_DumpDefault, &count, 8, SEGREG_DATA);
  211. fnDumpDoubleMemory(&g_DumpDefault, (ULONG)count);
  212. break;
  213. case 'f':
  214. count = 16;
  215. GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
  216. fnDumpFloatMemory(&g_DumpDefault, (ULONG)count);
  217. break;
  218. case 'g':
  219. fnDumpSelector((ULONG)GetExpression());
  220. break;
  221. case 'l':
  222. BOOL followBlink;
  223. count = 32;
  224. size = 4;
  225. followBlink = s_DumpSecondary == 'b';
  226. if ((ch = PeekChar()) != '\0' && ch != ';')
  227. {
  228. GetAddrExpression(SEGREG_DATA, &g_DumpDefault);
  229. if ((ch = PeekChar()) != '\0' && ch != ';')
  230. {
  231. count = GetExpression();
  232. if ((ch = PeekChar()) != '\0' && ch != ';')
  233. {
  234. size = (ULONG)GetExpression();
  235. }
  236. }
  237. }
  238. fnDumpListMemory(&g_DumpDefault, (ULONG)count, size, followBlink);
  239. break;
  240. case 'q':
  241. count = 16;
  242. DumpSymbols = s_DumpSecondary == 's';
  243. GetRange(&g_DumpDefault, &count, 8, SEGREG_DATA);
  244. fnDumpQuadMemory(&g_DumpDefault, (ULONG)count, DumpSymbols);
  245. break;
  246. case 's':
  247. case 'S':
  248. UNICODE_STRING64 UnicodeString;
  249. ADDR BufferAddr;
  250. count = 1;
  251. GetRange(&g_DumpDefault, &count, 2, SEGREG_DATA);
  252. while (count--)
  253. {
  254. if (g_Target->ReadUnicodeString(g_Machine, Flat(g_DumpDefault),
  255. &UnicodeString) == S_OK)
  256. {
  257. ADDRFLAT(&BufferAddr, UnicodeString.Buffer);
  258. if (s_DumpPrimary == 'S')
  259. {
  260. fnDumpUnicodeMemory( &BufferAddr,
  261. UnicodeString.Length / sizeof(WCHAR));
  262. }
  263. else
  264. {
  265. fnDumpAsciiMemory( &BufferAddr, UnicodeString.Length );
  266. }
  267. }
  268. }
  269. break;
  270. case 't':
  271. case 'T':
  272. SymbolTypeDumpEx(g_CurrentProcess->Handle,
  273. g_CurrentProcess->ImageHead,
  274. g_CurCmd);
  275. break;
  276. case 'u':
  277. count = 384;
  278. GetRange(&g_DumpDefault, &count, 2, SEGREG_DATA);
  279. fnDumpUnicodeMemory(&g_DumpDefault, (ULONG)count);
  280. break;
  281. case 'v':
  282. RequireCurrentScope();
  283. EnumerateLocals(LocalSymbolEnumerator, NULL);
  284. break;
  285. case 'w':
  286. count = 64;
  287. GetRange(&g_DumpDefault, &count, 2, SEGREG_DATA);
  288. fnDumpWordMemory(&g_DumpDefault, (ULONG)count);
  289. break;
  290. case 'y':
  291. switch(s_DumpSecondary)
  292. {
  293. case 'b':
  294. count = 32;
  295. GetRange(&g_DumpDefault, &count, 1, SEGREG_DATA);
  296. fnDumpByteBinaryMemory(&g_DumpDefault, (ULONG)count);
  297. break;
  298. case 'd':
  299. count = 8;
  300. GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
  301. fnDumpDwordBinaryMemory(&g_DumpDefault, (ULONG)count);
  302. break;
  303. default:
  304. error(SYNTAX);
  305. }
  306. break;
  307. default:
  308. error(SYNTAX);
  309. break;
  310. }
  311. }
  312. //----------------------------------------------------------------------------
  313. //
  314. // DumpValues
  315. //
  316. // Generic columnar value dumper. Returns the number of values
  317. // printed.
  318. //
  319. //----------------------------------------------------------------------------
  320. class DumpValues
  321. {
  322. public:
  323. DumpValues(ULONG Size, ULONG Columns);
  324. ULONG Dump(PADDR Start, ULONG Count);
  325. protected:
  326. // Worker methods that derived classes must define.
  327. virtual ULONG64 GetValue(void) = 0;
  328. virtual BOOL PrintValue(void) = 0;
  329. virtual void PrintUnknown(void) = 0;
  330. // Optional worker methods. Base implementations do nothing.
  331. virtual void EndRow(void);
  332. // Fixed members controlling how this instance dumps values.
  333. ULONG m_Size;
  334. ULONG m_Columns;
  335. // Work members during dumping.
  336. UCHAR* m_Value;
  337. ULONG m_Col;
  338. PADDR m_Start;
  339. // Optional per-row values. Out is automatically reset to
  340. // Base at the beginning of every row.
  341. UCHAR* m_Base;
  342. UCHAR* m_Out;
  343. };
  344. DumpValues::DumpValues(ULONG Size, ULONG Columns)
  345. {
  346. m_Size = Size;
  347. m_Columns = Columns;
  348. }
  349. ULONG
  350. DumpValues::Dump(PADDR Start, ULONG Count)
  351. {
  352. ULONG Read;
  353. UCHAR ReadBuffer[512];
  354. ULONG Idx;
  355. ULONG Block;
  356. BOOL First = TRUE;
  357. ULONG64 Offset;
  358. ULONG Printed;
  359. BOOL RowStarted;
  360. ULONG PageVal;
  361. ULONG64 NextOffs, NextPage;
  362. Offset = Flat(*Start);
  363. Printed = 0;
  364. RowStarted = FALSE;
  365. m_Start = Start;
  366. m_Col = 0;
  367. m_Out = m_Base;
  368. while (Count > 0)
  369. {
  370. Block = sizeof(ReadBuffer) / m_Size;
  371. Block = min(Count, Block);
  372. g_Target->NearestDifferentlyValidOffsets(Offset, &NextOffs, &NextPage);
  373. PageVal = (ULONG)(NextPage - Offset + m_Size - 1) / m_Size;
  374. Block = min(Block, PageVal);
  375. Read = GetMemString(Start, ReadBuffer, Block * m_Size) / m_Size;
  376. if (Read < Block && NextOffs < NextPage)
  377. {
  378. // In dump files data validity can change from
  379. // one byte to the next so we cannot assume that
  380. // stepping by pages will always be correct. Instead,
  381. // if we didn't have a successful read we step just
  382. // past the end of the valid data or to the next
  383. // valid offset, whichever is farther.
  384. if (Offset + (Read + 1) * m_Size < NextOffs)
  385. {
  386. Block = (ULONG)(NextOffs - Offset + m_Size - 1) / m_Size;
  387. }
  388. else
  389. {
  390. Block = Read + 1;
  391. }
  392. }
  393. m_Value = ReadBuffer;
  394. Idx = 0;
  395. if (First && Read >= 1)
  396. {
  397. First = FALSE;
  398. EXPRLastDump = GetValue();
  399. }
  400. while (Idx < Block)
  401. {
  402. while (m_Col < m_Columns && Idx < Block)
  403. {
  404. if (m_Col == 0)
  405. {
  406. dprintAddr(Start);
  407. RowStarted = TRUE;
  408. }
  409. if (Idx < Read)
  410. {
  411. if (!PrintValue())
  412. {
  413. // Increment address since this value was
  414. // examined, but do not increment print count
  415. // or column since no output was produced.
  416. AddrAdd(Start, m_Size);
  417. goto Exit;
  418. }
  419. m_Value += m_Size;
  420. }
  421. else
  422. {
  423. PrintUnknown();
  424. }
  425. Idx++;
  426. Printed++;
  427. m_Col++;
  428. AddrAdd(Start, m_Size);
  429. }
  430. if (m_Col == m_Columns)
  431. {
  432. EndRow();
  433. m_Out = m_Base;
  434. dprintf("\n");
  435. RowStarted = FALSE;
  436. m_Col = 0;
  437. }
  438. if (CheckUserInterrupt())
  439. {
  440. return Printed;
  441. }
  442. }
  443. Count -= Block;
  444. Offset += Block * m_Size;
  445. }
  446. Exit:
  447. if (RowStarted)
  448. {
  449. EndRow();
  450. m_Out = m_Base;
  451. dprintf("\n");
  452. }
  453. return Printed;
  454. }
  455. void
  456. DumpValues::EndRow(void)
  457. {
  458. // Empty base implementation.
  459. }
  460. /*** fnDumpAsciiMemory - output ascii strings from memory
  461. *
  462. * Purpose:
  463. * Function of "da<range>" command.
  464. *
  465. * Outputs the memory in the specified range as ascii
  466. * strings up to 32 characters per line. The default
  467. * display is 12 lines for 384 characters total.
  468. *
  469. * Input:
  470. * Start - starting address to begin display
  471. * Count - number of characters to display as ascii
  472. *
  473. * Output:
  474. * None.
  475. *
  476. * Notes:
  477. * memory locations not accessible are output as "?",
  478. * but no errors are returned.
  479. *
  480. *************************************************************************/
  481. class DumpAscii : public DumpValues
  482. {
  483. public:
  484. DumpAscii(void)
  485. : DumpValues(sizeof(UCHAR), (sizeof(m_Buf) / sizeof(m_Buf[0]) - 1))
  486. {
  487. m_Base = m_Buf;
  488. }
  489. protected:
  490. // Worker methods that derived classes must define.
  491. virtual ULONG64 GetValue(void);
  492. virtual BOOL PrintValue(void);
  493. virtual void PrintUnknown(void);
  494. virtual void EndRow(void);
  495. UCHAR m_Buf[33];
  496. };
  497. ULONG64
  498. DumpAscii::GetValue(void)
  499. {
  500. return *m_Value;
  501. }
  502. BOOL
  503. DumpAscii::PrintValue(void)
  504. {
  505. UCHAR ch;
  506. ch = *m_Value;
  507. if (ch == 0)
  508. {
  509. return FALSE;
  510. }
  511. if (ch < 0x20 || ch > 0x7e)
  512. {
  513. ch = '.';
  514. }
  515. *m_Out++ = ch;
  516. return TRUE;
  517. }
  518. void
  519. DumpAscii::PrintUnknown(void)
  520. {
  521. *m_Out++ = '?';
  522. }
  523. void
  524. DumpAscii::EndRow(void)
  525. {
  526. *m_Out++ = 0;
  527. dprintf(" \"%s\"", m_Base);
  528. }
  529. ULONG
  530. fnDumpAsciiMemory(
  531. PADDR Start,
  532. ULONG Count
  533. )
  534. {
  535. DumpAscii Dumper;
  536. return Count - Dumper.Dump(Start, Count);
  537. }
  538. /*** fnDumpUnicodeMemory - output unicode strings from memory
  539. *
  540. * Purpose:
  541. * Function of "du<range>" command.
  542. *
  543. * Outputs the memory in the specified range as unicode
  544. * strings up to 32 characters per line. The default
  545. * display is 12 lines for 384 characters total (768 bytes)
  546. *
  547. * Input:
  548. * Start - starting address to begin display
  549. * Count - number of characters to display as ascii
  550. *
  551. * Output:
  552. * None.
  553. *
  554. * Notes:
  555. * memory locations not accessible are output as "?",
  556. * but no errors are returned.
  557. *
  558. *************************************************************************/
  559. class DumpUnicode : public DumpValues
  560. {
  561. public:
  562. DumpUnicode(void)
  563. : DumpValues(sizeof(WCHAR), (sizeof(m_Buf) / sizeof(m_Buf[0]) - 1))
  564. {
  565. m_Base = (PUCHAR)m_Buf;
  566. }
  567. protected:
  568. // Worker methods that derived classes must define.
  569. virtual ULONG64 GetValue(void);
  570. virtual BOOL PrintValue(void);
  571. virtual void PrintUnknown(void);
  572. virtual void EndRow(void);
  573. WCHAR m_Buf[33];
  574. };
  575. ULONG64
  576. DumpUnicode::GetValue(void)
  577. {
  578. return *(WCHAR *)m_Value;
  579. }
  580. BOOL
  581. DumpUnicode::PrintValue(void)
  582. {
  583. WCHAR ch;
  584. ch = *(WCHAR *)m_Value;
  585. if (ch == UNICODE_NULL)
  586. {
  587. return FALSE;
  588. }
  589. if (ch < 0x20 || ch > 0x7e)
  590. {
  591. ch = L'.';
  592. }
  593. *(WCHAR *)m_Out = ch;
  594. m_Out += sizeof(WCHAR);
  595. return TRUE;
  596. }
  597. void
  598. DumpUnicode::PrintUnknown(void)
  599. {
  600. *(WCHAR *)m_Out = L'?';
  601. m_Out += sizeof(WCHAR);
  602. }
  603. void
  604. DumpUnicode::EndRow(void)
  605. {
  606. *(WCHAR *)m_Out = UNICODE_NULL;
  607. m_Out += sizeof(WCHAR);
  608. dprintf(" \"%ws\"", m_Base);
  609. }
  610. ULONG
  611. fnDumpUnicodeMemory(
  612. PADDR Start,
  613. ULONG Count
  614. )
  615. {
  616. DumpUnicode Dumper;
  617. return Count - Dumper.Dump(Start, Count);
  618. }
  619. /*** fnDumpByteMemory - output byte values from memory
  620. *
  621. * Purpose:
  622. * Function of "db<range>" command.
  623. *
  624. * Output the memory in the specified range as hex
  625. * byte values and ascii characters up to 16 bytes
  626. * per line. The default display is 16 lines for
  627. * 256 byte total.
  628. *
  629. * Input:
  630. * Start - starting address to begin display
  631. * Count - number of bytes to display as hex and characters
  632. *
  633. * Output:
  634. * None.
  635. *
  636. * Notes:
  637. * memory location not accessible are output as "??" for
  638. * byte values and "?" as characters, but no errors are returned.
  639. *
  640. *************************************************************************/
  641. class DumpByte : public DumpValues
  642. {
  643. public:
  644. DumpByte(void)
  645. : DumpValues(sizeof(UCHAR), (sizeof(m_Buf) / sizeof(m_Buf[0]) - 1))
  646. {
  647. m_Base = m_Buf;
  648. }
  649. protected:
  650. // Worker methods that derived classes must define.
  651. virtual ULONG64 GetValue(void);
  652. virtual BOOL PrintValue(void);
  653. virtual void PrintUnknown(void);
  654. virtual void EndRow(void);
  655. UCHAR m_Buf[17];
  656. };
  657. ULONG64
  658. DumpByte::GetValue(void)
  659. {
  660. return *m_Value;
  661. }
  662. BOOL
  663. DumpByte::PrintValue(void)
  664. {
  665. UCHAR ch;
  666. ch = *m_Value;
  667. if (m_Col == 8)
  668. {
  669. dprintf("-");
  670. }
  671. else
  672. {
  673. dprintf(" ");
  674. }
  675. dprintf("%02x", ch);
  676. if (ch < 0x20 || ch > 0x7e)
  677. {
  678. ch = '.';
  679. }
  680. *m_Out++ = ch;
  681. return TRUE;
  682. }
  683. void
  684. DumpByte::PrintUnknown(void)
  685. {
  686. if (m_Col == 8)
  687. {
  688. dprintf("-??");
  689. }
  690. else
  691. {
  692. dprintf(" ??");
  693. }
  694. *m_Out++ = '?';
  695. }
  696. void
  697. DumpByte::EndRow(void)
  698. {
  699. *m_Out++ = 0;
  700. while (m_Col < m_Columns)
  701. {
  702. dprintf(" ");
  703. m_Col++;
  704. }
  705. if ((m_Start->type & ADDR_1632) == ADDR_1632)
  706. {
  707. dprintf(" %s", m_Base);
  708. }
  709. else
  710. {
  711. dprintf(" %s", m_Base);
  712. }
  713. }
  714. void
  715. fnDumpByteMemory(
  716. PADDR Start,
  717. ULONG Count
  718. )
  719. {
  720. DumpByte Dumper;
  721. Dumper.Dump(Start, Count);
  722. }
  723. /*** fnDumpWordMemory - output word values from memory
  724. *
  725. * Purpose:
  726. * Function of "dw<range>" command.
  727. *
  728. * Output the memory in the specified range as word
  729. * values up to 8 words per line. The default display
  730. * is 16 lines for 128 words total.
  731. *
  732. * Input:
  733. * Start - starting address to begin display
  734. * Count - number of words to be displayed
  735. *
  736. * Output:
  737. * None.
  738. *
  739. * Notes:
  740. * memory locations not accessible are output as "????",
  741. * but no errors are returned.
  742. *
  743. *************************************************************************/
  744. class DumpWord : public DumpValues
  745. {
  746. public:
  747. DumpWord(void)
  748. : DumpValues(sizeof(WORD), 8) {}
  749. protected:
  750. // Worker methods that derived classes must define.
  751. virtual ULONG64 GetValue(void);
  752. virtual BOOL PrintValue(void);
  753. virtual void PrintUnknown(void);
  754. };
  755. ULONG64
  756. DumpWord::GetValue(void)
  757. {
  758. return *(WORD *)m_Value;
  759. }
  760. BOOL
  761. DumpWord::PrintValue(void)
  762. {
  763. dprintf(" %04x", *(WORD *)m_Value);
  764. return TRUE;
  765. }
  766. void
  767. DumpWord::PrintUnknown(void)
  768. {
  769. dprintf(" ????");
  770. }
  771. void
  772. fnDumpWordMemory(
  773. PADDR Start,
  774. ULONG Count
  775. )
  776. {
  777. DumpWord Dumper;
  778. Dumper.Dump(Start, Count);
  779. }
  780. /*** fnDumpDwordMemory - output dword value from memory
  781. *
  782. * Purpose:
  783. * Function of "dd<range>" command.
  784. *
  785. * Output the memory in the specified range as double
  786. * word values up to 4 double words per line. The default
  787. * display is 16 lines for 64 double words total.
  788. *
  789. * Input:
  790. * Start - starting address to begin display
  791. * Count - number of double words to be displayed
  792. * fDumpSymbols - Dump symbol for DWORD.
  793. *
  794. * Output:
  795. * None.
  796. *
  797. * Notes:
  798. * memory locations not accessible are output as "????????",
  799. * but no errors are returned.
  800. *
  801. *************************************************************************/
  802. class DumpDword : public DumpValues
  803. {
  804. public:
  805. DumpDword(BOOL DumpSymbols)
  806. : DumpValues(sizeof(DWORD), DumpSymbols ? 1 : 4)
  807. {
  808. m_DumpSymbols = DumpSymbols;
  809. }
  810. protected:
  811. // Worker methods that derived classes must define.
  812. virtual ULONG64 GetValue(void);
  813. virtual BOOL PrintValue(void);
  814. virtual void PrintUnknown(void);
  815. BOOL m_DumpSymbols;
  816. };
  817. ULONG64
  818. DumpDword::GetValue(void)
  819. {
  820. return *(DWORD *)m_Value;
  821. }
  822. BOOL
  823. DumpDword::PrintValue(void)
  824. {
  825. CHAR SymBuf[MAX_SYMBOL_LEN];
  826. USHORT StdCallArgs;
  827. ULONG64 Displacement;
  828. dprintf(" %08lx", *(DWORD *)m_Value);
  829. if (m_DumpSymbols)
  830. {
  831. GetSymbolStdCall(EXTEND64(*(LONG *)m_Value),
  832. SymBuf,
  833. sizeof(SymBuf),
  834. &Displacement,
  835. &StdCallArgs);
  836. if (*SymBuf)
  837. {
  838. dprintf(" %s", SymBuf);
  839. if (Displacement)
  840. {
  841. dprintf("+0x%s", FormatDisp64(Displacement));
  842. }
  843. if (g_SymOptions & SYMOPT_LOAD_LINES)
  844. {
  845. OutputLineAddr(EXTEND64(*(LONG*)m_Value), " [%s @ %d]");
  846. }
  847. }
  848. }
  849. return TRUE;
  850. }
  851. void
  852. DumpDword::PrintUnknown(void)
  853. {
  854. dprintf(" ????????");
  855. }
  856. void
  857. fnDumpDwordMemory(
  858. PADDR Start,
  859. ULONG Count,
  860. BOOL fDumpSymbols
  861. )
  862. {
  863. DumpDword Dumper(fDumpSymbols);
  864. Dumper.Dump(Start, Count);
  865. }
  866. /*** fnDumpDwordAndCharMemory - output dword value from memory
  867. *
  868. * Purpose:
  869. * Function of "dc<range>" command.
  870. *
  871. * Output the memory in the specified range as double
  872. * word values up to 4 double words per line, followed by
  873. * an ASCII character representation of the bytes.
  874. * The default display is 16 lines for 64 double words total.
  875. *
  876. * Input:
  877. * Start - starting address to begin display
  878. * Count - number of double words to be displayed
  879. *
  880. * Output:
  881. * None.
  882. *
  883. * Notes:
  884. * memory locations not accessible are output as "????????",
  885. * but no errors are returned.
  886. *
  887. *************************************************************************/
  888. class DumpDwordAndChar : public DumpValues
  889. {
  890. public:
  891. DumpDwordAndChar(void)
  892. : DumpValues(sizeof(DWORD), (sizeof(m_Buf) - 1) / sizeof(DWORD))
  893. {
  894. m_Base = m_Buf;
  895. }
  896. protected:
  897. // Worker methods that derived classes must define.
  898. virtual ULONG64 GetValue(void);
  899. virtual BOOL PrintValue(void);
  900. virtual void PrintUnknown(void);
  901. virtual void EndRow(void);
  902. UCHAR m_Buf[17];
  903. };
  904. ULONG64
  905. DumpDwordAndChar::GetValue(void)
  906. {
  907. return *(DWORD *)m_Value;
  908. }
  909. BOOL
  910. DumpDwordAndChar::PrintValue(void)
  911. {
  912. UCHAR ch;
  913. ULONG byte;
  914. dprintf(" %08x", *(DWORD *)m_Value);
  915. for (byte = 0; byte < sizeof(DWORD); byte++)
  916. {
  917. ch = *(m_Value + byte);
  918. if (ch < 0x20 || ch > 0x7e)
  919. {
  920. ch = '.';
  921. }
  922. *m_Out++ = ch;
  923. }
  924. return TRUE;
  925. }
  926. void
  927. DumpDwordAndChar::PrintUnknown(void)
  928. {
  929. dprintf(" ????????");
  930. *m_Out++ = '?';
  931. *m_Out++ = '?';
  932. *m_Out++ = '?';
  933. *m_Out++ = '?';
  934. }
  935. void
  936. DumpDwordAndChar::EndRow(void)
  937. {
  938. *m_Out++ = 0;
  939. while (m_Col < m_Columns)
  940. {
  941. dprintf(" ");
  942. m_Col++;
  943. }
  944. dprintf(" %s", m_Base);
  945. }
  946. void
  947. fnDumpDwordAndCharMemory(PADDR Start, ULONG Count)
  948. {
  949. DumpDwordAndChar Dumper;
  950. Dumper.Dump(Start, Count);
  951. }
  952. /*** fnDumpListMemory - output linked list from memory
  953. *
  954. * Purpose:
  955. * Function of "dl addr length size" command.
  956. *
  957. * Output the memory in the specified range as a linked list
  958. *
  959. * Input:
  960. * Start - starting address to begin display
  961. * Count - number of list elements to be displayed
  962. *
  963. * Output:
  964. * None.
  965. *
  966. * Notes:
  967. * memory locations not accessible are output as "????????",
  968. * but no errors are returned.
  969. *
  970. *************************************************************************/
  971. void
  972. fnDumpListMemory(
  973. PADDR Start,
  974. ULONG elemcount,
  975. ULONG size,
  976. BOOL followBlink
  977. )
  978. {
  979. ULONG64 firstaddr;
  980. ULONG64 link;
  981. LIST_ENTRY64 list;
  982. ADDR curaddr;
  983. ULONG linkSize;
  984. PULONG plink;
  985. if (Type(*Start) & (ADDR_UNKNOWN | ADDR_V86 | ADDR_16 | ADDR_1632))
  986. {
  987. dprintf("[%u,%x:%x`%08x,%08x`%08x] - bogus address type.\n",
  988. Type(*Start),
  989. Start->seg,
  990. (ULONG)(Off(*Start)>>32),
  991. (ULONG)Off(*Start),
  992. (ULONG)(Flat(*Start)>>32),
  993. (ULONG)Flat(*Start)
  994. );
  995. return;
  996. }
  997. //
  998. // Setup to follow forward or backward links. Avoid reading more
  999. // than the forward link here if going forwards. (in case the link
  1000. // is at the end of a page).
  1001. //
  1002. firstaddr = Flat(*Start);
  1003. while (elemcount-- != 0 && Flat(*Start) != 0)
  1004. {
  1005. if (followBlink)
  1006. {
  1007. if (g_Target->ReadListEntry(g_Machine,
  1008. Flat(*Start), &list) != S_OK)
  1009. {
  1010. break;
  1011. }
  1012. link = list.Blink;
  1013. }
  1014. else
  1015. {
  1016. if (g_Target->ReadPointer(g_Machine,
  1017. Flat(*Start), &link) != S_OK)
  1018. {
  1019. break;
  1020. }
  1021. }
  1022. curaddr = *Start;
  1023. if (g_Machine->m_Ptr64)
  1024. {
  1025. fnDumpQuadMemory(&curaddr, size, FALSE);
  1026. }
  1027. else
  1028. {
  1029. fnDumpDwordMemory(&curaddr, size, FALSE);
  1030. }
  1031. //
  1032. // If we get back to the first entry, we're done.
  1033. //
  1034. if (link == firstaddr)
  1035. {
  1036. break;
  1037. }
  1038. //
  1039. // Bail if the link is immediately circular.
  1040. //
  1041. if (Flat(*Start) == link)
  1042. {
  1043. break;
  1044. }
  1045. Flat(*Start) = Start->off = link;
  1046. if (CheckUserInterrupt())
  1047. {
  1048. WarnOut("-- User interrupt\n");
  1049. return;
  1050. }
  1051. }
  1052. }
  1053. //----------------------------------------------------------------------------
  1054. //
  1055. // fnDumpFloatMemory
  1056. //
  1057. // Dumps float values.
  1058. //
  1059. //----------------------------------------------------------------------------
  1060. class DumpFloat : public DumpValues
  1061. {
  1062. public:
  1063. DumpFloat(void)
  1064. : DumpValues(sizeof(float), 4) {}
  1065. protected:
  1066. // Worker methods that derived classes must define.
  1067. virtual ULONG64 GetValue(void);
  1068. virtual BOOL PrintValue(void);
  1069. virtual void PrintUnknown(void);
  1070. };
  1071. ULONG64
  1072. DumpFloat::GetValue(void)
  1073. {
  1074. // NTRAID#72849-2000/02/09-drewb.
  1075. // Expression results are always integers right now
  1076. // so just return the raw bits for the float.
  1077. return *(ULONG *)m_Value;
  1078. }
  1079. BOOL
  1080. DumpFloat::PrintValue(void)
  1081. {
  1082. dprintf(" %16.8g", *(float *)m_Value);
  1083. return TRUE;
  1084. }
  1085. void
  1086. DumpFloat::PrintUnknown(void)
  1087. {
  1088. dprintf(" ????????????????");
  1089. }
  1090. void
  1091. fnDumpFloatMemory(PADDR Start, ULONG Count)
  1092. {
  1093. DumpFloat Dumper;
  1094. Dumper.Dump(Start, Count);
  1095. }
  1096. //----------------------------------------------------------------------------
  1097. //
  1098. // fnDumpDoubleMemory
  1099. //
  1100. // Dumps double values.
  1101. //
  1102. //----------------------------------------------------------------------------
  1103. class DumpDouble : public DumpValues
  1104. {
  1105. public:
  1106. DumpDouble(void)
  1107. : DumpValues(sizeof(double), 3) {}
  1108. protected:
  1109. // Worker methods that derived classes must define.
  1110. virtual ULONG64 GetValue(void);
  1111. virtual BOOL PrintValue(void);
  1112. virtual void PrintUnknown(void);
  1113. };
  1114. ULONG64
  1115. DumpDouble::GetValue(void)
  1116. {
  1117. // NTRAID#72849-2000/02/09-drewb.
  1118. // Expression results are always integers right now
  1119. // so just return the raw bits for the float.
  1120. return *(ULONG64 *)m_Value;
  1121. }
  1122. BOOL
  1123. DumpDouble::PrintValue(void)
  1124. {
  1125. dprintf(" %22.12lg", *(double *)m_Value);
  1126. return TRUE;
  1127. }
  1128. void
  1129. DumpDouble::PrintUnknown(void)
  1130. {
  1131. dprintf(" ????????????????????????");
  1132. }
  1133. void
  1134. fnDumpDoubleMemory(PADDR Start, ULONG Count)
  1135. {
  1136. DumpDouble Dumper;
  1137. Dumper.Dump(Start, Count);
  1138. }
  1139. /*** fnDumpQuadMemory - output quad value from memory
  1140. *
  1141. * Purpose:
  1142. * Function of "dq<range>" command.
  1143. *
  1144. * Output the memory in the specified range as quad
  1145. * word values up to 2 quad words per line. The default
  1146. * display is 16 lines for 32 quad words total.
  1147. *
  1148. * Input:
  1149. * Start - starting address to begin display
  1150. * Count - number of double words to be displayed
  1151. *
  1152. * Output:
  1153. * None.
  1154. *
  1155. * Notes:
  1156. * memory locations not accessible are output as "????????",
  1157. * but no errors are returned.
  1158. *
  1159. *************************************************************************/
  1160. class DumpQuad : public DumpValues
  1161. {
  1162. public:
  1163. DumpQuad(BOOL DumpSymbols)
  1164. : DumpValues(sizeof(ULONGLONG), DumpSymbols ? 1 : 2)
  1165. {
  1166. m_DumpSymbols = DumpSymbols;
  1167. }
  1168. protected:
  1169. // Worker methods that derived classes must define.
  1170. virtual ULONG64 GetValue(void);
  1171. virtual BOOL PrintValue(void);
  1172. virtual void PrintUnknown(void);
  1173. BOOL m_DumpSymbols;
  1174. };
  1175. ULONG64
  1176. DumpQuad::GetValue(void)
  1177. {
  1178. return *(ULONG64 *)m_Value;
  1179. }
  1180. BOOL
  1181. DumpQuad::PrintValue(void)
  1182. {
  1183. CHAR SymBuf[MAX_SYMBOL_LEN];
  1184. USHORT StdCallArgs;
  1185. ULONG64 Displacement;
  1186. ULONG64 Val = *(ULONG64*)m_Value;
  1187. dprintf(" %08lx`%08lx", (ULONG)(Val >> 32), (ULONG)Val);
  1188. if (m_DumpSymbols)
  1189. {
  1190. GetSymbolStdCall(Val,
  1191. SymBuf,
  1192. sizeof(SymBuf),
  1193. &Displacement,
  1194. &StdCallArgs);
  1195. if (*SymBuf)
  1196. {
  1197. dprintf(" %s", SymBuf);
  1198. if (Displacement)
  1199. {
  1200. dprintf("+0x%s", FormatDisp64(Displacement));
  1201. }
  1202. if (g_SymOptions & SYMOPT_LOAD_LINES)
  1203. {
  1204. OutputLineAddr(Val, " [%s @ %d]");
  1205. }
  1206. }
  1207. }
  1208. return TRUE;
  1209. }
  1210. void
  1211. DumpQuad::PrintUnknown(void)
  1212. {
  1213. dprintf(" ????????`????????");
  1214. }
  1215. void
  1216. fnDumpQuadMemory(
  1217. PADDR Start,
  1218. ULONG Count,
  1219. BOOL fDumpSymbols
  1220. )
  1221. {
  1222. DumpQuad Dumper(fDumpSymbols);
  1223. Dumper.Dump(Start, Count);
  1224. }
  1225. /*** fnDumpByteBinaryMemory - output binary value from memory
  1226. *
  1227. * Purpose:
  1228. * Function of "dyb<range>" command.
  1229. *
  1230. * Output the memory in the specified range as binary
  1231. * values up to 32 bits per line. The default
  1232. * display is 8 lines for 32 bytes total.
  1233. *
  1234. * Input:
  1235. * Start - starting address to begin display
  1236. * Count - number of double words to be displayed
  1237. *
  1238. * Output:
  1239. * None.
  1240. *
  1241. * Notes:
  1242. * memory locations not accessible are output as "????????",
  1243. * but no errors are returned.
  1244. *
  1245. *************************************************************************/
  1246. class DumpByteBinary : public DumpValues
  1247. {
  1248. public:
  1249. DumpByteBinary(void)
  1250. : DumpValues(sizeof(UCHAR), (DIMA(m_HexValue) - 1) / 3)
  1251. {
  1252. m_Base = m_HexValue;
  1253. }
  1254. protected:
  1255. // Worker methods that derived classes must define.
  1256. virtual ULONG64 GetValue(void);
  1257. virtual BOOL PrintValue(void);
  1258. virtual void PrintUnknown(void);
  1259. virtual void EndRow(void);
  1260. UCHAR m_HexValue[13];
  1261. };
  1262. ULONG64
  1263. DumpByteBinary::GetValue(void)
  1264. {
  1265. return *m_Value;
  1266. }
  1267. BOOL
  1268. DumpByteBinary::PrintValue(void)
  1269. {
  1270. ULONG i;
  1271. UCHAR RawVal;
  1272. RawVal = *m_Value;
  1273. sprintf((PSTR)m_Out, " %02x", RawVal);
  1274. m_Out += 3;
  1275. dprintf(" ");
  1276. for (i = 0; i < 8; i++)
  1277. {
  1278. dprintf("%c", (RawVal & 0x80) ? '1' : '0');
  1279. RawVal <<= 1;
  1280. }
  1281. return TRUE;
  1282. }
  1283. void
  1284. DumpByteBinary::PrintUnknown(void)
  1285. {
  1286. dprintf(" ????????");
  1287. strcpy((PSTR)m_Out, " ??");
  1288. m_Out += 3;
  1289. }
  1290. void
  1291. DumpByteBinary::EndRow(void)
  1292. {
  1293. while (m_Col < m_Columns)
  1294. {
  1295. dprintf(" ");
  1296. m_Col++;
  1297. }
  1298. dprintf(" %s", m_HexValue);
  1299. }
  1300. void
  1301. fnDumpByteBinaryMemory(
  1302. PADDR Start,
  1303. ULONG Count
  1304. )
  1305. {
  1306. DumpByteBinary Dumper;
  1307. PSTR Blanks = g_Machine->m_Ptr64 ? " " : " ";
  1308. dprintf("%s 76543210 76543210 76543210 76543210\n", Blanks);
  1309. dprintf("%s -------- -------- -------- --------\n", Blanks);
  1310. Dumper.Dump(Start, Count);
  1311. }
  1312. /*** fnDumpDwordBinaryMemory - output binary value from memory
  1313. *
  1314. * Purpose:
  1315. * Function of "dyd<range>" command.
  1316. *
  1317. * Output the memory in the specified range as binary
  1318. * values of 32 bits per line. The default
  1319. * display is 8 lines for 8 dwords total.
  1320. *
  1321. * Input:
  1322. * Start - starting address to begin display
  1323. * Count - number of double words to be displayed
  1324. *
  1325. * Output:
  1326. * None.
  1327. *
  1328. * Notes:
  1329. * memory locations not accessible are output as "????????",
  1330. * but no errors are returned.
  1331. *
  1332. *************************************************************************/
  1333. class DumpDwordBinary : public DumpValues
  1334. {
  1335. public:
  1336. DumpDwordBinary(void)
  1337. : DumpValues(sizeof(ULONG), 1)
  1338. {
  1339. }
  1340. protected:
  1341. // Worker methods that derived classes must define.
  1342. virtual ULONG64 GetValue(void);
  1343. virtual BOOL PrintValue(void);
  1344. virtual void PrintUnknown(void);
  1345. virtual void EndRow(void);
  1346. UCHAR m_HexValue[9];
  1347. };
  1348. ULONG64
  1349. DumpDwordBinary::GetValue(void)
  1350. {
  1351. return *(PULONG)m_Value;
  1352. }
  1353. BOOL
  1354. DumpDwordBinary::PrintValue(void)
  1355. {
  1356. ULONG i;
  1357. ULONG RawVal;
  1358. RawVal = *(PULONG)m_Value;
  1359. sprintf((PSTR)m_HexValue, "%08lx", RawVal);
  1360. for (i = 0; i < sizeof(ULONG) * 8; i++)
  1361. {
  1362. if ((i & 7) == 0)
  1363. {
  1364. dprintf(" ");
  1365. }
  1366. dprintf("%c", (RawVal & 0x80000000) ? '1' : '0');
  1367. RawVal <<= 1;
  1368. }
  1369. return TRUE;
  1370. }
  1371. void
  1372. DumpDwordBinary::PrintUnknown(void)
  1373. {
  1374. dprintf(" ???????? ???????? ???????? ????????");
  1375. strcpy((PSTR)m_HexValue, "????????");
  1376. }
  1377. void
  1378. DumpDwordBinary::EndRow(void)
  1379. {
  1380. dprintf(" %s", m_HexValue);
  1381. }
  1382. void
  1383. fnDumpDwordBinaryMemory(
  1384. PADDR Start,
  1385. ULONG Count
  1386. )
  1387. {
  1388. DumpDwordBinary Dumper;
  1389. PSTR Blanks = g_Machine->m_Ptr64 ? " " : " ";
  1390. dprintf("%s 3 2 1 0\n", Blanks);
  1391. dprintf("%s 10987654 32109876 54321098 76543210\n", Blanks);
  1392. dprintf("%s -------- -------- -------- --------\n", Blanks);
  1393. Dumper.Dump(Start, Count);
  1394. }
  1395. //----------------------------------------------------------------------------
  1396. //
  1397. // fnDumpSelector
  1398. //
  1399. // Dumps an x86 selector.
  1400. //
  1401. //----------------------------------------------------------------------------
  1402. void
  1403. fnDumpSelector(
  1404. ULONG Selector
  1405. )
  1406. {
  1407. DESCRIPTOR64 Desc;
  1408. ULONG Type;
  1409. LPSTR TypeName;
  1410. PSTR PreFill, PostFill, Dash;
  1411. if (g_Target->GetSelDescriptor(g_Machine,
  1412. g_CurrentProcess->CurrentThread->Handle,
  1413. Selector, &Desc) != S_OK)
  1414. {
  1415. ErrOut("Unable to get selector %X description\n", Selector);
  1416. return;
  1417. }
  1418. if (g_Machine->m_Ptr64)
  1419. {
  1420. PreFill = " ";
  1421. PostFill = " ";
  1422. Dash = "---------";
  1423. }
  1424. else
  1425. {
  1426. PreFill = "";
  1427. PostFill = "";
  1428. Dash = "";
  1429. }
  1430. dprintf("Selector %sBase%s %sLimit%s Type DPL Size Gran\n",
  1431. PreFill, PostFill, PreFill, PostFill);
  1432. dprintf("-------- --------%s --------%s ------ --- ------- ----\n",
  1433. Dash, Dash);
  1434. Type = X86_DESC_TYPE(Desc.Flags);
  1435. if ( Type & 0x10 )
  1436. {
  1437. if ( Type & 0x8 )
  1438. {
  1439. // Code Descriptor
  1440. TypeName = " Code ";
  1441. }
  1442. else
  1443. {
  1444. // Data Descriptor
  1445. TypeName = " Data ";
  1446. }
  1447. }
  1448. else
  1449. {
  1450. TypeName = " Sys. ";
  1451. }
  1452. // 1234 12345678 12345678 ?Type? 1 ....... ....
  1453. dprintf(" %04X %s %s %s %d %s %s\n",
  1454. Selector,
  1455. FormatAddr64(Desc.Base),
  1456. FormatAddr64(Desc.Limit),
  1457. TypeName,
  1458. X86_DESC_PRIVILEGE(Desc.Flags),
  1459. (Desc.Flags & X86_DESC_DEFAULT_BIG) ? " Big " : "Not Big",
  1460. (Desc.Flags & X86_DESC_GRANULARITY) ? "Page" : "Byte"
  1461. );
  1462. }
  1463. //----------------------------------------------------------------------------
  1464. //
  1465. // parseEnterCommand
  1466. //
  1467. // Parses memory entry commands.
  1468. //
  1469. //----------------------------------------------------------------------------
  1470. void
  1471. parseEnterCommand(
  1472. void
  1473. )
  1474. {
  1475. CHAR ch;
  1476. static CHAR s_EnterType = 'b';
  1477. ADDR addr1;
  1478. UCHAR list[STRLISTSIZE * 2];
  1479. PUCHAR plist = &list[0];
  1480. ULONG count;
  1481. ULONG size;
  1482. ch = (CHAR)tolower(*g_CurCmd);
  1483. if (ch == 'a' || ch == 'b' || ch == 'w' || ch == 'd' || ch == 'q' ||
  1484. ch == 'u')
  1485. {
  1486. g_CurCmd++;
  1487. s_EnterType = ch;
  1488. }
  1489. GetAddrExpression(SEGREG_DATA, &addr1);
  1490. if (s_EnterType == 'a' || s_EnterType == 'u')
  1491. {
  1492. AsciiList((PSTR)list, &count);
  1493. if (count == 0)
  1494. {
  1495. error(UNIMPLEMENT); //TEMP
  1496. }
  1497. if (s_EnterType == 'u')
  1498. {
  1499. ULONG Ansi;
  1500. // Expand ANSI to Unicode.
  1501. Ansi = count;
  1502. count *= 2;
  1503. while (Ansi-- > 0)
  1504. {
  1505. list[Ansi * 2] = list[Ansi];
  1506. list[Ansi * 2 + 1] = 0;
  1507. }
  1508. }
  1509. }
  1510. else
  1511. {
  1512. size = 1;
  1513. if (s_EnterType == 'w')
  1514. {
  1515. size = 2;
  1516. }
  1517. else if (s_EnterType == 'd')
  1518. {
  1519. size = 4;
  1520. }
  1521. else if (s_EnterType == 'q')
  1522. {
  1523. size = 8;
  1524. }
  1525. HexList(list, &count, size);
  1526. if (count == 0)
  1527. {
  1528. fnInteractiveEnterMemory(&addr1, size);
  1529. return;
  1530. }
  1531. }
  1532. //
  1533. // memory was entered at the command line.
  1534. // just write it in, one byte at a time
  1535. //
  1536. while (count--)
  1537. {
  1538. if (SetMemString(&addr1, plist++, 1) != 1)
  1539. {
  1540. error(MEMORY);
  1541. }
  1542. AddrAdd(&addr1, 1);
  1543. if (CheckUserInterrupt())
  1544. {
  1545. WarnOut("-- User interrupt\n");
  1546. return;
  1547. }
  1548. }
  1549. }
  1550. //----------------------------------------------------------------------------
  1551. //
  1552. // fnInteractiveEnterMemory
  1553. //
  1554. // Interactively walks through memory, displaying current contents
  1555. // and prompting for new contents.
  1556. //
  1557. //----------------------------------------------------------------------------
  1558. void
  1559. fnInteractiveEnterMemory(
  1560. PADDR Address,
  1561. ULONG Size
  1562. )
  1563. {
  1564. CHAR EnterBuf[1024];
  1565. PSTR Enter;
  1566. ULONG64 Content;
  1567. PSTR CmdSaved = g_CurCmd;
  1568. PSTR StartSaved = g_CommandStart;
  1569. ULONG64 EnteredValue;
  1570. CHAR ch;
  1571. g_PromptLength = 9 + 2 * Size;
  1572. while (TRUE)
  1573. {
  1574. if (GetMemString(Address, (PUCHAR)&Content, Size) != Size)
  1575. {
  1576. error(MEMORY);
  1577. }
  1578. dprintAddr(Address);
  1579. switch (Size)
  1580. {
  1581. case 1:
  1582. dprintf("%02x", (UCHAR)Content);
  1583. break;
  1584. case 2:
  1585. dprintf("%04x", (USHORT)Content);
  1586. break;
  1587. case 4:
  1588. dprintf("%08lx", (ULONG)Content);
  1589. break;
  1590. case 8:
  1591. dprintf("%08lx`%08lx", (ULONG)(Content>>32), (ULONG)Content);
  1592. break;
  1593. }
  1594. GetInput(" ", EnterBuf, 1024);
  1595. RemoveDelChar(EnterBuf);
  1596. Enter = EnterBuf;
  1597. if (*Enter == '\0')
  1598. {
  1599. g_CurCmd = CmdSaved;
  1600. g_CommandStart = StartSaved;
  1601. return;
  1602. }
  1603. ch = *Enter;
  1604. while (ch == ' ' || ch == '\t' || ch == ';')
  1605. {
  1606. ch = *++Enter;
  1607. }
  1608. if (*Enter == '\0')
  1609. {
  1610. AddrAdd(Address, Size);
  1611. continue;
  1612. }
  1613. g_CurCmd = Enter;
  1614. g_CommandStart = Enter;
  1615. EnteredValue = HexValue(Size);
  1616. if (SetMemString(Address, (PUCHAR)&EnteredValue, Size) != Size)
  1617. {
  1618. error(MEMORY);
  1619. }
  1620. AddrAdd(Address, Size);
  1621. }
  1622. }
  1623. /*** fnCompareMemory - compare two ranges of memory
  1624. *
  1625. * Purpose:
  1626. * Function of "c<range><addr>" command.
  1627. *
  1628. * To compare two ranges of memory, starting at offsets
  1629. * src1addr and src2addr, respectively, for length bytes.
  1630. * Bytes that mismatch are displayed with their offsets
  1631. * and contents.
  1632. *
  1633. * Input:
  1634. * src1addr - start of first memory region
  1635. * length - count of bytes to compare
  1636. * src2addr - start of second memory region
  1637. *
  1638. * Output:
  1639. * None.
  1640. *
  1641. * Exceptions:
  1642. * error exit: MEMORY - memory read access failure
  1643. *
  1644. *************************************************************************/
  1645. void
  1646. fnCompareMemory(
  1647. PADDR src1addr,
  1648. ULONG length,
  1649. PADDR src2addr
  1650. )
  1651. {
  1652. ULONG compindex;
  1653. UCHAR src1ch;
  1654. UCHAR src2ch;
  1655. for (compindex = 0; compindex < length; compindex++)
  1656. {
  1657. if (!GetMemByte(src1addr, &src1ch))
  1658. {
  1659. error(MEMORY);
  1660. }
  1661. if (!GetMemByte(src2addr, &src2ch))
  1662. {
  1663. error(MEMORY);
  1664. }
  1665. if (src1ch != src2ch)
  1666. {
  1667. dprintAddr(src1addr); dprintf(" %02x - ", src1ch);
  1668. dprintAddr(src2addr); dprintf(" %02x\n", src2ch);
  1669. }
  1670. AddrAdd(src1addr,1);
  1671. AddrAdd(src2addr,1);
  1672. if (CheckUserInterrupt())
  1673. {
  1674. WarnOut("-- User interrupt\n");
  1675. return;
  1676. }
  1677. }
  1678. }
  1679. /*** fnMoveMemory - move a range of memory to another
  1680. *
  1681. * Purpose:
  1682. * Function of "m<range><addr>" command.
  1683. *
  1684. * To move a range of memory starting at srcaddr to memory
  1685. * starting at destaddr for length bytes.
  1686. *
  1687. * Input:
  1688. * srcaddr - start of source memory region
  1689. * length - count of bytes to move
  1690. * destaddr - start of destination memory region
  1691. *
  1692. * Output:
  1693. * memory at destaddr has moved values
  1694. *
  1695. * Exceptions:
  1696. * error exit: MEMORY - memory reading or writing access failure
  1697. *
  1698. *************************************************************************/
  1699. void
  1700. fnMoveMemory(
  1701. PADDR srcaddr,
  1702. ULONG length,
  1703. PADDR destaddr
  1704. )
  1705. {
  1706. UCHAR ch;
  1707. ULONG64 incr = 1;
  1708. if (AddrLt(*srcaddr, *destaddr))
  1709. {
  1710. AddrAdd(srcaddr, length - 1);
  1711. AddrAdd(destaddr, length - 1);
  1712. incr = (ULONG64)-1;
  1713. }
  1714. while (length--)
  1715. {
  1716. if (GetMemString(srcaddr, &ch, 1) != 1)
  1717. {
  1718. error(MEMORY);
  1719. }
  1720. if (SetMemString(destaddr, &ch, 1) != 1)
  1721. {
  1722. error(MEMORY);
  1723. }
  1724. AddrAdd(srcaddr, incr);
  1725. AddrAdd(destaddr, incr);
  1726. if (CheckUserInterrupt())
  1727. {
  1728. WarnOut("-- User interrupt\n");
  1729. return;
  1730. }
  1731. }
  1732. }
  1733. /*** fnFillMemory - fill memory with a byte list
  1734. *
  1735. * Purpose:
  1736. * Function of "f<range><bytelist>" command.
  1737. *
  1738. * To fill a range of memory with the byte list specified.
  1739. * The pattern repeats if the range size is larger than the
  1740. * byte list size.
  1741. *
  1742. * Input:
  1743. * Start - offset of memory to fill
  1744. * length - number of bytes to fill
  1745. * *plist - pointer to byte array to define values to set
  1746. * length - size of *plist array
  1747. *
  1748. * Exceptions:
  1749. * error exit: MEMORY - memory write access failure
  1750. *
  1751. * Output:
  1752. * memory at Start filled.
  1753. *
  1754. *************************************************************************/
  1755. void
  1756. ParseFillMemory(void)
  1757. {
  1758. HRESULT Status;
  1759. BOOL Virtual = TRUE;
  1760. ADDR Addr;
  1761. ULONG64 Size;
  1762. UCHAR Pattern[STRLISTSIZE];
  1763. ULONG PatternSize;
  1764. ULONG Done;
  1765. if (*g_CurCmd == 'p')
  1766. {
  1767. Virtual = FALSE;
  1768. g_CurCmd++;
  1769. }
  1770. GetRange(&Addr, &Size, 1, SEGREG_DATA);
  1771. HexList(Pattern, &PatternSize, 1);
  1772. if (PatternSize == 0)
  1773. {
  1774. error(SYNTAX);
  1775. }
  1776. if (Virtual)
  1777. {
  1778. Status = g_Target->FillVirtual(Flat(Addr), (ULONG)Size,
  1779. Pattern, PatternSize,
  1780. &Done);
  1781. }
  1782. else
  1783. {
  1784. Status = g_Target->FillPhysical(Flat(Addr), (ULONG)Size,
  1785. Pattern, PatternSize,
  1786. &Done);
  1787. }
  1788. if (Status != S_OK)
  1789. {
  1790. error(MEMORY);
  1791. }
  1792. else
  1793. {
  1794. dprintf("Filled 0x%x bytes\n", Done);
  1795. }
  1796. }
  1797. /*** fnSearchMemory - search memory with for a byte list
  1798. *
  1799. * Purpose:
  1800. * Function of "s<range><bytelist>" command.
  1801. *
  1802. * To search a range of memory with the byte list specified.
  1803. * If a match occurs, the offset of memory is output.
  1804. *
  1805. * Input:
  1806. * Start - offset of memory to start search
  1807. * length - size of range to search
  1808. * *plist - pointer to byte array to define values to search
  1809. * count - size of *plist array
  1810. *
  1811. * Output:
  1812. * None.
  1813. *
  1814. * Exceptions:
  1815. * error exit: MEMORY - memory read access failure
  1816. *
  1817. *************************************************************************/
  1818. void
  1819. fnSearchMemory(
  1820. PADDR Start,
  1821. ULONG64 length,
  1822. PUCHAR plist,
  1823. ULONG count,
  1824. ULONG Granularity
  1825. )
  1826. {
  1827. ULONG searchindex;
  1828. ULONG listindex;
  1829. UCHAR ch;
  1830. ADDR tAddr = *Start;
  1831. ULONG64 Found;
  1832. LONG64 SearchLength = length;
  1833. HRESULT st;
  1834. do
  1835. {
  1836. st = g_Target->SearchVirtual(Flat(*Start),
  1837. SearchLength,
  1838. plist,
  1839. count,
  1840. Granularity,
  1841. &Found);
  1842. if (st == S_OK)
  1843. {
  1844. ADDRFLAT(&tAddr, Found);
  1845. switch(Granularity)
  1846. {
  1847. case 1:
  1848. fnDumpByteMemory(&tAddr, 16);
  1849. break;
  1850. case 2:
  1851. fnDumpWordMemory(&tAddr, 8);
  1852. break;
  1853. case 4:
  1854. fnDumpDwordAndCharMemory(&tAddr, 4);
  1855. break;
  1856. case 8:
  1857. fnDumpQuadMemory(&tAddr, 2, FALSE);
  1858. break;
  1859. }
  1860. // Flush out the output immediately so that
  1861. // the user can see partial results during long searches.
  1862. FlushCallbacks();
  1863. SearchLength -= Found - Flat(*Start) + Granularity;
  1864. AddrAdd(Start, (ULONG)(Found - Flat(*Start) + Granularity));
  1865. if (CheckUserInterrupt())
  1866. {
  1867. WarnOut("-- User interrupt\n");
  1868. return;
  1869. }
  1870. }
  1871. }
  1872. while (SearchLength > 0 && st == S_OK);
  1873. }
  1874. void
  1875. ParseSearchMemory(void)
  1876. {
  1877. ADDR Addr;
  1878. ULONG64 Length;
  1879. UCHAR Pat[STRLISTSIZE];
  1880. ULONG PatLen;
  1881. ULONG Gran;
  1882. while (*g_CurCmd == ' ')
  1883. {
  1884. g_CurCmd++;
  1885. }
  1886. Gran = 1;
  1887. if (*g_CurCmd == '-')
  1888. {
  1889. g_CurCmd++;
  1890. switch(*g_CurCmd)
  1891. {
  1892. case 'w':
  1893. Gran = 2;
  1894. break;
  1895. case 'd':
  1896. Gran = 4;
  1897. break;
  1898. case 'q':
  1899. Gran = 8;
  1900. break;
  1901. default:
  1902. error(SYNTAX);
  1903. break;
  1904. }
  1905. g_CurCmd++;
  1906. }
  1907. ADDRFLAT(&Addr, 0);
  1908. Length = 16;
  1909. GetRange(&Addr, &Length, Gran, SEGREG_DATA);
  1910. if (Flat(Addr))
  1911. {
  1912. HexList(Pat, &PatLen, Gran);
  1913. if (PatLen == 0)
  1914. {
  1915. PCSTR Err = "Search pattern missing from";
  1916. ReportError(SYNTAX, &Err);
  1917. }
  1918. fnSearchMemory(&Addr, Length * Gran, Pat, PatLen, Gran);
  1919. }
  1920. }
  1921. /*** fnInputIo - read and output io
  1922. *
  1923. * Purpose:
  1924. * Function of "ib, iw, id <address>" command.
  1925. *
  1926. * Read (input) and print the value at the specified io address.
  1927. *
  1928. * Input:
  1929. * IoAddress - Address to read.
  1930. * InputType - The size type 'b', 'w', or 'd'
  1931. *
  1932. * Output:
  1933. * None.
  1934. *
  1935. * Notes:
  1936. * I/O locations not accessible are output as "??", "????", or
  1937. * "????????", depending on size. No errors are returned.
  1938. *
  1939. *************************************************************************/
  1940. void
  1941. fnInputIo(
  1942. ULONG64 IoAddress,
  1943. UCHAR InputType
  1944. )
  1945. {
  1946. ULONG InputValue;
  1947. ULONG InputSize = 1;
  1948. HRESULT Status;
  1949. CHAR Format[] = "%01lx";
  1950. InputValue = 0;
  1951. if (InputType == 'w')
  1952. {
  1953. InputSize = 2;
  1954. }
  1955. else if (InputType == 'd')
  1956. {
  1957. InputSize = 4;
  1958. }
  1959. Status = g_Target->ReadIo(Isa, 0, 1, IoAddress, &InputValue, InputSize,
  1960. NULL);
  1961. dprintf("%s: ", FormatAddr64(IoAddress));
  1962. if (Status == S_OK)
  1963. {
  1964. Format[2] = (CHAR)('0' + (InputSize * 2));
  1965. dprintf(Format, InputValue);
  1966. }
  1967. else
  1968. {
  1969. while (InputSize--)
  1970. {
  1971. dprintf("??");
  1972. }
  1973. }
  1974. dprintf("\n");
  1975. }
  1976. /*** fnOutputIo - output io
  1977. *
  1978. * Purpose:
  1979. * Function of "ob, ow, od <address>" command.
  1980. *
  1981. * Write a value to the specified io address.
  1982. *
  1983. * Input:
  1984. * IoAddress - Address to read.
  1985. * OutputValue - Value to be written
  1986. * OutputType - The output size type 'b', 'w', or 'd'
  1987. *
  1988. * Output:
  1989. * None.
  1990. *
  1991. * Notes:
  1992. * No errors are returned.
  1993. *
  1994. *************************************************************************/
  1995. void
  1996. fnOutputIo (
  1997. ULONG64 IoAddress,
  1998. ULONG OutputValue,
  1999. UCHAR OutputType
  2000. )
  2001. {
  2002. ULONG OutputSize = 1;
  2003. if (OutputType == 'w')
  2004. {
  2005. OutputSize = 2;
  2006. }
  2007. else if (OutputType == 'd')
  2008. {
  2009. OutputSize = 4;
  2010. }
  2011. g_Target->WriteIo(Isa, 0, 1, IoAddress, &OutputValue, OutputSize, NULL);
  2012. }