winegstreamer: Set the default H264 caps profile to "baseline".
[wine.git] / programs / winedbg / be_x86_64.c
blobd3cdafb335680423b3fb3079e50a6bfcfd32281a
1 /*
2 * Debugger x86_64 specific functions
4 * Copyright 2004 Vincent BĂ©ron
5 * Copyright 2009 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
25 #include "debugger.h"
26 #include "wine/debug.h"
28 #if defined(__x86_64__)
30 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
32 #define STEP_FLAG 0x00000100 /* single step flag */
34 static BOOL be_x86_64_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
35 enum be_cpu_addr bca, ADDRESS64* addr)
37 addr->Mode = AddrModeFlat;
38 switch (bca)
40 case be_cpu_addr_pc:
41 addr->Segment = ctx->ctx.SegCs;
42 addr->Offset = ctx->ctx.Rip;
43 return TRUE;
44 case be_cpu_addr_stack:
45 addr->Segment = ctx->ctx.SegSs;
46 addr->Offset = ctx->ctx.Rsp;
47 return TRUE;
48 case be_cpu_addr_frame:
49 addr->Segment = ctx->ctx.SegSs;
50 addr->Offset = ctx->ctx.Rbp;
51 return TRUE;
52 default:
53 addr->Mode = -1;
54 return FALSE;
58 static BOOL be_x86_64_get_register_info(int regno, enum be_cpu_addr* kind)
60 /* this is true when running in 32bit mode... and wrong in 64 :-/ */
61 switch (regno)
63 case CV_AMD64_RIP: *kind = be_cpu_addr_pc; return TRUE;
64 case CV_AMD64_EBP: *kind = be_cpu_addr_frame; return TRUE;
65 case CV_AMD64_ESP: *kind = be_cpu_addr_stack; return TRUE;
67 return FALSE;
70 static void be_x86_64_single_step(dbg_ctx_t *ctx, BOOL enable)
72 if (enable) ctx->ctx.EFlags |= STEP_FLAG;
73 else ctx->ctx.EFlags &= ~STEP_FLAG;
76 static void be_x86_64_print_context(HANDLE hThread, const dbg_ctx_t *pctx,
77 int all_regs)
79 static const char mxcsr_flags[16][4] = { "IE", "DE", "ZE", "OE", "UE", "PE", "DAZ", "IM",
80 "DM", "ZM", "OM", "UM", "PM", "R-", "R+", "FZ" };
81 static const char flags[] = "aVR-N--ODITSZ-A-P-C";
82 const CONTEXT *ctx = &pctx->ctx;
83 char buf[33];
84 int i;
86 strcpy(buf, flags);
87 for (i = 0; buf[i]; i++)
88 if (buf[i] != '-' && !(ctx->EFlags & (1 << (sizeof(flags) - 2 - i))))
89 buf[i] = ' ';
91 dbg_printf("Register dump:\n");
92 dbg_printf(" rip:%016I64x rsp:%016I64x rbp:%016I64x eflags:%08lx (%s)\n",
93 ctx->Rip, ctx->Rsp, ctx->Rbp, ctx->EFlags, buf);
94 dbg_printf(" rax:%016I64x rbx:%016I64x rcx:%016I64x rdx:%016I64x\n",
95 ctx->Rax, ctx->Rbx, ctx->Rcx, ctx->Rdx);
96 dbg_printf(" rsi:%016I64x rdi:%016I64x r8:%016I64x r9:%016I64x r10:%016I64x\n",
97 ctx->Rsi, ctx->Rdi, ctx->R8, ctx->R9, ctx->R10 );
98 dbg_printf(" r11:%016I64x r12:%016I64x r13:%016I64x r14:%016I64x r15:%016I64x\n",
99 ctx->R11, ctx->R12, ctx->R13, ctx->R14, ctx->R15 );
101 if (!all_regs) return;
103 dbg_printf(" cs:%04x ds:%04x es:%04x fs:%04x gs:%04x ss:%04x\n",
104 ctx->SegCs, ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs, ctx->SegSs );
106 dbg_printf("Debug:\n");
107 dbg_printf(" dr0:%016I64x dr1:%016I64x dr2:%016I64x dr3:%016I64x\n",
108 ctx->Dr0, ctx->Dr1, ctx->Dr2, ctx->Dr3 );
109 dbg_printf(" dr6:%016I64x dr7:%016I64x\n", ctx->Dr6, ctx->Dr7 );
111 dbg_printf("Floating point:\n");
112 dbg_printf(" flcw:%04x ", LOWORD(ctx->u.FltSave.ControlWord));
113 dbg_printf(" fltw:%04x ", LOWORD(ctx->u.FltSave.TagWord));
114 dbg_printf(" flsw:%04x", LOWORD(ctx->u.FltSave.StatusWord));
116 dbg_printf("(cc:%d%d%d%d", (ctx->u.FltSave.StatusWord & 0x00004000) >> 14,
117 (ctx->u.FltSave.StatusWord & 0x00000400) >> 10,
118 (ctx->u.FltSave.StatusWord & 0x00000200) >> 9,
119 (ctx->u.FltSave.StatusWord & 0x00000100) >> 8);
121 dbg_printf(" top:%01x", (unsigned int) (ctx->u.FltSave.StatusWord & 0x00003800) >> 11);
123 if (ctx->u.FltSave.StatusWord & 0x00000001) /* Invalid Fl OP */
125 if (ctx->u.FltSave.StatusWord & 0x00000040) /* Stack Fault */
127 if (ctx->u.FltSave.StatusWord & 0x00000200) /* C1 says Overflow */
128 dbg_printf(" #IE(Stack Overflow)");
129 else
130 dbg_printf(" #IE(Stack Underflow)"); /* Underflow */
132 else dbg_printf(" #IE(Arithmetic error)"); /* Invalid Fl OP */
134 if (ctx->u.FltSave.StatusWord & 0x00000002) dbg_printf(" #DE"); /* Denormalised OP */
135 if (ctx->u.FltSave.StatusWord & 0x00000004) dbg_printf(" #ZE"); /* Zero Divide */
136 if (ctx->u.FltSave.StatusWord & 0x00000008) dbg_printf(" #OE"); /* Overflow */
137 if (ctx->u.FltSave.StatusWord & 0x00000010) dbg_printf(" #UE"); /* Underflow */
138 if (ctx->u.FltSave.StatusWord & 0x00000020) dbg_printf(" #PE"); /* Precision error */
139 if (ctx->u.FltSave.StatusWord & 0x00000040)
140 if (!(ctx->u.FltSave.StatusWord & 0x00000001))
141 dbg_printf(" #SE"); /* Stack Fault (don't think this can occur) */
142 if (ctx->u.FltSave.StatusWord & 0x00000080) dbg_printf(" #ES"); /* Error Summary */
143 if (ctx->u.FltSave.StatusWord & 0x00008000) dbg_printf(" #FB"); /* FPU Busy */
144 dbg_printf(")\n");
145 dbg_printf(" flerr:%04x:%08lx fldata:%04x:%08lx\n",
146 ctx->u.FltSave.ErrorSelector, ctx->u.FltSave.ErrorOffset,
147 ctx->u.FltSave.DataSelector, ctx->u.FltSave.DataOffset );
149 for (i = 0; i < 8; i++)
151 M128A reg = ctx->u.FltSave.FloatRegisters[i];
152 if (i == 4) dbg_printf("\n");
153 dbg_printf(" ST%u:%016I64x%16I64x ", i, reg.High, reg.Low );
155 dbg_printf("\n");
157 dbg_printf(" mxcsr: %04lx (", ctx->u.FltSave.MxCsr );
158 for (i = 0; i < 16; i++)
159 if (ctx->u.FltSave.MxCsr & (1 << i)) dbg_printf( " %s", mxcsr_flags[i] );
160 dbg_printf(" )\n");
162 for (i = 0; i < 16; i++)
164 dbg_printf( " %sxmm%u: uint=%016I64x%016I64x", (i > 9) ? "" : " ", i,
165 ctx->u.FltSave.XmmRegisters[i].High, ctx->u.FltSave.XmmRegisters[i].Low );
166 dbg_printf( " double={%g; %g}", *(double *)&ctx->u.FltSave.XmmRegisters[i].Low,
167 *(double *)&ctx->u.FltSave.XmmRegisters[i].High );
168 dbg_printf( " float={%g; %g; %g; %g}\n",
169 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 0),
170 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 1),
171 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 2),
172 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 3) );
176 static void be_x86_64_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
180 static struct dbg_internal_var be_x86_64_ctx[] =
182 {CV_AMD64_AL, "AL", (void*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_int8},
183 {CV_AMD64_BL, "BL", (void*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_int8},
184 {CV_AMD64_CL, "CL", (void*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_int8},
185 {CV_AMD64_DL, "DL", (void*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_int8},
186 {CV_AMD64_AH, "AH", (void*)(FIELD_OFFSET(CONTEXT, Rax)+1), dbg_itype_unsigned_int8},
187 {CV_AMD64_BH, "BH", (void*)(FIELD_OFFSET(CONTEXT, Rbx)+1), dbg_itype_unsigned_int8},
188 {CV_AMD64_CH, "CH", (void*)(FIELD_OFFSET(CONTEXT, Rcx)+1), dbg_itype_unsigned_int8},
189 {CV_AMD64_DH, "DH", (void*)(FIELD_OFFSET(CONTEXT, Rdx)+1), dbg_itype_unsigned_int8},
190 {CV_AMD64_AX, "AX", (void*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_int16},
191 {CV_AMD64_BX, "BX", (void*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_int16},
192 {CV_AMD64_CX, "CX", (void*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_int16},
193 {CV_AMD64_DX, "DX", (void*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_int16},
194 {CV_AMD64_SP, "SP", (void*)FIELD_OFFSET(CONTEXT, Rsp), dbg_itype_unsigned_int16},
195 {CV_AMD64_BP, "BP", (void*)FIELD_OFFSET(CONTEXT, Rbp), dbg_itype_unsigned_int16},
196 {CV_AMD64_SI, "SI", (void*)FIELD_OFFSET(CONTEXT, Rsi), dbg_itype_unsigned_int16},
197 {CV_AMD64_DI, "DI", (void*)FIELD_OFFSET(CONTEXT, Rdi), dbg_itype_unsigned_int16},
198 {CV_AMD64_EAX, "EAX", (void*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_int32},
199 {CV_AMD64_EBX, "EBX", (void*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_int32},
200 {CV_AMD64_ECX, "ECX", (void*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_int32},
201 {CV_AMD64_EDX, "EDX", (void*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_int32},
202 {CV_AMD64_ESP, "ESP", (void*)FIELD_OFFSET(CONTEXT, Rsp), dbg_itype_unsigned_int32},
203 {CV_AMD64_EBP, "EBP", (void*)FIELD_OFFSET(CONTEXT, Rbp), dbg_itype_unsigned_int32},
204 {CV_AMD64_ESI, "ESI", (void*)FIELD_OFFSET(CONTEXT, Rsi), dbg_itype_unsigned_int32},
205 {CV_AMD64_EDI, "EDI", (void*)FIELD_OFFSET(CONTEXT, Rdi), dbg_itype_unsigned_int32},
206 {CV_AMD64_ES, "ES", (void*)FIELD_OFFSET(CONTEXT, SegEs), dbg_itype_unsigned_int16},
207 {CV_AMD64_CS, "CS", (void*)FIELD_OFFSET(CONTEXT, SegCs), dbg_itype_unsigned_int16},
208 {CV_AMD64_SS, "SS", (void*)FIELD_OFFSET(CONTEXT, SegSs), dbg_itype_unsigned_int16},
209 {CV_AMD64_DS, "DS", (void*)FIELD_OFFSET(CONTEXT, SegDs), dbg_itype_unsigned_int16},
210 {CV_AMD64_FS, "FS", (void*)FIELD_OFFSET(CONTEXT, SegFs), dbg_itype_unsigned_int16},
211 {CV_AMD64_GS, "GS", (void*)FIELD_OFFSET(CONTEXT, SegGs), dbg_itype_unsigned_int16},
212 {CV_AMD64_FLAGS, "FLAGS", (void*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_int16},
213 {CV_AMD64_EFLAGS, "EFLAGS", (void*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_int32},
214 {CV_AMD64_RIP, "RIP", (void*)FIELD_OFFSET(CONTEXT, Rip), dbg_itype_unsigned_int64},
215 {CV_AMD64_RAX, "RAX", (void*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_int64},
216 {CV_AMD64_RBX, "RBX", (void*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_int64},
217 {CV_AMD64_RCX, "RCX", (void*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_int64},
218 {CV_AMD64_RDX, "RDX", (void*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_int64},
219 {CV_AMD64_RSP, "RSP", (void*)FIELD_OFFSET(CONTEXT, Rsp), dbg_itype_unsigned_int64},
220 {CV_AMD64_RBP, "RBP", (void*)FIELD_OFFSET(CONTEXT, Rbp), dbg_itype_unsigned_int64},
221 {CV_AMD64_RSI, "RSI", (void*)FIELD_OFFSET(CONTEXT, Rsi), dbg_itype_unsigned_int64},
222 {CV_AMD64_RDI, "RDI", (void*)FIELD_OFFSET(CONTEXT, Rdi), dbg_itype_unsigned_int64},
223 {CV_AMD64_R8, "R8", (void*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_int64},
224 {CV_AMD64_R9, "R9", (void*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_int64},
225 {CV_AMD64_R10, "R10", (void*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_int64},
226 {CV_AMD64_R11, "R11", (void*)FIELD_OFFSET(CONTEXT, R11), dbg_itype_unsigned_int64},
227 {CV_AMD64_R12, "R12", (void*)FIELD_OFFSET(CONTEXT, R12), dbg_itype_unsigned_int64},
228 {CV_AMD64_R13, "R13", (void*)FIELD_OFFSET(CONTEXT, R13), dbg_itype_unsigned_int64},
229 {CV_AMD64_R14, "R14", (void*)FIELD_OFFSET(CONTEXT, R14), dbg_itype_unsigned_int64},
230 {CV_AMD64_R15, "R15", (void*)FIELD_OFFSET(CONTEXT, R15), dbg_itype_unsigned_int64},
231 {CV_AMD64_ST0, "ST0", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[0]), dbg_itype_long_real},
232 {CV_AMD64_ST0+1, "ST1", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[1]), dbg_itype_long_real},
233 {CV_AMD64_ST0+2, "ST2", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[2]), dbg_itype_long_real},
234 {CV_AMD64_ST0+3, "ST3", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[3]), dbg_itype_long_real},
235 {CV_AMD64_ST0+4, "ST4", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[4]), dbg_itype_long_real},
236 {CV_AMD64_ST0+5, "ST5", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[5]), dbg_itype_long_real},
237 {CV_AMD64_ST0+6, "ST6", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[6]), dbg_itype_long_real},
238 {CV_AMD64_ST0+7, "ST7", (void*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[7]), dbg_itype_long_real},
239 {CV_AMD64_XMM0, "XMM0", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm0), dbg_itype_m128a},
240 {CV_AMD64_XMM0+1, "XMM1", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm1), dbg_itype_m128a},
241 {CV_AMD64_XMM0+2, "XMM2", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm2), dbg_itype_m128a},
242 {CV_AMD64_XMM0+3, "XMM3", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm3), dbg_itype_m128a},
243 {CV_AMD64_XMM0+4, "XMM4", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm4), dbg_itype_m128a},
244 {CV_AMD64_XMM0+5, "XMM5", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm5), dbg_itype_m128a},
245 {CV_AMD64_XMM0+6, "XMM6", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm6), dbg_itype_m128a},
246 {CV_AMD64_XMM0+7, "XMM7", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm7), dbg_itype_m128a},
247 {CV_AMD64_XMM8, "XMM8", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm8), dbg_itype_m128a},
248 {CV_AMD64_XMM8+1, "XMM9", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm9), dbg_itype_m128a},
249 {CV_AMD64_XMM8+2, "XMM10", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm10), dbg_itype_m128a},
250 {CV_AMD64_XMM8+3, "XMM11", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm11), dbg_itype_m128a},
251 {CV_AMD64_XMM8+4, "XMM12", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm12), dbg_itype_m128a},
252 {CV_AMD64_XMM8+5, "XMM13", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm13), dbg_itype_m128a},
253 {CV_AMD64_XMM8+6, "XMM14", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm14), dbg_itype_m128a},
254 {CV_AMD64_XMM8+7, "XMM15", (void*)FIELD_OFFSET(CONTEXT, u.s.Xmm15), dbg_itype_m128a},
255 {0, NULL, 0, dbg_itype_none}
258 #define f_mod(b) ((b)>>6)
259 #define f_reg(b) (((b)>>3)&0x7)
260 #define f_rm(b) ((b)&0x7)
261 #define f_sib_b(b) ((b)&0x7)
262 #define f_sib_i(b) (((b)>>3)&0x7)
263 #define f_sib_s(b) ((b)>>6)
265 static BOOL be_x86_64_is_step_over_insn(const void* insn)
267 BYTE ch;
269 for (;;)
271 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
273 switch (ch)
275 /* Skip all prefixes */
276 case 0x2e: /* cs: */
277 case 0x36: /* ss: */
278 case 0x3e: /* ds: */
279 case 0x26: /* es: */
280 case 0x64: /* fs: */
281 case 0x65: /* gs: */
282 case 0x66: /* opcode size prefix */
283 case 0x67: /* addr size prefix */
284 case 0xf0: /* lock */
285 case 0xf2: /* repne */
286 case 0xf3: /* repe */
287 insn = (const char*)insn + 1;
288 continue;
290 /* Handle call instructions */
291 case 0xcd: /* int <intno> */
292 case 0xe8: /* call <offset> */
293 case 0x9a: /* lcall <seg>:<off> */
294 return TRUE;
296 case 0xff: /* call <regmodrm> */
297 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
298 return FALSE;
299 return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
301 /* Handle string instructions */
302 case 0x6c: /* insb */
303 case 0x6d: /* insw */
304 case 0x6e: /* outsb */
305 case 0x6f: /* outsw */
306 case 0xa4: /* movsb */
307 case 0xa5: /* movsw */
308 case 0xa6: /* cmpsb */
309 case 0xa7: /* cmpsw */
310 case 0xaa: /* stosb */
311 case 0xab: /* stosw */
312 case 0xac: /* lodsb */
313 case 0xad: /* lodsw */
314 case 0xae: /* scasb */
315 case 0xaf: /* scasw */
316 return TRUE;
318 default:
319 return FALSE;
324 static BOOL be_x86_64_is_function_return(const void* insn)
326 BYTE c;
328 /* sigh... amd64 for prefetch optimization requires 'rep ret' in some cases */
329 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
330 if (c == 0xF3) /* REP */
332 insn = (const char*)insn + 1;
333 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
335 return c == 0xC2 /* ret */ || c == 0xC3 /* ret NN */;
338 static BOOL be_x86_64_is_break_insn(const void* insn)
340 BYTE c;
341 return dbg_read_memory(insn, &c, sizeof(c)) && c == 0xCC;
344 static BOOL fetch_value(const char* addr, unsigned sz, LONG* value)
346 char value8;
347 short value16;
349 switch (sz)
351 case 1:
352 if (!dbg_read_memory(addr, &value8, sizeof(value8))) return FALSE;
353 *value = value8;
354 break;
355 case 2:
356 if (!dbg_read_memory(addr, &value16, sizeof(value16))) return FALSE;
357 *value = value16;
358 case 4:
359 if (!dbg_read_memory(addr, value, sizeof(*value))) return FALSE;
360 break;
361 default: return FALSE;
363 return TRUE;
366 static BOOL add_fixed_displacement(const void* insn, BYTE mod, DWORD64* addr)
368 LONG delta = 0;
370 if (mod == 1)
372 if (!fetch_value(insn, 1, &delta))
373 return FALSE;
375 else if (mod == 2)
377 if (!fetch_value(insn, sizeof(delta), &delta))
378 return FALSE;
380 *addr += delta;
381 return TRUE;
384 static BOOL evaluate_sib_address(const void* insn, BYTE mod, DWORD64* addr)
386 BYTE ch;
387 BYTE scale;
388 DWORD64 loc;
390 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
392 switch (f_sib_b(ch))
394 case 0x00: loc = dbg_context.ctx.Rax; break;
395 case 0x01: loc = dbg_context.ctx.Rcx; break;
396 case 0x02: loc = dbg_context.ctx.Rdx; break;
397 case 0x03: loc = dbg_context.ctx.Rbx; break;
398 case 0x04: loc = dbg_context.ctx.Rsp; break;
399 case 0x05:
400 loc = dbg_context.ctx.Rbp;
401 if (mod == 0)
403 loc = 0;
404 mod = 2;
406 break;
407 case 0x06: loc = dbg_context.ctx.Rsi; break;
408 case 0x07: loc = dbg_context.ctx.Rdi; break;
411 scale = f_sib_s(ch);
412 switch (f_sib_i(ch))
414 case 0x00: loc += dbg_context.ctx.Rax << scale; break;
415 case 0x01: loc += dbg_context.ctx.Rcx << scale; break;
416 case 0x02: loc += dbg_context.ctx.Rdx << scale; break;
417 case 0x03: loc += dbg_context.ctx.Rbx << scale; break;
418 case 0x04: break;
419 case 0x05: loc += dbg_context.ctx.Rbp << scale; break;
420 case 0x06: loc += dbg_context.ctx.Rsi << scale; break;
421 case 0x07: loc += dbg_context.ctx.Rdi << scale; break;
424 if (!add_fixed_displacement((const char*)insn + 1, mod, &loc))
425 return FALSE;
427 *addr = loc;
428 return TRUE;
431 static BOOL load_indirect_target(DWORD64* dst)
433 ADDRESS64 addr;
435 addr.Mode = AddrModeFlat;
436 addr.Segment = dbg_context.ctx.SegDs;
437 addr.Offset = *dst;
438 return dbg_read_memory(memory_to_linear_addr(&addr), &dst, sizeof(dst));
441 static BOOL be_x86_64_is_func_call(const void* insn, ADDRESS64* callee)
443 BYTE ch;
444 LONG delta;
445 unsigned op_size = 32, rex = 0;
446 DWORD64 dst;
448 /* we assume 64bit mode all over the place */
449 for (;;)
451 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
452 if (ch == 0x66) op_size = 16;
453 else if (ch == 0x67) WINE_FIXME("prefix not supported %x\n", ch);
454 else if (ch >= 0x40 && ch <= 0x4f) rex = ch & 0xf;
455 else break;
456 insn = (const char*)insn + 1;
457 } while (0);
459 /* that's the only mode we support anyway */
460 callee->Mode = AddrModeFlat;
461 callee->Segment = dbg_context.ctx.SegCs;
463 switch (ch)
465 case 0xe8: /* relative near call */
466 assert(op_size == 32);
467 if (!fetch_value((const char*)insn + 1, sizeof(delta), &delta))
468 return FALSE;
469 callee->Offset = (DWORD_PTR)insn + 1 + 4 + delta;
470 return TRUE;
472 case 0xff:
473 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
474 return FALSE;
475 WINE_TRACE("Got 0xFF %x (&C7=%x) with rex=%x\n", ch, ch & 0xC7, rex);
476 /* keep only the CALL and LCALL insn:s */
477 switch (f_reg(ch))
479 case 0x02:
480 break;
481 default: return FALSE;
483 if (rex == 0) switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
485 case 0x04:
486 case 0x44:
487 case 0x84:
489 evaluate_sib_address((const char*)insn + 2, f_mod(ch), &dst);
490 if (!load_indirect_target(&dst)) return FALSE;
491 callee->Offset = dst;
492 return TRUE;
494 case 0x05: /* addr32 */
495 if (f_reg(ch) == 0x2)
497 /* rip-relative to next insn */
498 if (!dbg_read_memory((const char*)insn + 2, &delta, sizeof(delta)) ||
499 !dbg_read_memory((const char*)insn + 6 + delta, &dst, sizeof(dst)))
500 return FALSE;
502 callee->Offset = dst;
503 return TRUE;
505 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) at %p\n", ch, insn);
506 return FALSE;
507 default:
508 switch (f_rm(ch))
510 case 0x00: dst = dbg_context.ctx.Rax; break;
511 case 0x01: dst = dbg_context.ctx.Rcx; break;
512 case 0x02: dst = dbg_context.ctx.Rdx; break;
513 case 0x03: dst = dbg_context.ctx.Rbx; break;
514 case 0x04: dst = dbg_context.ctx.Rsp; break;
515 case 0x05: dst = dbg_context.ctx.Rbp; break;
516 case 0x06: dst = dbg_context.ctx.Rsi; break;
517 case 0x07: dst = dbg_context.ctx.Rdi; break;
519 if (f_mod(ch) != 0x03)
521 if (!add_fixed_displacement((const char*)insn + 2, f_mod(ch), &dst))
522 return FALSE;
523 if (!load_indirect_target(&dst)) return FALSE;
525 callee->Offset = dst;
526 return TRUE;
528 else
529 WINE_FIXME("Unsupported yet call insn (rex=0x%02x 0xFF 0x%02x) at %p\n", rex, ch, insn);
530 return FALSE;
532 default:
533 return FALSE;
537 static BOOL be_x86_64_is_jump(const void* insn, ADDRESS64* jumpee)
539 return FALSE;
542 #define DR7_CONTROL_SHIFT 16
543 #define DR7_CONTROL_SIZE 4
545 #define DR7_RW_EXECUTE (0x0)
546 #define DR7_RW_WRITE (0x1)
547 #define DR7_RW_READ (0x3)
549 #define DR7_LEN_1 (0x0)
550 #define DR7_LEN_2 (0x4)
551 #define DR7_LEN_4 (0xC)
552 #define DR7_LEN_8 (0x8)
554 #define DR7_LOCAL_ENABLE_SHIFT 0
555 #define DR7_GLOBAL_ENABLE_SHIFT 1
556 #define DR7_ENABLE_SIZE 2
558 #define DR7_LOCAL_ENABLE_MASK (0x55)
559 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
561 #define DR7_CONTROL_RESERVED (0xFC00)
562 #define DR7_LOCAL_SLOWDOWN (0x100)
563 #define DR7_GLOBAL_SLOWDOWN (0x200)
565 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
566 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
568 static inline int be_x86_64_get_unused_DR(dbg_ctx_t *pctx, DWORD64** r)
570 CONTEXT *ctx = &pctx->ctx;
572 if (!IS_DR7_SET(ctx->Dr7, 0))
574 *r = &ctx->Dr0;
575 return 0;
577 if (!IS_DR7_SET(ctx->Dr7, 1))
579 *r = &ctx->Dr1;
580 return 1;
582 if (!IS_DR7_SET(ctx->Dr7, 2))
584 *r = &ctx->Dr2;
585 return 2;
587 if (!IS_DR7_SET(ctx->Dr7, 3))
589 *r = &ctx->Dr3;
590 return 3;
592 dbg_printf("All hardware registers have been used\n");
594 return -1;
597 static BOOL be_x86_64_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
598 dbg_ctx_t *ctx, enum be_xpoint_type type,
599 void* addr, unsigned *val, unsigned size)
601 unsigned char ch;
602 SIZE_T sz;
603 DWORD64 *pr;
604 int reg;
605 unsigned int bits;
607 switch (type)
609 case be_xpoint_break:
610 if (size != 0) return FALSE;
611 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
612 *val = ch;
613 ch = 0xcc;
614 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
615 break;
616 case be_xpoint_watch_exec:
617 bits = DR7_RW_EXECUTE;
618 goto hw_bp;
619 case be_xpoint_watch_read:
620 bits = DR7_RW_READ;
621 goto hw_bp;
622 case be_xpoint_watch_write:
623 bits = DR7_RW_WRITE;
624 hw_bp:
625 if ((reg = be_x86_64_get_unused_DR(ctx, &pr)) == -1) return FALSE;
626 *pr = (DWORD64)addr;
627 if (type != be_xpoint_watch_exec) switch (size)
629 case 8: bits |= DR7_LEN_8; break;
630 case 4: bits |= DR7_LEN_4; break;
631 case 2: bits |= DR7_LEN_2; break;
632 case 1: bits |= DR7_LEN_1; break;
633 default: WINE_FIXME("Unsupported xpoint_watch of size %d\n", size); return FALSE;
635 *val = reg;
636 /* clear old values */
637 ctx->ctx.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
638 /* set the correct ones */
639 ctx->ctx.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
640 ctx->ctx.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
641 break;
642 default:
643 dbg_printf("Unknown bp type %c\n", type);
644 return FALSE;
646 return TRUE;
649 static BOOL be_x86_64_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
650 dbg_ctx_t *ctx, enum be_xpoint_type type,
651 void* addr, unsigned val, unsigned size)
653 SIZE_T sz;
654 unsigned char ch;
656 switch (type)
658 case be_xpoint_break:
659 if (size != 0) return FALSE;
660 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
661 if (ch != (unsigned char)0xCC)
662 WINE_FIXME("Cannot get back %02x instead of 0xCC at %p\n", ch, addr);
663 ch = (unsigned char)val;
664 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
665 break;
666 case be_xpoint_watch_exec:
667 case be_xpoint_watch_read:
668 case be_xpoint_watch_write:
669 /* simply disable the entry */
670 ctx->ctx.Dr7 &= ~DR7_ENABLE_MASK(val);
671 break;
672 default:
673 dbg_printf("Unknown bp type %c\n", type);
674 return FALSE;
676 return TRUE;
679 static BOOL be_x86_64_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
681 return ctx->ctx.Dr6 & (1 << idx);
684 static void be_x86_64_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
686 ctx->ctx.Dr6 &= ~(1 << idx);
689 static int be_x86_64_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
691 if (way)
693 ctx->ctx.Rip--;
694 return -1;
696 ctx->ctx.Rip++;
697 return 1;
700 static BOOL be_x86_64_get_context(HANDLE thread, dbg_ctx_t *ctx)
702 ctx->ctx.ContextFlags = CONTEXT_ALL;
703 return GetThreadContext(thread, &ctx->ctx);
706 static BOOL be_x86_64_set_context(HANDLE thread, const dbg_ctx_t *ctx)
708 return SetThreadContext(thread, &ctx->ctx);
711 #define REG(f,n,t,r) {f, n, t, FIELD_OFFSET(CONTEXT, r), sizeof(((CONTEXT*)NULL)->r)}
713 static struct gdb_register be_x86_64_gdb_register_map[] = {
714 REG("core", "rax", NULL, Rax),
715 REG(NULL, "rbx", NULL, Rbx),
716 REG(NULL, "rcx", NULL, Rcx),
717 REG(NULL, "rdx", NULL, Rdx),
718 REG(NULL, "rsi", NULL, Rsi),
719 REG(NULL, "rdi", NULL, Rdi),
720 REG(NULL, "rbp", "data_ptr", Rbp),
721 REG(NULL, "rsp", "data_ptr", Rsp),
722 REG(NULL, "r8", NULL, R8),
723 REG(NULL, "r9", NULL, R9),
724 REG(NULL, "r10", NULL, R10),
725 REG(NULL, "r11", NULL, R11),
726 REG(NULL, "r12", NULL, R12),
727 REG(NULL, "r13", NULL, R13),
728 REG(NULL, "r14", NULL, R14),
729 REG(NULL, "r15", NULL, R15),
730 REG(NULL, "rip", "code_ptr", Rip),
731 REG(NULL, "eflags", "i386_eflags", EFlags),
732 REG(NULL, "cs", NULL, SegCs),
733 REG(NULL, "ss", NULL, SegSs),
734 REG(NULL, "ds", NULL, SegDs),
735 REG(NULL, "es", NULL, SegEs),
736 REG(NULL, "fs", NULL, SegFs),
737 REG(NULL, "gs", NULL, SegGs),
738 { NULL, "st0", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 0]), 10},
739 { NULL, "st1", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 1]), 10},
740 { NULL, "st2", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 2]), 10},
741 { NULL, "st3", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 3]), 10},
742 { NULL, "st4", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 4]), 10},
743 { NULL, "st5", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 5]), 10},
744 { NULL, "st6", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 6]), 10},
745 { NULL, "st7", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 7]), 10},
746 REG(NULL, "fctrl", NULL, u.FltSave.ControlWord),
747 REG(NULL, "fstat", NULL, u.FltSave.StatusWord),
748 REG(NULL, "ftag", NULL, u.FltSave.TagWord),
749 REG(NULL, "fiseg", NULL, u.FltSave.ErrorSelector),
750 REG(NULL, "fioff", NULL, u.FltSave.ErrorOffset),
751 REG(NULL, "foseg", NULL, u.FltSave.DataSelector),
752 REG(NULL, "fooff", NULL, u.FltSave.DataOffset),
753 REG(NULL, "fop", NULL, u.FltSave.ErrorOpcode),
755 REG("sse", "xmm0", "vec128", u.s.Xmm0),
756 REG(NULL, "xmm1", "vec128", u.s.Xmm1),
757 REG(NULL, "xmm2", "vec128", u.s.Xmm2),
758 REG(NULL, "xmm3", "vec128", u.s.Xmm3),
759 REG(NULL, "xmm4", "vec128", u.s.Xmm4),
760 REG(NULL, "xmm5", "vec128", u.s.Xmm5),
761 REG(NULL, "xmm6", "vec128", u.s.Xmm6),
762 REG(NULL, "xmm7", "vec128", u.s.Xmm7),
763 REG(NULL, "xmm8", "vec128", u.s.Xmm8),
764 REG(NULL, "xmm9", "vec128", u.s.Xmm9),
765 REG(NULL, "xmm10", "vec128", u.s.Xmm10),
766 REG(NULL, "xmm11", "vec128", u.s.Xmm11),
767 REG(NULL, "xmm12", "vec128", u.s.Xmm12),
768 REG(NULL, "xmm13", "vec128", u.s.Xmm13),
769 REG(NULL, "xmm14", "vec128", u.s.Xmm14),
770 REG(NULL, "xmm15", "vec128", u.s.Xmm15),
771 REG(NULL, "mxcsr", "i386_mxcsr", u.FltSave.MxCsr),
774 struct backend_cpu be_x86_64 =
776 IMAGE_FILE_MACHINE_AMD64,
778 be_cpu_linearize,
779 be_cpu_build_addr,
780 be_x86_64_get_addr,
781 be_x86_64_get_register_info,
782 be_x86_64_single_step,
783 be_x86_64_print_context,
784 be_x86_64_print_segment_info,
785 be_x86_64_ctx,
786 be_x86_64_is_step_over_insn,
787 be_x86_64_is_function_return,
788 be_x86_64_is_break_insn,
789 be_x86_64_is_func_call,
790 be_x86_64_is_jump,
791 memory_disasm_one_x86_insn,
792 be_x86_64_insert_Xpoint,
793 be_x86_64_remove_Xpoint,
794 be_x86_64_is_watchpoint_set,
795 be_x86_64_clear_watchpoint,
796 be_x86_64_adjust_pc_for_break,
797 be_x86_64_get_context,
798 be_x86_64_set_context,
799 be_x86_64_gdb_register_map,
800 ARRAY_SIZE(be_x86_64_gdb_register_map),
802 #endif