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.

1121 lines
26 KiB

  1. /*++
  2. Copyright (c) 1990-2001 Microsoft Corporation
  3. Module Name:
  4. kdcpuapi.c
  5. Abstract:
  6. This module implements CPU specific remote debug APIs.
  7. Author:
  8. Mark Lucovsky (markl) 04-Sep-1990
  9. Revision History:
  10. 24-sep-90 bryanwi
  11. Port to the x86.
  12. --*/
  13. #include <stdio.h>
  14. #include "kdp.h"
  15. #define END_OF_CONTROL_SPACE
  16. extern ULONG KdpCurrentSymbolStart, KdpCurrentSymbolEnd;
  17. extern ULONG KdSpecialCalls[];
  18. extern ULONG KdNumberOfSpecialCalls;
  19. LONG
  20. KdpLevelChange (
  21. ULONG Pc,
  22. PCONTEXT ContextRecord,
  23. PBOOLEAN SpecialCall
  24. );
  25. LONG
  26. regValue(
  27. UCHAR reg,
  28. PCONTEXT ContextRecord
  29. );
  30. BOOLEAN
  31. KdpIsSpecialCall (
  32. ULONG Pc,
  33. PCONTEXT ContextRecord,
  34. UCHAR opcode,
  35. UCHAR ModRM
  36. );
  37. ULONG
  38. KdpGetReturnAddress (
  39. PCONTEXT ContextRecord
  40. );
  41. ULONG
  42. KdpGetCallNextOffset (
  43. ULONG Pc,
  44. PCONTEXT ContextRecord
  45. );
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGEKD, KdpLevelChange)
  48. #pragma alloc_text(PAGEKD, regValue)
  49. #pragma alloc_text(PAGEKD, KdpIsSpecialCall)
  50. #pragma alloc_text(PAGEKD, KdpGetReturnAddress)
  51. #pragma alloc_text(PAGEKD, KdpSetContextState)
  52. #pragma alloc_text(PAGEKD, KdpSetStateChange)
  53. #pragma alloc_text(PAGEKD, KdpGetStateChange)
  54. #pragma alloc_text(PAGEKD, KdpSysReadControlSpace)
  55. #pragma alloc_text(PAGEKD, KdpSysWriteControlSpace)
  56. #pragma alloc_text(PAGEKD, KdpSysReadIoSpace)
  57. #pragma alloc_text(PAGEKD, KdpSysWriteIoSpace)
  58. #pragma alloc_text(PAGEKD, KdpSysReadMsr)
  59. #pragma alloc_text(PAGEKD, KdpSysWriteMsr)
  60. #pragma alloc_text(PAGEKD, KdpGetCallNextOffset)
  61. #endif
  62. /**** KdpIsTryFinallyReturn - detect finally optimization
  63. *
  64. * Input:
  65. * pc - program counter of instruction to check
  66. * ContextRecord - machine specific context
  67. *
  68. * Output:
  69. * returns TRUE if this is a try-finally returning to the same
  70. * scope
  71. ***************************************************************************/
  72. BOOLEAN
  73. KdpIsTryFinallyReturn (
  74. ULONG Pc,
  75. PCONTEXT ContextRecord
  76. )
  77. {
  78. ULONG retaddr;
  79. ULONG calldisp;
  80. UCHAR inst;
  81. //
  82. // The complier generates code for a try-finally that involves having
  83. // a ret instruction that does not match with a call instruction.
  84. // This ret never returns a value (ie, it's a c3 return and not a
  85. // c2). It always returns into the current symbol scope. It is never
  86. // preceeded by a leave, which (hopefully) should differentiate it
  87. // from recursive returns. Check for this, and if we find it count
  88. // it as *0* level change.
  89. //
  90. // As an optimization, the compiler will often change:
  91. // CALL
  92. // RET
  93. // into:
  94. // JMP
  95. // In either case, we figure out the return address. It's the first 4 bytes
  96. // on the stack.
  97. //
  98. if (!NT_SUCCESS(KdpCopyFromPtr(&retaddr, ContextRecord->Esp, 4, NULL))) {
  99. return FALSE;
  100. }
  101. // DPRINT(( "Start %x return %x end %x\n", KdpCurrentSymbolStart, retaddr, KdpCurrentSymbolEnd ));
  102. if ( (KdpCurrentSymbolStart < retaddr) && (retaddr < KdpCurrentSymbolEnd) ) {
  103. //
  104. // Well, things aren't this nice. We may have transferred but not yet
  105. // updated the start/end. This case occurs in a call to a thunk. We
  106. // look to see if the instruction before the return address is a call.
  107. // Gross and not 100% reliable.
  108. //
  109. if (!NT_SUCCESS(KdpCopyFromPtr(&inst, (PCHAR)retaddr - 5, 1, NULL))) {
  110. return FALSE;
  111. }
  112. if (!NT_SUCCESS(KdpCopyFromPtr(&calldisp, (PCHAR)retaddr - 4, 4, NULL))) {
  113. return FALSE;
  114. }
  115. if (inst == 0xe8 && calldisp + retaddr == Pc) {
  116. // DPRINT(( "call to thunk @ %x\n", Pc ));
  117. return FALSE;
  118. }
  119. //
  120. // returning to the current function. Either a finally
  121. // or a recursive return. Check for a leave. This is not 100%
  122. // reliable since we are betting on an instruction longer than a byte
  123. // and not ending with 0xc9.
  124. //
  125. if (!NT_SUCCESS(KdpCopyFromPtr(&inst, (PCHAR)Pc - 1, 1, NULL))) {
  126. return FALSE;
  127. }
  128. if ( inst != 0xc9 ) {
  129. // not a leave. Assume a try-finally.
  130. // DPRINT(( "transfer at %x is try-finally\n", Pc ));
  131. return TRUE;
  132. }
  133. }
  134. //
  135. // This appears to be a true RET instruction
  136. //
  137. return FALSE;
  138. }
  139. /**** KdpLevelChange - say how the instruction affects the call level
  140. *
  141. * Input:
  142. * pc - program counter of instruction to check
  143. * ContextRecord - machine specific context
  144. * SpecialCall - pointer to returned boolean indicating if the
  145. * instruction is a transfer to a special routine
  146. *
  147. * Output:
  148. * returns -1 for a level pop, 1 for a push and 0 if it is
  149. * unchanged.
  150. * NOTE: This function belongs in some other file. I should move it.
  151. ***************************************************************************/
  152. LONG
  153. KdpLevelChange (
  154. ULONG Pc,
  155. PCONTEXT ContextRecord,
  156. PBOOLEAN SpecialCall
  157. )
  158. {
  159. UCHAR membuf[2];
  160. ULONG Addr;
  161. membuf[0] = 0xcc;
  162. membuf[1] = 0xcc;
  163. KdpCopyFromPtr(membuf, Pc, 2, NULL);
  164. switch (membuf[0]) {
  165. case 0xe8: // CALL direct w/32 bit displacement
  166. //
  167. // For try/finally, the compiler may, in addition to the push/ret trick
  168. // below, use a call to the finally thunk. Since we treat a RET to
  169. // within the same symbol scope as not changing levels, we will also
  170. // treat such a call as not changing levels either
  171. //
  172. if (!NT_SUCCESS(KdpCopyFromPtr(&Addr, (PCHAR)Pc + 1, 4, NULL))) {
  173. Addr = 0;
  174. } else {
  175. Addr += Pc + 5;
  176. }
  177. if ((KdpCurrentSymbolStart <= Addr) && (Addr < KdpCurrentSymbolEnd)) {
  178. *SpecialCall = FALSE;
  179. return 0;
  180. }
  181. case 0x9a: // CALL segmented 16:32
  182. *SpecialCall = KdpIsSpecialCall( Pc, ContextRecord, membuf[0], membuf[1] );
  183. return 1;
  184. case 0xff:
  185. //
  186. // This is a compound instruction. Dispatch on operation
  187. //
  188. switch (membuf[1] & 0x38) {
  189. case 0x10: // CALL with mod r/m
  190. *SpecialCall = KdpIsSpecialCall( Pc, ContextRecord, membuf[0], membuf[1] );
  191. return 1;
  192. case 0x20: // JMP with mod r/m
  193. *SpecialCall = KdpIsSpecialCall( Pc, ContextRecord, membuf[0], membuf[1] );
  194. //
  195. // If this is a try/finally, we'd like to treat it as call since the
  196. // return inside the destination will bring us back to this context.
  197. // However, if it is a jmp to a special routine, we must treat it
  198. // as a no-level change operation since we won't see the special
  199. // routines's return.
  200. //
  201. // If it is not a try/finally, we'd like to treat it as a no-level
  202. // change, unless again, it is a transfer to a special call which
  203. // views this as a level up.
  204. //
  205. if (KdpIsTryFinallyReturn( Pc, ContextRecord )) {
  206. if (*SpecialCall) {
  207. //
  208. // We won't see the return, so pretend it is just
  209. // inline code
  210. //
  211. return 0;
  212. } else {
  213. //
  214. // The destinations return will bring us back to this
  215. // context
  216. //
  217. return 1;
  218. }
  219. } else if (*SpecialCall) {
  220. //
  221. // We won't see the return but we are, indeed, doing one.
  222. //
  223. return -1;
  224. } else {
  225. return 0;
  226. }
  227. default:
  228. *SpecialCall = FALSE;
  229. return 0;
  230. }
  231. case 0xc3: // RET
  232. //
  233. // If we are a try/finally ret, then we indicate that it is NOT a level
  234. // change
  235. //
  236. if (KdpIsTryFinallyReturn( Pc, ContextRecord )) {
  237. *SpecialCall = FALSE;
  238. return 0;
  239. }
  240. case 0xc2: // RET w/16 bit esp change
  241. case 0xca: // RETF w/16 bit esp change
  242. case 0xcb: // RETF
  243. *SpecialCall = FALSE;
  244. return -1;
  245. default:
  246. *SpecialCall = FALSE;
  247. return 0;
  248. }
  249. } // KdpLevelChange
  250. LONG
  251. regValue(
  252. UCHAR reg,
  253. PCONTEXT ContextRecord
  254. )
  255. {
  256. switch (reg) {
  257. case 0x0:
  258. return(ContextRecord->Eax);
  259. break;
  260. case 0x1:
  261. return(ContextRecord->Ecx);
  262. break;
  263. case 0x2:
  264. return(ContextRecord->Edx);
  265. break;
  266. case 0x3:
  267. return(ContextRecord->Ebx);
  268. break;
  269. case 0x4:
  270. return(ContextRecord->Esp);
  271. break;
  272. case 0x5:
  273. return(ContextRecord->Ebp);
  274. break;
  275. case 0x6:
  276. return(ContextRecord->Esi);
  277. break;
  278. case 0x7:
  279. return(ContextRecord->Edi);
  280. break;
  281. }
  282. return 0;
  283. }
  284. BOOLEAN
  285. KdpIsSpecialCall (
  286. ULONG Pc,
  287. PCONTEXT ContextRecord,
  288. UCHAR opcode,
  289. UCHAR modRM
  290. )
  291. /*++
  292. Routine Description:
  293. Check to see if the instruction at pc is a call to one of the
  294. SpecialCall routines.
  295. Argument:
  296. Pc - program counter of instruction in question.
  297. --*/
  298. {
  299. UCHAR sib;
  300. USHORT twoBytes;
  301. ULONG callAddr;
  302. ULONG addrAddr;
  303. LONG offset;
  304. ULONG i;
  305. char d8;
  306. if ( opcode == 0xe8 ) {
  307. //
  308. // Signed offset from pc
  309. //
  310. if (!NT_SUCCESS(KdpCopyFromPtr(&offset, (PCHAR)Pc + 1, 4, NULL))) {
  311. callAddr = 0;
  312. } else {
  313. callAddr = Pc + offset + 5; // +5 for instr len.
  314. }
  315. } else if ( opcode == 0xff ) {
  316. if ( ((modRM & 0x38) != 0x10) && ((modRM & 0x38) != 0x20) ) {
  317. // not call or jump
  318. return FALSE;
  319. }
  320. if ( (modRM & 0x08) == 0x08 ) {
  321. // m16:16 or m16:32 -- we don't handle this
  322. return FALSE;
  323. }
  324. if ( (modRM & 0xc0) == 0xc0 ) {
  325. /* Direct register addressing */
  326. callAddr = regValue( (UCHAR)(modRM&0x7), ContextRecord );
  327. } else if ( (modRM & 0xc7) == 0x05 ) {
  328. //
  329. // Calls across dll boundaries involve a call into a jump table,
  330. // wherein the jump address is set to the real called routine at DLL
  331. // load time. Check to see if we're calling such an instruction,
  332. // and if so, compute its target address and set callAddr there.
  333. //
  334. // ff15 or ff25 -- call or jump indirect with disp32. Get
  335. // address of address
  336. //
  337. if (!NT_SUCCESS(KdpCopyFromPtr(&addrAddr, (PCHAR)Pc + 2, 4, NULL))) {
  338. callAddr = 0;
  339. } else {
  340. //
  341. // Get real destination address
  342. //
  343. if (!NT_SUCCESS(KdpCopyFromPtr(&callAddr, addrAddr, 4, NULL))) {
  344. callAddr = 0;
  345. }
  346. }
  347. // DPRINT(( "Indirect call/jmp @ %x\n", Pc ));
  348. } else if ( (modRM & 0x7) == 0x4 ) {
  349. LONG indexValue;
  350. /* sib byte present */
  351. if (!NT_SUCCESS(KdpCopyFromPtr(&sib, (PCHAR)Pc + 2, 1, NULL))) {
  352. sib = 0;
  353. }
  354. indexValue = regValue( (UCHAR)((sib & 0x31) >> 3), ContextRecord );
  355. switch ( sib&0xc0 ) {
  356. case 0x0: /* x1 */
  357. break;
  358. case 0x40:
  359. indexValue *= 2;
  360. break;
  361. case 0x80:
  362. indexValue *= 4;
  363. break;
  364. case 0xc0:
  365. indexValue *= 8;
  366. break;
  367. } /* switch */
  368. switch ( modRM & 0xc0 ) {
  369. case 0x0: /* no displacement */
  370. if ( (sib & 0x7) == 0x5 ) {
  371. // DPRINT(("funny call #1 at %x\n", Pc));
  372. return FALSE;
  373. }
  374. callAddr = indexValue + regValue((UCHAR)(sib&0x7), ContextRecord );
  375. break;
  376. case 0x40:
  377. if ( (sib & 0x6) == 0x4 ) {
  378. // DPRINT(("Funny call #2\n")); /* calling into the stack */
  379. return FALSE;
  380. }
  381. if (!NT_SUCCESS(KdpCopyFromPtr( &d8, (PCHAR)Pc + 3, 1, NULL))) {
  382. d8 = 0;
  383. }
  384. callAddr = indexValue + d8 +
  385. regValue((UCHAR)(sib&0x7), ContextRecord );
  386. break;
  387. case 0x80:
  388. if ( (sib & 0x6) == 0x4 ) {
  389. // DPRINT(("Funny call #3\n")); /* calling into the stack */
  390. return FALSE;
  391. }
  392. if (!NT_SUCCESS(KdpCopyFromPtr(&offset, (PCHAR)Pc + 3, 4, NULL))) {
  393. offset = 0;
  394. }
  395. callAddr = indexValue + offset +
  396. regValue((UCHAR)(sib&0x7), ContextRecord );
  397. break;
  398. case 0xc0:
  399. ASSERT( FALSE );
  400. break;
  401. }
  402. } else {
  403. //KdPrint(( "undecoded call at %x\n",
  404. // CONTEXT_TO_PROGRAM_COUNTER(ContextRecord) ));
  405. return FALSE;
  406. }
  407. } else if ( opcode == 0x9a ) {
  408. /* Absolute address call (best I can tell, cc doesn't generate this) */
  409. if (!NT_SUCCESS(KdpCopyFromPtr( &callAddr, (PCHAR)Pc + 1, 4, NULL))) {
  410. callAddr = 0;
  411. }
  412. } else {
  413. return FALSE;
  414. }
  415. //
  416. // Calls across dll boundaries involve a call into a jump table,
  417. // wherein the jump address is set to the real called routine at DLL
  418. // load time. Check to see if we're calling such an instruction,
  419. // and if so, compute its target address and set callAddr there.
  420. //
  421. #if 0
  422. if (!NT_SUCCESS(KdpCopyFromPtr( &twoBytes, (PCHAR)callAddr, 2, NULL))) {
  423. twoBytes = 0;
  424. }
  425. if ( twoBytes == 0x25ff ) { /* i386 is little-Endian; really 0xff25 */
  426. //
  427. // This is a 'jmp dword ptr [mem]' instruction, which is the sort of
  428. // jump used for a dll-boundary crossing call. Fixup callAddr.
  429. //
  430. if (!NT_SUCCESS(KdpCopyFromPtr( &addrAddr, (PCHAR)callAddr + 2, 4, NULL))) {
  431. callAddr = 0;
  432. } else if (!NT_SUCCESS(KdpCopyFromPtr( &callAddr, addrAddr, 4, NULL))) {
  433. callAddr = 0;
  434. }
  435. }
  436. #endif
  437. for ( i = 0; i < KdNumberOfSpecialCalls; i++ ) {
  438. if ( KdSpecialCalls[i] == callAddr ) {
  439. return TRUE;
  440. }
  441. }
  442. return FALSE;
  443. }
  444. /*
  445. * Find the return address of the current function. Only works when
  446. * locals haven't yet been pushed (ie, on the first instruction of the
  447. * function).
  448. */
  449. ULONG
  450. KdpGetReturnAddress (
  451. PCONTEXT ContextRecord
  452. )
  453. {
  454. ULONG retaddr;
  455. if (!NT_SUCCESS(KdpCopyFromPtr(&retaddr, ContextRecord->Esp, 4, NULL))) {
  456. retaddr = 0;
  457. }
  458. return retaddr;
  459. } // KdpGetReturnAddress
  460. VOID
  461. KdpSetContextState(
  462. IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
  463. IN PCONTEXT ContextRecord
  464. )
  465. {
  466. PKPRCB Prcb;
  467. //
  468. // Special registers for the x86
  469. //
  470. Prcb = KeGetCurrentPrcb();
  471. WaitStateChange->ControlReport.Dr6 =
  472. Prcb->ProcessorState.SpecialRegisters.KernelDr6;
  473. WaitStateChange->ControlReport.Dr7 =
  474. Prcb->ProcessorState.SpecialRegisters.KernelDr7;
  475. WaitStateChange->ControlReport.SegCs = (USHORT)(ContextRecord->SegCs);
  476. WaitStateChange->ControlReport.SegDs = (USHORT)(ContextRecord->SegDs);
  477. WaitStateChange->ControlReport.SegEs = (USHORT)(ContextRecord->SegEs);
  478. WaitStateChange->ControlReport.SegFs = (USHORT)(ContextRecord->SegFs);
  479. WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags;
  480. WaitStateChange->ControlReport.ReportFlags = X86_REPORT_INCLUDES_SEGS;
  481. // If the current code segment is a known flat code
  482. // segment let the debugger know so that it doesn't
  483. // have to retrieve the descriptor.
  484. if (ContextRecord->SegCs == KGDT_R0_CODE ||
  485. ContextRecord->SegCs == KGDT_R3_CODE + 3) {
  486. WaitStateChange->ControlReport.ReportFlags |= X86_REPORT_STANDARD_CS;
  487. }
  488. }
  489. VOID
  490. KdpSetStateChange(
  491. IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
  492. IN PEXCEPTION_RECORD ExceptionRecord,
  493. IN PCONTEXT ContextRecord,
  494. IN BOOLEAN SecondChance
  495. )
  496. /*++
  497. Routine Description:
  498. Fill in the Wait_State_Change message record.
  499. Arguments:
  500. WaitStateChange - Supplies pointer to record to fill in
  501. ExceptionRecord - Supplies a pointer to an exception record.
  502. ContextRecord - Supplies a pointer to a context record.
  503. SecondChance - Supplies a boolean value that determines whether this is
  504. the first or second chance for the exception.
  505. Return Value:
  506. None.
  507. --*/
  508. {
  509. KdpSetContextState(WaitStateChange, ContextRecord);
  510. }
  511. VOID
  512. KdpGetStateChange(
  513. IN PDBGKD_MANIPULATE_STATE64 ManipulateState,
  514. IN PCONTEXT ContextRecord
  515. )
  516. /*++
  517. Routine Description:
  518. Extract continuation control data from Manipulate_State message
  519. Arguments:
  520. ManipulateState - supplies pointer to Manipulate_State packet
  521. ContextRecord - Supplies a pointer to a context record.
  522. Return Value:
  523. None.
  524. --*/
  525. {
  526. PKPRCB Prcb;
  527. ULONG Processor;
  528. if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus) == TRUE) {
  529. //
  530. // If NT_SUCCESS returns TRUE, then the debugger is doing a
  531. // continue, and it makes sense to apply control changes.
  532. // Otherwise the debugger is saying that it doesn't know what
  533. // to do with this exception, so control values are ignored.
  534. //
  535. if (ManipulateState->u.Continue2.ControlSet.TraceFlag == TRUE) {
  536. ContextRecord->EFlags |= 0x100L;
  537. } else {
  538. ContextRecord->EFlags &= ~0x100L;
  539. }
  540. for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) {
  541. Prcb = KiProcessorBlock[Processor];
  542. Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
  543. ManipulateState->u.Continue2.ControlSet.Dr7;
  544. Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L;
  545. }
  546. if (ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart != 1) {
  547. KdpCurrentSymbolStart = ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart;
  548. KdpCurrentSymbolEnd = ManipulateState->u.Continue2.ControlSet.CurrentSymbolEnd;
  549. }
  550. }
  551. }
  552. NTSTATUS
  553. KdpSysReadControlSpace(
  554. ULONG Processor,
  555. ULONG64 Address,
  556. PVOID Buffer,
  557. ULONG Request,
  558. PULONG Actual
  559. )
  560. /*++
  561. Routine Description:
  562. Reads implementation specific system data.
  563. IMPLEMENTATION NOTE:
  564. On the X86, control space is defined as follows:
  565. 0: Base of KPROCESSOR_STATE structure. (KPRCB.ProcessorState)
  566. This includes CONTEXT record,
  567. followed by a SPECIAL_REGISTERs record
  568. Arguments:
  569. Processor - Processor's information to access.
  570. Address - Offset in control space.
  571. Buffer - Data buffer.
  572. Request - Amount of data to move.
  573. Actual - Amount of data actually moved.
  574. Return Value:
  575. NTSTATUS.
  576. --*/
  577. {
  578. ULONG Length, t;
  579. PVOID StartAddr;
  580. NTSTATUS Status;
  581. Length = Request;
  582. if ((Address < sizeof(KPROCESSOR_STATE)) &&
  583. (Processor < (ULONG)KeNumberProcessors)) {
  584. t = (ULONG)(sizeof(KPROCESSOR_STATE)) - (ULONG)Address;
  585. if (t < Length) {
  586. Length = t;
  587. }
  588. StartAddr = (PVOID)
  589. ((ULONG)Address +
  590. (ULONG)&(KiProcessorBlock[Processor]->ProcessorState));
  591. Status = KdpCopyToPtr(Buffer,
  592. StartAddr,
  593. Length,
  594. Actual);
  595. } else {
  596. Status = STATUS_UNSUCCESSFUL;
  597. *Actual = 0;
  598. }
  599. return Status;
  600. }
  601. NTSTATUS
  602. KdpSysWriteControlSpace(
  603. ULONG Processor,
  604. ULONG64 Address,
  605. PVOID Buffer,
  606. ULONG Request,
  607. PULONG Actual
  608. )
  609. /*++
  610. Routine Description:
  611. Writes implementation specific system data.
  612. Control space for x86 is as defined above.
  613. Arguments:
  614. Processor - Processor's information to access.
  615. Address - Offset in control space.
  616. Buffer - Data buffer.
  617. Request - Amount of data to move.
  618. Actual - Amount of data actually moved.
  619. Return Value:
  620. NTSTATUS.
  621. --*/
  622. {
  623. ULONG Length;
  624. PVOID StartAddr;
  625. NTSTATUS Status;
  626. if (((Address + Request) <= sizeof(KPROCESSOR_STATE)) &&
  627. (Processor < (ULONG)KeNumberProcessors)) {
  628. StartAddr = (PVOID)
  629. ((ULONG)Address +
  630. (ULONG)&(KiProcessorBlock[Processor]->ProcessorState));
  631. Status = KdpCopyFromPtr(StartAddr,
  632. Buffer,
  633. Request,
  634. Actual);
  635. } else {
  636. Status = STATUS_UNSUCCESSFUL;
  637. *Actual = 0;
  638. }
  639. return Status;
  640. }
  641. NTSTATUS
  642. KdpSysReadIoSpace(
  643. INTERFACE_TYPE InterfaceType,
  644. ULONG BusNumber,
  645. ULONG AddressSpace,
  646. ULONG64 Address,
  647. PVOID Buffer,
  648. ULONG Request,
  649. PULONG Actual
  650. )
  651. /*++
  652. Routine Description:
  653. Reads system I/O locations.
  654. Arguments:
  655. InterfaceType - I/O interface type.
  656. BusNumber - Bus number.
  657. AddressSpace - Address space.
  658. Address - I/O address.
  659. Buffer - Data buffer.
  660. Request - Amount of data to move.
  661. Actual - Amount of data actually moved.
  662. Return Value:
  663. NTSTATUS.
  664. --*/
  665. {
  666. NTSTATUS Status = STATUS_SUCCESS;
  667. if (InterfaceType != Isa || BusNumber != 0 || AddressSpace != 1) {
  668. *Actual = 0;
  669. return STATUS_UNSUCCESSFUL;
  670. }
  671. //
  672. // Check Size and Alignment
  673. //
  674. switch ( Request ) {
  675. case 1:
  676. *(PUCHAR)Buffer = READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)Address);
  677. *Actual = 1;
  678. break;
  679. case 2:
  680. if ( Address & 1 ) {
  681. Status = STATUS_DATATYPE_MISALIGNMENT;
  682. } else {
  683. *(PUSHORT)Buffer =
  684. READ_PORT_USHORT((PUSHORT)(ULONG_PTR)Address);
  685. *Actual = 2;
  686. }
  687. break;
  688. case 4:
  689. if ( Address & 3 ) {
  690. Status = STATUS_DATATYPE_MISALIGNMENT;
  691. } else {
  692. *(PULONG)Buffer =
  693. READ_PORT_ULONG((PULONG)(ULONG_PTR)Address);
  694. *Actual = 4;
  695. }
  696. break;
  697. default:
  698. Status = STATUS_INVALID_PARAMETER;
  699. *Actual = 0;
  700. break;
  701. }
  702. return Status;
  703. }
  704. NTSTATUS
  705. KdpSysWriteIoSpace(
  706. INTERFACE_TYPE InterfaceType,
  707. ULONG BusNumber,
  708. ULONG AddressSpace,
  709. ULONG64 Address,
  710. PVOID Buffer,
  711. ULONG Request,
  712. PULONG Actual
  713. )
  714. /*++
  715. Routine Description:
  716. Writes system I/O locations.
  717. Arguments:
  718. InterfaceType - I/O interface type.
  719. BusNumber - Bus number.
  720. AddressSpace - Address space.
  721. Address - I/O address.
  722. Buffer - Data buffer.
  723. Request - Amount of data to move.
  724. Actual - Amount of data actually moved.
  725. Return Value:
  726. NTSTATUS.
  727. --*/
  728. {
  729. NTSTATUS Status = STATUS_SUCCESS;
  730. if (InterfaceType != Isa || BusNumber != 0 || AddressSpace != 1) {
  731. *Actual = 0;
  732. return STATUS_UNSUCCESSFUL;
  733. }
  734. //
  735. // Check Size and Alignment
  736. //
  737. switch ( Request ) {
  738. case 1:
  739. WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)Address,
  740. *(PUCHAR)Buffer);
  741. *Actual = 1;
  742. break;
  743. case 2:
  744. if ( Address & 1 ) {
  745. Status = STATUS_DATATYPE_MISALIGNMENT;
  746. } else {
  747. WRITE_PORT_USHORT((PUSHORT)(ULONG_PTR)Address,
  748. *(PUSHORT)Buffer);
  749. *Actual = 2;
  750. }
  751. break;
  752. case 4:
  753. if ( Address & 3 ) {
  754. Status = STATUS_DATATYPE_MISALIGNMENT;
  755. } else {
  756. WRITE_PORT_ULONG((PULONG)(ULONG_PTR)Address,
  757. *(PULONG)Buffer);
  758. *Actual = 4;
  759. }
  760. break;
  761. default:
  762. Status = STATUS_INVALID_PARAMETER;
  763. *Actual = 0;
  764. break;
  765. }
  766. return Status;
  767. }
  768. NTSTATUS
  769. KdpSysReadMsr(
  770. ULONG Msr,
  771. PULONG64 Data
  772. )
  773. /*++
  774. Routine Description:
  775. Reads an MSR.
  776. Arguments:
  777. Msr - MSR index.
  778. Data - Data buffer.
  779. Return Value:
  780. NTSTATUS.
  781. --*/
  782. {
  783. NTSTATUS Status = STATUS_SUCCESS;
  784. try {
  785. *Data = RDMSR(Msr);
  786. } except (EXCEPTION_EXECUTE_HANDLER) {
  787. *Data = 0;
  788. Status = STATUS_NO_SUCH_DEVICE;
  789. }
  790. return Status;
  791. }
  792. NTSTATUS
  793. KdpSysWriteMsr(
  794. ULONG Msr,
  795. PULONG64 Data
  796. )
  797. /*++
  798. Routine Description:
  799. Writes an MSR.
  800. Arguments:
  801. Msr - MSR index.
  802. Data - Data buffer.
  803. Return Value:
  804. NTSTATUS.
  805. --*/
  806. {
  807. NTSTATUS Status = STATUS_SUCCESS;
  808. try {
  809. WRMSR (Msr, *Data);
  810. } except (EXCEPTION_EXECUTE_HANDLER) {
  811. Status = STATUS_NO_SUCH_DEVICE;
  812. }
  813. return Status;
  814. }
  815. /*** KdpGetCallNextOffset - compute "next" instruction on a call-like instruction
  816. *
  817. * Purpose:
  818. * Compute how many bytes are in a call-type instruction
  819. * so that a breakpoint can be set upon this instruction's
  820. * return. Treat indirect jmps as if they were call/ret/ret
  821. *
  822. * Returns:
  823. * offset to "next" instruction, or 0 if it wasn't a call instruction.
  824. *
  825. *************************************************************************/
  826. ULONG
  827. KdpGetCallNextOffset (
  828. ULONG Pc,
  829. PCONTEXT ContextRecord
  830. )
  831. {
  832. UCHAR membuf[2];
  833. UCHAR opcode;
  834. ULONG sib;
  835. ULONG disp;
  836. if (!NT_SUCCESS(KdpCopyFromPtr( membuf, Pc, 2, NULL ))) {
  837. return 0;
  838. }
  839. opcode = membuf[0];
  840. if ( opcode == 0xe8 ) { // CALL 32 bit disp
  841. return Pc+5;
  842. } else if ( opcode == 0x9a ) { // CALL 16:32
  843. return Pc+7;
  844. } else if ( opcode == 0xff ) {
  845. if ( membuf[1] == 0x25) { // JMP indirect
  846. return KdpGetReturnAddress( ContextRecord );
  847. }
  848. sib = ((membuf[1] & 0x07) == 0x04) ? 1 : 0;
  849. disp = (membuf[1] & 0xc0) >> 6;
  850. switch (disp) {
  851. case 0:
  852. if ( (membuf[1] & 0x07) == 0x05 ) {
  853. disp = 4; // disp32 alone
  854. } else {
  855. // disp = 0; // no displacement with reg or sib
  856. }
  857. break;
  858. case 1:
  859. // disp = 1; // disp8 with reg or sib
  860. break;
  861. case 2:
  862. disp = 4; // disp32 with reg or sib
  863. break;
  864. case 3:
  865. disp = 0; // direct register addressing (e.g., call esi)
  866. break;
  867. }
  868. return Pc + 2 + sib + disp;
  869. }
  870. return 0;
  871. } // KdpGetCallNextOffset