Windows2000/private/windbg64/windbg/codemgr.c
2020-09-30 17:12:32 +02:00

6130 lines
159 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
codemgr.c
Abstract:
This file contains the majority of the interface code to the OSDebug API
Author:
Jim Schaad (jimsch)
Griffith Wm. Kadnier (v-griffk) 16-Jan-1993
Environment:
Win32 user mode
--*/
#include "precomp.h"
#pragma hdrstop
#include "dbugexcp.h"
#define MAX_MAPPED_ROOTS (5)
#ifdef __cplusplus
extern "C" {
#endif
extern AVS Avs;
#ifdef __cplusplus
} // extern "C" {
#endif
#include "include\cntxthlp.h"
extern HWND GetWatchHWND(void);
typedef struct _BROWSESTRUCT {
LRESULT Rslt;
DWORD DlgId;
DLGPROC DlgProc;
LPSTR pszFileName;
DWORD FnameSize;
PFIND_SYM_FILE pFindSymFileData;
} BROWSESTRUCT, *LPBROWSESTRUCT;
LRESULT SendMessageNZ (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
INT_PTR WINAPI DlgFileSearchResolve(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
extern CVF Cvf;
extern CRF Crf;
extern KNF Knf;
extern DBF Dbf;
extern EXCEPTION_LIST *DefaultExceptionList;
EESTATUS PASCAL MELoadEEParse(const char FAR *, EERADIX, SHFLAG, PHTM, LPDWORD);
XOSD OSDAPI OSDCallbackFunc(DWORD, HPID, HTID, DWORD64, DWORD64);
DBGSTATE DbgState = ds_normal;
CXF CxfIp;
HTL Htl = 0; /* Handle to transport layer */
HEM Hem = 0; /* Handle to execution module */
HPID HpidBase; /* Handle to base PID */
HTID HtidBase; /* Handle to base TID */
LPPD LppdFirst = NULL;
extern LPSHF Lpshf; /* Pointer to SH entry structure */
ATOM * RgAtomMaskedNames = NULL; /* Names of masked source files */
int CMacAtomMasked = 0; /* Size of array */
int CAtomMasked = 0; /* Count of atoms in array */
struct MpPair {
ATOM atomSrc;
ATOM atomTarget;
} * RgAtomMappedNames = NULL; /* Mapping from source to target names */
int CMacAtomMapped = 0; /* Size of array */
int CAtomMapped = 0; /* Count of mappings in array */
// Structure to map one root to another
struct MRootPair {
DWORD dwSrcLen;
LPSTR lpszSrcRoot;
LPSTR lpszTargetRoot;
} RgMappedRoots[MAX_MAPPED_ROOTS];
UINT CMappedRoots = 0;
// When a source file can be mapped to one or more open documents,
// the user may choose of to use a currently loaded document in
// which case the return value is >=0. If the user chooses to use
// the source file that was specified by the debug information, then a value of 'MATCHLIST_USEFILEFROMIMAGE' is returned.
// If the user decides not to use any of these values then 'MATCHLIST_NONEMATCHED' is returned.
#define MATCHLIST_NONEMATCHED (-1)
#define MATCHLIST_USEFILEFROMIMAGE (-2)
static INT MatchedList[MAX_DOCUMENTS];
static LONG lMatchCnt = 0;
static LONG lMatchIdx = 0;
static CHAR szFSSrcName[MAX_PATH];
static BOOL FAddToSearchPath = FALSE;
static BOOL FAddToRootMap = FALSE;
static CHAR szBrowsePrompt[256];
static CHAR szBrowseFname[256];
static BOOL fBrowseAnswer;
/*
** Expression Evaluator items
*/
CI Ci = { sizeof(CI), 0, &Cvf, &Crf };
EXF Exf = {NULL, NULL, MELoadEEParse};
EI Ei = {
sizeof(EI), 0, &Exf
};
// If it isn't large enough, windbg can wedge during startup
// since it only has one thread, and none of the items in
// the queue can possibly be removed.
// This will usually occur if the back-end generates a lot of
// text output to the command window via DPRINT.
#ifdef DBG
#define QUEUE_SIZE (1024 * 100)
#else
#define QUEUE_SIZE (1024 * 10)
#endif
static DWORD64 RgbDbgMsgBuffer[QUEUE_SIZE];
static int iDbgMsgBufferFront = 0;
static int iDbgMsgBufferBack = 0;
static CRITICAL_SECTION csDbgMsgBuffer;
BOOL FKilling = FALSE;
HWND HwndDebuggee = NULL;
/********* Prototypes ****/
BOOL FLoadEmTl(BOOL *pfReconnecting);
BOOL RootNameIsMapped(LPSTR, LPSTR, UINT);
BOOL SrcNameIsMasked(ATOM);
BOOL SrcNameIsMapped(ATOM, LSZ, UINT);
INT MatchOpenedDoc(LPSTR, UINT);
BOOL SrcSearchOnPath(LSZ, UINT, BOOL);
BOOL SrcSearchOnRoot(LSZ, UINT);
BOOL SrcBrowseForFile(LSZ, UINT);
BOOL MiscBrowseForFile(
LSZ lpb,
UINT cb,
LSZ lpDir,
UINT cchDir,
int nDefExt,
int nIdDlgTitle,
void (*fnSetMapped)(LSZ, LSZ),
LPOFNHOOKPROC lpfnHook,
int nExplorerExtensionTemplateName
);
VOID SrcSetMasked(LSZ);
VOID SrcSetMapped(LSZ, LSZ);
VOID ExeSetMapped(LSZ, LSZ);
void EnsureFocusDebuggee( void );
VOID CmdMatchOpenedDocPrompt(BOOL, BOOL);
BOOL CmdMatchOpenedDocInputString(LPSTR);
VOID InitCodemgr(void)
/*++
Routine Description:
Initialize private data for Codemgr.c
--*/
{
InitializeCriticalSection(&csDbgMsgBuffer);
}
LRESULT SendMessageNZ(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
/*++
Routine Description:
Call SendMessage() if and only if the handle is non-zero
Arguments:
Exactly the same as the Win32 SendMessage() call.
Return Value:
The return from the SendMessage() or 0 if we didn't send it.
--*/
{
if (hWnd) {
return( SendMessage(hWnd, uMsg, wParam, lParam) );
}
else {
return(0);
}
}
BOOL PASCAL DbgCommandOk(void)
/*++
Routine Description:
This routine is called before issuing any debugger commands.
it will validate will all the appropriate windows that no editing commands are current in progess which would cause the debugger to abort out.
Return Value:
None.
--*/
{
return TRUE;
}/* DbgOk() */
BOOL PASCAL DbgFEmLoaded(void)
{
return (Hem != 0);
}/* DbgFEmLoaded() */
void PASCAL Go(void)
{
EXOP exop = {0};
if (OSDGo(LppdCur->hpid, LptdCur->htid, &exop) == xosdNone) {
if (LppdCur->pstate == psPreRunning) {
SetPTState(psInvalidState, tsRunning);
} else {
SetPTState(psRunning, tsRunning);
LppdCur->fHasRun = TRUE;
}
EnsureFocusDebuggee();
}
}/* Go() */
BOOL PASCAL GoUntil(PADDR paddr)
/*++
Routine Description:
Set temporary breakpoint and go
Modelled after go_until in CV0.C
--*/
{
HBPT hBpt;
if (BPSetTmp(paddr, LppdCur->hpid, LptdCur->htid, &hBpt) != BPNOERROR) {
return FALSE;
}
LptdCur->fDisasm = TRUE;
AuxPrintf(3, "GoUntil - doing the go!!!, BP set at 0x%X:0x%I64X", GetAddrSeg(*paddr), GetAddrOff(*paddr));
Go();
return TRUE;
}/* GoUntil() */
int Step(int Overcalls, int StepMode)
/*++
Routine Description:
Single step at source or assembler code level.
--*/
{
DWORD wLn = 0;
SHOFF cbLn = 0;
SHOFF dbLn = 0;
CXT cxt;
ADDR addr;
ADDR addr2;
EXOP exop = {0};
if (!DebuggeeAlive()) {
AuxPrintf(1, "STEP - child is dead");
return FALSE;
}
exop.fStepOver = (UCHAR) Overcalls;
switch (StepMode) {
case ASMSTEPPING: // step a machine instruction
if (OSDSingleStep(LppdCur->hpid, LptdCur->htid, &exop) != xosdNone) {
return FALSE;
} else {
// it is possible to do many steps before entering
// the real debuggee. Set the stop at entry flag
// to ensure that we stop after leaving the loader.
if (!LppdCur->fHasRun) {
LppdCur->fStopAtEntry = TRUE;
}
SetPTState(psRunning, tsRunning);
EnsureFocusDebuggee();
return TRUE;
}
case SRCSTEPPING: // step a source line
// If this is an initial step, the breakpoint
// will be resolved at the entrypoint event.
if (!LppdCur->fHasRun ) {
LppdCur->fInitialStep = 1;
Go();
return TRUE;
}
OSDGetAddr(LppdCur->hpid, LptdCur->htid, adrPC, &addr);
if (!ADDR_IS_LI( addr ) ) {
SYUnFixupAddr ( &addr );
}
SHHmodFrompCxt(&cxt) = (HMOD) NULL;
SHSetCxt(&addr, &cxt);
if (!SHHmodFrompCxt(&cxt) || !SLLineFromAddr ( &addr, &wLn, &cbLn, &dbLn )) {
exop.fInitialBP = TRUE;
if (OSDSingleStep(LppdCur->hpid, LptdCur->htid, &exop) != xosdNone) {
return FALSE;
} else {
SetPTState(psRunning, tsRunning);
EnsureFocusDebuggee();
return TRUE;
}
} else {
Assert( cbLn >= dbLn );
if (cbLn < dbLn) {
return FALSE;
}
SYFixupAddr(&addr);
addr2 = addr;
GetAddrOff(addr2) += cbLn - dbLn;
exop.fInitialBP = TRUE;
if (OSDRangeStep(LppdCur->hpid, LptdCur->htid, &addr, &addr2, &exop) != xosdNone) {
return FALSE;
} else {
SetPTState(psRunning, tsRunning);
EnsureFocusDebuggee();
return TRUE;
}
}
default:
Assert(FALSE);
break;
}
return FALSE;
} /* Step() */
BOOL PASCAL DebuggeeRunning(void)
/*++
Routine Description:
This will return TRUE iff the child debuggee current thread is actually executing code.
Return Value:
TRUE if the debuggee is currently running, FALSE otherwise
--*/
{
// The name of the function (and of SetDebugeeRunning) is ambiguous. Does this mean the current process/thread is
// running? Or any thread in the current process? Or any process being debugged?
// From the way people use the function seems like its
// semantics are "Current thread is running" so it is implemented that way.
if ( LptdCur != NULL ) {
return (LptdCur->tstate == tsRunning);
}
return FALSE;
} /* DebuggeeRunning() */
BOOL PASCAL IsProcRunning(LPPD lppd)
/*++
Routine Description:
Alternative to DebuggeeRunning(); determines whether process is actually running, not suspended.
Arguments:
lppd - Supplies pointer to process descriptor
Return Value:
TRUE if running, FALSE if not
--*/
{
LPTD lptd;
if (lppd == NULL) {
return FALSE;
}
if (!DebuggeeActive()) {
return FALSE;
}
for (lptd = lppd->lptdList; lptd; lptd = lptd->lptdNext) {
if (lptd->tstate != tsRunning) {
return FALSE;
}
}
return TRUE;
}
BOOL PASCAL IsProcStopped(LPPD lppd)
/*++
Routine Description:
Not precisely the opposite of IsProcRunning - this returns TRUE only if an existing thread is stopped, ignoring any thread which is being created.
Arguments:
lppd - Supplies pointer to process descriptor
Return Value:
TRUE if running, FALSE if not
--*/
{
LPTD lptd;
if (lppd == NULL) {
return FALSE;
}
if (!DebuggeeActive()) {
return FALSE;
}
for (lptd = lppd->lptdList; lptd; lptd = lptd->lptdNext) {
if (lptd->tstate != tsRunning && lptd->tstate != tsPreRunning) {
return TRUE;
}
}
return FALSE;
}
/*
UI oriented general purpose functions for debugging sessions
*/
/*** GetExecutableFilename
** Synopsis:
** Entry:
** Returns:
** Address of passed buffer if successful, NULL otherwise
** Description:
** Gets the full path name of the current executable file -
** from the project if there is one, or from the current
** source file otherwise.
*/
PSTR PASCAL GetExecutableFilename(PSTR pszExecutable, UINT uSize)
{
Assert(pszExecutable);
Assert(uSize > 0);
PCSTR pszProgramName = g_Windbg_WkSp.GetCurrentProgramName(FALSE);
if (pszProgramName) {
strncpy(pszExecutable, pszProgramName, uSize);
pszExecutable[uSize-1] = NULL;
return pszExecutable;
} else {
return NULL;
}
}
void PASCAL BuildRelativeFilename(LPSTR rgchSource, LPSTR rgchBase, LPSTR rgchDest, int cbDest)
/*++
Routine Description:
Given a filename and base directory build the fully specified filename.
Note that BaseDir can be a fully qualified path name
(ie including filename) or just the directory. If just the directory is passed it should contain the trailing '\\'.
Arguments:
rgchSource - Supplies the source name to build relative path for
rgchBase - Supplies the Base directory to build path relative to
rgchDest - Supplies a Buffer to place the absolute path name to
cbDest - Supplies the Length of buffer
--*/
{
char * pchDest;
char * pchSource = rgchSource;
char * pchBase = rgchBase;
int iDriveCur = _getdrive();
char rgchDirCur[_MAX_PATH];
int iDriveSrc;
_getcwd(rgchDirCur, sizeof(rgchDirCur));
/*
* Check to see if either of the passed in directories have
* drives specified.
*/
if (!IsDBCSLeadByte(pchSource[0]) && pchSource[1] == ':') {
iDriveSrc = toupper(pchSource[0]) - 'A' + 1;
pchSource += 2;
if (_chdrive( iDriveSrc ) == -1) {
goto nextDrive;
}
pchBase = 0;
} else {
nextDrive:
if (!IsDBCSLeadByte(pchBase[0]) && pchBase[1] == ':') {
iDriveSrc = toupper(pchBase[0]) - 'A' + 1;
pchBase += 2;
if (_chdrive( iDriveSrc ) == -1) {
iDriveSrc = iDriveCur;
}
} else {
iDriveSrc = iDriveCur;
}
}
rgchDest[0] = 'A' + iDriveSrc - 1;
rgchDest[1] = ':';
rgchDest[2] = '\\';
pchDest = &rgchDest[2];
/*
* Now check to see if either base is based at the root. If not
* then we need to the get current directory for that drive.
*/
if ((pchSource[0] == '\\') || (pchSource[0] == '/')) {
pchSource ++;
pchBase = NULL;
cbDest -= 3;
} else if ((pchBase != NULL) && ((pchBase[0] == '\\') || (pchBase[0] == '/'))) {
pchBase ++;
cbDest -= 3;
} else {
Dbg(_getcwd(rgchDest, cbDest-1) != NULL);
pchDest = CharPrev(rgchDest, rgchDest + strlen(rgchDest));
if (*pchDest != '\\') {
if (IsDBCSLeadByte(*pchDest)) {
pchDest += 2;
} else {
pchDest++;
}
*pchDest = '\\';
}
cbDest = (int) (cbDest - (pchDest - rgchDest + 1));
}
/*
* Now lets copy from the base to the destination looking for
* any funnyness in the path being copied.
*/
if (pchBase != NULL) {
char ch;
char * pch = CharPrev(pchBase, pchBase + strlen(pchBase));
if (pch == pchBase) {
// Make sure the result is same as US code.
pch = pchBase - 1;
}
while ((pch >= pchBase) && ((*pch != '\\') && (*pch != '/'))) {
if ((pch = CharPrev(pchBase, pch)) == pchBase) {
// Make sure the result is same as US code.
pch--;
}
}
if ((*pch == '\\') || (*pch == '/')) {
pch++;
ch = *pch;
*pch = 0;
} else {
ch = *(pch = CharNext(pch));
pch = *pch ? pch : pch+1;
*pch = 0;
}
while (*pchBase != 0) {
if (*pchBase == '.') {
if (pchBase[1] == '.') {
if ((pchBase[2] == '\\') || (pchBase[2] == '/')) {
/*
* Found the string '..\' in the input, move up to the
* next '\' unless the next character up is a ':'
*/
pchDest = CharPrev(rgchDest, pchDest);
cbDest += ((IsDBCSLeadByte(*pchDest)) ? 2 : 1);
if (*pchDest == ':') {
pchDest++;
cbDest -= 1;
} else {
while (*pchDest != '\\') {
Assert(*pchDest != ':');
pchDest = CharPrev(rgchDest, pchDest);
cbDest += ((IsDBCSLeadByte(*pchDest)) ? 2 : 1);
}
}
pchBase += 3;
} else {
/*
* Found the string '..X' where X was not '\', this
* is "illegal" but copy it straight over
*/
*++pchDest = *pchBase++;
*++pchDest = *pchBase++;
cbDest -= 2;
}
} else if ((pchBase[1] == '\\') || (pchBase[1] == '/')) {
/*
* We just found the string '.\' This is an ignore string
*/
pchBase += 2;
} else {
/*
* We just found the string '.X' where X was not '\', this
* is legal and just copy over
*/
*++pchDest = *pchBase++;
cbDest -= 1;
}
} else if (*pchBase == '/') {
/*
* convert / to \
*/
*++pchDest = '\\';
pchBase++;
cbDest -= 1;
} else {
/*
* No funny characters
*/
if (IsDBCSLeadByte(*pchBase) && *(pchBase+1)) {
*++pchDest = *pchBase++;
cbDest -= 1;
}
*++pchDest = *pchBase++;
cbDest -= 1;
}
}
*pch = ch;
}
/*
* Now lets copy from the source to the destination looking for
* any funnyness in the path being copied.
*/
while (*pchSource != 0) {
if (*pchSource == '.') {
if (pchSource[1] == '.') {
if ((pchSource[2] == '\\') || (pchSource[2] == '/')) {
/*
* Found the string '..\' in the input, move up to the
* next '\' unless the next character up is a ':'
*/
pchDest = CharPrev(rgchDest, pchDest);
cbDest += ((IsDBCSLeadByte(*pchDest)) ? 2 : 1);
if (*pchDest == ':') {
pchDest++;
cbDest -= 1;
} else {
while (*pchDest != '\\') {
Assert(*pchDest != ':');
pchDest = CharPrev(rgchDest, pchDest);
cbDest += ((IsDBCSLeadByte(*pchDest)) ? 2 : 1);
}
}
pchSource += 3;
} else {
/*
* Found the string '..X' where X was not '\', this
* is "illegal" but copy it straight over
*/
*++pchDest = *pchSource++;
*++pchDest = *pchSource++;
cbDest -= 2;
}
} else if ((pchSource[1] == '\\') || (pchSource[1] == '/')) {
/*
* We just found the string '.\' This is an ignore string
*/
pchSource += 2;
} else {
/*
* We just found the string '.X' where X was not '\', this
* is legal and just copy over
*/
*++pchDest = *pchSource++;
cbDest -= 1;
}
} else {
/*
* No funny characters
*/
if (IsDBCSLeadByte(*pchSource) && *(pchSource+1)) {
*++pchDest = *pchSource++;
cbDest -= 1;
}
*++pchDest = *pchSource++;
cbDest -= 1;
}
}
*++pchDest = 0;
Dbg(_chdir(rgchDirCur) == 0);
return;
}/* BuildRelativeFilename() */
void PASCAL EnsureFocusDebugger()
/*++
Routine Description:
Set the foreground window to the debugger, if it wasn't already.
--*/
{
if (AutoTest) {
return;
}
HwndDebuggee = GetForegroundWindow();
if ((HwndDebuggee != hwndFrame) && !IsChild(hwndFrame, HwndDebuggee) && !IsIconic(hwndFrame)) {
SetForegroundWindow(hwndFrame);
}
}/* EnsureFocusDebugger() */
void EnsureFocusDebuggee(void)
/*++
Routine Description:
Set the foreground window to the client, or out best guess as to what the client was
--*/
{
return;
} /* EnsureFocusDebuggee() */
HWND GetTopSourceWindow(BOOL bAsmOk)
/*++
Routine Description:
Returns the handle of the topmost src. It can optionally
consider the asm window as a src window.
Arguments:
bAsmOk - Consider the asm window as a src window.
Return Value:
SUCCESS - Returns the handle of a valid window. If bAsmOk is FALSE,
then the return value will always be the handle of a doc
window. If bAsmOk is TRUE, then the return value, can either
be a doc or a src window.
FAILURE - NULL.
--*/
{
HWND hwnd = GetTopWindow(g_hwndMDIClient);
int nView, nType;
while ( hwnd ) {
nView = GetWindowWord( hwnd, GWW_VIEW );
// Valid view index?
if ( nView >= 0 && nView < MAX_VIEWS ) {
// Figure out what type of window we have
if (Views[nView].Doc < -1) {
nType = -Views[nView].Doc;
} else {
nType = Docs[Views[nView].Doc].docType;
}
if (bAsmOk && DISASM_WIN == nType // Consider the asm window a src window?
|| DOC_WIN == nType) { // We found a doc window?
return hwnd;
}
}
hwnd = GetNextWindow( hwnd, GW_HWNDNEXT );
}
// No src windows
return NULL;
}
void UpdateDebuggerState(UINT UpdateFlags)
/*++
Routine Description:
According to the passed flags asks the various debug
windows (Watch, Locals, etc) to update their displays.
??? Also take care of handling system state when debuggee dies.
Arguments:
UpdateFlags -
--*/
{
BOOL bDebugeeActive;
ADDR addr = {0};
int indx;
HWND hwndTopSource;
int view;
BOOL bForceDisasm = FALSE;
int fGotNext = 0;
bDebugeeActive = DebuggeeActive();
// Get a current CS:IP for the expression evaluator
if ((UpdateFlags & UPDATE_CONTEXT) && bDebugeeActive) {
Assert(LppdCur && LptdCur);
if (LppdCur && LptdCur) {
HTID vhtid;
OSDGetAddr(LppdCur->hpid, LptdCur->htid, adrPC, &addr);
SHChangeProcess(LppdCur->hpds);
if ( ! ADDR_IS_LI ( addr ) ) {
SYUnFixupAddr ( &addr );
}
memset(&CxfIp, 0, sizeof(CxfIp));
SHSetCxt(&addr, SHpCxtFrompCxf( &CxfIp ) );
SHhFrameFrompCXF(&CxfIp) = (HFRAME) LptdCur->htid;
}
}
// Tell the expression evaluator to dump any cached values
if (EEInvalidateCache != NULL) {
EEInvalidateCache();
}
if ( (UpdateFlags & UPDATE_CPU) && bDebugeeActive) {
SendMessageNZ( GetCpuHWND(), WU_UPDATE, 0, 0L);
}
if ( (UpdateFlags & UPDATE_FLOAT) && bDebugeeActive) {
SendMessageNZ( GetFloatHWND(), WU_UPDATE, 0, 0L);
}
if ( (UpdateFlags & UPDATE_LOCALS) && bDebugeeActive) {
SendMessageNZ( GetLocalHWND(), WU_UPDATE, 0, 0L);
}
if ( UpdateFlags & UPDATE_WATCH) {
if (UpdateFlags & UPDATE_SYMBOLS_CHANGED) {
ReloadAllWatchVariables();
SendMessageNZ( GetWatchHWND(), WU_INVALIDATE, 0, 0L);
} else {
SendMessageNZ( GetWatchHWND(), WU_UPDATE, 0, 0L);
}
}
if ( UpdateFlags & UPDATE_CALLS) {
SendMessageNZ( GetCallsHWND(), WU_UPDATE, 0, 0L);
}
if (UpdateFlags & UPDATE_SOURCE) {
if (!bDebugeeActive) {
ClearAllDocStatus(BRKPOINT_LINE | CURRENT_LINE | UBP_LINE);
} else {
char SrcFname[_MAX_PATH];
DWORD SrcLine;
int doc;
int saveDoc = TraceInfo.doc;
int iViewCur = curView;
// Clear out any existing current source line highlighting
if (TraceInfo.doc != -1) {
if (Docs[TraceInfo.doc].FirstView != -1) {
LineStatus(TraceInfo.doc, TraceInfo.CurTraceLine,
CURRENT_LINE, LINESTATUS_OFF, FALSE, TRUE);
}
TraceInfo.doc = -1;
TraceInfo.CurTraceLine = -1;
}
if (!GetCurrentSource(SrcFname, sizeof(SrcFname), &SrcLine)) {
if (UpdateFlags & UPDATE_NOFORCE) {
bForceDisasm = FALSE;
} else {
bForceDisasm = TRUE;
}
} else {
AuxPrintf(1, "Got Source:%s, Line:%u", (LPSTR)SrcFname, SrcLine);
if (UpdateFlags & UPDATE_NOFORCE) {
fGotNext = SrcMapSourceFilename(SrcFname, sizeof(SrcFname), SRC_MAP_ONLY, FindDoc1, FALSE); // Not user activated
} else {
fGotNext = SrcMapSourceFilename(SrcFname, sizeof(SrcFname), SRC_MAP_OPEN, FindDoc1, FALSE); // Not user activated
}
if (fGotNext > 0) {
// We have a new document.
Dbg( FindDoc1(SrcFname, &doc, TRUE) );
LineStatus(doc, SrcLine, CURRENT_LINE, LINESTATUS_ON, TRUE, TRUE);
TraceInfo.doc = doc;
TraceInfo.CurTraceLine = SrcLine;
}
}
}
}
// always update a memory window if "live" flag is set
for (indx = 0; indx < MAX_VIEWS; indx++) {
if (Views[indx].Doc > -1) {
if (Docs[Views[indx].Doc].docType == MEMORY_WIN) {
memView = indx;
if ((MemWinDesc[memView].fLive) || (UpdateFlags & UPDATE_MEMORY)) {
// check of valid views or sparse array
ViewMem(indx, TRUE);
}
}
}
}
if ( disasmView != -1 // If it is already open, let's update it
// Else let's see if we want to open it.
|| (bForceDisasm && !(g_contWorkspace_WkSp.m_dopDisAsmOpts & dopNeverOpenAutomatically) )
|| fGotNext < 0 || !GetSrcMode_StatusBar()) {
// We only open the disasm window if:
// (1) Windbg requested it and "never open disasm" option is not checked.
// (2) The respective src file could not be found
// (3) We are in ASM mode
if (disasmView == -1) {
OpenDebugWindow(DISASM_WIN, FALSE); // Not user activated
}
if (disasmView != -1) {
if (bDebugeeActive) {
ViewDisasm(SHPAddrFromPCxf(&CxfIp), DISASM_PC);
}
}
}
EnableToolbarControls();
} // UpdateDebuggerState()
/*** SetDebugLines
** Synopsis:
** Entry:
** Returns:
** Description:
** Given a doc, set the debug line highlights,
** (ie breakpoints, current_line) that refer to that doc.
** NOTE: This can be called whether or not there is a current
** debuggee. When there isn't, only source line bps
** are highlighted.
*/
void SetDebugLines(int doc, BOOL ResetTraceInfo)
{
Unreferenced( doc );
Unreferenced( ResetTraceInfo );
BPHighlightSourceFile( Docs[doc].szFileName );
} /* SetDebugLines() */
/*** AdjustDebugLines
** Synopsis:
** void = AdjustDebugLines(DocNumber, StartLine, NumberLines, Added)
** Entry:
** DocNumber - Index of document to have lines adjusted for
** StartLine - First line to be adjusted
** NumberLines - Number of lines to adjust by
** Added - TRUE if lines were inserted FALSE if lines were deleted
** Returns:
** Nothing
** Description:
** Updates source/line breakpoint nodes when lines are
** added/deleted to a file in the editor. If Added is
** TRUE the lines have been added otherwise they've been
** deleted. Also updates the TraceInfo var.
** NOTE: This is called from the editor every time a block is
** added or deleted.
** Insertions are always performed BEFORE the StartLine.
** Deletions are always performed INCLUDING the StartLine.
** StartLine is passed 0 relative.
** Also note that for the TraceInfo, all we avoid is
** having multiple trace lines. If lines are added
** or deleted to a file the current line will still
** seem wrong as this info. comes from the debugging
** info.
*/
void PASCAL AdjustDebugLines(int DocNumber, int StartLine, int NumberLines, BOOL Added)
{
Unused(DocNumber);
Unused(StartLine);
Unused(NumberLines);
Unused(Added);
} /* AdjustDebugLines() */
/*
General Task Management Routines
KillDebuggee
AttachDebuggee
RestartDebuggee
*/
BOOL KillDebuggee(void)
/*++
Routine Description:
This routine will check to see if a debuggee is currently
loaded in the system. If so it will kill the debuggee and any children.
Return Value:
TRUE if the child was killed and FALSE otherwise
--*/
{
MSG msg;
LPPD lppd;
HPID hpid;
BOOL fTmp;
BOOL rVal = TRUE;
/*
** Clear out any existing current source line highlighting
*/
if (TraceInfo.doc != -1) {
if (Docs[TraceInfo.doc].FirstView != -1) {
LineStatus(TraceInfo.doc, TraceInfo.CurTraceLine,
CURRENT_LINE, LINESTATUS_OFF, FALSE, TRUE);
}
TraceInfo.doc = -1;
TraceInfo.CurTraceLine = -1;
}
FKilling = TRUE;
fTmp = SetAutoRunSuppress(TRUE);
for (;;) {
/*
** See if there is anything to kill
*/
lppd = GetLppdHead();
while (lppd && (lppd->pstate == psDestroyed || lppd->pstate == psError || lppd->pstate == psNoProgLoaded))
{
lppd = lppd->lppdNext;
}
if (!lppd) {
break;
}
hpid = lppd->hpid;
BPTUnResolveAll(hpid);
/*
* This is a synchronous call and we must pump callback messages through until the process has been deleted.
*/
if ( (OSDProgramFree(hpid) != xosdNone) && (lppd->pstate != psDestroyed) ) {
// if it got killed while we weren't looking, there should already be a message in the queue:
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
ProcessQCQPMessage(&msg);
lppd = LppdOfHpid( hpid );
if ((lppd == NULL) || (lppd->pstate == psDestroyed)) {
break;
}
}
// if it didn't go away, mark it as damaged:
if (lppd && (lppd == LppdOfHpid(hpid))) {
lppd->pstate = psError;
}
// this is for the case in the kernel debugger where the init of the dm fails (com port problems) and the createprocess never happens.
} else if (lppd->pstate == psPreRunning) {
lppd->pstate = psDestroyed;
} else if ( (lppd->pstate != psDestroyed) || (lppd != LppdOfHpid(hpid)) ) { // <--is this possible??
while (GetMessage(&msg, NULL, 0, 0)) {
ProcessQCQPMessage(&msg);
lppd = LppdOfHpid( hpid );
if ((lppd == NULL) || (lppd->pstate == psDestroyed))
{
break;
}
}
}
}
SetAutoRunSuppress(fTmp);
FKilling = FALSE;
if (rVal) {
// if we succeeded in killing everything...
SetIpid(1);
}
return( rVal );
} /* KillDebuggee() */
void ClearDebuggee(void)
/*++
Routine Description:
This function is called to implement Run.Stop Debugging.
It will kill any currently loaded debugee and unload all of the debugging DLLs.
--*/
{
HCURSOR hcursor;
LPSTR lpsz;
XOSD xosd;
int len;
hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (DbgState == ds_init) {
CmdLogVar(ERR_DbgState);
return;
}
while (DebuggeeActive()) {
KillDebuggee();
}
len = ModListGetSearchPath( NULL, 0 );
if (len) {
lpsz = (PSTR) malloc(len);
ModListGetSearchPath( lpsz, len );
ModListInit();
ModListSetSearchPath( lpsz );
free(lpsz);
}
ModListAdd( NT_KERNEL_NAME , sheNone );
if (LppdFirst) {
if (LppdFirst->hpds) {
SHDeleteProcess(LppdFirst->hpds);
}
OSDDestroyHpid( HpidBase );
DestroyPd( LppdFirst, TRUE );
LppdFirst = LppdCur = NULL;
SetIpid(0);
}
if (HModEM != 0) {
SendMessageNZ( GetCpuHWND(), WU_DBG_UNLOADEM, 0, 0); // Give'em a
SendMessageNZ( GetFloatHWND(), WU_DBG_UNLOADEM, 0, 0); // Chance
OSDDeleteEM( Hem );
FreeLibrary( HModEM );
HModEM = 0;
Hem = 0;
HpidBase = 0;
HtidBase = 0;
}
if (HModTL != 0) {
xosd = OSDDeleteTL( Htl );
FreeLibrary( HModTL );
HModTL = 0;
Htl = 0;
}
if (HModEE != 0) {
SendMessageNZ( GetCpuHWND(), WU_DBG_UNLOADEE, 0, 0); // Give'em a change
SendMessageNZ( GetFloatHWND(), WU_DBG_UNLOADEE, 0, 0); // to Unload
SendMessageNZ( GetLocalHWND(), WU_DBG_UNLOADEE, 0, 0);
SendMessageNZ( GetWatchHWND(), WU_DBG_UNLOADEE, 0, 0);
SendMessageNZ( GetCallsHWND(), WU_DBG_UNLOADEE, 0, 0);
// Tell the EE we are about to unloaded it.
EEUnload();
// Unload the EE
FreeLibrary( HModEE );
HModEE = 0;
Ei.pStructExprAPI = &Exf;
}
if (HModSH != 0) {
// Tell the symbol handler its about to be unloaded
SHUnloadSymbolHandler(FALSE);
// Unload the symbol handler
FreeLibrary( HModSH );
HModSH = 0;
Lpshf = NULL;
}
EnableToolbarControls();
memset( &CxfIp, 0, sizeof( CxfIp ) );
SetCursor(hcursor);
} /* ClearDebuggee() */
void DisconnectDebuggee(void)
/*++
Routine Description:
This function is called to implement Run.Disconnect
--*/
{
HCURSOR hcursor;
LPSTR lpsz;
LPPD lppd;
int len;
hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (DbgState == ds_init) {
CmdLogVar(ERR_DbgState);
return;
}
if (LppdFirst) {
if (LppdFirst->hpds) {
SHDeleteProcess(LppdFirst->hpds);
}
while (lppd = LppdFirst->lppdNext) {
OSDDestroyHpid( lppd->hpid );
DestroyPd( lppd, TRUE );
}
OSDDestroyHpid( HpidBase );
DestroyPd( LppdFirst, TRUE );
}
len = ModListGetSearchPath( NULL, 0 );
if (len) {
lpsz = (PSTR) malloc(len);
ModListGetSearchPath( lpsz, len );
ModListInit();
ModListSetSearchPath( lpsz );
free( lpsz );
}
ModListAdd( NT_KERNEL_NAME, sheNone );
SetIpid(0);
LppdFirst = NULL;
LppdCur = NULL;
LptdCur = NULL;
if (HModTL != 0) {
OSDDeleteTL( Htl );
Htl = 0;
FreeLibrary( HModTL );
HModTL = 0;
}
if (HModEM != 0) {
SendMessageNZ( GetCpuHWND(), WU_DBG_UNLOADEM, 0, 0); // Give'em a
SendMessageNZ( GetFloatHWND(), WU_DBG_UNLOADEM, 0, 0); // Chance
OSDDeleteEM( Hem );
FreeLibrary( HModEM );
HModEM = 0;
Hem = 0;
HpidBase = 0;
HtidBase = 0;
}
if (HModEE != 0) {
SendMessageNZ( GetCpuHWND(), WU_DBG_UNLOADEE, 0, 0); // Give'em a change
SendMessageNZ( GetFloatHWND(), WU_DBG_UNLOADEE, 0, 0); // to Unload
SendMessageNZ( GetLocalHWND(), WU_DBG_UNLOADEE, 0, 0);
SendMessageNZ( GetWatchHWND(), WU_DBG_UNLOADEE, 0, 0);
SendMessageNZ( GetCallsHWND(), WU_DBG_UNLOADEE, 0, 0);
FreeLibrary( HModEE );
HModEE = 0;
Ei.pStructExprAPI = &Exf;
}
if (HModSH != 0) {
LPFNSHSTOPBACKGROUND lpfn;
LPFNSHUNINIT lpfn2;
if (g_contWorkspace_WkSp.m_bShBackground) {
lpfn = (LPFNSHSTOPBACKGROUND) GetProcAddress( HModSH, "SHStopBackground" );
if (lpfn) {
lpfn();
}
}
lpfn2 = (LPFNSHUNINIT) GetProcAddress( HModSH, "SHUninit" );
if (lpfn2) {
lpfn2();
}
FreeLibrary( HModSH );
HModSH = 0;
Lpshf = NULL;
}
EnableToolbarControls();
memset( &CxfIp, 0, sizeof( CxfIp ) );
SetCursor(hcursor);
} /* DisconnectDebuggee() */
void SetProcessExceptions(LPPD lppd)
{
EXCEPTION_DESCRIPTION exd;
EXCEPTION_LIST *List;
// If we don't have a default exception list yet, load it.
if ( !DefaultExceptionList ) {
// Loop through all the exceptions known to OSDebug
exd.exc = exfFirst;
OSDGetExceptionState(lppd->hpid, NULL, &exd);
do {
EXCEPTION_LIST *eList= (EXCEPTION_LIST*)malloc(sizeof(EXCEPTION_LIST));
Assert(eList);
eList->next = NULL;
eList->dwExceptionCode = exd.dwExceptionCode;
eList->efd = exd.efd;
eList->lpName = MHStrdup(exd.rgchDescription);
eList->lpCmd = NULL;
eList->lpCmd2 = NULL;
InsertException( &DefaultExceptionList, eList );
exd.exc = exfNext;
} while (OSDGetExceptionState(lppd->hpid, NULL, &exd) == xosdNone);
}
if ( DefaultExceptionList ) {
if ( lppd->ipid == 0 ) {
// The exception list for process 0 is the default exception list.
lppd->exceptionList = DefaultExceptionList;
} else {
// All other processes get a copy of the default exception list.
List = DefaultExceptionList;
while ( List ) {
EXCEPTION_LIST *eList=(EXCEPTION_LIST*)malloc(sizeof(EXCEPTION_LIST));
Assert(eList);
eList->next = NULL;
eList->dwExceptionCode = List->dwExceptionCode;
eList->efd = List->efd;
eList->lpName = List->lpName ? MHStrdup(List->lpName) : NULL;
eList->lpCmd = List->lpCmd ? MHStrdup(List->lpCmd) : NULL;
eList->lpCmd2 = List->lpCmd2 ? MHStrdup(List->lpCmd2) : NULL;
InsertException( &lppd->exceptionList, eList);
List = List->next;
}
}
// Traverse the list and tell OSDebug not to ignore all exceptions that are not to be ignored (OSDebug will ignore all exceptions by default).
List = DefaultExceptionList;
while ( List ) {
exd.dwExceptionCode = List->dwExceptionCode;
exd.efd = List->efd;
exd.exc = exfSpecified;
strncpy(exd.rgchDescription, List->lpName? List->lpName: "", EXCEPTION_STRING_SIZE);
OSDSetExceptionState( lppd->hpid, NULL, &exd );
List = List->next;
}
if (EfdPreset != -1) {
exd.dwExceptionCode = 0;
exd.efd = EfdPreset;
exd.exc = exfDefault;
OSDSetExceptionState(lppd->hpid, NULL, &exd);
}
}
}
void ClearProcessExceptions(LPPD lppd)
{
EXCEPTION_LIST *el, *elt;
if ( lppd->ipid != 0 ) {
// For all processes other than process 0, we must deallocate
// the list. Process 0 is special since its exception list is
// the default exception list, which does not go away.
for ( el = lppd->exceptionList; el; el = elt ) {
elt = el->next;
if ( el->lpName ) {
MHFree( el->lpName );
}
if ( el->lpCmd ) {
MHFree( el->lpCmd );
}
if ( el->lpCmd2 ) {
MHFree( el->lpCmd2 );
}
MHFree(el);
}
}
lppd->exceptionList = NULL;
}
VOID GetDebugeePrompt(void)
{
LPPROMPTMSG pm;
DWORD dw;
pm = (LPPROMPTMSG) malloc( sizeof(PROMPTMSG)+PROMPT_SIZE );
if (!pm) {
return;
}
memset( pm, 0, sizeof(PROMPTMSG)+PROMPT_SIZE );
pm->len = PROMPT_SIZE;
// kcarlos - BUGBUG -> BUGCAST
//CmdGetDefaultPrompt( pm->szPrompt );
CmdGetDefaultPrompt( (PSTR) pm->szPrompt );
if (OSDSystemService( LppdCur->hpid, NULL, (SSVC) ssvcGetPrompt, pm, sizeof(PROMPTMSG)+PROMPT_SIZE, &dw) == xosdNone) {
// kcarlos - BUGBUG -> BUGCAST
//CmdSetDefaultPrompt( pm->szPrompt );
CmdSetDefaultPrompt( (PSTR) pm->szPrompt );
}
free( pm );
}
BOOL ConnectDebugger(BOOL *pfReconnecting)
{
// Check to see if we have already loaded an EM/DM pair and created the base process descriptor. If not then we need to do so now.
char str[9];
DWORD dw;
*pfReconnecting = FALSE;
if (LppdFirst == NULL) {
if (!FLoadEmTl(pfReconnecting)) {
return FALSE;
}
/*
** Hook this process up to the symbol handler
*/
LppdCur->hpds = SHCreateProcess();
SHSetHpid(HpidBase);
if (g_contWorkspace_WkSp.m_bAlternateSS) {
strcpy(str, "slowstep");
OSDSystemService(LppdCur->hpid, NULL, (SSVC) ssvcCustomCommand, str, strlen(str)+1, &dw);
}
} else if (LppdCur == NULL) {
LppdCur = LppdFirst;
}
SHChangeProcess(LppdCur->hpds);
GetDebugeePrompt();
return TRUE;
} /* ConnectDebugger() */
int
FinishAttachDebuggee(
DWORD dwProcessId,
HANDLE hEventGo
)
{
XOSD xosd;
BOOL fMakingRoot;
MSG msg;
int Errno;
LPPD lppd = NULL;
BOOL fTmp;
DWORD dwStatus = 0;
DAP Dap = { 0 };
char szStr[MAX_CMDLINE_TXT];
OSDSetPath( LppdCur->hpid, g_contGlobalPreferences_WkSp.m_bSrchSysPathForExe, NULL );
fMakingRoot = (LppdFirst->lppdNext == NULL && (LppdFirst->pstate == psNoProgLoaded));
// not psDestroyed. We don't restart proc 0 with an attach.
if (fMakingRoot) {
PCSTR pszProgramName = g_Windbg_WkSp.GetCurrentProgramName(FALSE);
if (pszProgramName && *pszProgramName) {
strcpy(szStr, pszProgramName);
if (LpszCommandLine && *LpszCommandLine) {
strcat(szStr, " ");
strcat(szStr, LpszCommandLine);
}
if (!g_contWorkspace_WkSp.m_bKernelDebugger) {
CmdLogVar(DBG_Losing_Command_Line, szStr);
g_Windbg_WkSp.SetCurrentProgramName(pszProgramName);
} else {
g_Windbg_WkSp.SetCurrentProgramName(g_Windbg_WkSp.m_pszNoProgramLoaded);
}
}
}
Dap.dwProcessId = dwProcessId;
Dap.hEventGo = hEventGo;
xosd = OSDDebugActive(LppdFirst->hpid, &Dap, sizeof(Dap));
if (xosd != xosdNone) {
if (fMakingRoot) {
DbgState = ds_error;
}
SetPTState(psNoProgLoaded, tsInvalidState);
switch( xosd ) {
case xosdAccessDenied:
Errno = ERR_File_Read;
break;
case xosdOutOfMemory:
Errno = ERR_Cannot_Allocate_Memory;
break;
default:
case xosdBadFormat:
case xosdUnknown:
Errno = ERR_Cant_Load;
break;
}
fTmp = SetAutoRunSuppress(TRUE);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
ProcessQCQPMessage(&msg);
}
SetAutoRunSuppress(fTmp);
sprintf(szStr, "process %d, status == %d", dwProcessId, dwStatus);
ErrorBox(Errno, szStr);
DbgState = ds_normal;
if (fMakingRoot) {
ClearDebuggee();
}
EnableToolbarControls();
return FALSE;
} else {
/*
* Process messages until the loader breakpoint has been handled.
*/
fTmp = SetAutoRunSuppress(TRUE);
// wait for new process...
if (fMakingRoot) {
lppd = LppdFirst;
lppd->pstate = psPreRunning;
} else {
HPID hpid = 0;
while (GetMessage(&msg, NULL, 0, 0)) {
ProcessQCQPMessage(&msg);
if (msg.wParam == dbcNewProc) {
hpid = (HPID) msg.lParam;
}
if ((hpid != 0) && (lppd = LppdOfHpid((HPID) msg.lParam)) != NULL) {
break;
}
}
}
// wait for it to finish loading
lppd->fChild = FALSE;
lppd->fHasRun = FALSE;
lppd->fInitialStep = FALSE;
lppd->hbptSaved = NULL;
lppd->fStopAtEntry = FALSE;
while (GetMessage(&msg, NULL, 0, 0)) {
ProcessQCQPMessage(&msg);
if (lppd->pstate != psPreRunning) {
break;
}
}
SetAutoRunSuppress(fTmp);
EnableToolbarControls();
if (lppd->pstate != psRunning && lppd->pstate != psStopped) {
return FALSE;
} else {
return TRUE;
}
}
} /* FinishAttachDebuggee() */
BOOL AttachDebuggee(DWORD dwProcessId, HANDLE hEventGo)
/*++
Routine Description:
Debug an active process.
Tell osdebug to hook up to a running process.
If the process crashed, the system has provided an event handle to signal when the debugger is ready to field the second chance exception.
--*/
{
BOOL fReconnecting;
/*
** Disable all of the buttons
*/
EnableToolbarControls();
// connect the OSDebug components and wake up the DM.
if (!ConnectDebugger(&fReconnecting)) {
EnableToolbarControls();
return FALSE;
}
if (fReconnecting) {
FinishAttachDebuggee(0, NULL);
}
if (dwProcessId == 0) {
return TRUE;
} else {
return FinishAttachDebuggee(dwProcessId, hEventGo);
}
}
BOOL RestartDebuggee(LPSTR ExeName, LPSTR Args)
{
MSG msg;
int Errno;
XOSD xosd;
ULONG ulFlags = 0;
BOOL fTmp;
BOOL fMakingRoot;
LPPD lppd = NULL;
BOOL fReconnecting;
Assert(ExeName);
/*
** Disable all of the buttons
*/
EnableToolbarControls();
if (!ConnectDebugger(&fReconnecting)) {
EnableToolbarControls();
return FALSE;
}
// Allow the debugger to pick up any abandoned debuggees
if (fReconnecting) {
if (FinishAttachDebuggee(0, NULL)) {
Go();
}
return FALSE;
}
fMakingRoot = (LppdFirst->lppdNext == NULL) && ((LppdFirst->pstate == psNoProgLoaded) || (LppdFirst->pstate == psDestroyed));
/*
** Mark as being in the original load so defer working with
** any breakpoints until all initial DLL load notifications are done
*/
if (fMakingRoot) {
DbgState = ds_init; //??
}
if (g_contWorkspace_WkSp.m_bDebugChildren) {
ulFlags |= ulfMultiProcess;
}
if (g_contWorkspace_WkSp.m_bInheritHandles) {
ulFlags |= ulfInheritHandles;
}
if (g_contWorkspace_WkSp.m_bWowVdm) {
ulFlags |= ulfWowVdm;
}
if (AutoTest) {
ulFlags |= ulfNoActivate;
}
OSDSetPath( LppdCur->hpid, g_contGlobalPreferences_WkSp.m_bSrchSysPathForExe, NULL );
xosd = OSDProgramLoad(LppdCur->hpid, ExeName, Args, NULL, "WINDBG: ", ulFlags);
if (xosd != xosdNone) {
DbgState = ds_error;
switch( xosd ) {
case xosdFileNotFound:
Errno = ERR_File_Not_Found;
break;
case xosdAccessDenied:
Errno = ERR_File_Read;
break;
case xosdOpenFailed:
Errno = ERR_File_Open;
break;
case xosdOutOfMemory:
Errno = ERR_Cannot_Allocate_Memory;
break;
case xosdDumpInvalidFile:
Errno = ERR_DumpInvalidFile;
break;
case xosdDumpWrongPlatform:
Errno = ERR_DumpWrongPlatform;
break;
default:
case xosdBadFormat:
case xosdUnknown:
Errno = ERR_Cant_Load;
break;
}
ErrorBox(Errno, ExeName);
DbgState = ds_normal;
if (fMakingRoot) {
ClearDebuggee();
}
EnableToolbarControls();
InvalidateAllWindows();
return FALSE;
} else {
/*
* Before draining message queue, ensure that thread state is right
*/
fTmp = SetAutoRunSuppress(TRUE);
// wait for new process...
if (fMakingRoot) {
// we never see a dbcNewProc for this process,
// so set things up here.
lppd = LppdFirst;
lppd->pstate = psPreRunning;
lppd->ctid = 0;
SetPdInfo(lppd);
EESetTarget(lppd->mptProcessorType);
DbgState = ds_normal;
} else {
// Process messages until the loader breakpoint has been handled, or the half started debuggee is killed.
HPID hpid = 0;
while (GetMessage(&msg, NULL, 0, 0)) {
ProcessQCQPMessage(&msg);
if (msg.wParam == dbcNewProc) {
hpid = (HPID) msg.lParam;
DbgState = ds_normal;
}
if ((hpid != 0) &&
(lppd = LppdOfHpid((HPID) msg.lParam)) != NULL) {
break;
}
}
}
Assert(lppd);
// wait for it to finish loading
lppd->fChild = FALSE;
lppd->fHasRun = FALSE;
lppd->fInitialStep = FALSE;
lppd->hbptSaved = NULL;
lppd->fStopAtEntry = FALSE;
while (GetMessage(&msg, NULL, 0, 0)) {
ProcessQCQPMessage(&msg);
if (lppd->pstate != psPreRunning) {
break;
}
}
// do this again after dbcLoadComplete to pick up info
// that wasn't available at first when debugging a crashdump...
SetPdInfo(lppd);
SetAutoRunSuppress(fTmp);
EnableToolbarControls();
InvalidateAllWindows();
if (g_contWorkspace_WkSp.m_bKernelDebugger && g_contKernelDbgPreferences_WkSp.m_bUseCrashDump) {
// lets be nice and do an automatic symbol reload
CmdExecuteLine( ".reload" );
}
return (LppdCur != NULL && LptdCur != NULL) && (LptdCur->tstate == tsRunning || LptdCur->tstate == tsStopped || LptdCur->tstate == tsException1 || LptdCur->tstate == tsException2);
}
} /* RestartDebuggee() */
BOOL DebuggeeAlive(void)
/*++
Routine Description:
This function is used to determine if the debugger is currently active with a child process.
See Also:
DebuggeeActive()
Return Value:
TRUE if there is currently a debuggee process and FALSE otherwise
--*/
{
return GetLppdHead() != (LPPD)0;
} /* DebuggeeAlive() */
BOOL DebuggeeActive(void)
/*++
Routine Description:
This function is used to determine if the debugger currently has a debuggee which is in a state where it is partially debugged.
The difference between this and DebuggeeAlive is that if a debuggee has not been run or it has been terminated this will return FALSE while DebuggeeAlive will return TRUE.
See Also:
DebuggeeAlive
Return Value:
TRUE if debuggee is in an active state and FALSE otherwise
--*/
{
LPPD lppd;
/*
* If any process is loaded, we have a debuggee:
*/
for (lppd = GetLppdHead(); lppd; lppd = lppd->lppdNext) {
switch (lppd->pstate) {
case psNoProgLoaded:
case psExited:
case psDestroyed:
case psError:
break;
default:
return TRUE;
}
}
return FALSE;
} /* DebuggeeActive() */
/*** GetSourceFromAddress
** Synopsis:
** bool = GetSourceFromAddress(pADDR, SrcFname, SrcLen, pSrcLine)
** Entry:
** Returns:
** Description:
*/
BOOL
GetSourceFromAddress(
PADDR pADDR,
PSTR SrcFname,
int SrcLen,
DWORD *pSrcLine
)
{
ADDR addr;
DWORD wLn;
SHOFF cbLn;
SHOFF dbLn;
HSF hsf;
LPCH lpchFname;
CXT CXTT;
char TmpSrcFname[_MAX_PATH];
char Executable[_MAX_PATH];
AuxPrintf(1, "GetSourceFromAddress - 0x%X:0x%I64X, emi:%X",
GetAddrSeg(*pADDR),
GetAddrOff(*pADDR),
emiAddr(*pADDR)
);
if ( ! ADDR_IS_LI ( *pADDR ) ) {
SYUnFixupAddr ( pADDR );
}
addr = *pADDR;
SHHMODFrompCXT(&CXTT) = (HMOD) NULL;
/*
** Translate the given addresss into a file and line.
*/
SHSetCxt(pADDR, &CXTT);
if (SHHMODFrompCXT(&CXTT)
&& SLLineFromAddr (&addr, &wLn, &cbLn, &dbLn)
&& (hsf = SLHsfFromPcxt (&CXTT)) ) {
// Canonicalise the found file relative to the ProgramName
lpchFname = SLNameFromHsf (hsf);
#if 0
Assert(SrcLen > 0);
_fmemcpy ( SrcFname, lpchFname + 1, min(SrcLen-1, *lpchFname));
SrcFname[*lpchFname] = '\0';
#else
_fmemcpy ( TmpSrcFname, lpchFname + 1, *lpchFname);
TmpSrcFname[*lpchFname] = '\0';
GetExecutableFilename(Executable, sizeof(Executable));
BuildRelativeFilename(TmpSrcFname,
Executable,
SrcFname,
SrcLen);
#endif
// M00HACK
{
char * lpch = SrcFname + strlen(SrcFname);
while (lpch > SrcFname && *lpch != '.'){
lpch = CharPrev(SrcFname, lpch);
}
if (_stricmp(lpch, ".OBJ") == 0) {
strcpy(lpch, ".C");
}
}
// M00HACK
*pSrcLine = wLn;
return TRUE;
}
return FALSE;
} /* GetSourceFromAddress() */
/*** GetCurrentSource
** Synopsis:
** bool = GetCurrentSource(SrcFname, SrcLen, pSrcLine)
** Entry:
** SrcFname :
** SrcLen :
** pSrcLine :
** Returns:
** Description:
*/
BOOL
GetCurrentSource(
PSTR SrcFname,
int SrcLen,
DWORD *pSrcLine
)
{
ADDR addr;
OSDGetAddr(LppdCur->hpid, LptdCur->htid, adrPC, &addr);
return GetSourceFromAddress(&addr, SrcFname, SrcLen, pSrcLine);
}
/*** MoveEditorToAddr
** Synopsis:
** bool = MoveEditorToAddr(pAddr)
** Entry:
** pAddr - Address to move the editor to
** bUserActivated - Indicates whether this action was initiated by the
** user or by windbg. The value is to determine the Z order of
** any windows that are opened.
** Returns:
** TRUE if successful and FALSE otherwise
** Description:
** This function will take the address in the structure pAddr and
** move the editor so that the source line cooresponding to the address
** will be in the front window and the cursor placed on that line
*/
BOOL
PASCAL
MoveEditorToAddr(
PADDR pAddr,
BOOL bUserActivated
)
{
char szFname[_MAX_PATH];
DWORD FnameLine;
int doc = 0;
BOOL GotSource;
if (!pAddr) {
return FALSE;
}
GotSource = FALSE;
if (GetSourceFromAddress( pAddr, szFname, sizeof(szFname), &FnameLine)) {
GotSource = SrcMapSourceFilename(szFname, sizeof(szFname),
SRC_MAP_OPEN, NULL, bUserActivated);
switch( GotSource ) {
case -2:
return FALSE;
case -1:
return FALSE;
case 0:
return FALSE;
case 1:
case 2:
GotSource = FindDoc(szFname, &doc, TRUE);
break;
default:
Assert(FALSE);
break;
}
if (!GotSource) {
GotSource = ((AddFile(MODE_OPEN, DOC_WIN, (LPSTR)szFname, NULL, NULL, TRUE, -1, -1, bUserActivated) != -1) &&
FindDoc(szFname, &doc, bUserActivated));
}
}
if (GotSource) {
// Make sure window is visible
ActivateMDIChild(Views[Docs[doc].FirstView].hwndFrame, TRUE);
// And show the function
GotoLine(Docs[doc].FirstView, FnameLine, TRUE);
}
return GotSource;
} /* MoveEditorToAddr() */
BOOL
ToggleInRange(
int thisView,
DWORD dwLineNumber,
DWORD Lines,
BOOL LoadSymbols,
HBPT hBpt,
char *rgch
)
{
BOOL BpSet = FALSE;
char szCurLine[300];
BPSTATUS bpstatus;
ULONG LineBpt;
BOOL OldLoadSymbols;
OldLoadSymbols = BPSymbolLoading( LoadSymbols );
// See if there is a breakpoint on this file/line pair already.
// Note that we only check for existing breakpoints in the first
// line of the range, so that we'll toggle (i.e. clear) existing
// breakpoints only if clicking over a highlighted line.
bpstatus = BPHbptFromFileLine(rgch, dwLineNumber, &hBpt);
if (bpstatus == BPNOERROR || bpstatus == BPAmbigous) {
BPDelete(hBpt);
BPCommit();
BpSet = TRUE;
} else {
// set a breakpoint on the next line that has code associated with it.
Assert(bpstatus == BPNoBreakpoint);
for (; dwLineNumber < Lines; dwLineNumber++) {
bpstatus = BPHbptFromFileLine(rgch, dwLineNumber, &hBpt);
if (bpstatus == BPNOERROR || bpstatus == BPAmbigous) {
// This line already has a breakpoint, place the cursor on this
// line, do nothing more
if (BPQueryHighlightLineOfHbpt(hBpt, &LineBpt) == BPNOERROR) {
dwLineNumber = (DWORD)LineBpt;
}
PosXYCenter(thisView, Views[thisView].X, dwLineNumber-1, FALSE);
BpSet = TRUE;
break;
}
// Set up a breakpoint node and a command string for the
// current line
// Make a current line BP command
sprintf(szCurLine, "%c%d", BP_LINELEADER, dwLineNumber);
bpstatus = BPParse(&hBpt, szCurLine, NULL, rgch,
LppdCur ? LppdCur->hpid : 0 );
if (bpstatus == BPNOERROR) {
Dbg(BPAddToList( hBpt, -1 ) == BPNOERROR);
if (DebuggeeAlive()) {
bpstatus = BPBindHbpt( hBpt, NULL );
if (bpstatus != BPNOERROR) {
// If this file is in a module that we have loaded,
// then the line is not valid, so we discard the
// breakpoint. Otherwise this file might belong
// to a module that has not been loaded yet, so
// we leave the uninstantiated BP to be resolved
// later on.
if ( BPFileNameToMod( rgch ) || !LoadSymbols ) {
BPUnCommit();
if ( bpstatus != BPCancel ) {
continue;
}
}
}
}
BPCommit();
if (BPQueryHighlightLineOfHbpt(hBpt, &LineBpt) == BPNOERROR) {
dwLineNumber = (DWORD)LineBpt;
}
PosXYCenter(thisView, Views[thisView].X, dwLineNumber-1, FALSE);
BpSet = TRUE;
break;
}
}
}
BPSymbolLoading( OldLoadSymbols );
return BpSet;
} /* ToggleInRange() */
/*** ToggleLocBP
** Synopsis:
** bool = ToggleLocBP()
** Entry:
** None
** Returns:
** TRUE if successful, FALSE otherwise.
** Description:
** Toggles the breakpoint at the current editor line.
*/
BOOL PASCAL
ToggleLocBP(
void
)
{
char szCurLine[300];
char rgch[300];
HBPT hBpt = NULL;
BPSTATUS bpstatus;
ADDR addr;
ADDR addr2;
DWORD dwLineNumber;
int thisView = curView;
// can't do this if windbg is the kernel debugger and the system is running
if ( g_contWorkspace_WkSp.m_bKernelDebugger && IsProcRunning(LppdCur) ) {
CmdInsertInit();
CmdLogFmt( "Cannot set breakpoints while the target system is running\r\n" );
MessageBeep(0);
return FALSE;
}
// check first that a window is active
if (hwndActiveEdit == NULL) {
return FALSE;
}
// Could be the disassembler window
if (Views[thisView].Doc < 0) {
// Must be in a src or disasm window to do this
return FALSE;
} else if (Docs[Views[thisView].Doc].docType == DISASM_WIN) {
if (!DisasmGetAddrFromLine(&addr, Views[thisView].Y)) {
return FALSE;
}
// Check to see if breakpoint already at this address
addr2 = addr;
bpstatus = BPHbptFromAddr(&addr2, &hBpt);
if ((bpstatus == BPNOERROR) || (bpstatus == BPAmbigous)) {
BPDelete(hBpt);
BPCommit();
return TRUE;
}
Assert( bpstatus == BPNoBreakpoint );
EEFormatAddress(&addr, szCurLine, sizeof(szCurLine), 0);
bpstatus =
BPParse( &hBpt, szCurLine, NULL, NULL, LppdCur ? LppdCur->hpid : 0);
if (bpstatus != BPNOERROR) {
return FALSE;
} else {
Dbg(BPAddToList( hBpt, -1) == BPNOERROR);
Assert(DebuggeeAlive());
bpstatus = BPBindHbpt( hBpt, NULL );
if (bpstatus != BPNOERROR) {
BPUnCommit();
return FALSE;
}
BPCommit();
return TRUE;
}
} else if (Docs[Views[thisView].Doc].docType == DOC_WIN) {
// Ok to do this in source win
// Deal with any mapping of file names
strcpy(rgch, Docs[Views[thisView].Doc].szFileName);
SrcBackMapSourceFilename(rgch, sizeof(rgch));
// set the line number to the current line (where the caret is)
dwLineNumber = Views[thisView].Y+1;
if ( ToggleInRange(
thisView,
dwLineNumber,
min( (DWORD)Docs[Views[thisView].Doc].NbLines+1, dwLineNumber+20 ),
FALSE,
hBpt,
rgch ) ) {
return TRUE;
}
if ( ToggleInRange(
thisView,
dwLineNumber,
(DWORD)Docs[Views[thisView].Doc].NbLines+1,
TRUE,
hBpt,
rgch ) ) {
return TRUE;
}
}
return FALSE;
} /* ToggleLocBP() */
/*** ContinueToCursor
** Synopsis:
** bool = ContinueToCursor()
** Entry:
** Nothing
** Returns:
** TRUE on success and FALSE on failure
** Description:
** Attemps to do a GoUntil to the address that corresponds to the
** source line at the current cursor position in the editor
*/
BOOL PASCAL
ContinueToCursor(
int View,
int line
)
{
char szCurLine[255];
char rgch[300];
HBPT hBpt;
ADDR addr;
BPSTATUS bpstatus;
// Check for active window
if (hwndActiveEdit == NULL) {
return FALSE;
}
// If we get here then the debuggee must be alive. If it is not
// also active then return FALSE. We can't do anything in that case
Assert( DebuggeeAlive() );
// Check first for a disassembler window.
if (Views[View].Doc < 0) {
// Can't do this in a pane window
return FALSE;
} else if (Docs[Views[View].Doc].docType == DISASM_WIN) {
if (DisasmGetAddrFromLine(&addr, line)) {
GoUntil(&addr);
return TRUE;
} else {
return FALSE;
}
} else if (Docs[Views[View].Doc].docType != DOC_WIN) {
// Must be in a source window in order to do this
return FALSE;
}
if (!DebuggeeActive()) {
return FALSE;
}
sprintf(szCurLine, "%c%d", BP_LINELEADER, line + 1);
// Back map the current file name to the original file name
// if it has been changed
strcpy(rgch, Docs[Views[View].Doc].szFileName);
SrcBackMapSourceFilename(rgch, sizeof(rgch));
bpstatus = BPParse(&hBpt,
szCurLine,
NULL,
rgch,
LppdCur ? LppdCur->hpid : 0);
if (bpstatus != BPNOERROR) {
return FALSE;
} else if ((bpstatus = BPBindHbpt( hBpt, &CxfIp )) == BPNOERROR) {
Dbg( BPAddrFromHbpt( hBpt, &addr ) == BPNOERROR );
Dbg( BPFreeHbpt( hBpt ) == BPNOERROR );
GoUntil( &addr );
} else if (!LppdCur->fHasRun) {
// not yet at entrypoint: save it for later
LppdCur->hbptSaved = (HANDLE)hBpt;
Go();
} else {
// it should have bound
Dbg( BPFreeHbpt( hBpt ) == BPNOERROR );
return FALSE;
}
return TRUE;
} /* ContinueToCursor() */
void PASCAL
UpdateRadix(
UINT newradix
)
/*++
Routine Description:
Change the global radix and update any windows that need to track radix.
Arguments:
newradix - Supplies new radix value: 8, 10 or 16
Return Value:
None
--*/
{
Assert(newradix == 8 || newradix == 10 || newradix == 16);
if (newradix != radix) {
radix = newradix;
UpdateDebuggerState(UPDATE_RADIX);
}
return;
} /* UpdateRadix() */
int
GetQueueLength()
{
int i;
EnterCriticalSection(&csDbgMsgBuffer);
// OK so its not the length -- all I currently really care about
// is if there are any messages setting and waiting for me.
i = iDbgMsgBufferFront - iDbgMsgBufferBack;
LeaveCriticalSection(&csDbgMsgBuffer);
return i;
} /* GetQueueLength() */
void
BPCallbackFunc(
HBPT hBpt,
BPSTATUS bpstatus
)
/*++
Routine Description:
This function will be called for each breakpoint which
mets its criteria
Arguments:
hBpt - Supplies breakpoint which met the breakpoint criteria
bpstatus - Supplies breakpoint status code during evaluation
Return Value:
None
--*/
{
ULONG i;
char rgchT[256];
if (bpstatus != BPNOERROR) {
Dbg( BPIFromHbpt( &i, hBpt ) == BPNOERROR);
CmdInsertInit();
CmdLogFmt("Error checking breakpoint #%d\r\n", i);
}
return;
} /* BPCallbackFunc() */
BOOL AddQueueItemQuad(DWORD64 l)
{
int newBufferFront;
BOOL fEmpty;
EnterCriticalSection(&csDbgMsgBuffer);
newBufferFront = (iDbgMsgBufferFront + 1) % QUEUE_SIZE;
while (newBufferFront == iDbgMsgBufferBack) {
LeaveCriticalSection(&csDbgMsgBuffer);
Sleep(1000);
EnterCriticalSection(&csDbgMsgBuffer);
}
fEmpty = (GetQueueLength() == 0);
RgbDbgMsgBuffer[iDbgMsgBufferFront] = l;
iDbgMsgBufferFront = newBufferFront;
LeaveCriticalSection(&csDbgMsgBuffer);
return fEmpty;
}
DWORD64
GetQueueItemQuad(
void
)
{
DWORD64 l;
EnterCriticalSection(&csDbgMsgBuffer);
while (iDbgMsgBufferFront == iDbgMsgBufferBack) {
LeaveCriticalSection(&csDbgMsgBuffer);
Sleep(1000);
EnterCriticalSection(&csDbgMsgBuffer);
}
l = RgbDbgMsgBuffer[iDbgMsgBufferBack];
iDbgMsgBufferBack = (iDbgMsgBufferBack + 1) % QUEUE_SIZE;
LeaveCriticalSection(&csDbgMsgBuffer);
return l;
}
LPTD
CBLptdOfHpidHtid(
HPID hpid,
HTID htid
)
/*++
Routine Description:
This is a specialized debugger version of this function. It should
only be called from the callback routine. It will return a thread
pointer if one can be found and otherwise will push the process
and thread handles onto the save memory area.
Arguments:
hpid - osdebug handle to a process
htid - osdebug handle to a thread
Return Value:
pointer to thread descriptor block if one exists for the thread
and process handles. Otherwise it will return NULL.
--*/
{
LPPD lppd;
LPTD lptd = NULL;
lppd = LppdOfHpid(hpid);
if (lppd) {
lptd = LptdOfLppdHtid( lppd, htid );
}
AddQueueItemQuad((DWORD64) lptd);
if (lptd == NULL) {
AddQueueItemQuad((DWORD64) hpid);
AddQueueItemQuad((DWORD64) htid);
}
return( lptd );
} /* CBLptdOfHpidHtid() */
XOSD
OSDAPI
OSDCallbackFunc(
DWORD wMsg,
HPID hpid,
HTID htid,
DWORD64 wParam,
DWORD64 lParam
)
/*++
Routine Description:
This function posts a message to the main message pump to be processed in CmdNextExec.
All of the relevent data is posted as part of the message.
This must be done for the Win16 case as things such as memory allocation are not good here since this could called be non-syncronous.
Arguments:
wMsg - Callback message number (dbc*)
hpid - process ID for the message
htid - thread ID for the message
wParam - Data about the message
lParam - Data about the message
Return Value:
xosdNone - never returns an error
--*/
{
BOOL fPostMsg = FALSE;
LPBPR lpbpr;
LPINFOAVAIL lpinf;
LPADDR lpaddr;
HSYM hSym;
UOFF32 uoff;
CXF Cxf;
CANSTEP *CanStep;
FUNCTION_INFORMATION FunctionInfo;
ADDR Addr;
DWORD wLn;
SHOFF cbLn;
SHOFF dbLn;
HPDS HpdsOld;
BPSTATUS bpstatus;
int cch;
switch ((DBC)wMsg) {
case dbcInfoAvail:
case dbcInfoReq:
lpinf = (LPINFOAVAIL)lParam;
fPostMsg = AddQueueItemQuad( wMsg );
if ( (DBC)wMsg == dbcInfoAvail ) {
AddQueueItemQuad( lpinf->fReply );
} else {
Assert( lpinf->fReply );
}
AddQueueItemQuad( lpinf->fUniCode );
if (!lpinf->fUniCode) {
AddQueueItemQuad( (DWORD64) MHStrdup( (PSTR) lpinf->buffer) );
} else {
int l = lstrlenW( (LPWSTR) lpinf->buffer);
LPWSTR lpw = (LPWSTR) MHAlloc(2*l + 2);
memcpy(lpw, lpinf->buffer, 2*l);
lpw[l] = 0;
AddQueueItemQuad( (DWORD64) lpw );
}
break;
case dbcCheckWatchPoint:
case dbcCheckMsgBpt:
case dbcCheckBpt:
// Do the check here rather than queueing it for the shell.
// if the BP fires, the DM will notify us,
// so don't tell the shell anything.
OSDGetAddr(hpid, htid, adrPC, &Addr);
if ( ! ADDR_IS_LI ( Addr ) ) {
SYUnFixupAddr ( &Addr );
}
memset(&Cxf, 0, sizeof(Cxf));
HpdsOld = SHChangeProcess(LppdOfHpid(hpid)->hpds);
SHSetCxt(&Addr, SHpCxtFrompCxf( &Cxf ) );
SHhFrameFrompCXF(&Cxf) = (HFRAME) htid;
bpstatus = BPCheckHbpt( Cxf, BPCallbackFunc, hpid, htid, wParam);
SHChangeProcess(HpdsOld);
Assert(bpstatus == BPPassBreakpoint || bpstatus == BPNOERROR);
return (bpstatus == BPNOERROR);
case dbcStep:
case dbcBpt:
case dbcSendBpt:
case dbcWatchPoint:
case dbcSendWatchPoint:
case dbcMsgBpt:
case dbcSendMsgBpt:
case dbcAsyncStop:
case dbcEntryPoint:
case dbcLoadComplete:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid );
// wParam contains the Breakpoint notify tag when relevant
AddQueueItemQuad(wParam);
break;
case dbcProcTerm:
fPostMsg = AddQueueItemQuad( wMsg );
AddQueueItemQuad( (DWORD64) hpid );
AddQueueItemQuad((DWORD64) lParam); // Save away exit code
break;
case dbcDeleteProc:
fPostMsg = AddQueueItemQuad( wMsg );
AddQueueItemQuad( (DWORD64) hpid );
break;
case dbcModFree:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid );
AddQueueItemQuad((DWORD64) lParam);
break;
case dbcModLoad:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid );
AddQueueItemQuad((DWORD64) MHStrdup((LSZ)lParam)); // remember name
AddQueueItemQuad((DWORD64) wParam); // TRUE if thread is stopped
break;
case dbcError:
fPostMsg = AddQueueItemQuad( wMsg );
AddQueueItemQuad((DWORD64) hpid);
AddQueueItemQuad((DWORD64) htid);
AddQueueItemQuad((DWORD64) wParam);
AddQueueItemQuad((DWORD64)MHStrdup((LSZ) lParam));
break;
case dbcCanStep:
lpaddr = (LPADDR) lParam;
if ( (HPID)emiAddr( *lpaddr ) == hpid && ADDR_IS_LI(*lpaddr) ) {
// This is magic, don't ask.
emiAddr( *lpaddr ) = 0;
ADDR_IS_LI( *lpaddr ) = FALSE;
OSDSetEmi(hpid,htid,lpaddr);
}
if ( (HPID)emiAddr( *lpaddr ) != hpid ) {
SHWantSymbols( (HEXE)emiAddr( *lpaddr ) );
}
SHSetCxt( lpaddr, SHpCxtFrompCxf( &Cxf ) );
CanStep = (CANSTEP*)lParam;
uoff = SHGetNearestHSYM( lpaddr, Cxf.cxt.hMod , EECODE, &hSym );
if ( uoff != CV_MAXOFFSET && SHIsThunk( hSym ) ) {
CanStep->Flags = CANSTEP_THUNK;
} else if (uoff == CV_MAXOFFSET &&
!SLLineFromAddr( lpaddr, &wLn, NULL, NULL)) {
CanStep->Flags = CANSTEP_NO;
} else {
uoff = 0;
Addr = Cxf.cxt.addr;
SYFixupAddr( &Addr );
// v-vadimp - always use sapi's IsInProlog on IA64
if (LppdOfHpid(hpid)->mptProcessorType != mptia64 &&
OSDGetFunctionInformation( hpid,
NULL,
&Addr,
&FunctionInfo )
== xosdNone)
{
if (GetAddrOff(FunctionInfo.AddrPrologEnd) > GetAddrOff(Addr)) {
uoff = (UOFF32)(GetAddrOff(FunctionInfo.AddrPrologEnd) - GetAddrOff(Addr));
}
} else if ( GetSrcMode_StatusBar() ) {
while( SHIsInProlog( &Cxf.cxt ) ) {
Cxf.cxt.addr.addr.off++;
uoff++;
}
}
CanStep->Flags = CANSTEP_YES;
CanStep->PrologOffset = uoff;
}
return xosdNone;
case dbcLastAddr:
// We will return:
// If SRC mode and have src for line - Last addr in line
// If SRC mode and no src for line - Zero
// if ASM mode - Same addr
lpaddr = (LPADDR) lParam;
if ( GetSrcMode_StatusBar() ) {
if ( SLLineFromAddr( lpaddr, &wLn, &cbLn, &dbLn ) ) {
Assert( cbLn >= dbLn );
if (cbLn >= dbLn) {
lpaddr->addr.off += cbLn - dbLn;
}
} else {
memset( lpaddr, 0, sizeof( ADDR ) );
}
}
return xosdNone;
case dbcFlipScreen:
return xosdNone;
case dbcException:
{
LPEPR lpepr;
DWORD size = sizeof(EPR) + ((LPEPR)lParam)->NumberParameters * sizeof(DWORD);
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid);
lpepr = (LPEPR) MHAlloc(size);
memcpy(lpepr, (PVOID)lParam, size);
AddQueueItemQuad((DWORD64)lpepr);
}
break;
case dbcThreadTerm:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid );
AddQueueItemQuad((DWORD64) lParam); // Save away exit code
break;
case dbcExecuteDone:
AddQueueItemQuad( wMsg );
PostMessage(hwndFrame, DBG_REFRESH, dbcExecuteDone, xosdNone);
return xosdNone;
case dbcNewProc:
// hpid belongs to root proc; new hpid is in wParam.
AddQueueItemQuad( wMsg );
AddQueueItemQuad( wParam);
PostMessage(hwndFrame, DBG_REFRESH, dbcNewProc, (LPARAM)wParam);
return xosdNone;
case (DBC)dbcRemoteQuit:
fPostMsg = AddQueueItemQuad( wMsg );
break;
case (DBC)dbcMemoryChanged:
fPostMsg = AddQueueItemQuad( wMsg );
AddQueueItemQuad( lParam );
break;
case dbcSegLoad:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid) ;
AddQueueItemQuad(lParam);
break;
case dbcCreateThread:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid);
break;
case dbcExitedFunction:
// if we are going to use this, we must read the return value now,
// while the DM is blocked. If the shell reads it, the thread will
// already be running.
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid);
AddQueueItemQuad( 0 ); // <<-- return value goes here
break;
case dbcGetExpression:
// Evaluate an expression using the masm evaluator
lpaddr = (LPADDR)wParam;
if (CPGetAddress((LPSTR)lParam,
&cch,
lpaddr,
/*radix*/10,
&CxfIp,
/*fCaseSensitive*/FALSE,
/*fSpecial*/TRUE) != 0) {
lpaddr->addr.off = 0;
}
break;
default:
fPostMsg = AddQueueItemQuad( wMsg );
CBLptdOfHpidHtid( hpid, htid);
break;
}
if (fPostMsg) {
PostMessage(hwndFrame, DBG_REFRESH, 0, 0);
}
return (xosdNone);
} /* OSDCallbackFunc() */
/*** FDebInit
** Synopsis:
** bool = FDebInit()
** Entry:
** none
** Returns:
** TRUE if the debugger was initialized successfully and FALSE
** if the debugger failed to initialize
** Description:
** Initialize the OSDebug debugger.
*/
BOOL
FDebInit(
void
)
{
if (OSDInit(&Dbf) != xosdNone) {
return (FALSE); /* Error during initialization */
}
BPInit();
SetPidTid_StatusBar(NULL, NULL);
return (TRUE);
} /* FDebInit() */
/*** FDebTerm
** Synopsis:
** bool = FDebTerm()
** Entry:
** None
** Returns:
** TRUE if successful and FALSE otherwise
** Description:
** This routine will go back and do any clean up necessary to
** kill all of the debugger dlls, debuggee processes and so forth.
*/
BOOL
FDebTerm(
void
)
{
ClearDebuggee();
OSDTerm();
return TRUE;
} /* FDebTerm() */
BOOL
DllVersionMatch(
HINSTANCE hMod,
PCSTR pName,
PCSTR pType,
BOOL fNoisy
)
{
DBGVERSIONPROC pVerProc;
BOOL Ok = TRUE;
LPAVS pavs;
pVerProc = (DBGVERSIONPROC)GetProcAddress(hMod, DBGVERSIONPROCNAME);
if (!pVerProc) {
Ok = FALSE;
if (fNoisy) {
ErrorBox(ERR_Not_Windbg_DLL, pName);
}
} else {
pavs = (*pVerProc)();
if (pType[0] != pavs->rgchType[0] || pType[1] != pavs->rgchType[1]) {
Ok = FALSE;
if (fNoisy) {
ErrorBox(ERR_Wrong_DLL_Type,
pName, (LPSTR)pavs->rgchType, (LPSTR)pType);
}
} else if (Avs.rlvt != pavs->rlvt) {
Ok = FALSE;
if (fNoisy) {
ErrorBox(ERR_Wrong_DLL_Version, pName,
pavs->rlvt, pavs->iRmj, Avs.rlvt, Avs.iRmj);
}
} else if (Avs.iRmj != pavs->iRmj) {
Ok = FALSE;
if (fNoisy) {
ErrorBox(ERR_Wrong_DLL_Version, pName,
pavs->rlvt, pavs->iRmj, Avs.rlvt, Avs.iRmj);
}
}
}
return Ok;
}
HINSTANCE
LoadHelperDll(
PCTSTR psz,
PCTSTR pType,
BOOL fError
)
/*++
Routine Description:
Load a debugger DLL, verify that it is the correct type
and version.
Arguments:
psz - Supplies string contianing name of DLL to be loaded
pType - Supplies type string
fError - Supplies flag saying whether to display an error message
on failure.
Returns:
HMODULE to library or NULL
--*/
{
HINSTANCE hMod;
BOOL fail = FALSE;
hMod = LoadLibrary(psz);
if (hMod == NULL) {
fail = TRUE;
}
else if (!DllVersionMatch( hMod, psz, pType, fError ) ) {
FreeLibrary( hMod );
hMod = NULL;
fail = TRUE;
}
if (fail && fError) {
PTSTR pszErr = WKSP_FormatLastErrorMessage();
ErrorBox(ERR_Cannot_Load_DLL, (LPSTR) psz, pszErr);
free(pszErr);
}
return hMod;
} /* LoadHelperDll() */
/*** FLoadShEe
** Synopsis:
** Entry:
** Returns:
** Description:
*/
BOOL
FloadShEe(
DWORD mach
)
{
LPFNSHINIT lpfn2;
LPFNEEINIT lpfn3;
PCSTR pszDll;
char * szDllEEAuto;
HCURSOR hcursor;
int nErrno;
CmdInsertInit();
/*
** Place the hour glass icon onto the screen
*/
hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
/*
*/
if (Lpshf == NULL) {
pszDll = g_pszDLL_SYMBOL_HANDLER;
Assert(pszDll);
if ((HModSH = LoadHelperDll(pszDll, "SH", TRUE)) == 0) {
SetCursor(hcursor);
return( FALSE );
}
if ((lpfn2 = (LPFNSHINIT) GetProcAddress(HModSH, "SHInit")) == NULL) {
nErrno = ERR_Invalid_Debugger_Dll;
goto errRet;
}
if (lpfn2(&Lpshf, &Knf) == FALSE) {
nErrno = ERR_Initializing_Debugger;
goto errRet;
}
}
pszDll = g_pszDLL_EXPR_EVAL;
Assert(pszDll);
/*
** Check for either a space or a tab following the name of the DLL
** if so then replace that character with a 0 and ignore the rest
** of the string
*/
Assert(NULL == strchr( (PBYTE) pszDll, ' '));
Assert(NULL == strchr( (PBYTE) pszDll, '\t'));
#if 0
if ((lpch = (PSTR) strchr( (PBYTE) pszDll, ' ')) == NULL) {
lpch = (PSTR) strchr( (PBYTE) pszDll, '\t');
}
if (lpch != NULL) {
chSave = *lpch;
*lpch = 0;
}
#endif
if ((HModEE = LoadHelperDll(pszDll, "EE", TRUE)) == 0) {
#if 0
if (lpch != NULL) {
*lpch = chSave;
}
#endif
SetCursor(hcursor);
return FALSE;
}
#if 0
if (lpch != NULL) {
*lpch = chSave;
}
#endif
if ((lpfn3 = (LPFNEEINIT) GetProcAddress(HModEE, "EEInitializeExpr")) == NULL) {
nErrno = ERR_Invalid_Debugger_Dll;
goto errRet;
}
lpfn3(&Ci, &Ei);
/*
** Back fill any structures
*/
CopyShToEe();
/*
** Make sure that open windows find out about the new EE
*/
SendMessageNZ( GetCpuHWND(), WU_DBG_LOADEE, 0, 0); // Give'em a change
SendMessageNZ( GetFloatHWND(), WU_DBG_LOADEE, 0, 0); // to Unload
SendMessageNZ( GetLocalHWND(), WU_DBG_LOADEE, 0, 0);
SendMessageNZ( GetWatchHWND(), WU_DBG_LOADEE, 0, 0);
SendMessageNZ( GetCallsHWND(), WU_DBG_LOADEE, 0, 0);
/*
** Set the mouse cursor back to the origial one
*/
SetCursor(hcursor);
// BUGBUG Unicode/ANSI support in EE?
//EESetSuffix( SuffixToAppend );
return(TRUE);
errRet:
SetCursor( hcursor );
ErrorBox( nErrno, pszDll );
return FALSE;
} /* FLoadShEe() */
BOOL
FLoadEmTl(
BOOL *pfReconnecting
)
/*++
Routine Description:
This routine is used to load the Execution Module and the
Transport Layer DLLs
Arguments:
None
Return Value:
TRUE if the dlls were sucessfully loaded and FALSE otherwise.
--*/
{
PCSTR pszDllErr = NULL;
EMFUNC lpfnEm;
TLFUNC lpfnTl;
HCURSOR hcursor;
int nErrno;
XOSD xosd;
CmdInsertInit();
hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
if (g_Windbg_WkSp.GetSelected_TL_Dll_Name() == NULL) {
SetCursor(hcursor);
InformationBox(ERR_DLL_Transport_Unspecified);
return( FALSE );
}
pszDllErr = g_Windbg_WkSp.GetSelected_TL_Dll_Name();
if ((HModTL = LoadHelperDll(g_Windbg_WkSp.GetSelected_TL_Dll_Name(), "TL", TRUE)) == 0) {
SetCursor(hcursor);
return(FALSE);
}
/*
** Now get the entry point for the transport DLL
*/
if ((lpfnTl = (TLFUNC) GetProcAddress(HModTL, "TLFunc")) == NULL) {
nErrno = ERR_Invalid_Debugger_Dll;
goto errRet;
}
xosd = OSDAddTL( lpfnTl, &Dbf, &Htl );
if (xosd == xosdNone) {
WKSPSetupTL( Htl );
} else {
Htl = NULL;
}
if (xosd == xosdNone) {
xosd = OSDStartTL( Htl );
}
switch ( xosd ) {
case xosdNone:
break; // cool, we're set up.
case xosdBadVersion:
nErrno = ERR_Wrong_Remote_DLL_Version;
goto errRet;
break;
case xosdCannotConnect:
nErrno = ERR_Cannot_Connect;
goto errRet;
break;
case xosdCantOpenComPort:
nErrno = ERR_Cant_Open_Com_Port;
pszDllErr = NULL;
goto errRet;
break;
case xosdBadComParameters:
nErrno = ERR_Bad_Com_Parameters;
pszDllErr = NULL;
goto errRet;
break;
case xosdBadPipeServer:
nErrno = ERR_Bad_Pipe_Server;
pszDllErr = NULL;
goto errRet;
break;
case xosdBadPipeName:
nErrno = ERR_Bad_Pipe_Name;
pszDllErr = NULL;
goto errRet;
break;
default:
nErrno = ERR_Initializing_Debugger;
goto errRet;
break;
}
/*
*/
if (!FloadShEe(0)) {
SetCursor(hcursor);
return FALSE;
}
Assert(g_pszDLL_EXEC_MODEL);
if ((HModEM = LoadHelperDll(g_pszDLL_EXEC_MODEL, "EM", TRUE)) == 0) {
SetCursor(hcursor);
nErrno = 0; // LoadHelperDll already complained.
goto errRet;
}
if ((lpfnEm = (EMFUNC) GetProcAddress(HModEM, "EMFunc")) == NULL) {
nErrno = ERR_Invalid_Debugger_Dll;
goto errRet;
}
if (OSDAddEM(lpfnEm, &Dbf, &Hem, emNative) != xosdNone) {
nErrno = ERR_Initializing_Debugger;
goto errRet;
}
WKSPSetupEM(Hem);
// in OSDEBUG4, EM will load the DM during the first emfCreateHpid
*pfReconnecting = FALSE;
switch (OSDCreateHpid(OSDCallbackFunc, Hem, Htl, &HpidBase)) {
case xosdNone:
break; // all cool
case xosdInUse:
// This is OK, but we need to pick up any existing processes
// before we start a new one, so let the caller know what happened.
*pfReconnecting = TRUE;
break;
//case xosdBadRemoteVersion:
//nErrno = ERR_Wrong_Remote_DLL_Version;
//pszDllErr = szDllTL;
//goto errRet;
//break;
case xosdCannotConnect:
nErrno = ERR_Cannot_Connect;
pszDllErr = g_Windbg_WkSp.GetSelected_TL_Dll_Name();
goto errRet;
break;
default:
nErrno = ERR_Initializing_Debugger;
goto errRet;
break;
}
/*
** Set up the Process Descriptor block for the base process
** Clear out the pointer to the current thread descripter block.
*/
SetIpid(0);
LppdCur = LppdFirst = CreatePd( HpidBase );
LppdFirst->fPrecious = TRUE;
LptdCur = NULL;
if (g_contWorkspace_WkSp.m_bShBackground) {
LPFNSHSTARTBACKGROUND lpfn;
lpfn = (LPFNSHSTARTBACKGROUND) GetProcAddress( HModSH, "SHStartBackground" );
if (lpfn) {
lpfn();
}
}
/*
** Tell other people about the newly loaded EM
*/
SendMessageNZ( GetCpuHWND(), WU_DBG_LOADEM, 0, 0);
SendMessageNZ( GetFloatHWND(), WU_DBG_LOADEM, 0, 0);
SetCursor(hcursor);
return TRUE ;
errRet:
if (Hem) {
OSDDeleteEM( Hem );
}
if (HModEM) {
FreeLibrary(HModEM);
}
HModEM = NULL;
lpfnEm = NULL;
Hem = 0;
if (Htl) {
OSDDeleteTL( Htl );
}
if (HModTL) {
FreeLibrary(HModTL);
}
HModTL = NULL;
lpfnTl = NULL;
Htl = 0;
SetCursor( hcursor );
if (nErrno != 0) {
ErrorBox(nErrno, pszDllErr);
}
return FALSE;
} /* FLoadEmTl() */
/*** BPQuerySrcWinFls
** Synopsis:
** Entry:
** Returns:
** Description:
*/
BOOL PASCAL BPQuerySrcWinFls(char * pfls)
{
Unreferenced( pfls );
return FALSE;
} /* BPQuerySrcWinFls() */
/*** MELoadEEParse
** Synopsis:
** Entry:
** Returns:
** Description:
*/
EESTATUS
PASCAL
MELoadEEParse(
const char * lpb,
EERADIX iRadix,
SHFLAG shflag,
PHTM phtm,
LPDWORD lpus
)
{
if (!FloadShEe(mptUnknown)) {
return (EESTATUS) -1;
}
return(EEParse(lpb, iRadix, shflag, phtm, lpus));
} /* MELoadEEParse() */
/*** BPCBGetSouceFromAddr
** Synopsis:
** Entry:
** Returns:
** Description:
*/
BOOL PASCAL BPCBGetSourceFromAddr(LPADDR pAddr, char FAR * rgchFile, int cchFile, int FAR * pLine)
{
DWORD iLine;
if (GetSourceFromAddress(pAddr, rgchFile, cchFile, &iLine)) {
*pLine = iLine;
return TRUE;
}
return FALSE;
} /* BPCBGetSourceFromAddr() */
/*** SrcNameIsMasked
** Synopsis:
** bool = SrcNameIsMasked(atm)
** Entry:
** atm - Atom of file to look for in the set of masked files
** Returns:
** TRUE if a match was found and FALSE otherwise
** Description:
** This routine will look through the set of masked out file names
** which are stored in an array of atoms looking for a match. If
** one is found the the name is considered to be masked out and TRUE
** will be returned. If no match is found then FALSE is returned.
*/
BOOL SrcNameIsMasked(ATOM atm)
{
int i;
for (i=0; i<CAtomMasked; i++) {
if (RgAtomMaskedNames[i] == atm) {
return TRUE;
}
}
return FALSE;
} /* SrcNameIsMasked() */
/*** SrcNameIsMapped
** Synopsis:
** bool = SrcNameIsMapped(atm, lpb, cb)
** Entry:
** atm - Atom for the file to be mapped from
** lpb - buffer to return the mapped to name if mapping exists
** cb - size of lpb in bytes
** Returns:
** TRUE if a mapping was found and FALSE otherwise
** Description:
** This function will look through the set of mappings looking for
** a match to the input file name (atm). If a mapping is found then
** the name of the map to file is returned in the buffer lpb.
*/
BOOL SrcNameIsMapped(ATOM atm, LSZ lpb, UINT cb)
{
int i;
for (i=0; i<CAtomMapped; i++) {
if (RgAtomMappedNames[i].atomSrc == atm) {
GetAtomName(RgAtomMappedNames[i].atomTarget, lpb, cb);
return TRUE;
}
}
return FALSE;
} /* SrcNameIsMapped() */
/*** MatchOpenedDoc
** Synopsis:
** int = MatchOpenedDoc
** Entry:
** lpszSrc - buffer containing entry & exit filename
** cbSrc - size of lpszSrc buffer in bytes
** Returns:
** -1 - error occurred
** 0 - no match
** 1 - found and possibly mapping added
** Description:
** This routine searches through the doc list and matches doc
** that has the same file name as lpszSrc. If there is a match,
** the file has not been mapped, and one of the following conditions
** is true:
** 1. The file satisfies root mapping transformation
** 2. The file can be found along the source search path
** 3. The user agrees on the mapping
** then a 1 will be returned.
*/
INT
MatchOpenedDoc(
LPSTR lpszSrc,
UINT cbSrc
)
{
LPSTR SrcFile = GetFileName(lpszSrc);
CHAR szDestName[MAX_PATH];
int doc;
lMatchCnt = 0;
if ( SrcFile ) {
for (doc = 0; doc < MAX_DOCUMENTS; doc++) {
if (Docs[doc].docType == DOC_WIN && Docs[doc].FirstView != -1 &&
_stricmp(GetFileName(Docs[doc].szFileName), SrcFile) == 0) {
// found a match just based on filename only
strcpy(szDestName, Docs[doc].szFileName);
if (SrcBackMapSourceFilename(szDestName, sizeof(szDestName)) == 0) {
// file has no backward mapping
if (RootNameIsMapped(lpszSrc, szDestName, sizeof(szDestName)) &&
_stricmp(szDestName, Docs[doc].szFileName) == 0) {
SrcSetMapped(lpszSrc, szDestName);
if (cbSrc <= strlen(szDestName)) {
return (-1); // error
} else {
strcpy(lpszSrc, szDestName);
return (1); // matched and mapped
}
} else if (strcpy(szDestName, lpszSrc) &&
SrcSearchOnPath(szDestName, sizeof(szDestName), FALSE) &&
_stricmp(szDestName, Docs[doc].szFileName) == 0) {
SrcSetMapped(lpszSrc, szDestName);
if (cbSrc <= strlen(szDestName)) {
return (-1); // error
} else {
strcpy(lpszSrc, szDestName);
return (1); // matched and mapped
}
} else { // ask user
MatchedList[lMatchCnt++] = doc;
}
}
}
}
}
if (lMatchCnt > 0 && !AutoTest) {
if (NoPopups) {
MSG msg;
matchopeneddocagain:
sprintf( szBrowsePrompt, "File %s can be mapped to several opened documents.\n", lpszSrc );
fBrowseAnswer = FALSE;
CmdSetCmdProc( CmdMatchOpenedDocInputString, CmdMatchOpenedDocPrompt );
CmdSetAutoHistOK(FALSE);
CmdSetEatEOLWhitespace(FALSE);
CmdDoPrompt( TRUE, TRUE );
while (GetMessage( &msg, NULL, 0, 0 )) {
ProcessQCQPMessage( &msg );
if (fBrowseAnswer) {
break;
}
}
if (szBrowseFname[0]) {
lMatchIdx = atoi(szBrowseFname);
if (0 < lMatchIdx && lMatchIdx <= lMatchCnt) {
SrcFile = Docs[MatchedList[lMatchIdx-1]].szFileName;
SrcSetMapped(lpszSrc, SrcFile);
if (cbSrc <= strlen(SrcFile))
return(-1);
else {
strcpy(lpszSrc, SrcFile);
return(1);
}
} else {
goto matchopeneddocagain;
}
}
CmdSetDefaultCmdProc();
CmdDoPrompt(TRUE, TRUE);
return 0;
}
strcpy(szFSSrcName, lpszSrc);
StartDialog( DLG_FSRESOLVE, DlgFileSearchResolve );
if (lMatchIdx >= 0) {
SrcFile = Docs[MatchedList[lMatchIdx]].szFileName;
SrcSetMapped(lpszSrc, SrcFile);
if (FAddToSearchPath)
AddToSearchPath(SrcFile);
else if (FAddToRootMap)
RootSetMapped(lpszSrc, SrcFile);
if (cbSrc <= strlen(SrcFile))
return(-1);
else {
strcpy(lpszSrc, SrcFile);
return(1);
}
}
}
return 0;
} // MatchOpenedDoc
/*** SrcSearchOnPath
** Synopsis:
** bool = SrcSearchOnPath(lpb, cb)
** Entry:
** lpb - buffer containing entry & exit filename
** cb - size of lpb in bytes
** Returns:
** TRUE if the file was found in the search path and FALSE otherwise
** Description:
** This routine will strip down to the base file name of the
** source file the system is currently looking for and check for
** the file in the current working directory, the exe's directory
** and on the directories specified in the SourcePath tools.ini
** variable. If the file is found then the full path is returned
** in lpb.
*/
BOOL
SrcSearchOnPath(
LSZ lpb,
UINT cb,
BOOL fAddToMap
)
{
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
TCHAR szFName[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
TCHAR rgch[_MAX_PATH];
TCHAR rgch2[_MAX_PATH];
TCHAR rgchFName[_MAX_FNAME+_MAX_EXT];
BOOL Found;
TCHAR *p;
// Get file name
_splitpath(lpb, szDrive, szDir, szFName, szExt);
strcpy(rgchFName, szFName);
strcat(rgchFName, szExt);
// Look in the current directory.
Found = FindNameOn(rgch, sizeof(rgch), ".", rgchFName);
if ( !Found ) {
// Not in current directory, look in EXE directory.
if ( g_Windbg_WkSp.GetCurrentProgramName(FALSE) ) {
strcpy( rgch, g_Windbg_WkSp.GetCurrentProgramName(FALSE) );
_splitpath(rgch, szDrive, szDir, szFName, szExt );
strcpy( rgch2, szDrive );
strcat( rgch2, szDir );
p = CharPrev(rgch2, rgch2 + strlen(rgch2));
if ( *p == '\\' ) {
*p = '\0';
}
Found = FindNameOn(rgch, sizeof(rgch), rgch2, rgchFName);
}
if ( !Found ) {
// Not in EXE directory, look along SourcePath.
Found = FindNameOn(rgch, sizeof(rgch), g_contPaths_WkSp.m_pszSourceCodeSearchPath, rgchFName);
}
}
if ( Found ) {
if (strlen(rgch) > cb) {
// Not enough space in return buffer
Found = FALSE;
} else {
if (fAddToMap) {
SrcSetMapped(lpb, rgch);
}
strcpy(lpb, rgch);
}
}
return Found;
} /* SrcSearchOnPath() */
/*** SrcSearchOnRoot
** Synopsis:
** bool = SrcSearchOnRoot(lpb, cb)
** Entry:
** lpb - buffer containing entry & exit filename
** cb - size of lpb in bytes
** Returns:
** TRUE if the file was found by root mapping and FALSE otherwise
** Description:
** This routine compares the given file's root with those stored
** in the root mapping table. If not found, it uses the debuggee's
** drive to locate the source.
*/
BOOL SrcSearchOnRoot(LSZ lpb, UINT cb)
{
char rgch[_MAX_PATH];
char rgch2[_MAX_PATH];
char rgchDest[_MAX_PATH];
BOOL Found;
char *p;
int i;
Found = RootNameIsMapped(lpb, rgchDest, sizeof(rgchDest));
#if 0
if (!Found) {
_splitpath(lpb, szDrive, szDir, szFName, szExt);
Assert(szDir[0] == '\\');
sprintf(rgch, "%s%s%s", (szDir[0] == '\\') ? szDir+1 : szDir,
szFName, szExt); // src without drive
// Look into the debuggee's drive
if ( g_Windbg_WkSp.GetCurrentProgramName(FALSE) ) {
if (_fullpath(rgch2, g_Windbg_WkSp.GetCurrentProgramName(FALSE), sizeof(rgch2)) != NULL) {
// make sure drive letter exists and not the same as
// the original one as it would have been searched
if (rgch2[1] == ':' && _strnicmp(szDrive, rgch2, 2) != 0) {
rgch2[2] = '\0';
Found = FindNameOn(rgchDest, sizeof(rgchDest), rgch2, rgch);
}
}
}
}
#endif
if ( Found ) {
if (strlen(rgchDest) >= cb) {
// Not enough space in return buffer
Found = FALSE;
} else {
SrcSetMapped(lpb, rgchDest);
strcpy(lpb, rgchDest);
}
}
return Found;
} /* SrcSearchOnRoot() */
BOOL
MiscBrowseForFile(
LSZ lpb,
UINT cb,
LSZ lpDir,
UINT cchDir,
int nDefExt,
int nIdDlgTitle,
void (*fnSetMapped)(LSZ, LSZ),
LPOFNHOOKPROC lpfnHook,
int nExplorerExtensionTemplateName
)
/*++
Routine Description:
Tell the user that we can't find a file, and allow him to
browse for a it using a standard File Open dialog.
Arguments:
lpb - Supplies name of requested file,
Returns fully qualified path
cb - Supplies size of buffer at lpb
lpDir - Supplies directory to start browse in,
Returns directory file was found in
cchDir - Supplies size of buffer at lpDir
nDefExt - Supplies resource id for default extension filter
nIdDlgTitle - Supplies res id for dialog title string
fnSetMapped - Supplies pointer to function for mapping
requested name to returned name.
lpfnHook - Pointer to a hook procedure for the additional
controls or to customize the file open dlg.
pszExplorerExtensionTemplateId - Resource Id to a dlg
template that will be an extension of the
typical explorer dlg. This simple adds
controls to the file open dlg. 0 for none.
Return Value:
If a file is found, return TRUE and copy the path into
the buffer at lpb.
--*/
{
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
DWORD dwFlags = OFN_FILEMUSTEXIST |
OFN_PATHMUSTEXIST |
OFN_HIDEREADONLY |
OFN_NOCHANGEDIR;
char rgchT[_MAX_PATH];
char CurrentDirectory[_MAX_PATH ];
BOOL Ret = FALSE;
// Make sure we always use the new look.
if (nExplorerExtensionTemplateName || lpfnHook) {
dwFlags |= OFN_EXPLORER;
}
// Tell the file open dlg that we want to
// append controls to it.
if (nExplorerExtensionTemplateName) {
dwFlags |= OFN_ENABLETEMPLATE;
}
Assert(strlen(lpb) < sizeof(rgchT));
strcpy(rgchT, lpb);
if (DLG_Browse_Filebox_Title != nIdDlgTitle) {
_splitpath( rgchT, NULL, NULL, fname, ext );
_makepath( rgchT, NULL, NULL, fname, ext );
}
GetCurrentDirectory( sizeof( CurrentDirectory ), CurrentDirectory );
if ( *lpDir ) {
SetCurrentDirectory( lpDir );
}
if (StartFileDlg(hwndFrame,
nIdDlgTitle,
nDefExt,
ID_BROWSE_HELP,
nExplorerExtensionTemplateName,
rgchT,
&dwFlags,
lpfnHook)
) {
Assert( strlen(rgchT) < cb );
if ( strlen(rgchT)+1 <= cb) {
(*fnSetMapped)(lpb, rgchT);
strcpy(lpb, rgchT);
GetCurrentDirectory( cchDir, lpDir);
Ret = TRUE;
}
}
SetCurrentDirectory( CurrentDirectory );
return Ret;
} /* MiscBrowseForFile() */
BOOL NEAR PASCAL
StringLogger(
LPCSTR szStr,
BOOL fFileLog,
BOOL fSendRemote,
BOOL fPrintLocal
);
VOID
CmdMatchOpenedDocPrompt(
BOOL fRemote,
BOOL fLocal
)
{
int i;
LPSTR lpszName;
CmdInsertInit();
StringLogger( szBrowsePrompt, TRUE, fRemote, fLocal );
StringLogger( "Please select from one of the followings or <CR> for none:\n", TRUE, fRemote, fLocal );
for (i=0; i < lMatchCnt; i++) {
lpszName = Docs[MatchedList[i]].szFileName;
sprintf(szBrowsePrompt, "%d. %s\n", i+1, lpszName);
StringLogger( szBrowsePrompt, TRUE, fRemote, fLocal );
}
}
BOOL
CmdMatchOpenedDocInputString(
LPSTR lpsz
)
{
strcpy( szBrowseFname, lpsz );
fBrowseAnswer = TRUE;
CmdSetDefaultCmdProc();
return TRUE;
}
VOID
CmdBrowsePrompt(
BOOL fRemote,
BOOL fLocal
)
{
CmdInsertInit();
StringLogger( szBrowsePrompt, TRUE, fRemote, fLocal );
}
BOOL
CmdBrowseInputString(
LPSTR lpsz
)
{
strcpy( szBrowseFname, lpsz );
fBrowseAnswer = TRUE;
CmdSetDefaultCmdProc();
return TRUE;
}
int
InsertListViewItem(
HWND hwndList,
UINT uPos,
LV_ITEM * lplvi,
int nNumColumns,
...
)
/*++
Routine Description:
Inserts a root mapping pair into the list view control.
Arguments:
hwndList - List view control.
uPos - Position where the item is to be inserted.
lplvi - A prexisting item that is to be used as a template.
nNumColumns - Number of text columns to be added.
... - Text names of the columns
Return Value:
Returns the index of the new item if successful, or -1 otherwise.
--*/
{
Assert(nNumColumns);
LV_ITEM lvi;
int nColIdx;
int nIdx;
va_list marker;
// Initialize variable arguments
va_start(marker, nNumColumns);
// Initialize LV_ITEM members that are common to all items.
if (lplvi) {
memcpy(&lvi, lplvi, sizeof(lvi));
} else {
memset(&lvi, 0, sizeof(lvi));
}
lvi.mask = LVIF_TEXT;
// Add name (main item)
lvi.iItem = uPos;
lvi.pszText = va_arg(marker, PTSTR);
lvi.iSubItem = 0;
nIdx = ListView_InsertItem(hwndList, &lvi);
Assert(-1 != nIdx);
for (nColIdx = 1; nColIdx < nNumColumns; nColIdx++) {
// Add target (sub item)
ListView_SetItemText(hwndList, nIdx, nColIdx, va_arg( marker, PTSTR));
}
va_end( marker );
return nIdx;
}
INT_PTR
CALLBACK
DlgProcBadSymbols(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
// WARNING: On entry lpbs->pFindSymFileData->szImageFilePath contains the name of the image
// we want to find symbols for. On exit, it will be blank if the user DID NOT choose
// a symbol file. If the user chose a symbol file from the list or by browsing,
// lpbs->pFindSymFileData->szImageFilePath will contain the path to the file.
static LPBROWSESTRUCT lpbs = {0};
switch (message) {
case WM_INITDIALOG :
lpbs = (LPBROWSESTRUCT) lParam;
Assert(lpbs);
// Initialize image list
{
HWND hwndImageList = GetDlgItem(hDlg, IDC_LIST_IMAGE_FILE);
TCHAR szColHdr[MAX_MSG_TXT];
LV_COLUMN lvc;
Assert(hwndImageList);
// Set the extended style
ListView_SetExtendedListViewStyle(hwndImageList, LVS_EX_FULLROWSELECT);
// Setup the column header for the list view
// Add Column headers
// Initialize the LV_COLUMN structure.
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.pszText = szColHdr;
// Make the column width half of the window width
{
RECT rc;
GetClientRect(hwndImageList, &rc);
lvc.cx = rc.right * 2;
}
// Add the 1st column hdr
Dbg(LoadString(g_hInst, SYS_Image_Col_Hdr1,
szColHdr, sizeof(szColHdr) / sizeof(TCHAR) ));
lvc.iSubItem = 0;
Dbg(ListView_InsertColumn(hwndImageList, lvc.iSubItem, &lvc) != -1);
// Add the data to the list view
// Add the individual items
InsertListViewItem(hwndImageList,
1,
NULL,
1,
lpbs->pFindSymFileData->szImageFilePath);
// Select the first item
ListView_SetItemState(hwndImageList,
0,
LVIS_FOCUSED | LVIS_SELECTED,
0x000F);
}
// Initialize symbol list
{
HWND hwndSymbolList = GetDlgItem(hDlg, IDC_LIST_SYM_FILES);
TCHAR szColHdr[MAX_MSG_TXT];
LV_COLUMN lvc;
Assert(hwndSymbolList);
// Set the extended style
ListView_SetExtendedListViewStyle(hwndSymbolList, LVS_EX_FULLROWSELECT);
// Setup the column header for the list view
// Add Column headers
// Initialize the LV_COLUMN structure.
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.pszText = szColHdr;
// Make the column width half of the window width
{
RECT rc;
GetClientRect(hwndSymbolList, &rc);
lvc.cx = rc.right / 3;
}
// Add the 1st column hdr
Dbg(LoadString(g_hInst, SYS_Bad_Sym_Col_Hdr1,
szColHdr, sizeof(szColHdr) / sizeof(TCHAR) ));
lvc.iSubItem = 0;
Dbg(ListView_InsertColumn(hwndSymbolList, lvc.iSubItem, &lvc) != -1);
// Add the 2nd col hdr
Dbg(LoadString(g_hInst, SYS_Bad_Sym_Col_Hdr2,
szColHdr, sizeof(szColHdr) / sizeof(TCHAR) ));
lvc.iSubItem = 1;
Dbg(ListView_InsertColumn(hwndSymbolList, lvc.iSubItem, &lvc) != -1);
// Add the 3rd col hdr
Dbg(LoadString(g_hInst, SYS_Bad_Sym_Col_Hdr3,
szColHdr, sizeof(szColHdr) / sizeof(TCHAR) ));
lvc.iSubItem = 2;
// Make this one really wide.
lvc.cx *= 6;
Dbg(ListView_InsertColumn(hwndSymbolList, lvc.iSubItem, &lvc) != -1);
// Add the data to the list view
// Add the individual items
if ( IsListEmpty( (PLIST_ENTRY) &lpbs->pFindSymFileData->LoadErr )
&& !lpbs->pFindSymFileData->LoadErr.hSymFile ) {
// Nothing to list
EnableWindow(hwndSymbolList, FALSE);
} else {
// We have some files to add
EnableWindow(GetDlgItem(hDlg, IDC_BUT_LOAD), TRUE);
int nIdx = 0; // Position in list where it was actually placed.
UINT uPos = 0;
PTSTR pszSHE = NULL;
PTSTR pszExtendedSHE = NULL;
PSYM_FILE_LOAD_ERR pLoadErr = &lpbs->pFindSymFileData->LoadErr;
LVITEM lvitem;
LVITEM lvitem2;
LVITEM lvitem3;
do {
pszSHE = pLoadErr->pszSHE ? pLoadErr->pszSHE : "";
pszExtendedSHE = pLoadErr->pszExtendedSHE
? pLoadErr->pszExtendedSHE : "";
nIdx = InsertListViewItem(
hwndSymbolList,
ListView_GetItemCount(hwndSymbolList),
NULL,
3,
pLoadErr->szSymFilePath,
pszSHE,
pszExtendedSHE);
ZeroMemory(&lvitem, sizeof(lvitem));
ZeroMemory(&lvitem2, sizeof(lvitem2));
ZeroMemory(&lvitem3, sizeof(lvitem3));
lvitem.iItem = nIdx;
lvitem.mask = LVIF_PARAM;
lvitem.lParam = (LPARAM) pLoadErr;
lvitem2.iItem = nIdx;
lvitem2.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_INDENT
| LVIF_NORECOMPUTE | LVIF_PARAM | LVIF_STATE
| LVIF_DI_SETITEM;
lvitem3 = lvitem2;
Dbg( ListView_GetItem(hwndSymbolList, &lvitem2) );
Dbg( ListView_SetItem(hwndSymbolList, &lvitem) );
Dbg( ListView_GetItem(hwndSymbolList, &lvitem3) );
pLoadErr = pLoadErr->Flink;
} while ( pLoadErr != &lpbs->pFindSymFileData->LoadErr );
// Select the first item
ListView_SetItemState(hwndSymbolList,
0,
LVIS_FOCUSED | LVIS_SELECTED,
0x000F);
}
// Set focus manually
SetFocus(hwndSymbolList);
SetForegroundWindow( hDlg );
MessageBeep( MB_ICONQUESTION );
return FALSE;
}
case WM_COMMAND:
switch (wParam) {
default:
// return as not handled
return FALSE;
case IDC_BUT_ADVANCED:
DialogBox(g_hInst,
MAKEINTRESOURCE(DLG_BADSYMBOLS_ADV),
hDlg,
DlgProc_Adv_BadSymbols);
return TRUE;
case IDCANCEL:
// End the dialog and return the result
break;
case IDC_BUT_LOAD:
{
HWND hwndSymbolList = GetDlgItem(hDlg, IDC_LIST_SYM_FILES);
Assert(hwndSymbolList);
int nCurSel = ListView_GetNextItem(hwndSymbolList, -1, LVNI_SELECTED);
lpbs->pFindSymFileData->szImageFilePath[0] = NULL;
if (nCurSel >= 0) {
char sz[MAX_PATH];
ListView_GetItemText(
hwndSymbolList,
nCurSel,
0,
lpbs->pFindSymFileData->szImageFilePath,
sizeof(lpbs->pFindSymFileData->szImageFilePath) / sizeof(TCHAR));
}
}
// End the dialog and return the result
break;
case IDC_BUT_BROWSE:
// End the dialog and return the result
{
OPENFILENAME ofn = {0};
PTSTR pszFilter = NULL;
TCHAR szTitle[200] = {0};
TCHAR szNewSymFile[_MAX_PATH] = {0};
static TCHAR szInitialDir[_MAX_PATH] = {0};
if (!*szInitialDir) {
GetCurrentDirectory(sizeof(szInitialDir) / sizeof(TCHAR), szInitialDir);
}
// Title
Dbg(LoadString(g_hInst, DLG_Browse_For_Symbols_Title, szTitle, sizeof(szTitle) / sizeof(TCHAR) ));
// Add the abbreviated path to the title
AdjustFullPathName(lpbs->pFindSymFileData->szImageFilePath,
szTitle + _tcslen(szTitle), 10);
Assert(_tcslen(szTitle) < sizeof(szTitle) / sizeof(TCHAR) );
// File filters
{
const int MAX_EXTENSIONS = 3;
TCHAR szImageName[_MAX_FNAME] = {0};
// Include room for the ";"
TCHAR szCustFilter[(_MAX_FNAME + _MAX_EXT + 1) * MAX_EXTENSIONS] = {0};
PTSTR pszDefExtAllSyms = WKSP_DynaLoadString(g_hInst, DEF_Ext_All_SYMS);
PTSTR pszTypeFileAllSyms = WKSP_DynaLoadString(g_hInst, TYP_File_All_SYMS);
PTSTR pszDefExtCustSyms = WKSP_DynaLoadString(g_hInst, DEF_Ext_Cust_SYMS);
PTSTR pszTypeFileCustSyms = WKSP_DynaLoadString(g_hInst, TYP_File_Cust_SYMS);
PTSTR pszTmp;
// Build the specific filter
_tsplitpath(lpbs->pFindSymFileData->szImageFilePath, NULL, NULL, szImageName, NULL);
{
pszTmp = pszDefExtCustSyms;
for (int nCnt=0; *pszTmp; nCnt++, pszTmp += _tcslen(pszTmp) +1) {
if (nCnt) {
_tcscat(szCustFilter, ";");
}
_tcscat(szCustFilter, szImageName);
_tcscat(szCustFilter, pszTmp);
}
Assert(MAX_EXTENSIONS == nCnt);
}
pszFilter = pszTmp = (PTSTR) calloc(_tcslen(pszTypeFileCustSyms) + _tcslen(szCustFilter) *2
+ _tcslen(pszTypeFileAllSyms) + _tcslen(pszDefExtAllSyms)
+ 4 + 3 + 1, // 4 string terminator, plus " ()", plus the extra one at the end
sizeof(TCHAR));
_tcscpy(pszTmp, pszTypeFileCustSyms);
_tcscat(pszTmp, " (");
_tcscat(pszTmp, szCustFilter);
_tcscat(pszTmp, ")");
pszTmp += _tcslen(pszTmp) +1;
_tcscpy(pszTmp, szCustFilter);
pszTmp += _tcslen(pszTmp) +1;
_tcscpy(pszTmp, pszTypeFileAllSyms);
pszTmp += _tcslen(pszTmp) +1;
_tcscpy(pszTmp, pszDefExtAllSyms);
FREE_STR(pszDefExtAllSyms);
FREE_STR(pszTypeFileAllSyms);
FREE_STR(pszDefExtCustSyms);
FREE_STR(pszTypeFileCustSyms);
}
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hDlg;
//ofn.hInstance;
ofn.lpstrFilter = pszFilter;
//ofn.lpstrCustomFilter;
//ofn.nMaxCustFilter;
//ofn.nFilterIndex;
ofn.lpstrFile = szNewSymFile;
ofn.nMaxFile = sizeof(szNewSymFile) / sizeof(TCHAR);
//ofn.lpstrFileTitle;
//ofn.nMaxFileTitle;
ofn.lpstrInitialDir = szInitialDir;
ofn.lpstrTitle = szTitle;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR
| OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
//ofn.nFileOffset;
//ofn.nFileExtension;
//ofn.lpstrDefExt;
//ofn.lCustData;
//ofn.lpfnHook;
//ofn.lpTemplateName;
if (!GetOpenFileName(&ofn)) {
// User canceled browse or an error occurred.
// Stay where we are.
return FALSE;
} else {
// User selected a file
// Copy the drive letter here
TCHAR szDrive[_MAX_DRIVE] = {0};
TCHAR szDir[_MAX_DIR] = {0};
// Ask him if he wants to add this path to the sym search path
_tsplitpath(szNewSymFile, szDrive, szDir, NULL, NULL);
_tcscpy(szInitialDir, szDrive);
_tcscat(szInitialDir, szDir);
if (IDYES == VarMsgBox(hDlg, DLG_AddPathToSymSearchPath,
MB_ICONQUESTION | MB_YESNO, szInitialDir)) {
ModListAddSearchPath(szInitialDir);
}
// Place the data in the list head
_tcscpy(lpbs->pFindSymFileData->LoadErr.szSymFilePath, szNewSymFile);
}
FREE_STR(pszFilter);
}
break;
}
// End the dialog
lpbs->Rslt = wParam;
EndDialog(hDlg, wParam);
return TRUE;
}
return FALSE;
}
INT_PTR
CALLBACK
DlgProc_Adv_BadSymbols(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
switch (message) {
case WM_INITDIALOG :
// Set radio buttons
Assert(!g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors);
CheckRadioButton(hDlg, IDC_RADIO_IGNORE_ERRORS, IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS,
g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors
? IDC_RADIO_PROMPT_ON_ERROR : IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS);
return FALSE;
case WM_COMMAND:
switch (wParam) {
default:
// return as not handled
return FALSE;
case IDOK:
// Dlg is about to end. Set any modified values.
if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RADIO_IGNORE_ERRORS)) {
g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors = TRUE;
} else if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RADIO_PROMPT_ON_ERROR)) {
g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors = FALSE;
g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors = TRUE;
} else if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS)) {
g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors = FALSE;
g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors = FALSE;
} else {
Assert(!"Not supposed to happen");
}
break;
case IDCANCEL:
// End the dialog and return the result
break;
}
// End the dialog
EndDialog(hDlg, wParam);
return TRUE;
}
return FALSE;
}
INT_PTR
CALLBACK
DlgBrowse(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
static LPBROWSESTRUCT lpbs = {0};
char szAskBrowse[_MAX_PATH];
char szTemp[FILES_MENU_WIDTH + 1];
switch (message) {
case WM_INITDIALOG :
lpbs = (LPBROWSESTRUCT) lParam;
AdjustFullPathName( lpbs->pszFileName, szTemp, FILES_MENU_WIDTH);
strcpy(szAskBrowse, "Browse for: ");
strcat(szAskBrowse, szTemp);
strcat(szAskBrowse, " ?");
SetDlgItemText(hDlg, IDC_STXT_BROWSE_FOR, szAskBrowse);
SetForegroundWindow(hDlg);
MessageBeep( 0 );
return TRUE;
case WM_COMMAND:
switch (wParam) {
case IDCANCEL:
case IDOK:
case IDC_STXT_BROWSE_FOR:
lpbs->Rslt = wParam;
EndDialog( hDlg,wParam );
return TRUE;
case IDWINDBGHELP :
Dbg(WinHelp(hDlg,szHelpFileName, HELP_CONTEXT, ID_ASKBROWSE_HELP));
return TRUE;
}
break;
}
return FALSE;
}
DWORD
BrowseThread(
LPVOID lpv
)
{
HWND hDlg;
MSG msg;
LPBROWSESTRUCT lpbs = (LPBROWSESTRUCT)lpv;
hDlg = CreateDialogParam( g_hInst, MAKEINTRESOURCE(lpbs->DlgId),
NULL, lpbs->DlgProc, (LPARAM)lpbs );
if (!hDlg) {
return FALSE;
}
ShowWindow( hDlg, SW_SHOW );
while ((lpbs->Rslt == (DWORD_PTR)-1) && (GetMessage (&msg, NULL, 0, 0))) {
if (!IsDialogMessage( hDlg, &msg )) {
TranslateMessage ( &msg );
DispatchMessage ( &msg );
}
}
return TRUE;
}
BOOL
SrcBrowseForFile(
LSZ lpb,
UINT cb
)
{
HANDLE hThread;
DWORD id;
BROWSESTRUCT bs = {0};
MSG msg;
/*
* Check to see if running from scripts -- if so then
* don't bring up this dialog and error boxes.
*/
if (AutoTest) {
return FALSE;
}
if (NoPopups) {
browseagain:
sprintf( szBrowsePrompt, "Cannot load [ %s ] - Enter new path or <CR> to ignore ", lpb );
fBrowseAnswer = FALSE;
CmdSetCmdProc( CmdBrowseInputString, CmdBrowsePrompt );
CmdSetAutoHistOK(FALSE);
CmdSetEatEOLWhitespace(FALSE);
CmdDoPrompt( TRUE, TRUE );
while (GetMessage( &msg, NULL, 0, 0 )) {
ProcessQCQPMessage( &msg );
if (fBrowseAnswer) {
break;
}
}
if (szBrowseFname[0]) {
if (FileExist( szBrowseFname )) {
strcpy( lpb, szBrowseFname );
return TRUE;
} else {
goto browseagain;
}
}
CmdSetDefaultCmdProc();
CmdDoPrompt(TRUE, TRUE);
return FALSE;
}
EnsureFocusDebugger();
bs.Rslt = (DWORD_PTR)-1;
bs.DlgId = DLG_ASKSRCBROWSE;
bs.DlgProc = DlgBrowse;
bs.pszFileName = lpb;
bs.FnameSize = cb;
hThread = CreateThread( NULL, 0, BrowseThread, (LPVOID)&bs, 0, &id );
if (!hThread) {
return FALSE;
}
WaitForSingleObject( hThread, INFINITE );
if (bs.Rslt == IDCANCEL) {
return FALSE;
} else {
return MiscBrowseForFile(lpb,
cb,
SrcFileDirectory,
sizeof(SrcFileDirectory),
DEF_Ext_C,
DLG_Browse_Filebox_Title,
SrcSetMapped,
GetOpenFileNameHookProc,
IDD_DLG_FILEOPEN_EXPLORER_EXTENSION);
}
} /* SrcBrowseForFile() */
INT_PTR
ExeBrowseBadSym(
PFIND_SYM_FILE pFindSymFileData
)
/*++
Routine Description:
Arguments:
pszImageFile - Name of the image that we hope to find symbols for
pFindSymFileData - Info returned by DBGHELP.DLL
Returns:
IDCANCEL - User does not wish to load a corresponding sym file.
IDC_BUT_LOAD - User selected a sym file from the list of files previously tested.
IDC_BUT_BROWSE - New file selected.
--*/
{
Assert(pFindSymFileData);
HANDLE hThread;
DWORD id;
BROWSESTRUCT bs = {0};
if (arCmdline == AutoRun || NoPopups) {
// Don't load symbols with any errors
return IDCANCEL;
}
bs.Rslt = (DWORD_PTR)-1;
bs.DlgId = DLG_BADSYMBOLS;
bs.DlgProc = DlgProcBadSymbols;
//bs.szFileName;
//bs.FnameSize;
bs.pFindSymFileData = pFindSymFileData;
hThread = CreateThread( NULL, 0, BrowseThread, (LPVOID)&bs, 0, &id );
if (!hThread) {
return FALSE;
}
WaitForSingleObject( hThread, INFINITE );
return bs.Rslt;
}
VOID
ExeSetMapped(
LSZ lsz1,
LSZ lsz2
)
{
// nobody home
}
/*** SrcSetMasked
** Synopsis:
** void = SrcSetMasked(lsz)
** Entry:
** lsz - Pointer to byte array for unfound name
** Returns:
** Nothing
** Description:
** This routine will take the entry name and set it as to be
** masked out. This allows use to prevent re-display of error
** messages on the same file.
*/
VOID
SrcSetMasked(
LSZ lsz
)
{
ATOM atom;
atom = AddAtom(lsz);
if (atom == 0) {
return;
}
if (RgAtomMaskedNames == NULL) {
CMacAtomMasked = 10;
RgAtomMaskedNames = (ATOM *) malloc(sizeof(ATOM)*CMacAtomMasked);
} else if (CAtomMasked == CMacAtomMasked) {
CMacAtomMasked += 10;
RgAtomMaskedNames = (ATOM *) realloc(RgAtomMaskedNames, sizeof(ATOM)*CMacAtomMasked);
}
RgAtomMaskedNames[CAtomMasked] = atom;
CAtomMasked += 1;
return;
} /* SrcSetMasked() */
/*** SrcSetMapped
** Synopsis:
** void = SrcSetmapped(lsz1, lsz2)
** Entry:
** lsz1 - Name of file to be mapped from
** lsz2 - Name of file to be mapped to
** Returns:
** Nothing
** Description:
** This function will setup a mapping of source file names from
** file name lsz1 to lsz2. This will allow for a fast reamapping
** without haveing to do searches or ask the user a second time.
*/
VOID
SrcSetMapped(
LSZ lsz1,
LSZ lsz2
)
{
ATOM atomSrc = AddAtom(lsz1);
ATOM atomTrg = AddAtom(lsz2);
if (RgAtomMappedNames == NULL) {
CMacAtomMapped = 10;
RgAtomMappedNames = (struct MpPair *) malloc(sizeof(*RgAtomMappedNames)*CMacAtomMapped);
} else if (CAtomMapped == CMacAtomMapped) {
CMacAtomMapped += 10;
RgAtomMappedNames = (struct MpPair *) realloc(RgAtomMappedNames, sizeof(*RgAtomMappedNames)*CMacAtomMapped);
}
RgAtomMappedNames[CAtomMapped].atomSrc = atomSrc;
RgAtomMappedNames[CAtomMapped].atomTarget = atomTrg;
CAtomMapped += 1;
} /* SrcSetMapped() */
/*** SrcMapSourceFilename
** Synopsis:
** int = SrcMapSourceFilename(lpszSrc, cbSrc, flags, bUserActivated)
** Entry:
** lpszSrc - Source buffer to map file in
** cbSrc - size of source buffer
** flags - flags to control behavior
** bUserActivated - Indicates whether this action was initiated by the
** user or by windbg. The value is to determine the Z order of
** any windows that are opened.
** Returns:
** -2 - operation canceled
** -1 - error occured
** 0 - No mapping done -- no source file mapped
** 1 - Mapping done -- no file openned
** 2 - Mapping done -- openned a new source window
** Description:
** This function will setup a mapping of source file names from
** file name lsz1 to lsz2. This will allow for a fast reamapping
** without haveing to do searches or ask the user a second time.
*/
int
PASCAL
SrcMapSourceFilename(
LPSTR lpszSrc,
UINT cbSrc,
int flags,
FINDDOC lpFindDoc,
BOOL bUserActivated
)
{
ATOM atomFile;
int doc;
/*
** Step 1. Is this file actually in a source window. If
** so then no changes need to be made to the source
** file name.
*/
if (lpFindDoc == NULL) {
lpFindDoc = FindDoc;
}
if ((*lpFindDoc)(lpszSrc, &doc, TRUE)) {
return (1);
}
/*
** Step 2. Make sure file is not on the "I'don't want to hear about it
** list". If file has been mapped or exists on disk, it would not
** not have been on this list.
*/
atomFile = FindAtom(lpszSrc);
if (atomFile != (ATOM) NULL && SrcNameIsMasked(atomFile)) {
return 0;
}
/*
** Step 3. Now check to see if the file has been previously remapped
** or not
*/
if ((atomFile != (ATOM) NULL) &&
SrcNameIsMapped(atomFile, lpszSrc, cbSrc)) {
if ((*lpFindDoc)(lpszSrc, &doc, TRUE)) {
return 1;
} else if (flags & SRC_MAP_OPEN) {
if (AddFile(MODE_OPEN, DOC_WIN, lpszSrc, NULL, NULL, TRUE, -1, -1, bUserActivated) != -1) {
return 2;
}
return -1;
}
return 0;
}
/*
** Step 4. The file we are looking for is not on the "I don't
** want to hear about it list" and has no forward mapping.
** Let's consider opened file of the same name.
*/
doc = MatchOpenedDoc(lpszSrc, cbSrc);
if (doc != 0) {
return(doc);
}
/*
** Step 5. Does the requested file in fact actually exist on
** the disk. If so then we want to read in the file
** if requested and return the correct code.
** This step does not need to be taken if we are just remapping
** the file name. In this case we are just interested if we
** have done any type of file mapping on the name yet.
*/
if ((flags & SRC_MAP_OPEN) && FileExist(lpszSrc)) {
if (flags & SRC_MAP_OPEN) {
if (AddFile(MODE_OPEN, DOC_WIN, lpszSrc, NULL, NULL, TRUE, -1, -1, bUserActivated) != -1) {
return 2;
} else {
return -1;
}
}
return 1;
}
/*
** Step 6. Now check to see if the file can be root map
** or not
*/
if (SrcSearchOnRoot(lpszSrc, cbSrc)) {
if ((*lpFindDoc)(lpszSrc, &doc, TRUE) ) {
return 1;
} else if (flags & SRC_MAP_OPEN) {
if (AddFile(MODE_OPEN, DOC_WIN, lpszSrc, NULL, NULL, TRUE, -1, -1, bUserActivated) != -1) {
return 2;
}
return -1;
}
return 0;
}
/*
** If we are only interested in checking for an existing re-mapping
** on the source file then we do not need to go any futher
*/
if (flags & SRC_MAP_ONLY) {
return 0;
}
/*
** Step 7. We must now search the source file path for the file. This
** needs to include the cwd and exe directory for the file
*/
if (SrcSearchOnPath(lpszSrc, cbSrc, TRUE) || SrcBrowseForFile(lpszSrc, cbSrc)) {
if ((*lpFindDoc)(lpszSrc, &doc, TRUE)) {
return 1;
} else if (flags & SRC_MAP_OPEN) {
if (AddFile(MODE_OPEN, DOC_WIN, lpszSrc, NULL, NULL, TRUE, -1, -1, bUserActivated) != -1) {
return 2;
}
return -1;
}
return 0;
} else {
// Error occurred, couldn't find it or something.
SrcSetMasked(lpszSrc); // add file to the I don't
// want to hear about it list.
return -2;
}
} /* SrcMapSourceFilename() */
/*** SrcBackMapSourceFilename
** Synopsis:
** int = SrcBackMapSourceFilename(lpszTarget, cbTarget)
** Entry:
** lpszTarget - Source buffer to map file from
** cbTarget - size of source buffer
** Returns:
** 0 - No mapping done -- no source file mapped
** 1 - Mapping done
** Description:
** This function will look from a mapping which goes to the
** file lpszTarget and replace it with the source file. Thus
** this code does the opposit of SrcMapSourceFilename.
*/
int
SrcBackMapSourceFilename(
LPSTR lpszTarget,
UINT cbTarget
)
{
ATOM atomTarget;
int i;
/*
* Look for the file name in the atom table. If it can't be found
* then there must not be any mapping for this file.
*/
atomTarget = FindAtom(lpszTarget);
if (atomTarget == (ATOM) NULL) {
return 0;
}
for (i=0; i<CAtomMapped; i++) {
if (RgAtomMappedNames[i].atomTarget == atomTarget) {
GetAtomName(RgAtomMappedNames[i].atomSrc, lpszTarget, cbTarget);
return 1;
}
}
return 0;
} /* SrcBackMapSourceFilename() */
VOID
SetPTState(
PSTATEX pstate,
TSTATEX tstate
)
/*++
Routine Description:
Set current process and thread states
Arguments:
pstate - Supplies new pstate, or -1 to leave it the same
tstate - Supplies new tstate, or -1 to leave it the same
Return Value:
none
--*/
{
if (pstate >= 0) {
if (LppdCur != NULL) LppdCur->pstate = pstate;
}
if (tstate >= 0) {
if (LptdCur != NULL) LptdCur->tstate = tstate;
}
EnableToolbarControls();
} /* SetPTState() */
VOID
AsyncStop(
void
)
/*++
Routine Description:
This routine will send a message to the DM to cause an ASYNC stop
on the current thread.
Arguments:
None
Return Value:
None.
--*/
{
/*
* If the current process is not running then we don't need
* to do an ASYNC stop
*/
if (!LppdCur) {
MessageBeep(MB_OK);
CmdLogFmt("Cannot stop the current process\r\n");
return;
}
/*
* Send down the ASYNC STOP message
*/
OSDAsyncStop(LppdCur->hpid, 0);
return;
} /* AsyncStop() */
void
FormatKdParams(
LPSTR p
)
{
LPSTR lpsz;
int len;
#define append(s,n) p=p+sprintf(p,s,n)
append( "baudrate=%d ", g_contKernelDbgPreferences_WkSp.m_dwBaudRate );
append( "port=%d ", g_contKernelDbgPreferences_WkSp.m_dwPort );
append( "cache=%d ", g_contKernelDbgPreferences_WkSp.m_dwCache );
append( "initialbp=%d ", g_contKernelDbgPreferences_WkSp.m_bInitialBp );
append( "usemodem=%d ", g_contKernelDbgPreferences_WkSp.m_bUseModem );
append( "goexit=%d ", g_contKernelDbgPreferences_WkSp.m_bGoExit );
if (g_contKernelDbgPreferences_WkSp.m_pszCrashDump
&& *g_contKernelDbgPreferences_WkSp.m_pszCrashDump) {
append( "crashdump=%s ", g_contKernelDbgPreferences_WkSp.m_pszCrashDump );
}
len = ModListGetSearchPath( NULL, 0 );
if (len) {
lpsz = (PSTR) malloc( len );
ModListGetSearchPath( lpsz, len );
append( "symbolpath=%s ", lpsz );
free(lpsz);
}
#undef append
}
// Root Mapping Routines
/*** RootSetMapped
** Synopsis:
** BOOL = RootSetMapped(lsz1, lsz2)
** Entry:
** lsz1 - Name of file to be mapped from
** lsz2 - Name of file to be mapped to
** Returns:
** TRUE if mapping was successfully recorded
** Description:
** This function will setup a mapping of source root to target root.
** This will allow for a fast reamapping without haveing to do
** searches or ask the user a second time.
*/
BOOL
RootSetMapped(
LSZ lpszSrcRoot,
LSZ lpszTargetRoot
)
{
UINT i;
LPSTR p, q;
CHAR chpSaved, chqSaved;
if (lpszSrcRoot == NULL || lpszTargetRoot == NULL ||
*lpszSrcRoot == '\0' || *lpszTargetRoot == '\0') {
return FALSE; // strlen is zero
}
if (!((lpszSrcRoot[1] == ':' ||
(lpszSrcRoot[0] == '\\' && lpszSrcRoot[1] == '\\')) &&
(lpszTargetRoot[1] == ':' ||
(lpszTargetRoot[0] == '\\' && lpszTargetRoot[1] == '\\'))
)
) {
return FALSE; // ignore non fullpath for now
}
// Make both strings lower case so we don't have some problems
_strlwr(lpszSrcRoot);
_strlwr(lpszTargetRoot);
p = lpszSrcRoot + strlen(lpszSrcRoot) - 1;
q = lpszTargetRoot + strlen(lpszTargetRoot) - 1;
while (p >= lpszSrcRoot && q >= lpszTargetRoot) {
if (*(p--) != *(q--)) {
// Move to last matched character
p += 1;
q += 1;
// If last matched char is a ':' then skip 1 character
// If last matched is ":\" then skip 2 characters
if (*p == ':') {
p++;
q++;
if (*p == '\\') {
p++;
q++;
}
}
// If last matched char is a "\" then skip 1 character
else if (*p == '\\') {
p++;
q++;
}
// If last matched is not a "\" then
// look for a slash and skip it
else {
while (*p != '\\') {
p++;
q++;
}
p++;
q++;
}
chpSaved = *p;
chqSaved = *q;
*p = *q = '\0';
for (i=0; i<CMappedRoots; i++) {
if (_stricmp(RgMappedRoots[i].lpszSrcRoot, lpszSrcRoot) == 0 &&
_stricmp(RgMappedRoots[i].lpszTargetRoot, lpszTargetRoot) == 0)
{
*p = chpSaved;
*q = chqSaved;
return TRUE; // already there
}
}
if (CMappedRoots >= MAX_MAPPED_ROOTS) {
memcpy(RgMappedRoots,
&(RgMappedRoots[1]),
sizeof(struct MRootPair)*--CMappedRoots);
}
if ((RgMappedRoots[CMappedRoots].lpszSrcRoot = _strdup(lpszSrcRoot)) == NULL) {
*p = chpSaved;
*q = chqSaved;
return FALSE;
}
if ((RgMappedRoots[CMappedRoots].lpszTargetRoot = _strdup(lpszTargetRoot)) == NULL) {
free(RgMappedRoots[CMappedRoots].lpszSrcRoot);
*p = chpSaved;
*q = chqSaved;
return FALSE; // error - out of memory? - skip the mapping
}
RgMappedRoots[CMappedRoots++].dwSrcLen = strlen(lpszSrcRoot);
*p = chpSaved;
*q = chqSaved;
return (TRUE);
}
}
return (FALSE);
} /* RootSetMapped() */
/*** RootNameIsMapped
** Synopsis:
** BOOL = RootNameIsMapped(lpb, lpszDest, cbDest)
** Entry:
** lpb - Name of file to try for root mapping
** lpszDest - Name of file root mapped to
** cbDest - Size of lpszDest buffer
** Returns:
** TRUE if mapping was successfully done
** Description:
** This function will try to map the given source in lpb to it's mapped
** location. If file does exists, it will return TRUE and the new full
** file path thru lpszDest.
*/
BOOL
RootNameIsMapped(
LPSTR lpb,
LPSTR lpszDest,
UINT cbDest
)
{
struct MRootPair *lpRoot;
char rgch[_MAX_PATH];
char *p;
INT i;
for (i=(INT)CMappedRoots-1; i >= 0; i--) {
lpRoot = &(RgMappedRoots[i]);
if (_strnicmp(lpRoot->lpszSrcRoot, lpb, lpRoot->dwSrcLen) == 0) {
strcpy(rgch, lpRoot->lpszTargetRoot);
p = rgch + strlen(rgch) - 1;
if (*p == '\\') {
*p = 0;
}
if (FindNameOn(lpszDest, cbDest, rgch, lpb+lpRoot->dwSrcLen)) {
return(TRUE);
}
}
}
return(FALSE);
}
/*** GetRootNameMappings
** Synopsis:
** BOOL = GetRootNameMappings(String, Length)
** Entry:
** String - Address of the variable pointing to the multistring
** Length - Address of Length of the multi-string
** Returns:
** TRUE if operation completed successfully
** Description:
** This function scans thru all the root mappings and returns
** all the source and target roots in the form of a multi-string
*/
BOOL
GetRootNameMappings(
LPSTR *String,
DWORD *Length
)
{
struct MRootPair *lpRoot = RgMappedRoots;
UINT i;
for (i=0; i<CMappedRoots; lpRoot++, i++) {
if (!AddToMultiString(String, Length, lpRoot->lpszSrcRoot))
return(FALSE);
if (!AddToMultiString(String, Length, lpRoot->lpszTargetRoot))
return(FALSE);
}
return(TRUE);
}
/*** SetRootNameMappings
** Synopsis:
** BOOL = SetRootNameMappings(String, Length)
** Entry:
** String - Pointer to the multistring
** Length - Length of the multi-string
** Returns:
** TRUE if operation completed successfully
** Description:
** This function clears all the current root mappings
** and reconstruct the root mappings table thru the given
** multi-string.
*/
BOOL
SetRootNameMappings(
LPSTR String,
DWORD Length
)
{
struct MRootPair *lpRoot = RgMappedRoots;
DWORD Next = 0;
UINT i;
LPSTR lpsztmp1, lpsztmp2;
for (i=0; i<CMappedRoots; lpRoot++, i++) {
if (lpRoot->lpszSrcRoot)
free(lpRoot->lpszSrcRoot);
if (lpRoot->lpszTargetRoot)
free(lpRoot->lpszTargetRoot);
}
CMappedRoots = 0;
lpRoot = RgMappedRoots;
while ((lpsztmp1 = GetNextStringFromMultiString(String, Length, &Next)) &&
(lpsztmp2 = GetNextStringFromMultiString(String, Length, &Next))) {
lpRoot->dwSrcLen = strlen(lpsztmp1);
if ((lpRoot->lpszSrcRoot = _tcsdup(lpsztmp1)) == NULL)
return (FALSE);
if ((lpRoot->lpszTargetRoot = _tcsdup(lpsztmp2)) == NULL) {
free(lpRoot->lpszSrcRoot);
return (FALSE);
}
lpRoot++;
CMappedRoots++;
if (CMappedRoots >= MAX_MAPPED_ROOTS)
return (GetNextStringFromMultiString(String, Length, &Next) == NULL);
lpsztmp2 = NULL;
}
return (lpsztmp1 == NULL);
}
INT_PTR
WINAPI
DlgFileSearchResolve(
HWND hDlg,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
HDC hdc;
int i;
int j;
int Idx;
int LargestString = 0;
SIZE Size;
HWND hList;
LPSTR lpszName;
CHAR rgch[_MAX_PATH];
static DWORD HelpArray[]=
{
ID_FSRESOLVE_LIST, IDH_FSRESOLVE_LIST,
ID_FSRESOLVE_USE, IDH_FSRESOLVE_USE,
ID_FSRESOLVE_ADDNONE, IDH_FSRESOLVE_ADD,
ID_FSRESOLVE_ADDROOT, IDH_FSRESOLVE_ADD,
ID_FSRESOLVE_ADDSOURCE, IDH_FSRESOLVE_ADD,
0, 0
};
Unreferenced( lParam );
switch( msg ) {
case WM_INITDIALOG:
SetDlgItemText(hDlg,
ID_FSRESOLVE_STRING,
szFSSrcName
);
LoadString(g_hInst, DLG_ResolveFSCaption, rgch, sizeof(rgch));
SetWindowText( hDlg, rgch );
hList = GetDlgItem(hDlg, ID_FSRESOLVE_LIST);
// Add the name of the file that was obtained from the image.
Idx = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM) (LPCSTR) szFSSrcName);
if (Idx >= LB_OKAY) {
// String successfully added to the list box.
SendMessage(hList,
LB_SETITEMDATA,
(WPARAM) Idx,
(LPARAM) MATCHLIST_USEFILEFROMIMAGE
);
}
for (i=0; i < lMatchCnt; i++) {
lpszName = Docs[MatchedList[i]].szFileName;
Idx = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)lpszName);
if (Idx >= LB_OKAY) {
// String successfully added to the list box.
SendMessage(hList,
LB_SETITEMDATA,
(WPARAM) Idx,
(LPARAM) MatchedList[i]
);
}
}
SendMessage(hList, LB_SETCURSEL, 0, 0L);
CheckRadioButton(hDlg, ID_FSRESOLVE_ADDNONE, ID_FSRESOLVE_ADDSOURCE,
ID_FSRESOLVE_ADDNONE);
lMatchIdx = MATCHLIST_NONEMATCHED;
return TRUE;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle,
"windbg.hlp",
HELP_WM_HELP,
(ULONG_PTR) HelpArray
);
return TRUE;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam,
"windbg.hlp",
HELP_CONTEXTMENU,
(ULONG_PTR) HelpArray
);
return TRUE;
case WM_COMMAND:
switch( LOWORD( wParam ) ) {
case ID_FSRESOLVE_USE:
Idx = SendDlgItemMessage(hDlg,
ID_FSRESOLVE_LIST,
LB_GETCURSEL,
0,
0
);
lMatchIdx = SendDlgItemMessage(hDlg,
ID_FSRESOLVE_LIST,
LB_GETITEMDATA,
(WPARAM) Idx,
0
);
Assert(lMatchIdx < lMatchCnt);
FAddToSearchPath = IsDlgButtonChecked( hDlg, ID_FSRESOLVE_ADDSOURCE );
FAddToRootMap = IsDlgButtonChecked(hDlg, ID_FSRESOLVE_ADDROOT);
if (FAddToSearchPath || FAddToRootMap) {
Assert(FAddToSearchPath != FAddToRootMap);
Assert(IsDlgButtonChecked(hDlg, ID_FSRESOLVE_ADDNONE) == FALSE);
} else {
Assert(IsDlgButtonChecked(hDlg, ID_FSRESOLVE_ADDNONE));
}
EndDialog(hDlg, TRUE);
return TRUE;
case IDCANCEL: // none
lMatchIdx = -1;
EndDialog(hDlg, TRUE);
return TRUE;
}
break;
}
return FALSE;
}
INT_PTR
CALLBACK
DlgProc_EditRootMapping(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
Dlg proc for the user to enter a source root mapping pair.
Arguments:
lParam - Supplies a valid "MRootPair" struct.
Return Value:
TRUE if the WM message was handled, FALSE if not.
--*/
{
static struct MRootPair * lpMRootPair = NULL;
static DWORD HelpArray[]=
{
IDC_EDIT_SRCROOT, IDH_EDIT_SRCROOT,
IDC_EDIT_TARGETROOT, IDH_EDIT_TARGETROOT,
0, 0
};
switch (uMsg) {
case WM_INITDIALOG:
Dbg(lParam);
lpMRootPair = (struct MRootPair *) lParam;
SetDlgItemText(hwndDlg, IDC_EDIT_SRCROOT, lpMRootPair->lpszSrcRoot);
SetDlgItemText(hwndDlg, IDC_EDIT_TARGETROOT, lpMRootPair->lpszTargetRoot);
// Limit the amount of text
SendDlgItemMessage(hwndDlg, IDC_EDIT_SRCROOT, EM_LIMITTEXT, _MAX_PATH-1, 0);
SendDlgItemMessage(hwndDlg, IDC_EDIT_TARGETROOT, EM_LIMITTEXT, _MAX_PATH-1, 0);
break;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle,
"windbg.hlp",
HELP_WM_HELP,
(ULONG_PTR) HelpArray );
return TRUE;
case WM_CONTEXTMENU:
WinHelp ((HWND) wParam,
"windbg.hlp",
HELP_CONTEXTMENU,
(ULONG_PTR) HelpArray );
return TRUE;
case WM_COMMAND:
{
WORD wNotifyCode = HIWORD(wParam); // notification code
WORD wID = LOWORD(wParam); // item, control, or accelerator identifier
HWND hwndCtl = (HWND) lParam; // handle of control
BOOL bEnabled;
switch(wID) {
case IDOK:
GetDlgItemText(hwndDlg, IDC_EDIT_SRCROOT, lpMRootPair->lpszSrcRoot, MAX_PATH);
GetDlgItemText(hwndDlg, IDC_EDIT_TARGETROOT, lpMRootPair->lpszTargetRoot, MAX_PATH);
// Can't have blanks
if (0 == strlen(lpMRootPair->lpszSrcRoot)
|| 0 == strlen(lpMRootPair->lpszTargetRoot)) {
char sz[MAX_MSG_TXT];
LoadString(g_hInst, ERR_Entries_Cant_be_blank, sz, sizeof(sz));
MessageBox(hwndDlg, sz, NULL, MB_OK | MB_ICONWARNING | MB_APPLMODAL);
} else {
EndDialog(hwndDlg, IDOK);
}
return TRUE;
break;
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
return TRUE;
break;
}
}
break;
}
return FALSE;
}
void
Enable_DlgProc_SrcSearchPath_Buttons(
HWND hwndDlg
)
/*++
Routine Description:
Controls the enabling/disabling of the buttons add, edit, delete, up, down
buttons.
Arguments:
hwndDlg - Dlg window
Return Value:
--*/
{
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
HWND hwndAdd = GetDlgItem(hwndDlg, IDC_BUT_ADD);
HWND hwndEdit = GetDlgItem(hwndDlg, IDC_BUT_EDIT);
HWND hwndDelete = GetDlgItem(hwndDlg, IDC_BUT_DELETE);
HWND hwndMoveUp = GetDlgItem(hwndDlg, IDC_BUT_MOVE_UP);
HWND hwndMovedown = GetDlgItem(hwndDlg, IDC_BUT_MOVE_DOWN);
Assert(hwndList);
Assert(hwndAdd);
Assert(hwndEdit);
Assert(hwndDelete);
Assert(hwndMoveUp);
Assert(hwndMovedown);
int nCurSel = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
int nCount = ListView_GetItemCount(hwndList);
// As long as we don't exceed the max number of mappings.
EnableWindow(hwndAdd, nCount < MAX_MAPPED_ROOTS);
// As long as something is selected.
EnableWindow(hwndEdit, (-1 != nCurSel));
EnableWindow(hwndDelete, (-1 != nCurSel));
// Something must be selected and it must not be at the top.
EnableWindow(hwndMoveUp, (0 < nCurSel));
// Something must be selected and it must not be at the bottom.
EnableWindow(hwndMovedown, (-1 != nCurSel && nCurSel < nCount-1));
}
// This is not directly used by the prop sheet but by the IDD_DLG_SRC_SEARCH_PATH dlg
// that is invoked from the DlgProc_SourceFiles function by pressing the "Search Order" button.
INT_PTR
CALLBACK
DlgProc_SrcSearchPath(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
/*++
Routine Description:
Dlg proc
--*/
{
static DWORD HelpArray[]=
{
IDC_LIST1, IDH_MAP,
IDC_BUT_ADD, IDH_ADD,
IDC_BUT_EDIT, IDH_EDIT,
IDC_BUT_DELETE, IDH_DEL,
IDC_BUT_MOVE_UP, IDH_MOVEUP,
IDC_BUT_MOVE_DOWN, IDH_MOVEDOWN,
IDC_EDIT_DEF_SRC_SEARCH_PATH, IDH_DEFPATH,
IDC_HELP_DEF_SRC_SEARCH_PATH, IDH_SEARCHPATH,
0, 0
};
switch (uMsg) {
case WM_INITDIALOG:
{
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
char szColHdr[MAX_MSG_TXT];
UINT u;
LV_COLUMN lvc;
Assert(hwndList);
// Limit the text to a multiple of MAX_PATH
SendDlgItemMessage(hwndDlg, IDC_EDIT_DEF_SRC_SEARCH_PATH, EM_LIMITTEXT, MAX_PATH-1, 0);
ListView_DeleteAllItems(hwndList);
// Set the extended style
ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT);
// Setup the column header for the list view
// Add Column headers
// Initialize the LV_COLUMN structure.
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = 300;
lvc.pszText = szColHdr;
// Add the 1st column hdr
Dbg(LoadString(g_hInst, SYS_SRC_ROOT_MAPPING_COL_HDR1,
szColHdr, sizeof(szColHdr)));
lvc.iSubItem = 0;
Dbg(ListView_InsertColumn(hwndList, lvc.iSubItem, &lvc) != -1);
// Add the 2nd col hdr
Dbg(LoadString(g_hInst, SYS_SRC_ROOT_MAPPING_COL_HDR2,
szColHdr, sizeof(szColHdr)));
lvc.iSubItem = 1;
Dbg(ListView_InsertColumn(hwndList, lvc.iSubItem, &lvc) != -1);
// Add the data to the list view
// Add the individual items
for (u=0; u<CMappedRoots; u++) {
InsertListViewItem(hwndList,
u,
NULL,
2,
RgMappedRoots[u].lpszSrcRoot,
RgMappedRoots[u].lpszTargetRoot
);
}
// Select the first item
ListView_SetItemState(hwndList, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F);
if (g_contPaths_WkSp.m_pszSourceCodeSearchPath) {
SetDlgItemText(hwndDlg,
IDC_EDIT_DEF_SRC_SEARCH_PATH,
g_contPaths_WkSp.m_pszSourceCodeSearchPath
);
}
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
}
return TRUE;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle,
"windbg.hlp",
HELP_WM_HELP,
(ULONG_PTR) HelpArray );
return TRUE;
case WM_CONTEXTMENU:
WinHelp ((HWND) wParam,
"windbg.hlp",
HELP_CONTEXTMENU,
(ULONG_PTR) HelpArray );
return TRUE;
case WM_NOTIFY:
// It has to be from the list view control. Its the
// only thing on this Dlg box that would send a
// WM_NOTIFY msg.
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
break;
case WM_COMMAND:
{
WORD wNotifyCode = HIWORD(wParam); // notification code
WORD wID = LOWORD(wParam); // item, control, or accelerator identifier
HWND hwndCtl = (HWND) lParam; // handle of control
BOOL bEnabled;
switch(wID) {
case IDC_BUT_ADD:
if (BN_CLICKED == wNotifyCode) {
struct MRootPair mrp;
// These must be MAX_PATH or greater in size.
char szSrcRoot[MAX_PATH] = {0}, szTargetRoot[MAX_PATH] = {0};
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
Assert(hwndList);
mrp.lpszSrcRoot = szSrcRoot;
mrp.lpszTargetRoot = szTargetRoot;
// Pass the values into the dlg
if (IDOK == DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EDIT_SRC_ROOT_MAPPING),
hwndDlg, DlgProc_EditRootMapping, (LPARAM) &mrp)) {
Dbg(strlen(szSrcRoot) < sizeof(szSrcRoot));
Dbg(strlen(szTargetRoot) < sizeof(szTargetRoot));
InsertListViewItem(hwndList, ListView_GetItemCount(hwndList), NULL, 2,
szSrcRoot, szTargetRoot);
}
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
return TRUE;
}
break;
case IDC_BUT_EDIT:
if (BN_CLICKED == wNotifyCode) {
struct MRootPair mrp;
// These must be MAX_PATH or greater in size.
char szSrcRoot[MAX_PATH] = {0}, szTargetRoot[MAX_PATH] = {0};
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
int nCurSel = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
Assert(hwndList);
Assert(-1 != nCurSel);
mrp.lpszSrcRoot = szSrcRoot;
mrp.lpszTargetRoot = szTargetRoot;
ListView_GetItemText(hwndList, nCurSel, 0, szSrcRoot, sizeof(szSrcRoot));
ListView_GetItemText(hwndList, nCurSel, 1, szTargetRoot, sizeof(szTargetRoot));
if (IDOK == DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EDIT_SRC_ROOT_MAPPING),
hwndDlg, DlgProc_EditRootMapping, (LPARAM) &mrp)) {
Dbg(strlen(szSrcRoot) < sizeof(szSrcRoot));
Dbg(strlen(szTargetRoot) < sizeof(szTargetRoot));
ListView_SetItemText(hwndList, nCurSel, 0, szSrcRoot);
ListView_SetItemText(hwndList, nCurSel, 1, szTargetRoot);
}
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
return TRUE;
}
break;
case IDC_BUT_DELETE:
if (BN_CLICKED == wNotifyCode) {
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
Assert(hwndList);
int nCurSel = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
ListView_DeleteItem(GetDlgItem(hwndDlg, IDC_LIST1), nCurSel);
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
return TRUE;
}
break;
case IDC_BUT_MOVE_UP:
if (BN_CLICKED == wNotifyCode) {
// These must be MAX_PATH or greater in size.
char szSrcRoot[MAX_PATH] = {0}, szTargetRoot[MAX_PATH] = {0};
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
int nCurSel = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
LV_ITEM lvi;
Assert(hwndList);
Assert(-1 != nCurSel);
ListView_GetItemText(hwndList, nCurSel, 0, szSrcRoot, sizeof(szSrcRoot));
ListView_GetItemText(hwndList, nCurSel, 1, szTargetRoot, sizeof(szTargetRoot));
memset(&lvi, 0, sizeof(lvi));
lvi.iItem = 0;
lvi.iSubItem = 0;
lvi.mask = LVIF_STATE;
lvi.state = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED;
ListView_GetItem(hwndList, &lvi);
ListView_DeleteItem(hwndList, nCurSel);
InsertListViewItem(hwndList, nCurSel-1, &lvi, 2,
szSrcRoot, szTargetRoot);
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
return TRUE;
}
break;
case IDC_BUT_MOVE_DOWN:
if (BN_CLICKED == wNotifyCode) {
// These must be MAX_PATH or greater in size.
char szSrcRoot[MAX_PATH] = {0}, szTargetRoot[MAX_PATH] = {0};
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
int nCurSel = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
LV_ITEM lvi;
Assert(hwndList);
Dbg(-1 != nCurSel);
ListView_GetItemText(hwndList, nCurSel, 0, szSrcRoot, sizeof(szSrcRoot));
ListView_GetItemText(hwndList, nCurSel, 1, szTargetRoot, sizeof(szTargetRoot));
memset(&lvi, 0, sizeof(lvi));
lvi.iItem = 0;
lvi.iSubItem = 0;
lvi.mask = LVIF_STATE;
lvi.state = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED;
ListView_GetItem(hwndList, &lvi);
ListView_DeleteItem(hwndList, nCurSel);
InsertListViewItem(hwndList, nCurSel+1, &lvi, 2,
szSrcRoot, szTargetRoot);
Enable_DlgProc_SrcSearchPath_Buttons(hwndDlg);
return TRUE;
}
break;
case IDCANCEL:
if (BN_CLICKED == wNotifyCode) {
EndDialog(hwndDlg, wID);
return TRUE;
}
break;
case IDHELP:
WinHelp( hwndDlg, "windbg.hlp", HELP_CONTEXT, IDH_SEARCHPATH );
break;
case IDOK:
if (BN_CLICKED == wNotifyCode) {
unsigned int tmp_int;
char sz[MAX_PATH];
LPSTR lpszBuffer = NULL;
int nCount = 0, i;
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST1);
Assert(hwndList);
GetDlgItemText(hwndDlg, IDC_EDIT_DEF_SRC_SEARCH_PATH, sz, sizeof(sz));
FREE_STR( g_contPaths_WkSp.m_pszSourceCodeSearchPath );
g_contPaths_WkSp.m_pszSourceCodeSearchPath = _strdup(sz);
// Now do the src root mapping
tmp_int = ListView_GetItemCount(hwndList);
nCount = min(MAX_MAPPED_ROOTS, tmp_int);
// Zero the whole thing out.
lpszBuffer = (LPSTR) calloc(MAX_PATH * nCount +1, sizeof(char));
if (!lpszBuffer) {
ErrorBox(ERR_Cannot_Allocate_Memory);
} else {
LPSTR lpsz = lpszBuffer;
int nLen = 0;
for (i=0; i< nCount; i++) {
ListView_GetItemText(hwndList, i, 0, lpsz, MAX_PATH);
nLen += strlen(lpsz) +1;
lpsz += strlen(lpsz) +1;
ListView_GetItemText(hwndList, i, 1, lpsz, MAX_PATH);
nLen += strlen(lpsz) +1;
lpsz += strlen(lpsz) +1;
}
//nLen++; // Final zero
Dbg(SetRootNameMappings(lpszBuffer, nLen));
FREE_STR( g_contPaths_WkSp.m_pszRootMappingPairs );
g_contPaths_WkSp.m_pszRootMappingPairs = lpszBuffer;
}
EndDialog(hwndDlg, wID);
return TRUE;
}
break;
}
}
break;
}
return FALSE;
}