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