NT4/private/windows/inc/stdexts.c
2020-09-30 17:12:29 +02:00

542 lines
13 KiB
C

/****************************** Module Header ******************************\
* Module Name: stdexts.c
*
* Copyright (c) 1995, Microsoft Corporation
*
* This module contains standard routines for creating sane debuging extensions.
* It is meant to be included after stdexts.h in one of the files comprising
* the debug extsnsions for a given product or module.
*
* History:
* 11-Apr-1995 Sanfords Created
\***************************************************************************/
HANDLE hCurrentProcess;
HANDLE hCurrentThread;
DWORD dwCurrentPc;
PWINDBG_EXTENSION_APIS lpExtensionApis;
#ifdef KERNEL
DWORD dwProcessor;
#endif // KERNEL
PSTR pszAccessViolation = "%s: Access violation on \"%s\".\n";
PSTR pszMoveException = "%s: exception in moveBlock()\n";
PSTR pszReadFailure = "%s: lpReadProcessMemoryRoutine failed!\n";
PSTR pszCantContinue = "%s: Non-continuable exception.\n";
BOOL fCtrlCHit = FALSE;
/*
* This function returns TRUE once the user has hit a Ctrl-C.
* This allows proper operation of nested SAFEWHILE loops so
* that all levels exit.
*
* The globall fCtrlCHit flag needs to be reset manually and
* is done so in the CommandEP function.
*/
BOOL IsCtrlCHit()
{
if ((lpExtensionApis->lpCheckControlCRoutine)()) {
fCtrlCHit = TRUE;
}
return fCtrlCHit;
}
VOID moveBlock(
PVOID pdst,
PVOID src,
DWORD size)
{
BOOL fSuccess = TRUE;
ULONG Result;
try {
if (IsWinDbg()) {
if (!ReadMem((ULONG)src, pdst, size, &Result)) {
fSuccess = FALSE;
}
} else {
if (!NT_SUCCESS(NtReadVirtualMemory(hCurrentProcess,
src, pdst, size, NULL))) {
fSuccess = FALSE;
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
Print(pszMoveException, pszExtName);
fSuccess = FALSE;
}
if (!fSuccess) {
DEBUGPRINT("%s: moveBlock(%x, %x, %x) failed.\n",
pszExtName, pdst, src, size);
OUTAHERE();
}
}
BOOL tryMoveBlock(
PVOID pdst,
PVOID src,
DWORD size)
{
BOOL fSuccess = TRUE;
ULONG Result;
try {
if (IsWinDbg()) {
if (!ReadMem((DWORD)src, pdst, size, &Result)) {
DEBUGPRINT("%s: tryMoveBlock(%x, %x, %x) failed.\n", pszExtName, pdst, src, size);
fSuccess = FALSE;
}
} else {
if (!NT_SUCCESS(NtReadVirtualMemory(hCurrentProcess, src, pdst, size, NULL))) {
DEBUGPRINT("%s: tryMoveBlock(%x, %x, %x) failed.\n", pszExtName, pdst, src, size);
fSuccess = FALSE;
}
}
} except (EXCEPTION_EXECUTE_HANDLER) {
DEBUGPRINT("%s: tryMoveBlock(%x, %x, %x) faulted.\n", pszExtName, pdst, src, size);
fSuccess = FALSE;
}
return(fSuccess);
}
VOID moveExp(
PVOID pdst,
LPSTR pszExp)
{
DWORD dwGlobal;
BOOL fSuccess = TRUE;
try {
dwGlobal = (DWORD)EvalExp(pszExp);
#ifndef KERNEL
if (IsWinDbg()) {
fSuccess = tryMoveBlock(&dwGlobal, (PVOID)dwGlobal, sizeof(DWORD));
}
#endif // !KERNEL
*((PDWORD)pdst) = dwGlobal;
} except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
Print(pszAccessViolation, pszExtName, pszExp);
fSuccess = FALSE;
}
if (!fSuccess) {
Print("%s: moveExp failed on %s.\n", pszExtName, pszExp);
OUTAHERE();
}
}
BOOL tryMoveExp(
PVOID pdst,
LPSTR pszExp)
{
DWORD dwGlobal;
BOOL fSuccess = TRUE;
try {
dwGlobal = (DWORD)EvalExp(pszExp);
#ifndef KERNEL
if (IsWinDbg()) {
if (!tryMove(dwGlobal, (PVOID)dwGlobal)) {
DEBUGPRINT("%s: tryMoveExp(%x, %s) failed.\n", pszExtName, pdst, pszExp);
fSuccess = FALSE;
}
}
#endif // !KERNEL
*((PDWORD)pdst) = dwGlobal;
} except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
Print(pszAccessViolation, pszExtName, pszExp);
DEBUGPRINT("%s: tryMoveExp(%x, %s) faulted.\n", pszExtName, pdst, pszExp);
fSuccess = FALSE;
}
return(fSuccess);
}
VOID moveExpValue(
PVOID pdst,
LPSTR pszExp)
{
DWORD dw;
if (tryMoveExp(&dw, pszExp)) {
if (tryMoveBlock(&dw, (PVOID)dw, sizeof(DWORD))) {
*((PDWORD)pdst) = dw;
return;
}
}
Print("%s: moveExpValue failed on %s.\n", pszExtName, pszExp);
OUTAHERE();
}
BOOL tryMoveExpValue(
PVOID pdst,
LPSTR pszExp)
{
DWORD dw;
if (tryMoveExp(&dw, pszExp)) {
if (tryMove(dw, (PVOID)dw)) {
*((PDWORD)pdst) = dw;
return(TRUE);
}
}
DEBUGPRINT("%s: tryMoveExpValue failed on %s.\n", pszExtName, pszExp);
return(FALSE);
}
/***************************************************************************
* Common command parsing stuff *
***************************************************************************/
PVOID EvalExp(
LPSTR psz)
{
PVOID p;
p = (PVOID)(lpExtensionApis->lpGetExpressionRoutine)(psz);
if (p == NULL) {
Print("%s: EvalExp failed to evaluate %s.\n", pszExtName, psz);
}
return p;
}
PVOID OptEvalExp(
LPSTR psz)
{
while (*psz == ' ')
psz++;
if (*psz == '\0') {
return(NULL);
}
return(EvalExp(psz));
}
PVOID OptEvalExp2(
LPSTR *ppsz)
{
LPSTR psz = *ppsz;
PVOID dwRet = NULL;
while (*psz == ' ')
psz++;
if (*psz != '\0') {
dwRet = EvalExp(psz);
while (*psz != '\0' && *psz != ' ') {
psz++;
}
}
*ppsz = psz;
return(dwRet);
}
DWORD StringToOpts(
LPSTR psz)
{
DWORD opts = 0;
while (*psz != '\0' && *psz != ' ') {
if (*psz >= 'a' && *psz <= 'z') {
opts |= 1 << (*psz - 'a');
} else if (*psz >= 'A' && *psz <= 'Z') {
opts |= 1 << (*psz - 'A');
} else {
return(OPTS_ERROR); // any non-letter option is an error.
}
psz++;
}
return(opts);
}
/*
* Function to convert an option string to a DWORD of flags. pszLegalArgs
* is used to allow option validation at the same time.
*
* *ppszArgs is set to point to after the options on exit.
* On error, returns OPTS_ERROR.
*/
DWORD GetOpts(
LPSTR *ppszArgs,
LPSTR pszLegalArgs) // OPTIONAL
{
DWORD Opts = 0;
LPSTR pszArgs = *ppszArgs;
/*
* Skip whitespace
*/
while (*pszArgs == ' ') {
pszArgs++;
}
/*
* process '-' prepended options.
*/
while (*pszArgs == '-') {
pszArgs++;
Opts = StringToOpts(pszArgs);
/*
* skip to whitespace or end.
*/
while (*pszArgs != '\0' && *pszArgs != ' ') {
pszArgs++;
}
/*
* skip trailing whitespace.
*/
while (*pszArgs == ' ') {
pszArgs++;
}
*ppszArgs = pszArgs;
/*
* optionally validate against LegalArgs
*/
if (pszLegalArgs != NULL && ((Opts & StringToOpts(pszLegalArgs)) != Opts)) {
Opts = OPTS_ERROR;
Print("Bad options.\n");
return(Opts);
}
}
return(Opts);
}
VOID PrintHuge(
LPSTR psz)
{
/*
* Looks like this is faulting these days - Print seems to be fixed
* so I'm leaving this entry point for compatibility. (SAS)
*/
#ifdef ITWORKS
#define HUNK_SIZE 400
int cch;
CHAR chSave;
/*
* since dorky Print extension can't handle very long strings,
* break it up into peices for it to chew.
*/
cch = strlen(psz);
while (cch > HUNK_SIZE) {
chSave = psz[HUNK_SIZE];
psz[HUNK_SIZE] = '\0';
Print(psz);
psz[HUNK_SIZE] = chSave;
psz += HUNK_SIZE;
cch -= HUNK_SIZE;
}
#endif
Print(psz);
}
/*
* Dispatcher function used by generated entrypoint functions.
*/
VOID CommonEP(
PVOID pFunction,
LPSTR pszName,
int type,
LPSTR pszLegalOpts,
HANDLE hcp,
HANDLE hct,
DWORD dwcp,
#ifdef KERNEL
DWORD dwp,
#else // !KERNEL
PWINDBG_EXTENSION_APIS lpea,
#endif // !KERNEL
LPSTR lpas)
{
BOOL dwOptions, fSuccess;
PVOID param1, param2, param3;
hCurrentProcess = hcp;
hCurrentThread = hct;
dwCurrentPc = dwcp;
#ifdef KERNEL
dwProcessor = dwp;
lpExtensionApis = &ExtensionApis;
#else // !KERNEL
lpExtensionApis = lpea;
#endif // !KERNLE
#if 0
DEBUGPRINT("CommonEP(%x, \"%s\", %d, \"%s\", %x, %x, %x, %x, \"%s\")\n",
pFunction,
pszName,
type,
pszLegalOpts,
hcp,
hct,
dwcp,
#ifdef KERNEL
dwp,
#else // !KERNLE
lpea,
#endif // !KERNEL
lpas);
#endif
fCtrlCHit = FALSE; // reset this with each command. (SAFEWHILE fix)
switch (type) {
case NOARGS:
fSuccess = ((TYPE_NOARGS)pFunction)();
goto Exit;
}
dwOptions = GetOpts(&lpas, pszLegalOpts);
if (dwOptions == OPTS_ERROR) {
fSuccess = Ihelp(0, pszName);
goto Exit;
}
try {
switch (type) {
case CUSTOM:
fSuccess = ((TYPE_CUSTOM)pFunction)(dwOptions, lpas);
break;
case STDARGS0:
fSuccess = ((TYPE_STDARGS0)pFunction)(dwOptions);
break;
case STDARGS1:
fSuccess = ((TYPE_STDARGS1)pFunction)(dwOptions, OptEvalExp(lpas));
break;
case STDARGS2:
param1 = OptEvalExp2(&lpas);
fSuccess = ((TYPE_STDARGS2)pFunction)(dwOptions, param1, OptEvalExp(lpas));
break;
case STDARGS3:
param1 = OptEvalExp2(&lpas);
param2 = OptEvalExp2(&lpas);
fSuccess = ((TYPE_STDARGS3)pFunction)(dwOptions, param1, param2, OptEvalExp(lpas));
break;
case STDARGS4:
param1 = OptEvalExp2(&lpas);
param2 = OptEvalExp2(&lpas);
param3 = OptEvalExp2(&lpas);
fSuccess = ((TYPE_STDARGS4)pFunction)(dwOptions, param1, param2, param3, OptEvalExp(lpas));
break;
default:
Print("CommonEP: Don't recognize function type %d.\n", type);
break;
}
} except (GetExceptionCode() == STATUS_NONCONTINUABLE_EXCEPTION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
Print(pszCantContinue, pszExtName);
}
Exit:
if (!fSuccess) {
Print("%s failed.\n", pszName);
Ihelp(0, pszName);
}
}
/*
* Entrypoint functions (generated from exts.h)
*/
#ifdef KERNEL
#define DOIT(name, h1, h2, opts, type) \
VOID name##( \
HANDLE hcp, \
HANDLE hct, \
DWORD dwcp, \
DWORD dwp, \
LPSTR lpas) \
{ \
CommonEP(I##name, #name, type, opts, hcp, hct, dwcp, dwp, lpas); \
}
#else // !KERNEL
#define DOIT(name, h1, h2, opts, type) \
VOID name##( \
HANDLE hcp, \
HANDLE hct, \
DWORD dwcp, \
PWINDBG_EXTENSION_APIS lpea, \
LPSTR lpas) \
{ \
CommonEP(I##name, #name, type, opts, hcp, hct, dwcp, lpea, lpas); \
}
#endif // !KERNEL
#include "exts.h"
#undef DOIT
/*
* Standard help extension - present in all standard extensions.
*/
BOOL Ihelp(
DWORD opts,
LPSTR lpas)
{
#define DOIT(name, help1, help2, opts, type) { #name, help1, help2 },
static struct {
LPSTR pszCmdName;
LPSTR pszHelp1;
LPSTR pszHelp2;
} he[] = {
#include "exts.h"
};
#undef DOIT
int i;
while (*lpas == ' ')
lpas++;
if (*lpas == '\0') {
Print("-------------- %s Debug Extension help:--------------\n\n", pszExtName);
for (i = 0; i < sizeof(he) / sizeof(he[0]); i++) {
if (IsCtrlCHit()) {
break;
}
Print(he[i].pszHelp1);
if (opts & OFLAG(v)) {
PrintHuge(he[i].pszHelp2);
}
}
return(TRUE);
} else {
for (i = 0; i < sizeof(he) / sizeof(he[0]); i++) {
if (IsCtrlCHit()) {
break;
}
if (strcmp(lpas, he[i].pszCmdName) == 0) {
Print(he[i].pszHelp1);
PrintHuge(he[i].pszHelp2);
return(TRUE);
}
}
Print("%s is not supported.\n", lpas);
}
return(FALSE);
}