470 lines
12 KiB
C++
470 lines
12 KiB
C++
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Breakpoint support.
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1997-2001.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#ifndef _BRKPT_HPP_
|
||
|
#define _BRKPT_HPP_
|
||
|
|
||
|
// Ways in which a breakpoint can be hit. There's full
|
||
|
// match, hit but ignored and not hit.
|
||
|
#define BREAKPOINT_HIT 0
|
||
|
#define BREAKPOINT_HIT_IGNORED 1
|
||
|
#define BREAKPOINT_NOT_HIT 2
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Breakpoint.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#define BREAKPOINT_EXTERNAL_MODIFY_FLAGS \
|
||
|
(DEBUG_BREAKPOINT_GO_ONLY | DEBUG_BREAKPOINT_ENABLED | \
|
||
|
DEBUG_BREAKPOINT_ADDER_ONLY)
|
||
|
#define BREAKPOINT_EXTERNAL_FLAGS \
|
||
|
(BREAKPOINT_EXTERNAL_MODIFY_FLAGS | DEBUG_BREAKPOINT_DEFERRED)
|
||
|
|
||
|
// Internal flags.
|
||
|
#define BREAKPOINT_KD_INTERNAL 0x80000000
|
||
|
#define BREAKPOINT_KD_COUNT_ONLY 0x40000000
|
||
|
#define BREAKPOINT_VIRT_ADDR 0x20000000
|
||
|
#define BREAKPOINT_INSERTED 0x10000000
|
||
|
#define BREAKPOINT_IN_LIST 0x08000000
|
||
|
#define BREAKPOINT_HIDDEN 0x04000000
|
||
|
#define BREAKPOINT_NOTIFY 0x02000000
|
||
|
|
||
|
// Internal types.
|
||
|
#define EXBS_NONE 0x00000000
|
||
|
#define EXBS_BREAKPOINT_DATA 0x00000001
|
||
|
#define EXBS_BREAKPOINT_CODE 0x00000002
|
||
|
#define EXBS_BREAKPOINT_ANY 0x00000003
|
||
|
#define EXBS_STEP_INSTRUCTION 0x00000004
|
||
|
#define EXBS_STEP_BRANCH 0x00000008
|
||
|
#define EXBS_STEP_ANY 0x0000000c
|
||
|
#define EXBS_ANY 0xffffffff
|
||
|
|
||
|
enum BreakpointMatchAction
|
||
|
{
|
||
|
BREAKPOINT_ALLOW_MATCH,
|
||
|
BREAKPOINT_WARN_MATCH,
|
||
|
BREAKPOINT_REMOVE_MATCH
|
||
|
};
|
||
|
|
||
|
class Breakpoint
|
||
|
: public IDebugBreakpoint
|
||
|
{
|
||
|
public:
|
||
|
Breakpoint* m_Next;
|
||
|
Breakpoint* m_Prev;
|
||
|
ULONG m_Id;
|
||
|
ULONG m_BreakType;
|
||
|
ULONG m_Flags;
|
||
|
ULONG m_DataSize;
|
||
|
ULONG m_DataAccessType;
|
||
|
ULONG m_PassCount;
|
||
|
ULONG m_CurPassCount;
|
||
|
PCSTR m_Command;
|
||
|
PTHREAD_INFO m_MatchThread;
|
||
|
PPROCESS_INFO m_Process;
|
||
|
PCSTR m_OffsetExpr;
|
||
|
DebugClient* m_Adder;
|
||
|
ULONG64 m_MatchThreadData;
|
||
|
ULONG64 m_MatchProcessData;
|
||
|
|
||
|
Breakpoint(DebugClient* Adder, ULONG Id, ULONG Type, ULONG ProcType);
|
||
|
~Breakpoint(void);
|
||
|
|
||
|
// IUnknown.
|
||
|
STDMETHOD(QueryInterface)(
|
||
|
THIS_
|
||
|
IN REFIID InterfaceId,
|
||
|
OUT PVOID* Interface
|
||
|
);
|
||
|
STDMETHOD_(ULONG, AddRef)(
|
||
|
THIS
|
||
|
);
|
||
|
STDMETHOD_(ULONG, Release)(
|
||
|
THIS
|
||
|
);
|
||
|
|
||
|
// IDebugBreakpoint.
|
||
|
STDMETHOD(GetId)(
|
||
|
THIS_
|
||
|
OUT PULONG Id
|
||
|
);
|
||
|
STDMETHOD(GetType)(
|
||
|
THIS_
|
||
|
OUT PULONG BreakType,
|
||
|
OUT PULONG ProcType
|
||
|
);
|
||
|
STDMETHOD(GetAdder)(
|
||
|
THIS_
|
||
|
OUT PDEBUG_CLIENT* Adder
|
||
|
);
|
||
|
STDMETHOD(GetFlags)(
|
||
|
THIS_
|
||
|
OUT PULONG Flags
|
||
|
);
|
||
|
STDMETHOD(AddFlags)(
|
||
|
THIS_
|
||
|
IN ULONG Flags
|
||
|
);
|
||
|
STDMETHOD(RemoveFlags)(
|
||
|
THIS_
|
||
|
IN ULONG Flags
|
||
|
);
|
||
|
STDMETHOD(SetFlags)(
|
||
|
THIS_
|
||
|
IN ULONG Flags
|
||
|
);
|
||
|
STDMETHOD(GetOffset)(
|
||
|
THIS_
|
||
|
OUT PULONG64 Offset
|
||
|
);
|
||
|
STDMETHOD(SetOffset)(
|
||
|
THIS_
|
||
|
IN ULONG64 Offset
|
||
|
);
|
||
|
STDMETHOD(GetDataParameters)(
|
||
|
THIS_
|
||
|
OUT PULONG Size,
|
||
|
OUT PULONG AccessType
|
||
|
);
|
||
|
STDMETHOD(SetDataParameters)(
|
||
|
THIS_
|
||
|
IN ULONG Size,
|
||
|
IN ULONG AccessType
|
||
|
);
|
||
|
STDMETHOD(GetPassCount)(
|
||
|
THIS_
|
||
|
OUT PULONG Count
|
||
|
);
|
||
|
STDMETHOD(SetPassCount)(
|
||
|
THIS_
|
||
|
IN ULONG Count
|
||
|
);
|
||
|
STDMETHOD(GetCurrentPassCount)(
|
||
|
THIS_
|
||
|
OUT PULONG Count
|
||
|
);
|
||
|
STDMETHOD(GetMatchThreadId)(
|
||
|
THIS_
|
||
|
OUT PULONG Id
|
||
|
);
|
||
|
STDMETHOD(SetMatchThreadId)(
|
||
|
THIS_
|
||
|
IN ULONG Id
|
||
|
);
|
||
|
STDMETHOD(GetCommand)(
|
||
|
THIS_
|
||
|
OUT OPTIONAL PSTR Buffer,
|
||
|
IN ULONG BufferSize,
|
||
|
OUT OPTIONAL PULONG CommandSize
|
||
|
);
|
||
|
STDMETHOD(SetCommand)(
|
||
|
THIS_
|
||
|
IN PCSTR Command
|
||
|
);
|
||
|
STDMETHOD(GetOffsetExpression)(
|
||
|
THIS_
|
||
|
OUT OPTIONAL PSTR Buffer,
|
||
|
IN ULONG BufferSize,
|
||
|
OUT OPTIONAL PULONG ExpressionSize
|
||
|
);
|
||
|
STDMETHOD(SetOffsetExpression)(
|
||
|
THIS_
|
||
|
IN PCSTR Expression
|
||
|
);
|
||
|
STDMETHOD(GetParameters)(
|
||
|
THIS_
|
||
|
OUT PDEBUG_BREAKPOINT_PARAMETERS Params
|
||
|
);
|
||
|
// Breakpoint.
|
||
|
virtual HRESULT Validate(void) = 0;
|
||
|
virtual HRESULT Insert(void) = 0;
|
||
|
virtual HRESULT Remove(void) = 0;
|
||
|
virtual ULONG IsHit(PADDR Addr) = 0;
|
||
|
|
||
|
// Must resturn true if in case of THIS breakpoint hit
|
||
|
// Pc points to the instruction caused the hit
|
||
|
virtual BOOL PcAtHit() = 0;
|
||
|
|
||
|
PADDR GetAddr(void)
|
||
|
{
|
||
|
return &m_Addr;
|
||
|
}
|
||
|
|
||
|
BOOL PassHit(void)
|
||
|
{
|
||
|
if (--m_CurPassCount == 0)
|
||
|
{
|
||
|
m_CurPassCount = 1;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
ULONG GetProcType(void)
|
||
|
{
|
||
|
return m_ProcType;
|
||
|
}
|
||
|
void SetProcType(ULONG ProcType)
|
||
|
{
|
||
|
m_ProcType = ProcType;
|
||
|
m_ProcIndex = MachineTypeIndex(ProcType);
|
||
|
}
|
||
|
ULONG GetProcIndex(void)
|
||
|
{
|
||
|
return m_ProcIndex;
|
||
|
}
|
||
|
|
||
|
void ForceFlatAddr(void)
|
||
|
{
|
||
|
NotFlat(m_Addr);
|
||
|
ComputeFlatAddress(&m_Addr, NULL);
|
||
|
}
|
||
|
|
||
|
// Breakpoint is enabled, not deferred, not internal.
|
||
|
BOOL IsNormalEnabled(void)
|
||
|
{
|
||
|
return (m_Flags & (DEBUG_BREAKPOINT_ENABLED |
|
||
|
BREAKPOINT_KD_INTERNAL |
|
||
|
DEBUG_BREAKPOINT_DEFERRED)) ==
|
||
|
DEBUG_BREAKPOINT_ENABLED;
|
||
|
}
|
||
|
|
||
|
void LinkIntoList(void);
|
||
|
void UnlinkFromList(void);
|
||
|
void UpdateInternal(void);
|
||
|
BOOL EvalOffsetExpr(void);
|
||
|
HRESULT SetAddr(PADDR Addr, BreakpointMatchAction MatchAction);
|
||
|
// Matches breakpoints if they have the same insertion effect.
|
||
|
// Used when determining whether a breakpoint needs to be
|
||
|
// inserted or if another breakpoint is already covering the break.
|
||
|
BOOL IsInsertionMatch(Breakpoint* Match);
|
||
|
// Matches breakpoints if they have an insertion match and
|
||
|
// if they match publicly, such as between flags, hiddenness
|
||
|
// and so on. Used when determining whether a user breakpoint
|
||
|
// redefines an existing breakpoint.
|
||
|
BOOL IsPublicMatch(Breakpoint* Match);
|
||
|
// Check m_Match* fields against current state.
|
||
|
BOOL MatchesCurrentState(void);
|
||
|
|
||
|
protected:
|
||
|
// ProcType is private so that ProcType and ProcIndex can
|
||
|
// be kept in sync.
|
||
|
ULONG m_ProcType;
|
||
|
MachineIndex m_ProcIndex;
|
||
|
// Address is private to force users to go through SetAddr.
|
||
|
ADDR m_Addr;
|
||
|
ULONG m_CommandLen;
|
||
|
ULONG m_OffsetExprLen;
|
||
|
UCHAR m_InsertStorage[MAX_BREAKPOINT_LENGTH];
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// CodeBreakpoint.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CodeBreakpoint :
|
||
|
public Breakpoint
|
||
|
{
|
||
|
public:
|
||
|
CodeBreakpoint(DebugClient* Adder, ULONG Id, ULONG ProcType)
|
||
|
: Breakpoint(Adder, Id, DEBUG_BREAKPOINT_CODE, ProcType)
|
||
|
{
|
||
|
m_Flags |= BREAKPOINT_VIRT_ADDR;
|
||
|
}
|
||
|
|
||
|
// Breakpoint.
|
||
|
virtual HRESULT Validate(void);
|
||
|
virtual HRESULT Insert(void);
|
||
|
virtual HRESULT Remove(void);
|
||
|
virtual ULONG IsHit(PADDR Addr);
|
||
|
virtual BOOL PcAtHit()
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DataBreakpoint.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class DataBreakpoint :
|
||
|
public Breakpoint
|
||
|
{
|
||
|
public:
|
||
|
DataBreakpoint(DebugClient* Adder, ULONG Id, ULONG ProcType)
|
||
|
: Breakpoint(Adder, Id, DEBUG_BREAKPOINT_DATA, ProcType) {}
|
||
|
|
||
|
// Breakpoint.
|
||
|
virtual HRESULT Insert(void);
|
||
|
virtual HRESULT Remove(void);
|
||
|
|
||
|
// DataBreakpoint.
|
||
|
static void ClearThreadDataBreaks(PTHREAD_INFO Thread);
|
||
|
void AddToThread(PTHREAD_INFO Thread);
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// X86DataBreakpoint.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class X86DataBreakpoint :
|
||
|
public DataBreakpoint
|
||
|
{
|
||
|
public:
|
||
|
X86DataBreakpoint(DebugClient* Adder, ULONG Id,
|
||
|
ULONG Cr4Reg, ULONG Dr6Reg, ULONG ProcType)
|
||
|
: DataBreakpoint(Adder, Id, ProcType)
|
||
|
{
|
||
|
m_Dr7Bits = 0;
|
||
|
m_Cr4Reg = Cr4Reg;
|
||
|
m_Dr6Reg = Dr6Reg;
|
||
|
}
|
||
|
|
||
|
// Breakpoint.
|
||
|
virtual HRESULT Validate(void);
|
||
|
virtual ULONG IsHit(PADDR Addr);
|
||
|
|
||
|
virtual BOOL PcAtHit()
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Precomputed enable bits.
|
||
|
ULONG m_Dr7Bits;
|
||
|
|
||
|
// Register indices for getting breakpoint-related information.
|
||
|
ULONG m_Cr4Reg;
|
||
|
ULONG m_Dr6Reg;
|
||
|
|
||
|
friend class X86MachineInfo;
|
||
|
friend class Amd64MachineInfo;
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Ia64DataBreakpoint.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class Ia64DataBreakpoint :
|
||
|
public DataBreakpoint
|
||
|
{
|
||
|
public:
|
||
|
Ia64DataBreakpoint(DebugClient* Adder, ULONG Id)
|
||
|
: DataBreakpoint(Adder, Id, IMAGE_FILE_MACHINE_IA64)
|
||
|
{
|
||
|
m_Control = 0;
|
||
|
}
|
||
|
|
||
|
// Breakpoint.
|
||
|
virtual HRESULT Validate(void);
|
||
|
virtual ULONG IsHit(PADDR Addr);
|
||
|
virtual BOOL PcAtHit()
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static ULONG64 GetControl(ULONG AccessType, ULONG Size);
|
||
|
|
||
|
private:
|
||
|
ULONG64 m_Control;
|
||
|
|
||
|
friend class Ia64MachineInfo;
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// X86OnIa64DataBreakpoint.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
class X86OnIa64DataBreakpoint :
|
||
|
public X86DataBreakpoint
|
||
|
{
|
||
|
public:
|
||
|
X86OnIa64DataBreakpoint(DebugClient* Adder, ULONG Id);
|
||
|
|
||
|
// Breakpoint.
|
||
|
virtual HRESULT Validate(void);
|
||
|
virtual ULONG IsHit(PADDR Addr);
|
||
|
|
||
|
private:
|
||
|
ULONG64 m_Control;
|
||
|
|
||
|
friend class Ia64MachineInfo;
|
||
|
};
|
||
|
|
||
|
extern BOOL g_BreakpointListChanged;
|
||
|
extern BOOL g_UpdateDataBreakpoints;
|
||
|
extern BOOL g_DataBreakpointsChanged;
|
||
|
extern BOOL g_BreakpointsSuspended;
|
||
|
extern BOOL g_DeferDefined;
|
||
|
extern Breakpoint* g_DeferBp;
|
||
|
extern Breakpoint* g_StepTraceBp;
|
||
|
extern CHAR g_StepTraceCmdState;
|
||
|
extern ADDR g_PrevRelatedPc;
|
||
|
|
||
|
HRESULT BreakpointInit(void);
|
||
|
|
||
|
HRESULT InsertBreakpoints(void);
|
||
|
BOOL RemoveBreakpoints(void);
|
||
|
|
||
|
HRESULT AddBreakpoint(DebugClient* Client,
|
||
|
ULONG Type,
|
||
|
ULONG DesiredId,
|
||
|
Breakpoint** Bp);
|
||
|
void RemoveBreakpoint(Breakpoint* Bp);
|
||
|
void RemoveProcessBreakpoints(PPROCESS_INFO Process);
|
||
|
void RemoveThreadBreakpoints(PTHREAD_INFO Thread);
|
||
|
void RemoveAllKernelBreakpoints(void);
|
||
|
void RemoveAllBreakpoints(ULONG Reason);
|
||
|
|
||
|
Breakpoint* GetBreakpointByIndex(DebugClient* Client, ULONG Index);
|
||
|
Breakpoint* GetBreakpointById(DebugClient* Client, ULONG Id);
|
||
|
Breakpoint* CheckMatchingBreakpoints(Breakpoint* Match, BOOL PUBLIC,
|
||
|
ULONG IncFlags);
|
||
|
Breakpoint* CheckBreakpointHit(PPROCESS_INFO Process,
|
||
|
Breakpoint* Start, PADDR Addr,
|
||
|
ULONG ExbsType, ULONG IncFlags, ULONG ExcFlags,
|
||
|
PULONG HitType,
|
||
|
BOOL SetLastBreakpointHit);
|
||
|
ULONG NotifyHitBreakpoints(ULONG EventStatus);
|
||
|
|
||
|
void EvaluateOffsetExpressions(PPROCESS_INFO Process, ULONG Flags);
|
||
|
|
||
|
#define BPCMDS_FORCE_DISABLE 0x00000001
|
||
|
#define BPCMDS_ONE_LINE 0x00000002
|
||
|
#define BPCMDS_EXPR_ONLY 0x00000004
|
||
|
#define BPCMDS_MODULE_HINT 0x00000008
|
||
|
|
||
|
void ChangeBreakpointState(DebugClient* Client, PPROCESS_INFO ForProcess,
|
||
|
ULONG Id, UCHAR StateChange);
|
||
|
void ListBreakpoints(DebugClient* Client, PPROCESS_INFO ForProcess,
|
||
|
ULONG Id);
|
||
|
void ListBreakpointsAsCommands(DebugClient* Client, PPROCESS_INFO Process,
|
||
|
ULONG Flags);
|
||
|
PDEBUG_BREAKPOINT ParseBpCmd(DebugClient* Client, UCHAR Type,
|
||
|
PTHREAD_INFO Thread);
|
||
|
BOOL CheckBreakpointInsertedInRange(PPROCESS_INFO Process,
|
||
|
ULONG64 Start, ULONG64 End);
|
||
|
|
||
|
void DbgKdpAcquireHardwareBp(PDBGKD_CONTROL_REQUEST BpRequest);
|
||
|
void DbgKdpReleaseHardwareBp(PDBGKD_CONTROL_REQUEST BpRequest);
|
||
|
|
||
|
#endif // #ifndef _BRKPT_HPP_
|