/*++ Copyright (c) 1992 Microsoft Corporation Module Name: cpuwin.c Abstract: This module contains the routines to manipulate the CPU Window Author: William J. Heaton (v-willhe) 20-Jul-1992 Griffith Wm. Kadnier (v-griffk) 10-Mar-1993 Environment: Win32, User Mode --*/ /* * Preprocessor */ #include "precomp.h" #pragma hdrstop #define EACOUNT 4 //for effective address display offsets /* * Global Memory (PROGRAM) */ extern CXF CxfIp; // for EA calcs v-griffk /* * Global Memory (FILE) */ static HWND hWndCpu; static PREGINFO pCpu; static UINT CpuCnt = 0; static HWND hWndFloat; static PREGINFO pFloat; static UINT FloatCnt = 0; static char szValue[1024]; /* * Prototypes */ VOID AgeCpuValues(PREGINFO pReg, UINT nCnt); PREGINFO CpuInitRegs(RT rtType, FT ftType, BOOL fFlagsAppend, UINT* cnt); BOOL CpuVerifyNew(PREGINFO pReg, UINT oln, UINT count); PSTR GetCpuString(PREGINFO pInfo, UINT nCnt, UINT PanelNumber, UINT Index); PSTR GetCpuValue(PREGINFO pInfo, UINT n); PSTR GetEA(UINT n); BOOL CPUSetValue(PPANE p, PREGINFO pReg); /* * Start of Code */ /*** ** Synopsis: ** hWnd = GetFloatHWND() ** Returns: ** Pointer to the current Float window handle. */ HWND GetFloatHWND(VOID) { #if defined( NEW_WINDOWING_CODE ) return(g_DebuggerWindows.hwndFloat); #else return(hWndFloat); #endif } /*** ** Synopsis: ** hWnd = GetCpuHWND() ** Returns: ** Pointer to the current Register window handle. */ HWND GetCpuHWND(VOID) { #if defined( NEW_WINDOWING_CODE ) return(g_DebuggerWindows.hwndCpu); #else return(hWndCpu); #endif } /*** CPUSetValue ** Synopsis: ** BOOL CPUSetValue( PPANE p ) ** Entry: ** p - Pane Information ** Returns: ** Pointer to the current Register window handle. */ BOOL CPUSetValue(PPANE p, PREGINFO pReg) { UINT iReg = p->CurIdx; BYTE lpb[10]; //BYTE lpb[8]; UCHAR cNat; /* ** If we're not editing or not in the right pane ** its a no-op (a successful no-op) */ if (p->nCtrlId != ID_PANE_RIGHT) { return(TRUE); } if (!p->Edit) { return(TRUE); } //v-vadimp - strip the NAT bit if ((LppdCur->mptProcessorType == mptia64) && (pReg[iReg].type & fmtNat) && (p->EditBuf[strlen(p->EditBuf) - 2] == ' ')) { cNat = p->EditBuf[strlen(p->EditBuf) - 1]; p->EditBuf[strlen(p->EditBuf) - 2] = '\0'; } /* ** Convert the character buffer into a byte buffer */ if (CPUnformatMemory(lpb, p->EditBuf, pReg[iReg].cbits, pReg[iReg].type, 16) != EENOERROR) { return(FALSE); } /* ** Write back the register to the CPU */ if (pReg[iReg].hFlag == -1) { OSDWriteRegister(LppdCur->hpid, LptdCur->htid, pReg[iReg].hReg, lpb); // v-vadimp - write up the NAT bit if ((LppdCur->mptProcessorType == mptia64) && (pReg[iReg].type & fmtNat)) { UINT NatReg, NatBit; ULONGLONG NatRegValue; if (pReg[iReg].hReg >= CV_IA64_IntZero && pReg[iReg].hReg <= CV_IA64_IntT22) { NatReg = CV_IA64_IntNats; NatBit = pReg[iReg].hReg - CV_IA64_IntZero; } else if (pReg[iReg].hReg >= CV_IA64_IntR32 && pReg[iReg].hReg <= CV_IA64_IntR95) { NatReg = CV_IA64_IntNats2; NatBit = pReg[iReg].hReg - CV_IA64_IntR32; } else if (pReg[iReg].hReg >= CV_IA64_IntR96 && pReg[iReg].hReg <= CV_IA64_IntR127) { NatReg = CV_IA64_IntNats3; NatBit = pReg[iReg].hReg - CV_IA64_IntR96; } else { DAssert(!"Unknown register with a NAT bit"); } OSDReadRegister(LppdCur->hpid, LptdCur->htid, NatReg, &NatRegValue); switch (cNat) { case '1': NatRegValue |= (1 << NatBit); break; case '0': NatRegValue &= ~(1 << NatBit); break; default: Assert(!"Bad NAT Bit value"); break; } OSDWriteRegister(LppdCur->hpid, LptdCur->htid, NatReg, &NatRegValue); } } else { OSDWriteFlag(LppdCur->hpid, LptdCur->htid, pReg[iReg].hFlag, lpb); } return(TRUE); } /* CPUSetValue */ /*** CpuVerifyNew * Purpose: Determine if a registerss result has changed since * the last time a user saw it * Input: * pvit - A pointer to the vit * oln - Item number of interest * Output: * Returns: * TRUE/FALSE the item has changed */ BOOL CpuVerifyNew(PREGINFO pReg, UINT oln, UINT count) { // No Registers, No change if (pReg == 0) { return(FALSE); } // EA always get painted if (oln >= count) { return(TRUE); } GetCpuString(pReg, count, ID_PANE_RIGHT, oln); // Do we have a string at all? if (pReg[oln].pszValueP || pReg[oln].pszValueC) { // Do we have both strings? if (pReg[oln].pszValueP && pReg[oln].pszValueC) { if ((!_strcmpi(pReg[oln].pszValueC, pReg[oln].pszValueP)) && (pReg[oln].fChanged == FALSE)) { return(FALSE); } else if ((!_strcmpi(pReg[oln].pszValueC, pReg[oln].pszValueP)) && (pReg[oln].fChanged == TRUE)) { pReg[oln].fChanged = FALSE; return(TRUE); } } // Nope, It changed pReg[oln].fChanged = TRUE; return(TRUE); } // Nope, No change return(FALSE); } /* CpuVerifyNew() */ /*** CPUEditProc ** Synopsis: ** long = CPUEditProc(hwnd, msg, wParam, lParam) ** Entry: ** hwnd - handle to window to process message for ** msg - message to be processed ** wParam - information about message to be processed ** lParam - information about message to be processed ** Description: ** MDI function to handle register window messages */ LRESULT WINAPI CPUEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { PPANE p = (PPANE)lParam; PPANEINFO pInfo = (PPANEINFO)wParam; PREGINFO* ppReg = (p->Type == CPU_WIN) ? &pCpu : &pFloat; PREGINFO pReg = (p->Type == CPU_WIN) ? pCpu : pFloat; UINT* pnCnt = (p->Type == CPU_WIN) ? &CpuCnt : &FloatCnt; HWND* phwnd = (p->Type == CPU_WIN) ? &hWndCpu : &hWndFloat; UINT i; switch (msg) { case WM_DESTROY: *phwnd = NULL; // No Break intended case WU_DBG_UNLOADEM: case WU_DBG_UNLOADEE: for (i = 0; i < *pnCnt; i++) { if (pReg[i].pszValueC) { free(pReg[i].pszValueC); } if (pReg[i].pszValueP) { free(pReg[i].pszValueP); } } if (pReg) { free(pReg); } *ppReg = NULL; *pnCnt = 0; break; case WU_INVALIDATE: if (p != (PPANE)NULL) { InvalidateRect(p->hWndButton, NULL, TRUE); InvalidateRect(p->hWndLeft, NULL, TRUE); InvalidateRect(p->hWndRight, NULL, TRUE); UpdateWindow(p->hWndLeft); UpdateWindow(p->hWndRight); } break; case WU_INITDEBUGWIN: *phwnd = hwnd; SendMessage(p->hWndLeft, EM_SETREADONLY, (WPARAM)TRUE, 0L); SendMessage(p->hWndRight, EM_SETREADONLY, (WPARAM)TRUE, 0L); if (!DbgFEmLoaded()) { return(FALSE); } // No Break intended case WU_DBG_LOADEM: if (p->Type == CPU_WIN) { ULONG ul; RT rtType = rtCPU; if (g_contWorkspace_WkSp.m_bRegModeExt) { rtType |= rtExtended; } else { rtType |= rtRegular; } if (g_contWorkspace_WkSp.m_bRegModeMMU) { rtType |= rtSpecial; if (OSDGetDebugMetric(LppdCur->hpid, LptdCur->htid, mtrcExtMMU, &ul) == xosdNone && ul != 0) { rtType |= rtKmode; } } pCpu = CpuInitRegs(rtType, ftCPU, TRUE, &CpuCnt); SendMessage(p->hWndLeft, LB_SETCOUNT, *pnCnt + EACOUNT, 0); SendMessage(p->hWndButton, LB_SETCOUNT, *pnCnt + EACOUNT, 0); SendMessage(p->hWndRight, LB_SETCOUNT, *pnCnt + EACOUNT, 0); } else { RT rtType = rtFPU | (g_contWorkspace_WkSp.m_bRegModeExt ? rtExtended : rtRegular); pFloat = CpuInitRegs(rtType, ftFPU, TRUE, &FloatCnt); SendMessage(p->hWndLeft, LB_SETCOUNT, *pnCnt, 0); SendMessage(p->hWndButton, LB_SETCOUNT, *pnCnt, 0); SendMessage(p->hWndRight, LB_SETCOUNT, *pnCnt, 0); } p->MaxIdx = ((p->Type == CPU_WIN) ? (*pnCnt + EACOUNT) : *pnCnt); p->CurIdx = 0; // No Break intended case WU_UPDATE: // Is EM loaded? if (!DbgFEmLoaded()) { return(FALSE); } //v-vadimp - for Merced we need to reinit regs after branches since the number of stacked registers may have changed (not applicable to floating point regs?) if ((p->Type == CPU_WIN) && (LppdCur->mptProcessorType == mptia64)) { //save the old values PREGINFO pOldCpu = pCpu; UINT oldCpuCnt = CpuCnt; RT rtType = rtCPU; ULONG ul; UINT i, j; //get new reg info if (g_contWorkspace_WkSp.m_bRegModeExt) { rtType |= rtExtended; } else { rtType |= rtRegular; } if (g_contWorkspace_WkSp.m_bRegModeMMU) { rtType |= rtSpecial; if (OSDGetDebugMetric(LppdCur->hpid, LptdCur->htid, mtrcExtMMU, &ul) == xosdNone && ul != 0) { rtType |= rtKmode; } } pCpu = CpuInitRegs(rtType, ftCPU, TRUE, &CpuCnt); //now go through the new list and copy all info about regs that were alread present - this will preserve correct register window update for (i = 0; i < CpuCnt; i++) for (j = 0; j < oldCpuCnt; j++) { if (pCpu[i].hReg == pOldCpu[j].hReg) { memcpy((LPVOID)&pCpu[i], (LPVOID)&pOldCpu[j], sizeof(REGINFO)); } } //don't forget to free the old structure free(pOldCpu); //update the paneinfo SendMessage(p->hWndLeft, LB_SETCOUNT, *pnCnt + EACOUNT, 0); SendMessage(p->hWndButton, LB_SETCOUNT, *pnCnt + EACOUNT, 0); SendMessage(p->hWndRight, LB_SETCOUNT, *pnCnt + EACOUNT, 0); p->MaxIdx = ((p->Type == CPU_WIN) ? (*pnCnt + EACOUNT) : *pnCnt); } AgeCpuValues(*ppReg, *pnCnt); for (i = p->TopIdx; i < (UINT)(p->TopIdx + p->PaneLines); i++) { if (CpuVerifyNew(*ppReg, i, *pnCnt)) { PaneInvalidateItem(p->hWndRight, p, (WORD)i); } } p->RightOk = TRUE; CheckPaneScrollBar(p, (WORD)((p->Type == CPU_WIN) ? (*pnCnt + EACOUNT) : *pnCnt)); break; case WU_SETWATCH: if (CPUSetValue(p, pReg)) { p->RightOk = FALSE; UpdateDebuggerState(UPDATE_WINDOWS); return(TRUE); } break; case WU_INFO: i = pInfo->ItemId; pInfo->ReadOnly = TRUE; pInfo->NewText = FALSE; pInfo->pBuffer = GetCpuString(*ppReg, *pnCnt, pInfo->CtrlId, i); pInfo->pFormat = NULL; // No formatting allowed // If Its a Value Pane and Its a real register, allow edits // and....Set the Change History if ((pInfo->CtrlId == ID_PANE_RIGHT) && ((WORD)i < ((p->Type == CPU_WIN) ? (p->MaxIdx - EACOUNT) : p->MaxIdx))) { pInfo->ReadOnly = FALSE; if (DbgFEmLoaded()) { if (pReg[i].pszValueP && pReg[i].pszValueC) { pInfo->NewText = strcmp(pReg[i].pszValueP, pReg[i].pszValueC); } } } return(TRUE); case WU_OPTIONS: return(TRUE); } return FALSE; } /* CPUEditProc() */ BOOL bDisplayReg(RD rd) //TRUE if the reg qualifies for display { if (LppdCur->mptProcessorType != mptia64) { return TRUE; } if (rd.rt & rtInvisible) {//first check if visible return FALSE; } if (rd.rt & rtStacked) {//if an IA64 stacked register check if it's on stack ULONGLONG ulIFS; OSDReadRegister(LppdCur->hpid, LptdCur->htid, CV_IA64_StIFS, &ulIFS); // read the IFS if ((rd.dwId - CV_IA64_IntR32) >= (ulIFS & 0x3F)) { //the low 6 bits is the register frame size return FALSE; //stacked not on the frame - no display } else { return TRUE; //stacked on the frame - display } } return TRUE; //not IA64 stacked - display } /*** CpuInitRegs() ** Synopsis: ** void = CpuInitRegs() ** Entry: ** none ** Returns: ** Nothing ** Description: ** This routine sets up our internal description of what a CPU window ** will look like. Several things must be noted here. ** 1. This routine may be called multiple times if you load up a ** new EM or if you change EM models. ** 2. This routines requires that an EM be loaded in order to succeed ** 3. This routine will use a set of flags to determine which set ** of register is to be "formatted". ** 4. Actual positioning of the register is still done in the ** ViewCPU routine not here. */ PREGINFO CpuInitRegs(RT rtType, FT ftType, BOOL fFlagsAppend, UINT* cnt) { DWORD dw; int cRegs; int cFlags; int i; int j; RD rd; FD fd; int cSaveRegs = 0; int cbSaveArea = 0; HTID htid = (LptdCur != NULL) ? LptdCur->htid : (HTID)0; PREGINFO LpCpuInfo = NULL; DAssert(LppdCur != NULL); DAssert(DbgFEmLoaded()); /* ** Get the count of Register Description records in the EM */ OSDGetDebugMetric(LppdCur->hpid, htid, mtrcCRegs, &dw); cRegs = (int)dw; OSDGetDebugMetric(LppdCur->hpid, htid, mtrcCFlags, &dw); cFlags = (int)dw; /* ** Now determine how many of them we really want to look at and ** display to the user */ for (i = 0; i < cRegs; i++) { Dbg(OSDGetRegDesc(LppdCur->hpid, htid, i, &rd) == xosdNone); if (((rd.rt & rtProcessMask) == (rtType & rtProcessMask)) && ((rd.rt & rtType & rtGroupMask) != 0) && bDisplayReg(rd) && ((rtKmode & rd.rt) ? (rtKmode & rtType) : 1)) { cSaveRegs += 1; } } for (i = 0; i < cFlags; i++) { Dbg(OSDGetFlagDesc(LppdCur->hpid, htid, i, &fd) == xosdNone); if ((fd.ft & ftType) == ftType) { cSaveRegs += 1; } } /* ** Now allocate space for use to hold the information about ** the registers */ LpCpuInfo = (PREGINFO)malloc(cSaveRegs * sizeof(*LpCpuInfo)); /* ** Now fill in the elements of the information structure ** to the best of our ability */ for (i = 0, j = 0; i < cRegs; i++) { Dbg(OSDGetRegDesc(LppdCur->hpid, htid, i, &rd) == xosdNone); if (((rd.rt & rtProcessMask) == (rtType & rtProcessMask)) && ((rd.rt & rtType & rtGroupMask) != 0) && bDisplayReg(rd) && ((rtKmode & rd.rt) ? (rtKmode & rtType) : 1)) { LpCpuInfo[j].lpsz = rd.lszName; LpCpuInfo[j].hReg = rd.dwId; LpCpuInfo[j].hFlag = (UINT)-1; LpCpuInfo[j].cbits = rd.dwcbits; LpCpuInfo[j].offValue = cbSaveArea; LpCpuInfo[j].pszValueC = NULL; LpCpuInfo[j].pszValueP = NULL; if ((rd.rt & rtFmtTypeMask) == rtInteger) { LpCpuInfo[j].type = fmtUInt | fmtZeroPad; } else if ((rd.rt & rtFmtTypeMask) == rtFloat) { LpCpuInfo[j].type = fmtFloat; } else if ((rd.rt & rtFmtTypeMask) == rtBit) { LpCpuInfo[j].type = fmtBit; } else { DAssert(FALSE); } if (rd.rt & rtNat) { LpCpuInfo[j].type |= fmtNat; } cbSaveArea += (rd.dwcbits + 7) / 8; j += 1; } } if (fFlagsAppend) { for (i = 0; i < cFlags; i++) { Dbg(OSDGetFlagDesc(LppdCur->hpid, htid, i, &fd) == xosdNone); if ((fd.ft & ftType) == ftType) { LpCpuInfo[j].lpsz = fd.lszName; LpCpuInfo[j].hReg = fd.dwId; LpCpuInfo[j].hFlag = i; LpCpuInfo[j].type = fmtUInt; LpCpuInfo[j].cbits = fd.dwcbits; LpCpuInfo[j].offValue = cbSaveArea; LpCpuInfo[j].pszValueC = NULL; LpCpuInfo[j].pszValueP = NULL; cbSaveArea += (fd.dwcbits + 7) / 8; j += 1; } } } DAssert(j == cSaveRegs); *cnt = cSaveRegs; return(LpCpuInfo); } /* CpuInitRegs() */ /* AgeCpuValues ** Synopsis: ** void AgeCpuValues( PREGINFO pReg, UINT nCnt); ** Purpose: ** Age the Register value strings by moving it to the previous value. ** If we have a previous value free it. Null the current value. ** Input: ** pReg - Pointer to the Register Info ** nCnt - Count of Registers */ VOID AgeCpuValues(PREGINFO pReg, UINT nCnt) { ULONG i; for (i = 0; i < nCnt; i++) { if (pReg[i].pszValueP) { free(pReg[i].pszValueP); } // Move Current to Prev. and Null current pReg[i].pszValueP = pReg[i].pszValueC; pReg[i].pszValueC = NULL; } } // AgeCpuValues /*** GetCpuString * Purpose: * Get the String associated with a register index * Input: * UINT PanelNumber - Panel whos string we need (BUTTON, LEFT, RIGHT) * UINT n - Index of the register * Output: * PSTR Pointer to the buffer containing the string. */ PSTR GetCpuString(PREGINFO pInfo, UINT nMax, UINT PanelNumber, UINT nCnt) { Unreferenced(nMax); if (pInfo == NULL || LppdCur == NULL || LptdCur == NULL) { return(" "); } // Focus in on the one we want switch (PanelNumber) { case ID_PANE_BUTTON: if (nCnt < nMax) { return("~"); } else { return("~"); } case ID_PANE_LEFT: if (nCnt < nMax) { return(pInfo[nCnt].lpsz); } else if (nCnt == nMax + 1) { return("EA"); } else { return(" "); } case ID_PANE_RIGHT: if (nCnt < nMax) { if (pInfo[nCnt].pszValueC == NULL) { pInfo[nCnt].pszValueC = _strdup(GetCpuValue(pInfo, nCnt)); } return(pInfo[nCnt].pszValueC); } else { return GetEA(nCnt - nMax); } } return(" "); } // GetCpuString /* GetCpuValue ** Synopsis: ** void GetCpuValue( PREGINFO pReg, UINT nCnt); ** Purpose: ** Get the value string assoicated with the th register. ** Input: ** pReg - Pointer to the Register Info ** nCnt - Count of Registers ** Output: ** Returns a pointer to a string. ** Exceptions: ** Notes: ** Treat the string as READ-ONLY or else. */ PSTR GetCpuValue(PREGINFO pInfo, UINT n) { BYTE lpb[100]; UINT digits; // precision expected // Read the Value if (pInfo[n].hFlag == -1) { OSDReadRegister(LppdCur->hpid, LptdCur->htid, pInfo[n].hReg, &lpb); } else { OSDReadFlag(LppdCur->hpid, LptdCur->htid, pInfo[n].hFlag, &lpb); } // Format the Value szValue[0] = 0; DAssert(sizeof(szValue) > (pInfo[n].cbits + 3) / 4 + 1); if (pInfo[n].type == fmtFloat) { if (LppdCur->mptProcessorType == mptia64) { digits = 55; } else { digits = 26; } } else if ((pInfo[n].type & fmtBasis) == fmtBit) { digits = pInfo[n].cbits + (pInfo[n].cbits + 7) / 8; //v-vadimp bits plus a space for each byte } else { digits = (pInfo[n].cbits + 3) / 4 + 1; } CPFormatMemory(szValue, digits, lpb, pInfo[n].cbits, pInfo[n].type, 16); if ((LppdCur->mptProcessorType == mptia64) && (pInfo[n].type & fmtNat)) { // v-vadimp - pick up the NAT bit UINT NatReg, NatBit; LONGLONG NatRegValue; if (pInfo[n].hReg >= CV_IA64_IntZero && pInfo[n].hReg <= CV_IA64_IntT22) { NatReg = CV_IA64_IntNats; NatBit = pInfo[n].hReg - CV_IA64_IntZero; } else if (pInfo[n].hReg >= CV_IA64_IntR32 && pInfo[n].hReg <= CV_IA64_IntR95) { NatReg = CV_IA64_IntNats2; NatBit = pInfo[n].hReg - CV_IA64_IntR32; } else if (pInfo[n].hReg >= CV_IA64_IntR96 && pInfo[n].hReg <= CV_IA64_IntR127) { NatReg = CV_IA64_IntNats3; NatBit = pInfo[n].hReg - CV_IA64_IntR96; } else { DAssert(!"Unknown register with a NAT bit"); } OSDReadRegister(LppdCur->hpid, LptdCur->htid, NatReg, &NatRegValue); if ((NatRegValue >> NatBit) & 0x1) { strcat(szValue, " 1"); } else { strcat(szValue, " 0"); } } return(szValue); } // GetCpuValue /* GetEA ** Synopsis: ** PSTR GetEA( UINT nCnt); ** Purpose: ** Get one of the EA for the current instruction. ** Input: ** nCnt - The EA to Get (1-based) ** Output: ** None ** Exceptions: ** Notes: ** A nCnt of zero returns blank....it simplifies the caller */ PSTR GetEA(UINT n) { SDI sds; ADDR AddrPC; if (LppdCur && LptdCur && n > 0) { AddrPC = *SHpADDRFrompCXT(&CxfIp.cxt); SYFixupAddr(&AddrPC); sds.dop = dopEA | dopFlatAddr; sds.addr = AddrPC; OSDUnassemble(LppdCur->hpid, LptdCur->htid, &sds); switch (n) { case 1: if (sds.ichEA0 != -1) { return(&sds.lpch[sds.ichEA0]); } break; case 2: if (sds.ichEA1 != -1) { return(&sds.lpch[sds.ichEA1]); } break; case 3: if (sds.ichEA2 != -1) { return(&sds.lpch[sds.ichEA2]); } break; default: break; } } return(" "); }