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

2518 lines
60 KiB

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