ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cpu_x86_64.c
Go to the documentation of this file.
00001 /*
00002  * File cpu_x86_64.c
00003  *
00004  * Copyright (C) 1999, 2005 Alexandre Julliard
00005  * Copyright (C) 2009       Eric Pouech.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include <assert.h>
00023 
00024 #define NONAMELESSUNION
00025 #define NONAMELESSSTRUCT
00026 #include "ntstatus.h"
00027 #define WIN32_NO_STATUS
00028 #include "dbghelp_private.h"
00029 #include "winternl.h"
00030 #include "wine/debug.h"
00031 
00032 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
00033 
00034 /* x86-64 unwind information, for PE modules, as described on MSDN */
00035 
00036 typedef enum _UNWIND_OP_CODES
00037 {
00038     UWOP_PUSH_NONVOL = 0,
00039     UWOP_ALLOC_LARGE,
00040     UWOP_ALLOC_SMALL,
00041     UWOP_SET_FPREG,
00042     UWOP_SAVE_NONVOL,
00043     UWOP_SAVE_NONVOL_FAR,
00044     UWOP_SAVE_XMM128,
00045     UWOP_SAVE_XMM128_FAR,
00046     UWOP_PUSH_MACHFRAME
00047 } UNWIND_CODE_OPS;
00048 
00049 typedef union _UNWIND_CODE
00050 {
00051     struct
00052     {
00053         BYTE CodeOffset;
00054         BYTE UnwindOp : 4;
00055         BYTE OpInfo   : 4;
00056     };
00057     USHORT FrameOffset;
00058 } UNWIND_CODE, *PUNWIND_CODE;
00059 
00060 typedef struct _UNWIND_INFO
00061 {
00062     BYTE Version       : 3;
00063     BYTE Flags         : 5;
00064     BYTE SizeOfProlog;
00065     BYTE CountOfCodes;
00066     BYTE FrameRegister : 4;
00067     BYTE FrameOffset   : 4;
00068     UNWIND_CODE UnwindCode[1]; /* actually CountOfCodes (aligned) */
00069 /*
00070  *  union
00071  *  {
00072  *      OPTIONAL ULONG ExceptionHandler;
00073  *      OPTIONAL ULONG FunctionEntry;
00074  *  };
00075  *  OPTIONAL ULONG ExceptionData[];
00076  */
00077 } UNWIND_INFO, *PUNWIND_INFO;
00078 
00079 #define GetUnwindCodeEntry(info, index) \
00080     ((info)->UnwindCode[index])
00081 
00082 #define GetLanguageSpecificDataPtr(info) \
00083     ((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))
00084 
00085 #define GetExceptionHandler(base, info) \
00086     ((PEXCEPTION_HANDLER)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
00087 
00088 #define GetChainedFunctionEntry(base, info) \
00089     ((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))
00090 
00091 #define GetExceptionDataPtr(info) \
00092     ((PVOID)((PULONG)GetLanguageSpecificData(info) + 1)
00093 
00094 static unsigned x86_64_get_addr(HANDLE hThread, const CONTEXT* ctx,
00095                                 enum cpu_addr ca, ADDRESS64* addr)
00096 {
00097     addr->Mode = AddrModeFlat;
00098     switch (ca)
00099     {
00100 #ifdef __x86_64__
00101     case cpu_addr_pc:    addr->Segment = ctx->SegCs; addr->Offset = ctx->Rip; return TRUE;
00102     case cpu_addr_stack: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rsp; return TRUE;
00103     case cpu_addr_frame: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rbp; return TRUE;
00104 #endif
00105     default: addr->Mode = -1;
00106         return FALSE;
00107     }
00108 }
00109 
00110 enum st_mode {stm_start, stm_64bit, stm_done};
00111 
00112 /* indexes in Reserved array */
00113 #define __CurrentMode     0
00114 #define __CurrentCount    1
00115 /* #define __     2 (unused) */
00116 
00117 #define curr_mode   (frame->Reserved[__CurrentMode])
00118 #define curr_count  (frame->Reserved[__CurrentCount])
00119 /* #define ??? (frame->Reserved[__]) (unused) */
00120 
00121 #ifdef __x86_64__
00122 union handler_data
00123 {
00124     RUNTIME_FUNCTION chain;
00125     ULONG handler;
00126 };
00127 
00128 static void dump_unwind_info(HANDLE hProcess, ULONG64 base, RUNTIME_FUNCTION *function)
00129 {
00130     static const char * const reg_names[16] =
00131         { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
00132           "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15" };
00133 
00134     union handler_data *handler_data;
00135     char buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
00136     UNWIND_INFO* info = (UNWIND_INFO*)buffer;
00137     unsigned int i, count;
00138     SIZE_T r;
00139 
00140     TRACE("**** func %x-%x\n", function->BeginAddress, function->EndAddress);
00141     for (;;)
00142     {
00143         if (function->UnwindData & 1)
00144         {
00145 #if 0
00146             RUNTIME_FUNCTION *next = (RUNTIME_FUNCTION*)((char*)base + (function->UnwindData & ~1));
00147             TRACE("unwind info for function %p-%p chained to function %p-%p\n",
00148                   (char*)base + function->BeginAddress, (char*)base + function->EndAddress,
00149                   (char*)base + next->BeginAddress, (char*)base + next->EndAddress);
00150             function = next;
00151             continue;
00152 #else
00153             FIXME("NOT SUPPORTED\n");
00154 #endif
00155         }
00156         ReadProcessMemory(hProcess, (char*)base + function->UnwindData, info, sizeof(*info), &r);
00157         ReadProcessMemory(hProcess, (char*)base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
00158                           info->UnwindCode, 256 * sizeof(UNWIND_CODE), &r);
00159         TRACE("unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
00160               info, info->Flags, info->SizeOfProlog,
00161               (char*)base + function->BeginAddress, (char*)base + function->EndAddress);
00162 
00163         if (info->FrameRegister)
00164             TRACE("    frame register %s offset 0x%x(%%rsp)\n",
00165                   reg_names[info->FrameRegister], info->FrameOffset * 16);
00166 
00167         for (i = 0; i < info->CountOfCodes; i++)
00168         {
00169             TRACE("    0x%x: ", info->UnwindCode[i].CodeOffset);
00170             switch (info->UnwindCode[i].UnwindOp)
00171             {
00172             case UWOP_PUSH_NONVOL:
00173                 TRACE("pushq %%%s\n", reg_names[info->UnwindCode[i].OpInfo]);
00174                 break;
00175             case UWOP_ALLOC_LARGE:
00176                 if (info->UnwindCode[i].OpInfo)
00177                 {
00178                     count = *(DWORD*)&info->UnwindCode[i+1];
00179                     i += 2;
00180                 }
00181                 else
00182                 {
00183                     count = *(USHORT*)&info->UnwindCode[i+1] * 8;
00184                     i++;
00185                 }
00186                 TRACE("subq $0x%x,%%rsp\n", count);
00187                 break;
00188             case UWOP_ALLOC_SMALL:
00189                 count = (info->UnwindCode[i].OpInfo + 1) * 8;
00190                 TRACE("subq $0x%x,%%rsp\n", count);
00191                 break;
00192             case UWOP_SET_FPREG:
00193                 TRACE("leaq 0x%x(%%rsp),%s\n",
00194                       info->FrameOffset * 16, reg_names[info->FrameRegister]);
00195                 break;
00196             case UWOP_SAVE_NONVOL:
00197                 count = *(USHORT*)&info->UnwindCode[i+1] * 8;
00198                 TRACE("movq %%%s,0x%x(%%rsp)\n", reg_names[info->UnwindCode[i].OpInfo], count);
00199                 i++;
00200                 break;
00201             case UWOP_SAVE_NONVOL_FAR:
00202                 count = *(DWORD*)&info->UnwindCode[i+1];
00203                 TRACE("movq %%%s,0x%x(%%rsp)\n", reg_names[info->UnwindCode[i].OpInfo], count);
00204                 i += 2;
00205                 break;
00206             case UWOP_SAVE_XMM128:
00207                 count = *(USHORT*)&info->UnwindCode[i+1] * 16;
00208                 TRACE("movaps %%xmm%u,0x%x(%%rsp)\n", info->UnwindCode[i].OpInfo, count);
00209                 i++;
00210                 break;
00211             case UWOP_SAVE_XMM128_FAR:
00212                 count = *(DWORD*)&info->UnwindCode[i+1];
00213                 TRACE("movaps %%xmm%u,0x%x(%%rsp)\n", info->UnwindCode[i].OpInfo, count);
00214                 i += 2;
00215                 break;
00216             case UWOP_PUSH_MACHFRAME:
00217                 TRACE("PUSH_MACHFRAME %u\n", info->UnwindCode[i].OpInfo);
00218                 break;
00219             default:
00220                 FIXME("unknown code %u\n", info->UnwindCode[i].UnwindOp);
00221                 break;
00222             }
00223         }
00224 
00225         handler_data = (union handler_data*)&info->UnwindCode[(info->CountOfCodes + 1) & ~1];
00226         if (info->Flags & UNW_FLAG_CHAININFO)
00227         {
00228             TRACE("    chained to function %p-%p\n",
00229                   (char*)base + handler_data->chain.BeginAddress,
00230                   (char*)base + handler_data->chain.EndAddress);
00231             function = &handler_data->chain;
00232             continue;
00233         }
00234         if (info->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
00235             TRACE("    handler %p data at %p\n",
00236                   (char*)base + handler_data->handler, &handler_data->handler + 1);
00237         break;
00238     }
00239 }
00240 
00241 /* highly derived from dlls/ntdll/signal_x86_64.c */
00242 static ULONG64 get_int_reg(CONTEXT *context, int reg)
00243 {
00244     return *(&context->Rax + reg);
00245 }
00246 
00247 static void set_int_reg(CONTEXT *context, int reg, ULONG64 val)
00248 {
00249     *(&context->Rax + reg) = val;
00250 }
00251 
00252 static void set_float_reg(CONTEXT *context, int reg, M128A val)
00253 {
00254     *(&context->u.s.Xmm0 + reg) = val;
00255 }
00256 
00257 static int get_opcode_size(UNWIND_CODE op)
00258 {
00259     switch (op.UnwindOp)
00260     {
00261     case UWOP_ALLOC_LARGE:
00262         return 2 + (op.OpInfo != 0);
00263     case UWOP_SAVE_NONVOL:
00264     case UWOP_SAVE_XMM128:
00265         return 2;
00266     case UWOP_SAVE_NONVOL_FAR:
00267     case UWOP_SAVE_XMM128_FAR:
00268         return 3;
00269     default:
00270         return 1;
00271     }
00272 }
00273 
00274 static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc)
00275 {
00276     BYTE        op0, op1, op2;
00277 
00278     if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
00279 
00280     /* add or lea must be the first instruction, and it must have a rex.W prefix */
00281     if ((op0 & 0xf8) == 0x48)
00282     {
00283         if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
00284         if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
00285         switch (op1)
00286         {
00287         case 0x81: /* add $nnnn,%rsp */
00288             if (op0 == 0x48 && op2 == 0xc4)
00289             {
00290                 pc += 7;
00291                 break;
00292             }
00293             return FALSE;
00294         case 0x83: /* add $n,%rsp */
00295             if (op0 == 0x48 && op2 == 0xc4)
00296             {
00297                 pc += 4;
00298                 break;
00299             }
00300             return FALSE;
00301         case 0x8d: /* lea n(reg),%rsp */
00302             if (op0 & 0x06) return FALSE;  /* rex.RX must be cleared */
00303             if (((op2 >> 3) & 7) != 4) return FALSE;  /* dest reg mus be %rsp */
00304             if ((op2 & 7) == 4) return FALSE;  /* no SIB byte allowed */
00305             if ((op2 >> 6) == 1)  /* 8-bit offset */
00306             {
00307                 pc += 4;
00308                 break;
00309             }
00310             if ((op2 >> 6) == 2)  /* 32-bit offset */
00311             {
00312                 pc += 7;
00313                 break;
00314             }
00315             return FALSE;
00316         }
00317     }
00318 
00319     /* now check for various pop instructions */
00320     for (;;)
00321     {
00322         BYTE rex = 0;
00323 
00324         if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
00325         if ((op0 & 0xf0) == 0x40)
00326         {
00327             rex = op0 & 0x0f;  /* rex prefix */
00328             if (!sw_read_mem(csw, ++pc, &op0, 1)) return FALSE;
00329         }
00330 
00331         switch (op0)
00332         {
00333         case 0x58: /* pop %rax/%r8 */
00334         case 0x59: /* pop %rcx/%r9 */
00335         case 0x5a: /* pop %rdx/%r10 */
00336         case 0x5b: /* pop %rbx/%r11 */
00337         case 0x5c: /* pop %rsp/%r12 */
00338         case 0x5d: /* pop %rbp/%r13 */
00339         case 0x5e: /* pop %rsi/%r14 */
00340         case 0x5f: /* pop %rdi/%r15 */
00341             pc++;
00342             continue;
00343         case 0xc2: /* ret $nn */
00344         case 0xc3: /* ret */
00345             return TRUE;
00346         /* FIXME: add various jump instructions */
00347         }
00348         return FALSE;
00349     }
00350 }
00351 
00352 static BOOL default_unwind(struct cpu_stack_walk* csw, CONTEXT* context)
00353 {
00354     if (!sw_read_mem(csw, context->Rsp, &context->Rip, sizeof(DWORD64)))
00355     {
00356         WARN("Cannot read new frame offset %s\n", wine_dbgstr_longlong(context->Rsp));
00357         return FALSE;
00358     }
00359     context->Rsp += sizeof(DWORD64);
00360     return TRUE;
00361 }
00362 
00363 static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw,
00364                                            CONTEXT* context, RUNTIME_FUNCTION* function, DWORD64 base)
00365 {
00366     char                buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
00367     UNWIND_INFO*        info = (UNWIND_INFO*)buffer;
00368     unsigned            i;
00369     DWORD64             newframe, prolog_offset, off, value;
00370     M128A               floatvalue;
00371     union handler_data  handler_data;
00372 
00373     /* FIXME: we have some assumptions here */
00374     assert(context);
00375     dump_unwind_info(csw->hProcess, sw_module_base(csw, context->Rip), function);
00376     newframe = context->Rsp;
00377     for (;;)
00378     {
00379         if (!sw_read_mem(csw, base + function->UnwindData, info, sizeof(*info)) ||
00380             !sw_read_mem(csw, base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
00381                          info->UnwindCode, info->CountOfCodes * sizeof(UNWIND_CODE)))
00382         {
00383             WARN("Couldn't read unwind_code at %lx\n", base + function->UnwindData);
00384             return FALSE;
00385         }
00386 
00387         if (info->Version != 1)
00388         {
00389             WARN("unknown unwind info version %u at %lx\n", info->Version, base + function->UnwindData);
00390             return FALSE;
00391         }
00392 
00393         if (info->FrameRegister)
00394             newframe = get_int_reg(context, info->FrameRegister) - info->FrameOffset * 16;
00395 
00396         /* check if in prolog */
00397         if (context->Rip >= base + function->BeginAddress &&
00398             context->Rip < base + function->BeginAddress + info->SizeOfProlog)
00399         {
00400             prolog_offset = context->Rip - base - function->BeginAddress;
00401         }
00402         else
00403         {
00404             prolog_offset = ~0;
00405             if (is_inside_epilog(csw, context->Rip))
00406             {
00407                 FIXME("epilog management not fully done\n");
00408                 /* interpret_epilog((const BYTE*)frame->AddrPC.Offset, context); */
00409                 return TRUE;
00410             }
00411         }
00412 
00413         for (i = 0; i < info->CountOfCodes; i += get_opcode_size(info->UnwindCode[i]))
00414         {
00415             if (prolog_offset < info->UnwindCode[i].CodeOffset) continue; /* skip it */
00416 
00417             switch (info->UnwindCode[i].UnwindOp)
00418             {
00419             case UWOP_PUSH_NONVOL:  /* pushq %reg */
00420                 if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
00421                 set_int_reg(context, info->UnwindCode[i].OpInfo, value);
00422                 context->Rsp += sizeof(ULONG64);
00423                 break;
00424             case UWOP_ALLOC_LARGE:  /* subq $nn,%rsp */
00425                 if (info->UnwindCode[i].OpInfo) context->Rsp += *(DWORD*)&info->UnwindCode[i+1];
00426                 else context->Rsp += *(USHORT*)&info->UnwindCode[i+1] * 8;
00427                 break;
00428             case UWOP_ALLOC_SMALL:  /* subq $n,%rsp */
00429                 context->Rsp += (info->UnwindCode[i].OpInfo + 1) * 8;
00430                 break;
00431             case UWOP_SET_FPREG:  /* leaq nn(%rsp),%framereg */
00432                 context->Rsp = newframe;
00433                 break;
00434             case UWOP_SAVE_NONVOL:  /* movq %reg,n(%rsp) */
00435                 off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 8;
00436                 if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
00437                 set_int_reg(context, info->UnwindCode[i].OpInfo, value);
00438                 break;
00439             case UWOP_SAVE_NONVOL_FAR:  /* movq %reg,nn(%rsp) */
00440                 off = newframe + *(DWORD*)&info->UnwindCode[i+1];
00441                 if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
00442                 set_int_reg(context, info->UnwindCode[i].OpInfo, value);
00443                 break;
00444             case UWOP_SAVE_XMM128:  /* movaps %xmmreg,n(%rsp) */
00445                 off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 16;
00446                 if (!sw_read_mem(csw, context->Rsp, &floatvalue, sizeof(M128A))) return FALSE;
00447                 set_float_reg(context, info->UnwindCode[i].OpInfo, floatvalue);
00448                 break;
00449             case UWOP_SAVE_XMM128_FAR:  /* movaps %xmmreg,nn(%rsp) */
00450                 off = newframe + *(DWORD*)&info->UnwindCode[i+1];
00451                 if (!sw_read_mem(csw, context->Rsp, &floatvalue, sizeof(M128A))) return FALSE;
00452                 set_float_reg(context, info->UnwindCode[i].OpInfo, floatvalue);
00453                 break;
00454             case UWOP_PUSH_MACHFRAME:
00455                 FIXME("PUSH_MACHFRAME %u\n", info->UnwindCode[i].OpInfo);
00456                 break;
00457             default:
00458                 FIXME("unknown code %u\n", info->UnwindCode[i].UnwindOp);
00459                 break;
00460             }
00461         }
00462         if (!(info->Flags & UNW_FLAG_CHAININFO)) break;
00463         if (!sw_read_mem(csw, base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode) +
00464                                    ((info->CountOfCodes + 1) & ~1) * sizeof(UNWIND_CODE),
00465                          &handler_data, sizeof(handler_data))) return FALSE;
00466         function = &handler_data.chain;  /* restart with the chained info */
00467     }
00468     return default_unwind(csw, context);
00469 }
00470 
00471 /* fetch_next_frame()
00472  *
00473  * modify (at least) context.{rip, rsp, rbp} using unwind information
00474  * either out of PE exception handlers, debug info (dwarf), or simple stack unwind
00475  */
00476 static BOOL fetch_next_frame(struct cpu_stack_walk* csw, CONTEXT* context,
00477                              DWORD_PTR curr_pc, void** prtf)
00478 {
00479     DWORD_PTR               cfa;
00480     RUNTIME_FUNCTION*       rtf;
00481     DWORD64                 base;
00482 
00483     if (!curr_pc || !(base = sw_module_base(csw, curr_pc))) return FALSE;
00484     rtf = sw_table_access(csw, curr_pc);
00485     if (prtf) *prtf = rtf;
00486     if (rtf)
00487     {
00488         return interpret_function_table_entry(csw, context, rtf, base);
00489     }
00490     else if (dwarf2_virtual_unwind(csw, curr_pc, context, &cfa))
00491     {
00492         context->Rsp = cfa;
00493         TRACE("next function rip=%016lx\n", context->Rip);
00494         TRACE("  rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
00495               context->Rax, context->Rbx, context->Rcx, context->Rdx);
00496         TRACE("  rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
00497               context->Rsi, context->Rdi, context->Rbp, context->Rsp);
00498         TRACE("   r8=%016lx  r9=%016lx r10=%016lx r11=%016lx\n",
00499               context->R8, context->R9, context->R10, context->R11);
00500         TRACE("  r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
00501               context->R12, context->R13, context->R14, context->R15);
00502         return TRUE;
00503     }
00504     else
00505         return default_unwind(csw, context);
00506 }
00507 
00508 static BOOL x86_64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CONTEXT* context)
00509 {
00510     unsigned    deltapc = curr_count <= 1 ? 0 : 1;
00511 
00512     /* sanity check */
00513     if (curr_mode >= stm_done) return FALSE;
00514     assert(!csw->is32);
00515 
00516     TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s\n",
00517           wine_dbgstr_addr(&frame->AddrPC),
00518           wine_dbgstr_addr(&frame->AddrFrame),
00519           wine_dbgstr_addr(&frame->AddrReturn),
00520           wine_dbgstr_addr(&frame->AddrStack),
00521           curr_mode == stm_start ? "start" : "64bit",
00522           wine_dbgstr_longlong(curr_count));
00523 
00524     if (curr_mode == stm_start)
00525     {
00526         if ((frame->AddrPC.Mode == AddrModeFlat) &&
00527             (frame->AddrFrame.Mode != AddrModeFlat))
00528         {
00529             WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
00530             goto done_err;
00531         }
00532 
00533         /* Init done */
00534         curr_mode = stm_64bit;
00535         frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
00536         /* don't set up AddrStack on first call. Either the caller has set it up, or
00537          * we will get it in the next frame
00538          */
00539         memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
00540     }
00541     else
00542     {
00543         if (context->Rsp != frame->AddrStack.Offset) FIXME("inconsistent Stack Pointer\n");
00544         if (context->Rip != frame->AddrPC.Offset) FIXME("inconsistent Instruction Pointer\n");
00545 
00546         if (frame->AddrReturn.Offset == 0) goto done_err;
00547         if (!fetch_next_frame(csw, context, frame->AddrPC.Offset - deltapc, &frame->FuncTableEntry))
00548             goto done_err;
00549         deltapc = 1;
00550     }
00551 
00552     memset(&frame->Params, 0, sizeof(frame->Params));
00553 
00554     /* set frame information */
00555     frame->AddrStack.Offset = context->Rsp;
00556     frame->AddrFrame.Offset = context->Rbp;
00557     frame->AddrPC.Offset = context->Rip;
00558     if (1)
00559     {
00560         CONTEXT         newctx = *context;
00561 
00562         if (!fetch_next_frame(csw, &newctx, frame->AddrPC.Offset - deltapc, NULL))
00563             goto done_err;
00564         frame->AddrReturn.Mode = AddrModeFlat;
00565         frame->AddrReturn.Offset = newctx.Rip;
00566     }
00567 
00568     frame->Far = TRUE;
00569     frame->Virtual = TRUE;
00570     curr_count++;
00571 
00572     TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s FuncTable=%p\n",
00573           wine_dbgstr_addr(&frame->AddrPC),
00574           wine_dbgstr_addr(&frame->AddrFrame),
00575           wine_dbgstr_addr(&frame->AddrReturn),
00576           wine_dbgstr_addr(&frame->AddrStack),
00577           curr_mode == stm_start ? "start" : "64bit",
00578           wine_dbgstr_longlong(curr_count),
00579           frame->FuncTableEntry);
00580 
00581     return TRUE;
00582 done_err:
00583     curr_mode = stm_done;
00584     return FALSE;
00585 }
00586 #else
00587 static BOOL x86_64_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CONTEXT* context)
00588 {
00589     return FALSE;
00590 }
00591 #endif
00592 
00593 static void*    x86_64_find_runtime_function(struct module* module, DWORD64 addr)
00594 {
00595 #ifdef __x86_64__
00596     RUNTIME_FUNCTION*   rtf;
00597     ULONG               size;
00598     int                 min, max;
00599 
00600     rtf = (RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size);
00601     if (rtf) for (min = 0, max = size / sizeof(*rtf); min <= max; )
00602     {
00603         int pos = (min + max) / 2;
00604         if (addr < module->module.BaseOfImage + rtf[pos].BeginAddress) max = pos - 1;
00605         else if (addr >= module->module.BaseOfImage + rtf[pos].EndAddress) min = pos + 1;
00606         else
00607         {
00608             rtf += pos;
00609             while (rtf->UnwindData & 1)  /* follow chained entry */
00610             {
00611                 FIXME("RunTime_Function outside IMAGE_DIRECTORY_ENTRY_EXCEPTION unimplemented yet!\n");
00612                 /* we need to read into the other process */
00613                 /* rtf = (RUNTIME_FUNCTION*)(module->module.BaseOfImage + (rtf->UnwindData & ~1)); */
00614             }
00615             return rtf;
00616         }
00617     }
00618 #endif
00619     return NULL;
00620 }
00621 
00622 static unsigned x86_64_map_dwarf_register(unsigned regno)
00623 {
00624     unsigned    reg;
00625 
00626     if (regno >= 17 && regno <= 24)
00627         reg = CV_AMD64_XMM0 + regno - 17;
00628     else if (regno >= 25 && regno <= 32)
00629         reg = CV_AMD64_XMM8 + regno - 25;
00630     else if (regno >= 33 && regno <= 40)
00631         reg = CV_AMD64_ST0 + regno - 33;
00632     else switch (regno)
00633     {
00634     case  0: reg = CV_AMD64_RAX;    break;
00635     case  1: reg = CV_AMD64_RDX;    break;
00636     case  2: reg = CV_AMD64_RCX;    break;
00637     case  3: reg = CV_AMD64_RBX;    break;
00638     case  4: reg = CV_AMD64_RSI;    break;
00639     case  5: reg = CV_AMD64_RDI;    break;
00640     case  6: reg = CV_AMD64_RBP;    break;
00641     case  7: reg = CV_AMD64_RSP;    break;
00642     case  8: reg = CV_AMD64_R8;     break;
00643     case  9: reg = CV_AMD64_R9;     break;
00644     case 10: reg = CV_AMD64_R10;    break;
00645     case 11: reg = CV_AMD64_R11;    break;
00646     case 12: reg = CV_AMD64_R12;    break;
00647     case 13: reg = CV_AMD64_R13;    break;
00648     case 14: reg = CV_AMD64_R14;    break;
00649     case 15: reg = CV_AMD64_R15;    break;
00650     case 16: reg = CV_AMD64_RIP;    break;
00651     case 49: reg = CV_AMD64_EFLAGS; break;
00652     case 50: reg = CV_AMD64_ES;     break;
00653     case 51: reg = CV_AMD64_CS;     break;
00654     case 52: reg = CV_AMD64_SS;     break;
00655     case 53: reg = CV_AMD64_DS;     break;
00656     case 54: reg = CV_AMD64_FS;     break;
00657     case 55: reg = CV_AMD64_GS;     break;
00658     case 62: reg = CV_AMD64_TR;     break;
00659     case 63: reg = CV_AMD64_LDTR;   break;
00660     case 64: reg = CV_AMD64_MXCSR;  break;
00661     case 65: reg = CV_AMD64_CTRL;   break;
00662     case 66: reg = CV_AMD64_STAT;   break;
00663 /*
00664  * 56-57 reserved
00665  * 58 %fs.base
00666  * 59 %gs.base
00667  * 60-61 reserved
00668  */
00669     default:
00670         FIXME("Don't know how to map register %d\n", regno);
00671         return 0;
00672     }
00673     return reg;
00674 }
00675 
00676 static void* x86_64_fetch_context_reg(CONTEXT* ctx, unsigned regno, unsigned* size)
00677 {
00678 #ifdef __x86_64__
00679     switch (regno)
00680     {
00681     case CV_AMD64_RAX: *size = sizeof(ctx->Rax); return &ctx->Rax;
00682     case CV_AMD64_RDX: *size = sizeof(ctx->Rdx); return &ctx->Rdx;
00683     case CV_AMD64_RCX: *size = sizeof(ctx->Rcx); return &ctx->Rcx;
00684     case CV_AMD64_RBX: *size = sizeof(ctx->Rbx); return &ctx->Rbx;
00685     case CV_AMD64_RSI: *size = sizeof(ctx->Rsi); return &ctx->Rsi;
00686     case CV_AMD64_RDI: *size = sizeof(ctx->Rdi); return &ctx->Rdi;
00687     case CV_AMD64_RBP: *size = sizeof(ctx->Rbp); return &ctx->Rbp;
00688     case CV_AMD64_RSP: *size = sizeof(ctx->Rsp); return &ctx->Rsp;
00689     case CV_AMD64_R8:  *size = sizeof(ctx->R8);  return &ctx->R8;
00690     case CV_AMD64_R9:  *size = sizeof(ctx->R9);  return &ctx->R9;
00691     case CV_AMD64_R10: *size = sizeof(ctx->R10); return &ctx->R10;
00692     case CV_AMD64_R11: *size = sizeof(ctx->R11); return &ctx->R11;
00693     case CV_AMD64_R12: *size = sizeof(ctx->R12); return &ctx->R12;
00694     case CV_AMD64_R13: *size = sizeof(ctx->R13); return &ctx->R13;
00695     case CV_AMD64_R14: *size = sizeof(ctx->R14); return &ctx->R14;
00696     case CV_AMD64_R15: *size = sizeof(ctx->R15); return &ctx->R15;
00697     case CV_AMD64_RIP: *size = sizeof(ctx->Rip); return &ctx->Rip;
00698 
00699     case CV_AMD64_XMM0 + 0: *size = sizeof(ctx->u.s.Xmm0 ); return &ctx->u.s.Xmm0;
00700     case CV_AMD64_XMM0 + 1: *size = sizeof(ctx->u.s.Xmm1 ); return &ctx->u.s.Xmm1;
00701     case CV_AMD64_XMM0 + 2: *size = sizeof(ctx->u.s.Xmm2 ); return &ctx->u.s.Xmm2;
00702     case CV_AMD64_XMM0 + 3: *size = sizeof(ctx->u.s.Xmm3 ); return &ctx->u.s.Xmm3;
00703     case CV_AMD64_XMM0 + 4: *size = sizeof(ctx->u.s.Xmm4 ); return &ctx->u.s.Xmm4;
00704     case CV_AMD64_XMM0 + 5: *size = sizeof(ctx->u.s.Xmm5 ); return &ctx->u.s.Xmm5;
00705     case CV_AMD64_XMM0 + 6: *size = sizeof(ctx->u.s.Xmm6 ); return &ctx->u.s.Xmm6;
00706     case CV_AMD64_XMM0 + 7: *size = sizeof(ctx->u.s.Xmm7 ); return &ctx->u.s.Xmm7;
00707     case CV_AMD64_XMM8 + 0: *size = sizeof(ctx->u.s.Xmm8 ); return &ctx->u.s.Xmm8;
00708     case CV_AMD64_XMM8 + 1: *size = sizeof(ctx->u.s.Xmm9 ); return &ctx->u.s.Xmm9;
00709     case CV_AMD64_XMM8 + 2: *size = sizeof(ctx->u.s.Xmm10); return &ctx->u.s.Xmm10;
00710     case CV_AMD64_XMM8 + 3: *size = sizeof(ctx->u.s.Xmm11); return &ctx->u.s.Xmm11;
00711     case CV_AMD64_XMM8 + 4: *size = sizeof(ctx->u.s.Xmm12); return &ctx->u.s.Xmm12;
00712     case CV_AMD64_XMM8 + 5: *size = sizeof(ctx->u.s.Xmm13); return &ctx->u.s.Xmm13;
00713     case CV_AMD64_XMM8 + 6: *size = sizeof(ctx->u.s.Xmm14); return &ctx->u.s.Xmm14;
00714     case CV_AMD64_XMM8 + 7: *size = sizeof(ctx->u.s.Xmm15); return &ctx->u.s.Xmm15;
00715 
00716     case CV_AMD64_ST0 + 0: *size = sizeof(ctx->u.s.Legacy[0]); return &ctx->u.s.Legacy[0];
00717     case CV_AMD64_ST0 + 1: *size = sizeof(ctx->u.s.Legacy[1]); return &ctx->u.s.Legacy[1];
00718     case CV_AMD64_ST0 + 2: *size = sizeof(ctx->u.s.Legacy[2]); return &ctx->u.s.Legacy[2];
00719     case CV_AMD64_ST0 + 3: *size = sizeof(ctx->u.s.Legacy[3]); return &ctx->u.s.Legacy[3];
00720     case CV_AMD64_ST0 + 4: *size = sizeof(ctx->u.s.Legacy[4]); return &ctx->u.s.Legacy[4];
00721     case CV_AMD64_ST0 + 5: *size = sizeof(ctx->u.s.Legacy[5]); return &ctx->u.s.Legacy[5];
00722     case CV_AMD64_ST0 + 6: *size = sizeof(ctx->u.s.Legacy[6]); return &ctx->u.s.Legacy[6];
00723     case CV_AMD64_ST0 + 7: *size = sizeof(ctx->u.s.Legacy[7]); return &ctx->u.s.Legacy[7];
00724 
00725     case CV_AMD64_EFLAGS: *size = sizeof(ctx->EFlags); return &ctx->EFlags;
00726     case CV_AMD64_ES: *size = sizeof(ctx->SegEs); return &ctx->SegEs;
00727     case CV_AMD64_CS: *size = sizeof(ctx->SegCs); return &ctx->SegCs;
00728     case CV_AMD64_SS: *size = sizeof(ctx->SegSs); return &ctx->SegSs;
00729     case CV_AMD64_DS: *size = sizeof(ctx->SegDs); return &ctx->SegDs;
00730     case CV_AMD64_FS: *size = sizeof(ctx->SegFs); return &ctx->SegFs;
00731     case CV_AMD64_GS: *size = sizeof(ctx->SegGs); return &ctx->SegGs;
00732 
00733     }
00734 #endif
00735     FIXME("Unknown register %x\n", regno);
00736     return NULL;
00737 }
00738 
00739 static const char* x86_64_fetch_regname(unsigned regno)
00740 {
00741     switch (regno)
00742     {
00743     case CV_AMD64_RAX:          return "rax";
00744     case CV_AMD64_RDX:          return "rdx";
00745     case CV_AMD64_RCX:          return "rcx";
00746     case CV_AMD64_RBX:          return "rbx";
00747     case CV_AMD64_RSI:          return "rsi";
00748     case CV_AMD64_RDI:          return "rdi";
00749     case CV_AMD64_RBP:          return "rbp";
00750     case CV_AMD64_RSP:          return "rsp";
00751     case CV_AMD64_R8:           return "r8";
00752     case CV_AMD64_R9:           return "r9";
00753     case CV_AMD64_R10:          return "r10";
00754     case CV_AMD64_R11:          return "r11";
00755     case CV_AMD64_R12:          return "r12";
00756     case CV_AMD64_R13:          return "r13";
00757     case CV_AMD64_R14:          return "r14";
00758     case CV_AMD64_R15:          return "r15";
00759     case CV_AMD64_RIP:          return "rip";
00760 
00761     case CV_AMD64_XMM0 + 0:     return "xmm0";
00762     case CV_AMD64_XMM0 + 1:     return "xmm1";
00763     case CV_AMD64_XMM0 + 2:     return "xmm2";
00764     case CV_AMD64_XMM0 + 3:     return "xmm3";
00765     case CV_AMD64_XMM0 + 4:     return "xmm4";
00766     case CV_AMD64_XMM0 + 5:     return "xmm5";
00767     case CV_AMD64_XMM0 + 6:     return "xmm6";
00768     case CV_AMD64_XMM0 + 7:     return "xmm7";
00769     case CV_AMD64_XMM8 + 0:     return "xmm8";
00770     case CV_AMD64_XMM8 + 1:     return "xmm9";
00771     case CV_AMD64_XMM8 + 2:     return "xmm10";
00772     case CV_AMD64_XMM8 + 3:     return "xmm11";
00773     case CV_AMD64_XMM8 + 4:     return "xmm12";
00774     case CV_AMD64_XMM8 + 5:     return "xmm13";
00775     case CV_AMD64_XMM8 + 6:     return "xmm14";
00776     case CV_AMD64_XMM8 + 7:     return "xmm15";
00777 
00778     case CV_AMD64_ST0 + 0:      return "st0";
00779     case CV_AMD64_ST0 + 1:      return "st1";
00780     case CV_AMD64_ST0 + 2:      return "st2";
00781     case CV_AMD64_ST0 + 3:      return "st3";
00782     case CV_AMD64_ST0 + 4:      return "st4";
00783     case CV_AMD64_ST0 + 5:      return "st5";
00784     case CV_AMD64_ST0 + 6:      return "st6";
00785     case CV_AMD64_ST0 + 7:      return "st7";
00786 
00787     case CV_AMD64_EFLAGS:       return "eflags";
00788     case CV_AMD64_ES:           return "es";
00789     case CV_AMD64_CS:           return "cs";
00790     case CV_AMD64_SS:           return "ss";
00791     case CV_AMD64_DS:           return "ds";
00792     case CV_AMD64_FS:           return "fs";
00793     case CV_AMD64_GS:           return "gs";
00794     }
00795     FIXME("Unknown register %x\n", regno);
00796     return NULL;
00797 }
00798 
00799 DECLSPEC_HIDDEN struct cpu cpu_x86_64 = {
00800     IMAGE_FILE_MACHINE_AMD64,
00801     8,
00802     CV_AMD64_RSP,
00803     x86_64_get_addr,
00804     x86_64_stack_walk,
00805     x86_64_find_runtime_function,
00806     x86_64_map_dwarf_register,
00807     x86_64_fetch_context_reg,
00808     x86_64_fetch_regname,
00809 };

Generated on Sun May 27 2012 04:23:20 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.