//---------------------------------------------------------------------------- // // Register portions of X86 machine implementation. // // Copyright (C) Microsoft Corporation, 2000-2002. // //---------------------------------------------------------------------------- #include "ntsdp.hpp" BOOL g_X86InCode16; BOOL g_X86InVm86; #define REGALL_SEGREG REGALL_EXTRA0 #define REGALL_MMXREG REGALL_EXTRA1 #define REGALL_DREG REGALL_EXTRA2 REGALLDESC g_X86AllExtraDesc[] = { REGALL_SEGREG, "Segment registers", REGALL_MMXREG, "MMX registers", REGALL_DREG, "Debug registers and, in kernel, CR4", REGALL_XMMREG, "SSE XMM registers", 0, NULL, }; #define REGALL_CREG REGALL_EXTRA4 #define REGALL_DESC REGALL_EXTRA5 REGALLDESC g_X86KernelExtraDesc[] = { REGALL_CREG, "CR0, CR2 and CR3", REGALL_DESC, "Descriptor and task state", 0, NULL, }; char g_Gs[] = "gs"; char g_Fs[] = "fs"; char g_Es[] = "es"; char g_Ds[] = "ds"; char g_Edi[] = "edi"; char g_Esi[] = "esi"; char g_Ebx[] = "ebx"; char g_Edx[] = "edx"; char g_Ecx[] = "ecx"; char g_Eax[] = "eax"; char g_Ebp[] = "ebp"; char g_Eip[] = "eip"; char g_Cs[] = "cs"; char g_Efl[] = "efl"; char g_Esp[] = "esp"; char g_Ss[] = "ss"; char g_Dr0[] = "dr0"; char g_Dr1[] = "dr1"; char g_Dr2[] = "dr2"; char g_Dr3[] = "dr3"; char g_Dr6[] = "dr6"; char g_Dr7[] = "dr7"; char g_Cr0[] = "cr0"; char g_Cr2[] = "cr2"; char g_Cr3[] = "cr3"; char g_Cr4[] = "cr4"; char g_Gdtr[] = "gdtr"; char g_Gdtl[] = "gdtl"; char g_Idtr[] = "idtr"; char g_Idtl[] = "idtl"; char g_Tr[] = "tr"; char g_Ldtr[] = "ldtr"; char g_Di[] = "di"; char g_Si[] = "si"; char g_Bx[] = "bx"; char g_Dx[] = "dx"; char g_Cx[] = "cx"; char g_Ax[] = "ax"; char g_Bp[] = "bp"; char g_Ip[] = "ip"; char g_Fl[] = "fl"; char g_Sp[] = "sp"; char g_Bl[] = "bl"; char g_Dl[] = "dl"; char g_Cl[] = "cl"; char g_Al[] = "al"; char g_Bh[] = "bh"; char g_Dh[] = "dh"; char g_Ch[] = "ch"; char g_Ah[] = "ah"; char g_Iopl[] = "iopl"; char g_Of[] = "of"; char g_Df[] = "df"; char g_If[] = "if"; char g_Tf[] = "tf"; char g_Sf[] = "sf"; char g_Zf[] = "zf"; char g_Af[] = "af"; char g_Pf[] = "pf"; char g_Cf[] = "cf"; char g_Vip[] = "vip"; char g_Vif[] = "vif"; char g_Fpcw[] = "fpcw"; char g_Fpsw[] = "fpsw"; char g_Fptw[] = "fptw"; char g_St0[] = "st0"; char g_St1[] = "st1"; char g_St2[] = "st2"; char g_St3[] = "st3"; char g_St4[] = "st4"; char g_St5[] = "st5"; char g_St6[] = "st6"; char g_St7[] = "st7"; char g_Mm0[] = "mm0"; char g_Mm1[] = "mm1"; char g_Mm2[] = "mm2"; char g_Mm3[] = "mm3"; char g_Mm4[] = "mm4"; char g_Mm5[] = "mm5"; char g_Mm6[] = "mm6"; char g_Mm7[] = "mm7"; char g_Mxcsr[] = "mxcsr"; char g_Xmm0[] = "xmm0"; char g_Xmm1[] = "xmm1"; char g_Xmm2[] = "xmm2"; char g_Xmm3[] = "xmm3"; char g_Xmm4[] = "xmm4"; char g_Xmm5[] = "xmm5"; char g_Xmm6[] = "xmm6"; char g_Xmm7[] = "xmm7"; REGDEF g_X86Defs[] = { { g_Gs, X86_GS }, { g_Fs, X86_FS }, { g_Es, X86_ES }, { g_Ds, X86_DS }, { g_Edi, X86_EDI }, { g_Esi, X86_ESI }, { g_Ebx, X86_EBX }, { g_Edx, X86_EDX }, { g_Ecx, X86_ECX }, { g_Eax, X86_EAX }, { g_Ebp, X86_EBP }, { g_Eip, X86_EIP }, { g_Cs, X86_CS }, { g_Efl, X86_EFL }, { g_Esp, X86_ESP }, { g_Ss, X86_SS }, { g_Dr0, X86_DR0 }, { g_Dr1, X86_DR1 }, { g_Dr2, X86_DR2 }, { g_Dr3, X86_DR3 }, { g_Dr6, X86_DR6 }, { g_Dr7, X86_DR7 }, { g_Di, X86_DI }, { g_Si, X86_SI }, { g_Bx, X86_BX }, { g_Dx, X86_DX }, { g_Cx, X86_CX }, { g_Ax, X86_AX }, { g_Bp, X86_BP }, { g_Ip, X86_IP }, { g_Fl, X86_FL }, { g_Sp, X86_SP }, { g_Bl, X86_BL }, { g_Dl, X86_DL }, { g_Cl, X86_CL }, { g_Al, X86_AL }, { g_Bh, X86_BH }, { g_Dh, X86_DH }, { g_Ch, X86_CH }, { g_Ah, X86_AH }, { g_Fpcw, X86_FPCW }, { g_Fpsw, X86_FPSW }, { g_Fptw, X86_FPTW }, { g_St0, X86_ST0 }, { g_St1, X86_ST1 }, { g_St2, X86_ST2 }, { g_St3, X86_ST3 }, { g_St4, X86_ST4 }, { g_St5, X86_ST5 }, { g_St6, X86_ST6 }, { g_St7, X86_ST7 }, { g_Mm0, X86_MM0 }, { g_Mm1, X86_MM1 }, { g_Mm2, X86_MM2 }, { g_Mm3, X86_MM3 }, { g_Mm4, X86_MM4 }, { g_Mm5, X86_MM5 }, { g_Mm6, X86_MM6 }, { g_Mm7, X86_MM7 }, { g_Mxcsr, X86_MXCSR}, { g_Xmm0, X86_XMM0 }, { g_Xmm1, X86_XMM1 }, { g_Xmm2, X86_XMM2 }, { g_Xmm3, X86_XMM3 }, { g_Xmm4, X86_XMM4 }, { g_Xmm5, X86_XMM5 }, { g_Xmm6, X86_XMM6 }, { g_Xmm7, X86_XMM7 }, { g_Iopl, X86_IOPL }, { g_Of, X86_OF }, { g_Df, X86_DF }, { g_If, X86_IF }, { g_Tf, X86_TF }, { g_Sf, X86_SF }, { g_Zf, X86_ZF }, { g_Af, X86_AF }, { g_Pf, X86_PF }, { g_Cf, X86_CF }, { g_Vip, X86_VIP }, { g_Vif, X86_VIF }, { NULL, REG_ERROR }, }; REGDEF g_X86KernelReg[] = { { g_Cr0, X86_CR0 }, { g_Cr2, X86_CR2 }, { g_Cr3, X86_CR3 }, { g_Cr4, X86_CR4 }, { g_Gdtr, X86_GDTR }, { g_Gdtl, X86_GDTL }, { g_Idtr, X86_IDTR }, { g_Idtl, X86_IDTL }, { g_Tr, X86_TR }, { g_Ldtr, X86_LDTR }, { NULL, REG_ERROR }, }; REGSUBDEF g_X86SubDefs[] = { { X86_DI, X86_EDI, 0, 0xffff }, // DI register { X86_SI, X86_ESI, 0, 0xffff }, // SI register { X86_BX, X86_EBX, 0, 0xffff }, // BX register { X86_DX, X86_EDX, 0, 0xffff }, // DX register { X86_CX, X86_ECX, 0, 0xffff }, // CX register { X86_AX, X86_EAX, 0, 0xffff }, // AX register { X86_BP, X86_EBP, 0, 0xffff }, // BP register { X86_IP, X86_EIP, 0, 0xffff }, // IP register { X86_FL, X86_EFL, 0, 0xffff }, // FL register { X86_SP, X86_ESP, 0, 0xffff }, // SP register { X86_BL, X86_EBX, 0, 0xff }, // BL register { X86_DL, X86_EDX, 0, 0xff }, // DL register { X86_CL, X86_ECX, 0, 0xff }, // CL register { X86_AL, X86_EAX, 0, 0xff }, // AL register { X86_BH, X86_EBX, 8, 0xff }, // BH register { X86_DH, X86_EDX, 8, 0xff }, // DH register { X86_CH, X86_ECX, 8, 0xff }, // CH register { X86_AH, X86_EAX, 8, 0xff }, // AH register { X86_IOPL, X86_EFL,12, 3 }, // IOPL level value { X86_OF, X86_EFL,11, 1 }, // OF (overflow flag) { X86_DF, X86_EFL,10, 1 }, // DF (direction flag) { X86_IF, X86_EFL, 9, 1 }, // IF (interrupt enable flag) { X86_TF, X86_EFL, 8, 1 }, // TF (trace flag) { X86_SF, X86_EFL, 7, 1 }, // SF (sign flag) { X86_ZF, X86_EFL, 6, 1 }, // ZF (zero flag) { X86_AF, X86_EFL, 4, 1 }, // AF (aux carry flag) { X86_PF, X86_EFL, 2, 1 }, // PF (parity flag) { X86_CF, X86_EFL, 0, 1 }, // CF (carry flag) { X86_VIP, X86_EFL,20, 1 }, // VIP (virtual interrupt pending) { X86_VIF, X86_EFL,19, 1 }, // VIF (virtual interrupt flag) { REG_ERROR, REG_ERROR, 0, 0 } }; RegisterGroup g_X86BaseGroup = { 0, g_X86Defs, g_X86SubDefs, g_X86AllExtraDesc }; RegisterGroup g_X86KernelGroup = { 0, g_X86KernelReg, NULL, g_X86KernelExtraDesc }; // First ExecTypes entry must be the actual processor type. ULONG g_X86ExecTypes[] = { IMAGE_FILE_MACHINE_I386 }; // This array must be sorted by CV reg value. CvRegMap g_X86CvRegMap[] = { { CV_REG_AL, X86_AL}, { CV_REG_CL, X86_CL}, { CV_REG_DL, X86_DL}, { CV_REG_BL, X86_BL}, { CV_REG_AH, X86_AH}, { CV_REG_CH, X86_CH}, { CV_REG_DH, X86_DH}, { CV_REG_BH, X86_BH}, { CV_REG_AX, X86_AX}, { CV_REG_CX, X86_CX}, { CV_REG_DX, X86_DX}, { CV_REG_BX, X86_BX}, { CV_REG_SP, X86_SP}, { CV_REG_BP, X86_BP}, { CV_REG_SI, X86_SI}, { CV_REG_DI, X86_DI}, { CV_REG_EAX, X86_EAX}, { CV_REG_ECX, X86_ECX}, { CV_REG_EDX, X86_EDX}, { CV_REG_EBX, X86_EBX}, { CV_REG_ESP, X86_ESP}, { CV_REG_EBP, X86_EBP}, { CV_REG_ESI, X86_ESI}, { CV_REG_EDI, X86_EDI}, { CV_REG_ES, X86_ES}, { CV_REG_CS, X86_CS}, { CV_REG_SS, X86_SS}, { CV_REG_DS, X86_DS}, { CV_REG_FS, X86_FS}, { CV_REG_GS, X86_GS}, { CV_REG_IP, X86_IP}, { CV_REG_FLAGS, X86_FL}, { CV_REG_EIP, X86_EIP}, { CV_REG_EFLAGS, X86_EFL}, // { CV_REG_TEMP, REGTEMP}, // { CV_REG_TEMPH, REGTEMPH}, // { CV_REG_QUOTE, REGQUOTE}, // { CV_REG_PCDR3, REGPCDR3}, // { CV_REG_PCDR4, REGPCDR4}, // { CV_REG_PCDR5, REGPCDR5}, // { CV_REG_PCDR6, REGPCDR6}, // { CV_REG_PCDR7, REGPCDR7}, { CV_REG_CR0, X86_CR0}, // { CV_REG_CR1, REGCR1}, { CV_REG_CR2, X86_CR2}, { CV_REG_CR3, X86_CR3}, { CV_REG_CR4, X86_CR4}, { CV_REG_DR0, X86_DR0}, { CV_REG_DR1, X86_DR1}, { CV_REG_DR2, X86_DR2}, { CV_REG_DR3, X86_DR3}, // { CV_REG_DR4, REGDR4}, // { CV_REG_DR5, REGDR5}, { CV_REG_DR6, X86_DR6}, { CV_REG_DR7, X86_DR7}, { CV_REG_GDTR, X86_GDTR}, { CV_REG_GDTL, X86_GDTL}, { CV_REG_IDTR, X86_IDTR}, { CV_REG_IDTL, X86_IDTL}, { CV_REG_LDTR, X86_LDTR}, { CV_REG_TR, X86_TR}, // { CV_REG_PSEUDO1, REGPSEUDO1}, // { CV_REG_PSEUDO2, REGPSEUDO2}, // { CV_REG_PSEUDO3, REGPSEUDO3}, // { CV_REG_PSEUDO4, REGPSEUDO4}, // { CV_REG_PSEUDO5, REGPSEUDO5}, // { CV_REG_PSEUDO6, REGPSEUDO6}, // { CV_REG_PSEUDO7, REGPSEUDO7}, // { CV_REG_PSEUDO8, REGPSEUDO8}, // { CV_REG_PSEUDO9, REGPSEUDO9}, { CV_REG_ST0, X86_ST0}, { CV_REG_ST1, X86_ST1}, { CV_REG_ST2, X86_ST2}, { CV_REG_ST3, X86_ST3}, { CV_REG_ST4, X86_ST4}, { CV_REG_ST5, X86_ST5}, { CV_REG_ST6, X86_ST6}, { CV_REG_ST7, X86_ST7}, { CV_REG_CTRL, X86_FPCW}, { CV_REG_STAT, X86_FPSW}, { CV_REG_TAG, X86_FPTW}, // { CV_REG_FPIP, REGFPIP}, // { CV_REG_FPCS, REGFPCS}, // { CV_REG_FPDO, REGFPDO}, // { CV_REG_FPDS, REGFPDS}, // { CV_REG_ISEM, REGISEM}, // { CV_REG_FPEIP, REGFPEIP}, // { CV_REG_FPEDO, REGFPEDO}, { CV_REG_MM0, X86_MM0}, { CV_REG_MM1, X86_MM1}, { CV_REG_MM2, X86_MM2}, { CV_REG_MM3, X86_MM3}, { CV_REG_MM4, X86_MM4}, { CV_REG_MM5, X86_MM5}, { CV_REG_MM6, X86_MM6}, { CV_REG_MM7, X86_MM7}, }; X86MachineInfo::X86MachineInfo(TargetInfo* Target) : BaseX86MachineInfo(Target) { m_FullName = "x86 compatible"; m_AbbrevName = "x86"; m_PageSize = X86_PAGE_SIZE; m_PageShift = X86_PAGE_SHIFT; m_NumExecTypes = 1; m_ExecTypes = g_X86ExecTypes; m_Ptr64 = FALSE; m_RetRegIndex = X86_EAX; m_AllMask = REGALL_INT32 | REGALL_SEGREG, m_MaxDataBreakpoints = 4; m_SymPrefix = NULL; m_SizeCanonicalContext = sizeof(X86_NT5_CONTEXT); m_SverCanonicalContext = NT_SVER_W2K; m_SupportsBranchTrace = FALSE; m_ResetBranchTrace = TRUE; m_CvRegMapSize = DIMA(g_X86CvRegMap); m_CvRegMap = g_X86CvRegMap; } HRESULT X86MachineInfo::Initialize(void) { m_Groups[0] = &g_X86BaseGroup; m_NumGroups = 1; if (IS_KERNEL_TARGET(m_Target)) { m_Groups[m_NumGroups] = &g_X86KernelGroup; m_NumGroups++; } return MachineInfo::Initialize(); } HRESULT X86MachineInfo::InitializeForProcessor(void) { if (!strcmp(m_Target->m_FirstProcessorId.X86.VendorString, "GenuineIntel")) { // Branch trace support was added for the Pentium Pro. m_SupportsBranchTrace = m_Target->m_FirstProcessorId.X86.Family >= 6; } return MachineInfo::InitializeForProcessor(); } void X86MachineInfo::GetSystemTypeInfo(PSYSTEM_TYPE_INFO Info) { Info->TriagePrcbOffset = EXTEND64(X86_TRIAGE_PRCB_ADDRESS); Info->SizeTargetContext = sizeof(X86_CONTEXT); Info->OffsetSpecialRegisters = sizeof(X86_CONTEXT); Info->OffsetTargetContextFlags = FIELD_OFFSET(X86_CONTEXT, ContextFlags); Info->SizeControlReport = sizeof(X86_DBGKD_CONTROL_REPORT); Info->SizeKspecialRegisters = sizeof(X86_KSPECIAL_REGISTERS); Info->SizePageFrameNumber = sizeof(ULONG); Info->SizePte = m_Target->m_KdDebuggerData.PaeEnabled ? sizeof(ULONG64) : sizeof(ULONG); Info->SizeDynamicFunctionTable = 0; Info->SizeRuntimeFunction = 0; Info->SharedUserDataOffset = 0; Info->UmSharedUserDataOffset = 0; Info->UmSharedSysCallOffset = 0; Info->UmSharedSysCallSize = 0; if (m_Target->m_PlatformId == VER_PLATFORM_WIN32_NT) { Info->SharedUserDataOffset = IS_KERNEL_TARGET(m_Target) ? EXTEND64(X86_KI_USER_SHARED_DATA) : MM_SHARED_USER_DATA_VA; Info->UmSharedUserDataOffset = MM_SHARED_USER_DATA_VA; if (m_Target->m_SystemVersion >= NT_SVER_XP) { // The syscall offset should really be provided in the debugger // data block so that it automatically tracks system changes. It's // relatively stable, now, though. if (m_Target->m_BuildNumber >= 2492) { Info->UmSharedSysCallOffset = X86_SHARED_SYSCALL_BASE_GTE2492; } else if (m_Target->m_BuildNumber >= 2412) { Info->UmSharedSysCallOffset = X86_SHARED_SYSCALL_BASE_GTE2412; } else { Info->UmSharedSysCallOffset = X86_SHARED_SYSCALL_BASE_LT2412; } Info->UmSharedSysCallSize = X86_SHARED_SYSCALL_SIZE; } } if (m_Target->m_SystemVersion > NT_SVER_NT4) { Info->SizeTargetContext = sizeof(X86_NT5_CONTEXT); Info->OffsetSpecialRegisters = sizeof(X86_NT5_CONTEXT); Info->OffsetTargetContextFlags = FIELD_OFFSET(X86_NT5_CONTEXT, ContextFlags); } } void X86MachineInfo::GetDefaultKdData(PKDDEBUGGER_DATA64 KdData) { // // Parts of the data block may already be filled out // so don't destroy anything that's already set. // if (!KdData->OffsetKThreadApcProcess) { KdData->OffsetKThreadNextProcessor = X86_KTHREAD_NEXTPROCESSOR_OFFSET; KdData->OffsetKThreadTeb = X86_KTHREAD_TEB_OFFSET; KdData->OffsetKThreadKernelStack = X86_KTHREAD_KERNELSTACK_OFFSET; KdData->OffsetKThreadInitialStack = X86_KTHREAD_INITSTACK_OFFSET; KdData->OffsetKThreadApcProcess = X86_KTHREAD_APCPROCESS_OFFSET; KdData->OffsetKThreadState = X86_KTHREAD_STATE_OFFSET; KdData->OffsetEprocessPeb = X86_NT4_PEB_IN_EPROCESS; KdData->OffsetEprocessParentCID = X86_NT4_PCID_IN_EPROCESS; KdData->OffsetEprocessDirectoryTableBase = X86_DIRECTORY_TABLE_BASE_IN_EPROCESS; KdData->SizeEProcess = X86_NT5_EPROCESS_SIZE; KdData->SizePrcb = X86_NT4_KPRCB_SIZE; KdData->OffsetPrcbDpcRoutine = X86_KPRCB_DPC_ROUTINE_ACTIVE; KdData->OffsetPrcbCurrentThread = DEF_KPRCB_CURRENT_THREAD_OFFSET_32; KdData->OffsetPrcbMhz = X86_1381_KPRCB_MHZ; KdData->OffsetPrcbCpuType = X86_KPRCB_CPU_TYPE; KdData->OffsetPrcbVendorString = X86_1387_KPRCB_VENDOR_STRING; KdData->OffsetPrcbProcStateContext = X86_KPRCB_CONTEXT; KdData->OffsetPrcbNumber = X86_KPRCB_NUMBER; KdData->SizeEThread = X86_ETHREAD_SIZE; if (m_Target->m_SystemVersion > NT_SVER_NT4) { KdData->SizePrcb = X86_NT5_KPRCB_SIZE; KdData->OffsetEprocessPeb = X86_PEB_IN_EPROCESS; KdData->OffsetEprocessParentCID = X86_PCID_IN_EPROCESS; KdData->OffsetPrcbMhz = X86_2195_KPRCB_MHZ; } if (m_Target->m_BuildNumber >= 2087) { KdData->OffsetPrcbVendorString = X86_2087_KPRCB_VENDOR_STRING; } if (m_Target->m_BuildNumber > 2230) { KdData->OffsetKThreadNextProcessor = X86_2230_KTHREAD_NEXTPROCESSOR_OFFSET; } if (m_Target->m_BuildNumber >= 2251) { KdData->OffsetPrcbVendorString = X86_2251_KPRCB_VENDOR_STRING; } if (m_Target->m_SystemVersion > NT_SVER_W2K) { KdData->SizeEProcess = X86_NT51_EPROCESS_SIZE; } if (m_Target->m_BuildNumber > 2407) { KdData->SizeEThread = X86_NT51_ETHREAD_SIZE; KdData->OffsetKThreadNextProcessor = X86_NT51_KTHREAD_NEXTPROCESSOR_OFFSET; } if (m_Target->m_BuildNumber >= 2462) { KdData->OffsetPrcbMhz = X86_2462_KPRCB_MHZ; } if (m_Target->m_BuildNumber >= 2474) { KdData->OffsetPrcbVendorString = X86_2474_KPRCB_VENDOR_STRING; } if (m_Target->m_BuildNumber >= 2505) { KdData->OffsetPrcbMhz = X86_2505_KPRCB_MHZ; } if (m_Target->m_SystemVersion > NT_SVER_XP) { KdData->SizeEProcess = X86_NT511_EPROCESS_SIZE; } if (m_Target->m_BuildNumber > 3558) { KdData->OffsetKThreadApcProcess = X86_3555_KTHREAD_APCPROCESS_OFFSET; KdData->OffsetKThreadTeb = X86_3555_KTHREAD_TEB_OFFSET; KdData->OffsetKThreadKernelStack = X86_3555_KTHREAD_KERNELSTACK_OFFSET; KdData->OffsetKThreadNextProcessor = X86_3555_KTHREAD_NEXTPROCESSOR_OFFSET; KdData->OffsetKThreadState = X86_3555_KTHREAD_STATE_OFFSET; } } if (!KdData->SizePcr) { KdData->SizePcr = X86_1381_KPCR_SIZE; if (m_Target->m_BuildNumber >= 2195) { KdData->SizePcr = X86_2195_KPCR_SIZE; } if (m_Target->m_BuildNumber >= 2600) { KdData->SizePcr = X86_KPCR_SIZE; } KdData->OffsetPcrSelfPcr = X86_KPCR_SELF_PCR; KdData->OffsetPcrCurrentPrcb = X86_KPCR_PRCB; KdData->OffsetPcrContainedPrcb = X86_KPCR_PRCB_DATA; KdData->OffsetPcrInitialBStore = 0; KdData->OffsetPcrBStoreLimit = 0; KdData->OffsetPcrInitialStack = 0; KdData->OffsetPcrStackLimit = 0; KdData->OffsetPrcbPcrPage = 0; KdData->OffsetPrcbProcStateSpecialReg = X86_KPRCB_SPECIAL_REG; KdData->GdtR0Code = X86_KGDT_R0_CODE; KdData->GdtR0Data = X86_KGDT_R0_DATA; KdData->GdtR0Pcr = X86_KGDT_R0_PCR; KdData->GdtR3Code = X86_KGDT_R3_CODE + 3; KdData->GdtR3Data = X86_KGDT_R3_DATA + 3; KdData->GdtR3Teb = X86_KGDT_R3_TEB + 3; KdData->GdtLdt = X86_KGDT_LDT; KdData->GdtTss = X86_KGDT_TSS; KdData->Gdt64R3CmCode = 0; KdData->Gdt64R3CmTeb = 0; } } void X86MachineInfo:: InitializeContext(ULONG64 Pc, PDBGKD_ANY_CONTROL_REPORT ControlReport) { ULONG Pc32 = (ULONG)Pc; m_Context.X86Nt5Context.Eip = Pc32; m_ContextState = Pc32 ? MCTX_PC : MCTX_NONE; if (ControlReport != NULL) { BpOut("InitializeContext(%d) DR6 %X DR7 %X\n", m_Target->m_RegContextProcessor, ControlReport->X86ControlReport.Dr6, ControlReport->X86ControlReport.Dr7); m_Context.X86Nt5Context.Dr6 = ControlReport->X86ControlReport.Dr6; m_Context.X86Nt5Context.Dr7 = ControlReport->X86ControlReport.Dr7; m_ContextState = MCTX_DR67_REPORT; if (ControlReport->X86ControlReport.ReportFlags & X86_REPORT_INCLUDES_SEGS) { // // This is for backwards compatibility - older kernels // won't pass these registers in the report record. // m_Context.X86Nt5Context.SegCs = ControlReport->X86ControlReport.SegCs; m_Context.X86Nt5Context.SegDs = ControlReport->X86ControlReport.SegDs; m_Context.X86Nt5Context.SegEs = ControlReport->X86ControlReport.SegEs; m_Context.X86Nt5Context.SegFs = ControlReport->X86ControlReport.SegFs; m_Context.X86Nt5Context.EFlags = ControlReport->X86ControlReport.EFlags; m_ContextState = MCTX_REPORT; } } if (!IS_CONTEXT_POSSIBLE(m_Target)) { g_X86InVm86 = FALSE; g_X86InCode16 = FALSE; } else { // Check whether we're currently in V86 mode or 16-bit code. g_X86InVm86 = X86_IS_VM86(GetIntReg(X86_EFL)); if (IS_KERNEL_TARGET(m_Target) && !g_X86InVm86) { if (ControlReport == NULL || (ControlReport->X86ControlReport.ReportFlags & X86_REPORT_STANDARD_CS) == 0) { DESCRIPTOR64 Desc; if (GetSegRegDescriptor(SEGREG_CODE, &Desc) != S_OK) { WarnOut("CS descriptor lookup failed\n"); g_X86InCode16 = FALSE; } else { g_X86InCode16 = (Desc.Flags & X86_DESC_DEFAULT_BIG) == 0; } } else { g_X86InCode16 = FALSE; // We're in a standard code segment so cache // a default descriptor for CS to avoid further // CS lookups. m_Target-> EmulateNtX86SelDescriptor(m_Target->m_RegContextThread, this, m_Context.X86Nt5Context.SegCs, &m_SegRegDesc[SEGREG_CODE]); } } } // Add instructions to cache only if we're in 32-bit flat mode. if (Pc32 && ControlReport != NULL && !g_X86InVm86 && !g_X86InCode16) { CacheReportInstructions (Pc, ControlReport->X86ControlReport.InstructionCount, ControlReport->X86ControlReport.InstructionStream); } } HRESULT X86MachineInfo::KdGetContextState(ULONG State) { HRESULT Status; if (State >= MCTX_CONTEXT && m_ContextState < MCTX_CONTEXT) { Status = m_Target-> GetContext(m_Target->m_RegContextThread->m_Handle, &m_Context); if (Status != S_OK) { return Status; } m_ContextState = MCTX_CONTEXT; } if (State >= MCTX_FULL && m_ContextState < MCTX_FULL) { Status = m_Target->GetTargetSpecialRegisters (m_Target->m_RegContextThread->m_Handle, (PCROSS_PLATFORM_KSPECIAL_REGISTERS)&m_Special.X86Special); if (Status != S_OK) { return Status; } Status = m_Target->GetTargetSegRegDescriptors (m_Target->m_RegContextThread->m_Handle, 0, SEGREG_COUNT, m_SegRegDesc); if (Status != S_OK) { return Status; } m_ContextState = MCTX_FULL; KdSetSpecialRegistersInContext(); BpOut("GetContextState(%d) DR6 %X DR7 %X DR0 %X\n", m_Target->m_RegContextProcessor, m_Special.X86Special.KernelDr6, m_Special.X86Special.KernelDr7, m_Special.X86Special.KernelDr0); } return S_OK; } HRESULT X86MachineInfo::KdSetContext(void) { HRESULT Status; Status = m_Target->SetContext(m_Target->m_RegContextThread->m_Handle, &m_Context); if (Status != S_OK) { return Status; } KdGetSpecialRegistersFromContext(); Status = m_Target->SetTargetSpecialRegisters (m_Target->m_RegContextThread->m_Handle, (PCROSS_PLATFORM_KSPECIAL_REGISTERS)&m_Special.X86Special); if (Status != S_OK) { return Status; } BpOut("SetContext(%d) DR6 %X DR7 %X DR0 %X\n", m_Target->m_RegContextProcessor, m_Special.X86Special.KernelDr6, m_Special.X86Special.KernelDr7, m_Special.X86Special.KernelDr0); return S_OK; } HRESULT X86MachineInfo::ConvertContextFrom(PCROSS_PLATFORM_CONTEXT Context, ULONG FromSver, ULONG FromSize, PVOID From) { if (FromSver <= NT_SVER_NT4) { if (FromSize < sizeof(X86_CONTEXT)) { return E_INVALIDARG; } memcpy(Context, From, sizeof(X86_CONTEXT)); ZeroMemory(Context->X86Nt5Context.ExtendedRegisters, sizeof(Context->X86Nt5Context.ExtendedRegisters)); } else if (FromSize >= sizeof(X86_NT5_CONTEXT)) { memcpy(Context, From, sizeof(X86_NT5_CONTEXT)); } else { return E_INVALIDARG; } return S_OK; } HRESULT X86MachineInfo::ConvertContextTo(PCROSS_PLATFORM_CONTEXT Context, ULONG ToSver, ULONG ToSize, PVOID To) { if (ToSver <= NT_SVER_NT4) { if (ToSize < sizeof(X86_CONTEXT)) { return E_INVALIDARG; } memcpy(To, Context, sizeof(X86_CONTEXT)); } else if (ToSize >= sizeof(X86_NT5_CONTEXT)) { memcpy(To, Context, sizeof(X86_NT5_CONTEXT)); } else { return E_INVALIDARG; } return S_OK; } void X86MachineInfo::InitializeContextFlags(PCROSS_PLATFORM_CONTEXT Context, ULONG Version) { ULONG ContextFlags; ContextFlags = VDMCONTEXT_CONTROL | VDMCONTEXT_INTEGER | VDMCONTEXT_SEGMENTS | VDMCONTEXT_FLOATING_POINT; if (IS_USER_TARGET(m_Target)) { ContextFlags |= VDMCONTEXT_DEBUG_REGISTERS; } if (Version <= NT_SVER_NT4) { Context->X86Context.ContextFlags = ContextFlags; } else { Context->X86Nt5Context.ContextFlags = ContextFlags | VDMCONTEXT_EXTENDED_REGISTERS; } } HRESULT X86MachineInfo::GetContextFromThreadStack(ULONG64 ThreadBase, PCROSS_PLATFORM_CONTEXT Context, ULONG64 Stack) { HRESULT Status; X86_KSWITCHFRAME SwitchFrame; if ((Status = m_Target->ReadAllVirtual(m_Target->m_ProcessHead, Stack, &SwitchFrame, sizeof(SwitchFrame))) != S_OK) { return Status; } ZeroMemory(Context, sizeof(*Context)); Context->X86Nt5Context.Eip = SwitchFrame.RetAddr; Context->X86Nt5Context.Esp = (ULONG)Stack + sizeof(SwitchFrame); if ((Status = m_Target-> ReadAllVirtual(m_Target->m_ProcessHead, EXTEND64(Context->X86Nt5Context.Esp), &Context->X86Nt5Context.Ebp, sizeof(Context)->X86Nt5Context.Ebp)) != S_OK) { return Status; } // Fill the segments in from current information // instead of just leaving them blank. Context->X86Nt5Context.SegSs = GetIntReg(X86_SS); Context->X86Nt5Context.SegCs = GetIntReg(X86_CS); return S_OK; } HRESULT X86MachineInfo::GetContextFromFiber(ProcessInfo* Process, ULONG64 FiberBase, PCROSS_PLATFORM_CONTEXT Context, BOOL Verbose) { HRESULT Status; X86_FIBER Fiber; if ((Status = m_Target-> ReadAllVirtual(Process, FiberBase, &Fiber, sizeof(Fiber))) != S_OK) { if (Verbose) { ErrOut("Unable to read fiber data at %s\n", FormatMachineAddr64(this, FiberBase)); } return Status; } if ((Status = ConvertContextFrom(Context, m_Target->m_SystemVersion, m_Target->m_TypeInfo.SizeTargetContext, &Fiber.FiberContext)) != S_OK) { if (Verbose) { ErrOut("Unable to convert context to canonical form\n"); } return Status; } if (Verbose) { dprintf("Fiber at %s Fiber data: %08X\n", FormatMachineAddr64(this, FiberBase), Fiber.FiberData); dprintf(" Stack base: %08X Stack limit: %08X\n", Fiber.StackBase, Fiber.StackLimit); } return S_OK; } HRESULT X86MachineInfo::GetContextFromTrapFrame(ULONG64 TrapBase, PCROSS_PLATFORM_CONTEXT Context, BOOL Verbose) { HRESULT Status; X86_KTRAP_FRAME Trap; if ((Status = m_Target-> ReadAllVirtual(m_Target->m_ProcessHead, TrapBase, &Trap, sizeof(Trap))) != S_OK) { if (Verbose) { ErrOut("Unable to read trap frame at %s\n", FormatMachineAddr64(this, TrapBase)); } return Status; } ZeroMemory(Context, sizeof(*Context)); if ((Trap.SegCs & 1) || X86_IS_VM86(Trap.EFlags)) { Context->X86Nt5Context.Esp = Trap.HardwareEsp; } else { Context->X86Nt5Context.Esp = (ULONG)TrapBase + FIELD_OFFSET(X86_KTRAP_FRAME, HardwareEsp); } if (X86_IS_VM86(Trap.EFlags)) { Context->X86Nt5Context.SegSs = (USHORT)(Trap.HardwareSegSs & 0xffff); } else if ((Trap.SegCs & X86_MODE_MASK) != 0 /*KernelMode*/) { // // It's user mode. The HardwareSegSs contains R3 data selector. // Context->X86Nt5Context.SegSs = (USHORT)(Trap.HardwareSegSs | 3) & 0xffff; } else { Context->X86Nt5Context.SegSs = m_Target->m_KdDebuggerData.GdtR0Data; } Context->X86Nt5Context.SegGs = Trap.SegGs & 0xffff; Context->X86Nt5Context.SegFs = Trap.SegFs & 0xffff; Context->X86Nt5Context.SegEs = Trap.SegEs & 0xffff; Context->X86Nt5Context.SegDs = Trap.SegDs & 0xffff; Context->X86Nt5Context.SegCs = Trap.SegCs & 0xffff; Context->X86Nt5Context.Eip = Trap.Eip; Context->X86Nt5Context.Ebp = Trap.Ebp; Context->X86Nt5Context.Eax = Trap.Eax; Context->X86Nt5Context.Ebx = Trap.Ebx; Context->X86Nt5Context.Ecx = Trap.Ecx; Context->X86Nt5Context.Edx = Trap.Edx; Context->X86Nt5Context.Edi = Trap.Edi; Context->X86Nt5Context.Esi = Trap.Esi; Context->X86Nt5Context.EFlags = Trap.EFlags; return Status; } HRESULT X86MachineInfo::GetContextFromTaskSegment(ULONG64 TssBase, PCROSS_PLATFORM_CONTEXT Context, BOOL Verbose) { HRESULT Status; X86_KTSS Tss; if ((Status = m_Target-> ReadAllVirtual(m_Target->m_ProcessHead, TssBase, &Tss, sizeof(Tss))) != S_OK) { if (Verbose) { ErrOut("Unable to read TSS at %s\n", FormatMachineAddr64(this, TssBase)); } return Status; } ZeroMemory(Context, sizeof(*Context)); if (X86_IS_VM86(Tss.EFlags)) { Context->X86Nt5Context.SegSs = (USHORT)(Tss.Ss & 0xffff); } else if ((Tss.Cs & X86_MODE_MASK) != 0) { // // It's user mode. // The HardwareSegSs contains R3 data selector. // Context->X86Nt5Context.SegSs = (USHORT)(Tss.Ss | 3) & 0xffff; } else { Context->X86Nt5Context.SegSs = m_Target->m_KdDebuggerData.GdtR0Data; } Context->X86Nt5Context.SegGs = Tss.Gs & 0xffff; Context->X86Nt5Context.SegFs = Tss.Fs & 0xffff; Context->X86Nt5Context.SegEs = Tss.Es & 0xffff; Context->X86Nt5Context.SegDs = Tss.Ds & 0xffff; Context->X86Nt5Context.SegCs = Tss.Cs & 0xffff; Context->X86Nt5Context.Esp = Tss.Esp; Context->X86Nt5Context.Eip = Tss.Eip; Context->X86Nt5Context.Ebp = Tss.Ebp; Context->X86Nt5Context.Eax = Tss.Eax; Context->X86Nt5Context.Ebx = Tss.Ebx; Context->X86Nt5Context.Ecx = Tss.Ecx; Context->X86Nt5Context.Edx = Tss.Edx; Context->X86Nt5Context.Edi = Tss.Edi; Context->X86Nt5Context.Esi = Tss.Esi; Context->X86Nt5Context.EFlags = Tss.EFlags; return Status; } void X86MachineInfo::GetScopeFrameFromContext(PCROSS_PLATFORM_CONTEXT Context, PDEBUG_STACK_FRAME ScopeFrame) { ZeroMemory(ScopeFrame, sizeof(*ScopeFrame)); StackTrace(NULL, EXTEND64(Context->X86Context.Ebp), EXTEND64(Context->X86Context.Esp), EXTEND64(Context->X86Context.Eip), STACK_NO_DEFAULT, ScopeFrame, 1, 0, 0, 0); } void X86MachineInfo::GetStackDefaultsFromContext(PCROSS_PLATFORM_CONTEXT Context, LPADDRESS64 Instr, LPADDRESS64 Stack, LPADDRESS64 Frame) { // // On x86 we want to fill out the addresses so that // dbghelp doesn't have to deal with segmentation and // such. // // At least, that's the theory, but most of the // segmented stack support has been ripped out and // this code doesn't really do much useful. // Instr->Mode = AddrModeFlat; Instr->Segment = (USHORT)(Context->X86Nt5Context.SegCs & 0xffff); Instr->Offset = EXTEND64(Context->X86Nt5Context.Eip); Stack->Mode = AddrModeFlat; Stack->Segment = (USHORT)(Context->X86Nt5Context.SegSs & 0xffff); Stack->Offset = EXTEND64(Context->X86Nt5Context.Esp); Frame->Mode = AddrModeFlat; Frame->Segment = (USHORT)(Context->X86Nt5Context.SegSs & 0xffff); Frame->Offset = EXTEND64(Context->X86Nt5Context.Ebp); } HRESULT X86MachineInfo::GetScopeFrameRegister(ULONG Reg, PDEBUG_STACK_FRAME ScopeFrame, PULONG64 Value) { HRESULT Status; REGVAL RegVal; switch(Reg) { case X86_ESP: *Value = ScopeFrame->StackOffset; return S_OK; case X86_EBP: if (ScopeFrame->FuncTableEntry) { PFPO_DATA FpoData = (PFPO_DATA)ScopeFrame->FuncTableEntry; if (FpoData->cbFrame == FRAME_FPO) { // // Get EBP from FPO data, if available // if (SAVE_EBP(ScopeFrame) && (FpoData->fUseBP || ((SAVE_EBP(ScopeFrame) >> 32) == 0xEB))) { // Either the frame saved EBP or we saved it // during stackwalk along with tag 0xEB on upper 32 bits. *Value = EXTEND64(SAVE_EBP(ScopeFrame)); return S_OK; } else { // // Guess the ebp value, in most cases for FPO frames its // a DWORD off frameoffset // *Value = ScopeFrame->FrameOffset + sizeof(DWORD); return S_OK; } } } *Value = ScopeFrame->FrameOffset; return S_OK; default: RegVal.I64 = 0; if ((Status = FullGetVal(Reg, &RegVal)) != S_OK) { return Status; } *Value = RegVal.I64; return S_OK; } } HRESULT X86MachineInfo::SetScopeFrameRegister(ULONG Reg, PDEBUG_STACK_FRAME ScopeFrame, ULONG64 Value) { REGVAL RegVal; switch(Reg) { case X86_ESP: ScopeFrame->StackOffset = Value; return S_OK; case X86_EBP: // Don't allow EBP updating due to the FPO complexities. return E_INVALIDARG; default: RegVal.Type = GetType(Reg); RegVal.I64 = Value; return FullSetVal(Reg, &RegVal); } } void X86MachineInfo::SanitizeMemoryContext(PCROSS_PLATFORM_CONTEXT Context) { if (Context->X86Context.EFlags & X86_EFLAGS_V86_MASK) { Context->X86Context.SegSs &= 0xffff; } else if (Context->X86Context.SegCs & X86_MODE_MASK) { // // It's user mode. The HardwareSegSs contains R3 data selector. // Context->X86Context.SegSs = (USHORT)(Context->X86Context.SegSs | X86_RPL_MASK) & 0xffff; } else { Context->X86Context.SegSs = m_Target->m_KdDebuggerData.GdtR0Data; } } HRESULT X86MachineInfo::GetExdiContext(IUnknown* Exdi, PEXDI_CONTEXT Context, EXDI_CONTEXT_TYPE CtxType) { // Always ask for everything. switch(CtxType) { case EXDI_CTX_X86: Context->X86Context.RegGroupSelection.fSegmentRegs = TRUE; Context->X86Context.RegGroupSelection.fControlRegs = TRUE; Context->X86Context.RegGroupSelection.fIntegerRegs = TRUE; Context->X86Context.RegGroupSelection.fFloatingPointRegs = TRUE; Context->X86Context.RegGroupSelection.fDebugRegs = TRUE; return ((IeXdiX86Context*)Exdi)->GetContext(&Context->X86Context); case EXDI_CTX_X86_EX: Context->X86ExContext.RegGroupSelection.fSegmentRegs = TRUE; Context->X86ExContext.RegGroupSelection.fControlRegs = TRUE; Context->X86ExContext.RegGroupSelection.fIntegerRegs = TRUE; Context->X86ExContext.RegGroupSelection.fFloatingPointRegs = TRUE; Context->X86ExContext.RegGroupSelection.fDebugRegs = TRUE; Context->X86ExContext.RegGroupSelection.fSegmentDescriptors = TRUE; Context->X86ExContext.RegGroupSelection.fSSERegisters = TRUE; Context->X86ExContext.RegGroupSelection.fSystemRegisters = TRUE; return ((IeXdiX86ExContext*)Exdi)->GetContext(&Context->X86ExContext); default: return E_INVALIDARG; } } HRESULT X86MachineInfo::SetExdiContext(IUnknown* Exdi, PEXDI_CONTEXT Context, EXDI_CONTEXT_TYPE CtxType) { // Don't change the existing group selections on the assumption // that there was a full get prior to any modifications so // all groups are valid. switch(CtxType) { case EXDI_CTX_X86: return ((IeXdiX86Context*)Exdi)->SetContext(Context->X86Context); case EXDI_CTX_X86_EX: return ((IeXdiX86ExContext*)Exdi)->SetContext(Context->X86ExContext); default: return E_INVALIDARG; } } void X86MachineInfo::ConvertExdiContextFromContext(PCROSS_PLATFORM_CONTEXT Context, PEXDI_CONTEXT ExdiContext, EXDI_CONTEXT_TYPE CtxType) { switch(CtxType) { case EXDI_CTX_X86: if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_SEGMENTS) { ExdiContext->X86Context.SegGs = (USHORT)Context->X86Nt5Context.SegGs; ExdiContext->X86Context.SegFs = (USHORT)Context->X86Nt5Context.SegFs; ExdiContext->X86Context.SegEs = (USHORT)Context->X86Nt5Context.SegEs; ExdiContext->X86Context.SegDs = (USHORT)Context->X86Nt5Context.SegDs; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_CONTROL) { ExdiContext->X86Context.Ebp = Context->X86Nt5Context.Ebp; ExdiContext->X86Context.Eip = Context->X86Nt5Context.Eip; ExdiContext->X86Context.SegCs = (USHORT)Context->X86Nt5Context.SegCs; ExdiContext->X86Context.EFlags = Context->X86Nt5Context.EFlags; ExdiContext->X86Context.Esp = Context->X86Nt5Context.Esp; ExdiContext->X86Context.SegSs = (USHORT)Context->X86Nt5Context.SegSs; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_INTEGER) { ExdiContext->X86Context.Eax = Context->X86Nt5Context.Eax; ExdiContext->X86Context.Ebx = Context->X86Nt5Context.Ebx; ExdiContext->X86Context.Ecx = Context->X86Nt5Context.Ecx; ExdiContext->X86Context.Edx = Context->X86Nt5Context.Edx; ExdiContext->X86Context.Esi = Context->X86Nt5Context.Esi; ExdiContext->X86Context.Edi = Context->X86Nt5Context.Edi; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_FLOATING_POINT) { C_ASSERT(sizeof(X86_FLOATING_SAVE_AREA) == FIELD_OFFSET(CONTEXT_X86, Dr0) - FIELD_OFFSET(CONTEXT_X86, ControlWord)); memcpy(&ExdiContext->X86Context.ControlWord, &Context->X86Nt5Context.FloatSave, sizeof(X86_FLOATING_SAVE_AREA)); } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_DEBUG_REGISTERS) { ExdiContext->X86Context.Dr0 = Context->X86Nt5Context.Dr0; ExdiContext->X86Context.Dr1 = Context->X86Nt5Context.Dr1; ExdiContext->X86Context.Dr2 = Context->X86Nt5Context.Dr2; ExdiContext->X86Context.Dr3 = Context->X86Nt5Context.Dr3; ExdiContext->X86Context.Dr6 = Context->X86Nt5Context.Dr6; ExdiContext->X86Context.Dr7 = Context->X86Nt5Context.Dr7; } break; case EXDI_CTX_X86_EX: if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_SEGMENTS) { ExdiContext->X86ExContext.SegGs = (USHORT)Context->X86Nt5Context.SegGs; ExdiContext->X86ExContext.SegFs = (USHORT)Context->X86Nt5Context.SegFs; ExdiContext->X86ExContext.SegEs = (USHORT)Context->X86Nt5Context.SegEs; ExdiContext->X86ExContext.SegDs = (USHORT)Context->X86Nt5Context.SegDs; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_CONTROL) { ExdiContext->X86ExContext.Ebp = Context->X86Nt5Context.Ebp; ExdiContext->X86ExContext.Eip = Context->X86Nt5Context.Eip; ExdiContext->X86ExContext.SegCs = (USHORT)Context->X86Nt5Context.SegCs; ExdiContext->X86ExContext.EFlags = Context->X86Nt5Context.EFlags; ExdiContext->X86ExContext.Esp = Context->X86Nt5Context.Esp; ExdiContext->X86ExContext.SegSs = (USHORT)Context->X86Nt5Context.SegSs; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_INTEGER) { ExdiContext->X86ExContext.Eax = Context->X86Nt5Context.Eax; ExdiContext->X86ExContext.Ebx = Context->X86Nt5Context.Ebx; ExdiContext->X86ExContext.Ecx = Context->X86Nt5Context.Ecx; ExdiContext->X86ExContext.Edx = Context->X86Nt5Context.Edx; ExdiContext->X86ExContext.Esi = Context->X86Nt5Context.Esi; ExdiContext->X86ExContext.Edi = Context->X86Nt5Context.Edi; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_FLOATING_POINT) { C_ASSERT(sizeof(X86_FLOATING_SAVE_AREA) == FIELD_OFFSET(CONTEXT_X86_EX, Dr0) - FIELD_OFFSET(CONTEXT_X86_EX, ControlWord)); memcpy(&ExdiContext->X86ExContext.ControlWord, &Context->X86Nt5Context.FloatSave, sizeof(X86_FLOATING_SAVE_AREA)); } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_DEBUG_REGISTERS) { ExdiContext->X86ExContext.Dr0 = Context->X86Nt5Context.Dr0; ExdiContext->X86ExContext.Dr1 = Context->X86Nt5Context.Dr1; ExdiContext->X86ExContext.Dr2 = Context->X86Nt5Context.Dr2; ExdiContext->X86ExContext.Dr3 = Context->X86Nt5Context.Dr3; ExdiContext->X86ExContext.Dr6 = Context->X86Nt5Context.Dr6; ExdiContext->X86ExContext.Dr7 = Context->X86Nt5Context.Dr7; } if (Context->X86Nt5Context.ContextFlags & VDMCONTEXT_EXTENDED_REGISTERS) { C_ASSERT(X86_SIZE_OF_FX_REGISTERS == sizeof(ExdiContext->X86ExContext.Sse)); memcpy(ExdiContext->X86ExContext.Sse, Context->X86Nt5Context.FxSave.Reserved3, X86_SIZE_OF_FX_REGISTERS); ExdiContext->X86ExContext.Mxcsr = Context->X86Nt5Context.FxSave.MXCsr; } break; default: DBG_ASSERT(FALSE); break; } } void X86MachineInfo::ConvertExdiContextToContext(PEXDI_CONTEXT ExdiContext, EXDI_CONTEXT_TYPE CtxType, PCROSS_PLATFORM_CONTEXT Context) { switch(CtxType) { case EXDI_CTX_X86: Context->X86Nt5Context.SegCs = ExdiContext->X86Context.SegCs; Context->X86Nt5Context.SegSs = ExdiContext->X86Context.SegSs; Context->X86Nt5Context.SegGs = ExdiContext->X86Context.SegGs; Context->X86Nt5Context.SegFs = ExdiContext->X86Context.SegFs; Context->X86Nt5Context.SegEs = ExdiContext->X86Context.SegEs; Context->X86Nt5Context.SegDs = ExdiContext->X86Context.SegDs; Context->X86Nt5Context.EFlags = ExdiContext->X86Context.EFlags; Context->X86Nt5Context.Ebp = ExdiContext->X86Context.Ebp; Context->X86Nt5Context.Eip = ExdiContext->X86Context.Eip; Context->X86Nt5Context.Esp = ExdiContext->X86Context.Esp; Context->X86Nt5Context.Eax = ExdiContext->X86Context.Eax; Context->X86Nt5Context.Ebx = ExdiContext->X86Context.Ebx; Context->X86Nt5Context.Ecx = ExdiContext->X86Context.Ecx; Context->X86Nt5Context.Edx = ExdiContext->X86Context.Edx; Context->X86Nt5Context.Esi = ExdiContext->X86Context.Esi; Context->X86Nt5Context.Edi = ExdiContext->X86Context.Edi; C_ASSERT(sizeof(X86_FLOATING_SAVE_AREA) == FIELD_OFFSET(CONTEXT_X86, Dr0) - FIELD_OFFSET(CONTEXT_X86, ControlWord)); memcpy(&Context->X86Nt5Context.FloatSave, &ExdiContext->X86Context.ControlWord, sizeof(X86_FLOATING_SAVE_AREA)); Context->X86Nt5Context.Dr0 = ExdiContext->X86Context.Dr0; Context->X86Nt5Context.Dr1 = ExdiContext->X86Context.Dr1; Context->X86Nt5Context.Dr2 = ExdiContext->X86Context.Dr2; Context->X86Nt5Context.Dr3 = ExdiContext->X86Context.Dr3; Context->X86Nt5Context.Dr6 = ExdiContext->X86Context.Dr6; Context->X86Nt5Context.Dr7 = ExdiContext->X86Context.Dr7; break; case EXDI_CTX_X86_EX: Context->X86Nt5Context.SegCs = ExdiContext->X86ExContext.SegCs; Context->X86Nt5Context.SegSs = ExdiContext->X86ExContext.SegSs; Context->X86Nt5Context.SegGs = ExdiContext->X86ExContext.SegGs; Context->X86Nt5Context.SegFs = ExdiContext->X86ExContext.SegFs; Context->X86Nt5Context.SegEs = ExdiContext->X86ExContext.SegEs; Context->X86Nt5Context.SegDs = ExdiContext->X86ExContext.SegDs; Context->X86Nt5Context.EFlags = ExdiContext->X86ExContext.EFlags; Context->X86Nt5Context.Ebp = ExdiContext->X86ExContext.Ebp; Context->X86Nt5Context.Eip = ExdiContext->X86ExContext.Eip; Context->X86Nt5Context.Esp = ExdiContext->X86ExContext.Esp; Context->X86Nt5Context.Eax = ExdiContext->X86ExContext.Eax; Context->X86Nt5Context.Ebx = ExdiContext->X86ExContext.Ebx; Context->X86Nt5Context.Ecx = ExdiContext->X86ExContext.Ecx; Context->X86Nt5Context.Edx = ExdiContext->X86ExContext.Edx; Context->X86Nt5Context.Esi = ExdiContext->X86ExContext.Esi; Context->X86Nt5Context.Edi = ExdiContext->X86ExContext.Edi; C_ASSERT(sizeof(X86_FLOATING_SAVE_AREA) == FIELD_OFFSET(CONTEXT_X86, Dr0) - FIELD_OFFSET(CONTEXT_X86, ControlWord)); memcpy(&Context->X86Nt5Context.FloatSave, &ExdiContext->X86ExContext.ControlWord, sizeof(X86_FLOATING_SAVE_AREA)); Context->X86Nt5Context.Dr0 = ExdiContext->X86ExContext.Dr0; Context->X86Nt5Context.Dr1 = ExdiContext->X86ExContext.Dr1; Context->X86Nt5Context.Dr2 = ExdiContext->X86ExContext.Dr2; Context->X86Nt5Context.Dr3 = ExdiContext->X86ExContext.Dr3; Context->X86Nt5Context.Dr6 = ExdiContext->X86ExContext.Dr6; Context->X86Nt5Context.Dr7 = ExdiContext->X86ExContext.Dr7; C_ASSERT(X86_SIZE_OF_FX_REGISTERS == sizeof(ExdiContext->X86ExContext.Sse)); memcpy(Context->X86Nt5Context.FxSave.Reserved3, ExdiContext->X86ExContext.Sse, X86_SIZE_OF_FX_REGISTERS); Context->X86Nt5Context.FxSave.MXCsr = ExdiContext->X86ExContext.Mxcsr; break; default: DBG_ASSERT(FALSE); break; } } void X86MachineInfo::ConvertExdiContextToSegDescs(PEXDI_CONTEXT ExdiContext, EXDI_CONTEXT_TYPE CtxType, ULONG Start, ULONG Count, PDESCRIPTOR64 Descs) { switch(CtxType) { case EXDI_CTX_X86: // The basic x86 context doesn't have descriptor // state so just fake something up for basic boot state. while (Count-- > 0) { ULONG Type; if (Start == SEGREG_CODE) { Descs->Base = EXTEND64(0xffff0000); Type = 0x13; } else { Descs->Base = 0; Type = 0x1b; } Descs->Limit = 0xfffff; Descs->Flags = X86_DESC_PRESENT | X86_DESC_DEFAULT_BIG | Type; Descs++; Start++; } break; case EXDI_CTX_X86_EX: while (Count-- > 0) { X86_SEG_DESC_INFO* Desc; switch(Start) { case SEGREG_CODE: Desc = &ExdiContext->X86ExContext.DescriptorCs; break; case SEGREG_DATA: Desc = &ExdiContext->X86ExContext.DescriptorDs; break; case SEGREG_STACK: Desc = &ExdiContext->X86ExContext.DescriptorSs; break; case SEGREG_ES: Desc = &ExdiContext->X86ExContext.DescriptorEs; break; case SEGREG_FS: Desc = &ExdiContext->X86ExContext.DescriptorFs; break; case SEGREG_GS: Desc = &ExdiContext->X86ExContext.DescriptorGs; break; case SEGREG_GDT: Descs->Base = ExdiContext->X86ExContext.GdtBase; Descs->Limit = ExdiContext->X86ExContext.GdtLimit; Descs->Flags = X86_DESC_PRESENT; Desc = NULL; break; case SEGREG_LDT: Desc = &ExdiContext->X86ExContext.DescriptorLdtr; break; default: Descs->Flags = SEGDESC_INVALID; Desc = NULL; break; } if (Desc != NULL) { Descs->Base = EXTEND64(Desc->Base); Descs->Limit = Desc->Limit; Descs->Flags = ((Desc->Flags >> 4) & 0xf00) | (Desc->Flags & 0xff); } Descs++; Start++; } break; default: DBG_ASSERT(FALSE); break; } } void X86MachineInfo::ConvertExdiContextFromSpecial (PCROSS_PLATFORM_KSPECIAL_REGISTERS Special, PEXDI_CONTEXT ExdiContext, EXDI_CONTEXT_TYPE CtxType) { switch(CtxType) { case EXDI_CTX_X86: // No such information. break; case EXDI_CTX_X86_EX: ExdiContext->X86ExContext.Cr0 = Special->X86Special.Cr0; ExdiContext->X86ExContext.Cr2 = Special->X86Special.Cr2; ExdiContext->X86ExContext.Cr3 = Special->X86Special.Cr3; ExdiContext->X86ExContext.Cr4 = Special->X86Special.Cr4; ExdiContext->X86ExContext.Dr0 = Special->X86Special.KernelDr0; ExdiContext->X86ExContext.Dr1 = Special->X86Special.KernelDr1; ExdiContext->X86ExContext.Dr2 = Special->X86Special.KernelDr2; ExdiContext->X86ExContext.Dr3 = Special->X86Special.KernelDr3; ExdiContext->X86ExContext.Dr6 = Special->X86Special.KernelDr6; ExdiContext->X86ExContext.Dr7 = Special->X86Special.KernelDr7; ExdiContext->X86ExContext.GdtLimit = Special->X86Special.Gdtr.Limit; ExdiContext->X86ExContext.GdtBase = Special->X86Special.Gdtr.Base; ExdiContext->X86ExContext.IdtLimit = Special->X86Special.Idtr.Limit; ExdiContext->X86ExContext.IdtBase = Special->X86Special.Idtr.Base; ExdiContext->X86ExContext.Tr = Special->X86Special.Tr; ExdiContext->X86ExContext.Ldtr = Special->X86Special.Ldtr; break; default: DBG_ASSERT(FALSE); break; } } void X86MachineInfo::ConvertExdiContextToSpecial (PEXDI_CONTEXT ExdiContext, EXDI_CONTEXT_TYPE CtxType, PCROSS_PLATFORM_KSPECIAL_REGISTERS Special) { switch(CtxType) { case EXDI_CTX_X86: // No such information. break; case EXDI_CTX_X86_EX: Special->X86Special.Cr0 = ExdiContext->X86ExContext.Cr0; Special->X86Special.Cr2 = ExdiContext->X86ExContext.Cr2; Special->X86Special.Cr3 = ExdiContext->X86ExContext.Cr3; Special->X86Special.Cr4 = ExdiContext->X86ExContext.Cr4; Special->X86Special.KernelDr0 = ExdiContext->X86ExContext.Dr0; Special->X86Special.KernelDr1 = ExdiContext->X86ExContext.Dr1; Special->X86Special.KernelDr2 = ExdiContext->X86ExContext.Dr2; Special->X86Special.KernelDr3 = ExdiContext->X86ExContext.Dr3; Special->X86Special.KernelDr6 = ExdiContext->X86ExContext.Dr6; Special->X86Special.KernelDr7 = ExdiContext->X86ExContext.Dr7; Special->X86Special.Gdtr.Limit = (USHORT)ExdiContext->X86ExContext.GdtLimit; Special->X86Special.Gdtr.Base = ExdiContext->X86ExContext.GdtBase; Special->X86Special.Idtr.Limit = (USHORT)ExdiContext->X86ExContext.IdtLimit; Special->X86Special.Idtr.Base = ExdiContext->X86ExContext.IdtBase; Special->X86Special.Tr = (USHORT)ExdiContext->X86ExContext.Tr; Special->X86Special.Ldtr = (USHORT)ExdiContext->X86ExContext.Ldtr; break; default: DBG_ASSERT(FALSE); break; } } int X86MachineInfo::GetType(ULONG Reg) { if (Reg >= X86_MM_FIRST && Reg <= X86_MM_LAST) { return REGVAL_INT64; } else if (Reg >= X86_XMM_FIRST && Reg <= X86_XMM_LAST) { return REGVAL_VECTOR128; } else if (Reg >= X86_ST_FIRST && Reg <= X86_ST_LAST) { return REGVAL_FLOAT10; } else if (Reg < X86_FLAGBASE) { return REGVAL_INT32; } else { return REGVAL_SUB32; } } HRESULT X86MachineInfo::GetVal(ULONG Reg, REGVAL* Val) { HRESULT Status; if (Reg >= X86_MM_FIRST && Reg <= X86_MM_LAST) { Val->Type = REGVAL_VECTOR64; GetMmxReg(Reg, Val); } else if (Reg >= X86_XMM_FIRST && Reg <= X86_XMM_LAST) { if ((Status = GetContextState(MCTX_CONTEXT)) != S_OK) { return Status; } Val->Type = REGVAL_VECTOR128; memcpy(Val->Bytes, m_Context.X86Nt5Context.FxSave.Reserved3 + (Reg - X86_XMM_FIRST) * 16, 16); } else if (Reg >= X86_ST_FIRST && Reg <= X86_ST_LAST) { Val->Type = REGVAL_FLOAT10; GetFloatReg(Reg, Val); } else if (Reg < X86_FLAGBASE) { Val->Type = REGVAL_INT32; Val->I64 = (ULONG64)(LONG64)(LONG)GetIntReg(Reg); } else { ErrOut("X86MachineInfo::GetVal: " "unknown register %lx requested\n", Reg); return E_INVALIDARG; } return S_OK; } HRESULT X86MachineInfo::SetVal(ULONG Reg, REGVAL* Val) { HRESULT Status; if (m_ContextIsReadOnly) { return HRESULT_FROM_WIN32(ERROR_WRITE_FAULT); } if (Reg >= X86_FLAGBASE) { return E_INVALIDARG; } // Optimize away some common cases where registers are // set to their current value. if ((m_ContextState >= MCTX_PC && Reg == X86_EIP && Val->I32 == m_Context.X86Nt5Context.Eip) || (((m_ContextState >= MCTX_DR67_REPORT && m_ContextState <= MCTX_REPORT) || m_ContextState >= MCTX_FULL) && Reg == X86_DR7 && Val->I32 == m_Context.X86Nt5Context.Dr7)) { return S_OK; } if ((Status = GetContextState(MCTX_DIRTY)) != S_OK) { return Status; } if (Reg >= X86_MM_FIRST && Reg <= X86_MM_LAST) { *(ULONG64 UNALIGNED *)GetMmxRegSlot(Reg) = Val->I64; goto Notify; } else if (Reg >= X86_XMM_FIRST && Reg <= X86_XMM_LAST) { memcpy(m_Context.X86Nt5Context.FxSave.Reserved3 + (Reg - X86_XMM_FIRST) * 16, Val->Bytes, 16); goto Notify; } else if (Reg >= X86_ST_FIRST && Reg <= X86_ST_LAST) { memcpy(m_Context.X86Nt5Context.FloatSave.RegisterArea + 10 * (Reg - X86_ST_FIRST), Val->F10, sizeof(Val->F10)); goto Notify; } BOOL Recognized; Recognized = TRUE; switch(Reg) { case X86_GS: m_Context.X86Nt5Context.SegGs = Val->I16; m_SegRegDesc[SEGREG_GS].Flags = SEGDESC_INVALID; break; case X86_FS: m_Context.X86Nt5Context.SegFs = Val->I16; m_SegRegDesc[SEGREG_FS].Flags = SEGDESC_INVALID; break; case X86_ES: m_Context.X86Nt5Context.SegEs = Val->I16; m_SegRegDesc[SEGREG_ES].Flags = SEGDESC_INVALID; break; case X86_DS: m_Context.X86Nt5Context.SegDs = Val->I16; m_SegRegDesc[SEGREG_DATA].Flags = SEGDESC_INVALID; break; case X86_EDI: m_Context.X86Nt5Context.Edi = Val->I32; break; case X86_ESI: m_Context.X86Nt5Context.Esi = Val->I32; break; case X86_EBX: m_Context.X86Nt5Context.Ebx = Val->I32; break; case X86_EDX: m_Context.X86Nt5Context.Edx = Val->I32; break; case X86_ECX: m_Context.X86Nt5Context.Ecx = Val->I32; break; case X86_EAX: m_Context.X86Nt5Context.Eax = Val->I32; break; case X86_EBP: m_Context.X86Nt5Context.Ebp = Val->I32; break; case X86_EIP: m_Context.X86Nt5Context.Eip = Val->I32; break; case X86_CS: m_Context.X86Nt5Context.SegCs = Val->I16; m_SegRegDesc[SEGREG_CODE].Flags = SEGDESC_INVALID; break; case X86_EFL: if (IS_KERNEL_TARGET(m_Target)) { // leave TF clear m_Context.X86Nt5Context.EFlags = Val->I32 & ~0x100; } else { // allow TF set m_Context.X86Nt5Context.EFlags = Val->I32; } break; case X86_ESP: m_Context.X86Nt5Context.Esp = Val->I32; break; case X86_SS: m_Context.X86Nt5Context.SegSs = Val->I16; m_SegRegDesc[SEGREG_STACK].Flags = SEGDESC_INVALID; break; case X86_DR0: m_Context.X86Nt5Context.Dr0 = Val->I32; break; case X86_DR1: m_Context.X86Nt5Context.Dr1 = Val->I32; break; case X86_DR2: m_Context.X86Nt5Context.Dr2 = Val->I32; break; case X86_DR3: m_Context.X86Nt5Context.Dr3 = Val->I32; break; case X86_DR6: m_Context.X86Nt5Context.Dr6 = Val->I32; break; case X86_DR7: m_Context.X86Nt5Context.Dr7 = Val->I32; break; case X86_FPCW: m_Context.X86Nt5Context.FloatSave.ControlWord = (m_Context.X86Nt5Context.FloatSave.ControlWord & 0xffff0000) | (Val->I32 & 0xffff); break; case X86_FPSW: m_Context.X86Nt5Context.FloatSave.StatusWord = (m_Context.X86Nt5Context.FloatSave.StatusWord & 0xffff0000) | (Val->I32 & 0xffff); break; case X86_FPTW: m_Context.X86Nt5Context.FloatSave.TagWord = (m_Context.X86Nt5Context.FloatSave.TagWord & 0xffff0000) | (Val->I32 & 0xffff); break; case X86_MXCSR: m_Context.X86Nt5Context.FxSave.MXCsr = Val->I32; break; default: Recognized = FALSE; break; } if (!Recognized && IS_KERNEL_TARGET(m_Target)) { Recognized = TRUE; switch(Reg) { case X86_CR0: m_Special.X86Special.Cr0 = Val->I32; break; case X86_CR2: m_Special.X86Special.Cr2 = Val->I32; break; case X86_CR3: m_Special.X86Special.Cr3 = Val->I32; break; case X86_CR4: m_Special.X86Special.Cr4 = Val->I32; break; case X86_GDTR: m_Special.X86Special.Gdtr.Base = Val->I32; break; case X86_GDTL: m_Special.X86Special.Gdtr.Limit = (USHORT)Val->I32; break; case X86_IDTR: m_Special.X86Special.Idtr.Base = Val->I32; break; case X86_IDTL: m_Special.X86Special.Idtr.Limit = (USHORT)Val->I32; break; case X86_TR: m_Special.X86Special.Tr = (USHORT)Val->I32; break; case X86_LDTR: m_Special.X86Special.Ldtr = (USHORT)Val->I32; break; default: Recognized = FALSE; break; } } if (!Recognized) { ErrOut("X86MachineInfo::SetVal: " "unknown register %lx requested\n", Reg); return E_INVALIDARG; } Notify: NotifyChangeDebuggeeState(DEBUG_CDS_REGISTERS, RegCountFromIndex(Reg)); return S_OK; } void X86MachineInfo::GetPC (PADDR Address) { FormAddr(SEGREG_CODE, EXTEND64(GetIntReg(X86_EIP)), FORM_CODE | FORM_SEGREG | X86_FORM_VM86(GetIntReg(X86_EFL)), Address); } void X86MachineInfo::SetPC (PADDR paddr) { REGVAL Val; // We set the EIP to the offset (the non-translated value), // because we may not be in "flat" mode !!! Val.Type = REGVAL_INT32; Val.I32 = (ULONG)Off(*paddr); SetVal(X86_EIP, &Val); } void X86MachineInfo::GetFP(PADDR Addr) { FormAddr(SEGREG_STACK, EXTEND64(GetIntReg(X86_EBP)), FORM_SEGREG | X86_FORM_VM86(GetIntReg(X86_EFL)), Addr); } void X86MachineInfo::GetSP(PADDR Addr) { FormAddr(SEGREG_STACK, EXTEND64(GetIntReg(X86_ESP)), FORM_SEGREG | X86_FORM_VM86(GetIntReg(X86_EFL)), Addr); } ULONG64 X86MachineInfo::GetArgReg(void) { return (ULONG64)(LONG64)(LONG)GetIntReg(X86_EAX); } ULONG64 X86MachineInfo::GetRetReg(void) { return (ULONG64)(LONG64)(LONG)GetIntReg(X86_EAX); } ULONG X86MachineInfo::GetSegRegNum(ULONG SegReg) { switch(SegReg) { case SEGREG_CODE: return X86_CS; case SEGREG_DATA: return X86_DS; case SEGREG_STACK: return X86_SS; case SEGREG_ES: return X86_ES; case SEGREG_FS: return X86_FS; case SEGREG_GS: return X86_GS; case SEGREG_LDT: return X86_LDTR; } return 0; } HRESULT X86MachineInfo::GetSegRegDescriptor(ULONG SegReg, PDESCRIPTOR64 Desc) { if (SegReg == SEGREG_GDT) { Desc->Base = EXTEND64(GetIntReg(X86_GDTR)); Desc->Limit = GetIntReg(X86_GDTL); Desc->Flags = 0; return S_OK; } // Check and see if we already have a cached descriptor. if (m_SegRegDesc[SegReg].Flags != SEGDESC_INVALID) { *Desc = m_SegRegDesc[SegReg]; return S_OK; } HRESULT Status; // Attempt to retrieve segment descriptors directly. if ((Status = GetContextState(MCTX_FULL)) != S_OK) { return Status; } // Check and see if we now have a cached descriptor. if (m_SegRegDesc[SegReg].Flags != SEGDESC_INVALID) { *Desc = m_SegRegDesc[SegReg]; return S_OK; } // // Direct information is not available so look things up // in the descriptor tables. // ULONG RegNum = GetSegRegNum(SegReg); if (RegNum == 0) { return E_INVALIDARG; } // Do a quick sanity test to prevent bad values // from causing problems. ULONG Selector = GetIntReg(RegNum); if (SegReg == SEGREG_LDT && (Selector & 4)) { // The ldtr selector says that it's an LDT selector, // which is invalid. An LDT selector should always // reference the GDT. ErrOut("Invalid LDTR contents: %04X\n", Selector); return E_FAIL; } return m_Target->GetSelDescriptor(m_Target->m_RegContextThread, this, Selector, Desc); } /*** X86OutputAll - output all registers and present instruction * * Purpose: * To output the current register state of the processor. * All integer registers are output as well as processor status * registers. Important flag fields are also output separately. * * Input: * Mask - Which information to display. * * Output: * None. * *************************************************************************/ void X86MachineInfo::OutputAll(ULONG Mask, ULONG OutMask) { if (GetContextState(MCTX_FULL) != S_OK) { ErrOut("Unable to retrieve register information\n"); return; } if (Mask & (REGALL_INT32 | REGALL_INT64)) { ULONG efl; MaskOut(OutMask, "eax=%08lx ebx=%08lx ecx=%08lx " "edx=%08lx esi=%08lx edi=%08lx\n", GetIntReg(X86_EAX), GetIntReg(X86_EBX), GetIntReg(X86_ECX), GetIntReg(X86_EDX), GetIntReg(X86_ESI), GetIntReg(X86_EDI)); efl = GetIntReg(X86_EFL); MaskOut(OutMask, "eip=%08lx esp=%08lx ebp=%08lx iopl=%1lx " "%s %s %s %s %s %s %s %s %s %s\n", GetIntReg(X86_EIP), GetIntReg(X86_ESP), GetIntReg(X86_EBP), ((efl >> X86_SHIFT_FLAGIOPL) & X86_BIT_FLAGIOPL), (efl & X86_BIT_FLAGVIP) ? "vip" : " ", (efl & X86_BIT_FLAGVIF) ? "vif" : " ", (efl & X86_BIT_FLAGOF) ? "ov" : "nv", (efl & X86_BIT_FLAGDF) ? "dn" : "up", (efl & X86_BIT_FLAGIF) ? "ei" : "di", (efl & X86_BIT_FLAGSF) ? "ng" : "pl", (efl & X86_BIT_FLAGZF) ? "zr" : "nz", (efl & X86_BIT_FLAGAF) ? "ac" : "na", (efl & X86_BIT_FLAGPF) ? "po" : "pe", (efl & X86_BIT_FLAGCF) ? "cy" : "nc"); } if (Mask & REGALL_SEGREG) { MaskOut(OutMask, "cs=%04lx ss=%04lx ds=%04lx es=%04lx fs=%04lx " "gs=%04lx efl=%08lx\n", GetIntReg(X86_CS), GetIntReg(X86_SS), GetIntReg(X86_DS), GetIntReg(X86_ES), GetIntReg(X86_FS), GetIntReg(X86_GS), GetIntReg(X86_EFL)); } if (Mask & REGALL_FLOAT) { ULONG i; REGVAL val; char buf[32]; MaskOut(OutMask, "fpcw=%04X fpsw=%04X fptw=%04X\n", GetIntReg(X86_FPCW), GetIntReg(X86_FPSW), GetIntReg(X86_FPTW)); for (i = X86_ST_FIRST; i <= X86_ST_LAST; i++) { GetFloatReg(i, &val); _uldtoa((_ULDOUBLE *)&val.F10, sizeof(buf), buf); MaskOut(OutMask, "st%d=%s ", i - X86_ST_FIRST, buf); i++; GetFloatReg(i, &val); _uldtoa((_ULDOUBLE *)&val.F10, sizeof(buf), buf); MaskOut(OutMask, "st%d=%s\n", i - X86_ST_FIRST, buf); } } if (Mask & REGALL_MMXREG) { ULONG i; REGVAL val; for (i = X86_MM_FIRST; i <= X86_MM_LAST; i++) { GetMmxReg(i, &val); MaskOut(OutMask, "mm%d=%08x%08x ", i - X86_MM_FIRST, val.I64Parts.High, val.I64Parts.Low); i++; GetMmxReg(i, &val); MaskOut(OutMask, "mm%d=%08x%08x\n", i - X86_MM_FIRST, val.I64Parts.High, val.I64Parts.Low); } } if (Mask & REGALL_XMMREG) { ULONG i; REGVAL Val; for (i = X86_XMM_FIRST; i <= X86_XMM_LAST; i++) { GetVal(i, &Val); MaskOut(OutMask, "xmm%d=%hg %hg %hg %hg\n", i - X86_XMM_FIRST, *(float *)&Val.Bytes[3 * sizeof(float)], *(float *)&Val.Bytes[2 * sizeof(float)], *(float *)&Val.Bytes[1 * sizeof(float)], *(float *)&Val.Bytes[0 * sizeof(float)]); } } if (Mask & REGALL_CREG) { MaskOut(OutMask, "cr0=%08lx cr2=%08lx cr3=%08lx\n", GetIntReg(X86_CR0), GetIntReg(X86_CR2), GetIntReg(X86_CR3)); } if (Mask & REGALL_DREG) { MaskOut(OutMask, "dr0=%08lx dr1=%08lx dr2=%08lx\n", GetIntReg(X86_DR0), GetIntReg(X86_DR1), GetIntReg(X86_DR2)); MaskOut(OutMask, "dr3=%08lx dr6=%08lx dr7=%08lx", GetIntReg(X86_DR3), GetIntReg(X86_DR6), GetIntReg(X86_DR7)); if (IS_USER_TARGET(m_Target)) { MaskOut(OutMask, "\n"); } else { MaskOut(OutMask, " cr4=%08lx\n", GetIntReg(X86_CR4)); } } if (Mask & REGALL_DESC) { MaskOut(OutMask, "gdtr=%08lx gdtl=%04lx idtr=%08lx idtl=%04lx " "tr=%04lx ldtr=%04x\n", GetIntReg(X86_GDTR), GetIntReg(X86_GDTL), GetIntReg(X86_IDTR), GetIntReg(X86_IDTL), GetIntReg(X86_TR), GetIntReg(X86_LDTR)); } } HRESULT X86MachineInfo::SetAndOutputTrapFrame(ULONG64 TrapBase, PCROSS_PLATFORM_CONTEXT Context) { HRESULT Status; X86_KTRAP_FRAME TrapContents; if ((Status = m_Target->ReadAllVirtual(m_Target->m_ProcessHead, TrapBase, &TrapContents, sizeof(TrapContents))) != S_OK) { ErrOut("Unable to read trap frame at %s\n", FormatMachineAddr64(this, TrapBase)); return Status; } // // Check to see if Esp has been edited, and dump new value if it has // if ((!(TrapContents.EFlags & X86_EFLAGS_V86_MASK)) && ((TrapContents.SegCs & X86_MODE_MASK) == 0 /*KernelMode*/)) { if ((TrapContents.SegCs & X86_FRAME_EDITED) == 0) { dprintf("ESP EDITED! New esp=%08lx\n", TrapContents.TempEsp); } } dprintf("ErrCode = %08lx\n", TrapContents.ErrCode); return SetAndOutputContext(Context, TRUE, REGALL_INT32 | REGALL_SEGREG); } HRESULT X86MachineInfo::SetAndOutputTaskSegment(ULONG64 TssBase, PCROSS_PLATFORM_CONTEXT Context, BOOL Extended) { HRESULT Status; X86_KTSS TSS; ULONG i; if ((Status = m_Target->ReadAllVirtual(m_Target->m_ProcessHead, TssBase, &TSS, sizeof(TSS))) != S_OK) { ErrOut("Unable to read Task State Segment from host address %s\n", FormatMachineAddr64(this, TssBase)); return Status; } // // Display it. // if (Extended) { dprintf("\nTask State Segment 0x%p\n\n", TssBase); dprintf("Previous Task Link = %4x\n", TSS.Previous); for (i = 0 ; i < X86_MAX_RING; i++) { dprintf("Esp%d = %8x SS%d = %4x\n", i, TSS.Ring[i].Esp, i, TSS.Ring[i].Ss & 0xffff); } dprintf("CR3 (PDBR) = %08x\n", TSS.Cr3); dprintf("I/O Map Base Address = %4x, Debug Trap (T) = %s\n", TSS.IoMapBase, TSS.T == 0 ? "False" : "True"); dprintf("\nSaved General Purpose Registers\n\n"); } return SetAndOutputContext(Context, TRUE, REGALL_INT32 | REGALL_SEGREG); } TRACEMODE X86MachineInfo::GetTraceMode (void) { if (IS_KERNEL_TARGET(m_Target)) { return m_TraceMode; } else { return ((GetIntReg(X86_EFL) & X86_BIT_FLAGTF) != 0) ? TRACE_INSTRUCTION : TRACE_NONE; } } void X86MachineInfo::SetTraceMode (TRACEMODE Mode) { DBG_ASSERT(Mode == TRACE_NONE || Mode == TRACE_INSTRUCTION || (IS_KERNEL_TARGET(m_Target) && m_SupportsBranchTrace && Mode == TRACE_TAKEN_BRANCH)); if (IS_KERNEL_TARGET(m_Target)) { m_TraceMode = Mode; } else { ULONG Efl = GetIntReg(X86_EFL); switch (Mode) { case TRACE_NONE: Efl &= ~X86_BIT_FLAGTF; break; case TRACE_INSTRUCTION: Efl |= X86_BIT_FLAGTF; break; } SetReg32(X86_EFL, Efl); } } BOOL X86MachineInfo::IsStepStatusSupported(ULONG Status) { switch(Status) { case DEBUG_STATUS_STEP_INTO: case DEBUG_STATUS_STEP_OVER: return TRUE; case DEBUG_STATUS_STEP_BRANCH: return IS_KERNEL_TARGET(m_Target) && m_SupportsBranchTrace; default: return FALSE; } } void X86MachineInfo::KdUpdateControlSet (PDBGKD_ANY_CONTROL_SET ControlSet) { TRACEMODE TraceMode = GetTraceMode(); ULONG64 DebugCtlMsr; ControlSet->X86ControlSet.TraceFlag = TraceMode != TRACE_NONE; ControlSet->X86ControlSet.Dr7 = GetIntReg(X86_DR7); // We assume that branch tracing is off by default so if // we haven't turned branch tracing on there's no need // to do a RMW cycle on the control MSR. This saves two // protocol transactions per step. // The processor turns off the branch-trace and branch-record // flags on every debug trap. That's not quite good enough // as we may need to go back to instruction tracing after an // AV or non-debug trap. if (TraceMode != TRACE_NONE && m_SupportsBranchTrace && (TraceMode == TRACE_TAKEN_BRANCH || m_ResetBranchTrace) && m_Target->ReadMsr(X86_MSR_DEBUG_CTL, &DebugCtlMsr) == S_OK) { if (TraceMode == TRACE_TAKEN_BRANCH) { DebugCtlMsr |= (X86_DEBUG_CTL_BRANCH_TRACE | X86_DEBUG_CTL_LAST_BRANCH_RECORD); m_ResetBranchTrace = TRUE; } else { DebugCtlMsr &= ~(X86_DEBUG_CTL_BRANCH_TRACE | X86_DEBUG_CTL_LAST_BRANCH_RECORD); m_ResetBranchTrace = FALSE; } m_Target->WriteMsr(X86_MSR_DEBUG_CTL, DebugCtlMsr); } BpOut("UpdateControlSet(%d) trace %d, DR7 %X\n", m_Target->m_RegContextProcessor, ControlSet->X86ControlSet.TraceFlag, ControlSet->X86ControlSet.Dr7); if (!g_WatchFunctions.IsStarted() && g_WatchBeginCurFunc != 1) { ControlSet->X86ControlSet.CurrentSymbolStart = 0; ControlSet->X86ControlSet.CurrentSymbolEnd = 0; } else { ControlSet->X86ControlSet.CurrentSymbolStart = (ULONG)g_WatchBeginCurFunc; ControlSet->X86ControlSet.CurrentSymbolEnd = (ULONG)g_WatchEndCurFunc; } } ULONG X86MachineInfo::ExecutingMachine(void) { return IMAGE_FILE_MACHINE_I386; } HRESULT X86MachineInfo::SetPageDirectory(ThreadInfo* Thread, ULONG Idx, ULONG64 PageDir, PULONG NextIdx) { HRESULT Status; ULONG ValidMask; // Figure out which bits will be valid in the value. if (m_Target->m_KdDebuggerData.PaeEnabled) { ValidMask = X86_PDBR_MASK; } else { ValidMask = X86_VALID_PFN_MASK; } *NextIdx = PAGE_DIR_COUNT; if (PageDir == 0) { if (m_Target->m_ActualSystemVersion > XBOX_SVER_START && m_Target->m_ActualSystemVersion < XBOX_SVER_END) { // XBox has only one page directory in CR3 for everything. // The process doesn't have a dirbase entry. PageDir = GetReg32(X86_CR3) & ValidMask; if (PageDir == 0) { // Register retrieval failure. return E_FAIL; } } else { // Assume NT structures. if ((Status = m_Target->ReadImplicitProcessInfoPointer (Thread, m_Target->m_KdDebuggerData.OffsetEprocessDirectoryTableBase, &PageDir)) != S_OK) { return Status; } PageDir &= ValidMask; } if (m_Target->m_ImplicitProcessDataIsDefault && Thread == m_Target->m_RegContextThread && !IS_LOCAL_KERNEL_TARGET(m_Target)) { // Verify that the process dirbase matches the CR3 setting // as a sanity check. ULONG Cr3 = GetReg32(X86_CR3) & ValidMask; if (Cr3 && Cr3 != (ULONG)PageDir) { WarnOut("WARNING: Process directory table base %08X " "doesn't match CR3 %08X\n", (ULONG)PageDir, Cr3); } } } else { PageDir &= ValidMask; } // There is only one page directory so update all the slots. m_PageDirectories[PAGE_DIR_USER] = PageDir; m_PageDirectories[PAGE_DIR_SESSION] = PageDir; m_PageDirectories[PAGE_DIR_KERNEL] = PageDir; return S_OK; } #define X86_PAGE_FILE_INDEX(Entry) \ (((ULONG)(Entry) >> 1) & MAX_PAGING_FILE_MASK) #define X86_PAGE_FILE_OFFSET(Entry) \ (((Entry) >> 12) << X86_PAGE_SHIFT) HRESULT X86MachineInfo::GetVirtualTranslationPhysicalOffsets(ThreadInfo* Thread, ULONG64 Virt, PULONG64 Offsets, ULONG OffsetsSize, PULONG Levels, PULONG PfIndex, PULONG64 LastVal) { ULONG64 Addr; HRESULT Status; *Levels = 0; if (m_Translating) { return E_UNEXPECTED; } m_Translating = TRUE; // // throw away top 32 bits on X86. // Virt &= 0x00000000FFFFFFFF; // // Reset the page directory in case it was 0 // if (m_PageDirectories[PAGE_DIR_SINGLE] == 0) { if ((Status = SetDefaultPageDirectories(Thread, 1 << PAGE_DIR_SINGLE)) != S_OK) { m_Translating = FALSE; return Status; } } KdOut("X86VtoP: Virt %s, pagedir %s\n", FormatMachineAddr64(this, Virt), FormatDisp64(m_PageDirectories[PAGE_DIR_SINGLE])); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = m_PageDirectories[PAGE_DIR_SINGLE]; OffsetsSize--; } // This routine uses the fact that the PFN shift is the same // as the page shift to simplify some expressions. C_ASSERT(X86_VALID_PFN_SHIFT == X86_PAGE_SHIFT); if (m_Target->m_KdDebuggerData.PaeEnabled) { ULONG64 Pdpe; ULONG64 Entry; KdOut(" x86VtoP: PaeEnabled\n"); // Read the Page Directory Pointer entry. Pdpe = ((Virt >> X86_PDPE_SHIFT) * sizeof(Entry)) + m_PageDirectories[PAGE_DIR_SINGLE]; KdOut("X86VtoP: PAE PDPE %s\n", FormatDisp64(Pdpe)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = Pdpe; OffsetsSize--; } if ((Status = m_Target-> ReadAllPhysical(Pdpe, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PAE PDPE read error 0x%X\n", Status); m_Translating = FALSE; return Status; } // Read the Page Directory entry. Addr = (((Virt >> X86_PDE_SHIFT_PAE) & X86_PDE_MASK_PAE) * sizeof(Entry)) + (Entry & X86_VALID_PFN_MASK_PAE); KdOut("X86VtoP: PAE PDE %s\n", FormatDisp64(Addr)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = Addr; OffsetsSize--; } if ((Status = m_Target-> ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PAE PDE read error 0x%X\n", Status); m_Translating = FALSE; return Status; } // Check for a large page. Large pages can // never be paged out so also check for the present bit. if ((Entry & (X86_LARGE_PAGE_MASK | 1)) == (X86_LARGE_PAGE_MASK | 1)) { // // If we have a large page and this is a summary dump, then // the page may span multiple physical pages that may -- because // of how the summary dump is written -- not be included in the // dump. Fixup the large page address to its corresponding small // page address. // if (IS_KERNEL_SUMMARY_DUMP(m_Target)) { ULONG SpannedPages; SpannedPages = (ULONG) ((Virt & (X86_LARGE_PAGE_SIZE_PAE - 1)) >> X86_PAGE_SHIFT); *LastVal = ((Entry & ~(X86_LARGE_PAGE_SIZE_PAE - 1)) | ((ULONG64)SpannedPages << X86_PAGE_SHIFT) | (Virt & (X86_PAGE_SIZE - 1))); } else { *LastVal = ((Entry & ~(X86_LARGE_PAGE_SIZE_PAE - 1)) | (Virt & (X86_LARGE_PAGE_SIZE_PAE - 1))); } KdOut("X86VtoP: PAE Large page mapped phys %s\n", FormatDisp64(*LastVal)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = *LastVal; OffsetsSize--; } m_Translating = FALSE; return S_OK; } // Read the Page Table entry. if (Entry == 0) { KdOut("X86VtoP: PAE zero PDE\n"); m_Translating = FALSE; return HR_PAGE_NOT_AVAILABLE; } else if (!(Entry & 1)) { Addr = (((Virt >> X86_PTE_SHIFT) & X86_PTE_MASK_PAE) * sizeof(Entry)) + X86_PAGE_FILE_OFFSET(Entry); KdOut("X86VtoP: pagefile PAE PTE %d:%s\n", X86_PAGE_FILE_INDEX(Entry), FormatDisp64(Addr)); if ((Status = m_Target-> ReadPageFile(X86_PAGE_FILE_INDEX(Entry), Addr, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PAE PDE not present, 0x%X\n", Status); m_Translating = FALSE; return Status; } } else { Addr = (((Virt >> X86_PTE_SHIFT) & X86_PTE_MASK_PAE) * sizeof(Entry)) + (Entry & X86_VALID_PFN_MASK_PAE); KdOut("X86VtoP: PAE PTE %s\n", FormatDisp64(Addr)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = Addr; OffsetsSize--; } if ((Status = m_Target-> ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PAE PTE read error 0x%X\n", Status); m_Translating = FALSE; return Status; } } if (!(Entry & 0x1) && ((Entry & X86_MM_PTE_PROTOTYPE_MASK) || !(Entry & X86_MM_PTE_TRANSITION_MASK))) { if (Entry == 0) { KdOut("X86VtoP: PAE zero PTE\n"); Status = HR_PAGE_NOT_AVAILABLE; } else if (Entry & X86_MM_PTE_PROTOTYPE_MASK) { KdOut("X86VtoP: PAE prototype PTE\n"); Status = HR_PAGE_NOT_AVAILABLE; } else { *PfIndex = X86_PAGE_FILE_INDEX(Entry); *LastVal = (Virt & (X86_PAGE_SIZE - 1)) + X86_PAGE_FILE_OFFSET(Entry); KdOut("X86VtoP: PAE PTE not present, pagefile %d:%s\n", *PfIndex, FormatDisp64(*LastVal)); Status = HR_PAGE_IN_PAGE_FILE; } m_Translating = FALSE; return Status; } *LastVal = ((Entry & X86_VALID_PFN_MASK_PAE) | (Virt & (X86_PAGE_SIZE - 1))); KdOut("X86VtoP: PAE Mapped phys %s\n", FormatDisp64(*LastVal)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = *LastVal; OffsetsSize--; } m_Translating = FALSE; return S_OK; } else { ULONG Entry; // Read the Page Directory entry. Addr = ((Virt >> X86_PDE_SHIFT) * sizeof(Entry)) + m_PageDirectories[PAGE_DIR_SINGLE]; KdOut("X86VtoP: PDE %s\n", FormatDisp64(Addr)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = Addr; OffsetsSize--; } if ((Status = m_Target-> ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PDE read error 0x%X\n", Status); m_Translating = FALSE; return Status; } // Check for a large page. Large pages can // never be paged out so also check for the present bit. if ((Entry & (X86_LARGE_PAGE_MASK | 1)) == (X86_LARGE_PAGE_MASK | 1)) { *LastVal = ((Entry & ~(X86_LARGE_PAGE_SIZE - 1)) | (Virt & (X86_LARGE_PAGE_SIZE - 1))); KdOut("X86VtoP: Large page mapped phys %s\n", FormatDisp64(*LastVal)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = *LastVal; OffsetsSize--; } m_Translating = FALSE; return S_OK; } // Read the Page Table entry. if (Entry == 0) { KdOut("X86VtoP: zero PDE\n"); m_Translating = FALSE; return HR_PAGE_NOT_AVAILABLE; } else if (!(Entry & 1)) { Addr = (((Virt >> X86_PTE_SHIFT) & X86_PTE_MASK) * sizeof(Entry)) + X86_PAGE_FILE_OFFSET(Entry); KdOut("X86VtoP: pagefile PTE %d:%s\n", X86_PAGE_FILE_INDEX(Entry), FormatDisp64(Addr)); if ((Status = m_Target-> ReadPageFile(X86_PAGE_FILE_INDEX(Entry), Addr, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PDE not present, 0x%X\n", Status); m_Translating = FALSE; return Status; } } else { Addr = (((Virt >> X86_PTE_SHIFT) & X86_PTE_MASK) * sizeof(Entry)) + (Entry & X86_VALID_PFN_MASK); KdOut("X86VtoP: PTE %s\n", FormatDisp64(Addr)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = Addr; OffsetsSize--; } if ((Status = m_Target-> ReadAllPhysical(Addr, &Entry, sizeof(Entry))) != S_OK) { KdOut("X86VtoP: PTE read error 0x%X\n", Status); m_Translating = FALSE; return Status; } } if (!(Entry & 0x1) && ((Entry & X86_MM_PTE_PROTOTYPE_MASK) || !(Entry & X86_MM_PTE_TRANSITION_MASK))) { if (Entry == 0) { KdOut("X86VtoP: zero PTE\n"); Status = HR_PAGE_NOT_AVAILABLE; } else if (Entry & X86_MM_PTE_PROTOTYPE_MASK) { KdOut("X86VtoP: prototype PTE\n"); Status = HR_PAGE_NOT_AVAILABLE; } else { *PfIndex = X86_PAGE_FILE_INDEX(Entry); *LastVal = (Virt & (X86_PAGE_SIZE - 1)) + X86_PAGE_FILE_OFFSET(Entry); KdOut("X86VtoP: PTE not present, pagefile %d:%s\n", *PfIndex, FormatDisp64(*LastVal)); Status = HR_PAGE_IN_PAGE_FILE; } m_Translating = FALSE; return Status; } *LastVal = ((Entry & X86_VALID_PFN_MASK) | (Virt & (X86_PAGE_SIZE - 1))); KdOut("X86VtoP: Mapped phys %s\n", FormatDisp64(*LastVal)); (*Levels)++; if (Offsets != NULL && OffsetsSize > 0) { *Offsets++ = *LastVal; OffsetsSize--; } m_Translating = FALSE; return S_OK; } } HRESULT X86MachineInfo::GetBaseTranslationVirtualOffset(PULONG64 Offset) { if (m_Target->m_KdDebuggerData.PaeEnabled) { *Offset = EXTEND64(X86_BASE_VIRT_PAE); } else { *Offset = EXTEND64(X86_BASE_VIRT); } return S_OK; } void X86MachineInfo::DecodePte(ULONG64 Pte, PULONG64 PageFrameNumber, PULONG Flags) { *PageFrameNumber = (Pte & X86_VALID_PFN_MASK) >> X86_PAGE_SHIFT; *Flags = (Pte & 1) ? MPTE_FLAG_VALID : 0; } void X86MachineInfo::OutputFunctionEntry(PVOID RawEntry) { PFPO_DATA FpoData = (PFPO_DATA)RawEntry; dprintf("OffStart: %08x\n", FpoData->ulOffStart); dprintf("ProcSize: 0x%x\n", FpoData->cbProcSize); switch(FpoData->cbFrame) { case FRAME_FPO: dprintf("Params: %d\n", FpoData->cdwParams); dprintf("Locals: %d\n", FpoData->cdwLocals); dprintf("Registers: %d\n", FpoData->cbRegs); if (FpoData->fHasSEH) { dprintf("Has SEH\n"); } if (FpoData->fUseBP) { dprintf("Uses EBP\n"); } break; case FRAME_NONFPO: dprintf("Non-FPO\n"); break; case FRAME_TRAP: if (!IS_KERNEL_TARGET(m_Target)) { goto UnknownFpo; } dprintf("Params: %d\n", FpoData->cdwParams); dprintf("Locals: %d\n", FpoData->cdwLocals); dprintf("Trap frame\n"); break; case FRAME_TSS: if (!IS_KERNEL_TARGET(m_Target)) { goto UnknownFpo; } dprintf("Task gate\n"); break; default: UnknownFpo: dprintf("Unknown FPO type\n"); break; } } HRESULT X86MachineInfo::ReadKernelProcessorId (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id) { HRESULT Status; ULONG64 Prcb; ULONG Data; if ((Status = m_Target-> GetProcessorSystemDataOffset(Processor, DEBUG_DATA_KPRCB_OFFSET, &Prcb)) != S_OK) { return Status; } if ((Status = m_Target-> ReadAllVirtual(m_Target->m_ProcessHead, Prcb + m_Target->m_KdDebuggerData.OffsetPrcbCpuType, &Data, sizeof(Data))) != S_OK) { return Status; } Id->X86.Family = Data & 0xf; Id->X86.Model = (Data >> 24) & 0xf; Id->X86.Stepping = (Data >> 16) & 0xf; if ((Status = m_Target-> ReadAllVirtual(m_Target->m_ProcessHead, Prcb + m_Target->m_KdDebuggerData.OffsetPrcbVendorString, Id->X86.VendorString, X86_VENDOR_STRING_SIZE)) != S_OK) { return Status; } return S_OK; } HRESULT X86MachineInfo::GetAlternateTriageDumpDataRanges(ULONG64 PrcbBase, ULONG64 ThreadBase, PADDR_RANGE Ranges) { PADDR_RANGE Range = Ranges; if (m_Target->ReadPointer(m_Target->m_ProcessHead, this, PrcbBase + m_Target->m_KdDebuggerData.OffsetPrcbDpcRoutine, &Range->Base) == S_OK && Range->Base) { Range->Base = PAGE_ALIGN(this, Range->Base); Range->Size = m_PageSize; Range++; } else { Range->Base = 0; } return S_OK; } void X86MachineInfo::KdGetSpecialRegistersFromContext(void) { DBG_ASSERT(m_ContextState >= MCTX_FULL); m_Special.X86Special.KernelDr0 = m_Context.X86Nt5Context.Dr0; m_Special.X86Special.KernelDr1 = m_Context.X86Nt5Context.Dr1; m_Special.X86Special.KernelDr2 = m_Context.X86Nt5Context.Dr2; m_Special.X86Special.KernelDr3 = m_Context.X86Nt5Context.Dr3; m_Special.X86Special.KernelDr6 = m_Context.X86Nt5Context.Dr6; m_Special.X86Special.KernelDr7 = m_Context.X86Nt5Context.Dr7; } void X86MachineInfo::KdSetSpecialRegistersInContext(void) { DBG_ASSERT(m_ContextState >= MCTX_FULL); m_Context.X86Nt5Context.Dr0 = m_Special.X86Special.KernelDr0; m_Context.X86Nt5Context.Dr1 = m_Special.X86Special.KernelDr1; m_Context.X86Nt5Context.Dr2 = m_Special.X86Special.KernelDr2; m_Context.X86Nt5Context.Dr3 = m_Special.X86Special.KernelDr3; m_Context.X86Nt5Context.Dr6 = m_Special.X86Special.KernelDr6; m_Context.X86Nt5Context.Dr7 = m_Special.X86Special.KernelDr7; } ULONG X86MachineInfo::GetIntReg(ULONG regnum) { switch (m_ContextState) { case MCTX_PC: if (regnum == X86_EIP) { return m_Context.X86Nt5Context.Eip; } goto MctxContext; case MCTX_DR67_REPORT: switch (regnum) { case X86_DR6: return m_Context.X86Nt5Context.Dr6; case X86_DR7: return m_Context.X86Nt5Context.Dr7; } goto MctxContext; case MCTX_REPORT: switch (regnum) { case X86_CS: return (USHORT)m_Context.X86Nt5Context.SegCs; case X86_DS: return (USHORT)m_Context.X86Nt5Context.SegDs; case X86_ES: return (USHORT)m_Context.X86Nt5Context.SegEs; case X86_FS: return (USHORT)m_Context.X86Nt5Context.SegFs; case X86_EIP: return m_Context.X86Nt5Context.Eip; case X86_EFL: return m_Context.X86Nt5Context.EFlags; case X86_DR6: return m_Context.X86Nt5Context.Dr6; case X86_DR7: return m_Context.X86Nt5Context.Dr7; } // Fallthrough! case MCTX_NONE: MctxContext: if (GetContextState(MCTX_CONTEXT) != S_OK) { return 0; } // Fallthrough! case MCTX_CONTEXT: switch (regnum) { case X86_CS: return (USHORT)m_Context.X86Nt5Context.SegCs; case X86_DS: return (USHORT)m_Context.X86Nt5Context.SegDs; case X86_ES: return (USHORT)m_Context.X86Nt5Context.SegEs; case X86_FS: return (USHORT)m_Context.X86Nt5Context.SegFs; case X86_EIP: return m_Context.X86Nt5Context.Eip; case X86_EFL: return m_Context.X86Nt5Context.EFlags; case X86_GS: return (USHORT)m_Context.X86Nt5Context.SegGs; case X86_SS: return (USHORT)m_Context.X86Nt5Context.SegSs; case X86_EDI: return m_Context.X86Nt5Context.Edi; case X86_ESI: return m_Context.X86Nt5Context.Esi; case X86_EBX: return m_Context.X86Nt5Context.Ebx; case X86_EDX: return m_Context.X86Nt5Context.Edx; case X86_ECX: return m_Context.X86Nt5Context.Ecx; case X86_EAX: return m_Context.X86Nt5Context.Eax; case X86_EBP: return m_Context.X86Nt5Context.Ebp; case X86_ESP: return m_Context.X86Nt5Context.Esp; case X86_FPCW: return m_Context.X86Nt5Context.FloatSave.ControlWord & 0xffff; case X86_FPSW: return m_Context.X86Nt5Context.FloatSave.StatusWord & 0xffff; case X86_FPTW: return m_Context.X86Nt5Context.FloatSave.TagWord & 0xffff; case X86_MXCSR: return m_Context.X86Nt5Context.FxSave.MXCsr; } // // The requested register is not in our current context, load up // a complete context // if (GetContextState(MCTX_FULL) != S_OK) { return 0; } } // // We must have a complete context... // switch (regnum) { case X86_GS: return (USHORT)m_Context.X86Nt5Context.SegGs; case X86_FS: return (USHORT)m_Context.X86Nt5Context.SegFs; case X86_ES: return (USHORT)m_Context.X86Nt5Context.SegEs; case X86_DS: return (USHORT)m_Context.X86Nt5Context.SegDs; case X86_EDI: return m_Context.X86Nt5Context.Edi; case X86_ESI: return m_Context.X86Nt5Context.Esi; case X86_SI: return(m_Context.X86Nt5Context.Esi & 0xffff); case X86_DI: return(m_Context.X86Nt5Context.Edi & 0xffff); case X86_EBX: return m_Context.X86Nt5Context.Ebx; case X86_EDX: return m_Context.X86Nt5Context.Edx; case X86_ECX: return m_Context.X86Nt5Context.Ecx; case X86_EAX: return m_Context.X86Nt5Context.Eax; case X86_EBP: return m_Context.X86Nt5Context.Ebp; case X86_EIP: return m_Context.X86Nt5Context.Eip; case X86_CS: return (USHORT)m_Context.X86Nt5Context.SegCs; case X86_EFL: return m_Context.X86Nt5Context.EFlags; case X86_ESP: return m_Context.X86Nt5Context.Esp; case X86_SS: return (USHORT)m_Context.X86Nt5Context.SegSs; case X86_DR0: return m_Context.X86Nt5Context.Dr0; case X86_DR1: return m_Context.X86Nt5Context.Dr1; case X86_DR2: return m_Context.X86Nt5Context.Dr2; case X86_DR3: return m_Context.X86Nt5Context.Dr3; case X86_DR6: return m_Context.X86Nt5Context.Dr6; case X86_DR7: return m_Context.X86Nt5Context.Dr7; case X86_FPCW: return m_Context.X86Nt5Context.FloatSave.ControlWord & 0xffff; case X86_FPSW: return m_Context.X86Nt5Context.FloatSave.StatusWord & 0xffff; case X86_FPTW: return m_Context.X86Nt5Context.FloatSave.TagWord & 0xffff; case X86_MXCSR: return m_Context.X86Nt5Context.FxSave.MXCsr; } if (IS_KERNEL_TARGET(m_Target)) { switch(regnum) { case X86_CR0: return m_Special.X86Special.Cr0; case X86_CR2: return m_Special.X86Special.Cr2; case X86_CR3: return m_Special.X86Special.Cr3; case X86_CR4: return m_Special.X86Special.Cr4; case X86_GDTR: return m_Special.X86Special.Gdtr.Base; case X86_GDTL: return (ULONG)m_Special.X86Special.Gdtr.Limit; case X86_IDTR: return m_Special.X86Special.Idtr.Base; case X86_IDTL: return (ULONG)m_Special.X86Special.Idtr.Limit; case X86_TR: return (ULONG)m_Special.X86Special.Tr; case X86_LDTR: return (ULONG)m_Special.X86Special.Ldtr; } } ErrOut("X86MachineInfo::SetVal: " "unknown register %lx requested\n", regnum); return REG_ERROR; } PULONG64 X86MachineInfo::GetMmxRegSlot(ULONG regnum) { return (PULONG64)(m_Context.X86Nt5Context.FloatSave.RegisterArea + GetMmxRegOffset(regnum - X86_MM_FIRST, GetIntReg(X86_FPSW)) * 10); } void X86MachineInfo::GetMmxReg(ULONG Reg, REGVAL* Val) { if (GetContextState(MCTX_CONTEXT) == S_OK) { Val->I64 = *(ULONG64 UNALIGNED *)GetMmxRegSlot(Reg); } } void X86MachineInfo::GetFloatReg(ULONG Reg, REGVAL* Val) { if (GetContextState(MCTX_CONTEXT) == S_OK) { memcpy(Val->F10, m_Context.X86Nt5Context.FloatSave.RegisterArea + 10 * (Reg - X86_ST_FIRST), sizeof(Val->F10)); } }