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