4051 lines
92 KiB
C
4051 lines
92 KiB
C
/*++
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
Cmdexec0.c
|
|
|
|
Abstract:
|
|
This file contains the front end code for parsing the various commands for the command window, and the code for the debugger control commands.
|
|
|
|
Author:
|
|
David J. Gilman (davegi) 21-Apr-92
|
|
|
|
Environment:
|
|
Win32, User Mode
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
/************ Data declaration ***********/
|
|
|
|
/****** Publics ********/
|
|
|
|
// M00TODO a-kentf put these defaults in (windbg.h? cmdexec.h?)
|
|
ULONG ulRipBreakLevel = 1;
|
|
ULONG ulRipNotifyLevel = 3;
|
|
|
|
ULONG ulPseudo[10]={0,0,0,0,0,0,0,0,0,0};
|
|
|
|
LPPD LppdCommand;
|
|
LPTD LptdCommand;
|
|
|
|
BOOL FSetLptd; // Was thread specified
|
|
BOOL FSetLppd; // Was process specified
|
|
|
|
INT BpCmdPid;
|
|
INT BpCmdTid;
|
|
|
|
BOOL fWaitForDebugString;
|
|
LPSTR lpCmdString;
|
|
|
|
CHAR szLoggerBuf[MAX_USER_LINE+2];
|
|
|
|
|
|
/****** Locals ********/
|
|
|
|
|
|
|
|
char szPrompt[ PROMPT_SIZE ] = "> ";
|
|
|
|
BOOL
|
|
StringLogger(
|
|
LPCSTR szStr,
|
|
BOOL fFileLog,
|
|
BOOL fSendRemote,
|
|
BOOL fPrintLocal
|
|
);
|
|
|
|
LOGERR
|
|
LogOpenDoc(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
);
|
|
|
|
DOT_COMMAND DotTable[] = {
|
|
"attach", LogAttach, 0,
|
|
"<pid> Debug an existing process.",
|
|
"break", LogBreak, 0,
|
|
" Stop the current process.",
|
|
"connect", LogConnect, 0,
|
|
" Connect WinDbg to a remote session.",
|
|
"crash", LogCrash, 0,
|
|
"<filename> Generate a user-mode dump of the application.",
|
|
"disconnect",LogDisconnect, 0,
|
|
" Disconnect WinDbg from a remote session.",
|
|
"kill", LogKill, 0,
|
|
"<pnumber> Terminate a process being debugged.",
|
|
"list", LogList, 0,
|
|
"<address> Display source or assembly code for an address.",
|
|
"logappend", LogFileOpen, TRUE,
|
|
"[filename] Append to the log file.",
|
|
"logclose", LogFileClose, 0,
|
|
" Close the log file.",
|
|
"logopen", LogFileOpen, FALSE,
|
|
"[filename] Append to the log file and truncate any existing log.",
|
|
"open", LogOpenDoc, 0,
|
|
" Open a source file.",
|
|
"opt", LogOptions, 0,
|
|
"[args] Type .opt ? for a complete description.",
|
|
"refresh", LogRefresh, 0,
|
|
" Refresh the debugger state.",
|
|
"reload", LogReload, 0,
|
|
"[filename] Reload the symbol files.",
|
|
"sleep", LogSleep, 0,
|
|
"<seconds> Delay execution of debugger script.",
|
|
"source", LogSource, 0,
|
|
"<scriptfile> Run a debugger script.",
|
|
"start", LogStart, 0,
|
|
"<program> Debug an application.",
|
|
"title", LogTitle, 0,
|
|
"<window title> Set the debugger window title.",
|
|
"unload", LogUnload, 0,
|
|
"<dll name> Unload the specified extension DLL.",
|
|
"waitforstr", LogWaitForString, 0,
|
|
" Wait for a debug string.",
|
|
};
|
|
#define NDOTS (sizeof(DotTable)/sizeof(DOT_COMMAND))
|
|
const DWORD dwSizeofDotTable = NDOTS;
|
|
|
|
BOOL OnOffBOOLHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL OnOffKDHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL OnOffByteHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL AsmOptHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL DllSetHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL DllPathSetHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL HelpHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL KdBaudHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL KdPortHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL KdCacheHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL KdPlatformHandler(LPVOID, int, LPSTR, BOOL);
|
|
BOOL BackgroundSymHandler(LPVOID, int, LPSTR, BOOL);
|
|
|
|
|
|
typedef BOOL (*OPTHANDLER)(LPVOID lpData, int cbSize, LPSTR lpVal, BOOL fSet);
|
|
|
|
typedef struct tagOPTIONSTRUCT {
|
|
LPSTR lpName; // name for user to use
|
|
LPVOID lpData; // actual data
|
|
int cbSize; // for string fields or whatever
|
|
OPTHANDLER lpfnHandler; // work function
|
|
LPSTR lpDesc; // help text
|
|
} OPTIONSTRUCT, *LPOPTIONSTRUCT;
|
|
|
|
|
|
//static BOOL fFakeFlag = FALSE;
|
|
static OPTIONSTRUCT OptionTable[] =
|
|
{
|
|
|
|
// The help entry must be the first entry in this table
|
|
|
|
"?", 0,0, HelpHandler,
|
|
" Displays this list",
|
|
"AsmSymbols", (LPVOID) dopSym, 0, AsmOptHandler,
|
|
"{on/off} Show symbols in disassembly",
|
|
"AsmRaw", (LPVOID) dopRaw, 0, AsmOptHandler,
|
|
"{on/off} Show raw data in disassembly",
|
|
"AttachGo",&g_contWorkspace_WkSp.m_bAttachGo, 0, OnOffBOOLHandler,
|
|
"{on/off} Do not break into newly attached processes",
|
|
"AutoReloadSrcFiles",&g_contWorkspace_WkSp.m_bAutoReloadSrcFiles, 0, OnOffBOOLHandler,
|
|
"{on/off} Automatically reload changed source files",
|
|
"BackgroundSym", &g_contWorkspace_WkSp.m_bShBackground, 0, BackgroundSymHandler,
|
|
"{on/off} Load symbols in the background",
|
|
"BrowseOnSymError", &g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors, 0, OnOffBOOLHandler,
|
|
"{on/off} Prompts user on errors in symbol loading if IgnoreAll is off",
|
|
"CaseSensitive", &fCaseSensitive, 0, OnOffBOOLHandler,
|
|
"{on/off} Sets case sensitivity",
|
|
"ChildGo",&g_contWorkspace_WkSp.m_bChildGo, 0, OnOffBOOLHandler,
|
|
"{on/off} Do not break into new child processes",
|
|
"CommandRepeat", &g_contGlobalPreferences_WkSp.m_bCommandRepeat, 0, OnOffBOOLHandler,
|
|
"{on/off} Repeat last command with Enter key",
|
|
"DllEE", 0, DLL_EXPR_EVAL, DllSetHandler,
|
|
"<filename> Set the expression evaluator DLL",
|
|
"DllEm", 0, DLL_EXEC_MODEL, DllSetHandler,
|
|
"<filename> Set the execution model DLL",
|
|
"DllSh", 0, DLL_SYMBOL_HANDLER, DllSetHandler,
|
|
"<filename> Set the symbol handler DLL",
|
|
"DllTl", 0, DLL_TRANSPORT, DllSetHandler,
|
|
"<filename [args]> Set the transport layer DLL",
|
|
"DllPath",0,0, DllPathSetHandler,
|
|
"< path | \"path1;path2...\" > Set the search path for symbols",
|
|
"EPStep", &g_contWorkspace_WkSp.m_bEPIsFirstStep, 0, OnOffBOOLHandler,
|
|
"{on/off} First step goes to the entry point, not main",
|
|
"ExitGo", &g_contWorkspace_WkSp.m_bGoOnThreadTerm, 0, OnOffBOOLHandler,
|
|
"{on/off} Do not stop on thread termination",
|
|
"IgnoreAll", &g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors, 0, OnOffBOOLHandler,
|
|
"{on/off} Load all symbol files, even ones with errors",
|
|
"InheritHandles", &g_contWorkspace_WkSp.m_bInheritHandles, 0, OnOffBOOLHandler,
|
|
"{on/off} Debuggee inherits handles (for debugging debuggers)",
|
|
"KdInitialBp", &g_contKernelDbgPreferences_WkSp.m_bInitialBp, 0, OnOffBOOLHandler,
|
|
"{on/off} Stop at initial breakpoint (kernel debugger)",
|
|
"KdEnable", &g_contWorkspace_WkSp.m_bKernelDebugger, 0, OnOffKDHandler,
|
|
"{on/off} Enable the kernel debugger",
|
|
"KdGoExit", &g_contKernelDbgPreferences_WkSp.m_bGoExit, 0, OnOffBOOLHandler,
|
|
"{on/off} Go on exit",
|
|
"KdUseModem", &g_contKernelDbgPreferences_WkSp.m_bUseModem, 0, OnOffBOOLHandler,
|
|
"{on/off} Use modem controls (kernel debugger)",
|
|
"KdBaudRate", &g_contKernelDbgPreferences_WkSp.m_dwBaudRate, 0, KdBaudHandler,
|
|
"{on/off} Set baud rate (kernel debugger -\n"
|
|
" 1200, 2400, 4800, 9600, 38400, 56000)",
|
|
"KdPort", &g_contKernelDbgPreferences_WkSp.m_dwPort, 0, KdPortHandler,
|
|
"{on/off} Set communication port (kernel debugger - COM1, COM2, ...)",
|
|
"KdCacheSize", &g_contKernelDbgPreferences_WkSp.m_dwCache, 0, KdCacheHandler,
|
|
"{on/off} Set memory cache size (kernel debugger)",
|
|
"KdPlatform", &g_contKernelDbgPreferences_WkSp.m_mptPlatform, 0, KdPlatformHandler,
|
|
"{on/off} Set target system type (kernel debugger - x86, alpha, ia64)",
|
|
"LoadGo", &g_contWorkspace_WkSp.m_bGoOnModLoad, 0, OnOffBOOLHandler,
|
|
"{on/off} Go on module load",
|
|
"MasmEval", &g_contWorkspace_WkSp.m_bMasmEval, 0, OnOffBOOLHandler,
|
|
"{on/off} Use MASM-style expression evaluation",
|
|
"NotifyExit",&g_contWorkspace_WkSp.m_bNotifyThreadTerm, 0, OnOffBOOLHandler,
|
|
"{on/off} Print a message upon thread termination",
|
|
"NotifyNew",&g_contWorkspace_WkSp.m_bNotifyThreadCreate, 0, OnOffBOOLHandler,
|
|
"{on/off} Print a message upon thread creation",
|
|
"ShortContext", &g_contWorkspace_WkSp.m_bShortContext, 0, OnOffBOOLHandler,
|
|
"{on/off} Display abbreviated context information",
|
|
"UnicodeIsDefault", &g_contWorkspace_WkSp.m_bUnicodeIsDefault, 0, OnOffBOOLHandler,
|
|
"{on/off} Attempt to evaluate all UINT pointers as Unicode strings",
|
|
"Verbose", &g_contWorkspace_WkSp.m_bVerbose, 0, OnOffBOOLHandler,
|
|
"{on/off} Display verbose output",
|
|
};
|
|
|
|
#define NOPTS (sizeof(OptionTable) / sizeof(OPTIONSTRUCT))
|
|
|
|
HANDLE hFileLog = INVALID_HANDLE_VALUE;
|
|
extern CRITICAL_SECTION csLog;
|
|
|
|
static FILE * fpAutoRun = (FILE *)NULL;
|
|
|
|
static int XNew = 0;
|
|
static int YNew = 0;
|
|
|
|
static BOOL FDebugString = FALSE;
|
|
static int XNewDebug;
|
|
static int YNewDebug;
|
|
|
|
static BOOL (*lpfnLineProc)(LPSTR lpsz) = CmdExecuteLine;
|
|
static void (*lpfnPromptProc)(BOOL,BOOL) = CmdExecutePrompt;
|
|
|
|
static char * LpszCmdPtr = (char *)NULL; //
|
|
static char * LpszCmdBuff = (char *)NULL; //
|
|
|
|
|
|
/****** Externs from ??? *******/
|
|
|
|
extern LPSHF Lpshf; // vector table for symbol handler
|
|
extern CXF CxfIp;
|
|
|
|
LOGERR LogExtension(LPSTR lpsz);
|
|
LOGERR LogVersion(LPSTR lpsz);
|
|
BOOL NotifyDmOfProcessorChange(DWORD);
|
|
|
|
/************ Code ***********/
|
|
|
|
/** Option handler functions ***/
|
|
|
|
/*
|
|
* These return TRUE when they succeed, false when they don't.
|
|
*/
|
|
BOOL
|
|
HelpHandler(
|
|
LPVOID lpData,
|
|
int cbSize,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
{
|
|
int i;
|
|
if (!fSet) {
|
|
*lpVal = 0;
|
|
} else {
|
|
for (i = 0; i < NOPTS; i++) {
|
|
CmdLogFmt("%s %s\r\n",
|
|
OptionTable[i].lpName,
|
|
OptionTable[i].lpDesc);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
OnOffBOOLHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
|
|
cb - Supplies more data
|
|
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
int n;
|
|
BOOL fOK = FALSE;
|
|
char szToken[MAX_USER_LINE];
|
|
|
|
Unreferenced( cb );
|
|
|
|
if (!fSet) {
|
|
sprintf(lpVal, (*(BOOL *)lpData) ? "on" : "off");
|
|
return TRUE;
|
|
}
|
|
|
|
n = CPCopyToken(&lpVal, szToken);
|
|
|
|
if (*CPSkipWhitespace(lpVal)) {
|
|
|
|
CmdLogVar(ERR_Command_Error);
|
|
|
|
} else if (_stricmp(szToken, "yes") == 0
|
|
|| _stricmp(szToken, "y") == 0
|
|
|| _stricmp(szToken, "true") == 0
|
|
|| _stricmp(szToken, "1") == 0
|
|
|| _stricmp(szToken, "on") == 0 ) {
|
|
|
|
*(BOOL *)lpData = TRUE;
|
|
fOK = TRUE;
|
|
|
|
} else if (_stricmp(szToken, "no") == 0
|
|
|| _stricmp(szToken, "n") == 0
|
|
|| _stricmp(szToken, "false") == 0
|
|
|| _stricmp(szToken, "0") == 0
|
|
|| _stricmp(szToken, "off") == 0 ) {
|
|
|
|
*(BOOL *)lpData = FALSE;
|
|
fOK = TRUE;
|
|
|
|
} else {
|
|
|
|
CmdLogVar(ERR_True_False);
|
|
|
|
}
|
|
|
|
return fOK;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
OnOffKDHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle KD enable switch, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
|
|
cb - Supplies more data
|
|
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
BOOL WasSet = g_contWorkspace_WkSp.m_bKernelDebugger;
|
|
|
|
BOOL fOK = OnOffBOOLHandler(lpData, cb, lpVal, fSet);
|
|
|
|
if (fOK) {
|
|
if (fSet) {
|
|
g_Windbg_WkSp.SetCurrentProgramName(NT_KERNEL_NAME);
|
|
} else if (WasSet) {
|
|
g_Windbg_WkSp.SetCurrentProgramName(g_Windbg_WkSp.m_pszNoProgramLoaded);
|
|
}
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
|
|
BOOL
|
|
OnOffByteHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a byte for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
|
|
cb - Supplies more data
|
|
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
BOOL flag;
|
|
BOOL fOK;
|
|
|
|
flag = (BOOL)*((BYTE *)lpData);
|
|
|
|
fOK = OnOffBOOLHandler((LPVOID)&flag, cb, lpVal, fSet);
|
|
if (fOK) {
|
|
*((BYTE *)lpData) = (BYTE)flag;
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AsmOptHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
|
|
cb - Supplies more data
|
|
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
BOOL fOK;
|
|
BOOL flag;
|
|
int dops = PtrToInt(lpData);
|
|
|
|
flag = (g_contWorkspace_WkSp.m_dopDisAsmOpts & dops) ? 1 : 0;
|
|
|
|
fOK = OnOffBOOLHandler((LPVOID)&flag, cb, lpVal, fSet);
|
|
|
|
if (fOK) {
|
|
if (fSet) {
|
|
if (flag) {
|
|
g_contWorkspace_WkSp.m_dopDisAsmOpts |= dops;
|
|
} else {
|
|
g_contWorkspace_WkSp.m_dopDisAsmOpts &= ~dops;
|
|
}
|
|
}
|
|
}
|
|
return fOK;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DllSetHandler(
|
|
LPVOID /*lpData*/,
|
|
int nDll,
|
|
LPSTR pszVal,
|
|
BOOL bSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to change the set of DLLs used by windbg.
|
|
This is for use with scripting only.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
|
|
nDll - Supplies data size
|
|
|
|
pszVal - Supplies pointer to user input or string to format into
|
|
|
|
bSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
PTSTR pszToken = pszVal;
|
|
|
|
switch (nDll) {
|
|
case DLL_EXPR_EVAL:
|
|
|
|
// DllEE: Expression evaluator dll
|
|
|
|
if (bSet) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszVal, g_pszDLL_EXPR_EVAL);
|
|
break;
|
|
|
|
case DLL_EXEC_MODEL:
|
|
|
|
// DllEm: Execution model dll
|
|
|
|
if (bSet) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszVal, g_pszDLL_EXEC_MODEL);
|
|
break;
|
|
|
|
case DLL_SYMBOL_HANDLER:
|
|
|
|
// DllSh: Symbol handler dll
|
|
|
|
if (bSet) {
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(pszVal, g_pszDLL_SYMBOL_HANDLER);
|
|
break;
|
|
|
|
case DLL_TRANSPORT:
|
|
|
|
// DllTl: Transport layer dll
|
|
|
|
if (!bSet) {
|
|
|
|
|
|
// Query TL settings
|
|
|
|
|
|
if (!g_contWorkspace_WkSp.m_pszSelectedTL) {
|
|
|
|
|
|
// No TL is currently selected!
|
|
// Warn the user.
|
|
|
|
PTSTR psz = WKSP_DynaLoadString(g_hInst, ERR_No_TL_Selected);
|
|
if (!psz) {
|
|
_tcsncpy(pszVal, "none", MAX_USER_LINE);
|
|
} else {
|
|
_tcsncpy(pszVal, psz, MAX_USER_LINE);
|
|
FREE_STR(psz);
|
|
}
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
|
|
// Find the currently selected TL
|
|
|
|
TListEntry<CIndiv_TL_WKSP *> * pContEntry = g_dynacontAll_TLs_WkSp.m_listConts.Find(
|
|
g_contWorkspace_WkSp.m_pszSelectedTL,
|
|
WKSP_Generic_CmpRegName);
|
|
CIndiv_TL_WKSP * pIndTl = NULL;
|
|
if (pContEntry) {
|
|
pIndTl = pContEntry->m_tData;
|
|
AssertType(*pIndTl, CIndiv_TL_WKSP);
|
|
}
|
|
|
|
if (pIndTl) {
|
|
|
|
|
|
// We found the currently selected TL
|
|
|
|
_snprintf(pszVal,
|
|
MAX_USER_LINE,
|
|
_T("%s %s"),
|
|
pIndTl->m_pszDll,
|
|
pIndTl->m_pszParams
|
|
);
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
|
|
// Error: A TL is specified but it does not exist.
|
|
// Warn the user that the spcified TL doesn't exist
|
|
|
|
CmdLogVar(ERR_Transport_Doesnt_Exist, g_contWorkspace_WkSp.m_pszSelectedTL);
|
|
|
|
// Tell the user the name of the currently selected TL, completing our task
|
|
|
|
_tcsncpy(pszVal, g_contWorkspace_WkSp.m_pszSelectedTL, MAX_USER_LINE);
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
} else {
|
|
|
|
|
|
// Set new TL params from the command window
|
|
|
|
|
|
PTSTR pszTmp = NULL;
|
|
PCTSTR pszTLNameCreatedFromCmdWindow = _T("Command window TL");
|
|
TCHAR szBuffer[MAX_USER_LINE] = {0};
|
|
|
|
TListEntry<CIndiv_TL_WKSP *> * pContEntry = g_dynacontAll_TLs_WkSp.m_listConts.Find(
|
|
pszTLNameCreatedFromCmdWindow,
|
|
WKSP_Generic_CmpRegName);
|
|
|
|
CIndiv_TL_WKSP * pIndTl = NULL;
|
|
if (pContEntry) {
|
|
pIndTl = pContEntry->m_tData;
|
|
AssertType(*pIndTl, CIndiv_TL_WKSP);
|
|
}
|
|
|
|
if (pIndTl) {
|
|
|
|
|
|
// We found a previous instance of a TL created from the command window.
|
|
// Replace the current values with the new ones.
|
|
|
|
|
|
|
|
// Set the new default TL
|
|
|
|
FREE_STR(g_contWorkspace_WkSp.m_pszSelectedTL);
|
|
g_contWorkspace_WkSp.m_pszSelectedTL = _tcsdup(pszTLNameCreatedFromCmdWindow);
|
|
|
|
pIndTl->m_pszDescription = WKSP_DynaLoadString(g_hInst,
|
|
SYS_Desc_For_TL_Created_From_Cmd_Wnd);
|
|
|
|
pszToken = CPSzToken(&pszToken, szBuffer);
|
|
pIndTl->m_pszDll = _tcsdup(szBuffer);
|
|
|
|
CPSzToken(&pszToken, szBuffer);
|
|
pIndTl->m_pszParams = _tcsdup(szBuffer);
|
|
|
|
pszTmp = WKSP_DynaLoadStringWithArgs(g_hInst,
|
|
SYS_New_TL_Settings,
|
|
pIndTl->m_pszRegistryName,
|
|
pIndTl->m_pszDll,
|
|
pIndTl->m_pszParams
|
|
);
|
|
if (pszTmp) {
|
|
_tcsncpy(pszVal, pszTmp, MAX_USER_LINE);
|
|
} else {
|
|
*pszVal = 0;
|
|
}
|
|
FREE_STR(pszTmp);
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// A TL has not been previously created from the command window. If it
|
|
// has it has been erased. Let's create a new one.
|
|
|
|
CIndiv_TL_WKSP * pIndTl = new CIndiv_TL_WKSP();
|
|
if (!pIndTl) {
|
|
CmdLogFmt(LowMemoryMsg);
|
|
CmdLogFmt("\r\n");
|
|
*pszVal = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
CIndiv_TL_WKSP * pCont = new CIndiv_TL_WKSP();
|
|
Assert(pCont);
|
|
pCont->Init(&g_dynacontAll_TLs_WkSp,
|
|
pszTLNameCreatedFromCmdWindow,
|
|
FALSE,
|
|
FALSE
|
|
);
|
|
|
|
pIndTl->m_pszDescription = _tcsdup(_T("TL created from within the command window"));
|
|
|
|
pszToken = CPSzToken(&pszToken, szBuffer);
|
|
pIndTl->m_pszDll = _tcsdup(szBuffer);
|
|
|
|
CPSzToken(&pszToken, szBuffer);
|
|
pIndTl->m_pszParams = _tcsdup(szBuffer);
|
|
|
|
pszTmp = WKSP_DynaLoadStringWithArgs(g_hInst,
|
|
SYS_New_TL_Settings,
|
|
pIndTl->m_pszRegistryName,
|
|
pIndTl->m_pszDll,
|
|
pIndTl->m_pszParams
|
|
);
|
|
if (pszTmp) {
|
|
_tcsncpy(pszVal, pszTmp, MAX_USER_LINE);
|
|
} else {
|
|
*pszVal = 0;
|
|
}
|
|
FREE_STR(pszTmp);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Assert(0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
DllPathSetHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
{
|
|
int len;
|
|
LPSTR lpsz;
|
|
char sz[2000];
|
|
PIOCTLGENERIC pig;
|
|
DWORD dw;
|
|
|
|
if (!fSet) {
|
|
len = ModListGetSearchPath( NULL, 0 );
|
|
if (!len) {
|
|
*lpVal = 0;
|
|
} else {
|
|
lpsz = (PSTR) malloc(len);
|
|
Assert(lpsz);
|
|
ModListGetSearchPath( lpsz, len );
|
|
// BUGBUG kentf this is sleazy, but I don't have time to change it
|
|
strncpy(lpVal, lpsz, MAX_USER_LINE);
|
|
lpVal[MAX_USER_LINE-1] = 0;
|
|
free(lpsz);
|
|
}
|
|
} else {
|
|
lpVal = CPSkipWhitespace(lpVal);
|
|
CPCopyString(&lpVal, sz, '\0', *lpVal == '"' || *lpVal == '\'');
|
|
ModListSetSearchPath( sz );
|
|
if ( g_contWorkspace_WkSp.m_bKernelDebugger && LptdCur && DebuggeeAlive()) {
|
|
FormatKdParams( sz );
|
|
pig = (PIOCTLGENERIC)malloc(strlen(sz) + 1 + sizeof(IOCTLGENERIC));
|
|
if (!pig) {
|
|
return FALSE;
|
|
}
|
|
pig->ioctlSubType = IG_DM_PARAMS;
|
|
pig->length = strlen(sz) + 1;
|
|
strcpy((LPSTR)pig->data,sz);
|
|
OSDSystemService( LppdCur->hpid,
|
|
LptdCur->htid,
|
|
(SSVC) ssvcGeneric,
|
|
(LPV)pig,
|
|
strlen(sz) + 1 + sizeof(IOCTLGENERIC),
|
|
&dw
|
|
);
|
|
free( pig );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
KdBaudHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
cb - Supplies more data
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
char szToken[MAX_USER_LINE];
|
|
|
|
|
|
if (!fSet) {
|
|
sprintf(lpVal, "%d", g_contKernelDbgPreferences_WkSp.m_dwBaudRate );
|
|
return TRUE;
|
|
}
|
|
|
|
i = CPCopyToken(&lpVal, szToken);
|
|
|
|
if (*CPSkipWhitespace(lpVal)) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
|
|
for (i=0; i<strlen(szToken); i++) {
|
|
if (!isdigit(szToken[i])) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
g_contKernelDbgPreferences_WkSp.m_dwBaudRate = atol( szToken );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
KdPortHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
cb - Supplies more data
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
char szToken[MAX_USER_LINE];
|
|
LPSTR p = szToken;
|
|
|
|
|
|
if (!fSet) {
|
|
sprintf(lpVal, "COM%d", g_contKernelDbgPreferences_WkSp.m_dwPort );
|
|
return TRUE;
|
|
}
|
|
|
|
i = CPCopyToken(&lpVal, szToken);
|
|
|
|
if (*CPSkipWhitespace(lpVal)) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
|
|
if (_strnicmp(p, "com", 3) == 0) {
|
|
p += 3;
|
|
if (strlen(p) == 1 && isdigit(*p)) {
|
|
g_contKernelDbgPreferences_WkSp.m_dwPort = *p - '0';
|
|
} else {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
KdCacheHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
cb - Supplies more data
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
char szToken[MAX_USER_LINE];
|
|
|
|
|
|
if (!fSet) {
|
|
sprintf(lpVal, "%d", g_contKernelDbgPreferences_WkSp.m_dwCache );
|
|
return TRUE;
|
|
}
|
|
|
|
i = CPCopyToken(&lpVal, szToken);
|
|
|
|
if (*CPSkipWhitespace(lpVal)) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
|
|
for (i=0; i<strlen(szToken); i++) {
|
|
if (!isdigit(szToken[i])) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
g_contKernelDbgPreferences_WkSp.m_dwCache = atol( szToken );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
KdPlatformHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
cb - Supplies more data
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
char szToken[MAX_USER_LINE];
|
|
|
|
|
|
if (!fSet) {
|
|
strcpy(lpVal, GetPlatformNameFromId(g_contKernelDbgPreferences_WkSp.m_mptPlatform));
|
|
return TRUE;
|
|
}
|
|
|
|
i = CPCopyToken(&lpVal, szToken);
|
|
|
|
if (*CPSkipWhitespace(lpVal)) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetPlatformIdFromName(szToken, &g_contKernelDbgPreferences_WkSp.m_mptPlatform)) {
|
|
CmdLogVar(ERR_Command_Error);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BackgroundSymHandler(
|
|
LPVOID lpData,
|
|
int cb,
|
|
LPSTR lpVal,
|
|
BOOL fSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle boolean switches, with a native BOOL for the data item.
|
|
|
|
Arguments:
|
|
|
|
lpData - Supplies pointer to data
|
|
|
|
cb - Supplies more data
|
|
|
|
lpVal - Supplies pointer to user input or string to format into
|
|
|
|
fSet - Supplies TRUE for set, FALSE for read/format
|
|
|
|
Return Value:
|
|
|
|
TRUE when successful, FALSE if something is wrong.
|
|
|
|
--*/
|
|
{
|
|
int n;
|
|
BOOL fOK;
|
|
char szToken[MAX_USER_LINE];
|
|
|
|
Unreferenced( cb );
|
|
|
|
fOK = OnOffBOOLHandler(lpData, cb, lpVal, fSet);
|
|
if (!fSet) {
|
|
return fOK;
|
|
}
|
|
|
|
if (fOK) {
|
|
if (*(BOOL *)lpData) {
|
|
LPFNSHSTARTBACKGROUND lpfn;
|
|
lpfn = (LPFNSHSTARTBACKGROUND) GetProcAddress( (HINSTANCE) HModSH, "SHStartBackground" );
|
|
if (lpfn) {
|
|
lpfn();
|
|
}
|
|
} else {
|
|
LPFNSHSTOPBACKGROUND lpfn;
|
|
lpfn = (LPFNSHSTOPBACKGROUND) GetProcAddress( (HINSTANCE) HModSH, "SHStopBackground" );
|
|
if (lpfn) {
|
|
lpfn();
|
|
}
|
|
}
|
|
}
|
|
|
|
return fOK;
|
|
}
|
|
|
|
/************ ***********/
|
|
|
|
void
|
|
CmdSetDefaultCmdProc(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set input and prompt procs to the default (CmdExecuteLine)
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CmdSetCmdProc(CmdExecuteLine, CmdExecutePrompt);
|
|
CmdSetAutoHistOK(TRUE);
|
|
CmdSetEatEOLWhitespace(TRUE);
|
|
}
|
|
|
|
|
|
void
|
|
CmdSetCmdProc(
|
|
BOOL (*lpfnLP)(LPSTR lpsz),
|
|
void (*lpfnPP)(BOOL,BOOL)
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the input and prompt procs for the command window.
|
|
|
|
Arguments:
|
|
|
|
lpfnLP - pointer to the line input function
|
|
lpfnPP - pointer to the prompt printer function
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
lpfnLineProc = lpfnLP;
|
|
lpfnPromptProc = lpfnPP;
|
|
}
|
|
|
|
void
|
|
CmdDoPrompt(
|
|
BOOL fRemote,
|
|
BOOL fLocal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls the current prompt printer function, then sets the line to the left
|
|
of the cursor readonly.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
int XOld = 0;
|
|
int YOld;
|
|
int XPos = Views[cmdView].X;
|
|
int YPos = Views[cmdView].Y;
|
|
|
|
if (fLocal) {
|
|
CmdInsertInit();
|
|
FDebugString = FALSE;
|
|
|
|
// is there already a prompt here?
|
|
GetRORegion(cmdView, &XOld, &YOld);
|
|
if (YOld == YNew && XOld > 0) {
|
|
XNew = XOld;
|
|
StringLogger("\r\n", FALSE, FALSE, TRUE);
|
|
|
|
if (YPos > YOld) {
|
|
YPos++;
|
|
} else if (YPos == YOld && XPos >= XOld) {
|
|
YPos++;
|
|
XPos -= XOld;
|
|
}
|
|
}
|
|
|
|
XOld = XNew;
|
|
YOld = YNew;
|
|
}
|
|
|
|
(*lpfnPromptProc)(fRemote, fLocal);
|
|
|
|
if (fLocal) {
|
|
|
|
SetRORegion(cmdView, XNew, YNew);
|
|
|
|
if (YPos > YOld) {
|
|
PosXY(cmdView, XPos, YPos + YNew - YOld, FALSE);
|
|
} else if (YPos == YOld) {
|
|
PosXY(cmdView, XPos+XNew, YNew, FALSE);
|
|
} else {
|
|
PosXY(cmdView, XPos, YPos, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CmdDoLine(
|
|
LPSTR lpsz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls the current line input function
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies a line to be handled by the line input function
|
|
|
|
Return Value:
|
|
|
|
BOOL value from line input function: TRUE for synchronous, FALSE for asynch
|
|
|
|
--*/
|
|
{
|
|
__try {
|
|
return (*lpfnLineProc)(lpsz);
|
|
} __except(GenericExceptionFilter(GetExceptionInformation())) {
|
|
//DAssert(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CmdPrependCommands(
|
|
LPTD lptd,
|
|
LPSTR lpsz
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This function will take the argument lpsz and prepend any
|
|
commands in this string to the command line on the thread.
|
|
|
|
Arguments:
|
|
|
|
lptd - Supplies pointer to thread to add commands to
|
|
lpsz - Supplies commands to add to the threads context
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// NOTENOTE a-kentf something calls with an empty string - beta2
|
|
if (!lpsz || *lpsz == '\0') {
|
|
return;
|
|
}
|
|
|
|
if (lptd == (LPTD)NULL) {
|
|
if ( LpszCmdBuff == (char *)NULL ) {
|
|
LpszCmdBuff = LpszCmdPtr = _strdup(lpsz);
|
|
} else {
|
|
LPSTR lpszT;
|
|
|
|
lpszT = (PSTR) malloc( strlen(LpszCmdPtr) + strlen(lpsz) + 2);
|
|
Assert(lpszT);
|
|
strcpy(lpszT, lpsz);
|
|
strcat(lpszT, ";");
|
|
strcat(lpszT, LpszCmdPtr);
|
|
free( LpszCmdBuff );
|
|
|
|
LpszCmdPtr = LpszCmdBuff = lpszT;
|
|
}
|
|
} else if (lptd->lpszCmdBuffer == (LPSTR)NULL) {
|
|
lptd->lpszCmdBuffer = lptd->lpszCmdPtr = _strdup( lpsz );
|
|
} else {
|
|
LPSTR lpszT;
|
|
|
|
lpszT = (PSTR) malloc( strlen(lptd->lpszCmdPtr) + strlen(lpsz) + 2);
|
|
Assert(lpszT);
|
|
strcpy(lpszT, lpsz);
|
|
strcat(lpszT, ";");
|
|
strcat(lpszT, lptd->lpszCmdPtr);
|
|
free(lptd->lpszCmdBuffer);
|
|
|
|
lptd->lpszCmdBuffer = lptd->lpszCmdPtr = lpszT;
|
|
}
|
|
|
|
return;
|
|
} /* CmdPrependCommands() */
|
|
|
|
void
|
|
CmdExecutePrompt(
|
|
BOOL fRemote,
|
|
BOOL fLocal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print the command prompt and position the cursor after it
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
if (fLocal) {
|
|
CmdInsertInit();
|
|
}
|
|
StringLogger( szPrompt, TRUE, fRemote, fLocal );
|
|
}
|
|
|
|
void
|
|
CmdSetDefaultPrompt(
|
|
LPSTR lpPrompt
|
|
)
|
|
{
|
|
if (!lpPrompt) {
|
|
strcpy(szPrompt, "> ");
|
|
} else {
|
|
strcpy(szPrompt, lpPrompt);
|
|
}
|
|
}
|
|
|
|
LPSTR
|
|
CmdGetDefaultPrompt(
|
|
LPSTR lpPrompt
|
|
)
|
|
{
|
|
if (!lpPrompt) {
|
|
return szPrompt;
|
|
} else {
|
|
return strcpy(lpPrompt, szPrompt);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CmdExecuteLine(
|
|
LPSTR lpszArg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will parse up any existing strings for the current
|
|
thread and execute commands. If lpsz is non-null then the
|
|
commands represented by this string will be placed first on
|
|
the threads command list.
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies pointer to string containing commands to be executed
|
|
|
|
Return Value:
|
|
|
|
TRUE if the command is synchronous and FALSE if it is asynchronous
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSTR lpsz1;
|
|
LPSTR lpsz2;
|
|
int iSrc;
|
|
int cmdRet;
|
|
char ch;
|
|
LPTD lptd;
|
|
char rgchT[256];
|
|
BOOL fQuote;
|
|
char localArg[1024];
|
|
|
|
|
|
|
|
|
|
// in case the caller passes in a read only string
|
|
|
|
if (lpszArg) {
|
|
strcpy( localArg, lpszArg );
|
|
lpszArg = &localArg[0];
|
|
}
|
|
|
|
if (lpszArg && (lpszArg[0] == '*')) {
|
|
lpszArg = NULL;
|
|
}
|
|
|
|
if ((LptdCur == NULL) && (lpszArg == NULL) && (LpszCmdBuff == NULL)) {
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* If there are any steps left to be executed from a previous command
|
|
* these take precedence over any new commands to be executed
|
|
*/
|
|
|
|
if ((LptdCur != NULL) && (LptdCur->cStepsLeft != 0)) {
|
|
if (lpszArg != 0) {
|
|
CmdPrependCommands(LptdCur, lpszArg);
|
|
}
|
|
|
|
LptdCur->cStepsLeft -= 1;
|
|
if (ExecDebuggee((LptdCur->flags & tfStepOver) ? EXEC_STEPOVER : EXEC_TRACEINTO)) {
|
|
return FALSE;
|
|
}
|
|
LptdCur->cStepsLeft = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
do {
|
|
/*
|
|
** Setup for parsing and executing from the current thread
|
|
*/
|
|
|
|
lptd = LptdCur;
|
|
if (lpszArg) {
|
|
lpsz1 = lpszArg;
|
|
iSrc = 1;
|
|
lpszArg = NULL;
|
|
} else if ((lptd != NULL) && (lptd->lpszCmdBuffer != NULL)) {
|
|
lpsz1 = lptd->lpszCmdPtr;
|
|
iSrc = 0;
|
|
} else {
|
|
lpsz1 = LpszCmdPtr;
|
|
iSrc = 2;
|
|
}
|
|
|
|
if (lpsz1 == NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
lpsz2 = lpsz1;
|
|
|
|
/*
|
|
** Scan across the command looking for either the end of the command
|
|
** This is denoted by either a semi-colon or the end of the string.
|
|
*/
|
|
|
|
fQuote = FALSE;
|
|
while (*lpsz1) {
|
|
if (*lpsz1 == '\"') {
|
|
fQuote = !fQuote;
|
|
} else if (!fQuote && (*lpsz1 == ';')) {
|
|
break;
|
|
}
|
|
lpsz1 = CharNext(lpsz1);
|
|
}
|
|
|
|
ch = *lpsz1;
|
|
*lpsz1 = 0;
|
|
|
|
/*
|
|
** Update the thread state information to deal with the possiblity
|
|
** of a thread switch while executing the command
|
|
*/
|
|
|
|
if (ch == 0) {
|
|
switch( iSrc ) {
|
|
/*
|
|
** We are about to execute the last command from the
|
|
** threads buffer. Copy it locally and free
|
|
** the thread state buffer
|
|
*/
|
|
|
|
case 0: // Input from thread buffer
|
|
Assert( lptd != NULL );
|
|
Assert(lptd->lpszCmdBuffer != NULL);
|
|
|
|
strcpy(rgchT, lptd->lpszCmdPtr);
|
|
lpsz2 = &rgchT[0];
|
|
free( lptd->lpszCmdBuffer);
|
|
lptd->lpszCmdBuffer = lptd->lpszCmdPtr = NULL;
|
|
|
|
break;
|
|
|
|
/*
|
|
** No updates are needed -- We just executed a single
|
|
** command from the input argument and no modifications
|
|
** of the thread state are needed.
|
|
*/
|
|
|
|
case 1: // Input from argument buffer
|
|
break;
|
|
|
|
/*
|
|
** We are about to execute the last command from
|
|
** the global buffer. Copy it locally and free
|
|
** the global command buffer.
|
|
*/
|
|
|
|
case 2: // Input from global buffer
|
|
|
|
Assert( LpszCmdBuff != NULL );
|
|
|
|
strcpy(rgchT, LpszCmdPtr);
|
|
lpsz2 = &rgchT[0];
|
|
free( LpszCmdBuff );
|
|
LpszCmdBuff = LpszCmdPtr = NULL;
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
} else {
|
|
lpsz1++;
|
|
|
|
switch (iSrc) {
|
|
/*
|
|
** Just need to update the state information for
|
|
** this thread
|
|
*/
|
|
|
|
case 0:
|
|
Assert(lptd);
|
|
lptd->lpszCmdPtr = lpsz1;
|
|
break;
|
|
|
|
/*
|
|
** Need to prepend the rest of this command line onto
|
|
** the thread command buffer
|
|
*/
|
|
|
|
case 1:
|
|
CmdPrependCommands( lptd, lpsz1 );
|
|
break;
|
|
|
|
/*
|
|
** Just update the pointer state on the global
|
|
** command buffer
|
|
*/
|
|
|
|
case 2:
|
|
LpszCmdPtr = lpsz1;
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Execute this command and grab the return code. It will tell use if
|
|
** this specific command was syncronous or not.
|
|
*/
|
|
|
|
cmdRet = CmdExecuteCmd(lpsz2);
|
|
|
|
/*
|
|
** Loop while the last command was successful and
|
|
** synchronous. Plus there is either a command in the
|
|
** current thread buffer or the global buffer.
|
|
*/
|
|
} while ((cmdRet == CMD_RET_SYNC) &&
|
|
(((LptdCur != NULL) && (LptdCur->lpszCmdPtr != NULL)) ||
|
|
(LpszCmdPtr != NULL)));
|
|
|
|
if (cmdRet == CMD_RET_ERROR) {
|
|
|
|
// clear remaining commands on this thread and globally.
|
|
|
|
if (LptdCur && LptdCur->lpszCmdBuffer) {
|
|
free(LptdCur->lpszCmdBuffer);
|
|
LptdCur->lpszCmdPtr = LptdCur->lpszCmdBuffer = NULL;
|
|
}
|
|
if (LpszCmdBuff) {
|
|
free( LpszCmdBuff );
|
|
LpszCmdBuff = LpszCmdPtr = NULL;
|
|
}
|
|
}
|
|
|
|
return ((cmdRet == CMD_RET_SYNC) || (cmdRet == CMD_RET_ERROR));
|
|
} /* CmdExecLine() */
|
|
|
|
|
|
int
|
|
CmdExecuteCmd(
|
|
LPSTR lpsz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will parse up and attempt to execute a command string
|
|
this command string is equivalent to a return terminated string
|
|
rather than a single command. The return is optional as zero
|
|
termination will work equally well.
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies pointer to the string containning command to be executed
|
|
|
|
Return Value:
|
|
|
|
CMD_RET_SYNC - command is syncronous
|
|
CMD_RET_ASYNC - command is async
|
|
CMD_RET_ERROR - command was in error
|
|
|
|
|
|
--*/
|
|
{
|
|
int retCmd = CMD_RET_SYNC;
|
|
LOGERR logerror = LOGERROR_NOERROR;
|
|
UINT i;
|
|
BOOL err;
|
|
int cb;
|
|
LPSTR lpszSave = lpsz;
|
|
LPSTR lpszT;
|
|
LPSTR lpszX;
|
|
char ch;
|
|
|
|
static char chLastDump = 0;
|
|
|
|
// Skip over any preceeding white space
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
if (*lpsz == 0) {
|
|
return(CMD_RET_SYNC);
|
|
}
|
|
|
|
// Strip off any trailing white space
|
|
|
|
for (lpszX = lpsz-1, lpszT = lpsz; *lpszT; lpszT++) {
|
|
if (IsDBCSLeadByte(*lpszT) && *(lpszT+1)) {
|
|
lpszX = lpszT + 1;
|
|
lpszT++;
|
|
} else
|
|
if (!isspace(*lpszT)) {
|
|
lpszX = lpszT;
|
|
}
|
|
}
|
|
|
|
if (lpszX+1 != lpszT) {
|
|
*(lpszX + 1) = 0;
|
|
}
|
|
|
|
// Strip off anything relative to threads or processes which
|
|
// may preceed the command
|
|
|
|
// Possible starting strings are:
|
|
|
|
// lead := processID | threadID | processID threadID | <blank>
|
|
// processID := '|' Number | '|' '.'
|
|
// threadID := '~' Number | '~' '.'
|
|
|
|
LppdCommand = LppdCur;
|
|
LptdCommand = LptdCur;
|
|
FSetLptd = FALSE;
|
|
FSetLppd = FALSE;
|
|
BpCmdPid = LppdCommand? LppdCommand->ipid : 0;
|
|
BpCmdTid = LptdCommand? LptdCommand->itid : -1;
|
|
|
|
if (*lpsz == '|') {
|
|
FSetLppd = TRUE;
|
|
lpsz = CPSkipWhitespace(lpsz+1);
|
|
if (*lpsz == 0) {
|
|
logerror = LogProcess();
|
|
goto done;
|
|
} else if (*lpsz == '.') {
|
|
lpsz++;
|
|
} else if (*lpsz == '*') {
|
|
BpCmdPid = -1;
|
|
LppdCommand = (LPPD) -1;
|
|
lpsz++;
|
|
} else {
|
|
i = (int) CPGetInt(lpsz, &err, &cb);
|
|
if (err) {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
goto done;
|
|
} else {
|
|
BpCmdPid = i;
|
|
lpsz += cb;
|
|
LppdCommand = ValidLppdOfIpid(i);
|
|
if ( LppdCommand == NULL ) {
|
|
LptdCommand = NULL;
|
|
} else {
|
|
LptdCommand = LppdCommand->lptdList;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
if (*lpsz == '~') {
|
|
FSetLptd = TRUE;
|
|
lpsz = CPSkipWhitespace(lpsz+1);
|
|
if (*lpsz == 0) {
|
|
logerror = LogThread();
|
|
goto done;
|
|
} else if (*lpsz == '.') {
|
|
BpCmdTid = LptdCommand? LptdCommand->itid : 0;
|
|
lpsz++;
|
|
} else if (*lpsz == '*') {
|
|
BpCmdTid = -1;
|
|
LptdCommand = (LPTD) -1;
|
|
lpsz++;
|
|
} else {
|
|
i = (int) CPGetInt(lpsz, &err, &cb);
|
|
if (err) {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
goto done;
|
|
} else if (LppdCommand == (LPPD) -1) {
|
|
CmdInsertInit();
|
|
CmdLogVar(ERR_No_Thread_With_Wildproc);
|
|
logerror = LOGERROR_QUIET;
|
|
goto done;
|
|
} else {
|
|
BpCmdTid = i;
|
|
lpsz += cb;
|
|
if ( LppdCommand == NULL ) {
|
|
LptdCommand = NULL;
|
|
} else {
|
|
LptdCommand = LptdOfLppdItid(LppdCommand, i);
|
|
NotifyDmOfProcessorChange( i );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Skip across any leading white space.
|
|
*/
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
|
|
// For Breakpoint set, we accept nonexistend Process/Thread. For
|
|
// all other commands, Process/Thread must be valid if specified.
|
|
|
|
if ( !( (*lpsz == 'B' || *lpsz == 'b') &&
|
|
(*(lpsz+1) == 'P' || *(lpsz+1) == 'p') ) ) {
|
|
|
|
if ( FSetLppd ) {
|
|
if ( LppdCur == NULL ) {
|
|
CmdInsertInit();
|
|
CmdLogVar(ERR_Process_Not_Exist);
|
|
logerror = LOGERROR_QUIET;
|
|
goto done;
|
|
} else if ( LppdCommand == NULL ) {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if ( FSetLptd ) {
|
|
if ( LptdCur == NULL ) {
|
|
CmdInsertInit();
|
|
CmdLogVar(ERR_No_Threads);
|
|
logerror = LOGERROR_QUIET;
|
|
goto done;
|
|
} else if ( LptdCommand == NULL ) {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Now run through a big switch statement so that we can breakup
|
|
** the command
|
|
*/
|
|
|
|
switch ( *lpsz++ ) {
|
|
case 0:
|
|
if (FSetLptd || FSetLppd) {
|
|
|
|
if (LppdCommand == NULL || LppdCommand == (LPPD)-1
|
|
|| LptdCommand == NULL || LptdCommand == (LPTD)-1)
|
|
{
|
|
logerror = LOGERROR_UNKNOWN;
|
|
} else {
|
|
LppdCur = LppdCommand;
|
|
LptdCur = LptdCommand;
|
|
SetPidTid_StatusBar(LppdCur, LptdCur);
|
|
UpdateDebuggerState(UPDATE_WINDOWS);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case '.':
|
|
logerror = LogDotCommand(lpsz);
|
|
if (logerror == LOGERROR_ASYNC) {
|
|
retCmd = CMD_RET_ASYNC;
|
|
}
|
|
break;
|
|
|
|
case '*': // Comments
|
|
retCmd = CMD_RET_SYNC;
|
|
break;
|
|
|
|
case '+': // Pause
|
|
if (AutoRun != arSource && AutoRun != arCmdline) {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
retCmd = CMD_RET_ASYNC;
|
|
break;
|
|
|
|
case '-': // Continue
|
|
if (AutoRun == arSource || AutoRun == arCmdline) {
|
|
PostMessage(Views[cmdView].hwndClient, WU_AUTORUN, 0, 0);
|
|
} else {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
logerror = LogEvaluate(lpsz, g_contWorkspace_WkSp.m_bMasmEval);
|
|
break;
|
|
|
|
case '%':
|
|
logerror = LogFrameChange(lpsz);
|
|
break;
|
|
|
|
#ifdef MICHE
|
|
case 'a':
|
|
case 'A':
|
|
logerror = LogAssemble(lpsz);
|
|
break;
|
|
#endif
|
|
|
|
case 'b':
|
|
case 'B':
|
|
switch( *lpsz++ ) {
|
|
case 'c':
|
|
case 'C':
|
|
logerror = LogBPChange(lpsz, LOG_BP_CLEAR);
|
|
break;
|
|
|
|
case 'd':
|
|
case 'D':
|
|
logerror = LogBPChange(lpsz, LOG_BP_DISABLE);
|
|
break;
|
|
|
|
case 'e':
|
|
case 'E':
|
|
logerror = LogBPChange(lpsz, LOG_BP_ENABLE);
|
|
break;
|
|
|
|
case 'l':
|
|
case 'L':
|
|
if (*CPSkipWhitespace(lpsz) != 0) {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
} else {
|
|
logerror = LogBPList();
|
|
}
|
|
break;
|
|
|
|
case 'p':
|
|
case 'P':
|
|
logerror = LogBPSet(FALSE, lpsz);
|
|
break;
|
|
|
|
case 'a':
|
|
case 'A':
|
|
logerror = LogBPSet(TRUE, lpsz);
|
|
break;
|
|
|
|
default:
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
break;
|
|
|
|
case 'c':
|
|
case 'C':
|
|
logerror = LogCompare(lpsz);
|
|
break;
|
|
|
|
|
|
case 'd':
|
|
#ifdef MS_INTERNAL_DONT_COMPILE_THIS_DAMMIT
|
|
if ( lpsz[0] == 'C'
|
|
&& lpsz[1] == 'R'
|
|
&& lpsz[2] == 'E'
|
|
&& lpsz[3] == 'D'
|
|
&& lpsz[4] == 'I'
|
|
&& lpsz[5] == 'T'
|
|
&& lpsz[6] == 'S'
|
|
&& lpsz[7] == 0)
|
|
{
|
|
logerror = LOGERROR_NOERROR;
|
|
Egg();
|
|
break;
|
|
}
|
|
#endif
|
|
case 'D':
|
|
if (*CPSkipWhitespace(lpsz) == 0) {
|
|
ch = chLastDump;
|
|
} else {
|
|
ch = *lpsz++;
|
|
}
|
|
|
|
if (ch == 'c' || ch == 'C') {
|
|
logerror = LogDisasm(lpsz,FALSE);
|
|
} else {
|
|
logerror = LogDumpMem(ch, lpsz);
|
|
}
|
|
chLastDump = ch;
|
|
break;
|
|
|
|
case 'e':
|
|
case 'E':
|
|
logerror = LogEnterMem(lpsz);
|
|
break;
|
|
|
|
case 'f':
|
|
case 'F':
|
|
if (*lpsz == 'i' || *lpsz == 'I') {
|
|
logerror = LogFill(++lpsz);
|
|
} else if (*lpsz == 'r' || *lpsz == 'R') {
|
|
logerror = LogRegisters(++lpsz, TRUE);
|
|
} else {
|
|
logerror = LogFreeze(lpsz, TRUE);
|
|
}
|
|
break;
|
|
|
|
case 'h':
|
|
case 'H':
|
|
logerror = LogHelp(lpsz);
|
|
break;
|
|
|
|
case 'g':
|
|
case 'G':
|
|
if (*lpsz == 'h' || *lpsz == 'H') {
|
|
logerror = LogGoException(++lpsz, TRUE);
|
|
} else if (*lpsz == 'n' || *lpsz == 'N') {
|
|
logerror = LogGoException(++lpsz, FALSE);
|
|
} else {
|
|
logerror = LogGoUntil(lpsz);
|
|
}
|
|
retCmd = CMD_RET_ASYNC;
|
|
break;
|
|
|
|
case 'k':
|
|
case 'K':
|
|
logerror = LogCallStack(lpsz);
|
|
break;
|
|
|
|
case 'l':
|
|
case 'L':
|
|
if (*lpsz == 'n' || *lpsz == 'N') {
|
|
logerror = LogListNear(++lpsz);
|
|
} else if (*lpsz == 'm' || *lpsz == 'M') {
|
|
BOOL fExtendedLoadInfo = 'x' == tolower(lpsz[1]);
|
|
|
|
if (fExtendedLoadInfo) {
|
|
// skip over'x', else windbg will think we mean lm x.
|
|
// Where 'x' is a module name
|
|
lpsz++;
|
|
}
|
|
|
|
logerror = LogListModules(
|
|
++lpsz,
|
|
fExtendedLoadInfo
|
|
);
|
|
|
|
} else if (*lpsz == 'd' || *lpsz == 'D') {
|
|
logerror = LogLoadDefered(++lpsz);
|
|
} else if (*lpsz == '\0' || *lpsz == ' ' || *lpsz == '\t') {
|
|
logerror = LogRestart(lpsz);
|
|
} else {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
break;
|
|
|
|
case 'm':
|
|
case 'M':
|
|
logerror = LogMovemem(lpsz);
|
|
break;
|
|
|
|
case 'n':
|
|
case 'N':
|
|
logerror = LogRadix(lpsz);
|
|
break;
|
|
|
|
case 'p':
|
|
case 'P':
|
|
logerror = LogStep(lpsz, TRUE);
|
|
retCmd = CMD_RET_ASYNC;
|
|
break;
|
|
|
|
case 'q':
|
|
case 'Q':
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
if (*lpsz == 0) {
|
|
PostMessage(hwndFrame, WM_COMMAND, IDM_FILE_EXIT, 0L);
|
|
} else {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
retCmd = CMD_RET_ASYNC;
|
|
break;
|
|
|
|
case 'r':
|
|
case 'R':
|
|
if (*lpsz == 'e' && _strnicmp(lpsz,"emote",5)==0) {
|
|
lpsz += 5;
|
|
logerror = LogRemote(lpsz);
|
|
} else {
|
|
logerror = LogRegisters(lpsz, FALSE);
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
case 'S':
|
|
switch (*lpsz) {
|
|
case 'e':
|
|
case 'E':
|
|
LogSetErrorLevel(++lpsz);
|
|
break;
|
|
case 'x':
|
|
case 'X':
|
|
logerror = LogException(++lpsz);
|
|
break;
|
|
case '-':
|
|
SetSrcMode_StatusBar(FALSE);
|
|
break;
|
|
case '+':
|
|
SetSrcMode_StatusBar(TRUE);
|
|
break;
|
|
default:
|
|
logerror = LogSearch(lpsz);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
case 'T':
|
|
logerror = LogStep(lpsz, FALSE);
|
|
retCmd = CMD_RET_ASYNC;
|
|
break;
|
|
|
|
case 'u':
|
|
case 'U':
|
|
logerror = LogDisasm(lpsz,FALSE);
|
|
break;
|
|
|
|
case '#':
|
|
logerror = LogSearchDisasm(lpsz);
|
|
break;
|
|
|
|
case 'w':
|
|
case 'W':
|
|
if (*lpsz == 't' || *lpsz == 'T') {
|
|
logerror = LogWatchTime(lpsz+1);
|
|
} else {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
break;
|
|
|
|
case 'x':
|
|
case 'X':
|
|
logerror = LogExamine(lpsz);
|
|
break;
|
|
|
|
case 'v':
|
|
case 'V':
|
|
if (*lpsz == 'e' && _strnicmp(lpsz,"ersion",6)==0) {
|
|
logerror = LogVersion(lpsz);
|
|
} else {
|
|
logerror = LOGERROR_UNKNOWN;
|
|
}
|
|
break;
|
|
|
|
case 'z':
|
|
case 'Z':
|
|
logerror = LogFreeze(lpsz, FALSE);
|
|
break;
|
|
|
|
case '!':
|
|
logerror = LogExtension(lpsz);
|
|
break;
|
|
|
|
default:
|
|
logerror = LOGERROR_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
done:
|
|
switch (logerror) {
|
|
case LOGERROR_CP:
|
|
// get CP error string...
|
|
|
|
default:
|
|
case LOGERROR_UNKNOWN:
|
|
CmdInsertInit();
|
|
CmdLogVar(ERR_Command_Error);
|
|
// fall thru
|
|
|
|
case LOGERROR_QUIET:
|
|
retCmd = CMD_RET_ERROR;
|
|
break;
|
|
|
|
case LOGERROR_ASYNC:
|
|
case LOGERROR_NOERROR:
|
|
break;
|
|
|
|
}
|
|
|
|
return( retCmd );
|
|
} /* CmdExecuteCmd() */
|
|
|
|
|
|
VOID
|
|
CmdInsertInit(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the insertion point to the beginning of the last
|
|
line in the window.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
#if !defined( NEW_WINDOWING_CODE )
|
|
if (cmdView == -1) {
|
|
OpenDebugWindow(COMMAND_WIN, FALSE); // Not user activated
|
|
}
|
|
|
|
XNew = 0;
|
|
YNew = max(Docs[Views[cmdView].Doc].NbLines-1, 0);
|
|
|
|
return;
|
|
#endif
|
|
} /* CmdInsertInit() */
|
|
|
|
|
|
DWORD
|
|
LogFileWrite(
|
|
LPBYTE lpb,
|
|
DWORD cb
|
|
)
|
|
{
|
|
if (hFileLog == INVALID_HANDLE_VALUE) {
|
|
return 0;
|
|
}
|
|
|
|
EnterCriticalSection( &csLog );
|
|
|
|
WriteFile( hFileLog, lpb, cb, &cb, NULL );
|
|
|
|
LeaveCriticalSection( &csLog );
|
|
|
|
return cb;
|
|
}
|
|
|
|
|
|
VOID
|
|
RichEditControl_InsertCR(
|
|
HWND hwnd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to insert a CR into a command window history.
|
|
|
|
Only inserts a CR into the the history section of the command window.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful and FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
CHARRANGE chrgOld;
|
|
CHARRANGE chrgNew;
|
|
TEXTRANGE TextRange;
|
|
|
|
|
|
// Ensure that the command window exists
|
|
|
|
|
|
Assert(hwnd);
|
|
|
|
|
|
|
|
// Store the currently selected text
|
|
|
|
SendMessage(hwnd,
|
|
EM_EXGETSEL,
|
|
0,
|
|
(LPARAM) &chrgOld
|
|
);
|
|
|
|
|
|
// Append the text
|
|
|
|
chrgNew.cpMin = INT_MAX -1;
|
|
chrgNew.cpMax = INT_MAX;
|
|
SendMessage(hwnd,
|
|
EM_EXSETSEL,
|
|
0,
|
|
(LPARAM) &chrgNew
|
|
);
|
|
|
|
SendMessage(hwnd,
|
|
EM_REPLACESEL,
|
|
FALSE,
|
|
(LPARAM) _T("\r\n")
|
|
);
|
|
|
|
|
|
// Restore the previous selection
|
|
|
|
SendMessage(hwnd,
|
|
EM_EXSETSEL,
|
|
0,
|
|
(LPARAM) &chrgOld
|
|
);
|
|
}
|
|
|
|
|
|
|
|
#if defined( NEW_WINDOWING_CODE )
|
|
|
|
BOOL
|
|
StringLogger(
|
|
const TCHAR const *pszStr,
|
|
BOOL fFileLog,
|
|
BOOL fSendRemote,
|
|
BOOL fPrintLocal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to record data into the command window. It
|
|
will take care of checking for overflow in the current command line.
|
|
|
|
It is used in association with CmdInsertInit.
|
|
|
|
Additionally this function will log the string in the log file if
|
|
logging to file is currently enabled.
|
|
|
|
Arguments:
|
|
|
|
pszStr - Supplies the string to be logged in the command window.
|
|
fFileLog - If TRUE, the string is logged to the log file.
|
|
fSendRemote - If TRUE, the string is sent to the command window.
|
|
fPrintLocal - if TRUE, the string is logged to MDI command window.
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful and FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
PCSTR pszStart;
|
|
PCSTR pszEnd;
|
|
BOOL fUpdateScreen = FALSE;
|
|
TCHAR szLoggerBuf[MAX_USER_LINE+2];
|
|
CHARRANGE chrgOld;
|
|
TEXTRANGE TextRange;
|
|
PCMDWIN_DATA pCmdWinData;
|
|
|
|
|
|
// Ensure that the command window exists
|
|
|
|
|
|
if ( !g_DebuggerWindows.hwndCmd ) {
|
|
if ( !NewCmd_CreateWindow(g_hwndMDIClient) ) {
|
|
fPrintLocal = FALSE; // No window to log to.
|
|
}
|
|
}
|
|
|
|
|
|
AuxPrintf(1, "### %s", pszStr);
|
|
|
|
|
|
if (!fPrintLocal) {
|
|
|
|
if (fFileLog) {
|
|
LogFileWrite( (LPBYTE) pszStr, strlen(pszStr) );
|
|
}
|
|
|
|
if (fSendRemote) {
|
|
SendClientOutput( pszStr, strlen(pszStr) );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
pCmdWinData = GetCmdWinData(g_DebuggerWindows.hwndCmd);
|
|
if (!pCmdWinData) {
|
|
return FALSE;
|
|
}
|
|
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_EXGETSEL,
|
|
0,
|
|
(LPARAM) &chrgOld
|
|
);
|
|
|
|
|
|
// are there too many lines in the buffer?
|
|
|
|
if (MAX_CMDWIN_LINES < SendMessage(pCmdWinData->hwndHistory,
|
|
EM_GETLINECOUNT,
|
|
0,
|
|
0
|
|
)) {
|
|
|
|
|
|
// delete more than we need to so it doesn't happen
|
|
// every time a line is printed.
|
|
|
|
TextRange.chrg.cpMin = 0;
|
|
// Get the character index of the 50th line
|
|
TextRange.chrg.cpMax = SendMessage(pCmdWinData->hwndHistory,
|
|
EM_LINEINDEX,
|
|
50,
|
|
0
|
|
);
|
|
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_EXSETSEL,
|
|
0,
|
|
(LPARAM) &TextRange.chrg
|
|
);
|
|
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_REPLACESEL,
|
|
FALSE,
|
|
(LPARAM) ""
|
|
);
|
|
}
|
|
|
|
|
|
|
|
// Append the text to the command windows history.
|
|
|
|
|
|
|
|
// Set the selection to the very end, so that
|
|
// text will be appended.
|
|
|
|
TextRange.chrg.cpMin = INT_MAX -1;
|
|
TextRange.chrg.cpMax = INT_MAX;
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_EXSETSEL,
|
|
0,
|
|
(LPARAM) &TextRange.chrg
|
|
);
|
|
|
|
|
|
|
|
// Output the text to the cmd window
|
|
|
|
pszStart = pszEnd = pszStr;
|
|
for ( ; *pszEnd; pszStart = pszEnd) {
|
|
|
|
size_t uNumCharOut; // Number of characters to send to the cmd window.
|
|
BOOL fDoCR = FALSE;
|
|
|
|
|
|
// Find the carriage and line feeds
|
|
|
|
pszEnd = pszStart + _tcscspn(pszStart, "\r\n");
|
|
|
|
if (!*pszEnd) {
|
|
|
|
|
|
// The text does not contain a line feed or carriage return
|
|
// simply output the text.
|
|
|
|
|
|
uNumCharOut = _tcslen(pszStr);
|
|
|
|
} else {
|
|
|
|
|
|
// The text DOES contain line braks and carriage returns.
|
|
|
|
|
|
uNumCharOut = pszEnd - pszStart;
|
|
|
|
// skip over the line feeds and carriage returns
|
|
if (*pszEnd == '\r') {
|
|
pszEnd++;
|
|
}
|
|
|
|
if (*pszEnd == '\n') {
|
|
pszEnd++;
|
|
}
|
|
|
|
fDoCR = TRUE;
|
|
fUpdateScreen = TRUE;
|
|
}
|
|
|
|
|
|
|
|
// Output the text to the window
|
|
|
|
while (uNumCharOut) {
|
|
size_t uOut = min( uNumCharOut, _tsizeof(szLoggerBuf) -1 );
|
|
|
|
memmove(szLoggerBuf, pszStart, uOut);
|
|
szLoggerBuf[uOut] = 0;
|
|
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_REPLACESEL,
|
|
FALSE,
|
|
(LPARAM) szLoggerBuf
|
|
);
|
|
|
|
uNumCharOut -= uOut;
|
|
}
|
|
|
|
if (fDoCR) {
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_REPLACESEL,
|
|
FALSE,
|
|
(LPARAM) _T("\r\n")
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Reset the currently selected text
|
|
|
|
SendMessage(pCmdWinData->hwndHistory,
|
|
EM_EXSETSEL,
|
|
0,
|
|
(LPARAM) &chrgOld
|
|
);
|
|
|
|
if (fUpdateScreen) {
|
|
//UpdateWindow(pCmdWinData->hwndHistory);
|
|
}
|
|
|
|
return TRUE;
|
|
} /* StringLogger() */
|
|
|
|
#else //NEW_WINDOWING_CODE
|
|
|
|
BOOL
|
|
StringLogger(
|
|
LPCSTR szStr,
|
|
BOOL fFileLog,
|
|
BOOL fSendRemote,
|
|
BOOL fPrintLocal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to record data into the command window. It
|
|
will take care of checking for overflow in the current command line.
|
|
|
|
It is used in association with CmdInsertInit.
|
|
|
|
Additionally this function will log the string in the log file if
|
|
logging to file is currently enabled.
|
|
|
|
Arguments:
|
|
|
|
buf - Supplies the string to be logged in the command window.
|
|
fFileLog - Supplies TRUE if logging to a log file is desired.
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful and FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
LPLINEREC pLine;
|
|
LPBLOCKDEF pBlock;
|
|
int cWide;
|
|
|
|
int doc = Views[cmdView].Doc;
|
|
|
|
int PosXold = Views[cmdView].X;
|
|
int PosYold = Views[cmdView].Y;
|
|
int XOld = XNew; // remember original insertion point
|
|
int YOld = YNew;
|
|
int XNext; // IP after pending insert
|
|
int YNext;
|
|
int Xro;
|
|
int Yro;
|
|
long ytmp;
|
|
LPCSTR lpsz;
|
|
int cch;
|
|
LPSTR lpPut;
|
|
BOOL fDidCR = FALSE;
|
|
BOOL fRet = TRUE;
|
|
CHAR szLoggerBuf[MAX_USER_LINE+2];
|
|
|
|
|
|
AuxPrintf(1, "### %s", szStr);
|
|
|
|
/*
|
|
* Ensure that the command window exists
|
|
*/
|
|
|
|
Assert(cmdView != -1);
|
|
|
|
/*
|
|
* We are going to insert at XNew,YNew.
|
|
* We need to know where we ended up...
|
|
*/
|
|
|
|
YNext = YNew;
|
|
XNext = XNew;
|
|
|
|
lpsz = szStr;
|
|
lpPut = szLoggerBuf;
|
|
|
|
if (!fPrintLocal) {
|
|
|
|
if (fFileLog) {
|
|
LogFileWrite( (LPBYTE) lpsz, strlen(lpsz) );
|
|
}
|
|
|
|
if (fSendRemote) {
|
|
SendClientOutput( lpsz, strlen(lpsz) );
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
for ( ; *lpsz; lpPut = szLoggerBuf) {
|
|
|
|
ytmp = YNew; // FirstLine modifies the lineNo!!!!
|
|
|
|
// find how much line we have to work with:
|
|
Dbg (FirstLine(doc, &pLine, &ytmp, &pBlock));
|
|
cWide = AlignToTabs(pLine->Length - LHD,
|
|
pLine->Length - LHD,
|
|
(LPSTR)pLine->Text);
|
|
|
|
while (*lpsz) {
|
|
int cx = 1;
|
|
|
|
if (IsDBCSLeadByte(*lpsz) && *(lpsz+1)) {
|
|
if (XNext + 2 < (MAX_USER_LINE - cWide)) {
|
|
*lpPut++ = *lpsz++;
|
|
*lpPut++ = *lpsz++;
|
|
XNext += 2;
|
|
continue;
|
|
} else {
|
|
goto DoNewline;
|
|
}
|
|
}
|
|
|
|
if (*lpsz == '\r') {
|
|
|
|
// if there is a newline, eat it:
|
|
if (*++lpsz == '\n') {
|
|
lpsz++;
|
|
}
|
|
goto DoNewline;
|
|
|
|
} else if (*lpsz == '\n') {
|
|
|
|
lpsz++;
|
|
goto DoNewline;
|
|
|
|
} else {
|
|
cx = 1;
|
|
|
|
if (*lpsz == '\t') {
|
|
cx = g_contGlobalPreferences_WkSp.m_nTabSize - (XNext % g_contGlobalPreferences_WkSp.m_nTabSize);
|
|
}
|
|
if (XNext + cx < (MAX_USER_LINE - cWide)) {
|
|
|
|
*lpPut++ = *lpsz++;
|
|
XNext += cx;
|
|
|
|
} else {
|
|
|
|
DoNewline:
|
|
|
|
*lpPut++ = '\r';
|
|
*lpPut++ = '\n';
|
|
YNext++;
|
|
XNext = 0;
|
|
fDidCR = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
*lpPut = '\0';
|
|
|
|
// remember readonly info, clear it:
|
|
GetRORegion(cmdView, &Xro, &Yro);
|
|
SetRORegion(cmdView, 0, 0);
|
|
|
|
// spew buffer
|
|
cch = (int) (lpPut - szLoggerBuf);
|
|
fRet = InsertBlock(doc, XNew, YNew, cch, szLoggerBuf);
|
|
|
|
// fix read only marker
|
|
if (fRet) {
|
|
if (YNew < Yro) {
|
|
Yro += YNext - YNew;
|
|
} else if (YNew == Yro && XNew < Xro) {
|
|
Yro += YNext - YNew;
|
|
Xro += XNext - XNew;
|
|
}
|
|
}
|
|
|
|
SetRORegion(cmdView, Xro, Yro);
|
|
|
|
if (!fRet) {
|
|
break;
|
|
}
|
|
|
|
// remember new insertion point
|
|
XNew = XNext;
|
|
YNew = YNext;
|
|
|
|
if (fFileLog) {
|
|
LogFileWrite( (PBYTE) szLoggerBuf, cch );
|
|
}
|
|
|
|
if (fSendRemote) {
|
|
SendClientOutput( szLoggerBuf, cch );
|
|
}
|
|
|
|
}
|
|
|
|
// are there too many lines in the buffer?
|
|
ytmp = max(Docs[doc].NbLines, 1) - MAX_CMDWIN_LINES;
|
|
if (ytmp > 0) {
|
|
|
|
// delete more than we need to so it doesn't happen
|
|
// every time a line is printed.
|
|
|
|
ytmp += 20;
|
|
GetRORegion(cmdView, &Xro, &Yro);
|
|
SetRORegion(cmdView, 0, 0);
|
|
// This means delete full lines
|
|
DeleteBlock(doc, 0, 0, 0, ytmp);
|
|
YNew -= ytmp;
|
|
YOld -= ytmp;
|
|
PosYold -= ytmp;
|
|
Yro -= ytmp;
|
|
YNewDebug -= ytmp;
|
|
SetRORegion(cmdView, Xro, Yro);
|
|
InvalidateRect(Views[cmdView].hwndClient, NULL, FALSE);
|
|
}
|
|
|
|
SetVerticalScrollBar(cmdView, FALSE);
|
|
|
|
InvalidateLines(cmdView, YOld, YNew, TRUE);
|
|
|
|
if (YOld <= PosYold) {
|
|
// insert was on or before cursor line:
|
|
PosYold += YNew - YOld;
|
|
}
|
|
|
|
PosXY(cmdView, PosXold, PosYold, FALSE);
|
|
|
|
if (fDidCR) {
|
|
UpdateWindow(Views[cmdView].hwndClient);
|
|
}
|
|
|
|
return fRet;
|
|
} /* StringLogger() */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
CDECL
|
|
CmdLogVar(
|
|
WORD wFormat,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format arguments with vsprintf, print with stringlogger
|
|
|
|
Arguments:
|
|
|
|
wFormat - Supplies resource ID for format string
|
|
.... - Optional args supply values to be formatted by vsprintf
|
|
|
|
Return Value:
|
|
|
|
Return value from StringLogger
|
|
|
|
--*/
|
|
{
|
|
char szFormat[MAX_MSG_TXT];
|
|
char szText[MAX_VAR_MSG_TXT];
|
|
va_list vargs;
|
|
|
|
// load format string from resource file
|
|
Dbg(LoadString(g_hInst, wFormat, (LPSTR)szFormat, MAX_MSG_TXT));
|
|
va_start(vargs, wFormat);
|
|
vsprintf(szText, szFormat, vargs);
|
|
va_end(vargs);
|
|
|
|
if (cmdView == -1) {
|
|
#if defined( NEW_WINDOWING_CODE )
|
|
New_OpenDebugWindow(CMD_WINDOW, FALSE); // Not user activated
|
|
#else
|
|
OpenDebugWindow(COMMAND_WIN, FALSE); // Not user activated
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* If we just change from doing a debug string to doing something else
|
|
* then we need to insert a return in the command string.
|
|
*/
|
|
|
|
FDebugString = FALSE;
|
|
|
|
return StringLogger(szText, TRUE, TRUE, TRUE) &&
|
|
StringLogger("\r\n", TRUE, TRUE, TRUE);
|
|
} /* CmdLogVar() */
|
|
|
|
|
|
void
|
|
WDBGAPIV
|
|
CmdLogFmt(
|
|
LPCSTR lpFmt,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format arguments with vsprintf and print result with StringLogger
|
|
|
|
Arguments:
|
|
|
|
lpFmt - Supplies pointer to format string
|
|
... - Optional args supply values to be formatted
|
|
|
|
Return Value:
|
|
|
|
Return value from StringLogger
|
|
|
|
--*/
|
|
{
|
|
char szText[MAX_VAR_MSG_TXT];
|
|
va_list vargs;
|
|
|
|
|
|
va_start(vargs, lpFmt);
|
|
_vsnprintf(szText, MAX_VAR_MSG_TXT-1, lpFmt, vargs);
|
|
va_end(vargs);
|
|
|
|
if (cmdView == -1 ) {
|
|
#if defined( NEW_WINDOWING_CODE )
|
|
New_OpenDebugWindow(CMD_WINDOW, FALSE); // Not user activated
|
|
#else
|
|
OpenDebugWindow(COMMAND_WIN, FALSE); // Not user activated
|
|
#endif
|
|
}
|
|
/*
|
|
* If we just change from doing a debug string to doing something else
|
|
* then we need to insert a return in the command string.
|
|
*/
|
|
|
|
FDebugString = FALSE;
|
|
|
|
StringLogger(szText, TRUE, TRUE, TRUE);
|
|
} /* CmdLogFmt() */
|
|
|
|
|
|
void
|
|
WDBGAPIV
|
|
CmdLogFmtEx(
|
|
BOOL fFileLog,
|
|
BOOL fSendRemote,
|
|
BOOL fPrintLocal,
|
|
LPCSTR lpFmt,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format arguments with vsprintf and print result with StringLogger
|
|
|
|
Arguments:
|
|
|
|
lpFmt - Supplies pointer to format string
|
|
... - Optional args supply values to be formatted
|
|
|
|
Return Value:
|
|
|
|
Return value from StringLogger
|
|
|
|
--*/
|
|
{
|
|
char szText[MAX_VAR_MSG_TXT];
|
|
va_list vargs;
|
|
|
|
|
|
va_start(vargs, lpFmt);
|
|
_vsnprintf(szText, MAX_VAR_MSG_TXT-1, lpFmt, vargs);
|
|
va_end(vargs);
|
|
|
|
if (cmdView == -1 ) {
|
|
#if defined( NEW_WINDOWING_CODE )
|
|
New_OpenDebugWindow(CMD_WINDOW, FALSE); // Not user activated
|
|
#else
|
|
OpenDebugWindow(COMMAND_WIN, FALSE); // Not user activated
|
|
#endif
|
|
}
|
|
/*
|
|
* If we just change from doing a debug string to doing something else
|
|
* then we need to insert a return in the command string.
|
|
*/
|
|
|
|
FDebugString = FALSE;
|
|
|
|
StringLogger(szText,
|
|
fFileLog,
|
|
fSendRemote,
|
|
fPrintLocal
|
|
);
|
|
} /* CmdLogFmt() */
|
|
|
|
|
|
BOOL
|
|
CmdNoLogString(
|
|
LPCSTR buf
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to record data into the command window. It
|
|
will take care of checking for overflow in the current command line.
|
|
|
|
It is used in association with CmdInsertInit.
|
|
|
|
Arguments:
|
|
|
|
buf - Supplies the string to be logged in the command window
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful and FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
/*
|
|
* If we just change from doing a debug string to doing something else
|
|
* then we need to insert a return in the command string.
|
|
*/
|
|
|
|
if (cmdView == -1) {
|
|
#if defined( NEW_WINDOWING_CODE )
|
|
New_OpenDebugWindow(CMD_WINDOW, FALSE); // Not user activated
|
|
#else
|
|
OpenDebugWindow(COMMAND_WIN, FALSE); // Not user activated
|
|
#endif
|
|
}
|
|
|
|
FDebugString = FALSE;
|
|
|
|
return StringLogger(buf, FALSE, TRUE, TRUE);
|
|
} /* CmdNoLogString() */
|
|
|
|
VOID
|
|
CmdLogDebugString(
|
|
LPSTR lpStr,
|
|
BOOL fSendRemote
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to put out debug strings into the command
|
|
window. This needs to deal with the possiblity of not having
|
|
returns on the end of a string.
|
|
|
|
Arguments:
|
|
|
|
lpStr - Supplies pointer to characters to be displayed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
static int fDebugNewline;
|
|
static int XNewSave;
|
|
|
|
LPSTR lpszOriginal;
|
|
LPSTR lpszDuplicate;
|
|
LPSTR lpszTmp;
|
|
|
|
XNewSave = XNew;
|
|
|
|
if (!FDebugString) {
|
|
CmdInsertInit();
|
|
fDebugNewline = TRUE;
|
|
} else {
|
|
XNew = XNewDebug;
|
|
YNew = YNewDebug;
|
|
}
|
|
|
|
// don't modify src string!!
|
|
|
|
|
|
lpszTmp = lpszDuplicate = lpszOriginal = _strdup(lpStr);
|
|
for (;;) {
|
|
if (*lpszTmp == 0) {
|
|
if (lpszTmp > lpszDuplicate) {
|
|
StringLogger(lpszDuplicate, TRUE, fSendRemote, TRUE);
|
|
}
|
|
break;
|
|
} else if (fDebugNewline) {
|
|
StringLogger("\r\n", FALSE, FALSE, TRUE);
|
|
--YNew;
|
|
fDebugNewline = FALSE;
|
|
} else if (*lpszTmp == '\n') {
|
|
*lpszTmp++ = 0;
|
|
StringLogger(lpszDuplicate, TRUE, fSendRemote, TRUE);
|
|
lpszDuplicate = lpszTmp;
|
|
fDebugNewline = TRUE;
|
|
StringLogger("\r\n", TRUE, fSendRemote, FALSE);
|
|
CmdInsertInit();
|
|
} else if (*lpszTmp == '\r') {
|
|
*lpszTmp++ = 0;
|
|
if (*lpszTmp == '\n') {
|
|
lpszTmp++;
|
|
}
|
|
StringLogger(lpszDuplicate, TRUE, fSendRemote, TRUE);
|
|
lpszDuplicate = lpszTmp;
|
|
fDebugNewline = TRUE;
|
|
StringLogger("\r\n", TRUE, fSendRemote, FALSE);
|
|
CmdInsertInit();
|
|
} else {
|
|
lpszTmp = CharNext( lpszTmp );
|
|
}
|
|
}
|
|
|
|
FDebugString = TRUE;
|
|
XNewDebug = XNew;
|
|
YNewDebug = YNew;
|
|
|
|
CmdInsertInit();
|
|
XNew = XNewSave;
|
|
|
|
free(lpszOriginal);
|
|
} /* CmdLogDebugString() */
|
|
|
|
|
|
VOID
|
|
CmdFileString(
|
|
LPSTR lpsz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to dump a string only to the log file.
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies string to be dumped to the file
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LogFileWrite( (LPBYTE) lpsz, strlen(lpsz) );
|
|
return;
|
|
} /* CmdFileString() */
|
|
|
|
BOOL
|
|
CmdAutoRunInit(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to set up the internal AutoRun variables
|
|
to read command from a file and get them processed
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
Assert( AutoRun == arSource || AutoRun == arCmdline );
|
|
|
|
if ((fpAutoRun = fopen(PszAutoRun, "rb")) == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
PostMessage(Views[cmdView].hwndClient, WU_AUTORUN, 0, 0);
|
|
|
|
return TRUE;
|
|
} /* CmdAutoRunInit() */
|
|
|
|
void
|
|
CmdAutoRunNext(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the next line from the auto run file and cause it to be processed
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
char rgchCmd[300];
|
|
char * ptr;
|
|
|
|
Assert(AutoRun != arNone);
|
|
|
|
if (AutoRun == arQuit || fpAutoRun == NULL) {
|
|
return;
|
|
}
|
|
|
|
while (fgets(rgchCmd, sizeof(rgchCmd), fpAutoRun) != NULL) {
|
|
|
|
/*
|
|
** Sanitize
|
|
*/
|
|
|
|
ptr = rgchCmd + strlen(rgchCmd);
|
|
while (ptr > rgchCmd) {
|
|
ptr = CharPrev(rgchCmd, ptr);
|
|
if ( *ptr != '\n' && *ptr != '\r') {
|
|
break;
|
|
}
|
|
*ptr = '\0';
|
|
}
|
|
|
|
/*
|
|
** Log the command into the command window
|
|
*/
|
|
|
|
if (cmdView != -1) {
|
|
Views[cmdView].X = 0;
|
|
}
|
|
CmdDoPrompt(TRUE, TRUE);
|
|
CmdLogFmt("%s\r\n", rgchCmd);
|
|
|
|
/*
|
|
** Do it, and return on asynch commands
|
|
*/
|
|
|
|
if (CmdDoLine(rgchCmd) == FALSE) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
AutoRun = arNone;
|
|
return;
|
|
|
|
} /* CmdAutoRunNext() */
|
|
|
|
|
|
LOGERR
|
|
LogSource(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
)
|
|
{
|
|
AutoRun = arSource;
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
PszAutoRun = _strdup(lpsz);
|
|
|
|
if (CmdAutoRunInit()) {
|
|
return LOGERROR_NOERROR;
|
|
} else {
|
|
CmdLogVar( ERR_File_Open, PszAutoRun );
|
|
free(PszAutoRun);
|
|
PszAutoRun = NULL;
|
|
return LOGERROR_QUIET;
|
|
}
|
|
}
|
|
|
|
|
|
LOGERR
|
|
LogFileOpen(
|
|
LPSTR lpsz,
|
|
DWORD fAppend
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will open up a log file name. By default if no
|
|
name is specified we will use "QCWIN.LOG" as the default name.
|
|
If fAppend is TRUE then we append to the end if the specified
|
|
file, else we create the requested file.
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies string containning the log file name
|
|
fAppend - Supplies TRUE if append to the specified file
|
|
|
|
Return Value:
|
|
|
|
log error code
|
|
|
|
--*/
|
|
{
|
|
char rgch[256];
|
|
|
|
CmdInsertInit();
|
|
/*
|
|
** Skip over any leading whitespace
|
|
*/
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
/*
|
|
** Setup a default name if none was specified
|
|
*/
|
|
|
|
if (*lpsz == 0) {
|
|
MakeFileNameFromProg(".LOG", rgch);
|
|
lpsz = rgch;
|
|
}
|
|
|
|
/*
|
|
** If a handle is already open then we will close that file
|
|
*/
|
|
|
|
if (hFileLog != INVALID_HANDLE_VALUE) {
|
|
CloseHandle( hFileLog );
|
|
}
|
|
|
|
/*
|
|
** Open a handle onto the requested file
|
|
*/
|
|
|
|
hFileLog = CreateFile( lpsz,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
fAppend ? OPEN_ALWAYS : CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, // | FILE_FLAG_WRITE_THROUGH,
|
|
NULL
|
|
);
|
|
|
|
if (fAppend) {
|
|
SetFilePointer(hFileLog, 0, NULL, FILE_END);
|
|
}
|
|
if (hFileLog == INVALID_HANDLE_VALUE) {
|
|
CmdLogVar(ERR_File_Open, lpsz);
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
/*
|
|
** All done -- return
|
|
*/
|
|
|
|
return LOGERROR_NOERROR;
|
|
} /* LogFileOpen() */
|
|
|
|
LOGERR
|
|
LogFileClose(
|
|
LPSTR lpUnused,
|
|
DWORD dwUnused
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close the log file
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
log error code
|
|
|
|
--*/
|
|
{
|
|
LOGERR lerr = LOGERROR_NOERROR;
|
|
CmdInsertInit();
|
|
EnterCriticalSection( &csLog );
|
|
if (hFileLog != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hFileLog);
|
|
hFileLog = INVALID_HANDLE_VALUE;
|
|
} else {
|
|
CmdLogVar(ERR_File_Not_Open);
|
|
lerr = LOGERROR_QUIET;
|
|
}
|
|
|
|
LeaveCriticalSection( &csLog );
|
|
return lerr;
|
|
} /* LogFileClose() */
|
|
|
|
|
|
LOGERR
|
|
LogOpenDoc(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
)
|
|
{
|
|
int ret;
|
|
|
|
CmdInsertInit();
|
|
|
|
|
|
// Skip over any leading whitespace
|
|
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
|
|
// Require a name
|
|
|
|
|
|
if (*lpsz == 0) {
|
|
return LOGERROR_UNKNOWN;
|
|
}
|
|
|
|
if (hFileLog != INVALID_HANDLE_VALUE) {
|
|
CloseHandle( hFileLog );
|
|
}
|
|
|
|
ret = AddFile(MODE_OPENCREATE,
|
|
DOC_WIN,
|
|
lpsz,
|
|
NULL,
|
|
NULL,
|
|
TRUE,
|
|
-1,
|
|
-1,
|
|
TRUE
|
|
);
|
|
|
|
return ret == -1 ? LOGERROR_UNKNOWN : LOGERROR_NOERROR;
|
|
|
|
} /* LogOpenDoc */
|
|
|
|
|
|
|
|
LOGERR
|
|
LogWaitForString(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Waits for a debug string
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies string containning the log file name
|
|
fAppend - not used
|
|
|
|
Return Value:
|
|
|
|
log error code
|
|
|
|
--*/
|
|
{
|
|
CmdInsertInit();
|
|
/*
|
|
** Skip over any leading whitespace
|
|
*/
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
if (*lpsz == 0) {
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
lpCmdString = _strdup(lpsz);
|
|
fWaitForDebugString = TRUE;
|
|
|
|
/*
|
|
** All done -- return
|
|
*/
|
|
|
|
return LOGERROR_ASYNC;
|
|
} /* LogWaitForString() */
|
|
|
|
|
|
LOGERR LogSleep(LPSTR lpsz, DWORD dwUnused)
|
|
/*++
|
|
Routine Description:
|
|
Waits for n seconds.
|
|
Arguments:
|
|
lpsz - seconds to sleep
|
|
fAppend - not used
|
|
Return Value:
|
|
log error code
|
|
--*/
|
|
{
|
|
CmdInsertInit();
|
|
/*
|
|
** Skip over any leading whitespace
|
|
*/
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
if (*lpsz == 0) {
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
Sleep( atol(lpsz) * 1000 );
|
|
|
|
/*
|
|
** All done -- return
|
|
*/
|
|
|
|
return LOGERROR_NOERROR;
|
|
} /* LogSleep() */
|
|
|
|
|
|
LOGERR LogBreak(LPSTR lpsz, DWORD dwUnused)
|
|
/*++
|
|
Routine Description:
|
|
Call AsyncStop() to halt debuggee.
|
|
Arguments:
|
|
lpsz - not used
|
|
fAppend - not used
|
|
Return Value:
|
|
log error code
|
|
--*/
|
|
{
|
|
CmdInsertInit();
|
|
|
|
AsyncStop();
|
|
|
|
return LOGERROR_NOERROR;
|
|
} /* LogBreak() */
|
|
|
|
|
|
LOGERR
|
|
LogDotHelp(
|
|
LPSTR lpsz
|
|
)
|
|
{
|
|
int i;
|
|
CmdInsertInit();
|
|
for (i = 0; i < NDOTS; i++) {
|
|
CmdLogFmt("%s %s\r\n", DotTable[i].lpName, DotTable[i].lpDesc);
|
|
}
|
|
return LOGERROR_NOERROR;
|
|
}
|
|
|
|
|
|
LOGERR
|
|
LogDotCommand(
|
|
LPSTR lpsz
|
|
)
|
|
{
|
|
int i;
|
|
int l;
|
|
LPPD lppd;
|
|
LPTD lptd;
|
|
BOOL fNoError = FALSE;
|
|
XOSD xosd = xosdUnknown;
|
|
DWORD dw;
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
if (!*lpsz) {
|
|
return LOGERROR_UNKNOWN;
|
|
}
|
|
|
|
if (*lpsz == '?') {
|
|
|
|
LogDotHelp(lpsz + 1);
|
|
fNoError = TRUE;
|
|
|
|
} else if (_strnicmp(lpsz, "help", (size_t) 4) == 0) {
|
|
|
|
LogDotHelp(lpsz + 4);
|
|
fNoError = TRUE;
|
|
|
|
} else if (!(g_contWorkspace_WkSp.m_bKernelDebugger && !_strnicmp(lpsz, "crash", (size_t) 5)) ) {
|
|
|
|
|
|
// If we are kernel debugging, the .crash should be passed to the EM,
|
|
// else try to find the appropiate handler
|
|
|
|
|
|
for (i = 0; i < NDOTS; i++) {
|
|
l = strlen(DotTable[i].lpName);
|
|
if (_strnicmp(lpsz, DotTable[i].lpName, l) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i < NDOTS) {
|
|
return (*DotTable[i].lpfnHandler)(lpsz+l, DotTable[i].dwArg);
|
|
}
|
|
}
|
|
|
|
// Pass unrecognized commands and "?" or "help" to the EM:
|
|
|
|
lppd = LppdCur;
|
|
lptd = LptdCur;
|
|
if (!lppd || !lppd->hpid) {
|
|
lppd = LppdFirst;
|
|
lptd = NULL;
|
|
}
|
|
if (lppd && lppd->hpid) {
|
|
xosd = OSDSystemService(lppd->hpid,
|
|
lptd? lptd->htid : 0,
|
|
(SSVC) ssvcCustomCommand,
|
|
(LPVOID)lpsz,
|
|
strlen(lpsz)+1,
|
|
&dw
|
|
);
|
|
}
|
|
|
|
return (fNoError || xosd == xosdNone)? LOGERROR_NOERROR : LOGERROR_UNKNOWN;
|
|
}
|
|
|
|
LOGERR
|
|
LogOptions(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
.opt command
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies command line tail
|
|
|
|
Return Value:
|
|
|
|
LOGERROR code
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
int n;
|
|
char szToken[MAX_USER_LINE];
|
|
|
|
CmdInsertInit();
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
if (!*lpsz) {
|
|
for (i = 0; i < NOPTS; i++) {
|
|
(*OptionTable[i].lpfnHandler)(OptionTable[i].lpData,
|
|
OptionTable[i].cbSize,
|
|
szToken,
|
|
FALSE);
|
|
CmdLogFmt("%-21s %s\r\n", OptionTable[i].lpName, szToken);
|
|
}
|
|
return LOGERROR_NOERROR;
|
|
}
|
|
|
|
n = CPCopyToken(&lpsz, szToken);
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
for (i = 0; i < NOPTS; i++) {
|
|
if (_stricmp(OptionTable[i].lpName, szToken) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= NOPTS) {
|
|
CmdLogVar(ERR_Invalid_Option);
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
// special for help:
|
|
if (i == 0) {
|
|
(*OptionTable[i].lpfnHandler)(OptionTable[i].lpData,
|
|
OptionTable[i].cbSize,
|
|
lpsz,
|
|
TRUE);
|
|
return LOGERROR_NOERROR;
|
|
|
|
} else if (!*lpsz) {
|
|
(*OptionTable[i].lpfnHandler)(OptionTable[i].lpData,
|
|
OptionTable[i].cbSize,
|
|
szToken,
|
|
FALSE);
|
|
CmdLogFmt("%-21s %s\r\n", OptionTable[i].lpName, szToken);
|
|
return LOGERROR_NOERROR;
|
|
} else if ((*OptionTable[i].lpfnHandler)(OptionTable[i].lpData,
|
|
OptionTable[i].cbSize,
|
|
lpsz,
|
|
TRUE)) {
|
|
return LOGERROR_NOERROR;
|
|
} else {
|
|
return LOGERROR_QUIET;
|
|
}
|
|
}
|
|
|
|
|
|
LOGERR
|
|
LogRadix(
|
|
LPSTR lpsz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to change the display and input radix for
|
|
the system.
|
|
|
|
Arguments:
|
|
|
|
lpsz - String with the command
|
|
|
|
Return Value:
|
|
|
|
log error code
|
|
|
|
--*/
|
|
{
|
|
int err;
|
|
int cch;
|
|
int i;
|
|
|
|
CmdInsertInit();
|
|
|
|
/*
|
|
** Check for no arguement
|
|
*/
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
if (*lpsz == 0) {
|
|
CmdLogFmt("%d\r\n", radix);
|
|
return LOGERROR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
** An argument -- must be a number in base 10
|
|
*/
|
|
|
|
i = (int) CPGetInt(lpsz, &err, &cch);
|
|
if (err) {
|
|
return LOGERROR_UNKNOWN;
|
|
}
|
|
if (i != 8 && i != 10 && i != 16) {
|
|
CmdLogVar(ERR_Radix_Invalid);
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
UpdateRadix(i);
|
|
|
|
return LOGERROR_NOERROR;
|
|
} /* LogRadix() */
|
|
|
|
|
|
LOGERR
|
|
LogSetErrorLevel(
|
|
LPSTR lpsz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set error reporting and break levels for RIPs.
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies tail of command, after "se"
|
|
|
|
Return Value:
|
|
|
|
LOGERROR code
|
|
|
|
--*/
|
|
{
|
|
int i;
|
|
char chCmd;
|
|
int err, cch;
|
|
|
|
CmdInsertInit();
|
|
|
|
chCmd = *lpsz++;
|
|
|
|
if (!strchr( (PBYTE) "bBwW", chCmd)) {
|
|
return LOGERROR_UNKNOWN;
|
|
}
|
|
|
|
/*
|
|
** Check for no argument
|
|
*/
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
if (*lpsz == 0) {
|
|
CmdLogVar(DBG_Notify_Break_Levels, ulRipNotifyLevel, ulRipBreakLevel);
|
|
return LOGERROR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
** An argument -- must be a number in base 10
|
|
*/
|
|
|
|
i = (int) CPGetInt(lpsz, &err, &cch);
|
|
if (err) {
|
|
return LOGERROR_UNKNOWN;
|
|
}
|
|
if (i < 0 || i > 3) {
|
|
CmdLogVar(ERR_Error_Level_Invalid);
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
if (chCmd == 'w' || chCmd == 'W') {
|
|
ulRipNotifyLevel = (ULONG)i;
|
|
} else {
|
|
ulRipBreakLevel = (ULONG)i;
|
|
if ((ULONG)i > ulRipNotifyLevel) {
|
|
ulRipNotifyLevel = (ULONG)i;
|
|
}
|
|
}
|
|
|
|
return LOGERROR_NOERROR;
|
|
} /* LogSetErrorLevel() */
|
|
|
|
|
|
LOGERR
|
|
LogReload(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
)
|
|
{
|
|
LPPD lppd = NULL;
|
|
LPTD lptd = NULL;
|
|
XOSD xosd = xosdUnknown;
|
|
MSG msg;
|
|
PIOCTLGENERIC pig;
|
|
DWORD dw;
|
|
|
|
|
|
IsKdCmdAllowed();
|
|
|
|
if (DebuggeeActive()) {
|
|
lppd = LppdCur;
|
|
lptd = LptdCur;
|
|
if (!lppd || !lppd->hpid) {
|
|
Assert(LppdFirst);
|
|
lppd = LppdFirst;
|
|
lptd = lppd->lptdList;
|
|
}
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
|
|
if (lppd && lppd->hpid) {
|
|
pig = (PIOCTLGENERIC)malloc(strlen(lpsz) + 1 + sizeof(IOCTLGENERIC));
|
|
if (!pig) {
|
|
return FALSE;
|
|
}
|
|
pig->ioctlSubType = IG_RELOAD;
|
|
pig->length = strlen(lpsz) + 1;
|
|
strcpy((LPSTR)pig->data, lpsz);
|
|
xosd = OSDSystemService( lppd->hpid,
|
|
lptd->htid,
|
|
(SSVC) ssvcGeneric,
|
|
(LPV)pig,
|
|
strlen(lpsz) + 1 + sizeof(IOCTLGENERIC),
|
|
&dw
|
|
);
|
|
free( pig );
|
|
}
|
|
}
|
|
|
|
if (xosd == xosdNone) {
|
|
while (GetMessage( &msg, NULL, 0, 0 )) {
|
|
ProcessQCQPMessage( &msg );
|
|
if (WaitForSingleObject( hEventIoctl, 0 ) == WAIT_OBJECT_0) {
|
|
|
|
// Let's add this in so that we don't confuse anyone.
|
|
|
|
if (g_contWorkspace_WkSp.m_bKernelDebugger) {
|
|
CmdLogFmt( "Finished re-loading kernel modules\n" );
|
|
} else {
|
|
CmdLogFmt( "Finished re-loading user modules\n" );
|
|
}
|
|
|
|
ResetEvent( hEventIoctl );
|
|
|
|
|
|
// Notify the back-end that new symbols have been loaded
|
|
|
|
OSDNewSymbolsLoaded( lppd->hpid );
|
|
break;
|
|
}
|
|
}
|
|
|
|
UpdateDebuggerState( UPDATE_CONTEXT );
|
|
}
|
|
|
|
return (xosd == xosdNone) ? LOGERROR_NOERROR : LOGERROR_UNKNOWN;
|
|
}
|
|
|
|
|
|
|
|
LOGERR
|
|
LogList(
|
|
LPSTR lpsz,
|
|
DWORD dwUnused
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine prints mixed mode source & disassembly for a
|
|
address that is computed from the expression in the string
|
|
passed in. If the string is null then the list starts where
|
|
the last one left off.
|
|
|
|
Wesley Witt (wesw) - 29-May-1994
|
|
|
|
Arguments:
|
|
|
|
lpsz - Supplies the expression
|
|
dwUnused - as it says its unused
|
|
|
|
Return Value:
|
|
|
|
Log error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
#define MAX_LINES 10
|
|
INT cch;
|
|
static ADDR addr = {0};
|
|
ADDR addrT;
|
|
ADDR addrN;
|
|
SDI sds;
|
|
LPSTR p;
|
|
CHAR buf[256];
|
|
LPSTR lpch;
|
|
INT cb;
|
|
DWORD i;
|
|
BOOL SourceFound;
|
|
CHAR SrcFname[MAX_PATH];
|
|
CHAR SrcFnameN[MAX_PATH];
|
|
DWORD lineno;
|
|
DWORD dwLineno = 0;
|
|
DWORD lastLineno = 0;
|
|
INT doc = 0;
|
|
LPLINEREC lr;
|
|
LPBLOCKDEF bd;
|
|
SHOFF cbLn = 0;
|
|
SHOFF dbLn;
|
|
|
|
|
|
CmdInsertInit();
|
|
IsKdCmdAllowed();
|
|
|
|
if ( !DebuggeeActive() ) {
|
|
|
|
// No debuggee - nothing to do.
|
|
|
|
CmdLogVar(ERR_Debuggee_Not_Alive);
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
|
|
|
|
// get the address for the user's expression
|
|
|
|
lpsz = CPSkipWhitespace(lpsz);
|
|
if (*lpsz) {
|
|
if (CPGetAddress( lpsz,
|
|
&cch,
|
|
&addr,
|
|
radix,
|
|
&CxfIp,
|
|
fCaseSensitive,
|
|
g_contWorkspace_WkSp.m_bMasmEval ) != CPNOERROR) {
|
|
CmdLogVar( ERR_AddrExpr_Invalid );
|
|
return LOGERROR_QUIET;
|
|
}
|
|
} else if (addr.addr.off == 0) {
|
|
addr = CxfIp.cxt.addr;
|
|
}
|
|
|
|
for (i=0; i<MAX_LINES; i++) {
|
|
|
|
|
|
// create a fixedup and unfixedup address
|
|
|
|
addrT = addr;
|
|
SYUnFixupAddr(&addr);
|
|
SYFixupAddr(&addrT);
|
|
|
|
|
|
// assume we cannot find any source
|
|
|
|
SourceFound = FALSE;
|
|
|
|
|
|
// locate the source file and line number for this address
|
|
|
|
if (!GetSourceFromAddress( &addr, SrcFname, sizeof(SrcFname), &lineno )) {
|
|
goto disasm;
|
|
}
|
|
|
|
|
|
// locate the document for the found source file name
|
|
|
|
if (!FindDoc( SrcFname, &doc, TRUE )) {
|
|
|
|
// the document was not found so lets map it in and
|
|
// create a document record
|
|
|
|
// Not user activated.
|
|
if (SrcMapSourceFilename( SrcFname, sizeof(SrcFname),
|
|
SRC_MAP_OPEN, FindDoc1,
|
|
// Not user activated
|
|
FALSE) < 0) {
|
|
goto disasm;
|
|
}
|
|
|
|
|
|
// locate the document for the found source file name
|
|
|
|
if (!FindDoc( SrcFname, &doc, TRUE )) {
|
|
goto disasm;
|
|
}
|
|
}
|
|
|
|
|
|
// adjust the line number and save it away in a dword
|
|
|
|
lineno = min(max(1, (int)lineno), (int)Docs[doc].NbLines) - 1;
|
|
dwLineno = lineno;
|
|
// kcarlos - BUGBUG -> BUGCAST
|
|
//if (!FirstLine( doc, &lr, &dwLineno, &bd )) {
|
|
if (!FirstLine( doc, &lr, (PLONG) &dwLineno, &bd )) {
|
|
goto disasm;
|
|
}
|
|
|
|
|
|
// this call is used only to get the code size for the
|
|
// current line number
|
|
|
|
if (!SLLineFromAddr ( &addr, &lineno, &cbLn, &dbLn )) {
|
|
goto disasm;
|
|
}
|
|
|
|
|
|
// print the source text
|
|
|
|
CmdLogFmt( "%4d: %s\n", dwLineno, lr->Text );
|
|
|
|
|
|
// set the source found flag to success
|
|
|
|
SourceFound = TRUE;
|
|
|
|
disasm:
|
|
|
|
// this is where the code is unassembled
|
|
// if there was no source found the this loop will
|
|
// unassemble one instrustion and move on to the next address
|
|
|
|
|
|
|
|
// set the disasm options to the user's settings
|
|
|
|
sds.dop = (g_contWorkspace_WkSp.m_dopDisAsmOpts & ~(0x800)) | dopAddr | dopOpcode | dopOperands;
|
|
|
|
|
|
// use the current source address
|
|
|
|
sds.addr = addrT;
|
|
|
|
do {
|
|
|
|
// call the disassm routine in the EM
|
|
|
|
if (OSDUnassemble( LppdCur->hpid, LptdCur->htid, &sds ) != xosdNone) {
|
|
CmdLogFmt( "Could not unassemble code for address 0x%08x\n", sds.addr.addr.off );
|
|
return LOGERROR_QUIET;
|
|
}
|
|
|
|
|
|
// format the assm code
|
|
|
|
p = &buf[0];
|
|
*p = 0;
|
|
|
|
if (sds.ichAddr != -1) {
|
|
sprintf(p, "%s ", &sds.lpch[sds.ichAddr]);
|
|
p += strlen(p);
|
|
}
|
|
cb = strlen(&sds.lpch[sds.ichAddr]) + 2;
|
|
|
|
if (sds.ichBytes != -1) {
|
|
lpch = sds.lpch + sds.ichBytes;
|
|
|
|
//v-vadimp - this breaks bundle byte string display on IA64
|
|
|
|
if (LppdCur->mptProcessorType != mptia64) {
|
|
while (strlen(lpch) > 16) {
|
|
sprintf(p, "%16.16s\r\n%*s", lpch, cb, " ");
|
|
p += strlen(p);
|
|
lpch += 16;
|
|
}
|
|
}
|
|
cb = 17 - strlen(lpch);
|
|
sprintf(p, "%-17s", lpch);
|
|
p += strlen(p);
|
|
}
|
|
|
|
if (LppdCur->mptProcessorType == mptia64 && sds.ichPreg != -1) {
|
|
sprintf(p, "%-5s", &sds.lpch[sds.ichPreg]);
|
|
p += strlen(p);
|
|
}
|
|
|
|
sprintf(p, "%-12s ", &sds.lpch[sds.ichOpcode]);
|
|
p += strlen(p);
|
|
|
|
if (sds.ichOperands != -1) {
|
|
sprintf(p, "%-25s ", &sds.lpch[sds.ichOperands]);
|
|
p += strlen(p);
|
|
} else if (sds.ichComment != -1) {
|
|
sprintf(p, "%25s ", " ");
|
|
p += strlen(p);
|
|
}
|
|
|
|
if (sds.ichComment != -1) {
|
|
sprintf(p, "%s", &sds.lpch[sds.ichComment]);
|
|
p += strlen(p);
|
|
}
|
|
|
|
|
|
// print the formatted code
|
|
|
|
CmdLogFmt( "%s\r\n", buf );
|
|
|
|
|
|
// if there was no source found then bail out
|
|
|
|
if (!SourceFound) {
|
|
break;
|
|
}
|
|
} while (sds.addr.addr.off <= addrT.addr.off + cbLn);
|
|
|
|
|
|
// setup for the next source line
|
|
|
|
addr = sds.addr;
|
|
|
|
|
|
// this causes the dead source, ie source that did not generate
|
|
// any code, to be printed.
|
|
|
|
if (i < MAX_LINES-1) {
|
|
|
|
// start at the last ending address
|
|
|
|
addrN = addr;
|
|
|
|
|
|
// the dead source is printed when the source file name for the
|
|
// next address is the same as the last address and ...
|
|
|
|
if ((GetSourceFromAddress( &addrN, SrcFnameN, sizeof(SrcFnameN), &lineno )) &&
|
|
(_stricmp(SrcFname, SrcFnameN) == 0)) {
|
|
|
|
// the line number is more that one greater
|
|
|
|
lineno = min(max(1, (int)lineno), (int)Docs[doc].NbLines) - 1;
|
|
if (lineno > dwLineno + 1) {
|
|
|
|
// enumerate all the dead source lines and print them
|
|
|
|
while (lineno > dwLineno) {
|
|
// kcarlos - BUGBUG -> BUGCAST
|
|
//if (NextLine( doc, &lr, &dwLineno, &bd )) {
|
|
if (NextLine( doc, &lr, (PLONG) &dwLineno, &bd )) {
|
|
CmdLogFmt( "%4d: %s\n", dwLineno, lr->Text );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// return success
|
|
|
|
return LOGERROR_NOERROR;
|
|
}
|
|
|
|
BOOL
|
|
NotifyDmOfProcessorChange(
|
|
DWORD Processor
|
|
)
|
|
{
|
|
XOSD xosd = xosdUnknown;
|
|
PIOCTLGENERIC pig;
|
|
DWORD dw;
|
|
|
|
|
|
if (!g_contWorkspace_WkSp.m_bKernelDebugger) {
|
|
return FALSE;
|
|
}
|
|
|
|
pig = (PIOCTLGENERIC)malloc(sizeof(ULONG) + sizeof(IOCTLGENERIC));
|
|
if (!pig) {
|
|
return FALSE;
|
|
}
|
|
pig->ioctlSubType = IG_CHANGE_PROC;
|
|
pig->length = sizeof(ULONG);
|
|
((PULONG)pig->data)[0] = Processor;
|
|
xosd = OSDSystemService( LppdCur->hpid,
|
|
NULL,
|
|
(SSVC) ssvcGeneric,
|
|
(LPV)pig,
|
|
pig->length + sizeof(IOCTLGENERIC),
|
|
&dw
|
|
);
|
|
free( pig );
|
|
return xosd == xosdNone;
|
|
}
|