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 | #ifndef __DBG_TARGET_CONTEXT_INCLUDED |
6 | #define __DBG_TARGET_CONTEXT_INCLUDED |
7 | |
8 | #include <dbgportable.h> |
9 | #include <stddef.h> |
10 | #include "crosscomp.h" |
11 | |
12 | // |
13 | // The right side of the debugger can be built to target multiple platforms. This means it is not |
14 | // safe to use the CONTEXT structure directly: the context of the platform we're building for might not match |
15 | // that of the one the debugger is targetting. So all right side code will use the DT_CONTEXT abstraction |
16 | // instead. When the debugger target is the local platform this will just resolve back into CONTEXT, but cross |
17 | // platform we'll provide a hand-rolled version. |
18 | // |
19 | |
20 | // |
21 | // For cross platform cases we also need to provide a helper function for byte-swapping a context structure |
22 | // should the endian-ness of the debugger and debuggee platforms differ. This is called ByteSwapContext and is |
23 | // obviously a no-op for those cases where the left and right sides agree on storage format. |
24 | // |
25 | // NOTE: Any changes to the field layout of DT_CONTEXT must be tracked in the associated definition of |
26 | // ByteSwapContext. |
27 | // |
28 | |
29 | // |
30 | // **** NOTE: Keep these in sync with pal/inc/pal.h **** |
31 | // |
32 | |
33 | // This odd define pattern is needed because in DBI we set _TARGET_ to match the host and |
34 | // DBG_TARGET to control our targeting. In x-plat DBI DBG_TARGET won't match _TARGET_ and |
35 | // DBG_TARGET needs to take precedence |
36 | #if defined(DBG_TARGET_X86) |
37 | #define DTCONTEXT_IS_X86 |
38 | #elif defined (DBG_TARGET_AMD64) |
39 | #define DTCONTEXT_IS_AMD64 |
40 | #elif defined (DBG_TARGET_ARM) |
41 | #define DTCONTEXT_IS_ARM |
42 | #elif defined (DBG_TARGET_ARM64) |
43 | #define DTCONTEXT_IS_ARM64 |
44 | #elif defined (_TARGET_X86_) |
45 | #define DTCONTEXT_IS_X86 |
46 | #elif defined (_TARGET_AMD64_) |
47 | #define DTCONTEXT_IS_AMD64 |
48 | #elif defined (_TARGET_ARM_) |
49 | #define DTCONTEXT_IS_ARM |
50 | #elif defined (_TARGET_ARM64_) |
51 | #define DTCONTEXT_IS_ARM64 |
52 | #endif |
53 | |
54 | #if defined(DTCONTEXT_IS_X86) |
55 | |
56 | #define DT_SIZE_OF_80387_REGISTERS 80 |
57 | |
58 | #define DT_CONTEXT_i386 0x00010000 |
59 | #define DT_CONTEXT_CONTROL (DT_CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP |
60 | #define DT_CONTEXT_INTEGER (DT_CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI |
61 | #define DT_CONTEXT_SEGMENTS (DT_CONTEXT_i386 | 0x00000004L) |
62 | #define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_i386 | 0x00000008L) // 387 state |
63 | #define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_i386 | 0x00000010L) |
64 | |
65 | #define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_SEGMENTS) |
66 | #define DT_CONTEXT_EXTENDED_REGISTERS (DT_CONTEXT_i386 | 0x00000020L) |
67 | |
68 | #define DT_MAXIMUM_SUPPORTED_EXTENSION 512 |
69 | |
70 | typedef struct { |
71 | DWORD ControlWord; |
72 | DWORD StatusWord; |
73 | DWORD TagWord; |
74 | DWORD ErrorOffset; |
75 | DWORD ErrorSelector; |
76 | DWORD DataOffset; |
77 | DWORD DataSelector; |
78 | BYTE RegisterArea[DT_SIZE_OF_80387_REGISTERS]; |
79 | DWORD Cr0NpxState; |
80 | } DT_FLOATING_SAVE_AREA; |
81 | |
82 | typedef struct { |
83 | ULONG ContextFlags; |
84 | |
85 | ULONG Dr0; |
86 | ULONG Dr1; |
87 | ULONG Dr2; |
88 | ULONG Dr3; |
89 | ULONG Dr6; |
90 | ULONG Dr7; |
91 | |
92 | DT_FLOATING_SAVE_AREA FloatSave; |
93 | |
94 | ULONG SegGs; |
95 | ULONG SegFs; |
96 | ULONG SegEs; |
97 | ULONG SegDs; |
98 | |
99 | ULONG Edi; |
100 | ULONG Esi; |
101 | ULONG Ebx; |
102 | ULONG Edx; |
103 | ULONG Ecx; |
104 | ULONG Eax; |
105 | |
106 | ULONG Ebp; |
107 | ULONG Eip; |
108 | ULONG SegCs; |
109 | ULONG EFlags; |
110 | ULONG Esp; |
111 | ULONG SegSs; |
112 | |
113 | UCHAR ExtendedRegisters[DT_MAXIMUM_SUPPORTED_EXTENSION]; |
114 | |
115 | } DT_CONTEXT; |
116 | |
117 | // Since the target is little endian in this case we only have to provide a real implementation of |
118 | // ByteSwapContext if the platform we're building on is big-endian. |
119 | #ifdef BIGENDIAN |
120 | inline void ByteSwapContext(DT_CONTEXT *pContext) |
121 | { |
122 | // Our job is simplified since the context has large contiguous ranges with fields of the same size. Keep |
123 | // the following logic in sync with the definition of DT_CONTEXT above. |
124 | BYTE *pbContext = (BYTE*)pContext; |
125 | |
126 | // The first span consists of 4 byte fields. |
127 | DWORD cbFields = (offsetof(DT_CONTEXT, FloatSave) + offsetof(DT_FLOATING_SAVE_AREA, RegisterArea)) / 4; |
128 | for (DWORD i = 0; i < cbFields; i++) |
129 | { |
130 | ByteSwapPrimitive(pbContext, pbContext, 4); |
131 | pbContext += 4; |
132 | } |
133 | |
134 | // Then there's a float save area containing 8 byte fields. |
135 | cbFields = sizeof(pContext->FloatSave.RegisterArea); |
136 | for (DWORD i = 0; i < cbFields; i++) |
137 | { |
138 | ByteSwapPrimitive(pbContext, pbContext, 8); |
139 | pbContext += 8; |
140 | } |
141 | |
142 | // Back to 4 byte fields. |
143 | cbFields = (offsetof(DT_CONTEXT, ExtendedRegisters) - offsetof(DT_CONTEXT, SegGs)) / 4; |
144 | for (DWORD i = 0; i < cbFields; i++) |
145 | { |
146 | ByteSwapPrimitive(pbContext, pbContext, 4); |
147 | pbContext += 4; |
148 | } |
149 | |
150 | // We don't know the formatting of the extended register area, but the debugger doesn't access this data |
151 | // on the left side, so just leave it in left-side format for now. |
152 | |
153 | // Validate that we converted up to where we think we did as a hedge against DT_CONTEXT layout changes. |
154 | _PASSERT((pbContext - ((BYTE*)pContext)) == (sizeof(DT_CONTEXT) - sizeof(pContext->ExtendedRegisters))); |
155 | } |
156 | #else // BIGENDIAN |
157 | inline void ByteSwapContext(DT_CONTEXT *pContext) |
158 | { |
159 | } |
160 | #endif // BIGENDIAN |
161 | |
162 | #elif defined(DTCONTEXT_IS_AMD64) |
163 | |
164 | #define DT_CONTEXT_AMD64 0x00100000L |
165 | |
166 | #define DT_CONTEXT_CONTROL (DT_CONTEXT_AMD64 | 0x00000001L) |
167 | #define DT_CONTEXT_INTEGER (DT_CONTEXT_AMD64 | 0x00000002L) |
168 | #define DT_CONTEXT_SEGMENTS (DT_CONTEXT_AMD64 | 0x00000004L) |
169 | #define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_AMD64 | 0x00000008L) |
170 | #define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_AMD64 | 0x00000010L) |
171 | |
172 | #define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT) |
173 | #define DT_CONTEXT_ALL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_SEGMENTS | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_DEBUG_REGISTERS) |
174 | |
175 | typedef struct { |
176 | ULONGLONG Low; |
177 | LONGLONG High; |
178 | } DT_M128A; |
179 | |
180 | typedef struct { |
181 | WORD ControlWord; |
182 | WORD StatusWord; |
183 | BYTE TagWord; |
184 | BYTE Reserved1; |
185 | WORD ErrorOpcode; |
186 | DWORD ErrorOffset; |
187 | WORD ErrorSelector; |
188 | WORD Reserved2; |
189 | DWORD DataOffset; |
190 | WORD DataSelector; |
191 | WORD Reserved3; |
192 | DWORD MxCsr; |
193 | DWORD MxCsr_Mask; |
194 | DT_M128A FloatRegisters[8]; |
195 | DT_M128A XmmRegisters[16]; |
196 | BYTE Reserved4[96]; |
197 | } DT_XMM_SAVE_AREA32; |
198 | |
199 | typedef struct DECLSPEC_ALIGN(16) { |
200 | |
201 | DWORD64 P1Home; |
202 | DWORD64 P2Home; |
203 | DWORD64 P3Home; |
204 | DWORD64 P4Home; |
205 | DWORD64 P5Home; |
206 | DWORD64 P6Home; |
207 | |
208 | DWORD ContextFlags; |
209 | DWORD MxCsr; |
210 | |
211 | WORD SegCs; |
212 | WORD SegDs; |
213 | WORD SegEs; |
214 | WORD SegFs; |
215 | WORD SegGs; |
216 | WORD SegSs; |
217 | DWORD EFlags; |
218 | |
219 | DWORD64 Dr0; |
220 | DWORD64 Dr1; |
221 | DWORD64 Dr2; |
222 | DWORD64 Dr3; |
223 | DWORD64 Dr6; |
224 | DWORD64 Dr7; |
225 | |
226 | DWORD64 Rax; |
227 | DWORD64 Rcx; |
228 | DWORD64 Rdx; |
229 | DWORD64 Rbx; |
230 | DWORD64 Rsp; |
231 | DWORD64 Rbp; |
232 | DWORD64 Rsi; |
233 | DWORD64 Rdi; |
234 | DWORD64 R8; |
235 | DWORD64 R9; |
236 | DWORD64 R10; |
237 | DWORD64 R11; |
238 | DWORD64 R12; |
239 | DWORD64 R13; |
240 | DWORD64 R14; |
241 | DWORD64 R15; |
242 | |
243 | DWORD64 Rip; |
244 | |
245 | union { |
246 | DT_XMM_SAVE_AREA32 FltSave; |
247 | struct { |
248 | DT_M128A [2]; |
249 | DT_M128A Legacy[8]; |
250 | DT_M128A Xmm0; |
251 | DT_M128A Xmm1; |
252 | DT_M128A Xmm2; |
253 | DT_M128A Xmm3; |
254 | DT_M128A Xmm4; |
255 | DT_M128A Xmm5; |
256 | DT_M128A Xmm6; |
257 | DT_M128A Xmm7; |
258 | DT_M128A Xmm8; |
259 | DT_M128A Xmm9; |
260 | DT_M128A Xmm10; |
261 | DT_M128A Xmm11; |
262 | DT_M128A Xmm12; |
263 | DT_M128A Xmm13; |
264 | DT_M128A Xmm14; |
265 | DT_M128A Xmm15; |
266 | }; |
267 | }; |
268 | |
269 | DT_M128A VectorRegister[26]; |
270 | DWORD64 VectorControl; |
271 | |
272 | DWORD64 DebugControl; |
273 | DWORD64 LastBranchToRip; |
274 | DWORD64 LastBranchFromRip; |
275 | DWORD64 LastExceptionToRip; |
276 | DWORD64 LastExceptionFromRip; |
277 | } DT_CONTEXT; |
278 | |
279 | #elif defined(DTCONTEXT_IS_ARM) |
280 | |
281 | #define DT_CONTEXT_ARM 0x00200000L |
282 | |
283 | #define DT_CONTEXT_CONTROL (DT_CONTEXT_ARM | 0x1L) |
284 | #define DT_CONTEXT_INTEGER (DT_CONTEXT_ARM | 0x2L) |
285 | #define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_ARM | 0x4L) |
286 | #define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_ARM | 0x8L) |
287 | |
288 | #define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT) |
289 | #define DT_CONTEXT_ALL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_DEBUG_REGISTERS) |
290 | |
291 | #define DT_ARM_MAX_BREAKPOINTS 8 |
292 | #define DT_ARM_MAX_WATCHPOINTS 1 |
293 | |
294 | typedef struct { |
295 | ULONGLONG Low; |
296 | LONGLONG High; |
297 | } DT_NEON128; |
298 | |
299 | typedef DECLSPEC_ALIGN(8) struct { |
300 | |
301 | // |
302 | // Control flags. |
303 | // |
304 | |
305 | DWORD ContextFlags; |
306 | |
307 | // |
308 | // Integer registers |
309 | // |
310 | |
311 | DWORD R0; |
312 | DWORD R1; |
313 | DWORD R2; |
314 | DWORD R3; |
315 | DWORD R4; |
316 | DWORD R5; |
317 | DWORD R6; |
318 | DWORD R7; |
319 | DWORD R8; |
320 | DWORD R9; |
321 | DWORD R10; |
322 | DWORD R11; |
323 | DWORD R12; |
324 | |
325 | // |
326 | // Control Registers |
327 | // |
328 | |
329 | DWORD Sp; |
330 | DWORD Lr; |
331 | DWORD Pc; |
332 | DWORD Cpsr; |
333 | |
334 | // |
335 | // Floating Point/NEON Registers |
336 | // |
337 | |
338 | DWORD Fpscr; |
339 | DWORD Padding; |
340 | union { |
341 | DT_NEON128 Q[16]; |
342 | ULONGLONG D[32]; |
343 | DWORD S[32]; |
344 | }; |
345 | |
346 | // |
347 | // Debug registers |
348 | // |
349 | |
350 | DWORD Bvr[DT_ARM_MAX_BREAKPOINTS]; |
351 | DWORD Bcr[DT_ARM_MAX_BREAKPOINTS]; |
352 | DWORD Wvr[DT_ARM_MAX_WATCHPOINTS]; |
353 | DWORD Wcr[DT_ARM_MAX_WATCHPOINTS]; |
354 | |
355 | DWORD Padding2[2]; |
356 | |
357 | } DT_CONTEXT; |
358 | |
359 | #elif defined(DTCONTEXT_IS_ARM64) |
360 | |
361 | #define DT_CONTEXT_ARM64 0x00400000L |
362 | |
363 | #define DT_CONTEXT_CONTROL (DT_CONTEXT_ARM64 | 0x1L) |
364 | #define DT_CONTEXT_INTEGER (DT_CONTEXT_ARM64 | 0x2L) |
365 | #define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_ARM64 | 0x4L) |
366 | #define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_ARM64 | 0x8L) |
367 | |
368 | #define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT) |
369 | #define DT_CONTEXT_ALL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_DEBUG_REGISTERS) |
370 | |
371 | #define DT_ARM64_MAX_BREAKPOINTS 8 |
372 | #define DT_ARM64_MAX_WATCHPOINTS 2 |
373 | |
374 | typedef struct { |
375 | ULONGLONG Low; |
376 | LONGLONG High; |
377 | } DT_NEON128; |
378 | |
379 | typedef DECLSPEC_ALIGN(16) struct { |
380 | // |
381 | // Control flags. |
382 | // |
383 | |
384 | /* +0x000 */ DWORD ContextFlags; |
385 | |
386 | // |
387 | // Integer registers |
388 | // |
389 | |
390 | /* +0x004 */ DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel |
391 | /* +0x008 */ union { |
392 | struct { |
393 | DWORD64 X0; |
394 | DWORD64 X1; |
395 | DWORD64 X2; |
396 | DWORD64 X3; |
397 | DWORD64 X4; |
398 | DWORD64 X5; |
399 | DWORD64 X6; |
400 | DWORD64 X7; |
401 | DWORD64 X8; |
402 | DWORD64 X9; |
403 | DWORD64 X10; |
404 | DWORD64 X11; |
405 | DWORD64 X12; |
406 | DWORD64 X13; |
407 | DWORD64 X14; |
408 | DWORD64 X15; |
409 | DWORD64 X16; |
410 | DWORD64 X17; |
411 | DWORD64 X18; |
412 | DWORD64 X19; |
413 | DWORD64 X20; |
414 | DWORD64 X21; |
415 | DWORD64 X22; |
416 | DWORD64 X23; |
417 | DWORD64 X24; |
418 | DWORD64 X25; |
419 | DWORD64 X26; |
420 | DWORD64 X27; |
421 | DWORD64 X28; |
422 | }; |
423 | DWORD64 X[29]; |
424 | }; |
425 | /* +0x0f0 */ DWORD64 Fp; |
426 | /* +0x0f8 */ DWORD64 Lr; |
427 | /* +0x100 */ DWORD64 Sp; |
428 | /* +0x108 */ DWORD64 Pc; |
429 | |
430 | // |
431 | // Floating Point/NEON Registers |
432 | // |
433 | |
434 | /* +0x110 */ DT_NEON128 V[32]; |
435 | /* +0x310 */ DWORD Fpcr; |
436 | /* +0x314 */ DWORD Fpsr; |
437 | |
438 | // |
439 | // Debug registers |
440 | // |
441 | |
442 | /* +0x318 */ DWORD Bcr[DT_ARM64_MAX_BREAKPOINTS]; |
443 | /* +0x338 */ DWORD64 Bvr[DT_ARM64_MAX_BREAKPOINTS]; |
444 | /* +0x378 */ DWORD Wcr[DT_ARM64_MAX_WATCHPOINTS]; |
445 | /* +0x380 */ DWORD64 Wvr[DT_ARM64_MAX_WATCHPOINTS]; |
446 | /* +0x390 */ |
447 | |
448 | } DT_CONTEXT; |
449 | |
450 | #else |
451 | #error Unsupported platform |
452 | #endif |
453 | |
454 | |
455 | #endif // __DBG_TARGET_CONTEXT_INCLUDED |
456 | |