/*** ntreg.c - processor-specific register structures * * Copyright 1990, Microsoft Corporation * * Purpose: * Structures used to parse and access register and flag * fields. * * Revision History: * * [-] 01-Jul-1990 Richk Created. * *************************************************************************/ #include #include #include "ntsdp.h" #include "86reg.h" #if defined(KERNEL) && defined(i386) #include #endif #if defined(KERNEL) && defined(i386) #include extern USHORT NtsdCurrentProcessor; extern ULONG NumberProcessors; extern BOOLEAN fSetGlobalDataBrkpts; extern BOOLEAN fSwitched; USHORT PreviousProcessor; VDMCONTEXT SavedRegisterContext; extern BOOLEAN KdVerbose; // from ntsym.c #define fVerboseOutput KdVerbose #endif #define DPRINT(str) if (fVerboseOutput) dprintf str extern ADDR EAaddr[2]; // from module ntdis.c extern ulong EXPRLastExpression; // from module ntexpr.c extern ulong EXPRLastDump; // from module ntcmd.c extern BOOLEAN STtrace; // from module ntcmd.c extern ULONG STeip, STebp, STesp; // from module ntcmd.c extern int fControlC; extern PUCHAR UserRegs[10]; BOOLEAN X86fDelayInstruction(void); void X86OutputHelp(void); #if defined(KERNEL) && defined(i386) BOOLEAN fTraceFlag; void InitFirCache(ULONG, PUCHAR); void SaveProcessorState(void); void RestoreProcessorState(void); BOOLEAN X86GetTraceFlag(void); extern NTSTATUS TaskGate2TrapFrame(USHORT, PKTRAP_FRAME, PULONG); extern NTSTATUS ReadTrapFrame(ULONG, PKTRAP_FRAME); extern DbgKdInitVirtualCacheEntry (ULONG, ULONG, PUCHAR); #endif ULONG GetDregValue(ULONG); void SetDregValue(ULONG, ULONG); void X86ClearTraceFlag(void); void X86SetTraceFlag(void); PUCHAR X86RegNameFromIndex(ULONG); extern PUCHAR pchCommand; // current pointer in command buffer #if defined(KERNEL) && defined(i386) KSPECIAL_REGISTERS SpecialRegContext, SavedSpecialRegContext; ULONG TerseLevel = 1; #endif ULONG VDMcbBrkptLength = 1L; ULONG VDMtrapInstr = 0xcc; #if !defined(KERNEL) && defined(i386) ULONG VDMContextType = VDMCONTEXT_CONTROL | VDMCONTEXT_INTEGER | VDMCONTEXT_SEGMENTS | VDMCONTEXT_DEBUG_REGISTERS; #else ULONG VDMContextType = VDMCONTEXT_CONTROL | VDMCONTEXT_INTEGER | VDMCONTEXT_SEGMENTS; #endif #if defined(KERNEL) && defined(i386) ULONG contextState, SavedContextState; #define CONTEXTNONE 5 // no context #define CONTEXTFIR 0 // only unchanged FIR in context #define CONTEXTVALID 1 // full, but unchanged context #define CONTEXTDIRTY 2 // full, but changed context #define CONTEXTSHORT 3 // short context loaded (unchanged) #define CONTEXTHALF 4 // half context loaded UCHAR FullContextPresent[] = { FALSE, TRUE, TRUE, FALSE, FALSE }; #endif char szGsReg[] = "gs"; char szFsReg[] = "fs"; char szEsReg[] = "es"; char szDsReg[] = "ds"; char szEdiReg[] = "edi"; char szEsiReg[] = "esi"; char szEbxReg[] = "ebx"; char szEdxReg[] = "edx"; char szEcxReg[] = "ecx"; char szEaxReg[] = "eax"; char szEbpReg[] = "ebp"; char szEipReg[] = "eip"; char szCsReg[] = "cs"; char szEflReg[] = "efl"; char szEspReg[] = "esp"; char szSsReg[] = "ss"; #if defined(KERNEL) && defined(i386) char szCr0Reg[] = "cr0"; char szCr2Reg[] = "cr2"; char szCr3Reg[] = "cr3"; char szCr4Reg[] = "cr4"; char szDr0Reg[] = "dr0"; char szDr1Reg[] = "dr1"; char szDr2Reg[] = "dr2"; char szDr3Reg[] = "dr3"; char szDr6Reg[] = "dr6"; char szDr7Reg[] = "dr7"; char szGdtrReg[] = "gdtr"; char szGdtlReg[] = "gdtl"; char szIdtrReg[] = "idtr"; char szIdtlReg[] = "idtl"; char szTrReg[] = "tr"; char szLdtrReg[] = "ldtr"; #endif char szDiReg[] = "di"; char szSiReg[] = "si"; char szBxReg[] = "bx"; char szDxReg[] = "dx"; char szCxReg[] = "cx"; char szAxReg[] = "ax"; char szBpReg[] = "bp"; char szIpReg[] = "ip"; char szFlReg[] = "fl"; char szSpReg[] = "sp"; char szBlReg[] = "bl"; char szDlReg[] = "dl"; char szClReg[] = "cl"; char szAlReg[] = "al"; char szBhReg[] = "bh"; char szDhReg[] = "dh"; char szChReg[] = "ch"; char szAhReg[] = "ah"; char szIoplFlag[] = "iopl"; char szFlagOf[] = "of"; char szFlagDf[] = "df"; char szFlagIf[] = "if"; char szFlagTf[] = "tf"; char szFlagSf[] = "sf"; char szFlagZf[] = "zf"; char szFlagAf[] = "af"; char szFlagPf[] = "pf"; char szFlagCf[] = "cf"; char szFlagVip[] = "vip"; char szFlagVif[] = "vif"; extern char szEaPReg[]; extern char szExpPReg[]; extern char szRaPReg[]; extern char szPPReg[]; extern char szU0Preg[]; extern char szU1Preg[]; extern char szU2Preg[]; extern char szU3Preg[]; extern char szU4Preg[]; extern char szU5Preg[]; extern char szU6Preg[]; extern char szU7Preg[]; extern char szU8Preg[]; extern char szU9Preg[]; struct Reg regname[] = { { szGsReg, REGGS }, { szFsReg, REGFS }, { szEsReg, REGES }, { szDsReg, REGDS }, { szEdiReg, REGEDI }, { szEsiReg, REGESI }, { szEbxReg, REGEBX }, { szEdxReg, REGEDX }, { szEcxReg, REGECX }, { szEaxReg, REGEAX }, { szEbpReg, REGEBP }, { szEipReg, REGEIP }, { szCsReg, REGCS }, { szEflReg, REGEFL }, { szEspReg, REGESP }, { szSsReg, REGSS }, #if defined(KERNEL) && defined(i386) { szCr0Reg, REGCR0 }, { szCr2Reg, REGCR2 }, { szCr3Reg, REGCR3 }, { szCr4Reg, REGCR4 }, { szDr0Reg, REGDR0 }, { szDr1Reg, REGDR1 }, { szDr2Reg, REGDR2 }, { szDr3Reg, REGDR3 }, { szDr6Reg, REGDR6 }, { szDr7Reg, REGDR7 }, { szGdtrReg, REGGDTR }, { szGdtlReg, REGGDTL }, { szIdtrReg, REGIDTR }, { szIdtlReg, REGIDTL }, { szTrReg, REGTR }, { szLdtrReg, REGLDTR }, #endif { szDiReg, REGDI }, { szSiReg, REGSI }, { szBxReg, REGBX }, { szDxReg, REGDX }, { szCxReg, REGCX }, { szAxReg, REGAX }, { szBpReg, REGBP }, { szIpReg, REGIP }, { szFlReg, REGFL }, { szSpReg, REGSP }, { szBlReg, REGBL }, { szDlReg, REGDL }, { szClReg, REGCL }, { szAlReg, REGAL }, { szBhReg, REGBH }, { szDhReg, REGDH }, { szChReg, REGCH }, { szAhReg, REGAH }, { szIoplFlag, FLAGIOPL }, { szFlagOf, FLAGOF }, { szFlagDf, FLAGDF }, { szFlagIf, FLAGIF }, { szFlagTf, FLAGTF }, { szFlagSf, FLAGSF }, { szFlagZf, FLAGZF }, { szFlagAf, FLAGAF }, { szFlagPf, FLAGPF }, { szFlagCf, FLAGCF }, { szFlagVip, FLAGVIP }, { szFlagVif, FLAGVIF }, { szEaPReg, PREGEA }, { szExpPReg, PREGEXP }, { szRaPReg, PREGRA }, { szPPReg, PREGP }, { szU0Preg, PREGU0 }, { szU1Preg, PREGU1 }, { szU2Preg, PREGU2 }, { szU3Preg, PREGU3 }, { szU4Preg, PREGU4 }, { szU5Preg, PREGU5 }, { szU6Preg, PREGU6 }, { szU7Preg, PREGU7 }, { szU8Preg, PREGU8 }, { szU9Preg, PREGU9 }, }; #define REGNAMESIZE (sizeof(regname) / sizeof(struct Reg)) struct SubReg X86subregname[] = { { REGEDI, 0, 0xffff }, // DI register { REGESI, 0, 0xffff }, // SI register { REGEBX, 0, 0xffff }, // BX register { REGEDX, 0, 0xffff }, // DX register { REGECX, 0, 0xffff }, // CX register { REGEAX, 0, 0xffff }, // AX register { REGEBP, 0, 0xffff }, // BP register { REGEIP, 0, 0xffff }, // IP register { REGEFL, 0, 0xffff }, // FL register { REGESP, 0, 0xffff }, // SP register { REGEBX, 0, 0xff }, // BL register { REGEDX, 0, 0xff }, // DL register { REGECX, 0, 0xff }, // CL register { REGEAX, 0, 0xff }, // AL register { REGEBX, 8, 0xff }, // BH register { REGEDX, 8, 0xff }, // DH register { REGECX, 8, 0xff }, // CH register { REGEAX, 8, 0xff }, // AH register { REGEFL, 12, 3 }, // IOPL level value { REGEFL, 11, 1 }, // OF (overflow flag) { REGEFL, 10, 1 }, // DF (direction flag) { REGEFL, 9, 1 }, // IF (interrupt enable flag) { REGEFL, 8, 1 }, // TF (trace flag) { REGEFL, 7, 1 }, // SF (sign flag) { REGEFL, 6, 1 }, // ZF (zero flag) { REGEFL, 4, 1 }, // AF (aux carry flag) { REGEFL, 2, 1 }, // PF (parity flag) { REGEFL, 0, 1 }, // CF (carry flag) { REGEFL, 20, 1 }, // VIP (virtual interrupt pending) { REGEFL, 19, 1 } // VIF (virtual interrupt flag) }; /*** X86GetRegFlagValue - get register or flag value * * Purpose: * Return the value of the specified register or flag. * This routine calls X86GetRegValue to get the register * value and shifts and masks appropriately to extract a * flag value. * * Input: * regnum - register or flag specification * * Returns: * Value of register or flag. * *************************************************************************/ ULONG X86GetRegFlagValue ( ULONG regnum ) { ULONG value; if (regnum < FLAGBASE) { value = X86GetRegValue(regnum); } else { regnum -= FLAGBASE; value = X86GetRegValue(X86subregname[regnum].regindex); value = (value >> X86subregname[regnum].shift) & X86subregname[regnum].mask; } return value; } /*** X86GetRegValue - get register value * * Purpose: * Returns the value of the register from the processor * context structure. * * Input: * regnum - register specification * * Returns: * value of the register from the context structure * *************************************************************************/ ULONG X86GetRegValue ( ULONG regnum ) { #if defined(KERNEL) && defined(i386) ULONG cBytesRead; NTSTATUS NtStatus; //fprintf (stdout, "X86GetRegValue %d\n", regnum); switch (contextState) { case CONTEXTFIR: switch (regnum) { case REGEIP: return VDMRegisterContext.Eip; case REGDR6: return SpecialRegContext.KernelDr6; case REGDR7: return SpecialRegContext.KernelDr7; } // // Requested register was not in CONTEXTFIR - go get the next // context level. (we skip CONTEXTSMALL since that's the only // api we have) // if (!DbgGetThreadContext(NtsdCurrentProcessor, &VDMRegisterContext)) { dprintf("DbgKdGetContext failed\n"); exit(1); } contextState = CONTEXTHALF; // Fallthrough! case CONTEXTSHORT: switch (regnum) { case REGCS: return VDMRegisterContext.SegCs; case REGDS: return VDMRegisterContext.SegDs; case REGES: return VDMRegisterContext.SegEs; case REGFS: return VDMRegisterContext.SegFs; case REGEIP: return VDMRegisterContext.Eip; case REGEFL: return VDMRegisterContext.EFlags; case REGDR6: return SpecialRegContext.KernelDr6; case REGDR7: return SpecialRegContext.KernelDr7; } // // Requested register was not in CONTEXTSHORT - go get the next // context level. // case CONTEXTNONE: if (contextState < CONTEXTHALF || contextState == CONTEXTNONE) { if (!DbgGetThreadContext(NtsdCurrentProcessor, &VDMRegisterContext)) { dprintf("DbgKdGetContext failed\n"); exit(1); } contextState = CONTEXTHALF; } // Fallthrough! case CONTEXTHALF: switch (regnum) { case REGCS: return VDMRegisterContext.SegCs; case REGDS: return VDMRegisterContext.SegDs; case REGES: return VDMRegisterContext.SegEs; case REGFS: return VDMRegisterContext.SegFs; case REGEIP: return VDMRegisterContext.Eip; case REGEFL: return VDMRegisterContext.EFlags; case REGDR6: return SpecialRegContext.KernelDr6; case REGDR7: return SpecialRegContext.KernelDr7; case REGGS: return VDMRegisterContext.SegGs; case REGSS: return VDMRegisterContext.SegSs; case REGEDI: return VDMRegisterContext.Edi; case REGESI: return VDMRegisterContext.Esi; case REGEBX: return VDMRegisterContext.Ebx; case REGEDX: return VDMRegisterContext.Edx; case REGECX: return VDMRegisterContext.Ecx; case REGEAX: return VDMRegisterContext.Eax; case REGEBP: return VDMRegisterContext.Ebp; case REGESP: return VDMRegisterContext.Esp; } // // The requested register is not in our current context, load up // a complete context // NtStatus = DbgKdReadControlSpace(NtsdCurrentProcessor, (PVOID)sizeof(CONTEXT), (PVOID)&SpecialRegContext, sizeof(KSPECIAL_REGISTERS), &cBytesRead); if (!NT_SUCCESS(NtStatus) || cBytesRead != sizeof(KSPECIAL_REGISTERS)) { dprintf("DbgKdReadControlSpace failed\n"); exit(1); } contextState = CONTEXTVALID; } // // We must have a complete context... // #endif switch (regnum) { case REGGS: return VDMRegisterContext.SegGs; case REGFS: return VDMRegisterContext.SegFs; case REGES: return VDMRegisterContext.SegEs; case REGDS: return VDMRegisterContext.SegDs; case REGEDI: return VDMRegisterContext.Edi; case REGESI: return VDMRegisterContext.Esi; case REGSI: return(VDMRegisterContext.Esi & 0xffff); case REGDI: return(VDMRegisterContext.Edi & 0xffff); case REGEBX: return VDMRegisterContext.Ebx; case REGEDX: return VDMRegisterContext.Edx; case REGECX: return VDMRegisterContext.Ecx; case REGEAX: return VDMRegisterContext.Eax; case REGEBP: return VDMRegisterContext.Ebp; case REGEIP: return VDMRegisterContext.Eip; case REGCS: return VDMRegisterContext.SegCs; case REGEFL: return VDMRegisterContext.EFlags; case REGESP: return VDMRegisterContext.Esp; case REGSS: return VDMRegisterContext.SegSs; case PREGEA: return EAaddr[0].flat; case PREGEXP: return EXPRLastExpression; case PREGRA: { ADDR stackBP; struct { ULONG oldBP; ULONG retAddr; } stackRead; FormAddress(&stackBP, (ULONG)X86GetRegValue(REGSS), (ULONG)X86GetRegValue(REGEBP)); GetMemString(&stackBP, (PUCHAR)&stackRead, sizeof(stackRead)); return stackRead.retAddr; } case PREGP: return EXPRLastDump; case PREGU0: case PREGU1: case PREGU2: case PREGU3: case PREGU4: case PREGU5: case PREGU6: case PREGU7: case PREGU8: case PREGU9: return (ULONG)UserRegs[regnum - PREGU0]; #if defined(KERNEL) && defined(i386) case REGCR0: return SpecialRegContext.Cr0; case REGCR2: return SpecialRegContext.Cr2; case REGCR3: return SpecialRegContext.Cr3; case REGCR4: return SpecialRegContext.Cr4; case REGDR0: return SpecialRegContext.KernelDr0; case REGDR1: return SpecialRegContext.KernelDr1; case REGDR2: return SpecialRegContext.KernelDr2; case REGDR3: return SpecialRegContext.KernelDr3; case REGDR6: return SpecialRegContext.KernelDr6; case REGDR7: return SpecialRegContext.KernelDr7; case REGGDTR: return SpecialRegContext.Gdtr.Base; case REGGDTL: return (ULONG)SpecialRegContext.Gdtr.Limit; case REGIDTR: return SpecialRegContext.Idtr.Base; case REGIDTL: return (ULONG)SpecialRegContext.Idtr.Limit; case REGTR: return (ULONG)SpecialRegContext.Tr; case REGLDTR: return (ULONG)SpecialRegContext.Ldtr; #endif #if !defined(KERNEL) && defined(i386) case REGDR0: return VDMRegisterContext.Dr0; case REGDR1: return VDMRegisterContext.Dr1; case REGDR2: return VDMRegisterContext.Dr2; case REGDR3: return VDMRegisterContext.Dr3; case REGDR6: return VDMRegisterContext.Dr6; case REGDR7: return VDMRegisterContext.Dr7; #endif default: dprintf("X86GetRegValue: unknown register %lx requested\n",regnum); return((ULONG)-1); } } /*** X86SetRegFlagValue - set register or flag value * * Purpose: * Set the value of the specified register or flag. * This routine calls X86SetRegValue to set the register * value and shifts and masks appropriately to set a * flag value. * * Input: * regnum - register or flag specification * regvalue - new register or flag value * * Output: * None. * * Exceptions: * error exit: OVERFLOW - value too large for flag * * Notes: * *************************************************************************/ void X86SetRegFlagValue (ULONG regnum, ULONG regvalue) { ULONG regindex; ULONG newvalue; PUCHAR szValue; ULONG index; if (regnum >= PREGU0 && regnum <= PREGU9) { szValue = (PUCHAR)regvalue; index = 0L; while (szValue[index] >= ' ') index++; szValue[index] = 0; if (szValue = UserRegs[regnum - PREGU0]) free(szValue); szValue = UserRegs[regnum - PREGU0] = malloc(strlen((PUCHAR)regvalue) + 1); if (szValue) strcpy(szValue, (PUCHAR)regvalue); } else if (regnum < PREGBASE) X86SetRegValue(regnum, regvalue); else if (regnum >= FLAGBASE) { regnum -= FLAGBASE; if (regvalue > X86subregname[regnum].mask) error(OVERFLOW); regindex = X86subregname[regnum].regindex; newvalue = X86GetRegValue(regindex) & (~(X86subregname[regnum].mask << X86subregname[regnum].shift)) | (regvalue << X86subregname[regnum].shift); X86SetRegValue(regindex, newvalue); } } /*** X86SetRegValue - set register value * * Purpose: * Set the value of the register in the processor context * structure. * * Input: * regnum - register specification * regvalue - new value to set the register * * Output: * None. * *************************************************************************/ void X86SetRegValue (ULONG regnum, ULONG regvalue) { #if defined(KERNEL) && defined(i386) ULONG cBytesRead; NTSTATUS NtStatus; if ((regnum == REGEIP && regvalue != VDMRegisterContext.Eip) || (regnum != REGEIP && regnum != REGDR7)) { if (!FullContextPresent[contextState]) { if (!DbgGetThreadContext(NtsdCurrentProcessor, &VDMRegisterContext)) { dprintf("DbgKdGetContext failed\n"); exit(1); } NtStatus = DbgKdReadControlSpace(NtsdCurrentProcessor, (PVOID)sizeof(CONTEXT), (PVOID)&SpecialRegContext, sizeof(KSPECIAL_REGISTERS), &cBytesRead); if (!NT_SUCCESS(NtStatus) || cBytesRead != sizeof(KSPECIAL_REGISTERS)) { dprintf("DbgKdReadControlSpace failed\n"); exit(1); } } contextState = CONTEXTDIRTY; } #endif switch (regnum) { case REGGS: VDMRegisterContext.SegGs = regvalue; break; case REGFS: VDMRegisterContext.SegFs = regvalue; break; case REGES: VDMRegisterContext.SegEs = regvalue; break; case REGDS: VDMRegisterContext.SegDs = regvalue; break; case REGEDI: VDMRegisterContext.Edi = regvalue; break; case REGESI: VDMRegisterContext.Esi = regvalue; break; case REGEBX: VDMRegisterContext.Ebx = regvalue; break; case REGEDX: VDMRegisterContext.Edx = regvalue; break; case REGECX: VDMRegisterContext.Ecx = regvalue; break; case REGEAX: VDMRegisterContext.Eax = regvalue; break; case REGEBP: VDMRegisterContext.Ebp = regvalue; break; case REGEIP: VDMRegisterContext.Eip = regvalue; break; case REGCS: VDMRegisterContext.SegCs = regvalue; break; case REGEFL: #if defined(KERNEL) && defined(i386) VDMRegisterContext.EFlags = regvalue & ~0x100; // leave TF clear #else VDMRegisterContext.EFlags = regvalue; // allow TF set #endif break; case REGESP: VDMRegisterContext.Esp = regvalue; break; case REGSS: VDMRegisterContext.SegSs = regvalue; break; #if defined(KERNEL) && defined(i386) case REGCR0: SpecialRegContext.Cr0 = regvalue; break; case REGCR2: SpecialRegContext.Cr2 = regvalue; break; case REGCR3: SpecialRegContext.Cr3 = regvalue; break; case REGCR4: SpecialRegContext.Cr4 = regvalue; break; case REGDR0: SpecialRegContext.KernelDr0 = regvalue; break; case REGDR1: SpecialRegContext.KernelDr1 = regvalue; break; case REGDR2: SpecialRegContext.KernelDr2 = regvalue; break; case REGDR3: SpecialRegContext.KernelDr3 = regvalue; break; case REGDR6: SpecialRegContext.KernelDr6 = regvalue; break; case REGDR7: SpecialRegContext.KernelDr7 = regvalue; break; case REGGDTR: SpecialRegContext.Gdtr.Base = regvalue; break; case REGGDTL: SpecialRegContext.Gdtr.Limit = (USHORT)regvalue; break; case REGIDTR: SpecialRegContext.Idtr.Base = regvalue; break; case REGIDTL: SpecialRegContext.Idtr.Limit = (USHORT)regvalue; break; case REGTR: SpecialRegContext.Tr = (USHORT)regvalue; break; case REGLDTR: SpecialRegContext.Ldtr = (USHORT)regvalue; break; #endif #if !defined(KERNEL) && defined(i386) case REGDR0: VDMRegisterContext.Dr0 = regvalue; break; case REGDR1: VDMRegisterContext.Dr1 = regvalue; break; case REGDR2: VDMRegisterContext.Dr2 = regvalue; break; case REGDR3: VDMRegisterContext.Dr3 = regvalue; break; case REGDR6: VDMRegisterContext.Dr6 = regvalue; break; case REGDR7: VDMRegisterContext.Dr7 = regvalue; break; #endif default: dprintf("X86SetRegValue: unknown register %lx requested\n",regnum); } } /*** X86GetRegName - get register name * * Purpose: * Parse a register name from the current command line position. * If successful, return the register index value, else return -1. * * Input: * pchCommand - present command string position * * Returns: * register or flag index if found, else -1 * *************************************************************************/ ULONG X86GetRegName (void) { char szregname[8]; char ch; int count = 0; ch = (char)tolower(*pchCommand); pchCommand++; while (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9' || ch == '$') { if (count == 7) return (ULONG)-1; szregname[count++] = ch; ch = (char)tolower(*pchCommand); pchCommand++; } szregname[count] = '\0'; pchCommand--; return X86GetRegString(szregname); } ULONG X86GetRegString (PUCHAR pszString) { ULONG count; for (count = 0; count < REGNAMESIZE; count++) if (!strcmp(pszString, regname[count].psz)) return regname[count].value; return (ULONG)-1; } void X86GetRegPCValue (PADDR Address) { Off(*Address) = X86GetRegValue(REGEIP); #ifdef MULTIMODE if (VM86(X86GetRegValue(REGEFL))) { Address->type = ADDR_V86; Address->seg = (USHORT)X86GetRegValue(REGCS); ComputeFlatAddress(Address, NULL); } else { DESCRIPTOR_TABLE_ENTRY desc; static USHORT MainCodeSeg = 0; ULONG base; Address->seg = (USHORT)(desc.Selector = X86GetRegValue(REGCS)); #ifdef i386 DbgKdLookupSelector(NtsdCurrentProcessor, &desc); Address->type = desc.Descriptor.HighWord.Bits.Default_Big ? ADDR_1632 : ADDR_16; if ( Address->type == ADDR_1632 ) { if ( MainCodeSeg == 0 ) { base = ((ULONG)desc.Descriptor.HighWord.Bytes.BaseHi << 24) + ((ULONG)desc.Descriptor.HighWord.Bytes.BaseMid << 16) + ((ULONG)desc.Descriptor.BaseLow); if ( base == 0 ) { MainCodeSeg = Address->seg; } } if ( Address->seg == MainCodeSeg ) { Address->type = ADDR_32; } } #else Address->type = ADDR_16; #endif ComputeFlatAddress(Address, &desc); } #endif return; } PADDR X86GetRegFPValue (void) { static ADDR addrFP; Off(addrFP) = X86GetRegValue(REGEBP); #ifdef MULTIMODE if (VM86(X86GetRegValue(REGEFL))) { addrFP.type = ADDR_V86; addrFP.seg = (USHORT)X86GetRegValue(REGSS); ComputeFlatAddress(&addrFP, NULL); } else { DESCRIPTOR_TABLE_ENTRY desc; addrFP.seg = (USHORT)(desc.Selector = X86GetRegValue(REGSS)); #ifdef i386 DbgKdLookupSelector(NtsdCurrentProcessor, &desc); addrFP.type = desc.Descriptor.HighWord.Bits.Default_Big ? ADDR_32 : ADDR_16; #else addrFP.type = ADDR_16; #endif ComputeFlatAddress(&addrFP, &desc); } #endif return &addrFP; } void X86SetRegPCValue (PADDR paddr) { // We set the EIP to the offset (the non-translated value), // because we may not be in "flat" mode !!! X86SetRegValue(REGEIP, Off(*paddr)); } /*** X86OutputAllRegs - 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: * fTerseReg - (kernel only) - if set, do not output all control * register, just the more commonly useful ones. * * Output: * None. * *************************************************************************/ void X86OutputAllRegs(void) { dprintf("eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n", X86GetRegValue(REGEAX), X86GetRegValue(REGEBX), X86GetRegValue(REGECX), X86GetRegValue(REGEDX), X86GetRegValue(REGESI), X86GetRegValue(REGEDI)); dprintf("eip=%08lx esp=%08lx ebp=%08lx iopl=%1lx " "%s %s %s %s %s %s %s %s %s %s\n", X86GetRegValue(REGEIP), X86GetRegValue(REGESP), X86GetRegValue(REGEBP), X86GetRegFlagValue(FLAGIOPL), X86GetRegFlagValue(FLAGVIP) ? "vip" : " ", X86GetRegFlagValue(FLAGVIF) ? "vif" : " ", X86GetRegFlagValue(FLAGOF) ? "ov" : "nv", X86GetRegFlagValue(FLAGDF) ? "dn" : "up", X86GetRegFlagValue(FLAGIF) ? "ei" : "di", X86GetRegFlagValue(FLAGSF) ? "ng" : "pl", X86GetRegFlagValue(FLAGZF) ? "zr" : "nz", X86GetRegFlagValue(FLAGAF) ? "ac" : "na", X86GetRegFlagValue(FLAGPF) ? "po" : "pe", X86GetRegFlagValue(FLAGCF) ? "cy" : "nc"); #if defined(KERNEL) && defined(i386) if (TerseLevel >= 3) return ; #endif dprintf("cs=%04lx ss=%04lx ds=%04lx es=%04lx fs=%04lx gs=%04lx" " efl=%08lx\n", X86GetRegValue(REGCS), X86GetRegValue(REGSS), X86GetRegValue(REGDS), X86GetRegValue(REGES), X86GetRegValue(REGFS), X86GetRegValue(REGGS), X86GetRegFlagValue(REGEFL)); #if defined(KERNEL) && defined(i386) if (TerseLevel >= 2) return ; dprintf("cr0=%08lx cr2=%08lx cr3=%08lx", X86GetRegValue(REGCR0), X86GetRegValue(REGCR2), X86GetRegValue(REGCR3)); if (TerseLevel >= 1) { dprintf("\n"); return ; } dprintf(" dr0=%08lx dr1=%08lx dr2=%08lx\n", X86GetRegValue(REGDR0), X86GetRegValue(REGDR1), X86GetRegValue(REGDR2)); dprintf("dr3=%08lx dr6=%08lx dr7=%08lx cr4=%08lx\n", X86GetRegValue(REGDR3), X86GetRegValue(REGDR6), X86GetRegValue(REGDR7), X86GetRegValue(REGCR4)); dprintf("gdtr=%08lx gdtl=%04lx idtr=%08lx idtl=%04lx " "tr=%04lx ldtr=%04x\n", X86GetRegValue(REGGDTR), X86GetRegValue(REGGDTL), X86GetRegValue(REGIDTR), X86GetRegValue(REGIDTL), X86GetRegValue(REGTR), X86GetRegValue(REGLDTR)); #endif } /*** X86OutputOneReg - output one register value * * Purpose: * Function for the "r " command. * * Output the value for the specified register or flag. * * Input: * regnum - register or flag specification * * Output: * None. * *************************************************************************/ VOID X86OutputOneReg( ULONG regnum ) { ULONG value; value = X86GetRegFlagValue(regnum); if (regnum < FLAGBASE) { dprintf("%08lx\n", value); } else{ dprintf("%lx\n", value); } } BOOLEAN X86fDelayInstruction (void) { return FALSE; } /*** X86OutputHelp - output help text * * Purpose: * To output a one-page summary help text. * * Input: * None. * * Output: * None. * *************************************************************************/ void X86OutputHelp (void) { #if defined(KERNEL) && defined(i386) dprintf("A [
] - assemble N [] - set / show radix\n"); dprintf("BA[#] <1|2|4> - addr bp P[R] [=] [] - program step\n"); dprintf("BC[] - clear breakpoint(s) Q - quit\n"); dprintf("BD[] - disable breakpoint(s) R[T] [[ [= ]]] - reg/flag\n"); dprintf("BE[] - enable breakpoint(s) #R[T] - multiprocessor register dump\n"); dprintf("BL[] - list breakpoint(s) S - search\n"); dprintf("BP[#]
- set breakpoint\n"); dprintf("C
- compare SS - set symbol suffix\n"); dprintf("D[type][] - dump memory T[R] [=
] [] - trace\n"); dprintf("E[type]
[] - enter U [] - unassemble\n"); dprintf("F - fill V [] - view source lines\n"); dprintf("G [=
[
...]] - go X [<*|module>!]<*|symbol> - view symbols\n"); dprintf("J [']cmd1['];[']cmd2['] - conditional execution\n"); dprintf("K[B] - stacktrace .logappend [] - append to log file\n"); dprintf("LN - list near .logclose - close log file\n"); dprintf("M
- move .logopen [] - open new log file\n"); dprintf("O - write I/O \n"); dprintf("~ - list threads status ~#s - set default thread\n"); dprintf("~[.|#|*|ddd]f - freeze thread ~[.|#|ddd]k[value] - backtrace stack\n"); dprintf("| - list processes status |#s - set default process\n"); dprintf("|# - default process override\n"); dprintf("? - display expression\n"); dprintf("# [address] - search for a string in the dissasembly\n"); dprintf("$< - take input from a command file\n"); dprintf("\n"); dprintf(" ops: + - * / not by wo dw poi mod(%) and(&) xor(^) or(|) hi low\n"); dprintf(" operands: number in current radix, public symbol, \n"); dprintf(" : B (byte), W (word), D (doubleword), A (ascii)\n"); dprintf(" C , U (unicode), L (list)\n"); dprintf(" : [(nt | )!] ( can include ? and *)\n"); dprintf(" : 8, 10, 16\n"); dprintf(" : [e]ax, [e]bx, [e]cx, [e]dx, [e]si, [e]di, [e]bp, [e]sp, [e]ip, [e]fl,\n"); dprintf(" al, ah, bl, bh, cl, ch, dl, ch, cs, ds, es, fs, gs, ss\n"); dprintf(" cr0, cr2, cr3, cr4, dr0, dr1, dr2, dr3, dr6, dr7\n"); dprintf(" gdtr, gdtl, idtr, idtl, tr, ldtr, $u0-$u9, $ea, $exp, $ra, $p\n"); dprintf(" : iopl, of, df, if, tf, sf, zf, af, pf, cf\n"); dprintf(" : %<32-bit address>, #<16-bit protect-mode [seg:]address>,\n"); dprintf(" &\n"); #else dprintf("A [
] - assemble O - write I/O\n"); dprintf("BA[#] <1|2|4> - addr bp P[R] [=] [] - program step\n"); dprintf("BC[] - clear breakpoint(s) Q - quit\n"); dprintf("BD[] - disable breakpoint(s) R[T] [[ [= ]]] - reg/flag\n"); dprintf("BE[] - enable breakpoint(s) #R[T] - multiprocessor register dump\n"); dprintf("BL[] - list breakpoint(s) S - search\n"); dprintf("BP[#]
- set breakpoint\n"); dprintf("C
- compare SS - set symbol suffix\n"); dprintf("D[type][] - dump memory T[R] [=
] [] - trace\n"); dprintf("E[type]
[] - enter U [] - unassemble\n"); dprintf("F - fill V [] - view source lines\n"); dprintf("G [=
[
...]] - go X [<*|module>!]<*|symbol> - view symbols\n"); dprintf("I - read I/O port .cache [size] - set vmem cache size\n"); dprintf("J [']cmd1['];[']cmd2['] - conditional execution\n"); dprintf("K[B] - stacktrace .logappend [] - append to log file\n"); dprintf("LN - list near .logclose - close log file\n"); dprintf("M
- move .logopen [] - open new log file\n"); dprintf("N [] - set / show radix .reboot - reboot target machine\n"); dprintf("? - display expression \n"); dprintf("# [address] - search for a string in the dissasembly\n"); dprintf("$< - take input from a command file\n"); dprintf("\n"); dprintf(" ops: + - * / not by wo dw poi mod(%) and(&) xor(^) or(|) hi low\n"); dprintf(" operands: number in current radix, public symbol, \n"); dprintf(" : B (byte), W (word), D (doubleword), A (ascii)\n"); dprintf(" U (unicode), L (list), O (object)\n"); dprintf(" : [(nt | )!] ( can include ? and *)\n"); dprintf(" : 8, 10, 16\n"); dprintf(" : [e]ax, [e]bx, [e]cx, [e]dx, [e]si, [e]di, [e]bp, [e]sp, [e]ip, [e]fl,\n"); dprintf(" al, ah, bl, bh, cl, ch, dl, ch, cs, ds, es, fs, gs, ss\n"); dprintf(" cr0, cr2, cr3, cr4, dr0, dr1, dr2, dr3, dr6, dr7\n"); dprintf(" gdtr, gdtl, idtr, idtl, tr, ldtr, $u0-$u9, $ea, $exp, $ra, $p\n"); dprintf(" : iopl, of, df, if, tf, sf, zf, af, pf, cf\n"); dprintf(" : %<32-bit address>, #<16-bit protect-mode [seg:]address>,\n"); dprintf(" &\n"); #endif } #if defined(KERNEL) && defined(i386) BOOLEAN X86GetTraceFlag (void) { return fTraceFlag; } #endif void X86ClearTraceFlag (void) { #if defined(KERNEL) && defined(i386) fTraceFlag = FALSE; #else X86SetRegFlagValue(FLAGTF, 0); #endif } void X86SetTraceFlag (void) { #if defined(KERNEL) && defined(i386) fTraceFlag = TRUE; #else X86SetRegFlagValue(FLAGTF, 1); #endif } #if defined(KERNEL) && defined(i386) /*** GetRegContext - return register context pointer * * Purpose: * Return the pointer to the current register context. * For kernel debugging, ensure the context is read. * * Input: * None. * * Returns: * Pointer to the context. * *************************************************************************/ PCONTEXT GetRegContext (void) { if (contextState == CONTEXTFIR) { if (!DbgGetThreadContext(NtsdCurrentProcessor, &RegisterContext)) { dprintf("DbgKdGetContext failed\n"); exit(1); } contextState = CONTEXTVALID; } return &RegisterContext; } void ChangeKdRegContext(ULONG pcValue, PDBGKD_CONTROL_REPORT pCtlReport) { ULONG cBytesWritten; ULONG cBytesRead; USHORT Processor; NTSTATUS NtStatus; if (pcValue) { // initial context contextState = CONTEXTFIR; VDMRegisterContext.Eip = pcValue; SpecialRegContext.KernelDr6 = pCtlReport->Dr6; SpecialRegContext.KernelDr7 = pCtlReport->Dr7; if (pCtlReport->ReportFlags & REPORT_INCLUDES_SEGS) { // // This is for backwards compatibility - older kernels // won't pass these registers in the report record. // contextState = CONTEXTSHORT; VDMRegisterContext.SegCs = pCtlReport->SegCs; VDMRegisterContext.SegDs = pCtlReport->SegDs; VDMRegisterContext.SegEs = pCtlReport->SegEs; VDMRegisterContext.SegFs = pCtlReport->SegFs; VDMRegisterContext.EFlags = pCtlReport->EFlags; } } else if (contextState == CONTEXTDIRTY) { // write final context if (!DbgSetThreadContext(NtsdCurrentProcessor, &VDMRegisterContext)) { dprintf("DbgKdSetContext failed\n"); exit(1); } NtStatus = DbgKdWriteControlSpace(NtsdCurrentProcessor, (PVOID)sizeof(CONTEXT), (PVOID)&SpecialRegContext, sizeof(KSPECIAL_REGISTERS), &cBytesWritten); if (!NT_SUCCESS(NtStatus) || cBytesWritten != sizeof(KSPECIAL_REGISTERS)) { dprintf("DbgKdWriteControlSpace failed\n"); exit(1); } if (fSetGlobalDataBrkpts && NumberProcessors > 1) { for ( Processor = 0; Processor < NumberProcessors; Processor++) { if (Processor != NtsdCurrentProcessor) { NtStatus = DbgKdReadControlSpace((USHORT)Processor, (PVOID)sizeof(CONTEXT), (PVOID)&SavedSpecialRegContext, sizeof(KSPECIAL_REGISTERS), &cBytesRead); if (!NT_SUCCESS(NtStatus) || cBytesRead != sizeof(KSPECIAL_REGISTERS)) { dprintf("DbgKdReadControlSpace failed\n"); exit(1); } memcpy(&SavedSpecialRegContext.KernelDr0, &SpecialRegContext.KernelDr0, 6 * sizeof(ULONG)); NtStatus = DbgKdWriteControlSpace((USHORT)Processor, (PVOID)sizeof(CONTEXT), (PVOID)&SavedSpecialRegContext, sizeof(KSPECIAL_REGISTERS), &cBytesWritten); if (!NT_SUCCESS(NtStatus) || cBytesWritten != sizeof(KSPECIAL_REGISTERS)) { dprintf("DbgKdWriteControlSpace failed\n"); exit(1); } } } } } } #endif #if defined(KERNEL) && defined(i386) void InitFirCache (ULONG count, PUCHAR pstream) { // // If we are in anything but 32-bit flat mode, then don't init cache // if (!fVm86 && !f16pm) { DbgKdInitVirtualCacheEntry (X86GetRegValue(REGEIP), count, pstream); } } #endif ULONG GetDregValue ( ULONG index ) { if (index < 4) { index += REGDR0; } else { index += REGDR6 - 6; } return X86GetRegValue(index); } VOID SetDregValue ( ULONG index, ULONG value ) { if (index < 4) { index += REGDR0; } else { index += REGDR6 - 6; } X86SetRegValue(index, value); } #if defined(KERNEL) && defined(i386) void SaveProcessorState(void) { PreviousProcessor = NtsdCurrentProcessor; SavedRegisterContext = VDMRegisterContext; SavedSpecialRegContext = SpecialRegContext; SavedContextState = contextState; contextState = CONTEXTNONE; } void RestoreProcessorState(void) { NtsdCurrentProcessor = PreviousProcessor; VDMRegisterContext = SavedRegisterContext; SpecialRegContext = SavedSpecialRegContext; contextState = SavedContextState; } #endif #ifdef i386 ULONGLONG STGetRegValue (ULONG regnum) { if (!STtrace) { return X86GetRegValue(regnum); } switch (regnum) { case REGEBP: return STebp; case REGESP: return STesp; default: DPRINT(("%s: bad regnum\n",DebuggerName)); break; } return 0; } #endif PUCHAR X86RegNameFromIndex (ULONG index) { ULONG count; for (count = 0; count < REGNAMESIZE; count++) if (regname[count].value == index) return regname[count].psz; return NULL; } #if defined(i386) BOOL DbgGetThreadContext( THREADORPROCESSOR TorP, PCONTEXT Context ) { #ifdef KERNEL return NT_SUCCESS(DbgKdGetContext(TorP, Context)); #else // KERNEL return GetThreadContext(TorP, Context); #endif // KERNEL } BOOL DbgSetThreadContext( THREADORPROCESSOR TorP, PCONTEXT Context ) { #ifdef KERNEL return NT_SUCCESS(DbgKdSetContext(TorP, Context)); #else // KERNEL return SetThreadContext(TorP, Context); #endif // KERNEL } #endif // i386