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.
170 lines
5.2 KiB
170 lines
5.2 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// Disassembly portions of AMD64 machine implementation.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2000-2002.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
#define BIT20(b) ((b) & 0x07)
|
|
#define BIT53(b) (((b) >> 3) & 0x07)
|
|
#define BIT76(b) (((b) >> 6) & 0x03)
|
|
|
|
HRESULT
|
|
Amd64MachineInfo::NewBreakpoint(DebugClient* Client,
|
|
ULONG Type,
|
|
ULONG Id,
|
|
Breakpoint** RetBp)
|
|
{
|
|
HRESULT Status;
|
|
|
|
switch(Type & (DEBUG_BREAKPOINT_CODE | DEBUG_BREAKPOINT_DATA))
|
|
{
|
|
case DEBUG_BREAKPOINT_CODE:
|
|
*RetBp = new CodeBreakpoint(Client, Id, IMAGE_FILE_MACHINE_AMD64);
|
|
Status = (*RetBp) ? S_OK : E_OUTOFMEMORY;
|
|
break;
|
|
case DEBUG_BREAKPOINT_DATA:
|
|
*RetBp = new X86DataBreakpoint(Client, Id, AMD64_CR4,
|
|
IS_KERNEL_TARGET(m_Target) ?
|
|
AMD64_KDR6 : AMD64_DR6,
|
|
IMAGE_FILE_MACHINE_AMD64);
|
|
Status = (*RetBp) ? S_OK : E_OUTOFMEMORY;
|
|
break;
|
|
default:
|
|
// Unknown breakpoint type.
|
|
Status = E_NOINTERFACE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
void
|
|
Amd64MachineInfo::InsertThreadDataBreakpoints(void)
|
|
{
|
|
ULONG64 Dr7Value;
|
|
ULONG Dr6Idx, Dr7Idx, Dr0Idx;
|
|
|
|
BpOut("Thread %d data breaks %d\n",
|
|
g_Thread->m_UserId, g_Thread->m_NumDataBreaks);
|
|
|
|
if (IS_KERNEL_TARGET(m_Target))
|
|
{
|
|
Dr6Idx = AMD64_KDR6;
|
|
Dr7Idx = AMD64_KDR7;
|
|
Dr0Idx = AMD64_KDR0;
|
|
}
|
|
else
|
|
{
|
|
Dr6Idx = AMD64_DR6;
|
|
Dr7Idx = AMD64_DR7;
|
|
Dr0Idx = AMD64_DR0;
|
|
}
|
|
|
|
// Start with all breaks turned off.
|
|
Dr7Value = GetReg64(Dr7Idx) & ~X86_DR7_CTRL_03_MASK;
|
|
|
|
if (g_Thread->m_NumDataBreaks > 0)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < g_Thread->m_NumDataBreaks; i++)
|
|
{
|
|
X86DataBreakpoint* Bp =
|
|
(X86DataBreakpoint *)g_Thread->m_DataBreakBps[i];
|
|
|
|
ULONG64 Addr = Flat(*Bp->GetAddr());
|
|
BpOut(" dbp %d at %I64x\n", i, Addr);
|
|
if (g_DataBreakpointsChanged)
|
|
{
|
|
SetReg64(Dr0Idx + i, Addr);
|
|
}
|
|
// There are two enable bits per breakpoint
|
|
// and four len/rw bits so split up enables
|
|
// and len/rw when shifting into place.
|
|
Dr7Value |=
|
|
((Bp->m_Dr7Bits & 0xffff0000) << (i * 4)) |
|
|
((Bp->m_Dr7Bits & X86_DR7_ALL_ENABLES) << (i * 2));
|
|
}
|
|
|
|
// The kernel automatically clears DR6 when it
|
|
// processes a DBGKD_CONTROL_SET.
|
|
if (IS_USER_TARGET(m_Target))
|
|
{
|
|
SetReg64(Dr6Idx, 0);
|
|
}
|
|
|
|
// Set local exact match, which is effectively global on NT.
|
|
Dr7Value |= X86_DR7_LOCAL_EXACT_ENABLE;
|
|
}
|
|
|
|
BpOut(" thread %d DR7 %I64X\n", g_Thread->m_UserId, Dr7Value);
|
|
SetReg64(Dr7Idx, Dr7Value);
|
|
}
|
|
|
|
void
|
|
Amd64MachineInfo::RemoveThreadDataBreakpoints(void)
|
|
{
|
|
SetReg64(IS_KERNEL_TARGET(m_Target) ? AMD64_KDR7 : AMD64_DR7, 0);
|
|
}
|
|
|
|
ULONG
|
|
Amd64MachineInfo::IsBreakpointOrStepException(PEXCEPTION_RECORD64 Record,
|
|
ULONG FirstChance,
|
|
PADDR BpAddr,
|
|
PADDR RelAddr)
|
|
{
|
|
if (Record->ExceptionCode == STATUS_BREAKPOINT)
|
|
{
|
|
// Data breakpoints hit as STATUS_SINGLE_STEP so
|
|
// this can only be a code breakpoint.
|
|
if (IS_USER_TARGET(m_Target) && FirstChance)
|
|
{
|
|
// Back up to the actual breakpoint instruction.
|
|
AddrSub(BpAddr, X86_INT3_LEN);
|
|
SetPC(BpAddr);
|
|
}
|
|
return EXBS_BREAKPOINT_CODE;
|
|
}
|
|
else if (Record->ExceptionCode == STATUS_SINGLE_STEP)
|
|
{
|
|
ULONG64 Dr6;
|
|
ULONG64 Dr7;
|
|
|
|
if (IS_KERNEL_TARGET(m_Target))
|
|
{
|
|
Dr6 = GetReg64(AMD64_KDR6);
|
|
Dr7 = GetReg64(AMD64_KDR7);
|
|
}
|
|
else
|
|
{
|
|
Dr6 = GetReg64(AMD64_DR6);
|
|
Dr7 = GetReg64(AMD64_DR7);
|
|
}
|
|
|
|
BpOut("Amd64 step: DR6 %I64X, DR7 %I64X\n", Dr6, Dr7);
|
|
|
|
// The single step bit should always be clear if a data breakpoint
|
|
// is hit but also check the DR7 enables just in case.
|
|
// We've also seen cases where DR6 shows no hits, so consider
|
|
// that a single step also.
|
|
if ((Dr6 & X86_DR6_SINGLE_STEP) || (Dr7 & X86_DR7_ALL_ENABLES) == 0 ||
|
|
(Dr6 & X86_DR6_BREAK_03) == 0)
|
|
{
|
|
// This is a true single step exception, not
|
|
// a data breakpoint.
|
|
return EXBS_STEP_INSTRUCTION;
|
|
}
|
|
else
|
|
{
|
|
// Some data breakpoint must be hit.
|
|
// There doesn't appear to be any way to get the
|
|
// faulting instruction address so just leave the PC.
|
|
return EXBS_BREAKPOINT_DATA;
|
|
}
|
|
}
|
|
|
|
return EXBS_NONE;
|
|
}
|