win32u: Use the dummy surface for empty layered window surfaces.
[wine.git] / dlls / dbghelp / cpu_x86_64.c
bloba328d592d434768be6fbe35ffb75274b9ce7ea8e
1 /*
2 * File cpu_x86_64.c
4 * Copyright (C) 1999, 2005 Alexandre Julliard
5 * Copyright (C) 2009, 2011 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 #include <assert.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "dbghelp_private.h"
27 #include "winternl.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
32 /* x86-64 unwind information, for PE modules, as described on MSDN */
34 typedef enum _UNWIND_OP_CODES
36 UWOP_PUSH_NONVOL = 0,
37 UWOP_ALLOC_LARGE,
38 UWOP_ALLOC_SMALL,
39 UWOP_SET_FPREG,
40 UWOP_SAVE_NONVOL,
41 UWOP_SAVE_NONVOL_FAR,
42 UWOP_EPILOG,
43 UWOP_SAVE_XMM128 = 8,
44 UWOP_SAVE_XMM128_FAR,
45 UWOP_PUSH_MACHFRAME
46 } UNWIND_CODE_OPS;
48 typedef union _UNWIND_CODE
50 struct
52 BYTE CodeOffset;
53 BYTE UnwindOp : 4;
54 BYTE OpInfo : 4;
56 USHORT FrameOffset;
57 } UNWIND_CODE, *PUNWIND_CODE;
59 typedef struct _UNWIND_INFO
61 BYTE Version : 3;
62 BYTE Flags : 5;
63 BYTE SizeOfProlog;
64 BYTE CountOfCodes;
65 BYTE FrameRegister : 4;
66 BYTE FrameOffset : 4;
67 UNWIND_CODE UnwindCode[1]; /* actually CountOfCodes (aligned) */
69 * union
70 * {
71 * OPTIONAL ULONG ExceptionHandler;
72 * OPTIONAL ULONG FunctionEntry;
73 * };
74 * OPTIONAL ULONG ExceptionData[];
76 } UNWIND_INFO, *PUNWIND_INFO;
78 static BOOL x86_64_get_addr(HANDLE hThread, const CONTEXT* ctx,
79 enum cpu_addr ca, ADDRESS64* addr)
81 addr->Mode = AddrModeFlat;
82 switch (ca)
84 #ifdef __x86_64__
85 case cpu_addr_pc: addr->Segment = ctx->SegCs; addr->Offset = ctx->Rip; return TRUE;
86 case cpu_addr_stack: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rsp; return TRUE;
87 case cpu_addr_frame: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rbp; return TRUE;
88 #endif
89 default: addr->Mode = -1;
90 return FALSE;
94 #ifdef __x86_64__
96 enum st_mode {stm_start, stm_64bit, stm_done};
98 /* indexes in Reserved array */
99 #define __CurrentMode 0
100 #define __CurrentCount 1
101 /* #define __ 2 (unused) */
103 #define curr_mode (frame->Reserved[__CurrentMode])
104 #define curr_count (frame->Reserved[__CurrentCount])
105 /* #define ??? (frame->Reserved[__]) (unused) */
107 union handler_data
109 RUNTIME_FUNCTION chain;
110 ULONG handler;
113 static void dump_unwind_info(struct cpu_stack_walk* csw, ULONG64 base, RUNTIME_FUNCTION *function)
115 static const char * const reg_names[16] =
116 { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
117 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
119 union handler_data handler_data;
120 char buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
121 UNWIND_INFO* info = (UNWIND_INFO*)buffer;
122 unsigned int i, count;
123 RUNTIME_FUNCTION snext;
124 ULONG64 addr;
126 TRACE("**** func %lx-%lx\n", function->BeginAddress, function->EndAddress);
127 for (;;)
129 if (function->UnwindData & 1)
131 if (!sw_read_mem(csw, base + function->UnwindData, &snext, sizeof(snext)))
133 TRACE("Couldn't unwind RUNTIME_INFO at %Ix\n", base + function->UnwindData);
134 return;
136 TRACE("unwind info for function %p-%p chained to function %p-%p\n",
137 (char*)base + function->BeginAddress, (char*)base + function->EndAddress,
138 (char*)base + snext.BeginAddress, (char*)base + snext.EndAddress);
139 function = &snext;
140 continue;
142 addr = base + function->UnwindData;
143 if (!sw_read_mem(csw, addr, info, FIELD_OFFSET(UNWIND_INFO, UnwindCode)) ||
144 !sw_read_mem(csw, addr + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
145 info->UnwindCode, info->CountOfCodes * sizeof(UNWIND_CODE)))
147 FIXME("couldn't read memory for UNWIND_INFO at %Ix\n", addr);
148 return;
150 TRACE("unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
151 (char*)addr, info->Flags, info->SizeOfProlog,
152 (char*)base + function->BeginAddress, (char*)base + function->EndAddress);
154 if (info->FrameRegister)
155 TRACE(" frame register %s offset 0x%x(%%rsp)\n",
156 reg_names[info->FrameRegister], info->FrameOffset * 16);
158 for (i = 0; i < info->CountOfCodes; i++)
160 TRACE(" 0x%x: ", info->UnwindCode[i].CodeOffset);
161 switch (info->UnwindCode[i].UnwindOp)
163 case UWOP_PUSH_NONVOL:
164 TRACE("pushq %%%s\n", reg_names[info->UnwindCode[i].OpInfo]);
165 break;
166 case UWOP_ALLOC_LARGE:
167 if (info->UnwindCode[i].OpInfo)
169 count = *(DWORD*)&info->UnwindCode[i+1];
170 i += 2;
172 else
174 count = *(USHORT*)&info->UnwindCode[i+1] * 8;
175 i++;
177 TRACE("subq $0x%x,%%rsp\n", count);
178 break;
179 case UWOP_ALLOC_SMALL:
180 count = (info->UnwindCode[i].OpInfo + 1) * 8;
181 TRACE("subq $0x%x,%%rsp\n", count);
182 break;
183 case UWOP_SET_FPREG:
184 TRACE("leaq 0x%x(%%rsp),%s\n",
185 info->FrameOffset * 16, reg_names[info->FrameRegister]);
186 break;
187 case UWOP_SAVE_NONVOL:
188 count = *(USHORT*)&info->UnwindCode[i+1] * 8;
189 TRACE("movq %%%s,0x%x(%%rsp)\n", reg_names[info->UnwindCode[i].OpInfo], count);
190 i++;
191 break;
192 case UWOP_SAVE_NONVOL_FAR:
193 count = *(DWORD*)&info->UnwindCode[i+1];
194 TRACE("movq %%%s,0x%x(%%rsp)\n", reg_names[info->UnwindCode[i].OpInfo], count);
195 i += 2;
196 break;
197 case UWOP_SAVE_XMM128:
198 count = *(USHORT*)&info->UnwindCode[i+1] * 16;
199 TRACE("movaps %%xmm%u,0x%x(%%rsp)\n", info->UnwindCode[i].OpInfo, count);
200 i++;
201 break;
202 case UWOP_SAVE_XMM128_FAR:
203 count = *(DWORD*)&info->UnwindCode[i+1];
204 TRACE("movaps %%xmm%u,0x%x(%%rsp)\n", info->UnwindCode[i].OpInfo, count);
205 i += 2;
206 break;
207 case UWOP_PUSH_MACHFRAME:
208 TRACE("PUSH_MACHFRAME %u\n", info->UnwindCode[i].OpInfo);
209 break;
210 case UWOP_EPILOG:
211 if (info->Version == 2)
213 unsigned int offset;
214 if (info->UnwindCode[i].OpInfo)
215 offset = info->UnwindCode[i].CodeOffset;
216 else
217 offset = (info->UnwindCode[i+1].OpInfo << 8) + info->UnwindCode[i+1].CodeOffset;
218 TRACE("UWOP_EPILOG %u offset %u\n", info->UnwindCode[i].OpInfo, offset);
219 i += 1;
220 break;
222 /* Fall through */
223 default:
224 FIXME("unknown code %u\n", info->UnwindCode[i].UnwindOp);
225 break;
229 addr += FIELD_OFFSET(UNWIND_INFO, UnwindCode) +
230 ((info->CountOfCodes + 1) & ~1) * sizeof(UNWIND_CODE);
231 if (info->Flags & UNW_FLAG_CHAININFO)
233 if (!sw_read_mem(csw, addr, &handler_data, sizeof(handler_data.chain)))
235 FIXME("couldn't read memory for handler_data.chain\n");
236 return;
238 TRACE(" chained to function %p-%p\n",
239 (char*)base + handler_data.chain.BeginAddress,
240 (char*)base + handler_data.chain.EndAddress);
241 function = &handler_data.chain;
242 continue;
244 if (info->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
246 if (!sw_read_mem(csw, addr, &handler_data, sizeof(handler_data.handler)))
248 FIXME("couldn't read memory for handler_data.handler\n");
249 return;
251 TRACE(" handler %p data at %p\n",
252 (char*)base + handler_data.handler, (char*)addr + sizeof(handler_data.handler));
254 break;
258 /* highly derived from dlls/ntdll/signal_x86_64.c */
259 static ULONG64 get_int_reg(CONTEXT *context, int reg)
261 return *(&context->Rax + reg);
264 static void set_int_reg(CONTEXT *context, int reg, ULONG64 val)
266 *(&context->Rax + reg) = val;
269 static void set_float_reg(CONTEXT *context, int reg, M128A val)
271 *(&context->Xmm0 + reg) = val;
274 static int get_opcode_size(UNWIND_CODE op)
276 switch (op.UnwindOp)
278 case UWOP_ALLOC_LARGE:
279 return 2 + (op.OpInfo != 0);
280 case UWOP_SAVE_NONVOL:
281 case UWOP_SAVE_XMM128:
282 case UWOP_EPILOG:
283 return 2;
284 case UWOP_SAVE_NONVOL_FAR:
285 case UWOP_SAVE_XMM128_FAR:
286 return 3;
287 default:
288 return 1;
292 static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc,
293 DWORD64 base, const RUNTIME_FUNCTION *function )
295 BYTE op0, op1, op2;
296 LONG val32;
298 if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
300 /* add or lea must be the first instruction, and it must have a rex.W prefix */
301 if ((op0 & 0xf8) == 0x48)
303 if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
304 switch (op1)
306 case 0x81: /* add $nnnn,%rsp */
307 if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
308 if (op0 == 0x48 && op2 == 0xc4)
310 pc += 7;
311 break;
313 return FALSE;
314 case 0x83: /* add $n,%rsp */
315 if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
316 if (op0 == 0x48 && op2 == 0xc4)
318 pc += 4;
319 break;
321 return FALSE;
322 case 0x8d: /* lea n(reg),%rsp */
323 if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
324 if (op0 & 0x06) return FALSE; /* rex.RX must be cleared */
325 if (((op2 >> 3) & 7) != 4) return FALSE; /* dest reg mus be %rsp */
326 if ((op2 & 7) == 4) return FALSE; /* no SIB byte allowed */
327 if ((op2 >> 6) == 1) /* 8-bit offset */
329 pc += 4;
330 break;
332 if ((op2 >> 6) == 2) /* 32-bit offset */
334 pc += 7;
335 break;
337 return FALSE;
341 /* now check for various pop instructions */
342 for (;;)
344 if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
345 if ((op0 & 0xf0) == 0x40) /* rex prefix */
347 if (!sw_read_mem(csw, ++pc, &op0, 1)) return FALSE;
350 switch (op0)
352 case 0x58: /* pop %rax/%r8 */
353 case 0x59: /* pop %rcx/%r9 */
354 case 0x5a: /* pop %rdx/%r10 */
355 case 0x5b: /* pop %rbx/%r11 */
356 case 0x5c: /* pop %rsp/%r12 */
357 case 0x5d: /* pop %rbp/%r13 */
358 case 0x5e: /* pop %rsi/%r14 */
359 case 0x5f: /* pop %rdi/%r15 */
360 pc++;
361 continue;
362 case 0xc2: /* ret $nn */
363 case 0xc3: /* ret */
364 return TRUE;
365 case 0xe9: /* jmp nnnn */
366 if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE;
367 pc += 5 + val32;
368 if (pc - base >= function->BeginAddress && pc - base < function->EndAddress)
369 continue;
370 break;
371 case 0xeb: /* jmp n */
372 if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
373 pc += 2 + (signed char)op1;
374 if (pc - base >= function->BeginAddress && pc - base < function->EndAddress)
375 continue;
376 break;
377 case 0xf3: /* rep; ret (for amd64 prediction bug) */
378 if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
379 return op1 == 0xc3;
381 return FALSE;
385 static BOOL interpret_epilog(struct cpu_stack_walk* csw, ULONG64 pc, CONTEXT *context )
387 BYTE insn, val8;
388 WORD val16;
389 LONG val32;
390 DWORD64 val64;
392 for (;;)
394 BYTE rex = 0;
396 if (!sw_read_mem(csw, pc, &insn, 1)) return FALSE;
397 if ((insn & 0xf0) == 0x40)
399 rex = insn & 0x0f; /* rex prefix */
400 if (!sw_read_mem(csw, ++pc, &insn, 1)) return FALSE;
403 switch (insn)
405 case 0x58: /* pop %rax/r8 */
406 case 0x59: /* pop %rcx/r9 */
407 case 0x5a: /* pop %rdx/r10 */
408 case 0x5b: /* pop %rbx/r11 */
409 case 0x5c: /* pop %rsp/r12 */
410 case 0x5d: /* pop %rbp/r13 */
411 case 0x5e: /* pop %rsi/r14 */
412 case 0x5f: /* pop %rdi/r15 */
413 if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
414 set_int_reg(context, insn - 0x58 + (rex & 1) * 8, val64);
415 context->Rsp += sizeof(ULONG64);
416 pc++;
417 continue;
418 case 0x81: /* add $nnnn,%rsp */
419 if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE;
420 context->Rsp += val32;
421 pc += 2 + sizeof(LONG);
422 continue;
423 case 0x83: /* add $n,%rsp */
424 if (!sw_read_mem(csw, pc + 2, &val8, sizeof(BYTE))) return FALSE;
425 context->Rsp += (signed char)val8;
426 pc += 3;
427 continue;
428 case 0x8d:
429 if (!sw_read_mem(csw, pc + 1, &insn, sizeof(BYTE))) return FALSE;
430 if ((insn >> 6) == 1) /* lea n(reg),%rsp */
432 if (!sw_read_mem(csw, pc + 2, &val8, sizeof(BYTE))) return FALSE;
433 context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + (signed char)val8;
434 pc += 3;
436 else /* lea nnnn(reg),%rsp */
438 if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE;
439 context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + val32;
440 pc += 2 + sizeof(LONG);
442 continue;
443 case 0xc2: /* ret $nn */
444 if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
445 if (!sw_read_mem(csw, pc + 1, &val16, sizeof(WORD))) return FALSE;
446 context->Rip = val64;
447 context->Rsp += sizeof(ULONG64) + val16;
448 return TRUE;
449 case 0xc3: /* ret */
450 case 0xf3: /* rep; ret */
451 if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
452 context->Rip = val64;
453 context->Rsp += sizeof(ULONG64);
454 return TRUE;
455 case 0xe9: /* jmp nnnn */
456 if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE;
457 pc += 5 + val32;
458 continue;
459 case 0xeb: /* jmp n */
460 if (!sw_read_mem(csw, pc + 1, &val8, sizeof(BYTE))) return FALSE;
461 pc += 2 + (signed char)val8;
462 continue;
464 FIXME("unsupported insn %x\n", insn);
465 return FALSE;
469 static BOOL default_unwind(struct cpu_stack_walk* csw, CONTEXT* context)
471 if (!sw_read_mem(csw, context->Rsp, &context->Rip, sizeof(DWORD64)))
473 WARN("Cannot read new frame offset %I64x\n", context->Rsp);
474 return FALSE;
476 context->Rsp += sizeof(DWORD64);
477 return TRUE;
480 static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw,
481 CONTEXT* context, RUNTIME_FUNCTION* function, DWORD64 base)
483 char buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
484 UNWIND_INFO* info = (UNWIND_INFO*)buffer;
485 unsigned i;
486 DWORD64 newframe, prolog_offset, off, value;
487 M128A floatvalue;
488 union handler_data handler_data;
489 BOOL mach_frame = FALSE;
491 /* FIXME: we have some assumptions here */
492 assert(context);
493 dump_unwind_info(csw, sw_module_base(csw, context->Rip), function);
494 newframe = context->Rsp;
495 for (;;)
497 if (!sw_read_mem(csw, base + function->UnwindData, info, sizeof(*info)) ||
498 !sw_read_mem(csw, base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
499 info->UnwindCode, info->CountOfCodes * sizeof(UNWIND_CODE)))
501 WARN("Couldn't read unwind_code at %Ix\n", base + function->UnwindData);
502 return FALSE;
505 if (info->Version != 1 && info->Version != 2)
507 WARN("unknown unwind info version %u at %Ix\n", info->Version, base + function->UnwindData);
508 return FALSE;
511 if (info->FrameRegister)
512 newframe = get_int_reg(context, info->FrameRegister) - info->FrameOffset * 16;
514 /* check if in prolog */
515 if (context->Rip >= base + function->BeginAddress &&
516 context->Rip < base + function->BeginAddress + info->SizeOfProlog)
518 prolog_offset = context->Rip - base - function->BeginAddress;
520 else
522 prolog_offset = ~0;
523 if (is_inside_epilog(csw, context->Rip, base, function))
525 interpret_epilog(csw, context->Rip, context);
526 return TRUE;
530 for (i = 0; i < info->CountOfCodes; i += get_opcode_size(info->UnwindCode[i]))
532 if (prolog_offset < info->UnwindCode[i].CodeOffset) continue; /* skip it */
534 switch (info->UnwindCode[i].UnwindOp)
536 case UWOP_PUSH_NONVOL: /* pushq %reg */
537 if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
538 set_int_reg(context, info->UnwindCode[i].OpInfo, value);
539 context->Rsp += sizeof(ULONG64);
540 break;
541 case UWOP_ALLOC_LARGE: /* subq $nn,%rsp */
542 if (info->UnwindCode[i].OpInfo) context->Rsp += *(DWORD*)&info->UnwindCode[i+1];
543 else context->Rsp += *(USHORT*)&info->UnwindCode[i+1] * 8;
544 break;
545 case UWOP_ALLOC_SMALL: /* subq $n,%rsp */
546 context->Rsp += (info->UnwindCode[i].OpInfo + 1) * 8;
547 break;
548 case UWOP_SET_FPREG: /* leaq nn(%rsp),%framereg */
549 context->Rsp = newframe;
550 break;
551 case UWOP_SAVE_NONVOL: /* movq %reg,n(%rsp) */
552 off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 8;
553 if (!sw_read_mem(csw, off, &value, sizeof(DWORD64))) return FALSE;
554 set_int_reg(context, info->UnwindCode[i].OpInfo, value);
555 break;
556 case UWOP_SAVE_NONVOL_FAR: /* movq %reg,nn(%rsp) */
557 off = newframe + *(DWORD*)&info->UnwindCode[i+1];
558 if (!sw_read_mem(csw, off, &value, sizeof(DWORD64))) return FALSE;
559 set_int_reg(context, info->UnwindCode[i].OpInfo, value);
560 break;
561 case UWOP_SAVE_XMM128: /* movaps %xmmreg,n(%rsp) */
562 off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 16;
563 if (!sw_read_mem(csw, off, &floatvalue, sizeof(M128A))) return FALSE;
564 set_float_reg(context, info->UnwindCode[i].OpInfo, floatvalue);
565 break;
566 case UWOP_SAVE_XMM128_FAR: /* movaps %xmmreg,nn(%rsp) */
567 off = newframe + *(DWORD*)&info->UnwindCode[i+1];
568 if (!sw_read_mem(csw, off, &floatvalue, sizeof(M128A))) return FALSE;
569 set_float_reg(context, info->UnwindCode[i].OpInfo, floatvalue);
570 break;
571 case UWOP_PUSH_MACHFRAME:
572 if (info->Flags & UNW_FLAG_CHAININFO)
574 FIXME("PUSH_MACHFRAME with chained unwind info.\n");
575 break;
577 if (i + get_opcode_size(info->UnwindCode[i]) < info->CountOfCodes)
579 FIXME("PUSH_MACHFRAME is not the last opcode.\n");
580 break;
583 if (info->UnwindCode[i].OpInfo)
584 context->Rsp += 0x8;
586 if (!sw_read_mem(csw, context->Rsp, &context->Rip, sizeof(DWORD64))) return FALSE;
587 if (!sw_read_mem(csw, context->Rsp + 24, &context->Rsp, sizeof(DWORD64))) return FALSE;
588 mach_frame = TRUE;
589 break;
590 case UWOP_EPILOG:
591 if (info->Version == 2)
592 break; /* nothing to do */
593 default:
594 FIXME("unknown code %u\n", info->UnwindCode[i].UnwindOp);
595 break;
598 if (!(info->Flags & UNW_FLAG_CHAININFO)) break;
599 if (!sw_read_mem(csw, base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode) +
600 ((info->CountOfCodes + 1) & ~1) * sizeof(UNWIND_CODE),
601 &handler_data, sizeof(handler_data))) return FALSE;
602 function = &handler_data.chain; /* restart with the chained info */
604 return mach_frame ? TRUE : default_unwind(csw, context);
607 /* fetch_next_frame()
609 * modify (at least) context.{rip, rsp, rbp} using unwind information
610 * either out of PE exception handlers, debug info (dwarf), or simple stack unwind
612 static BOOL fetch_next_frame(struct cpu_stack_walk *csw, union ctx *pcontext,
613 DWORD_PTR curr_pc, void** prtf)
615 DWORD64 cfa;
616 RUNTIME_FUNCTION* rtf;
617 DWORD64 base;
618 CONTEXT *context = &pcontext->ctx;
619 DWORD64 input_Rip = context->Rip;
621 if (!curr_pc || !(base = sw_module_base(csw, curr_pc))) return FALSE;
622 rtf = sw_table_access(csw, curr_pc);
623 if (prtf) *prtf = rtf;
624 if (rtf)
626 return interpret_function_table_entry(csw, context, rtf, base);
628 else if (dwarf2_virtual_unwind(csw, curr_pc, pcontext, &cfa) && input_Rip != context->Rip)
630 context->Rsp = cfa;
631 TRACE("next function rip=%016Ix\n", context->Rip);
632 TRACE(" rax=%016Ix rbx=%016Ix rcx=%016Ix rdx=%016Ix\n",
633 context->Rax, context->Rbx, context->Rcx, context->Rdx);
634 TRACE(" rsi=%016Ix rdi=%016Ix rbp=%016Ix rsp=%016Ix\n",
635 context->Rsi, context->Rdi, context->Rbp, context->Rsp);
636 TRACE(" r8=%016Ix r9=%016Ix r10=%016Ix r11=%016Ix\n",
637 context->R8, context->R9, context->R10, context->R11);
638 TRACE(" r12=%016Ix r13=%016Ix r14=%016Ix r15=%016Ix\n",
639 context->R12, context->R13, context->R14, context->R15);
640 return TRUE;
642 else
643 return default_unwind(csw, context);
646 static BOOL x86_64_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame,
647 union ctx *context)
649 unsigned deltapc = curr_count <= 1 ? 0 : 1;
651 /* sanity check */
652 if (curr_mode >= stm_done) return FALSE;
653 assert(!csw->is32);
655 TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%I64u\n",
656 wine_dbgstr_addr(&frame->AddrPC),
657 wine_dbgstr_addr(&frame->AddrFrame),
658 wine_dbgstr_addr(&frame->AddrReturn),
659 wine_dbgstr_addr(&frame->AddrStack),
660 curr_mode == stm_start ? "start" : "64bit",
661 curr_count);
663 if (curr_mode == stm_start)
665 if ((frame->AddrPC.Mode == AddrModeFlat) &&
666 (frame->AddrFrame.Mode != AddrModeFlat))
668 WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
669 goto done_err;
672 /* Init done */
673 curr_mode = stm_64bit;
674 frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
675 /* don't set up AddrStack on first call. Either the caller has set it up, or
676 * we will get it in the next frame
678 memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
680 else
682 if (context->ctx.Rsp != frame->AddrStack.Offset) FIXME("inconsistent Stack Pointer\n");
683 if (context->ctx.Rip != frame->AddrPC.Offset) FIXME("inconsistent Instruction Pointer\n");
685 if (frame->AddrReturn.Offset == 0) goto done_err;
686 if (!fetch_next_frame(csw, context, frame->AddrPC.Offset - deltapc, &frame->FuncTableEntry))
687 goto done_err;
688 deltapc = 1;
691 memset(&frame->Params, 0, sizeof(frame->Params));
693 /* set frame information */
694 frame->AddrStack.Offset = context->ctx.Rsp;
695 frame->AddrFrame.Offset = context->ctx.Rbp;
696 frame->AddrPC.Offset = context->ctx.Rip;
697 if (1)
699 union ctx newctx = *context;
701 if (!fetch_next_frame(csw, &newctx, frame->AddrPC.Offset - deltapc, NULL))
702 goto done_err;
703 frame->AddrReturn.Mode = AddrModeFlat;
704 frame->AddrReturn.Offset = newctx.ctx.Rip;
707 frame->Far = TRUE;
708 frame->Virtual = TRUE;
709 curr_count++;
711 TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%I64u FuncTable=%p\n",
712 wine_dbgstr_addr(&frame->AddrPC),
713 wine_dbgstr_addr(&frame->AddrFrame),
714 wine_dbgstr_addr(&frame->AddrReturn),
715 wine_dbgstr_addr(&frame->AddrStack),
716 curr_mode == stm_start ? "start" : "64bit",
717 curr_count,
718 frame->FuncTableEntry);
720 return TRUE;
721 done_err:
722 curr_mode = stm_done;
723 return FALSE;
725 #else
726 static BOOL x86_64_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame,
727 union ctx *ctx)
729 return FALSE;
731 #endif
733 static void* x86_64_find_runtime_function(struct module* module, DWORD64 addr)
735 #ifdef __x86_64__
736 RUNTIME_FUNCTION *func = NULL;
737 const RUNTIME_FUNCTION *rtf;
738 ULONG size;
740 rtf = (const RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size);
741 if (rtf)
743 int lo, hi;
745 for (lo = 0, hi = size / sizeof(*rtf); lo <= hi; )
747 int pos = (lo + hi) / 2;
748 if (addr < module->module.BaseOfImage + rtf[pos].BeginAddress) hi = pos - 1;
749 else if (addr >= module->module.BaseOfImage + rtf[pos].EndAddress) lo = pos + 1;
750 else if ((func = fetch_buffer(module->process, sizeof(*func))))
752 *func = rtf[pos];
753 while (func && (func->UnwindData & 1))
755 const BYTE *next = pe_lock_region_from_rva(module, func->UnwindData & ~1, sizeof(*func), NULL);
756 if (next)
758 *func = *(const RUNTIME_FUNCTION *)next;
759 pe_unlock_region(module, next);
761 else
763 WARN("Couldn't find chained RUNTIME_FUNCTION\n");
764 func = NULL;
767 break;
770 pe_unmap_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, (const char*)rtf);
772 return func;
773 #else
774 return NULL;
775 #endif
778 static unsigned x86_64_map_dwarf_register(unsigned regno, const struct module* module, BOOL eh_frame)
780 unsigned reg;
782 if (regno >= 17 && regno <= 24)
783 reg = CV_AMD64_XMM0 + regno - 17;
784 else if (regno >= 25 && regno <= 32)
785 reg = CV_AMD64_XMM8 + regno - 25;
786 else if (regno >= 33 && regno <= 40)
787 reg = CV_AMD64_ST0 + regno - 33;
788 else switch (regno)
790 case 0: reg = CV_AMD64_RAX; break;
791 case 1: reg = CV_AMD64_RDX; break;
792 case 2: reg = CV_AMD64_RCX; break;
793 case 3: reg = CV_AMD64_RBX; break;
794 case 4: reg = CV_AMD64_RSI; break;
795 case 5: reg = CV_AMD64_RDI; break;
796 case 6: reg = CV_AMD64_RBP; break;
797 case 7: reg = CV_AMD64_RSP; break;
798 case 8: reg = CV_AMD64_R8; break;
799 case 9: reg = CV_AMD64_R9; break;
800 case 10: reg = CV_AMD64_R10; break;
801 case 11: reg = CV_AMD64_R11; break;
802 case 12: reg = CV_AMD64_R12; break;
803 case 13: reg = CV_AMD64_R13; break;
804 case 14: reg = CV_AMD64_R14; break;
805 case 15: reg = CV_AMD64_R15; break;
806 case 16: reg = CV_AMD64_RIP; break;
807 case 49: reg = CV_AMD64_EFLAGS; break;
808 case 50: reg = CV_AMD64_ES; break;
809 case 51: reg = CV_AMD64_CS; break;
810 case 52: reg = CV_AMD64_SS; break;
811 case 53: reg = CV_AMD64_DS; break;
812 case 54: reg = CV_AMD64_FS; break;
813 case 55: reg = CV_AMD64_GS; break;
814 case 62: reg = CV_AMD64_TR; break;
815 case 63: reg = CV_AMD64_LDTR; break;
816 case 64: reg = CV_AMD64_MXCSR; break;
817 case 65: reg = CV_AMD64_CTRL; break;
818 case 66: reg = CV_AMD64_STAT; break;
820 * 56-57 reserved
821 * 58 %fs.base
822 * 59 %gs.base
823 * 60-61 reserved
825 default:
826 FIXME("Don't know how to map register %d\n", regno);
827 return 0;
829 return reg;
832 static void *x86_64_fetch_context_reg(union ctx *pctx, unsigned regno, unsigned *size)
834 #ifdef __x86_64__
835 CONTEXT *ctx = &pctx->ctx;
837 switch (regno)
839 case CV_AMD64_RAX: *size = sizeof(ctx->Rax); return &ctx->Rax;
840 case CV_AMD64_RDX: *size = sizeof(ctx->Rdx); return &ctx->Rdx;
841 case CV_AMD64_RCX: *size = sizeof(ctx->Rcx); return &ctx->Rcx;
842 case CV_AMD64_RBX: *size = sizeof(ctx->Rbx); return &ctx->Rbx;
843 case CV_AMD64_RSI: *size = sizeof(ctx->Rsi); return &ctx->Rsi;
844 case CV_AMD64_RDI: *size = sizeof(ctx->Rdi); return &ctx->Rdi;
845 case CV_AMD64_RBP: *size = sizeof(ctx->Rbp); return &ctx->Rbp;
846 case CV_AMD64_RSP: *size = sizeof(ctx->Rsp); return &ctx->Rsp;
847 case CV_AMD64_R8: *size = sizeof(ctx->R8); return &ctx->R8;
848 case CV_AMD64_R9: *size = sizeof(ctx->R9); return &ctx->R9;
849 case CV_AMD64_R10: *size = sizeof(ctx->R10); return &ctx->R10;
850 case CV_AMD64_R11: *size = sizeof(ctx->R11); return &ctx->R11;
851 case CV_AMD64_R12: *size = sizeof(ctx->R12); return &ctx->R12;
852 case CV_AMD64_R13: *size = sizeof(ctx->R13); return &ctx->R13;
853 case CV_AMD64_R14: *size = sizeof(ctx->R14); return &ctx->R14;
854 case CV_AMD64_R15: *size = sizeof(ctx->R15); return &ctx->R15;
855 case CV_AMD64_RIP: *size = sizeof(ctx->Rip); return &ctx->Rip;
857 case CV_AMD64_XMM0 + 0: *size = sizeof(ctx->Xmm0 ); return &ctx->Xmm0;
858 case CV_AMD64_XMM0 + 1: *size = sizeof(ctx->Xmm1 ); return &ctx->Xmm1;
859 case CV_AMD64_XMM0 + 2: *size = sizeof(ctx->Xmm2 ); return &ctx->Xmm2;
860 case CV_AMD64_XMM0 + 3: *size = sizeof(ctx->Xmm3 ); return &ctx->Xmm3;
861 case CV_AMD64_XMM0 + 4: *size = sizeof(ctx->Xmm4 ); return &ctx->Xmm4;
862 case CV_AMD64_XMM0 + 5: *size = sizeof(ctx->Xmm5 ); return &ctx->Xmm5;
863 case CV_AMD64_XMM0 + 6: *size = sizeof(ctx->Xmm6 ); return &ctx->Xmm6;
864 case CV_AMD64_XMM0 + 7: *size = sizeof(ctx->Xmm7 ); return &ctx->Xmm7;
865 case CV_AMD64_XMM8 + 0: *size = sizeof(ctx->Xmm8 ); return &ctx->Xmm8;
866 case CV_AMD64_XMM8 + 1: *size = sizeof(ctx->Xmm9 ); return &ctx->Xmm9;
867 case CV_AMD64_XMM8 + 2: *size = sizeof(ctx->Xmm10); return &ctx->Xmm10;
868 case CV_AMD64_XMM8 + 3: *size = sizeof(ctx->Xmm11); return &ctx->Xmm11;
869 case CV_AMD64_XMM8 + 4: *size = sizeof(ctx->Xmm12); return &ctx->Xmm12;
870 case CV_AMD64_XMM8 + 5: *size = sizeof(ctx->Xmm13); return &ctx->Xmm13;
871 case CV_AMD64_XMM8 + 6: *size = sizeof(ctx->Xmm14); return &ctx->Xmm14;
872 case CV_AMD64_XMM8 + 7: *size = sizeof(ctx->Xmm15); return &ctx->Xmm15;
874 case CV_AMD64_ST0 + 0: *size = sizeof(ctx->Legacy[0]); return &ctx->Legacy[0];
875 case CV_AMD64_ST0 + 1: *size = sizeof(ctx->Legacy[1]); return &ctx->Legacy[1];
876 case CV_AMD64_ST0 + 2: *size = sizeof(ctx->Legacy[2]); return &ctx->Legacy[2];
877 case CV_AMD64_ST0 + 3: *size = sizeof(ctx->Legacy[3]); return &ctx->Legacy[3];
878 case CV_AMD64_ST0 + 4: *size = sizeof(ctx->Legacy[4]); return &ctx->Legacy[4];
879 case CV_AMD64_ST0 + 5: *size = sizeof(ctx->Legacy[5]); return &ctx->Legacy[5];
880 case CV_AMD64_ST0 + 6: *size = sizeof(ctx->Legacy[6]); return &ctx->Legacy[6];
881 case CV_AMD64_ST0 + 7: *size = sizeof(ctx->Legacy[7]); return &ctx->Legacy[7];
883 case CV_AMD64_EFLAGS: *size = sizeof(ctx->EFlags); return &ctx->EFlags;
884 case CV_AMD64_ES: *size = sizeof(ctx->SegEs); return &ctx->SegEs;
885 case CV_AMD64_CS: *size = sizeof(ctx->SegCs); return &ctx->SegCs;
886 case CV_AMD64_SS: *size = sizeof(ctx->SegSs); return &ctx->SegSs;
887 case CV_AMD64_DS: *size = sizeof(ctx->SegDs); return &ctx->SegDs;
888 case CV_AMD64_FS: *size = sizeof(ctx->SegFs); return &ctx->SegFs;
889 case CV_AMD64_GS: *size = sizeof(ctx->SegGs); return &ctx->SegGs;
892 #endif
893 FIXME("Unknown register %x\n", regno);
894 return NULL;
897 static const char* x86_64_fetch_regname(unsigned regno)
899 switch (regno)
901 case CV_AMD64_RAX: return "rax";
902 case CV_AMD64_RDX: return "rdx";
903 case CV_AMD64_RCX: return "rcx";
904 case CV_AMD64_RBX: return "rbx";
905 case CV_AMD64_RSI: return "rsi";
906 case CV_AMD64_RDI: return "rdi";
907 case CV_AMD64_RBP: return "rbp";
908 case CV_AMD64_RSP: return "rsp";
909 case CV_AMD64_R8: return "r8";
910 case CV_AMD64_R9: return "r9";
911 case CV_AMD64_R10: return "r10";
912 case CV_AMD64_R11: return "r11";
913 case CV_AMD64_R12: return "r12";
914 case CV_AMD64_R13: return "r13";
915 case CV_AMD64_R14: return "r14";
916 case CV_AMD64_R15: return "r15";
917 case CV_AMD64_RIP: return "rip";
919 case CV_AMD64_XMM0 + 0: return "xmm0";
920 case CV_AMD64_XMM0 + 1: return "xmm1";
921 case CV_AMD64_XMM0 + 2: return "xmm2";
922 case CV_AMD64_XMM0 + 3: return "xmm3";
923 case CV_AMD64_XMM0 + 4: return "xmm4";
924 case CV_AMD64_XMM0 + 5: return "xmm5";
925 case CV_AMD64_XMM0 + 6: return "xmm6";
926 case CV_AMD64_XMM0 + 7: return "xmm7";
927 case CV_AMD64_XMM8 + 0: return "xmm8";
928 case CV_AMD64_XMM8 + 1: return "xmm9";
929 case CV_AMD64_XMM8 + 2: return "xmm10";
930 case CV_AMD64_XMM8 + 3: return "xmm11";
931 case CV_AMD64_XMM8 + 4: return "xmm12";
932 case CV_AMD64_XMM8 + 5: return "xmm13";
933 case CV_AMD64_XMM8 + 6: return "xmm14";
934 case CV_AMD64_XMM8 + 7: return "xmm15";
936 case CV_AMD64_ST0 + 0: return "st0";
937 case CV_AMD64_ST0 + 1: return "st1";
938 case CV_AMD64_ST0 + 2: return "st2";
939 case CV_AMD64_ST0 + 3: return "st3";
940 case CV_AMD64_ST0 + 4: return "st4";
941 case CV_AMD64_ST0 + 5: return "st5";
942 case CV_AMD64_ST0 + 6: return "st6";
943 case CV_AMD64_ST0 + 7: return "st7";
945 case CV_AMD64_EFLAGS: return "eflags";
946 case CV_AMD64_ES: return "es";
947 case CV_AMD64_CS: return "cs";
948 case CV_AMD64_SS: return "ss";
949 case CV_AMD64_DS: return "ds";
950 case CV_AMD64_FS: return "fs";
951 case CV_AMD64_GS: return "gs";
953 FIXME("Unknown register %x\n", regno);
954 return NULL;
957 static BOOL x86_64_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
959 if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
961 /* FIXME: crop values across module boundaries, */
962 #ifdef __x86_64__
963 ULONG64 base = ctx->Rip <= 0x80 ? 0 : ctx->Rip - 0x80;
964 minidump_add_memory_block(dc, base, ctx->Rip + 0x80 - base, 0);
965 #endif
968 return TRUE;
971 static BOOL x86_64_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
973 return FALSE;
976 struct cpu cpu_x86_64 = {
977 IMAGE_FILE_MACHINE_AMD64,
979 CV_AMD64_RSP,
980 x86_64_get_addr,
981 x86_64_stack_walk,
982 x86_64_find_runtime_function,
983 x86_64_map_dwarf_register,
984 x86_64_fetch_context_reg,
985 x86_64_fetch_regname,
986 x86_64_fetch_minidump_thread,
987 x86_64_fetch_minidump_module,