1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// File: walker.h
6//
7
8//
9// Debugger code stream analysis routines
10//
11//*****************************************************************************
12
13#ifndef WALKER_H_
14#define WALKER_H_
15
16
17/* ========================================================================= */
18
19/* ------------------------------------------------------------------------- *
20 * Constants
21 * ------------------------------------------------------------------------- */
22
23enum WALK_TYPE
24{
25 WALK_NEXT,
26 WALK_BRANCH,
27 WALK_COND_BRANCH,
28 WALK_CALL,
29 WALK_RETURN,
30 WALK_BREAK,
31 WALK_THROW,
32 WALK_META,
33 WALK_UNKNOWN
34};
35
36// struct holding information for the instruction being skipped over
37struct InstructionAttribute
38{
39 bool m_fIsCall; // is this a call instruction?
40 bool m_fIsCond; // is this a conditional jump?
41 bool m_fIsAbsBranch; // is this an absolute branch (either a call or a jump)?
42 bool m_fIsRelBranch; // is this a relative branch (either a call or a jump)?
43 bool m_fIsWrite; // does the instruction write to an address?
44
45
46 DWORD m_cbInstr; // the size of the instruction
47 DWORD m_cbDisp; // the size of the displacement
48 DWORD m_dwOffsetToDisp; // the offset from the beginning of the instruction
49 // to the beginning of the displacement
50 BYTE m_cOperandSize; // the size of the operand
51
52 void Reset()
53 {
54 m_fIsCall = false;
55 m_fIsCond = false;
56 m_fIsAbsBranch = false;
57 m_fIsRelBranch = false;
58 m_fIsWrite = false;
59 m_cbInstr = 0;
60 m_cbDisp = 0;
61 m_dwOffsetToDisp = 0;
62 m_cOperandSize = 0;
63 }
64};
65
66/* ------------------------------------------------------------------------- *
67 * Classes
68 * ------------------------------------------------------------------------- */
69
70class Walker
71{
72protected:
73 Walker()
74 : m_type(WALK_UNKNOWN), m_registers(NULL), m_ip(0), m_skipIP(0), m_nextIP(0), m_isAbsoluteBranch(false)
75 {LIMITED_METHOD_CONTRACT; }
76
77public:
78
79 virtual void Init(const BYTE *ip, REGDISPLAY *pregisters)
80 {
81 PREFIX_ASSUME(pregisters != NULL);
82 _ASSERTE(GetControlPC(pregisters) == (PCODE)ip);
83
84 m_registers = pregisters;
85 SetIP(ip);
86 }
87
88 const BYTE *GetIP()
89 { return m_ip; }
90
91 WALK_TYPE GetOpcodeWalkType()
92 { return m_type; }
93
94 const BYTE *GetSkipIP()
95 { return m_skipIP; }
96
97 bool IsAbsoluteBranch()
98 { return m_isAbsoluteBranch; }
99
100 const BYTE *GetNextIP()
101 { return m_nextIP; }
102
103 // We don't currently keep the registers up to date
104 // <TODO> Check if it really works on IA64. </TODO>
105 virtual void Next() { m_registers = NULL; SetIP(m_nextIP); }
106 virtual void Skip() { m_registers = NULL; LOG((LF_CORDB, LL_INFO10000, "skipping over to %p \n", m_skipIP)); SetIP(m_skipIP); }
107
108 // Decode the instruction
109 virtual void Decode() = 0;
110
111private:
112 void SetIP(const BYTE *ip)
113 { m_ip = ip; Decode(); }
114
115protected:
116 WALK_TYPE m_type; // Type of instructions
117 REGDISPLAY *m_registers; // Registers
118 const BYTE *m_ip; // Current IP
119 const BYTE *m_skipIP; // IP if we skip the instruction
120 const BYTE *m_nextIP; // IP if the instruction is taken
121 bool m_isAbsoluteBranch; // Is it an obsolute branch or not
122};
123
124#ifdef _TARGET_X86_
125
126class NativeWalker : public Walker
127{
128public:
129 void Init(const BYTE *ip, REGDISPLAY *pregisters)
130 {
131 m_opcode = 0;
132 Walker::Init(ip, pregisters);
133 }
134
135 DWORD GetOpcode()
136 { return m_opcode; }
137/*
138 void SetRegDisplay(REGDISPLAY *registers)
139 { m_registers = registers; }
140*/
141 REGDISPLAY *GetRegDisplay()
142 { return m_registers; }
143
144 void Decode();
145 void DecodeModRM(BYTE mod, BYTE reg, BYTE rm, const BYTE *ip);
146 static void DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib);
147
148private:
149 DWORD GetRegisterValue(int registerNumber);
150
151 DWORD m_opcode; // Current instruction or opcode
152};
153
154#elif defined (_TARGET_ARM_)
155
156class NativeWalker : public Walker
157{
158public:
159 void Init(const BYTE *ip, REGDISPLAY *pregisters)
160 {
161 Walker::Init(ip, pregisters);
162 }
163
164 void Decode();
165
166private:
167 bool ConditionHolds(DWORD cond);
168 DWORD GetReg(DWORD reg);
169};
170
171#elif defined(_TARGET_AMD64_)
172
173class NativeWalker : public Walker
174{
175public:
176 void Init(const BYTE *ip, REGDISPLAY *pregisters)
177 {
178 m_opcode = 0;
179 Walker::Init(ip, pregisters);
180 }
181
182 DWORD GetOpcode()
183 { return m_opcode; }
184/*
185 void SetRegDisplay(REGDISPLAY *registers)
186 { m_registers = registers; }
187*/
188 REGDISPLAY *GetRegDisplay()
189 { return m_registers; }
190
191 void Decode();
192 void DecodeModRM(BYTE mod, BYTE reg, BYTE rm, const BYTE *ip);
193 static void DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib);
194
195private:
196 UINT64 GetRegisterValue(int registerNumber);
197
198 DWORD m_opcode; // Current instruction or opcode
199};
200#elif defined (_TARGET_ARM64_)
201#include "controller.h"
202class NativeWalker : public Walker
203{
204public:
205 void Init(const BYTE *ip, REGDISPLAY *pregisters)
206 {
207 Walker::Init(ip, pregisters);
208 }
209 void Decode();
210 static void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib)
211 {
212 pInstrAttrib->Reset();
213 }
214 static BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context,const PRD_TYPE& opcode, PCODE& offset, WALK_TYPE& walk);
215 static BOOL NativeWalker::DecodeCallInst(const PRD_TYPE& opcode, int& RegNum, WALK_TYPE& walk);
216 static BYTE* SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, SharedPatchBypassBuffer * m_pSharedPatchBypassBuffer, const BYTE *address, PRD_TYPE opcode);
217
218};
219#else
220PORTABILITY_WARNING("NativeWalker not implemented on this platform");
221class NativeWalker : public Walker
222{
223public:
224 void Init(const BYTE *ip, REGDISPLAY *pregisters)
225 {
226 m_opcode = 0;
227 Walker::Init(ip, pregisters);
228 }
229 DWORD GetOpcode()
230 { return m_opcode; }
231 void Next()
232 { Walker::Next(); }
233 void Skip()
234 { Walker::Skip(); }
235
236 void Decode()
237 {
238 PORTABILITY_ASSERT("NativeWalker not implemented on this platform");
239 m_type = WALK_UNKNOWN;
240 m_skipIP = m_ip++;
241 m_nextIP = m_ip++;
242 }
243
244 static void DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib)
245 {
246 PORTABILITY_ASSERT("NativeWalker not implemented on this platform");
247
248 }
249
250private:
251 DWORD m_opcode; // Current instruction or opcode
252};
253#endif
254
255#endif // WALKER_H_
256