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

891 lines
19 KiB
C

#include "precomp.h"
#pragma hdrstop
// Externals
#include "include\cntxthlp.h"
// Module List stuff
// This list contains the default symbol load actions for all
// modules. It is kept in the shell so it can be saved and loaded
// from a workspace and modified by the user before loading any
// debugger DLL.
// Helper functions
BOOL
TruncatePathsToMaxPath(
PCSTR pszOriginal,
PSTR & pszTruncated
)
/*++
Description:
Used to truncate a series of paths to MAX_PATH.
Each path is delimited by a semicolon: e:\;f:\hello;c:\dos
NOTE: Allocation done with malloc.
Args:
pszOriginal - Pointer to string to be validated. Cannot be NULL.
pszTruncated - Cannot be NULL. Destination of the newly allocated
string with all of the truncated paths. See Return values...
Returns:
TRUE - 1 or more of the individual paths were longer that MAX_PATH.
pszTruncated contains munged paths. The calling routine must free
the allocated memory.
FALSE - All of the individual path were shorter than MAX_PATH.
pszTruncated is NULL. NO changes were made
--*/
{
Assert(pszOriginal);
Assert(&pszTruncated);
BOOL bTruncation = FALSE;
// Place holder for the truncated paths
pszTruncated = (PSTR) calloc(strlen(pszOriginal) +1, 1);
Dbg(pszTruncated);
// Individual Paths
PSTR pszBuffer = _strdup(pszOriginal);
Dbg(pszBuffer);
PSTR pszToken = strtok(pszBuffer, ";");
while(pszToken) {
if (strlen(pszToken) >= MAX_PATH) {
pszToken[MAX_PATH-1] = NULL;
bTruncation = TRUE;
}
strcat(pszTruncated, pszToken);
pszToken = strtok(NULL, ";");
}
// cleanup
free(pszBuffer);
if (!bTruncation) {
// No need to truncate
free(pszTruncated);
pszTruncated = NULL;
}
return bTruncation;
}
BOOL
IsLenOfIndivPathValid(
PCSTR pszOriginal,
BOOL bWarn
)
/*++
Description:
Used to validate a series of paths to make sure that each individual
path is length than MAX_PATH.
Each path is delimited by a semicolon: e:\;f:\hello;c:\dos
Args:
pszOriginal - Pointer to string to be validated. Cannot be NULL.
bWarn - Indicates whether to issue the standard message box warning
Returns:
TRUE - All of the individual path were shorter than MAX_PATH
FALSE - 1 or more of the individual paths were longer that MAX_PATH
--*/
{
Assert(pszOriginal);
BOOL bAllShorterThanMaxPath = TRUE;
// Individual Paths
PSTR pszBuffer = _strdup(pszOriginal);
PSTR pszToken = strtok(pszBuffer, ";");
while(pszToken) {
if (strlen(pszToken) >= MAX_PATH) {
bAllShorterThanMaxPath = FALSE;
if (bWarn) {
pszToken[MAX_PATH-4] = NULL;
strcat(pszToken, "...");
InformationBox(ERR_Path_Too_Long, MAX_PATH-1, pszToken);
}
break;
}
pszToken = strtok( NULL, ";");
}
free(pszBuffer);
return bAllShorterThanMaxPath;
}
// How to search for a module
typedef enum _MATCHKIND {
MATCH_FULLPATH,
MATCH_FILENAME,
MATCH_BASENAME
} MATCHKIND;
// These flags tell us what to do with the module
#define MOD_FLAG_NONE 0x00000000
#define MOD_FLAG_TO_ADD 0x00000001
#define MOD_FLAG_TO_DELETE 0x00000002
#define MOD_FLAG_TO_MODIFY 0x00000004
// Node in the Module load list
typedef struct _MOD_NODE *PMOD_NODE;
typedef struct _MOD_NODE {
PMOD_NODE Prev;
PMOD_NODE Next;
CHAR Name[ MAX_PATH ];
SHE SheDefault;
SHE SheCurrent;
SHE SheNew;
DWORD Flags;
BOOL fLoaded;
} MOD_NODE;
static PMOD_NODE ModListHead = NULL;
static SHE SheDefault = sheNone;
INT ModMatch( CHAR *, CHAR *, MATCHKIND );
PMOD_NODE ModFind( CHAR *, MATCHKIND, BOOL );
PMOD_NODE ModFindIndex( DWORD, BOOL );
INT ModIndex( PMOD_NODE );
VOID ModAdd( PMOD_NODE );
PMOD_NODE ModNameAdd( CHAR *, SHE );
VOID ModDel( PMOD_NODE );
INT
ModMatch (
CHAR *Name1,
CHAR *Name2,
MATCHKIND MatchKind
)
{
INT Match;
char Base1[ _MAX_FNAME ];
char Base2[ _MAX_FNAME ];
char Ext1[ _MAX_EXT ];
char Ext2[ _MAX_EXT ];
Assert( Name1 );
Assert( Name2 );
if ( MatchKind == MATCH_FULLPATH ) {
Match = _stricmp( Name1, Name2 );
} else {
_splitpath( Name1, NULL, NULL, Base1, Ext1 );
_splitpath( Name2, NULL, NULL, Base2, Ext2 );
Match = _stricmp( Base1, Base2 );
if ( !Match && MatchKind == MATCH_FILENAME ) {
Match = _stricmp( Ext1, Ext2 );
}
}
return Match;
}
PMOD_NODE
ModFind(
CHAR *Name,
MATCHKIND MatchKind,
BOOL IgnoreFlags
)
{
PMOD_NODE ModNode = ModListHead;
Assert(Name != NULL);
if (Name == NULL) {
return NULL;
}
while( ModNode ) {
if ( IgnoreFlags || !(ModNode->Flags & MOD_FLAG_TO_ADD) ) {
if ( !ModMatch( ModNode->Name, Name, MatchKind ) ) {
break;
}
}
ModNode = ModNode->Next;
}
return ModNode;
}
PMOD_NODE
ModFindIndex(
DWORD Index,
BOOL UseFlag
)
{
PMOD_NODE ModNode;
DWORD i;
ModNode = ModListHead;
i = 0;
while ( ModNode ) {
if ( !UseFlag || !(ModNode->Flags & MOD_FLAG_TO_DELETE) ) {
i++;
}
if ( i > Index ) {
break;
}
ModNode = ModNode->Next;
}
return ModNode;
}
INT
ModIndex(
PMOD_NODE ModNode
)
{
PMOD_NODE ModNodeTmp;
INT Index;
Index = 0;
ModNodeTmp = ModListHead;
while ( ModNodeTmp ) {
if ( ModNodeTmp == ModNode ) {
break;
}
Index++;
ModNodeTmp = ModNodeTmp->Next;
}
if ( !ModNodeTmp ) {
Index = -1;
}
return Index;
}
VOID
ModAdd(
PMOD_NODE ModNode
)
{
PMOD_NODE Mod = ModListHead;
PMOD_NODE ModPrev = NULL;
while ( Mod && ModMatch( ModNode->Name, Mod->Name, MATCH_FILENAME ) > 0 ) {
ModPrev = Mod;
Mod = Mod->Next;
}
ModNode->Prev = ModPrev;
ModNode->Next = Mod;
if ( ModPrev ) {
ModPrev->Next = ModNode;
} else {
ModListHead = ModNode;
}
if ( Mod ) {
Mod->Prev = ModNode;
}
}
PMOD_NODE
ModNameAdd(
CHAR *Name,
SHE SheDefault
)
{
PMOD_NODE ModNode;
Assert( Name );
ModNode = (PMOD_NODE)calloc(sizeof(MOD_NODE), 1);
Dbg(ModNode);
if ( ModNode ) {
Dbg(strlen(Name) < sizeof(ModNode->Name));
// No need to null terminate since we used calloc
strncpy(ModNode->Name, Name, sizeof(ModNode->Name)-1);
ModNode->Prev = NULL;
ModNode->Next = NULL;
ModNode->SheDefault = SheDefault;
ModNode->SheCurrent = SheDefault;
ModNode->Flags = MOD_FLAG_NONE;
ModNode->fLoaded = FALSE;
ModAdd( ModNode );
}
return ModNode;
}
VOID
ModDel(
PMOD_NODE ModNode
)
{
if ( ModNode->Prev ) {
ModNode->Prev->Next = ModNode->Next;
} else {
ModListHead = ModNode->Next;
}
if ( ModNode->Next ) {
ModNode->Next->Prev = ModNode->Prev;
}
free( ModNode );
}
// External interface
VOID
ModListSetDefaultShe (
SHE She
)
{
SheDefault = She;
}
BOOL
ModListGetDefaultShe(
TCHAR * pszName,
SHE * pShe
)
/*++
Description:
Get the default SHE, or the SHE for a particular file.
Args:
pszName - if NULL, the default SHE is returned.
The name of a file, that will be matched in a
list to find it's particular SHE.
pShe - Can't be NULL. Pointer to a SHE, that will hold the
return value.
Return:
TRUE - Success. Valid SHE.
FALSE - Failure. SHE value is undefined.
--*/
{
BOOL bRet = FALSE;
PMOD_NODE pModNode;
Assert( pShe );
if ( pszName ) {
pModNode = ModFind( pszName, MATCH_FULLPATH, FALSE );
if ( !pModNode ) {
pModNode = ModFind( pszName, MATCH_FILENAME, FALSE );
if ( !pModNode ) {
pModNode = ModFind( pszName, MATCH_BASENAME, FALSE );
}
}
if ( pModNode ) {
*pShe = pModNode->SheDefault;
bRet = TRUE;
}
} else {
*pShe = SheDefault;
bRet = TRUE;
}
return bRet;
}
VOID
ModListInit(
VOID
)
{
PMOD_NODE ModNode;
PMOD_NODE ModNodeTmp;
ModNode = ModListHead;
while( ModNode ) {
ModNodeTmp = ModNode;
ModNode = ModNode->Next;
ModDel( ModNodeTmp );
}
ModListHead = NULL;
FREE_STR( g_contPaths_WkSp.m_pszSymPath );
}
VOID
ModListAdd(
CHAR *Name,
SHE SheDefault
)
{
ModNameAdd( Name, SheDefault );
}
VOID
ModListModLoad(
TCHAR *Name,
SHE SheCurrent
)
{
Assert(Name);
PMOD_NODE ModNode;
ModNode = ModFind( Name, MATCH_FULLPATH, FALSE );
if ( !ModNode ) {
ModNode = ModFind( Name, MATCH_FILENAME, FALSE );
if ( !ModNode ) {
ModNode = ModFind( Name, MATCH_BASENAME, FALSE );
}
}
if ( !ModNode ) {
ModNode = ModNameAdd( Name, SheDefault );
}
if ( ModNode ) {
ModNode->SheCurrent = SheCurrent;
ModNode->fLoaded = TRUE;
}
}
VOID
ModListModUnload(
TCHAR *Name
)
{
Assert(Name);
PMOD_NODE ModNode;
ModNode = ModFind( Name, MATCH_FULLPATH, FALSE );
if ( ModNode ) {
ModNode->SheCurrent = sheNone;
ModNode->fLoaded = TRUE;
}
}
PVOID
ModListGetNext(
PVOID Previous,
TCHAR *Name,
SHE *SheDefault
)
{
PMOD_NODE ModNode;
if ( !Previous ) {
ModNode = ModListHead;
} else {
ModNode = ((PMOD_NODE)Previous)->Next;
}
if ( ModNode ) {
strcpy( Name, ModNode->Name );
*SheDefault = ModNode->SheDefault;
}
return (PVOID)ModNode;
}
VOID
ModListSetSearchPath(
CHAR *Path
)
{
FREE_STR( g_contPaths_WkSp.m_pszSymPath );
ModListAddSearchPath( Path );
}
VOID
ModListAddSearchPath(
TCHAR *pszPath
)
{
size_t uNewPathLen;
Assert( pszPath );
uNewPathLen = strlen( pszPath );
if ( !g_contPaths_WkSp.m_pszSymPath ) {
g_contPaths_WkSp.m_pszSymPath = _strdup(pszPath);
} else {
size_t uOldPathLen = _tcslen(g_contPaths_WkSp.m_pszSymPath);
// +1 for ";" and +1 for NULL terminator
PSTR psz = (TCHAR *) realloc(
g_contPaths_WkSp.m_pszSymPath,
(uOldPathLen + uNewPathLen +2) * sizeof(TCHAR)
);
if (psz) {
g_contPaths_WkSp.m_pszSymPath = psz;
if (';' != g_contPaths_WkSp.m_pszSymPath[uOldPathLen -1]
&& ';' != *pszPath) {
_tcscat( g_contPaths_WkSp.m_pszSymPath, ";" );
}
strcat( g_contPaths_WkSp.m_pszSymPath, pszPath );
}
}
if (g_contPaths_WkSp.m_pszSymPath) {
PTSTR pszTruncated = NULL;
if (TruncatePathsToMaxPath(g_contPaths_WkSp.m_pszSymPath, pszTruncated)) {
// Free the previous string and then copy the new truncated one in.
FREE_STR(g_contPaths_WkSp.m_pszSymPath);
g_contPaths_WkSp.m_pszSymPath = pszTruncated;
}
}
}
DWORD
ModListGetSearchPath(
CHAR *Buffer,
DWORD Size
)
/*++
Buffer - If NULL:
No search path - return 0
else, simply returns the string length +1 (null terminator)
else,
Will copy the search path into the buffer, truncating and appending
a 0, if necessary.
Size - Size of the buffer. Can only be 0 if Buffer is NULL.
Returns
Number of chars copied, or the length of the search path if buffer is NULL. Value
include 0 terminator at end.
--*/
{
DWORD Len = 0;
if ( g_contPaths_WkSp.m_pszSymPath ) {
Len = (DWORD)strlen(g_contPaths_WkSp.m_pszSymPath);
if ( Buffer ) {
if ( Size > Len ) {
strcpy( Buffer, g_contPaths_WkSp.m_pszSymPath );
Len++;
} else {
strncpy( Buffer, g_contPaths_WkSp.m_pszSymPath, Size-1 );
Buffer[Size-1] = '\0';
Len = Size;
}
} else {
Len++;
}
}
return Len;
}
// User DLL Dialog stuff
SHE
UserDllGetShe(
HWND hwndDlg
)
{
if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, ID_USERDLL_LOAD)) {
return sheNone;
} else if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, ID_USERDLL_DEFER)) {
return sheDeferSyms;
} else {
Assert(!"Should never happen");
// Just in case he presses ignore
return sheNone;
}
}
VOID
Symbols_UserDllListInit(
HWND hwndDlg
)
{
SHE she;
// Get the default SHE.
Assert(ModListGetDefaultShe(NULL, &she));
switch (she) {
case sheNone:
CheckDlgButton(hwndDlg, ID_USERDLL_LOAD, BST_CHECKED);
break;
case sheDeferSyms:
case sheSuppressSyms:
default:
CheckDlgButton(hwndDlg, ID_USERDLL_DEFER, BST_CHECKED);
break;
}
{
int nLen = ModListGetSearchPath( NULL, 0 );
PSTR pszPath = (PSTR) calloc(1, nLen +2);
Assert(pszPath);
ModListGetSearchPath( pszPath, nLen );
SetDlgItemText(hwndDlg, IDC_EDIT_SEARCH_PATH, pszPath);
free(pszPath);
}
CheckRadioButton(
hwndDlg,
ID_DBUGOPT_SUFFIXA,
ID_DBUGOPT_SUFFIXNONE,
(SuffixToAppend == 'A') ? ID_DBUGOPT_SUFFIXA :
(SuffixToAppend == 'W') ? ID_DBUGOPT_SUFFIXW :
ID_DBUGOPT_SUFFIXNONE );
// Error handling on sym loads
{
int nId;
if (g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors) {
nId = IDC_RADIO_IGNORE_ERRORS;
} else {
if (g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors) {
nId = IDC_RADIO_PROMPT_ON_ERROR;
} else {
nId = IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS;
}
}
CheckRadioButton(hwndDlg, IDC_RADIO_IGNORE_ERRORS, IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS, nId);
}
}
INT_PTR
CALLBACK
DlgProc_Symbols(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static DWORD HelpArray[]=
{
ID_USERDLL_LOAD, IDH_LOAD,
ID_USERDLL_DEFER, IDH_DEFER,
ID_DBUGOPT_SUFFIXA, IDH_ANSI,
ID_DBUGOPT_SUFFIXW, IDH_UNICODE,
ID_DBUGOPT_SUFFIXNONE, IDH_NOSUFFIX,
IDC_EDIT_SEARCH_PATH, IDH_SYMPATH,
IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS, IDH_BADSYM_NOLOAD,
IDC_RADIO_PROMPT_ON_ERROR, IDH_BADSYM_PROMPT,
IDC_RADIO_IGNORE_ERRORS, IDH_BADSYM_IGNORE,
0, 0
};
switch (uMsg) {
case WM_INITDIALOG:
Symbols_UserDllListInit(hwndDlg);
return FALSE;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, "windbg.hlp", HELP_WM_HELP,
(DWORD_PTR)(LPVOID) HelpArray );
return TRUE;
case WM_CONTEXTMENU:
WinHelp ((HWND) wParam, "windbg.hlp", HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID) HelpArray );
return TRUE;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_KILLACTIVE:
{
BOOL bSuccess = TRUE;
HWND hwndSrchPath = GetDlgItem(hwndDlg, IDC_EDIT_SEARCH_PATH);
Assert(hwndSrchPath);
int nLen = GetWindowTextLength(hwndSrchPath) +1;
PSTR pszSrcPaths = (PSTR) calloc(1, nLen);
GetWindowText(hwndSrchPath, pszSrcPaths, nLen);
if (IsLenOfIndivPathValid(pszSrcPaths, TRUE)) {
// Ok
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
} else {
// Error
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
}
}
return TRUE;
case PSN_APPLY:
{
PMOD_NODE pModNode;
SHE She;
char ch;
int nUpdate = UPDATE_NONE;
She = UserDllGetShe(hwndDlg);
ModListSetDefaultShe(She);
// Change the defaults for all of the DLLs
for ( pModNode = ModListHead; pModNode; pModNode = pModNode->Next ) {
if ( pModNode->Flags & MOD_FLAG_TO_DELETE ) {
ModDel( pModNode );
} else {
pModNode->SheDefault = pModNode->SheNew = She;
pModNode->Flags = MOD_FLAG_NONE;
}
}
{
HWND hwndSrchPath = GetDlgItem(hwndDlg, IDC_EDIT_SEARCH_PATH);
Assert(hwndSrchPath);
int nLen = GetWindowTextLength(hwndSrchPath) +1;
PSTR psz = (PSTR) calloc(1, nLen);
Assert(psz);
GetWindowText(hwndSrchPath, psz, nLen);
ModListSetSearchPath(psz);
free(psz);
}
if (IsDlgButtonChecked(hwndDlg, ID_DBUGOPT_SUFFIXA)) {
ch = 'A';
} else if (IsDlgButtonChecked(hwndDlg, ID_DBUGOPT_SUFFIXW)) {
ch = 'W';
} else {
ch = '\0';
}
if (ch != SuffixToAppend) {
if ( HModEE ) {
#if 0
// BUGBUG kentf
EESetSuffix( ch );
#endif
}
SuffixToAppend = ch;
nUpdate = UPDATE_WATCH|UPDATE_LOCALS|UPDATE_MEMORY;
}
// Set behavior for error handling on symbol load
if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_IGNORE_ERRORS)) {
g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors = TRUE;
} else if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_PROMPT_ON_ERROR)) {
g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors = FALSE;
g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors = TRUE;
} else if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_NEVER_LOAD_BAD_SYMBOLS)) {
g_contWorkspace_WkSp.m_bIgnoreAllSymbolErrors = FALSE;
g_contWorkspace_WkSp.m_bBrowseForSymsOnSymLoadErrors = FALSE;
} else {
Assert(!"Not supposed to happen");
}
if (nUpdate != UPDATE_NONE) {
UpdateDebuggerState(nUpdate);
}
}
return TRUE;
}
}
return FALSE;
}