wldap32/tests: Add ber_printf/scanf tests.
[wine/zf.git] / programs / winedbg / be_x86_64.c
blob63521d990508daefdcb6a83e2721afe9e9822106
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 inline long double m128a_to_longdouble(const M128A m)
78 /* gcc uses the same IEEE-754 representation as M128A for long double
79 * but 16 byte aligned (hence only the first 10 bytes out of the 16 are used)
81 return *(long double*)&m;
84 static void be_x86_64_print_context(HANDLE hThread, const dbg_ctx_t *pctx,
85 int all_regs)
87 static const char mxcsr_flags[16][4] = { "IE", "DE", "ZE", "OE", "UE", "PE", "DAZ", "IM",
88 "DM", "ZM", "OM", "UM", "PM", "R-", "R+", "FZ" };
89 static const char flags[] = "aVR-N--ODITSZ-A-P-C";
90 const CONTEXT *ctx = &pctx->ctx;
91 char buf[33];
92 int i;
94 strcpy(buf, flags);
95 for (i = 0; buf[i]; i++)
96 if (buf[i] != '-' && !(ctx->EFlags & (1 << (sizeof(flags) - 2 - i))))
97 buf[i] = ' ';
99 dbg_printf("Register dump:\n");
100 dbg_printf(" rip:%016lx rsp:%016lx rbp:%016lx eflags:%08x (%s)\n",
101 ctx->Rip, ctx->Rsp, ctx->Rbp, ctx->EFlags, buf);
102 dbg_printf(" rax:%016lx rbx:%016lx rcx:%016lx rdx:%016lx\n",
103 ctx->Rax, ctx->Rbx, ctx->Rcx, ctx->Rdx);
104 dbg_printf(" rsi:%016lx rdi:%016lx r8:%016lx r9:%016lx r10:%016lx\n",
105 ctx->Rsi, ctx->Rdi, ctx->R8, ctx->R9, ctx->R10 );
106 dbg_printf(" r11:%016lx r12:%016lx r13:%016lx r14:%016lx r15:%016lx\n",
107 ctx->R11, ctx->R12, ctx->R13, ctx->R14, ctx->R15 );
109 if (!all_regs) return;
111 dbg_printf(" cs:%04x ds:%04x es:%04x fs:%04x gs:%04x ss:%04x\n",
112 ctx->SegCs, ctx->SegDs, ctx->SegEs, ctx->SegFs, ctx->SegGs, ctx->SegSs );
114 dbg_printf("Debug:\n");
115 dbg_printf(" dr0:%016lx dr1:%016lx dr2:%016lx dr3:%016lx\n",
116 ctx->Dr0, ctx->Dr1, ctx->Dr2, ctx->Dr3 );
117 dbg_printf(" dr6:%016lx dr7:%016lx\n", ctx->Dr6, ctx->Dr7 );
119 dbg_printf("Floating point:\n");
120 dbg_printf(" flcw:%04x ", LOWORD(ctx->u.FltSave.ControlWord));
121 dbg_printf(" fltw:%04x ", LOWORD(ctx->u.FltSave.TagWord));
122 dbg_printf(" flsw:%04x", LOWORD(ctx->u.FltSave.StatusWord));
124 dbg_printf("(cc:%d%d%d%d", (ctx->u.FltSave.StatusWord & 0x00004000) >> 14,
125 (ctx->u.FltSave.StatusWord & 0x00000400) >> 10,
126 (ctx->u.FltSave.StatusWord & 0x00000200) >> 9,
127 (ctx->u.FltSave.StatusWord & 0x00000100) >> 8);
129 dbg_printf(" top:%01x", (unsigned int) (ctx->u.FltSave.StatusWord & 0x00003800) >> 11);
131 if (ctx->u.FltSave.StatusWord & 0x00000001) /* Invalid Fl OP */
133 if (ctx->u.FltSave.StatusWord & 0x00000040) /* Stack Fault */
135 if (ctx->u.FltSave.StatusWord & 0x00000200) /* C1 says Overflow */
136 dbg_printf(" #IE(Stack Overflow)");
137 else
138 dbg_printf(" #IE(Stack Underflow)"); /* Underflow */
140 else dbg_printf(" #IE(Arithmetic error)"); /* Invalid Fl OP */
142 if (ctx->u.FltSave.StatusWord & 0x00000002) dbg_printf(" #DE"); /* Denormalised OP */
143 if (ctx->u.FltSave.StatusWord & 0x00000004) dbg_printf(" #ZE"); /* Zero Divide */
144 if (ctx->u.FltSave.StatusWord & 0x00000008) dbg_printf(" #OE"); /* Overflow */
145 if (ctx->u.FltSave.StatusWord & 0x00000010) dbg_printf(" #UE"); /* Underflow */
146 if (ctx->u.FltSave.StatusWord & 0x00000020) dbg_printf(" #PE"); /* Precision error */
147 if (ctx->u.FltSave.StatusWord & 0x00000040)
148 if (!(ctx->u.FltSave.StatusWord & 0x00000001))
149 dbg_printf(" #SE"); /* Stack Fault (don't think this can occur) */
150 if (ctx->u.FltSave.StatusWord & 0x00000080) dbg_printf(" #ES"); /* Error Summary */
151 if (ctx->u.FltSave.StatusWord & 0x00008000) dbg_printf(" #FB"); /* FPU Busy */
152 dbg_printf(")\n");
153 dbg_printf(" flerr:%04x:%08x fldata:%04x:%08x\n",
154 ctx->u.FltSave.ErrorSelector, ctx->u.FltSave.ErrorOffset,
155 ctx->u.FltSave.DataSelector, ctx->u.FltSave.DataOffset );
157 for (i = 0; i < 4; i++)
159 dbg_printf(" st%u:%-16Lg ", i, m128a_to_longdouble(ctx->u.FltSave.FloatRegisters[i]));
161 dbg_printf("\n");
162 for (i = 4; i < 8; i++)
164 dbg_printf(" st%u:%-16Lg ", i, m128a_to_longdouble(ctx->u.FltSave.FloatRegisters[i]));
166 dbg_printf("\n");
168 dbg_printf(" mxcsr: %04x (", ctx->u.FltSave.MxCsr );
169 for (i = 0; i < 16; i++)
170 if (ctx->u.FltSave.MxCsr & (1 << i)) dbg_printf( " %s", mxcsr_flags[i] );
171 dbg_printf(" )\n");
173 for (i = 0; i < 16; i++)
175 dbg_printf( " %sxmm%u: uint=%016lx%016lx", (i > 9) ? "" : " ", i,
176 ctx->u.FltSave.XmmRegisters[i].High, ctx->u.FltSave.XmmRegisters[i].Low );
177 dbg_printf( " double={%g; %g}", *(double *)&ctx->u.FltSave.XmmRegisters[i].Low,
178 *(double *)&ctx->u.FltSave.XmmRegisters[i].High );
179 dbg_printf( " float={%g; %g; %g; %g}\n",
180 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 0),
181 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 1),
182 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 2),
183 (double)*((float *)&ctx->u.FltSave.XmmRegisters[i] + 3) );
187 static void be_x86_64_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
191 static struct dbg_internal_var be_x86_64_ctx[] =
193 {CV_AMD64_AL, "AL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_char_int},
194 {CV_AMD64_BL, "BL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_char_int},
195 {CV_AMD64_CL, "CL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_char_int},
196 {CV_AMD64_DL, "DL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_char_int},
197 {CV_AMD64_AH, "AH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Rax)+1), dbg_itype_unsigned_char_int},
198 {CV_AMD64_BH, "BH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Rbx)+1), dbg_itype_unsigned_char_int},
199 {CV_AMD64_CH, "CH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Rcx)+1), dbg_itype_unsigned_char_int},
200 {CV_AMD64_DH, "DH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Rdx)+1), dbg_itype_unsigned_char_int},
201 {CV_AMD64_AX, "AX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_short_int},
202 {CV_AMD64_BX, "BX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_short_int},
203 {CV_AMD64_CX, "CX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_short_int},
204 {CV_AMD64_DX, "DX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_short_int},
205 {CV_AMD64_SP, "SP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rsp), dbg_itype_unsigned_short_int},
206 {CV_AMD64_BP, "BP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbp), dbg_itype_unsigned_short_int},
207 {CV_AMD64_SI, "SI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rsi), dbg_itype_unsigned_short_int},
208 {CV_AMD64_DI, "DI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdi), dbg_itype_unsigned_short_int},
209 {CV_AMD64_EAX, "EAX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_int},
210 {CV_AMD64_EBX, "EBX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_int},
211 {CV_AMD64_ECX, "ECX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_int},
212 {CV_AMD64_EDX, "EDX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_int},
213 {CV_AMD64_ESP, "ESP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rsp), dbg_itype_unsigned_int},
214 {CV_AMD64_EBP, "EBP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbp), dbg_itype_unsigned_int},
215 {CV_AMD64_ESI, "ESI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rsi), dbg_itype_unsigned_int},
216 {CV_AMD64_EDI, "EDI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdi), dbg_itype_unsigned_int},
217 {CV_AMD64_ES, "ES", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegEs), dbg_itype_unsigned_short_int},
218 {CV_AMD64_CS, "CS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegCs), dbg_itype_unsigned_short_int},
219 {CV_AMD64_SS, "SS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegSs), dbg_itype_unsigned_short_int},
220 {CV_AMD64_DS, "DS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegDs), dbg_itype_unsigned_short_int},
221 {CV_AMD64_FS, "FS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegFs), dbg_itype_unsigned_short_int},
222 {CV_AMD64_GS, "GS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegGs), dbg_itype_unsigned_short_int},
223 {CV_AMD64_FLAGS, "FLAGS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_short_int},
224 {CV_AMD64_EFLAGS, "EFLAGS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_int},
225 {CV_AMD64_RIP, "RIP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rip), dbg_itype_unsigned_long_int},
226 {CV_AMD64_RAX, "RAX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rax), dbg_itype_unsigned_long_int},
227 {CV_AMD64_RBX, "RBX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbx), dbg_itype_unsigned_long_int},
228 {CV_AMD64_RCX, "RCX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rcx), dbg_itype_unsigned_long_int},
229 {CV_AMD64_RDX, "RDX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdx), dbg_itype_unsigned_long_int},
230 {CV_AMD64_RSP, "RSP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rsp), dbg_itype_unsigned_long_int},
231 {CV_AMD64_RBP, "RBP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rbp), dbg_itype_unsigned_long_int},
232 {CV_AMD64_RSI, "RSI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rsi), dbg_itype_unsigned_long_int},
233 {CV_AMD64_RDI, "RDI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Rdi), dbg_itype_unsigned_long_int},
234 {CV_AMD64_R8, "R8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R8), dbg_itype_unsigned_long_int},
235 {CV_AMD64_R9, "R9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R9), dbg_itype_unsigned_long_int},
236 {CV_AMD64_R10, "R10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R10), dbg_itype_unsigned_long_int},
237 {CV_AMD64_R11, "R11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R11), dbg_itype_unsigned_long_int},
238 {CV_AMD64_R12, "R12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R12), dbg_itype_unsigned_long_int},
239 {CV_AMD64_R13, "R13", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R13), dbg_itype_unsigned_long_int},
240 {CV_AMD64_R14, "R14", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R14), dbg_itype_unsigned_long_int},
241 {CV_AMD64_R15, "R15", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, R15), dbg_itype_unsigned_long_int},
242 {CV_AMD64_ST0, "ST0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[0]), dbg_itype_long_real},
243 {CV_AMD64_ST0+1, "ST1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[1]), dbg_itype_long_real},
244 {CV_AMD64_ST0+2, "ST2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[2]), dbg_itype_long_real},
245 {CV_AMD64_ST0+3, "ST3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[3]), dbg_itype_long_real},
246 {CV_AMD64_ST0+4, "ST4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[4]), dbg_itype_long_real},
247 {CV_AMD64_ST0+5, "ST5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[5]), dbg_itype_long_real},
248 {CV_AMD64_ST0+6, "ST6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[6]), dbg_itype_long_real},
249 {CV_AMD64_ST0+7, "ST7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[7]), dbg_itype_long_real},
250 {CV_AMD64_XMM0, "XMM0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm0), dbg_itype_m128a},
251 {CV_AMD64_XMM0+1, "XMM1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm1), dbg_itype_m128a},
252 {CV_AMD64_XMM0+2, "XMM2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm2), dbg_itype_m128a},
253 {CV_AMD64_XMM0+3, "XMM3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm3), dbg_itype_m128a},
254 {CV_AMD64_XMM0+4, "XMM4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm4), dbg_itype_m128a},
255 {CV_AMD64_XMM0+5, "XMM5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm5), dbg_itype_m128a},
256 {CV_AMD64_XMM0+6, "XMM6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm6), dbg_itype_m128a},
257 {CV_AMD64_XMM0+7, "XMM7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm7), dbg_itype_m128a},
258 {CV_AMD64_XMM8, "XMM8", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm8), dbg_itype_m128a},
259 {CV_AMD64_XMM8+1, "XMM9", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm9), dbg_itype_m128a},
260 {CV_AMD64_XMM8+2, "XMM10", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm10), dbg_itype_m128a},
261 {CV_AMD64_XMM8+3, "XMM11", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm11), dbg_itype_m128a},
262 {CV_AMD64_XMM8+4, "XMM12", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm12), dbg_itype_m128a},
263 {CV_AMD64_XMM8+5, "XMM13", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm13), dbg_itype_m128a},
264 {CV_AMD64_XMM8+6, "XMM14", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm14), dbg_itype_m128a},
265 {CV_AMD64_XMM8+7, "XMM15", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, u.s.Xmm15), dbg_itype_m128a},
266 {0, NULL, 0, dbg_itype_none}
269 #define f_mod(b) ((b)>>6)
270 #define f_reg(b) (((b)>>3)&0x7)
271 #define f_rm(b) ((b)&0x7)
272 #define f_sib_b(b) ((b)&0x7)
273 #define f_sib_i(b) (((b)>>3)&0x7)
274 #define f_sib_s(b) ((b)>>6)
276 static BOOL be_x86_64_is_step_over_insn(const void* insn)
278 BYTE ch;
280 for (;;)
282 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
284 switch (ch)
286 /* Skip all prefixes */
287 case 0x2e: /* cs: */
288 case 0x36: /* ss: */
289 case 0x3e: /* ds: */
290 case 0x26: /* es: */
291 case 0x64: /* fs: */
292 case 0x65: /* gs: */
293 case 0x66: /* opcode size prefix */
294 case 0x67: /* addr size prefix */
295 case 0xf0: /* lock */
296 case 0xf2: /* repne */
297 case 0xf3: /* repe */
298 insn = (const char*)insn + 1;
299 continue;
301 /* Handle call instructions */
302 case 0xcd: /* int <intno> */
303 case 0xe8: /* call <offset> */
304 case 0x9a: /* lcall <seg>:<off> */
305 return TRUE;
307 case 0xff: /* call <regmodrm> */
308 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
309 return FALSE;
310 return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
312 /* Handle string instructions */
313 case 0x6c: /* insb */
314 case 0x6d: /* insw */
315 case 0x6e: /* outsb */
316 case 0x6f: /* outsw */
317 case 0xa4: /* movsb */
318 case 0xa5: /* movsw */
319 case 0xa6: /* cmpsb */
320 case 0xa7: /* cmpsw */
321 case 0xaa: /* stosb */
322 case 0xab: /* stosw */
323 case 0xac: /* lodsb */
324 case 0xad: /* lodsw */
325 case 0xae: /* scasb */
326 case 0xaf: /* scasw */
327 return TRUE;
329 default:
330 return FALSE;
335 static BOOL be_x86_64_is_function_return(const void* insn)
337 BYTE c;
339 /* sigh... amd64 for prefetch optimization requires 'rep ret' in some cases */
340 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
341 if (c == 0xF3) /* REP */
343 insn = (const char*)insn + 1;
344 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
346 return c == 0xC2 /* ret */ || c == 0xC3 /* ret NN */;
349 static BOOL be_x86_64_is_break_insn(const void* insn)
351 BYTE c;
352 return dbg_read_memory(insn, &c, sizeof(c)) && c == 0xCC;
355 static BOOL fetch_value(const char* addr, unsigned sz, int* value)
357 char value8;
358 short value16;
360 switch (sz)
362 case 1:
363 if (!dbg_read_memory(addr, &value8, sizeof(value8))) return FALSE;
364 *value = value8;
365 break;
366 case 2:
367 if (!dbg_read_memory(addr, &value16, sizeof(value16))) return FALSE;
368 *value = value16;
369 case 4:
370 if (!dbg_read_memory(addr, value, sizeof(*value))) return FALSE;
371 break;
372 default: return FALSE;
374 return TRUE;
377 static BOOL add_fixed_displacement(const void* insn, BYTE mod, DWORD64* addr)
379 LONG delta = 0;
381 if (mod == 1)
383 if (!fetch_value(insn, 1, &delta))
384 return FALSE;
386 else if (mod == 2)
388 if (!fetch_value(insn, sizeof(delta), &delta))
389 return FALSE;
391 *addr += delta;
392 return TRUE;
395 static BOOL evaluate_sib_address(const void* insn, BYTE mod, DWORD64* addr)
397 BYTE ch;
398 BYTE scale;
399 DWORD64 loc;
401 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
403 switch (f_sib_b(ch))
405 case 0x00: loc = dbg_context.ctx.Rax; break;
406 case 0x01: loc = dbg_context.ctx.Rcx; break;
407 case 0x02: loc = dbg_context.ctx.Rdx; break;
408 case 0x03: loc = dbg_context.ctx.Rbx; break;
409 case 0x04: loc = dbg_context.ctx.Rsp; break;
410 case 0x05:
411 loc = dbg_context.ctx.Rbp;
412 if (mod == 0)
414 loc = 0;
415 mod = 2;
417 break;
418 case 0x06: loc = dbg_context.ctx.Rsi; break;
419 case 0x07: loc = dbg_context.ctx.Rdi; break;
422 scale = f_sib_s(ch);
423 switch (f_sib_i(ch))
425 case 0x00: loc += dbg_context.ctx.Rax << scale; break;
426 case 0x01: loc += dbg_context.ctx.Rcx << scale; break;
427 case 0x02: loc += dbg_context.ctx.Rdx << scale; break;
428 case 0x03: loc += dbg_context.ctx.Rbx << scale; break;
429 case 0x04: break;
430 case 0x05: loc += dbg_context.ctx.Rbp << scale; break;
431 case 0x06: loc += dbg_context.ctx.Rsi << scale; break;
432 case 0x07: loc += dbg_context.ctx.Rdi << scale; break;
435 if (!add_fixed_displacement((const char*)insn + 1, mod, &loc))
436 return FALSE;
438 *addr = loc;
439 return TRUE;
442 static BOOL load_indirect_target(DWORD64* dst)
444 ADDRESS64 addr;
446 addr.Mode = AddrModeFlat;
447 addr.Segment = dbg_context.ctx.SegDs;
448 addr.Offset = *dst;
449 return dbg_read_memory(memory_to_linear_addr(&addr), &dst, sizeof(dst));
452 static BOOL be_x86_64_is_func_call(const void* insn, ADDRESS64* callee)
454 BYTE ch;
455 LONG delta;
456 unsigned op_size = 32, rex = 0;
457 DWORD64 dst;
459 /* we assume 64bit mode all over the place */
460 for (;;)
462 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
463 if (ch == 0x66) op_size = 16;
464 else if (ch == 0x67) WINE_FIXME("prefix not supported %x\n", ch);
465 else if (ch >= 0x40 && ch <= 0x4f) rex = ch & 0xf;
466 else break;
467 insn = (const char*)insn + 1;
468 } while (0);
470 /* that's the only mode we support anyway */
471 callee->Mode = AddrModeFlat;
472 callee->Segment = dbg_context.ctx.SegCs;
474 switch (ch)
476 case 0xe8: /* relative near call */
477 assert(op_size == 32);
478 if (!fetch_value((const char*)insn + 1, sizeof(delta), &delta))
479 return FALSE;
480 callee->Offset = (DWORD_PTR)insn + 1 + 4 + delta;
481 return TRUE;
483 case 0xff:
484 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
485 return FALSE;
486 WINE_TRACE("Got 0xFF %x (&C7=%x) with rex=%x\n", ch, ch & 0xC7, rex);
487 /* keep only the CALL and LCALL insn:s */
488 switch (f_reg(ch))
490 case 0x02:
491 break;
492 default: return FALSE;
494 if (rex == 0) switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
496 case 0x04:
497 case 0x44:
498 case 0x84:
500 evaluate_sib_address((const char*)insn + 2, f_mod(ch), &dst);
501 if (!load_indirect_target(&dst)) return FALSE;
502 callee->Offset = dst;
503 return TRUE;
505 case 0x05: /* addr32 */
506 if (f_reg(ch) == 0x2)
508 /* rip-relative to next insn */
509 if (!dbg_read_memory((const char*)insn + 2, &delta, sizeof(delta)) ||
510 !dbg_read_memory((const char*)insn + 6 + delta, &dst, sizeof(dst)))
511 return FALSE;
513 callee->Offset = dst;
514 return TRUE;
516 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) at %p\n", ch, insn);
517 return FALSE;
518 default:
519 switch (f_rm(ch))
521 case 0x00: dst = dbg_context.ctx.Rax; break;
522 case 0x01: dst = dbg_context.ctx.Rcx; break;
523 case 0x02: dst = dbg_context.ctx.Rdx; break;
524 case 0x03: dst = dbg_context.ctx.Rbx; break;
525 case 0x04: dst = dbg_context.ctx.Rsp; break;
526 case 0x05: dst = dbg_context.ctx.Rbp; break;
527 case 0x06: dst = dbg_context.ctx.Rsi; break;
528 case 0x07: dst = dbg_context.ctx.Rdi; break;
530 if (f_mod(ch) != 0x03)
532 if (!add_fixed_displacement((const char*)insn + 2, f_mod(ch), &dst))
533 return FALSE;
534 if (!load_indirect_target(&dst)) return FALSE;
536 callee->Offset = dst;
537 return TRUE;
539 else
540 WINE_FIXME("Unsupported yet call insn (rex=0x%02x 0xFF 0x%02x) at %p\n", rex, ch, insn);
541 return FALSE;
543 default:
544 return FALSE;
548 static BOOL be_x86_64_is_jump(const void* insn, ADDRESS64* jumpee)
550 return FALSE;
553 extern void be_x86_64_disasm_one_insn(ADDRESS64* addr, int display);
555 #define DR7_CONTROL_SHIFT 16
556 #define DR7_CONTROL_SIZE 4
558 #define DR7_RW_EXECUTE (0x0)
559 #define DR7_RW_WRITE (0x1)
560 #define DR7_RW_READ (0x3)
562 #define DR7_LEN_1 (0x0)
563 #define DR7_LEN_2 (0x4)
564 #define DR7_LEN_4 (0xC)
565 #define DR7_LEN_8 (0x8)
567 #define DR7_LOCAL_ENABLE_SHIFT 0
568 #define DR7_GLOBAL_ENABLE_SHIFT 1
569 #define DR7_ENABLE_SIZE 2
571 #define DR7_LOCAL_ENABLE_MASK (0x55)
572 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
574 #define DR7_CONTROL_RESERVED (0xFC00)
575 #define DR7_LOCAL_SLOWDOWN (0x100)
576 #define DR7_GLOBAL_SLOWDOWN (0x200)
578 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
579 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
581 static inline int be_x86_64_get_unused_DR(dbg_ctx_t *pctx, DWORD64** r)
583 CONTEXT *ctx = &pctx->ctx;
585 if (!IS_DR7_SET(ctx->Dr7, 0))
587 *r = &ctx->Dr0;
588 return 0;
590 if (!IS_DR7_SET(ctx->Dr7, 1))
592 *r = &ctx->Dr1;
593 return 1;
595 if (!IS_DR7_SET(ctx->Dr7, 2))
597 *r = &ctx->Dr2;
598 return 2;
600 if (!IS_DR7_SET(ctx->Dr7, 3))
602 *r = &ctx->Dr3;
603 return 3;
605 dbg_printf("All hardware registers have been used\n");
607 return -1;
610 static BOOL be_x86_64_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
611 dbg_ctx_t *ctx, enum be_xpoint_type type,
612 void* addr, unsigned long* val, unsigned size)
614 unsigned char ch;
615 SIZE_T sz;
616 DWORD64 *pr;
617 int reg;
618 unsigned long bits;
620 switch (type)
622 case be_xpoint_break:
623 if (size != 0) return FALSE;
624 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
625 *val = ch;
626 ch = 0xcc;
627 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
628 break;
629 case be_xpoint_watch_exec:
630 bits = DR7_RW_EXECUTE;
631 goto hw_bp;
632 case be_xpoint_watch_read:
633 bits = DR7_RW_READ;
634 goto hw_bp;
635 case be_xpoint_watch_write:
636 bits = DR7_RW_WRITE;
637 hw_bp:
638 if ((reg = be_x86_64_get_unused_DR(ctx, &pr)) == -1) return FALSE;
639 *pr = (DWORD64)addr;
640 if (type != be_xpoint_watch_exec) switch (size)
642 case 8: bits |= DR7_LEN_8; break;
643 case 4: bits |= DR7_LEN_4; break;
644 case 2: bits |= DR7_LEN_2; break;
645 case 1: bits |= DR7_LEN_1; break;
646 default: WINE_FIXME("Unsupported xpoint_watch of size %d\n", size); return FALSE;
648 *val = reg;
649 /* clear old values */
650 ctx->ctx.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
651 /* set the correct ones */
652 ctx->ctx.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
653 ctx->ctx.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
654 break;
655 default:
656 dbg_printf("Unknown bp type %c\n", type);
657 return FALSE;
659 return TRUE;
662 static BOOL be_x86_64_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
663 dbg_ctx_t *ctx, enum be_xpoint_type type,
664 void* addr, unsigned long val, unsigned size)
666 SIZE_T sz;
667 unsigned char ch;
669 switch (type)
671 case be_xpoint_break:
672 if (size != 0) return FALSE;
673 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
674 if (ch != (unsigned char)0xCC)
675 WINE_FIXME("Cannot get back %02x instead of 0xCC at %p\n", ch, addr);
676 ch = (unsigned char)val;
677 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
678 break;
679 case be_xpoint_watch_exec:
680 case be_xpoint_watch_read:
681 case be_xpoint_watch_write:
682 /* simply disable the entry */
683 ctx->ctx.Dr7 &= ~DR7_ENABLE_MASK(val);
684 break;
685 default:
686 dbg_printf("Unknown bp type %c\n", type);
687 return FALSE;
689 return TRUE;
692 static BOOL be_x86_64_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
694 return ctx->ctx.Dr6 & (1 << idx);
697 static void be_x86_64_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
699 ctx->ctx.Dr6 &= ~(1 << idx);
702 static int be_x86_64_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
704 if (way)
706 ctx->ctx.Rip--;
707 return -1;
709 ctx->ctx.Rip++;
710 return 1;
713 static BOOL be_x86_64_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
714 BOOL is_signed, LONGLONG* ret)
716 if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16)
717 return FALSE;
719 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
720 /* FIXME: this assumes that debuggee and debugger use the same
721 * integral representation
723 if (!memory_read_value(lvalue, size, ret)) return FALSE;
725 /* propagate sign information */
726 if (is_signed && size < sizeof(*ret) && (*ret >> (size * 8 - 1)) != 0)
728 ULONGLONG neg = -1;
729 *ret |= neg << (size * 8);
731 return TRUE;
734 static BOOL be_x86_64_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
735 long double* ret)
737 char tmp[sizeof(long double)];
739 /* FIXME: this assumes that debuggee and debugger use the same
740 * representation for reals
742 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
744 /* float & double types have to be promoted to a long double */
745 if (size == 4) *ret = *(float*)tmp;
746 else if (size == 8) *ret = *(double*)tmp;
747 else if (size == 10) *ret = *(long double*)tmp;
748 else return FALSE;
750 return TRUE;
753 static BOOL be_x86_64_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
754 BOOL is_signed, LONGLONG val)
756 /* this is simple as we're on a little endian CPU */
757 return memory_write_value(lvalue, size, &val);
760 static BOOL be_x86_64_get_context(HANDLE thread, dbg_ctx_t *ctx)
762 ctx->ctx.ContextFlags = CONTEXT_ALL;
763 return GetThreadContext(thread, &ctx->ctx);
766 static BOOL be_x86_64_set_context(HANDLE thread, const dbg_ctx_t *ctx)
768 return SetThreadContext(thread, &ctx->ctx);
771 #define REG(f,n,t,r) {f, n, t, FIELD_OFFSET(CONTEXT, r), sizeof(((CONTEXT*)NULL)->r)}
773 static struct gdb_register be_x86_64_gdb_register_map[] = {
774 REG("core", "rax", NULL, Rax),
775 REG(NULL, "rbx", NULL, Rbx),
776 REG(NULL, "rcx", NULL, Rcx),
777 REG(NULL, "rdx", NULL, Rdx),
778 REG(NULL, "rsi", NULL, Rsi),
779 REG(NULL, "rdi", NULL, Rdi),
780 REG(NULL, "rbp", "data_ptr", Rbp),
781 REG(NULL, "rsp", "data_ptr", Rsp),
782 REG(NULL, "r8", NULL, R8),
783 REG(NULL, "r9", NULL, R9),
784 REG(NULL, "r10", NULL, R10),
785 REG(NULL, "r11", NULL, R11),
786 REG(NULL, "r12", NULL, R12),
787 REG(NULL, "r13", NULL, R13),
788 REG(NULL, "r14", NULL, R14),
789 REG(NULL, "r15", NULL, R15),
790 REG(NULL, "rip", "code_ptr", Rip),
791 REG(NULL, "eflags", "i386_eflags", EFlags),
792 REG(NULL, "cs", NULL, SegCs),
793 REG(NULL, "ss", NULL, SegSs),
794 REG(NULL, "ds", NULL, SegDs),
795 REG(NULL, "es", NULL, SegEs),
796 REG(NULL, "fs", NULL, SegFs),
797 REG(NULL, "gs", NULL, SegGs),
798 { NULL, "st0", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 0]), 10},
799 { NULL, "st1", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 1]), 10},
800 { NULL, "st2", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 2]), 10},
801 { NULL, "st3", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 3]), 10},
802 { NULL, "st4", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 4]), 10},
803 { NULL, "st5", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 5]), 10},
804 { NULL, "st6", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 6]), 10},
805 { NULL, "st7", "i387_ext", FIELD_OFFSET(CONTEXT, u.FltSave.FloatRegisters[ 7]), 10},
806 REG(NULL, "fctrl", NULL, u.FltSave.ControlWord),
807 REG(NULL, "fstat", NULL, u.FltSave.StatusWord),
808 REG(NULL, "ftag", NULL, u.FltSave.TagWord),
809 REG(NULL, "fiseg", NULL, u.FltSave.ErrorSelector),
810 REG(NULL, "fioff", NULL, u.FltSave.ErrorOffset),
811 REG(NULL, "foseg", NULL, u.FltSave.DataSelector),
812 REG(NULL, "fooff", NULL, u.FltSave.DataOffset),
813 REG(NULL, "fop", NULL, u.FltSave.ErrorOpcode),
815 REG("sse", "xmm0", "vec128", u.s.Xmm0),
816 REG(NULL, "xmm1", "vec128", u.s.Xmm1),
817 REG(NULL, "xmm2", "vec128", u.s.Xmm2),
818 REG(NULL, "xmm3", "vec128", u.s.Xmm3),
819 REG(NULL, "xmm4", "vec128", u.s.Xmm4),
820 REG(NULL, "xmm5", "vec128", u.s.Xmm5),
821 REG(NULL, "xmm6", "vec128", u.s.Xmm6),
822 REG(NULL, "xmm7", "vec128", u.s.Xmm7),
823 REG(NULL, "xmm8", "vec128", u.s.Xmm8),
824 REG(NULL, "xmm9", "vec128", u.s.Xmm9),
825 REG(NULL, "xmm10", "vec128", u.s.Xmm10),
826 REG(NULL, "xmm11", "vec128", u.s.Xmm11),
827 REG(NULL, "xmm12", "vec128", u.s.Xmm12),
828 REG(NULL, "xmm13", "vec128", u.s.Xmm13),
829 REG(NULL, "xmm14", "vec128", u.s.Xmm14),
830 REG(NULL, "xmm15", "vec128", u.s.Xmm15),
831 REG(NULL, "mxcsr", "i386_mxcsr", u.FltSave.MxCsr),
834 struct backend_cpu be_x86_64 =
836 IMAGE_FILE_MACHINE_AMD64,
838 be_cpu_linearize,
839 be_cpu_build_addr,
840 be_x86_64_get_addr,
841 be_x86_64_get_register_info,
842 be_x86_64_single_step,
843 be_x86_64_print_context,
844 be_x86_64_print_segment_info,
845 be_x86_64_ctx,
846 be_x86_64_is_step_over_insn,
847 be_x86_64_is_function_return,
848 be_x86_64_is_break_insn,
849 be_x86_64_is_func_call,
850 be_x86_64_is_jump,
851 be_x86_64_disasm_one_insn,
852 be_x86_64_insert_Xpoint,
853 be_x86_64_remove_Xpoint,
854 be_x86_64_is_watchpoint_set,
855 be_x86_64_clear_watchpoint,
856 be_x86_64_adjust_pc_for_break,
857 be_x86_64_fetch_integer,
858 be_x86_64_fetch_float,
859 be_x86_64_store_integer,
860 be_x86_64_get_context,
861 be_x86_64_set_context,
862 be_x86_64_gdb_register_map,
863 ARRAY_SIZE(be_x86_64_gdb_register_map),
865 #endif