diff options
Diffstat (limited to 'src/debug/ee/walker.h')
-rw-r--r-- | src/debug/ee/walker.h | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/debug/ee/walker.h b/src/debug/ee/walker.h new file mode 100644 index 0000000000..d7deb10ca4 --- /dev/null +++ b/src/debug/ee/walker.h @@ -0,0 +1,255 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// File: walker.h +// + +// +// Debugger code stream analysis routines +// +//***************************************************************************** + +#ifndef WALKER_H_ +#define WALKER_H_ + + +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- * + * Constants + * ------------------------------------------------------------------------- */ + +enum WALK_TYPE +{ + WALK_NEXT, + WALK_BRANCH, + WALK_COND_BRANCH, + WALK_CALL, + WALK_RETURN, + WALK_BREAK, + WALK_THROW, + WALK_META, + WALK_UNKNOWN +}; + +// struct holding information for the instruction being skipped over +struct InstructionAttribute +{ + bool m_fIsCall; // is this a call instruction? + bool m_fIsCond; // is this a conditional jump? + bool m_fIsAbsBranch; // is this an absolute branch (either a call or a jump)? + bool m_fIsRelBranch; // is this a relative branch (either a call or a jump)? + bool m_fIsWrite; // does the instruction write to an address? + + + DWORD m_cbInstr; // the size of the instruction + DWORD m_cbDisp; // the size of the displacement + DWORD m_dwOffsetToDisp; // the offset from the beginning of the instruction + // to the beginning of the displacement + BYTE m_cOperandSize; // the size of the operand + + void Reset() + { + m_fIsCall = false; + m_fIsCond = false; + m_fIsAbsBranch = false; + m_fIsRelBranch = false; + m_fIsWrite = false; + m_cbInstr = 0; + m_cbDisp = 0; + m_dwOffsetToDisp = 0; + m_cOperandSize = 0; + } +}; + +/* ------------------------------------------------------------------------- * + * Classes + * ------------------------------------------------------------------------- */ + +class Walker +{ +protected: + Walker() + : m_type(WALK_UNKNOWN), m_registers(NULL), m_ip(0), m_skipIP(0), m_nextIP(0), m_isAbsoluteBranch(false) + {LIMITED_METHOD_CONTRACT; } + +public: + + virtual void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + PREFIX_ASSUME(pregisters != NULL); + _ASSERTE(GetControlPC(pregisters) == (PCODE)ip); + + m_registers = pregisters; + SetIP(ip); + } + + const BYTE *GetIP() + { return m_ip; } + + WALK_TYPE GetOpcodeWalkType() + { return m_type; } + + const BYTE *GetSkipIP() + { return m_skipIP; } + + bool IsAbsoluteBranch() + { return m_isAbsoluteBranch; } + + const BYTE *GetNextIP() + { return m_nextIP; } + + // We don't currently keep the registers up to date + // <TODO> Check if it really works on IA64. </TODO> + virtual void Next() { m_registers = NULL; SetIP(m_nextIP); } + virtual void Skip() { m_registers = NULL; LOG((LF_CORDB, LL_INFO10000, "skipping over to %p \n", m_skipIP)); SetIP(m_skipIP); } + + // Decode the instruction + virtual void Decode() = 0; + +private: + void SetIP(const BYTE *ip) + { m_ip = ip; Decode(); } + +protected: + WALK_TYPE m_type; // Type of instructions + REGDISPLAY *m_registers; // Registers + const BYTE *m_ip; // Current IP + const BYTE *m_skipIP; // IP if we skip the instruction + const BYTE *m_nextIP; // IP if the instruction is taken + bool m_isAbsoluteBranch; // Is it an obsolute branch or not +}; + +#ifdef _TARGET_X86_ + +class NativeWalker : public Walker +{ +public: + void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + m_opcode = 0; + Walker::Init(ip, pregisters); + } + + DWORD GetOpcode() + { return m_opcode; } +/* + void SetRegDisplay(REGDISPLAY *registers) + { m_registers = registers; } +*/ + REGDISPLAY *GetRegDisplay() + { return m_registers; } + + void Decode(); + void DecodeModRM(BYTE mod, BYTE reg, BYTE rm, const BYTE *ip); + static void DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib); + +private: + DWORD GetRegisterValue(int registerNumber); + + DWORD m_opcode; // Current instruction or opcode +}; + +#elif defined (_TARGET_ARM_) + +class NativeWalker : public Walker +{ +public: + void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + Walker::Init(ip, pregisters); + } + + void Decode(); + +private: + bool ConditionHolds(DWORD cond); + DWORD GetReg(DWORD reg); +}; + +#elif defined(_TARGET_AMD64_) + +class NativeWalker : public Walker +{ +public: + void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + m_opcode = 0; + Walker::Init(ip, pregisters); + } + + DWORD GetOpcode() + { return m_opcode; } +/* + void SetRegDisplay(REGDISPLAY *registers) + { m_registers = registers; } +*/ + REGDISPLAY *GetRegDisplay() + { return m_registers; } + + void Decode(); + void DecodeModRM(BYTE mod, BYTE reg, BYTE rm, const BYTE *ip); + static void DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib); + +private: + UINT64 GetRegisterValue(int registerNumber); + + DWORD m_opcode; // Current instruction or opcode +}; +#elif defined (_TARGET_ARM64_) +#include "controller.h" +class NativeWalker : public Walker +{ +public: + void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + Walker::Init(ip, pregisters); + } + void Decode(); + static void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib) + { + pInstrAttrib->Reset(); + } + static BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context,const PRD_TYPE& opcode, PCODE& offset, WALK_TYPE& walk); + static BOOL NativeWalker::DecodeCallInst(const PRD_TYPE& opcode, int& RegNum, WALK_TYPE& walk); + static BYTE* SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, SharedPatchBypassBuffer * m_pSharedPatchBypassBuffer, const BYTE *address, PRD_TYPE opcode); + +}; +#else +PORTABILITY_WARNING("NativeWalker not implemented on this platform"); +class NativeWalker : public Walker +{ +public: + void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + m_opcode = 0; + Walker::Init(ip, pregisters); + } + DWORD GetOpcode() + { return m_opcode; } + void Next() + { Walker::Next(); } + void Skip() + { Walker::Skip(); } + + void Decode() + { + PORTABILITY_ASSERT("NativeWalker not implemented on this platform"); + m_type = WALK_UNKNOWN; + m_skipIP = m_ip++; + m_nextIP = m_ip++; + } + + static void DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib) + { + PORTABILITY_ASSERT("NativeWalker not implemented on this platform"); + + } + +private: + DWORD m_opcode; // Current instruction or opcode +}; +#endif + +#endif // WALKER_H_ |