/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Cmdexec1.c Abstract: This file contains the code for the execution related commands in the command window. Author: Kent Forschmiedt (a-kentf) 20-Jul-92 Environment: Win32, User Mode --*/ #include "precomp.h" #pragma hdrstop #include "dbugexcp.h" #include #define strcspn _mbscspn /************ Data declaration ***********/ /****** Publics ********/ extern LPPD LppdCommand; extern LPTD LptdCommand; extern BOOL FSetLptd; // Was thread specified extern BOOL FSetLppd; // Was process specified extern INT BpCmdPid; extern INT BpCmdTid; extern char is_assign; extern EXCEPTION_LIST *DefaultExceptionList; extern ULONG ulPseudo[]; /****** Locals ********/ int LocalFrameNumber = 0; /****** Externs from ??? *******/ extern LPSHF Lpshf; // vector table for symbol handler extern CXF CxfIp; LPSTR ParseContext_FileName(LPSTR lpContext); void LogSx( EXCEPTION_LIST *eList ); /************ Code ***********/ /* * Helper and common functions */ BOOL GoOK(LPPD lppd, LPTD lptd) /*++ Routine Description: Determine whether a thread is GOable Arguments: lppd - Supplies pointer to process struct lptd - Supplies pointer to thread struct Return Value: TRUE if runnable, FALSE if not. --*/ { if (!lppd || !lptd) { return FALSE; } if (lppd->fFrozen) { return FALSE; } switch (lppd->pstate) { case psNoProgLoaded: case psPreRunning: case psExited: case psDestroyed: return FALSE; case psRunning: case psStopped: break; } switch (lptd->tstate) { case tsPreRunning: case tsStopped: case tsRipped: case tsExited: break; case tsRunning: case tsException1: case tsException2: return FALSE; } return TRUE; } /* GoOK() */ BOOL GoExceptOK(LPPD lppd, LPTD lptd) /*++ Routine Description: Determine whether a thread is in an exception, and can therefore GoHandled or GoUnHandled. Arguments: lppd - Supplies pointer to process struct lptd - Supplies pointer to thread struct Return Value: TRUE if runnable, FALSE if not. --*/ { if (!lppd || !lptd) { return FALSE; } if (lppd->fFrozen) { return FALSE; } switch (lppd->pstate) { case psNoProgLoaded: case psPreRunning: case psExited: case psDestroyed: return FALSE; case psRunning: case psStopped: break; } switch (lptd->tstate) { case tsPreRunning: case tsStopped: case tsRipped: case tsExited: case tsRunning: break; case tsException1: case tsException2: return TRUE; } return FALSE; } /* GoExceptOK() */ BOOL StepOK(LPPD lppd, LPTD lptd) /*++ Routine Description: Determine whether a thread is steppable. This will return TRUE for frozen threads, so caller will have to deal with that specially. Arguments: lppd - Supplies pointer to process structure lptd - Supplies pointer to thread structure Return Value: TRUE if steppable, FALSE if not --*/ { if (!lppd || !lptd) { return FALSE; } if (lppd->fFrozen || lptd->fFrozen) { return FALSE; } switch (lppd->pstate) { case psNoProgLoaded: case psPreRunning: case psExited: case psDestroyed: return FALSE; case psRunning: case psStopped: break; } switch (lptd->tstate) { case tsPreRunning: case tsStopped: break; case tsRunning: case tsException1: case tsException2: case tsRipped: case tsExited: return FALSE; } return TRUE; } /* StepOK() */ void NoRunExcuse(LPPD lppd, LPTD lptd) /*++ Routine Description: Print a message about why we can't run or step Arguments: lppd - Supplies pointer to process that isn't runnable lptd - Supplies pointer to thread that isn't runnable --*/ { if (!lppd) { CmdLogVar(ERR_Debuggee_Not_Alive); return; } if (lppd->fFrozen) { CmdLogVar(ERR_Cant_Run_Frozen_Proc); return; } switch (lppd->pstate) { case psNoProgLoaded: CmdLogVar(ERR_Debuggee_Not_Loaded); break; case psExited: case psDestroyed: CmdLogVar(ERR_Debuggee_Not_Alive); break; case psPreRunning: CmdLogVar(ERR_Debuggee_Starting); break; default: Assert(lptd); if (!lptd) { CmdLogVar(ERR_Debuggee_Not_Alive); return; } if (lptd->fFrozen) { CmdLogVar(ERR_Cant_Step_Frozen); return; } switch (lptd->tstate) { case tsRunning: CmdLogVar(ERR_Already_Running); break; case tsException1: case tsException2: CmdLogVar(ERR_Cant_Go_Exception); break; case tsRipped: CmdLogVar(ERR_Cant_Step_Rip); break; case tsExited: CmdLogVar(ERR_Thread_Exited); break; default: CmdLogVar(ERR_Command_Error); break; } } } /* NoRunExcuse() */ SHFLAG PASCAL PHCmpAlwaysMatch(LPSSTR lpsstr, LPV lpv, LSZ lpb, SHFLAG fcase) /*++ Routine Description: Compare function for PHFindNameInPublics which always succeeds. Arguments: lpsstr lpv lpb fcase Return Value: Always 0 --*/ { return 0; } VOID ThreadStatForThread(LPTD lptd) { LPTD lptdSave; TST tst; XOSD xosd; xosd = OSDGetThreadStatus(lptd->lppd->hpid, lptd->htid, &tst); if (xosd != xosdNone) { CmdLogFmt("No status for thread %d\r\n", lptd->itid); } else { CmdLogFmt("%s%2d %s %s %s", (lptd == LptdCur)? "*" : " ", lptd->itid, tst.rgchThreadID, tst.rgchState, tst.rgchPriority ); if (tst.dwTeb) { CmdLogFmt(" 0x%08x", tst.dwTeb ); } lptdSave = LptdCur; LptdCur = lptd; CmdLogFmt( " %s", GetLastFrameFuncName() ); LptdCur = lptdSave; CmdLogFmt( "\r\n" ); } } void ThreadStatForProcess(LPPD lppd) /*++ Routine Description: Prints status for all threads in a process Arguments: lppd - Supplies process to look at --*/ { LPTD lptd; if (lppd->lptdList == NULL) { CmdLogVar(ERR_No_Threads); return; } for (lptd = lppd->lptdList; lptd != NULL; lptd = lptd->lptdNext) { ThreadStatForThread(lptd); } } static BOOL makemask(char ** ppch, WORD * pmask) { WORD mask = 0; Assert ( ppch != NULL ); Assert ( *ppch != NULL ); if (!**ppch || **ppch == ' ' || **ppch == '\t') { mask = HSYMR_lexical | HSYMR_function | HSYMR_module | HSYMR_exe | HSYMR_public | HSYMR_global; } while ( **ppch != '\0' && **ppch != ' ' && **ppch != '\t' ) { BOOL fAdd = TRUE; fAdd = (BOOL)( *( *ppch + 1 ) != '-' ); switch ( **ppch ) { case 'l': case 'L': if( fAdd ) { mask |= HSYMR_lexical; } else { mask &= ~HSYMR_lexical; } break; case 'f': case 'F': if( fAdd ) { mask |= HSYMR_function; } else { mask &= ~HSYMR_function; } break; case 'c': case 'C': if ( fAdd ) { mask |= HSYMR_class; } else { mask &= ~HSYMR_class; } break; case 'm': case 'M': if( fAdd ) { mask |= HSYMR_module; } else { mask &= ~HSYMR_module; } break; case 'e': case 'E': if( fAdd ) { mask |= HSYMR_exe; } else { mask &= ~HSYMR_exe; } break; case 'p': case 'P': if( fAdd ) { mask |= HSYMR_public; } else { mask &= ~HSYMR_public; } break; case 'g': case 'G': if( fAdd ) { mask |= HSYMR_global; } else { mask &= ~HSYMR_global; } break; case '*': if( fAdd ) { mask = HSYMR_allscopes; } else { mask = 0x0000; } break; default: // invalid syntax return FALSE; } (*ppch)++; if( (**ppch == '+') || (**ppch == '-') ) { (*ppch)++; } } *pmask = mask; return TRUE; } typedef struct _tagHTMLIST { struct _tagHTMLIST *next; LPSTR lpszName; LPSTR lpszValue; BOOL fArg; } HTMLIST, *LPHTMLIST; LOGERR PrintAllLocals(CXF * pcxf) { DWORD cParm = 0; EESTATUS eeErr; LPHTMLIST found; HTMLIST head = {0}; EEHSTR hName = 0; HSYM hSym; HMEM hsyml = 0; HTM hTm = NULL; HTM hTmParm = NULL; EEHSTR hValue = 0; DWORD i; DWORD j; DWORD len; PHSL_HEAD lphsymhead; PHSL_LIST lphsyml; LPSTR lpszName; LPSTR lpszValue; LOGERR rval = LOGERROR_QUIET; SHFLAG shflag; DWORD strIndex; LPHTMLIST tail = NULL; if (!LppdCur) { CmdLogVar(ERR_Debuggee_Not_Alive); eeErr = EENOERROR; rval = LOGERROR_QUIET; goto exit; } tail = &head; SHGetNearestHSYM( &pcxf->cxt.addr, pcxf->cxt.hMod, EECODE, &hSym ); if (hSym) { eeErr = EEGetTMFromHSYM( hSym, &pcxf->cxt, &hTm, &i, /*ForceBind=*/TRUE, /*EnableProlog=*/FALSE ); if (eeErr == EENOERROR) { eeErr = EEcParamTM( &hTm, &cParm, &shflag ); if (eeErr) { goto exit; } for ( i=0; i<(DWORD)cParm; i++ ) { eeErr = EEGetParmTM( &hTm, (EERADIX)i, &hTmParm, &strIndex, FALSE ); if (eeErr) { continue; } eeErr = EEvaluateTM( &hTmParm, SHhFrameFrompCXF(pcxf), EEVERTICAL); if (eeErr) { EEFreeTM( &hTmParm ); continue; } eeErr = EEGetNameFromTM( &hTmParm, &hName ); if (eeErr) { EEFreeTM( &hTmParm ); continue; } eeErr = EEGetValueFromTM( &hTmParm, radix, NULL, &hValue ); if (eeErr) { EEFreeStr( hName ); EEFreeTM( &hTmParm ); continue; } lpszName = (PSTR) MMLpvLockMb( hName ); lpszValue = (PSTR) MMLpvLockMb( hValue ); tail->next = (LPHTMLIST) malloc( sizeof(HTMLIST) ); tail = tail->next; tail->next = NULL; tail->lpszName = _strdup( lpszName ); tail->lpszValue = _strdup( lpszValue ); tail->fArg = TRUE; MMbUnlockMb( hValue ); MMbUnlockMb( hName ); EEFreeStr( hValue ); EEFreeStr( hName ); } EEFreeTM( &hTm ); } } eeErr = EEGetHSYMList ( &hsyml, &pcxf->cxt, HSYMR_lexical + HSYMR_function, NULL, FALSE ); if (!hsyml) { goto exit; } len = 0; lphsymhead = (PHSL_HEAD) MMLpvLockMb ( hsyml ); lphsyml = (PHSL_LIST)(lphsymhead + 1); for ( i = 0; i != lphsymhead->blockcnt; i++ ) { for ( j = 0; j != lphsyml->symbolcnt; j++ ) { if ( SHCanDisplay ( lphsyml->hSym[j] ) ) { hSym = lphsyml->hSym[j]; if (!hSym) { continue; } eeErr = EEGetTMFromHSYM( hSym, &pcxf->cxt, &hTm, &strIndex, TRUE, FALSE ); if (eeErr) { continue; } eeErr = EEvaluateTM( &hTm, SHhFrameFrompCXF(pcxf), EEVERTICAL); if (eeErr) { EEFreeTM( &hTm ); break; } eeErr = EEGetNameFromTM( &hTm, &hName ); if (eeErr) { EEFreeTM( &hTm ); continue; } eeErr = EEGetValueFromTM( &hTm, radix, NULL, &hValue ); if (eeErr) { EEFreeStr( hName ); EEFreeTM( &hTm ); continue; } lpszValue = (PSTR) MMLpvLockMb( hValue ); lpszName = (PSTR) MMLpvLockMb( hName ); { DWORD tmp_len; tmp_len = strlen(lpszName); len = max( len, tmp_len); } found = head.next; while (found) { if (found->fArg && (_stricmp(found->lpszName,lpszName)==0)) { break; } found = found->next; } if (!found) { tail->next = (LPHTMLIST) malloc( sizeof(HTMLIST) ); tail = tail->next; tail->next = NULL; tail->lpszName = _strdup( lpszName ); tail->lpszValue = _strdup( lpszValue ); tail->fArg = FALSE; } MMbUnlockMb( hValue ); MMbUnlockMb( hName ); EEFreeStr( hValue ); EEFreeStr( hName ); EEFreeTM( &hTm ); } } lphsyml = (PHSL_LIST) &(lphsyml->hSym[j]); } MMbUnlockMb ( hsyml ); found = head.next; while (found) { if (found->fArg) { CmdLogFmt( " " ); } else { CmdLogFmt( " " ); } CmdLogFmt( "%-*s %s\r\n", len, found->lpszName, found->lpszValue ); found = found->next; } rval = LOGERROR_NOERROR; exit: if (tail) { found = tail->next; while (found) { free( found->lpszName ); free( found->lpszValue ); tail = found->next; free( found ); found = tail; } } return rval; } /* * Command Entry Points */ LOGERR LogAttach(LPSTR lpsz, DWORD dwUnused) { LONG pid = 0; HANDLE hEvent; LPSTR lpsz1; char szError[300]; BOOL fReconnect = FALSE; CmdInsertInit(); PDWildInvalid(); TDWildInvalid(); /* ** Check for no argument */ lpsz = CPSkipWhitespace(lpsz); if (*lpsz == 0) { fReconnect = TRUE; } else { lpsz1 = CPSzToken(&lpsz, NULL); if (!lpsz1) { return LOGERROR_UNKNOWN; } /* ** Process ID is always 32 bits */ if (CPGetCastNbr(lpsz1, T_LONG, 10, fCaseSensitive, &CxfIp, (LPSTR)&pid, szError, FALSE) != EENOERROR) { CmdLogFmt("%s\r\n", szError); return LOGERROR_QUIET; } } hEvent = (HANDLE)0; if (!AttachDebuggee(pid, hEvent)) { CmdLogVar(ERR_Attach_Failed); return LOGERROR_QUIET; } // AttachDebuggee() guarantees that the proc is finished loading on return. if (g_contWorkspace_WkSp.m_bAttachGo) { LptdCur->fGoOnTerm = TRUE; Go(); CmdLogVar(DBG_Attach_Running); } else { CmdLogVar(DBG_Attach_Stopped); if (LptdCur) { if ( !(LptdCur->tstate & tsException1) && !(LptdCur->tstate & tsException2)) { SetPTState(psInvalidState, tsStopped); } } UpdateDebuggerState(UPDATE_WINDOWS); } return LOGERROR_NOERROR; } LOGERR LogStart(LPSTR lpsz, DWORD dwUnused) { return LogStartWithArgs(lpsz, NULL); } LOGERR LogStartWithArgs(LPSTR lpsz, LPSTR lpszArgs) { lpsz = CPSkipWhitespace(lpsz); if (*lpsz == 0) { return LOGERROR_UNKNOWN; } if (!RestartDebuggee(lpsz, lpszArgs)) { CmdLogVar(ERR_Start_Failed); return LOGERROR_QUIET; } return LOGERROR_NOERROR; } LOGERR LogKill(LPSTR lpsz, DWORD dwUnused) { LPPD lppd; XOSD xosd; int err; int cch; int i; CmdInsertInit(); PDWildInvalid(); TDWildInvalid(); /* ** Check for no argument */ lpsz = CPSkipWhitespace(lpsz); if (*lpsz == 0) { return LOGERROR_UNKNOWN; } /* ** An argument -- must be a number in base 10 */ i = (int) CPGetInt(lpsz, &err, &cch); if (err) { return LOGERROR_UNKNOWN; } lppd = ValidLppdOfIpid(i); if (!lppd) { CmdLogVar(ERR_Process_Not_Exist); return LOGERROR_QUIET; } xosd = OSDProgramFree(lppd->hpid); if (xosd != xosdNone) { CmdLogVar(ERR_Kill_Failed); return LOGERROR_QUIET; } return LOGERROR_NOERROR; } LOGERR LogConnect(LPSTR lpsz, DWORD dwUnused) { CmdInsertInit(); PDWildInvalid(); TDWildInvalid(); AttachDebuggee(0, NULL); return LOGERROR_NOERROR; } LOGERR LogDisconnect(LPSTR lpsz, DWORD dwUnused) { XOSD xosd; CmdInsertInit(); PDWildInvalid(); TDWildInvalid(); if (!LppdFirst) { CmdLogFmt("not connected\r\n"); return LOGERROR_QUIET; } CmdLogFmt("Connection to remote has been broken\r\n" ); CmdLogFmt("Stopped debugging\r\n" ); if (g_contWorkspace_WkSp.m_bDisconnectOnExit && LppdCur && LptdCur) { xosd = OSDDisconnect( LppdCur->hpid, LptdCur->htid ); } else { xosd = OSDDisconnect( LppdFirst->hpid, NULL ); } DisconnectDebuggee(); return LOGERROR_NOERROR; } LOGERR LogTitle(LPSTR lpsz, DWORD dwUnused) { CmdInsertInit(); lpsz = CPSkipWhitespace(lpsz); FREE_STR(g_contWorkspace_WkSp.m_pszWindowTitle); g_contWorkspace_WkSp.m_pszWindowTitle = _strdup(lpsz); SetWindowText( hwndFrame, lpsz ); CmdLogFmt("Window title has been changed to %s\r\n", lpsz ); return LOGERROR_NOERROR; } LOGERR LogRemote(LPSTR lpsz) { BOOL fAppend = FALSE; CmdInsertInit(); if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) { CmdLogFmt("Remote is only supported on Windows NT and Windows 2000\r\n"); return LOGERROR_QUIET; } lpsz = CPSkipWhitespace(lpsz); if (((*lpsz == '/') || (*lpsz == '-')) && (tolower(*(lpsz+1)) == 'a')) { lpsz += 2; lpsz = CPSkipWhitespace(lpsz); fAppend = TRUE; } StartRemoteServer( lpsz, fAppend ); return LOGERROR_NOERROR; } LOGERR LogBPSet( BOOL fDataBp, LPSTR lpsz ) /*++ Routine Description: This routine is used by the command processor to add a breakpoint to the set of breakpoints. The breakpoint will be added and, if the debugger is running, committed. Arguments: fDataBp - TRUE if the command is BA command FALSE if the command is a BP command lpsz - Supplies string containing the breakpoint command to be added Return Value: log error code --*/ { BPSTATUS bpstatus; HBPT hbpt; int iBp = -1; int err, nRet; int cch; EESTATUS eest; ADDR addr; CHAR BaSize; CHAR BaType; LOGERR rVal = LOGERROR_NOERROR; LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; char szStr[MAX_USER_LINE], szC[MAX_USER_LINE]; LPSTR lpsz1, lpFile = 0; BOOL bMap = FALSE; CmdInsertInit(); IsKdCmdAllowed(); PDWildInvalid(); PreRunInvalid(); if (*CPSkipWhitespace(lpsz) == 0) { return LOGERROR_UNKNOWN; } if (fDataBp) { lpsz = CPSkipWhitespace( lpsz ); switch (tolower(*lpsz)) { case 'e': case 'r': case 'w': BaType = *lpsz; break; default: CmdLogFmt( "BA command missing type [e|r|w]\n" ); return LOGERROR_QUIET; } lpsz++; lpsz = CPSkipWhitespace( lpsz ); switch (*lpsz) { case '1': case '2': case '4': BaSize = *lpsz; break; default: CmdLogFmt( "BA command missing size [1|2|4]\n" ); return LOGERROR_QUIET; } lpsz++; eest = CPGetAddress(lpsz, &cch, &addr, radix, &CxfIp, fCaseSensitive, g_contWorkspace_WkSp.m_bMasmEval ); if (eest != EENOERROR) { CmdLogFmt( "Invalid address\n" ); return LOGERROR_QUIET; } SYFixupAddr(&addr); sprintf( szStr, "=\"0x%016I64x\" /R%c /A%c ", addr.addr.off, BaSize, BaType ); if (FSetLppd) { sprintf(szStr + strlen(szStr), " /H%d", BpCmdPid); } if (FSetLptd && BpCmdTid != -1) { sprintf(szStr + strlen(szStr), " /T%d", BpCmdTid); } bpstatus = BPParse( &hbpt, szStr, NULL, NULL, LppdCur ? LppdCur->hpid : 0 ); } else { strcpy(szStr, lpsz); lpsz = szStr; if (FSetLppd) { sprintf(szStr + strlen(szStr), " /H%d", BpCmdPid); } if (FSetLptd && BpCmdTid != -1) { sprintf(szStr + strlen(szStr), " /T%d", BpCmdTid); } if (isdigit(*lpsz)) { iBp = CPGetInt(lpsz, &err, &cch); lpsz += cch; if (BPHbptFromI(&hbpt, iBp) != BPNoMatch) { CmdLogVar(ERR_Breakpoint_Already_Used, iBp); rVal = LOGERROR_QUIET; goto done; } } // require space after bp[n] lpsz1 = CPSkipWhitespace(lpsz); if (lpsz1 == lpsz) { rVal = LOGERROR_UNKNOWN; goto done; } if (!DebuggeeActive()) { //try to parse a filename out of the context set strcpy (szC, lpsz1); lpFile = ParseContext_FileName(szC); if (lpFile != (LPSTR)NULL) { bMap = FALSE; nRet = SrcMapSourceFilename (lpFile,_MAX_PATH, SRC_MAP_OPEN, NULL, // Not user activated FALSE); if ((nRet >= 1) && (nRet <= 2)) { bMap = TRUE; } } } bpstatus = BPParse( &hbpt, lpsz1, NULL, (bMap == TRUE) ? lpFile : NULL, LppdCur ? LppdCur->hpid : 0 ); } if (bpstatus != BPNOERROR) { // NOTENOTE a-kentf we can do better than "command error" here rVal = LOGERROR_UNKNOWN; } else if ( BPAddToList(hbpt, iBp) != BPNOERROR ) { // NOTENOTE a-kentf here, too rVal = LOGERROR_UNKNOWN; } else { if (DebuggeeActive() ) { BPSTATUS Status; Status = BPBindHbpt( hbpt, &CxfIp ); if ( LppdCur != NULL ) { if ( Status == BPCancel ) { CmdLogVar(ERR_Breakpoint_Not_Set); } else if ( Status != BPNOERROR ) { CmdLogVar(ERR_Breakpoint_Not_Instantiated); } } } Dbg(BPCommit() == BPNOERROR); } done: LppdCur = LppdT; LptdCur = LptdT; UpdateDebuggerState(UPDATE_CONTEXT); return rVal; } /* LogBPSet() */ LPSTR ParseContext_FileName( LPSTR lpContext ) /*++ Routine Description: This routine is used by the command processor to parse the context set for filenames Arguments: lpContext - Supplies string containing the context set to be be parsed Return Value: LPSTR or (NULL) --*/ { LPSTR lpBegin; LPSTR lpEnd; LPSTR lpTarget = (LPSTR)NULL; // Skip module if ( lpBegin = (PSTR) strchr( (PBYTE) lpContext, ',' ) ) { // Skip blanks lpBegin++; lpBegin += strspn( lpBegin, " \t" ); // Get end of filename lpEnd = lpBegin + strcspn( (PBYTE) lpBegin, (PBYTE) ",} " ); *lpEnd = '\0'; if ( lpEnd > lpBegin ) { lpTarget = lpBegin; } } return lpTarget; } LOGERR LogBPList( void ) /*++ Routine Description: This routine will display a list of the breakpoints in the command window. Arguments: None Return Value: log error code --*/ { HBPT hbpt = 0; HPID hpid; char rgch[256]; CmdInsertInit(); PreRunInvalid(); Dbg(BPNextHbpt(&hbpt, bptNext) == BPNOERROR); if (hbpt == NULL) { /* ** No breakpoints to list */ // not really an error CmdLogVar(ERR_No_Breakpoints); } else { for ( ; hbpt != NULL; BPNextHbpt( &hbpt, bptNext )) { if (FSetLppd && LppdCommand && LppdCommand != (LPPD)-1) { BPGetHpid(hbpt, &hpid); if (hpid != LppdCommand->hpid) { continue; } } Dbg( BPFormatHbpt( hbpt, rgch, sizeof(rgch), BPFCF_ITEM_COUNT) == BPNOERROR ); CmdLogFmt("%s\r\n", rgch ); } } return LOGERROR_NOERROR; } /* LogBPList() */ LOGERR LogBPChange( LPSTR lpszArgs, int iAction ) /*++ Routine Description: This function will go through the set of arguments looking for a set of breakpoint numbers (or asterisk) and perform the action on each of the requested breakpoints. Arguments: lpszArgs - Supplies string containing the set of breakpoints to change iAction - Supplies which action to perform - Enable, Disable, Delete Return Value: log error code --*/ { HBPT hbpt; HBPT hbptN; int i, j; int err; int cb; DWORD ipid; LOGERR rVal = LOGERROR_NOERROR; LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; BPSTATUS Status; CmdInsertInit(); IsKdCmdAllowed(); PreRunInvalid(); lpszArgs = CPSkipWhitespace(lpszArgs); /* ** There are two possible sets of values at this point. The first ** is an asterisk ('*'), the second is a number or set of whitespace ** separated numbers. */ if (*lpszArgs == '\0') { rVal = LOGERROR_UNKNOWN; goto done; } if (*lpszArgs == '*') { if (*CPSkipWhitespace(lpszArgs+1)) { rVal = LOGERROR_UNKNOWN; goto done; } Dbg( BPNextHbpt(&hbpt, bptFirst) == BPNOERROR); for ( ; hbpt != NULL; hbpt = hbptN) { hbptN = hbpt; Dbg( BPNextHbpt( &hbptN, bptNext ) == BPNOERROR); if (LppdCommand && LppdCommand != (LPPD)-1) { BPGetIpid(hbpt, &ipid); if (LppdCommand->ipid != ipid) { continue; } } switch ( iAction ) { case LOG_BP_DISABLE: BPDisable( hbpt ); break; case LOG_BP_ENABLE: Status = BPEnable( hbpt ); if ( Status != BPNOERROR ) { CmdLogVar(ERR_Breakpoint_Not_Instantiated); } break; case LOG_BP_CLEAR: BPDelete( hbpt ); break; } } } else { while ( *(lpszArgs = CPSkipWhitespace(lpszArgs)) ) { i = (int) CPGetInt(lpszArgs, &err, &cb); if (err) { BPUnCommit(); rVal = LOGERROR_UNKNOWN; goto done; } lpszArgs = CPSkipWhitespace(lpszArgs + cb); j = i; if (*lpszArgs == '-') { j = CPGetInt((lpszArgs = CPSkipWhitespace(lpszArgs+1)), &err, &cb); if (err) { BPUnCommit(); rVal = LOGERROR_UNKNOWN; goto done; } lpszArgs = CPSkipWhitespace(lpszArgs + cb); } if (*lpszArgs == ',') { lpszArgs++; } for ( ; i <= j; i++) { err = BPHbptFromI( &hbpt, i ); if (err != BPNOERROR) { CmdLogVar(ERR_Breakpoint_Not_Exist, i); } else { switch ( iAction ) { case LOG_BP_DISABLE: BPDisable( hbpt ); break; case LOG_BP_ENABLE: Status = BPEnable( hbpt ); if ( Status != BPNOERROR ) { CmdLogVar(ERR_Breakpoint_Not_Instantiated); } break; case LOG_BP_CLEAR: BPDelete( hbpt ); break; } } } } } BPCommit(); done: LppdCur = LppdT; LptdCur = LptdT; return rVal; } /* LogBPChange() */ LOGERR LogEvaluate( LPSTR lpsz, BOOL fSpecialNtsdEval ) /*++ Routine Description: This function will take a string, evalute it and display either the result or an error message Arguments: lpsz - pointer to string to be evaluated fSpecialNtsdEval - use NTSD expresion evaluator Return Value: log error code --*/ { long cChild = 0; long cPtr = 0; CXF cxf; LOGERR logerror = LOGERROR_NOERROR; EESTATUS eeErr = EENOERROR; EEPDTYP ExpTyp; BOOL fFmtStr = FALSE; EEHSTR hErrStr; EEHSTR hName = 0; HTI hti; HTM hTm = NULL; HTM hTmChild = NULL; HTM hTmPtr = NULL; EEHSTR hValue = 0; long i; UINT len; LPPD LppdT = LppdCur; LPSTR lpszName; LPSTR lpszValue; LPTD LptdT = LptdCur; LPSTR pErrStr; PTI pti; RTMI rti = {0}; SHFLAG shflag; DWORD strIndex; #if 0 HTMLIST head = {0}; LPHTMLIST tail = NULL; LPHTMLIST found; HTM hTmParm = NULL; DWORD j; BOOL fExpandable; HMEM hsyml = 0; PHSL_HEAD lphsymhead; PHSL_LIST lphsyml; HSYM hSym; DWORD cParm = 0; #endif // 0 // Start by doing standard state checking on the command. CmdInsertInit(); IsKdCmdAllowed(); PDWildInvalid(); TDWildInvalid(); PreRunInvalid(); // Check for no expression lpsz = CPSkipWhitespace(lpsz); if (*lpsz == 0) { return LOGERROR_UNKNOWN; } // If a different thread or process that the current process is // specified -- switch the debugger to be looking at the requested // process not the current process LppdCur = LppdCommand; LptdCur = LptdCommand; if (LptdCur != LptdT || LppdCur != LppdT) { UpdateDebuggerState(UPDATE_CONTEXT); } // Force command window open CmdNoLogString(""); // If we need to -- change the context to point to the frame // on the stack rather than the frame associated with the current PC if (LocalFrameNumber) { cxf = *ChangeFrame( LocalFrameNumber ); } else { cxf = CxfIp; } // Use NTSD expression evaluator if (fSpecialNtsdEval) { // Use NTSD expresion evaluator. ADDR addr; int nStatus, nCntCharsUsed; XOSD xosd; nStatus = CPGetAddress(lpsz, &nCntCharsUsed, &addr, radix, &cxf, FALSE, TRUE); if (CPNOERROR == nStatus && (xosdNone == (xosd = SYFixupAddr(&addr)) ) ) { CmdLogFmt("Evaluate expression: %I64d = 0x%016I64x\r\n", addr.addr.off, addr.addr.off); } else { logerror = LOGERROR_CP; } goto exit; } // If we see a lone '.', we are going to list all of the locals for // the current procedure (this is mainly for remote debugging as // otherwise there is a locals window which shows the same thing) if (*lpsz == '.' && strlen(lpsz) == 1) { PrintAllLocals(&cxf); goto exit; } // Normal expression evaluation. // Start with the normal sequence of Parse, Bind and Evaluate // for the expression is_assign = FALSE; eeErr = EEParse(lpsz, radix, fCaseSensitive, &hTm, &strIndex); if (eeErr) { goto exit; } eeErr = EEBindTM( &hTm, SHpCXTFrompCXF(&cxf), TRUE, FALSE ); if (eeErr) { goto exit; } eeErr = EEvaluateTM( &hTm, SHhFrameFrompCXF(&cxf), EEVERTICAL ); if (eeErr) { goto exit; } // Extract some info from the result. There are certain types of // operations we can't or don't do. // 1. Function calls are not evaluated if the process is running eeErr = EEInfoFromTM( &hTm, &rti, &hti ); if (eeErr || hti == NULL) { goto exit; } pti = (PTI) MMLpvLockMb( hti ); if (pti == NULL) { goto exit; } if (pti->fFunction && IsProcRunning(LppdCur)) { MMbUnlockMb(hti); EEFreeTI( &hti ); goto exit; } fFmtStr = pti->fFmtStr; MMbUnlockMb(hti); EEFreeTI( &hti ); // Display the result we are first interested in eeErr = EEGetValueFromTM( &hTm, radix, NULL, &hValue); if (eeErr) { goto exit; } lpszValue = (PSTR) MMLpvLockMb(hValue); ulPseudo[CV_REG_PSEUDO9-CV_REG_PSEUDO1] = strtoul(lpszValue, NULL, 0); CmdLogFmt("%s\r\n", lpszValue); MMbUnlockMb(hValue); EEFreeStr(hValue); // Now lets do some interesting play as well -- // Specifically they want to display an expanded version of the // item if the conditions are correct. // What suppressed expanded display are the following things: // 1. The item is not expandable // 2. The expression has a side effect // 3. There is a format string on the expression if (fFmtStr || is_assign) { goto exit; } ExpTyp = EEIsExpandable(&hTm); if ((ExpTyp == EENOTEXP) || (ExpTyp == EETYPENOTEXP)) { goto exit; } eeErr = EEcChildrenTM(&hTm, &cChild, &shflag); if (eeErr) { goto exit; } if (ExpTyp == EEPOINTER) { eeErr = EEDereferenceTM(&hTm, &hTmPtr, &strIndex, fCaseSensitive); if (eeErr) { goto exit; } eeErr = EEcChildrenTM(&hTmPtr, &cPtr, &shflag); if (eeErr) { goto exit; } } #if 0 // Why is this here? // JLS eeErr = EEGetNameFromTM(&hTm, &hName); if (eeErr == EENOERROR) { lpszName = MMLpvLockMb(hName); CmdLogFmt("%s ", lpszName); MMbUnlockMb(hName); EEFreeStr(hName); } #endif // Why is this here? // This is a pointer to a class or a structure if ((ExpTyp == EEPOINTER) && (cChild == 1)) { if (!cPtr) { goto exit; } else { cChild = cPtr; EEFreeTM(&hTm); hTm = hTmPtr; hTmPtr = NULL; eeErr = EEvaluateTM(&hTm, SHhFrameFrompCXF(&cxf), EEVERTICAL); if (eeErr) { goto exit; } } } eeErr = EEGetValueFromTM(&hTm, radix, NULL, &hValue); if (eeErr) { goto exit; } lpszValue = (PSTR) MMLpvLockMb(hValue); if ((ExpTyp != EEPOINTER) || (cChild != 0)) { MMbUnlockMb( hValue ); EEFreeStr( hValue ); } else { // this is a pointer to an aggregate type or the user wants a // string printed eeErr = EEvaluateTM(&hTmPtr, SHhFrameFrompCXF(&cxf), EEVERTICAL); if (eeErr) { goto exit; } eeErr = EEGetValueFromTM(&hTmPtr, radix, NULL, &hName); if (eeErr) { goto exit; } lpszName = (PSTR) MMLpvLockMb(hName); CmdLogFmt("%s %s\r\n", lpszValue, lpszName); EEFreeStr(hValue); EEFreeStr(hName); MMbUnlockMb(hValue); MMbUnlockMb(hName); goto exit; } // From now on may take a while -- allow user to abort operation SetCtrlCTrap(); // first loop thru all of the children to see what the longest name is for (i=0,len=0; ifFunction && IsProcRunning(LppdCur)) { EEFreeTI( &hti ); goto exit; } fFmtStr = pti->fFmtStr; EEFreeTI( &hti ); if (fExpandable) { eeErr = EEGetNameFromTM( &hTm, &hName ); if (eeErr == EENOERROR) { lpszName = MMLpvLockMb( hName ); CmdLogFmt( "%s ", lpszName ); MMbUnlockMb( hName ); EEFreeStr( hName ); } if (ExpTyp == EEPOINTER && cChild == 1) { // this is a pointer to a class or a structure if (cPtr) { // the class/structure has members cChild = cPtr; EEFreeTM( &hTm ); hTm = hTmPtr; eeErr = EEvaluateTM( &hTm, SHhFrameFrompCXF(&cxf), EEVERTICAL ); if (eeErr) { goto exit; } } else { // this is an empty class/structure fExpandable = FALSE; fEmpty = TRUE; } } } eeErr = EEGetValueFromTM( &hTm, radix, NULL, &hValue); if (eeErr) { goto exit; } lpszValue = MMLpvLockMb( hValue ); if (!fExpandable) { ulPseudo[CV_REG_PSEUDO9-CV_REG_PSEUDO1] = strtoul(lpszValue, NULL, 0); } if (fExpandable && ExpTyp == EEPOINTER && cChild == 0 && (!fFmtStr)) { // this is pointer to an agregate type or the user wants a string printed eeErr = EEvaluateTM( &hTmPtr, SHhFrameFrompCXF(&cxf), EEVERTICAL ); if (eeErr) { goto exit; } eeErr = EEGetValueFromTM( &hTmPtr, radix, NULL, &hName ); if (eeErr) { goto exit; } lpszName = MMLpvLockMb( hName ); CmdLogFmt( "%s %s\r\n", lpszValue, lpszName ); EEFreeStr( hValue ); EEFreeStr( hName ); MMbUnlockMb( hValue ); MMbUnlockMb( hName ); goto exit; } else { if (fEmpty) { CmdLogFmt("%s (empty class/structure)\r\n", lpszValue); } else { CmdLogFmt("%s\r\n", lpszValue); } MMbUnlockMb( hValue ); EEFreeStr( hValue ); if (fExpandable && cChild > 0 && fFmtStr) { goto exit; } } if (fExpandable) { // first loop thru all of the children to see what the longest name is for (i=0,len=0; icxt, mask, (PBYTE) lpRE, TRUE ); if ( eest ) { // error occured, display error msg and get out CVExprErr ( eest, CMDWINDOW, &hTM, NULL); fAbort = TRUE; } else { // display the syms lphsymhead = (PHSL_HEAD) MMLpvLockMb ( hsyml ); lphsyml = (PHSL_LIST)(lphsymhead + 1); for ( i = 0; !fAbort && i != (UINT)lphsymhead->blockcnt; i++ ) { *szContext = 0; if ( lphsyml->status.hascxt && !EEFormatCXTFromPCXT(&lphsyml->Cxt, &hStr, g_contWorkspace_WkSp.m_bShortContext)) { lpStr = (PSTR) MMLpvLockMb( hStr ); if (g_contWorkspace_WkSp.m_bShortContext) { strcpy( szContext, lpStr ); } else { BPShortenContext( lpStr, szContext); strcat( szContext, " " ); } MMbUnlockMb(hStr); EEFreeStr(hStr); } szNameBuf[0] = '&'; for ( j = 0; !fAbort && j < (UINT)lphsyml->symbolcnt; j++ ) { if ( SHGetSymName ( lphsyml->hSym[j], (LPSTR)szNameBuf+1 ) ) { eest = EENOERROR; addr = *SHpAddrFrompCxt(&lpCxf->cxt); if (!SHAddrFromHsym(&addr, lphsyml->hSym[j])) { eest = CPGetAddress(szNameBuf, &cch, &addr, radix, lpCxf, fCaseSensitive, g_contWorkspace_WkSp.m_bMasmEval); } if (eest == EENOERROR) { SYFixupAddr(&addr); EEFormatAddress(&addr, szAddr, sizeof(szAddr), g_contWorkspace_WkSp.m_bShowSegVal? EEFMT_SEG : 0 ); CmdLogFmt("%s %s%s\n", szAddr, szContext, szNameBuf+1 ); } } fAbort = CheckCtrlCTrap(); } lphsyml = (PHSL_LIST) &(lphsyml->hSym[j]); } MMbUnlockMb ( hsyml ); } } while ( !fAbort && ! lphsymhead->status.endsearch ); if (!fAbort) { err = LOGERROR_NOERROR; } ClearCtrlCTrap(); if ( hsyml ) { EEFreeHSYMList ( &hsyml ); } return fAbort; } LOGERR LogExamine( LPSTR lpsz ) /*++ Routine Description: eXamine symbols command: x pattern may include * and ? as in DOS filename matching. Arguments: lpsz - Supplies pointer to command tail Return Value: LOGERROR code --*/ { #define CONTEXT_TEMPLATE "{,,%s}0" CXF cxf; EESTATUS eest; HTM hTM; HCXTL hCXTL = 0; PCXTL pCXTL; LPSTR lpRE; LPSTR lpCxt; LPSTR p; char szStr[257]; WORD mask; DWORD cc; ADDR addr; int err = LOGERROR_NOERROR; LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; CmdInsertInit(); PDWildInvalid(); TDWildInvalid(); PreRunInvalid(); LppdCur = LppdCommand; LptdCur = LptdCommand; UpdateDebuggerState(UPDATE_CONTEXT); if (!DebuggeeActive()) { CmdLogVar(ERR_Debuggee_Not_Alive); err = LOGERROR_QUIET; goto done; } p = CPSkipWhitespace( lpsz ); if (_stricmp(p,"*!")==0) { LogListModules("", FALSE); return LOGERROR_NOERROR; } // set up the mask if (!makemask ( &lpsz, &mask )) { err = LOGERROR_UNKNOWN; goto done; } if (!fCaseSensitive) { mask |= HSYMR_nocase; } memset(&cxf, 0, sizeof(cxf)); lpCxt = NULL; p = NULL; lpsz = CPSkipWhitespace( lpsz ); if ( *lpsz == '{' ) { for (p = lpsz; *p && *p != '}'; ) { p = CharNext(p); } if (!*p) { err = LOGERROR_UNKNOWN; goto done; } lpCxt = (PSTR) malloc( (size_t) (p-lpsz + 3) ); Assert(lpCxt); strncpy(lpCxt, lpsz, (size_t) (p-lpsz+1)); strcpy(lpCxt + (p-lpsz+1), "0"); lpsz = CPSkipWhitespace(p+1); } else if ( p = (PSTR) strchr( (PBYTE) lpsz, '!') ) { lpsz = CPSkipWhitespace(lpsz); lpCxt = (PSTR) malloc( (size_t) ((p-lpsz) + strlen(CONTEXT_TEMPLATE)) ); Assert(lpCxt); *p = '\0'; sprintf( lpCxt, CONTEXT_TEMPLATE, lpsz ); *p = '!'; lpsz = CPSkipWhitespace(p+1); } else { addr = CxfIp.cxt.addr; SYFixupAddr(&addr); SHGetModule(&addr,szStr); lpCxt = (PSTR) malloc( strlen(szStr) + strlen(CONTEXT_TEMPLATE) ); sprintf( lpCxt, CONTEXT_TEMPLATE, szStr ); lpsz = CPSkipWhitespace(lpsz); } eest = EEParse(lpCxt, radix, fCaseSensitive, &hTM, &cc); if (!eest) { eest = EEBindTM(&hTM, &CxfIp.cxt, TRUE, FALSE); if (!eest) { eest = EEGetCXTLFromTM(&hTM, &hCXTL); } } free ( lpCxt ); if (!eest) { pCXTL = (PCXTL) MMLpvLockMb (hCXTL); cxf.cxt = pCXTL->rgHCS[0].CXT; MMbUnlockMb (hCXTL); } else if ( hTM ) { // error occured, bail out CVExprErr (eest, CMDWINDOW, &hTM, NULL); EEFreeTM(&hTM); err = LOGERROR_QUIET; goto done; } else { EEFreeTM(&hTM); CmdLogVar(ERR_Bad_Context); goto done; } EEFreeTM(&hTM); lpRE = lpsz; // UNDONE: The tests below don't make sense to me. Why check for either alpha or '_', '@'? BryanT if ( isalpha(*lpRE) || *lpRE == '_' ) { *szStr = '_'; strcpy(szStr+1, lpRE); err = XWorker(szStr, mask, &cxf); } if ( isalpha(*lpRE) || *lpRE == '@' ) { *szStr = '@'; strcpy(szStr+1, lpRE); err = XWorker(szStr, mask, &cxf); } if ( isalpha(*lpRE) || (*lpRE == '.' && *(lpRE + 1) == '.') ) { *szStr = '.'; *(szStr+1) = '.'; strcpy(szStr+2, lpRE); err = XWorker(szStr, mask, &cxf); } if (err == LOGERROR_NOERROR) { err = XWorker(lpRE, mask, &cxf); } done: LppdCur = LppdT; LptdCur = LptdT; UpdateDebuggerState(UPDATE_CONTEXT); return err; } LOGERR LogException( LPSTR lpsz ) /*++ Routine Description: This function will take a string, evalute it as a hex digit and either disable or enable it. If the string is null then we will print out a list of all the known exceptions and whether they are handled or not. Arguments: lpsz - pointer to string holding the hex numbered exception Return Value: NOTENOTE No error code at this point --*/ { LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; LOGERR rVal = LOGERROR_NOERROR; char chCmd; BOOL fException = FALSE; BOOL fName = FALSE; BOOL fCmd = FALSE; BOOL fCmd2 = FALSE; BOOL fInvalid = FALSE; DWORD Exception; LPSTR lpName = NULL; LPSTR lpCmd = NULL; LPSTR lpCmd2 = NULL; EXCEPTION_LIST *eList = NULL; EXCEPTION_DESCRIPTION Exd = {0}; CmdInsertInit(); PDWildInvalid(); TDWildInvalid(); //PreRunInvalid(); LppdCur = LppdCommand; LptdCur = LptdCommand; // Get default exception list if necessary if ( !LppdCur && !DefaultExceptionList ) { if ( !GetDefaultExceptionList() ) { CmdLogVar(ERR_No_ExceptionList); rVal = LOGERROR_QUIET; goto done; } } // Get an Action: // D - Disable // E - Enable // N - Notify // Blank - List chCmd = *lpsz; if ( chCmd != '\0' ) { if ( IsDBCSLeadByte( chCmd ) ) { rVal = LOGERROR_UNKNOWN; goto done; } lpsz++; if ( strchr( (PBYTE) " \t", chCmd ) ) { chCmd = '\0'; } else if ( !strchr( (PBYTE) "dDeEnN", chCmd ) ) { rVal = LOGERROR_UNKNOWN; goto done; } } // handle sx[d|e|n] * lpsz = CPSkipWhitespace(lpsz); if (chCmd && *lpsz == '*') { lpsz = CPSkipWhitespace(lpsz+1); if (*lpsz) { rVal = LOGERROR_UNKNOWN; goto done; } Exd.dwExceptionCode = 0; Exd.exc = exfDefault; if (chCmd == 'd' || chCmd == 'D') { Exd.efd = efdIgnore; } else if (chCmd == 'e' || chCmd == 'E') { Exd.efd = efdStop; } else { Exd.efd = efdNotify; } if (LppdCur) { OSDSetExceptionState(LppdCur->hpid, LptdCur->htid, &Exd); } else { EfdPreset = Exd.efd; } rVal = LOGERROR_NOERROR; goto done; } // Parse line rVal = ParseException( lpsz, radix, &fException, NULL, &fName, &fCmd, &fCmd2, &fInvalid, &Exception, NULL, &lpName, &lpCmd, &lpCmd2 ); if ( rVal != LOGERROR_NOERROR ) { if ( fInvalid ) { CmdLogVar(ERR_Exception_Invalid); } goto done; } if (fException && fInvalid) { rVal = HandleSpecialExceptions( Exception, chCmd, lpName ); if (lpName) { free(lpName); } goto done; } // Validate arguments & Execute the command switch (chCmd) { case '\0': // Plain sx command if ( fName || fCmd || fCmd2 ) { rVal = LOGERROR_UNKNOWN; goto done; } break; case 'd': case 'D': // Can contain: Name if ( !fException ) { rVal = LOGERROR_QUIET; CmdLogVar(ERR_Exception_Invalid); goto done; } else if ( fCmd || fCmd2 ) { rVal = LOGERROR_UNKNOWN; goto done; } Exd.dwExceptionCode = Exception; Exd.exc = exfSpecified; Exd.efd = efdIgnore; if (fName) { strncpy(Exd.rgchDescription, lpName? lpName : "", EXCEPTION_STRING_SIZE); } if (LppdCur) { OSDSetExceptionState(LppdCur->hpid, LptdCur->htid, &Exd); } break; case 'n': case 'N': // Can contain: Name & Cmd2 if ( !fException ) { rVal = LOGERROR_QUIET; CmdLogVar(ERR_Exception_Invalid); goto done; } else if ( fCmd ) { rVal = LOGERROR_UNKNOWN; goto done; } Exd.dwExceptionCode = Exception; Exd.exc = exfSpecified; Exd.efd = efdNotify; if (fName) { strncpy(Exd.rgchDescription, lpName? lpName : "", EXCEPTION_STRING_SIZE); } if (LppdCur) { OSDSetExceptionState(LppdCur->hpid, LptdCur->htid, &Exd); } break; case 'e': case 'E': // Can contain: Name, Cmd & Cmd2 if ( !fException ) { rVal = LOGERROR_QUIET; CmdLogVar(ERR_Exception_Invalid); goto done; } Exd.dwExceptionCode = Exception; Exd.exc = exfSpecified; Exd.efd = efdStop; if (fName) { strncpy(Exd.rgchDescription, lpName? lpName : "", EXCEPTION_STRING_SIZE); } if (LppdCur) { OSDSetExceptionState(LppdCur->hpid, LptdCur->htid, &Exd); } break; } if ( fException ) { // Try to find this exception on the processes exception list for (eList = LppdCur ? LppdCur->exceptionList : DefaultExceptionList; eList; eList = eList->next) { if (eList->dwExceptionCode==Exception) { break; } } } if ( chCmd == '\0' ) { // Execute plain sx command if requested. if ( fException ) { // Display specified exception if ( eList ) { LogSx( eList ); } else { CmdLogVar(ERR_Exception_Unknown, Exception); rVal = LOGERROR_QUIET; goto done; } } else { char szString[MAX_PATH]; int n; if (LppdCur) { Exd.exc = exfDefault; OSDGetExceptionState(LppdCur->hpid, LptdCur->htid, &Exd); n = Exd.efd; } else { n = EfdPreset; } switch (n) { case efdIgnore: n = DBG_Default_Exception_Ignore; break; case efdCommand: case efdStop: n = DBG_Default_Exception_Stop; break; case efdNotify: n = DBG_Default_Exception_Notify; break; } if (n != -1) { Dbg(LoadString(g_hInst, n, (LPSTR)szString, MAX_MSG_TXT)); CmdLogVar(DBG_Default_Exception_Text, szString); } // Display all exceptions for (eList = LppdCur ? LppdCur->exceptionList : DefaultExceptionList; eList; eList = eList->next) { LogSx( eList ); } } } else { // Add exception if not in list if (!eList) { eList=(EXCEPTION_LIST*)malloc(sizeof(EXCEPTION_LIST)); Assert(eList); eList->dwExceptionCode = Exception; eList->lpName = NULL; eList->lpCmd = NULL; eList->lpCmd2 = NULL; eList->efd = efdIgnore; if ( LppdCur ) { InsertException( &LppdCur->exceptionList, eList); if ( LppdCur->ipid == 0 ) { DefaultExceptionList = LppdCur->exceptionList; } } else { InsertException( &DefaultExceptionList, eList); } } // Set appropriate fields eList->efd = Exd.efd; if (fName) { if (eList->lpName) { free(eList->lpName); } eList->lpName = lpName; } if (fCmd) { if (eList->lpCmd) { free(eList->lpCmd); } eList->lpCmd = lpCmd; } if (fCmd2) { if (eList->lpCmd2) { free(eList->lpCmd2); } eList->lpCmd2 = lpCmd2; } } done: LppdCur = LppdT; LptdCur = LptdT; if ( rVal != LOGERROR_NOERROR ) { // Free allocated memory if ( lpName ) { free( lpName ); } if ( lpCmd ) { free( lpCmd ); } if ( lpCmd2 ) { free( lpCmd2 ); } } return rVal; } void LogSx( EXCEPTION_LIST *eList ) /*++ Routine Description: Displays the given exception in the command window Arguments: eList - Supplies exception to display Return Value: none --*/ { char Buffer[512]; FormatException( eList->efd, eList->dwExceptionCode, eList->lpName, eList->lpCmd, eList->lpCmd2, " ", Buffer ); CmdLogFmt("%s\r\n", Buffer ); } LOGERR LogFreeze( LPSTR lpsz, BOOL fFreeze ) /*++ Routine Description: This function is used from the command line to freeze and thaw debuggee threads. We use LptdCommand to determine which thread should be frozen or thawed. Arguments: lpsz - Supplies argument list; should be empty fFreeze - Supplies TRUE if freeze the thread, FALSE if thaw the thread Return Value: log error code --*/ { LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; LOGERR rVal = LOGERROR_NOERROR; CmdInsertInit(); PreRunInvalid(); if (*lpsz != 0) { rVal = LOGERROR_UNKNOWN; } else if (LptdCommand == (LPTD)-1) { if (LppdCur == NULL) { rVal = LOGERROR_UNKNOWN; } else { for (LptdCur = LppdCur->lptdList; LptdCur; LptdCur = LptdCur->lptdNext) { #ifdef OSDEBUG4 if (OSDFreezeThread(LptdCur->lppd->hpid, LptdCur->htid, fFreeze) == xosdNone) #else if (OSDPtrace(fFreeze ? osdFreeze : osdThaw, 0, 0, LptdCur->lppd->hpid, LptdCur->htid) == xosdNone) #endif { LptdCur->fFrozen = fFreeze; } else { CmdLogVar((WORD)(fFreeze? ERR_Cant_Freeze : ERR_Cant_Thaw)); rVal = LOGERROR_QUIET; break; } } } } else { LppdCur = LppdCommand; LptdCur = LptdCommand; if (LptdCur == NULL) { rVal = LOGERROR_UNKNOWN; } else if (LptdCur == (LPTD) -1) { Assert(FALSE); } else if (fFreeze && LptdCur->fFrozen) { CmdLogVar(ERR_Thread_Is_Frozen); rVal = LOGERROR_QUIET; } else if (!fFreeze && !LptdCur->fFrozen) { CmdLogVar(ERR_Thread_Not_Frozen); rVal = LOGERROR_QUIET; } #ifdef OSDEBUG4 else if (OSDFreezeThread(LptdCur->lppd->hpid, LptdCur->htid, fFreeze) == xosdNone) #else else if (OSDPtrace(fFreeze ? osdFreeze : osdThaw, 0, 0, LptdCur->lppd->hpid, LptdCur->htid) == xosdNone) #endif { LptdCur->fFrozen = fFreeze; } else { CmdLogVar((WORD)(fFreeze? ERR_Cant_Freeze : ERR_Cant_Thaw)); rVal = LOGERROR_QUIET; } } LppdCur = LppdT; LptdCur = LptdT; return rVal; } /* LogFreeze() */ LOGERR LogGoException( LPSTR lpsz, BOOL fHandled ) /*++ Routine Description: GH and GN commands. Continue handled or unhandled from exception. Arguments: lpsz - Supplies pointer to tail of command fHandled - Supplies flag indicating whether exception should be handled or not. Return Value: LOGERROR code --*/ { XOSD xosd; LOGERR rVal = LOGERROR_NOERROR; LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; CmdInsertInit(); if (g_contWorkspace_WkSp.m_bKernelDebugger && g_contKernelDbgPreferences_WkSp.m_bUseCrashDump) { CmdLogFmt( "Go is not allowed for crash dumps\n" ); return rVal; } TDWildInvalid(); PDWildInvalid(); LppdCur = LppdCommand; LptdCur = LptdCommand; if (*CPSkipWhitespace(lpsz) != '\0') { rVal = LOGERROR_UNKNOWN; } if (LptdCur == NULL) { CmdLogVar(ERR_Debuggee_Not_Alive); rVal = LOGERROR_QUIET; } else if (LptdCur->tstate != tsException1 && LptdCur->tstate != tsException2) { CmdLogVar(ERR_Not_At_Exception); rVal = LOGERROR_QUIET; } else { EXOP exop = {0}; exop.fSingleThread = TRUE; exop.fInitialBP = TRUE; exop.fPassException = !fHandled; xosd = OSDGo(LppdCur->hpid, LptdCur->htid, &exop); if (xosd == xosdNone) { SetPTState(psRunning, tsRunning); } else { CmdLogVar(ERR_Cant_Cont_Exception); rVal = LOGERROR_QUIET; } } LppdCur = LppdT; LptdCur = LptdT; return rVal; } LOGERR LogGoUntil( LPSTR lpsz ) /*++ Routine Description: This routine will parse out an address, set a temp breakpoint at the address and issue a go command Syntax: g [=startaddr] [address] Arguments: lpsz - address to put the temporary breakpoint at Return Value: LOGERR code --*/ { ADDR addr; HBPT hbpt = NULL; CXF cxf = CxfIp; LPPD LppdT = NULL; LPTD LptdT = NULL; LOGERR rVal = LOGERROR_NOERROR; CmdInsertInit(); if (g_contWorkspace_WkSp.m_bKernelDebugger && g_contKernelDbgPreferences_WkSp.m_bUseCrashDump) { CmdLogFmt( "Go is not allowed for crash dumps\n" ); return rVal; } PDWildInvalid(); /* * If debugger is initializing, bail out. */ PreRunInvalid(); /* * Different process, implies any thread: */ if (FSetLppd && !FSetLptd) { /* * change process and make thread wildcard */ FSetLppd = FALSE; LppdT = LppdCur; LppdCur = LppdCommand; LptdT = LptdCur; LptdCur = LppdCur->lptdList; UpdateDebuggerState(UPDATE_CONTEXT); LptdCommand = (LPTD)-1; FSetLptd = TRUE; rVal = LogGoUntil(lpsz); LppdCur = LppdT; LptdCur = LptdT; UpdateDebuggerState(UPDATE_CONTEXT); return rVal; } /* * Any process, any thread: */ if (LptdCommand == (LPTD)-1) { BOOL fDidSomething = FALSE; FSetLptd = TRUE; // this should already be true, in fact. for (LptdCommand = LppdCur->lptdList; LptdCommand; LptdCommand = LptdCommand->lptdNext) { if (GoOK(LppdCur, LptdCommand)) { fDidSomething = TRUE; if ((rVal = LogGoUntil(lpsz)) != LOGERROR_NOERROR) { return rVal; } } } if (!fDidSomething) { CmdLogVar(ERR_Process_Cant_Go); rVal = LOGERROR_QUIET; } return rVal; } /* * switch debugger context to requested proc/thread */ if (FSetLppd || FSetLptd) { LppdT = LppdCur; LppdCur = LppdCommand; LptdT = LptdCur; LptdCur = LptdCommand; UpdateDebuggerState(UPDATE_CONTEXT); cxf = CxfIp; } if (DebuggeeActive()) { if (!GoOK(LppdCur, LptdCur)) { NoRunExcuse(LppdCur, LptdCur); rVal = LOGERROR_QUIET; goto done; } } else if (DebuggeeAlive()) { NoRunExcuse(GetLppdHead(), NULL); rVal = LOGERROR_QUIET; goto done; } /* ** If this is a no argument go command then just do the go and be done ** with the whole mess. */ if (*lpsz == 0) { if (LptdCur && LptdCur->fFrozen) { CmdLogVar(DBG_Go_When_Frozen); } if (ExecDebuggee(EXEC_GO)) { rVal = LOGERROR_NOERROR; goto done; } else { CmdLogVar(ERR_Go_Failed); rVal = LOGERROR_QUIET; goto done; } } if (LptdCur && LptdCur->fFrozen) { CmdLogVar(ERR_Simple_Go_Frozen); return LOGERROR_QUIET; } /* ** If the debuggee is not loaded then we need to get it loaded so that ** we have symbols that can be evaluated */ if (!DebuggeeAlive()) { if (!ExecDebuggee(EXEC_RESTART)) { CmdLogVar(ERR_Cant_Start_Proc); return LOGERROR_QUIET; } LppdCommand = LppdCur; LptdCommand = LppdCur->lptdList; } /* ** Can this happen? */ if (LppdCur->pstate == psExited) { return LOGERROR_UNKNOWN; } /* ** Check for a starting address optional argument. If no arguments ** are left then issue a go command after changing the current ** instruction pointer. */ if (*lpsz == '=') { CmdLogFmt(" NYI: starting address\r\n"); return LOGERROR_QUIET; } /* ** Now get the termination address, note that we need to replace any ** leading periods ('.') with '@'s as these must really be line numbers */ lpsz = CPSkipWhitespace(lpsz); if (BPParse(&hbpt, lpsz, NULL, NULL, LppdCur ? LppdCur->hpid: 0) != BPNOERROR) { Assert( hbpt == NULL ); CmdLogVar(ERR_AddrExpr_Invalid); rVal = LOGERROR_QUIET; } else if (BPBindHbpt( hbpt, &cxf ) == BPNOERROR) { /* ** go the go until */ Dbg( BPAddrFromHbpt( hbpt, &addr ) == BPNOERROR) ; Dbg( BPFreeHbpt( hbpt ) == BPNOERROR) ; GoUntil(&addr); } else if (!LppdCur->fHasRun) { /* * haven't executed entrypoint: save it for later */ LppdCur->hbptSaved = (HANDLE)hbpt; Go(); } else { /* * bind failed */ Dbg( BPFreeHbpt( hbpt ) == BPNOERROR ); CmdLogVar(ERR_AddrExpr_Invalid); rVal = LOGERROR_QUIET; } done: if (FSetLppd || FSetLptd) { LppdCur = LppdT; LptdCur = LptdT; UpdateDebuggerState(UPDATE_CONTEXT); } return rVal; } /* LogGoUntil() */ int WINAPIV CompareModEntryBySelector( const void *pMod1, const void *pMod2 ) { LPMODULE_ENTRY Mod1 = (LPMODULE_ENTRY)pMod1; LPMODULE_ENTRY Mod2 = (LPMODULE_ENTRY)pMod2; if ( ModuleEntrySelector(Mod1) < ModuleEntrySelector(Mod2) ) { return -1; } else if ( ModuleEntrySelector(Mod1) > ModuleEntrySelector(Mod2) ) { return 1; } else { return 0; } } int WINAPIV CompareModEntryByAddress( const void *pMod1, const void *pMod2 ) { return ModuleEntryBase((LPMODULE_ENTRY)pMod1) < ModuleEntryBase((LPMODULE_ENTRY)pMod2) ? -1 : 1; } BOOL FormatHSym( HSYM hsym, PCXT cxt, char *szStr ) { DWORD retval; HTM htm; DWORD strIndex; EEHSTR eehstr; DWORD cb; BOOL Ok = FALSE; EERADIX uradix = radix; retval = EEGetTMFromHSYM ( hsym, cxt, &htm, &strIndex, TRUE, FALSE ); if ( retval == EENOERROR ) { retval = EEGetExprFromTM( &htm, &uradix, &eehstr, &cb); if ( retval == EENOERROR ) { strcpy(szStr, (PSTR) MMLpvLockMb( eehstr )); MMbUnlockMb( eehstr ); EEFreeStr( eehstr ); Ok = TRUE; } EEFreeTM( &htm ); } if ( !Ok ) { Ok = PtrToInt(SHGetSymName(hsym, szStr)); } return Ok; } LOGERR LogListNear( LPSTR lpsz ) /*++ Routine Description: ln "list near" command: ln Arguments: lpsz - Supplies pointer to command tail Return Value: LOGERROR code --*/ { ADDR addr; ADDR addr1; HSYM hsymP; HSYM hsymN; DWORDLONG dwOff; DWORDLONG dwOffP; DWORDLONG dwOffN; HDEP hsyml; PHSL_HEAD lphsymhead; PHSL_LIST lphsyml; LPMODULE_LIST lpModList; LPMODULE_ENTRY lpModEntry; int cch; char szStr[MAX_USER_LINE]; char szContext[MAX_USER_LINE]; LPSTR lpContext; CXT cxt; HDEP hstr; UINT n; EESTATUS eest; XOSD xosd; LOGERR rVal = LOGERROR_NOERROR; LPPD LppdT = LppdCur; LPTD LptdT = LptdCur; CmdInsertInit(); IsKdCmdAllowed(); TDWildInvalid(); PDWildInvalid(); PreRunInvalid(); LppdCur = LppdCommand; LptdCur = LptdCommand; if (LptdCur != LptdT || LppdCur != LppdT) { UpdateDebuggerState(UPDATE_CONTEXT); } if (!DebuggeeActive()) { CmdLogVar(ERR_Debuggee_Not_Alive); rVal = LOGERROR_QUIET; goto done; } /* ** get address */ lpsz = CPSkipWhitespace(lpsz); if (*lpsz == 0) { lpsz = "."; } if (CPGetAddress(lpsz, &cch, &addr, radix, &CxfIp, fCaseSensitive, g_contWorkspace_WkSp.m_bMasmEval) == CPNOERROR) { if (*CPSkipWhitespace(lpsz + cch) != 0) { rVal = LOGERROR_UNKNOWN; goto done; } } else { CmdLogVar(ERR_AddrExpr_Invalid); rVal = LOGERROR_QUIET; goto done; } if ((HPID)emiAddr( addr ) == LppdCur->hpid && ADDR_IS_LI(addr)) { emiAddr( addr ) = 0; ADDR_IS_LI( addr ) = FALSE; #ifdef OSDEBUG4 OSDSetEmi(LppdCur->hpid,LptdCur->htid,&addr); #else OSDPtrace(osdSetEmi, wNull, &addr, LppdCur->hpid, LptdCur->htid); #endif if ( (HPID)emiAddr( addr ) != LppdCur->hpid ) { SHWantSymbols( (HEXE)emiAddr( addr ) ); } SYUnFixupAddr(&addr); } memset(&cxt, 0, sizeof(cxt)); SHSetCxt(&addr, &cxt); // the following hack works around a shortcoming of CV info. // We only have module maps for code contributor segments, so // we can't get a useful CXT for a data address. A little // brute force abuse will generate a usable HMOD: // (this is going to be harder if the address is segmented... // I didn't try to solve that one.) if ( SHHMODFrompCXT( &cxt ) == NULL ) { addr1 = addr; SYFixupAddr(&addr1); // get module table xosd = OSDGetModuleList( LppdCur->hpid, LptdCur->htid, NULL, &lpModList ); if (xosd == xosdNone && ModuleListCount(lpModList) > 0 ) { qsort( FirstModuleEntry(lpModList), ModuleListCount(lpModList), sizeof(MODULE_ENTRY), CompareModEntryByAddress ); // find nearest exe lpModEntry = FirstModuleEntry(lpModList); for ( n = 0; n < ModuleListCount( lpModList ) - 1; n++) { if (GetAddrOff(addr1) < ModuleEntryBase(NextModuleEntry(lpModEntry)) ) { break; } lpModEntry = NextModuleEntry(lpModEntry); } SHHMODFrompCXT( &cxt ) = SHGetNextMod((HEXE)ModuleEntryEmi(lpModEntry), NULL); } } hsyml = 0; eest = EEGetHSYMList(&hsyml, &cxt, HSYMR_module | HSYMR_global | HSYMR_public, NULL, TRUE); if (eest != EENOERROR) { rVal = LOGERROR_CP; goto done; } lphsymhead = (PHSL_HEAD) MMLpvLockMb ( hsyml ); lphsyml = (PHSL_LIST)(lphsymhead + 1); dwOffP = (DWORDLONG)(LONGLONG)-1; dwOffN = (DWORDLONG)(LONGLONG)-1; hsymP = 0; hsymN = 0; SYFixupAddr(&addr); addr1 = addr; for ( n = 0; n < (UINT)lphsyml->symbolcnt; n++ ) { if (SHAddrFromHsym(&addr1, lphsyml->hSym[n])) { SYFixupAddr(&addr1); if (!ADDR_IS_FLAT(addr1) && !ADDR_IS_FLAT(addr) && GetAddrSeg(addr1) != GetAddrSeg(addr)) { continue; } if (GetAddrOff(addr1) <= GetAddrOff(addr)) { dwOff = GetAddrOff(addr) - GetAddrOff(addr1); if (dwOff < dwOffP) { dwOffP = dwOff; hsymP = lphsyml->hSym[n]; } } else { dwOff = GetAddrOff(addr1) - GetAddrOff(addr); if (dwOff < dwOffN) { dwOffN = dwOff; hsymN = lphsyml->hSym[n]; } } } } MMbUnlockMb(hsyml); if (!hsymP && !hsymN) { CmdLogVar(DBG_Symbol_Not_Found); } else { EEFormatCXTFromPCXT( &cxt, &hstr, g_contWorkspace_WkSp.m_bShortContext ); lpContext = (PSTR) MMLpvLockMb( hstr ); if (g_contWorkspace_WkSp.m_bShortContext) { strcpy( szContext, lpContext ); } else { BPShortenContext( lpContext, szContext); } MMbUnlockMb(hstr); EEFreeStr(hstr); if ( hsymP && FormatHSym(hsymP, &cxt, szStr) ) { CmdLogFmt("%s%s+%#0x\r\n", szContext, szStr, dwOffP); } if ( hsymN && FormatHSym(hsymN, &cxt, szStr) ) { CmdLogFmt("%s%s-%#0x\r\n", szContext, szStr, dwOffN); } } MMFreeHmem(hsyml); done: if (LptdCur != LptdT || LppdCur != LppdT) { LppdCur = LppdT; LptdCur = LptdT; UpdateDebuggerState(UPDATE_CONTEXT); } return rVal; } /* LogListNear() */ LOGERR ListModules( LOGERR *prVal, BOOL Flat, BOOL SelSort, LPSTR ModName, BOOL fExtendedLoadInfo ) /*++ Routine Description: Lists modules Arguments: rVal - Pointer to LOGERR Flat - Flat flag SelSort - Sort by selector flag ModName - Module name to look for (optional) fExtendedInfo - TRUE - Display extended load errors FALSE - Don't display extended load errors Return Value: TRUE if modules listed. --*/ { XOSD xosd; LPMODULE_LIST ModList; LPMODULE_ENTRY ModEntry; DWORD Mod; LPSTR LastName; BOOL Ok = FALSE; LOGERR rVal = LOGERROR_NOERROR; LPSTR lpch; LPSTR lpModName; LPSTR lpSymName; CHAR buf[100]; SHE sheLoadStatus; SHE sheLoadError; BOOL fDoTitle = TRUE; // Get module list if ( !LppdCur || !LptdCur ) { rVal = LOGERROR_UNKNOWN; } else { xosd = OSDGetModuleList( LppdCur->hpid, LptdCur->htid, ModName, &ModList ); if ( xosd != xosdNone ) { // Could not get module list! rVal = LOGERROR_UNKNOWN; } else { if ( !ModName ) { if ( Flat ) { CmdLogFmt("\r\n" ); CmdLogFmt("Flat Modules:\r\n" ); } else { CmdLogFmt("\r\n" ); CmdLogFmt("Segmented Modules:\r\n" ); } } if ( ModuleListCount(ModList) > 0 ) { Ok = TRUE; // Sort Module list if ( SelSort ) { // Sort by selector qsort( FirstModuleEntry(ModList), ModuleListCount(ModList), sizeof(MODULE_ENTRY), CompareModEntryBySelector ); } else { // Sort by Base address qsort( FirstModuleEntry(ModList), ModuleListCount(ModList), sizeof(MODULE_ENTRY), CompareModEntryByAddress ); } //CmdLogFmt("\r\n" ); ModEntry = FirstModuleEntry(ModList); LastName = NULL; for ( Mod = 0, ModEntry = FirstModuleEntry(ModList); Mod < ModuleListCount( ModList ); Mod++, ModEntry = NextModuleEntry(ModEntry) ) { if ((!!Flat) != (!!ModuleEntryFlat(ModEntry))) { continue; } if (fDoTitle) { if ( Flat ) { CmdLogFmt(" Base Limit Name "); // Display extended load errors? if (fExtendedLoadInfo) { CmdLogFmt("Load Status Advanced Status Message" ); } CmdLogFmt("\r\n"); CmdLogFmt(" ---------------- ---------------- ------------ "); // Display extended load errors? if (fExtendedLoadInfo) { CmdLogFmt("-------- ----------"); } CmdLogFmt("\r\n"); } else { CmdLogFmt(" Sel Base Limit Seg Name\r\n" ); CmdLogFmt(" ---- ---------------- ---------------- ---- ------------\r\n"); } fDoTitle = FALSE; } lpSymName = SHGetSymFName( (HEXE)ModuleEntryEmi(ModEntry) ); lpModName = SHGetModNameFromHexe( (HEXE)ModuleEntryEmi(ModEntry) ); if ( ModuleEntryFlat(ModEntry) ) { CmdLogFmt( " %016I64X - %016I64X %-12s ", ModuleEntryBase(ModEntry), ModuleEntryBase(ModEntry) + ModuleEntryLimit(ModEntry), lpModName ); // Get the load status SHSymbolsLoaded((HEXE) ModuleEntryEmi(ModEntry), &sheLoadStatus); // Does the user want extended symbol load info? if (fExtendedLoadInfo) { // Get extended error text lpch = SHLszGetErrorText(sheLoadStatus); if (!lpch) { lpch = ""; } sprintf( buf, "(%s)", lpch ); CmdLogFmt( "%-28s ", buf ); // If the symbols have been loaded, report any INTERESTING load errors if (sheDeferSyms == sheLoadStatus || sheSuppressSyms == sheLoadStatus) { lpch = ""; } else { SHSymbolsLoadError((HEXE) ModuleEntryEmi(ModEntry), &sheLoadError); if (sheNone == sheLoadError || sheNoSymbols == sheLoadError) { lpch = ""; } else { lpch = SHLszGetErrorText(sheLoadError); } } // Prevent us from simply printing () *buf = 0; if (lpch && *lpch) { sprintf( buf, "(%s)", lpch ); } CmdLogFmt( "%-30s ", buf ); } // Print the sym/module name CmdLogFmt( "%s", lpSymName ); CmdLogFmt("\r\n"); } else { if ( !SelSort && LastName && _stricmp( LastName, lpModName )) { CmdLogFmt("\r\n" ); } LastName = lpModName; if ( ModuleEntryReal(ModEntry ) ) { CmdLogFmt(" %04x (Real mode) %04x ", ModuleEntrySelector(ModEntry), ModuleEntrySegment(ModEntry) ); } else { CmdLogFmt(" %04x %016I64x %016I64X %04x ", ModuleEntrySelector(ModEntry), ModuleEntryBase(ModEntry), ModuleEntryLimit(ModEntry), ModuleEntrySegment(ModEntry) ); } CmdLogFmt( "\t%s", lpModName ); CmdLogFmt( "\t%s", lpSymName ); CmdLogFmt("\r\n"); } } } // Deallocate module list MHFree( ModList ); } } *prVal = rVal; return Ok; } LOGERR LogListModules( LPSTR lpsz, BOOL fExtendedLoadInfo ) /*++ Routine Description: lm "list modules" command Arguments: lpsz - Supplies pointer to command tail fExtendedInfo - TRUE - Display extended load errors FALSE - Don't display extended load errors Return Value: LOGERROR code --*/ { char ModNameBuffer[ MAX_PATH ]; char *ModName; LOGERR rVal = LOGERROR_NOERROR; BOOL Flat = FALSE; BOOL Sgm = FALSE; BOOL SelSort = FALSE; BOOL Ok; CmdInsertInit(); IsKdCmdAllowed(); if ( !DebuggeeActive() ) { // No debuggee - nothing to do. CmdLogVar(ERR_Debuggee_Not_Alive); rVal = LOGERROR_QUIET; } else { // Parse arguments *ModNameBuffer = '\0'; if ( lpsz && *lpsz ) { lpsz = CPSkipWhitespace(lpsz); while ( rVal == LOGERROR_NOERROR && lpsz && *lpsz ) { switch (*lpsz) { case '/': lpsz++; switch( *lpsz ) { case 'f': case 'F': if ( !Flat ) { Flat = TRUE; lpsz++; } break; case 's': case 'S': if ( !Sgm ) { Sgm = TRUE; lpsz++; } break; case 'o': case 'O': if ( !SelSort ) { SelSort = TRUE; lpsz++; } break; default: break; } if ( *lpsz && *lpsz != ' ' && *lpsz != '\t' ) { rVal = LOGERROR_UNKNOWN; } break; default: if ( *ModNameBuffer ) { rVal = LOGERROR_UNKNOWN; } else { char *p = ModNameBuffer; while ( *lpsz && *lpsz != ' ' && *lpsz != '\t' ) { if (IsDBCSLeadByte(*lpsz)) { *p++ = *lpsz++; } *p++ = *lpsz++; } *p++ = '\0'; } break; } lpsz = CPSkipWhitespace(lpsz); } } if ( rVal == LOGERROR_NOERROR ) { // Validate switches if ( !Flat && !Sgm ) { // If command did not specify Flat or Sgm, we set // both by default. Flat = Sgm = TRUE; } // SelSort is valid only if listing segmented modules if ( SelSort && !Sgm ) { rVal = LOGERROR_UNKNOWN; } } if ( rVal == LOGERROR_NOERROR ) { // Now do the listing Ok = FALSE; ModName = *ModNameBuffer ? ModNameBuffer : NULL; // List Segmented modules if ( Sgm ) { Ok = ListModules(&rVal, FALSE, SelSort, ModName, fExtendedLoadInfo ); if ( !ModName && !Ok ) { CmdLogVar(ERR_NoModulesFound); } } // List flat modules, unless we are looking for a specific // module and we already found it. if ( rVal == LOGERROR_NOERROR && Flat && !( Ok && ModName ) ) { Ok = ListModules( &rVal, TRUE, FALSE, ModName, fExtendedLoadInfo ); if ( !ModName && !Ok ) { CmdLogVar(ERR_NoModulesFound); } } if ( rVal == LOGERROR_NOERROR ) { if ( ModName && !Ok ) { CmdLogVar(ERR_ModuleNotFound, ModName); } } } } return rVal; } LOGERR LogProcess( void ) /*++ Routine Description: Enumerate processes Arguments: None Return Value: LOGERR code --*/ { LPPD lppd; PST pst; WCHAR Ustr[MAX_PATH]; PWCHAR p; DWORD cb; ADDR addr; XOSD xosd; CmdInsertInit(); if (!DebuggeeActive()) { CmdLogVar(ERR_Debuggee_Not_Alive); return LOGERROR_NOERROR; } lppd = GetLppdHead(); Assert(lppd != NULL); for ( ;lppd != NULL; lppd = lppd->lppdNext) { if (lppd->pstate == psDestroyed) { continue; } if (OSDGetProcessStatus(lppd->hpid, &pst) != xosdNone) { CmdLogFmt("No status for process %d\r\n", lppd->ipid); } else { *Ustr = 0; p = Ustr; if (lppd->ProcessParameters.ImagePathName.Length > 0 && lppd->ProcessParameters.ImagePathName.Buffer != 0) { AddrInit(&addr, 0, 0, lppd->ProcessParameters.ImagePathName.Buffer, TRUE, TRUE, FALSE, FALSE); xosd = OSDReadMemory( lppd->hpid, NULL, &addr, Ustr, lppd->ProcessParameters.ImagePathName.Length, &cb); if (xosd == xosdNone && cb > 0) { Ustr[lppd->ProcessParameters.ImagePathName.Length] = 0; p = &Ustr[lppd->ProcessParameters.ImagePathName.Length] - 1; while (p > Ustr) { if (*p == '\\') { ++p; break; } else { --p; } } } } CmdLogFmt("%c%2d %s %s %ls\r\n", lppd == LppdCur? '*' : ' ', lppd->ipid, pst.rgchProcessID, pst.rgchProcessState, p); } } return LOGERROR_NOERROR; } /* LogProcess() */ LOGERR LogRestart( LPSTR lpsz ) /*++ Routine Description: This routine will restart the debuggee. If needed it will change the command line as well. If there is no command line present then the command line is not changed. Arguments: lpsz - Supplies new command line to be used Return Value: log error code --*/ { lpsz = CPSkipWhitespace(lpsz); CmdInsertInit(); // Restarting is not allowed on dumps if (g_contKernelDbgPreferences_WkSp.m_bUseCrashDump || g_contWorkspace_WkSp.m_bUserCrashDump) { CmdLogFmt("Neither kernel nor user memory dumps can be restarted\r\n"); return LOGERROR_QUIET; } if ( LppdCur && IsProcRunning( LppdCur ) ) { CmdLogVar(ERR_Stop_B4_Restart); return LOGERROR_QUIET; } if (g_contWorkspace_WkSp.m_bKernelDebugger && DebuggeeActive()) { CmdLogFmt("Target system already running\r\n"); return LOGERROR_QUIET; } if (*lpsz) { if (LpszCommandLine) { free(LpszCommandLine); } LpszCommandLine = _strdup(lpsz); } if (!ExecDebuggee(EXEC_RESTART)) { return LOGERROR_UNKNOWN; } return LOGERROR_NOERROR; } /* LogRestart() */ LOGERR LogStep( LPSTR lpsz, BOOL fStep ) /*++ Routine Description: This function is used from the command line to do either a step or a trace. If an argument is present it is assumed to be a count for a number of steps to make Arguments: lpsz - Supplies argument list for step/trace count fStep - Supplies TRUE to step or FALSE to trace Return Value: log error code --*/ { int cStep; int err; int cch; CXF cxf = CxfIp; LPPD LppdT; LPTD LptdT; static BOOL fRegisters = FALSE; LOGERR rVal = LOGERROR_NOERROR; CmdInsertInit(); if (g_contWorkspace_WkSp.m_bKernelDebugger && g_contKernelDbgPreferences_WkSp.m_bUseCrashDump) { CmdLogFmt( "Steps are not allowed for crash dumps\n" ); return rVal; } // NOTENOTE a-kentf thread wildcard is supposed to be valid here (LogStep) TDWildInvalid(); PDWildInvalid(); PreRunInvalid(); /* * Check for no argument -- then just do a single step or trace */ if (*lpsz == 'r') { fRegisters = !fRegisters; lpsz++; } lpsz = CPSkipWhitespace(lpsz); cStep = 1; if (*lpsz != 0) { cStep = (int) CPGetInt(lpsz, &err, &cch); if (err || cStep < 1) { CmdLogVar(ERR_Bad_Count); return LOGERROR_QUIET; } } /* ** If the debuggee is not loaded then we need to get it loaded so that ** we have symbols that can be evaluated */ if (!DebuggeeAlive()) { if (!ExecDebuggee(EXEC_RESTART)) { CmdLogVar(ERR_Cant_Start_Proc); return LOGERROR_QUIET; } LppdCommand = LppdCur; LptdCommand = LppdCur->lptdList; } /* * make sure thread is now runnable */ if (!StepOK(LppdCommand, LptdCommand)) { NoRunExcuse(LppdCommand, LptdCommand); return LOGERROR_QUIET; } LppdT = LppdCur; LptdT = LptdCur; if (LptdCur != LptdCommand) { LppdCur = LppdCommand; LptdCur = LptdCommand; UpdateDebuggerState(UPDATE_CONTEXT); } if (ExecDebuggee( fStep ? EXEC_STEPOVER : EXEC_TRACEINTO ) == 0) { if (LptdCur) { LptdCur->cStepsLeft = 0; } rVal = LOGERROR_UNKNOWN; } else { Assert(LptdCur); LptdCur->cStepsLeft = cStep - 1; LptdCur->flags &= ~tfStepOver; LptdCur->flags |= (fStep ? tfStepOver : 0); LptdCur->fRegisters = fRegisters; LptdCur->fDisasm = fRegisters; rVal = LOGERROR_NOERROR; } if (LptdT != LptdCur) { LppdCur = LppdT; LptdCur = LptdT; UpdateDebuggerState(UPDATE_CONTEXT); } return rVal; } /* LogStep() */ LOGERR LogThread( void ) /*++ Routine Description: Enumerate threads Arguments: None Return Value: log error code --*/ { LPPD lppd; CmdInsertInit(); if (!DebuggeeActive()) { CmdLogVar(ERR_Debuggee_Not_Alive); return LOGERROR_QUIET; } if (LppdCommand == NULL) { CmdLogVar(ERR_No_Threads); } else if (LppdCommand != (LPPD)-1) { ThreadStatForProcess(LppdCommand); } else { for (lppd = GetLppdHead(); lppd; lppd = lppd->lppdNext) { if (lppd->pstate == psDestroyed) { continue; } CmdLogFmt("\r\nProcess %d:\r\n", lppd->ipid); ThreadStatForProcess(lppd); } } return LOGERROR_NOERROR; } /* LogThread() */ LOGERR LogLoadDefered( LPSTR lpsz ) /*++ Routine Description: Loads defered symbols for a module Arguments: lpsz - Supplies new command line to be used Return Value: log error code --*/ { LOGERR LogErr = LOGERROR_QUIET; HEXE hexe; SHE she; CmdInsertInit(); if (!DebuggeeActive()) { CmdLogVar(ERR_Debuggee_Not_Alive); return LOGERROR_QUIET; } lpsz = CPSkipWhitespace(lpsz); if ( *lpsz == 0 ) { CmdLogFmt( "Load: Must specify module name\r\n" ); } else { hexe = SHGethExeFromName( lpsz ); if ( hexe ) { SHSymbolsLoaded(hexe, &she); if (she == sheDeferSyms ) { SHWantSymbols( hexe ); } } else { CmdLogFmt( "Load: Could not load %s\r\n", lpsz ); } } return LogErr; } LOGERR LogWatchTime( LPSTR lpsz ) /*++ Routine Description: The WT command generates a call tree for all of the code run under a call site. Arguments: lpsz - Supplies command tail Return Value: log error code --*/ { LOGERR LogErr = LOGERROR_QUIET; int cch; ADDR addr; ADDR addr1; CXT cxt; HDEP hsyml; PHSL_HEAD lphsymhead; PHSL_LIST lphsyml; UINT n; DWORDLONG dwOff; DWORDLONG dwOffP; DWORDLONG dwOffN; DWORDLONG dwAddrP; DWORDLONG dwAddrN; HSYM hsymP; HSYM hsymN; HDEP hstr; EESTATUS eest; char szContext[MAX_USER_LINE]; char szStr[MAX_USER_LINE]; PIOCTLGENERIC pig; LPBYTE lpb; DWORD dw; CmdInsertInit(); lpsz = CPSkipWhitespace(lpsz); if (_stricmp(lpsz,"stop")==0) { pig = (PIOCTLGENERIC) malloc( sizeof(IOCTLGENERIC) ); if (!pig) { CmdLogFmt("Could not allocate memory for wt command\r\n"); return LOGERROR_QUIET; } pig->ioctlSubType = IG_WATCH_TIME_STOP; pig->length = 0; OSDSystemService( LppdCur->hpid, LptdCur->htid, (SSVC) ssvcGeneric, (LPV)pig, sizeof(IOCTLGENERIC), &dw ); free( pig ); return LogErr; } // first lets do an effective loglistnear command if (CPGetAddress(".", &cch, &addr, 16, &CxfIp, FALSE, g_contWorkspace_WkSp.m_bMasmEval) != CPNOERROR) { CmdLogFmt("Could not find a symbol for current location\r\n"); return LOGERROR_QUIET; } ZeroMemory(&cxt, sizeof(cxt)); SHSetCxt(&addr, &cxt); hsyml = 0; eest = EEGetHSYMList(&hsyml, &cxt, HSYMR_public, NULL, TRUE); if (eest != EENOERROR) { CmdLogFmt("Could not find a symbol for current location\r\n"); return LOGERROR_QUIET; } lphsymhead = (PHSL_HEAD) MMLpvLockMb ( hsyml ); lphsyml = (PHSL_LIST)(lphsymhead + 1); dwOffP = (DWORDLONG)(LONGLONG)-1; dwOffN = (DWORDLONG)(LONGLONG)-1; dwAddrP = (DWORDLONG)(LONGLONG)-1; dwAddrN = (DWORDLONG)(LONGLONG)-1; hsymP = 0; hsymN = 0; SYFixupAddr(&addr); addr1 = addr; for ( n = 0; n < (UINT)lphsyml->symbolcnt; n++ ) { if (SHAddrFromHsym(&addr1, lphsyml->hSym[n])) { SYFixupAddr(&addr1); if (GetAddrSeg(addr1) != GetAddrSeg(addr)) { continue; } if (GetAddrOff(addr1) <= GetAddrOff(addr)) { dwOff = GetAddrOff(addr) - GetAddrOff(addr1); if (dwOff < dwOffP) { dwOffP = dwOff; dwAddrP = GetAddrOff(addr1); hsymP = lphsyml->hSym[n]; } } else { dwOff = GetAddrOff(addr1) - GetAddrOff(addr); if (dwOff < dwOffN) { dwOffN = dwOff; dwAddrN = GetAddrOff(addr1); hsymN = lphsyml->hSym[n]; } } } } MMbUnlockMb(hsyml); MMFreeHmem(hsyml); if (!hsymP || !hsymN) { CmdLogFmt("Could not find a symbol for current location\r\n"); return LOGERROR_QUIET; } EEFormatCXTFromPCXT( &cxt, &hstr, g_contWorkspace_WkSp.m_bShortContext ); if (g_contWorkspace_WkSp.m_bShortContext) { strcpy( szContext, (LPSTR)MMLpvLockMb(hstr) ); } else { BPShortenContext( (LPSTR)MMLpvLockMb(hstr), szContext ); } MMbUnlockMb(hstr); EEFreeStr(hstr); FormatHSym(hsymP, &cxt, szStr); strcat(szContext,szStr); // now notify the dm that the wt command should start now n = (2 * sizeof(DWORDLONG)) + strlen(szContext) + 1; pig = (PIOCTLGENERIC) malloc( n + sizeof(IOCTLGENERIC) ); if (!pig) { CmdLogFmt("Could not allocate memory for wt command\r\n"); return LOGERROR_QUIET; } pig->ioctlSubType = IG_WATCH_TIME; pig->length = n; lpb = (LPBYTE) pig->data; *(PDWORDLONG)lpb = dwAddrP; lpb += sizeof(DWORD); *(PDWORDLONG)lpb = dwAddrN - 1; lpb += sizeof(DWORD); strcpy( (PSTR) lpb, szContext); OSDSystemService( LppdCur->hpid, LptdCur->htid, (SSVC) ssvcGeneric, (LPV)pig, n + sizeof(IOCTLGENERIC), &dw ); free( pig ); return LogErr; } LOGERR LogUnload( LPSTR lpsz, DWORD dw ) { HEXE emi; HPDS HpdsOld; CmdInsertInit(); if (LppdCur == NULL) { CmdLogVar(ERR_Debuggee_Not_Alive); return LOGERROR_QUIET; } // Skip over any leading blanks lpsz = CPSkipWhitespace(lpsz); if (!*lpsz) { CmdLogFmt("Unload: Must specify a module name\r\n"); return LOGERROR_QUIET; } // Get the symbol handle for the desired module emi = SHGethExeFromName(lpsz); HpdsOld = SHChangeProcess(LppdCur->hpds); // unloading user mode modules in kernel mode // can result in nameless emis ModListModUnload( lpsz ); if (SHIsDllLoaded(emi) && lpsz) { CmdLogFmt("Module Unload: %s\r\n", lpsz); } // A module has been unloaded. We must unresolve all // the breakpoints in the module. if (LppdCur->pstate == psRunning) { BPTUnResolve( emi ); } // Unload the symbols SHUnloadSymbols(emi); // Rebind the emi to the module record, but don't update the debugger // since doing so may cause the symbols to reload instantly. OSDRegisterEmi(LppdCur->hpid, (HEMI)emi, ""); CmdLogFmt("Use \".refresh\" or \".reload\" to update the debugger"); //BPTResolveAll(LppdCur->hpid, FALSE); //UpdateDebuggerState(UPDATE_CONTEXT); SHChangeProcess(HpdsOld); return LOGERROR_NOERROR; } LOGERR LogRefresh( LPSTR lpsz, DWORD dw ) { CmdInsertInit(); if (LppdCur == NULL) { CmdLogVar(ERR_Debuggee_Not_Alive); return LOGERROR_QUIET; } BPTResolveAll(LppdCur->hpid, FALSE); UpdateDebuggerState(UPDATE_ALLDBGWIN); return LOGERROR_NOERROR; }