wineoss: Fix missing break statement.
[wine.git] / programs / winedbg / be_x86_64.c
blobb110e624b1f0457779886f30b85ee26cb12e2d62
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 extern void be_x86_64_disasm_one_insn(ADDRESS64* addr, int display);
544 #define DR7_CONTROL_SHIFT 16
545 #define DR7_CONTROL_SIZE 4
547 #define DR7_RW_EXECUTE (0x0)
548 #define DR7_RW_WRITE (0x1)
549 #define DR7_RW_READ (0x3)
551 #define DR7_LEN_1 (0x0)
552 #define DR7_LEN_2 (0x4)
553 #define DR7_LEN_4 (0xC)
554 #define DR7_LEN_8 (0x8)
556 #define DR7_LOCAL_ENABLE_SHIFT 0
557 #define DR7_GLOBAL_ENABLE_SHIFT 1
558 #define DR7_ENABLE_SIZE 2
560 #define DR7_LOCAL_ENABLE_MASK (0x55)
561 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
563 #define DR7_CONTROL_RESERVED (0xFC00)
564 #define DR7_LOCAL_SLOWDOWN (0x100)
565 #define DR7_GLOBAL_SLOWDOWN (0x200)
567 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
568 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
570 static inline int be_x86_64_get_unused_DR(dbg_ctx_t *pctx, DWORD64** r)
572 CONTEXT *ctx = &pctx->ctx;
574 if (!IS_DR7_SET(ctx->Dr7, 0))
576 *r = &ctx->Dr0;
577 return 0;
579 if (!IS_DR7_SET(ctx->Dr7, 1))
581 *r = &ctx->Dr1;
582 return 1;
584 if (!IS_DR7_SET(ctx->Dr7, 2))
586 *r = &ctx->Dr2;
587 return 2;
589 if (!IS_DR7_SET(ctx->Dr7, 3))
591 *r = &ctx->Dr3;
592 return 3;
594 dbg_printf("All hardware registers have been used\n");
596 return -1;
599 static BOOL be_x86_64_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
600 dbg_ctx_t *ctx, enum be_xpoint_type type,
601 void* addr, unsigned *val, unsigned size)
603 unsigned char ch;
604 SIZE_T sz;
605 DWORD64 *pr;
606 int reg;
607 unsigned int bits;
609 switch (type)
611 case be_xpoint_break:
612 if (size != 0) return FALSE;
613 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
614 *val = ch;
615 ch = 0xcc;
616 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
617 break;
618 case be_xpoint_watch_exec:
619 bits = DR7_RW_EXECUTE;
620 goto hw_bp;
621 case be_xpoint_watch_read:
622 bits = DR7_RW_READ;
623 goto hw_bp;
624 case be_xpoint_watch_write:
625 bits = DR7_RW_WRITE;
626 hw_bp:
627 if ((reg = be_x86_64_get_unused_DR(ctx, &pr)) == -1) return FALSE;
628 *pr = (DWORD64)addr;
629 if (type != be_xpoint_watch_exec) switch (size)
631 case 8: bits |= DR7_LEN_8; break;
632 case 4: bits |= DR7_LEN_4; break;
633 case 2: bits |= DR7_LEN_2; break;
634 case 1: bits |= DR7_LEN_1; break;
635 default: WINE_FIXME("Unsupported xpoint_watch of size %d\n", size); return FALSE;
637 *val = reg;
638 /* clear old values */
639 ctx->ctx.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
640 /* set the correct ones */
641 ctx->ctx.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
642 ctx->ctx.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
643 break;
644 default:
645 dbg_printf("Unknown bp type %c\n", type);
646 return FALSE;
648 return TRUE;
651 static BOOL be_x86_64_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
652 dbg_ctx_t *ctx, enum be_xpoint_type type,
653 void* addr, unsigned val, unsigned size)
655 SIZE_T sz;
656 unsigned char ch;
658 switch (type)
660 case be_xpoint_break:
661 if (size != 0) return FALSE;
662 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
663 if (ch != (unsigned char)0xCC)
664 WINE_FIXME("Cannot get back %02x instead of 0xCC at %p\n", ch, addr);
665 ch = (unsigned char)val;
666 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
667 break;
668 case be_xpoint_watch_exec:
669 case be_xpoint_watch_read:
670 case be_xpoint_watch_write:
671 /* simply disable the entry */
672 ctx->ctx.Dr7 &= ~DR7_ENABLE_MASK(val);
673 break;
674 default:
675 dbg_printf("Unknown bp type %c\n", type);
676 return FALSE;
678 return TRUE;
681 static BOOL be_x86_64_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
683 return ctx->ctx.Dr6 & (1 << idx);
686 static void be_x86_64_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
688 ctx->ctx.Dr6 &= ~(1 << idx);
691 static int be_x86_64_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
693 if (way)
695 ctx->ctx.Rip--;
696 return -1;
698 ctx->ctx.Rip++;
699 return 1;
702 static BOOL be_x86_64_get_context(HANDLE thread, dbg_ctx_t *ctx)
704 ctx->ctx.ContextFlags = CONTEXT_ALL;
705 return GetThreadContext(thread, &ctx->ctx);
708 static BOOL be_x86_64_set_context(HANDLE thread, const dbg_ctx_t *ctx)
710 return SetThreadContext(thread, &ctx->ctx);
713 #define REG(f,n,t,r) {f, n, t, FIELD_OFFSET(CONTEXT, r), sizeof(((CONTEXT*)NULL)->r)}
715 static struct gdb_register be_x86_64_gdb_register_map[] = {
716 REG("core", "rax", NULL, Rax),
717 REG(NULL, "rbx", NULL, Rbx),
718 REG(NULL, "rcx", NULL, Rcx),
719 REG(NULL, "rdx", NULL, Rdx),
720 REG(NULL, "rsi", NULL, Rsi),
721 REG(NULL, "rdi", NULL, Rdi),
722 REG(NULL, "rbp", "data_ptr", Rbp),
723 REG(NULL, "rsp", "data_ptr", Rsp),
724 REG(NULL, "r8", NULL, R8),
725 REG(NULL, "r9", NULL, R9),
726 REG(NULL, "r10", NULL, R10),
727 REG(NULL, "r11", NULL, R11),
728 REG(NULL, "r12", NULL, R12),
729 REG(NULL, "r13", NULL, R13),
730 REG(NULL, "r14", NULL, R14),
731 REG(NULL, "r15", NULL, R15),
732 REG(NULL, "rip", "code_ptr", Rip),
733 REG(NULL, "eflags", "i386_eflags", EFlags),
734 REG(NULL, "cs", NULL, SegCs),
735 REG(NULL, "ss", NULL, SegSs),
736 REG(NULL, "ds", NULL, SegDs),
737 REG(NULL, "es", NULL, SegEs),
738 REG(NULL, "fs", NULL, SegFs),
739 REG(NULL, "gs", NULL, SegGs),
740 { NULL, "st0", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 0]), 10},
741 { NULL, "st1", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 1]), 10},
742 { NULL, "st2", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 2]), 10},
743 { NULL, "st3", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 3]), 10},
744 { NULL, "st4", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 4]), 10},
745 { NULL, "st5", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 5]), 10},
746 { NULL, "st6", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 6]), 10},
747 { NULL, "st7", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 7]), 10},
748 REG(NULL, "fctrl", NULL, u.FltSave.ControlWord),
749 REG(NULL, "fstat", NULL, u.FltSave.StatusWord),
750 REG(NULL, "ftag", NULL, u.FltSave.TagWord),
751 REG(NULL, "fiseg", NULL, u.FltSave.ErrorSelector),
752 REG(NULL, "fioff", NULL, u.FltSave.ErrorOffset),
753 REG(NULL, "foseg", NULL, u.FltSave.DataSelector),
754 REG(NULL, "fooff", NULL, u.FltSave.DataOffset),
755 REG(NULL, "fop", NULL, u.FltSave.ErrorOpcode),
757 REG("sse", "xmm0", "vec128", u.s.Xmm0),
758 REG(NULL, "xmm1", "vec128", u.s.Xmm1),
759 REG(NULL, "xmm2", "vec128", u.s.Xmm2),
760 REG(NULL, "xmm3", "vec128", u.s.Xmm3),
761 REG(NULL, "xmm4", "vec128", u.s.Xmm4),
762 REG(NULL, "xmm5", "vec128", u.s.Xmm5),
763 REG(NULL, "xmm6", "vec128", u.s.Xmm6),
764 REG(NULL, "xmm7", "vec128", u.s.Xmm7),
765 REG(NULL, "xmm8", "vec128", u.s.Xmm8),
766 REG(NULL, "xmm9", "vec128", u.s.Xmm9),
767 REG(NULL, "xmm10", "vec128", u.s.Xmm10),
768 REG(NULL, "xmm11", "vec128", u.s.Xmm11),
769 REG(NULL, "xmm12", "vec128", u.s.Xmm12),
770 REG(NULL, "xmm13", "vec128", u.s.Xmm13),
771 REG(NULL, "xmm14", "vec128", u.s.Xmm14),
772 REG(NULL, "xmm15", "vec128", u.s.Xmm15),
773 REG(NULL, "mxcsr", "i386_mxcsr", u.FltSave.MxCsr),
776 struct backend_cpu be_x86_64 =
778 IMAGE_FILE_MACHINE_AMD64,
780 be_cpu_linearize,
781 be_cpu_build_addr,
782 be_x86_64_get_addr,
783 be_x86_64_get_register_info,
784 be_x86_64_single_step,
785 be_x86_64_print_context,
786 be_x86_64_print_segment_info,
787 be_x86_64_ctx,
788 be_x86_64_is_step_over_insn,
789 be_x86_64_is_function_return,
790 be_x86_64_is_break_insn,
791 be_x86_64_is_func_call,
792 be_x86_64_is_jump,
793 be_x86_64_disasm_one_insn,
794 be_x86_64_insert_Xpoint,
795 be_x86_64_remove_Xpoint,
796 be_x86_64_is_watchpoint_set,
797 be_x86_64_clear_watchpoint,
798 be_x86_64_adjust_pc_for_break,
799 be_x86_64_get_context,
800 be_x86_64_set_context,
801 be_x86_64_gdb_register_map,
802 ARRAY_SIZE(be_x86_64_gdb_register_map),
804 #endif