Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencpu_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
1.7.6.1
|