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.

178 lines
5.5 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Disassembly portions of AMD64 machine implementation.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. // See Get/SetRegVal comments in machine.hpp.
  10. #define RegValError Do_not_use_GetSetRegVal_in_machine_implementations
  11. #define GetRegVal(index, val) RegValError
  12. #define GetRegVal32(index) RegValError
  13. #define GetRegVal64(index) RegValError
  14. #define SetRegVal(index, val) RegValError
  15. #define SetRegVal32(index, val) RegValError
  16. #define SetRegVal64(index, val) RegValError
  17. #define BIT20(b) ((b) & 0x07)
  18. #define BIT53(b) (((b) >> 3) & 0x07)
  19. #define BIT76(b) (((b) >> 6) & 0x03)
  20. HRESULT
  21. Amd64MachineInfo::NewBreakpoint(DebugClient* Client,
  22. ULONG Type,
  23. ULONG Id,
  24. Breakpoint** RetBp)
  25. {
  26. HRESULT Status;
  27. switch(Type & (DEBUG_BREAKPOINT_CODE | DEBUG_BREAKPOINT_DATA))
  28. {
  29. case DEBUG_BREAKPOINT_CODE:
  30. *RetBp = new CodeBreakpoint(Client, Id, IMAGE_FILE_MACHINE_AMD64);
  31. Status = (*RetBp) ? S_OK : E_OUTOFMEMORY;
  32. break;
  33. case DEBUG_BREAKPOINT_DATA:
  34. *RetBp = new X86DataBreakpoint(Client, Id, AMD64_CR4, AMD64_DR6, IMAGE_FILE_MACHINE_AMD64);
  35. Status = (*RetBp) ? S_OK : E_OUTOFMEMORY;
  36. break;
  37. default:
  38. // Unknown breakpoint type.
  39. Status = E_NOINTERFACE;
  40. }
  41. return Status;
  42. }
  43. void
  44. Amd64MachineInfo::InsertAllDataBreakpoints(void)
  45. {
  46. PPROCESS_INFO ProcessSave = g_CurrentProcess;
  47. PTHREAD_INFO Thread;
  48. // Update thread context for every thread.
  49. g_CurrentProcess = g_ProcessHead;
  50. while (g_CurrentProcess != NULL)
  51. {
  52. Thread = g_CurrentProcess->ThreadHead;
  53. while (Thread != NULL)
  54. {
  55. ULONG64 Dr7Value;
  56. BpOut("Thread %d data breaks %d\n",
  57. Thread->UserId, Thread->NumDataBreaks);
  58. ChangeRegContext(Thread);
  59. // Start with all breaks turned off.
  60. Dr7Value = GetReg64(AMD64_DR7) & ~X86_DR7_CTRL_03_MASK;
  61. if (Thread->NumDataBreaks > 0)
  62. {
  63. ULONG i;
  64. for (i = 0; i < Thread->NumDataBreaks; i++)
  65. {
  66. X86DataBreakpoint* Bp =
  67. (X86DataBreakpoint *)Thread->DataBreakBps[i];
  68. ULONG64 Addr = Flat(*Bp->GetAddr());
  69. BpOut(" dbp %d at %I64x\n", i, Addr);
  70. if (g_DataBreakpointsChanged)
  71. {
  72. SetReg64(AMD64_DR0 + i, Addr);
  73. }
  74. // There are two enable bits per breakpoint
  75. // and four len/rw bits so split up enables
  76. // and len/rw when shifting into place.
  77. Dr7Value |=
  78. ((Bp->m_Dr7Bits & 0xffff0000) << (i * 4)) |
  79. ((Bp->m_Dr7Bits & X86_DR7_ALL_ENABLES) << (i * 2));
  80. }
  81. // The kernel automatically clears DR6 when it
  82. // processes a DBGKD_CONTROL_SET.
  83. if (IS_USER_TARGET())
  84. {
  85. SetReg64(AMD64_DR6, 0);
  86. }
  87. // Set local exact match, which is effectively global on NT.
  88. Dr7Value |= X86_DR7_LOCAL_EXACT_ENABLE;
  89. }
  90. BpOut(" thread %d DR7 %I64X\n", Thread->UserId, Dr7Value);
  91. SetReg64(AMD64_DR7, Dr7Value);
  92. Thread = Thread->Next;
  93. }
  94. g_CurrentProcess = g_CurrentProcess->Next;
  95. }
  96. g_CurrentProcess = ProcessSave;
  97. if (g_CurrentProcess != NULL)
  98. {
  99. ChangeRegContext(g_CurrentProcess->CurrentThread);
  100. }
  101. else
  102. {
  103. ChangeRegContext(NULL);
  104. }
  105. }
  106. void
  107. Amd64MachineInfo::RemoveAllDataBreakpoints(void)
  108. {
  109. SetReg64(AMD64_DR7, 0);
  110. }
  111. ULONG
  112. Amd64MachineInfo::IsBreakpointOrStepException(PEXCEPTION_RECORD64 Record,
  113. ULONG FirstChance,
  114. PADDR BpAddr,
  115. PADDR RelAddr)
  116. {
  117. if (Record->ExceptionCode == STATUS_BREAKPOINT)
  118. {
  119. // Data breakpoints hit as STATUS_SINGLE_STEP so
  120. // this can only be a code breakpoint.
  121. if (IS_USER_TARGET() && FirstChance)
  122. {
  123. // Back up to the actual breakpoint instruction.
  124. AddrSub(BpAddr, X86_INT3_LEN);
  125. SetPC(BpAddr);
  126. }
  127. return EXBS_BREAKPOINT_CODE;
  128. }
  129. else if (Record->ExceptionCode == STATUS_SINGLE_STEP)
  130. {
  131. ULONG64 Dr6 = GetReg64(AMD64_DR6);
  132. ULONG64 Dr7 = GetReg64(AMD64_DR7);
  133. BpOut("Amd64 step: DR6 %I64X, DR7 %I64X\n", Dr6, Dr7);
  134. // The single step bit should always be set if a data breakpoint
  135. // is hit but also check the DR7 enables just in case.
  136. if ((Dr6 & X86_DR6_SINGLE_STEP) || (Dr7 & X86_DR7_ALL_ENABLES) == 0)
  137. {
  138. // This is a true single step exception, not
  139. // a data breakpoint.
  140. return EXBS_STEP_INSTRUCTION;
  141. }
  142. else
  143. {
  144. // Some data breakpoint must be hit.
  145. DBG_ASSERT(Dr6 & X86_DR6_BREAK_03);
  146. // There doesn't appear to be any way
  147. // to get the faulting address so just leave the PC.
  148. return EXBS_BREAKPOINT_DATA;
  149. }
  150. }
  151. return EXBS_NONE;
  152. }