/****************************** Module Header ******************************\ * Module Name: stdexts.c * * Copyright (c) Microsoft Corporation. All rights reserved. * * 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; WINDBG_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((DWORD_PTR)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(%p, %p, %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_PTR)src, pdst, size, &Result)) { DEBUGPRINT("%s: tryMoveBlock(%p, %p, %x) failed.\n", pszExtName, pdst, src, size); fSuccess = FALSE; } } else { if (!NT_SUCCESS(NtReadVirtualMemory(hCurrentProcess, src, pdst, size, NULL))) { DEBUGPRINT("%s: tryMoveBlock(%p, %p, %x) failed.\n", pszExtName, pdst, src, size); fSuccess = FALSE; } } } except (EXCEPTION_EXECUTE_HANDLER) { DEBUGPRINT("%s: tryMoveBlock(%p, %p, %x) faulted.\n", pszExtName, pdst, src, size); fSuccess = FALSE; } return(fSuccess); } VOID moveExp( PVOID pdst, LPSTR pszExp) { DWORD_PTR dwGlobal; BOOL fSuccess = TRUE; try { dwGlobal = (DWORD_PTR)EvalExp(pszExp); #ifndef KERNEL if (IsWinDbg()) { fSuccess = tryMoveBlock(&dwGlobal, (PVOID)dwGlobal, sizeof(DWORD)); } #endif // !KERNEL *((PDWORD_PTR)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_PTR dwGlobal; BOOL fSuccess = TRUE; try { dwGlobal = (DWORD_PTR)EvalExp(pszExp); #ifndef KERNEL if (IsWinDbg()) { if (!tryMove(dwGlobal, (PVOID)dwGlobal)) { DEBUGPRINT("%s: tryMoveExp(%p, %s) failed.\n", pszExtName, pdst, pszExp); fSuccess = FALSE; } } #endif // !KERNEL *((PDWORD_PTR)pdst) = dwGlobal; } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Print(pszAccessViolation, pszExtName, pszExp); DEBUGPRINT("%s: tryMoveExp(%p, %s) faulted.\n", pszExtName, pdst, pszExp); fSuccess = FALSE; } return(fSuccess); } VOID moveExpValue( PVOID pdst, LPSTR pszExp) { DWORD dw; DWORD_PTR addr; if (tryMoveExp(&addr, pszExp)) { if (tryMoveBlock(&dw, (PVOID)addr, sizeof(DWORD))) { *((PDWORD)pdst) = dw; return; } } Print("%s: moveExpValue failed on %s.\n", pszExtName, pszExp); OUTAHERE(); } BOOL tryMoveExpValue( PVOID pdst, LPSTR pszExp) { DWORD dw; DWORD_PTR addr; if (tryMoveExp(&addr, pszExp)) { if (tryMove(dw, (PVOID)addr)) { *((PDWORD)pdst) = dw; return(TRUE); } } DEBUGPRINT("%s: tryMoveExpValue failed on %s.\n", pszExtName, pszExp); return(FALSE); } BOOL tryMoveExpPtr( PVOID pdst, LPSTR pszExp) { DWORD_PTR dwGlobal; BOOL fSuccess = TRUE; try { dwGlobal = (DWORD_PTR)EvalExp(pszExp); #ifndef KERNEL if (IsWinDbg()) { if (!tryMove(dwGlobal, (PVOID)dwGlobal)) { DEBUGPRINT("%s: tryMoveExpPtr(%p, %s) failed.\n", pszExtName, pdst, pszExp); fSuccess = FALSE; } } #endif // !KERNEL *((PDWORD_PTR)pdst) = dwGlobal; } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { Print(pszAccessViolation, pszExtName, pszExp); DEBUGPRINT("%s: tryMoveExpPtr(%p, %s) faulted.\n", pszExtName, pdst, pszExp); fSuccess = FALSE; } return(fSuccess); } VOID moveExpValuePtr( PVOID pdst, LPSTR pszExp) { DWORD_PTR dw; if (tryMoveExpPtr(&dw, pszExp)) { if (tryMoveBlock(&dw, (PVOID)dw, sizeof(dw))) { *((PDWORD_PTR)pdst) = dw; return; } } Print("%s: moveExpValue failed on %s.\n", pszExtName, pszExp); OUTAHERE(); } /*************************************************************************** * 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); }