You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
742 lines
22 KiB
742 lines
22 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: debugc.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* This module contains random debugging related functions.
|
|
*
|
|
* History:
|
|
* 17-May-1991 DarrinM Created.
|
|
* 22-Jan-1992 IanJa ANSI/Unicode neutral (all debug output is ANSI)
|
|
* 11-Mar-1993 JerrySh Pulled functions from user\server.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#if DBG
|
|
extern DBGTAG gadbgtag[];
|
|
#endif
|
|
|
|
|
|
|
|
// common globals
|
|
extern CONST ALWAYSZERO gZero;
|
|
|
|
#if DBG
|
|
CONST LPCSTR aszComponents[] = {
|
|
"?", // 0x00000000
|
|
"USER", // RIP_USER 0x00010000
|
|
"WSRV", // RIP_USERSRV 0x00020000
|
|
"URTL", // RIP_USERRTL 0x00030000
|
|
"GDI", // RIP_GDI 0x00040000
|
|
"GDIK", // RIP_GDIKRNL 0x00050000
|
|
"GRTL", // RIP_GDIRTL 0x00060000
|
|
"KRNL", // RIP_BASE 0x00070000
|
|
"BSRV", // RIP_BASESRV 0x00080000
|
|
"BRTL", // RIP_BASERTL 0x00090000
|
|
"DISP", // RIP_DISPLAYDRV 0x000A0000
|
|
"CONS", // RIP_CONSRV 0x000B0000
|
|
"USRK", // RIP_USERKRNL 0x000C0000
|
|
#ifdef FE_IME
|
|
"IMM", // RIP_IMM 0x000D0000
|
|
#else
|
|
"?", // 0x000D0000
|
|
#endif
|
|
"?", // 0x000E0000
|
|
"?", // 0x000F0000
|
|
};
|
|
|
|
|
|
BOOL IsNumChar(
|
|
int c,
|
|
int base)
|
|
{
|
|
return ('0' <= c && c <= '9') ||
|
|
(base == 16 && (('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')));
|
|
}
|
|
|
|
NTSTATUS GetInteger(
|
|
LPSTR psz,
|
|
int base,
|
|
int *pi,
|
|
LPSTR *ppsz)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
|
|
for (;;) {
|
|
if (IsNumChar(*psz, base)) {
|
|
Status = RtlCharToInteger(psz, base, pi);
|
|
if (ppsz && NT_SUCCESS(Status)) {
|
|
while (IsNumChar(*psz++, base)) {
|
|
/* do nothing */;
|
|
}
|
|
|
|
*ppsz = psz;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (*psz != ' ' && *psz != '\t') {
|
|
break;
|
|
}
|
|
|
|
psz++;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Use a separate debug assertion that doesn't cause recursion
|
|
* into this code.
|
|
*/
|
|
|
|
#define DebugAssertion(x) \
|
|
do { \
|
|
if (!(x)) { \
|
|
if (TEST_RIPF(RIPF_PRINTONERROR)) { \
|
|
KdPrint(("USER: Debug function assertion failure: %s \nFile %s line %ld\n", #x, __FILE__, __LINE__)); \
|
|
} \
|
|
if (TEST_RIPF(RIPF_PROMPTONERROR)) { \
|
|
DbgBreakPoint(); \
|
|
} \
|
|
} \
|
|
} while (FALSE)
|
|
|
|
/***************************************************************************\
|
|
* PrintAndPrompt
|
|
*
|
|
* Sets the last error, prints an error message, and prompts for
|
|
* debug actions.
|
|
*
|
|
* History:
|
|
* 11-Aug-1996 adams Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
PrintAndPrompt(
|
|
BOOL fPrint,
|
|
BOOL fPrompt,
|
|
DWORD idErr,
|
|
DWORD flags,
|
|
LPCSTR pszLevel,
|
|
LPCSTR pszFile,
|
|
int iLine,
|
|
LPCSTR pszFunction,
|
|
LPSTR pszErr,
|
|
PEXCEPTION_POINTERS pexi)
|
|
{
|
|
static CONST CHAR *szLevels[8] = {
|
|
"<none>",
|
|
"Errors",
|
|
"Warnings",
|
|
"Errors and Warnings",
|
|
"Verbose",
|
|
"Errors and Verbose",
|
|
"Warnings and Verbose",
|
|
"Errors, Warnings, and Verbose"
|
|
};
|
|
|
|
#ifdef _USERK_
|
|
static CONST CHAR *szSystem = "System";
|
|
static CONST CHAR *szUnknown = "???";
|
|
CONST CHAR *pszImage;
|
|
|
|
extern ULONG gSessionId;
|
|
#else
|
|
static CONST WCHAR *wszUnknown = L"???";
|
|
WCHAR *pwszImage;
|
|
ULONG ulLenImage;
|
|
#endif
|
|
|
|
DWORD dwT;
|
|
DWORD dwP;
|
|
DWORD dwSession;
|
|
char szT[512];
|
|
BOOL fBreak = FALSE;
|
|
|
|
/*
|
|
* Set the last error, but don't clear it!
|
|
*/
|
|
if (idErr) {
|
|
UserSetLastError(idErr);
|
|
}
|
|
|
|
/*
|
|
* Print the message.
|
|
*/
|
|
if (!fPrint && !fPrompt) {
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _USERK_
|
|
{
|
|
PETHREAD pet;
|
|
PEPROCESS pep;
|
|
|
|
dwT = HandleToUlong(PsGetCurrentThreadId());
|
|
dwP = HandleToUlong(PsGetCurrentProcessId());
|
|
|
|
pszImage = PsGetCurrentProcessImageFileName();
|
|
if (*pszImage == '\0') {
|
|
pszImage = szSystem;
|
|
}
|
|
}
|
|
#else
|
|
{
|
|
PTEB pteb;
|
|
PPEB ppeb;
|
|
|
|
if (pteb = NtCurrentTeb()) {
|
|
dwT = HandleToUlong(pteb->ClientId.UniqueThread);
|
|
dwP = HandleToUlong(pteb->ClientId.UniqueProcess);
|
|
} else {
|
|
dwT = dwP = 0;
|
|
}
|
|
|
|
if ((ppeb = NtCurrentPeb()) && ppeb->ProcessParameters != NULL) {
|
|
/*
|
|
* Get Pointers to the image path
|
|
*/
|
|
pwszImage = ppeb->ProcessParameters->ImagePathName.Buffer;
|
|
ulLenImage = (ppeb->ProcessParameters->ImagePathName.Length) / sizeof(WCHAR);
|
|
|
|
/*
|
|
* If the ProcessParameters haven't been normalized yet, then do it.
|
|
*/
|
|
if (pwszImage != NULL && !(ppeb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
|
|
pwszImage = (PWSTR)((PCHAR)(pwszImage) + (ULONG_PTR)(ppeb->ProcessParameters));
|
|
}
|
|
|
|
/*
|
|
* Munge out the path part.
|
|
*/
|
|
if (pwszImage != NULL && ulLenImage != 0) {
|
|
PWSTR pwszT = pwszImage + (ulLenImage - 1);
|
|
ULONG ulLenT = 1;
|
|
|
|
while (ulLenT != ulLenImage && *(pwszT-1) != L'\\') {
|
|
pwszT--;
|
|
ulLenT++;
|
|
}
|
|
|
|
pwszImage = pwszT;
|
|
ulLenImage = ulLenT;
|
|
}
|
|
|
|
} else {
|
|
pwszImage = (PWSTR)wszUnknown;
|
|
ulLenImage = 3;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef _USERK_
|
|
dwSession = gSessionId;
|
|
#else
|
|
{
|
|
PPEB ppeb = NtCurrentPeb();
|
|
|
|
dwSession = (ppeb != NULL ? ppeb->SessionId : 0);
|
|
}
|
|
#endif
|
|
|
|
szT[0] = 'p';
|
|
for (;;) {
|
|
switch (szT[0] | (char)0x20) {
|
|
/* print */
|
|
case 'p':
|
|
case ' ':
|
|
if (!(flags & RIP_NONAME) && (!TEST_RIPF(RIPF_HIDEPID))) {
|
|
#ifdef _USERK_
|
|
KdPrint((
|
|
"(s: %d %#lx.%lx %s) %s-[%s",
|
|
dwSession,
|
|
dwP,
|
|
dwT,
|
|
pszImage,
|
|
aszComponents[(flags & RIP_COMPBITS) >> RIP_COMPBITSSHIFT],
|
|
pszLevel));
|
|
|
|
#else
|
|
KdPrint((
|
|
"(s: %d %#lx.%lx %*ws) %s-[%s",
|
|
dwSession,
|
|
dwP,
|
|
dwT,
|
|
ulLenImage,
|
|
pwszImage,
|
|
aszComponents[(flags & RIP_COMPBITS) >> RIP_COMPBITSSHIFT],
|
|
pszLevel));
|
|
#endif
|
|
|
|
if (idErr) {
|
|
KdPrint(("=%ld] ", idErr));
|
|
} else {
|
|
KdPrint(("] "));
|
|
}
|
|
}
|
|
|
|
KdPrint(("%s", pszErr));
|
|
if (!(flags & RIP_NONEWLINE)) {
|
|
KdPrint(("\n"));
|
|
}
|
|
|
|
if (flags & RIP_THERESMORE) {
|
|
fPrompt = FALSE;
|
|
} else if (TEST_RIPF(RIPF_PRINTFILELINE) && (pexi == NULL)) {
|
|
KdPrint(("File: %s, Line: %d in function %s\n", pszFile, iLine, pszFunction));
|
|
}
|
|
|
|
break;
|
|
|
|
/* go */
|
|
case 'g':
|
|
fPrompt = FALSE;
|
|
break;
|
|
|
|
/* break */
|
|
case 'b':
|
|
|
|
KdPrint(("File: %s, Line: %d in function %s\n", pszFile, iLine, pszFunction));
|
|
|
|
fBreak = TRUE;
|
|
fPrompt = FALSE;
|
|
break;
|
|
|
|
/* display where this originated from */
|
|
case 'w':
|
|
if (pexi != NULL) {
|
|
break;
|
|
}
|
|
|
|
KdPrint(("File: %s, Line: %d in function %s\n", pszFile, iLine, pszFunction));
|
|
break;
|
|
|
|
/* dump information about this exception */
|
|
case 'i':
|
|
/*
|
|
* Dump some useful information about this exception, like its
|
|
* address, and the contents of the interesting registers at
|
|
* the time of the exception.
|
|
*/
|
|
if (pexi == NULL) {
|
|
break;
|
|
}
|
|
|
|
#if defined(i386) // legal
|
|
/*
|
|
* eip = instruction pointer
|
|
* esp = stack pointer
|
|
* ebp = stack frame pointer
|
|
*/
|
|
KdPrint(("eip = %lx\n", pexi->ContextRecord->Eip));
|
|
KdPrint(("esp = %lx\n", pexi->ContextRecord->Esp));
|
|
KdPrint(("ebp = %lx\n", pexi->ContextRecord->Ebp));
|
|
#elif defined(_IA64_)
|
|
/*
|
|
* StIIP = instruction pointer
|
|
* IntSp = stack pointer
|
|
* RsBSP = Rsestack pointer
|
|
*/
|
|
KdPrint(("StIIP = %lx\n", pexi->ContextRecord->StIIP));
|
|
KdPrint(("IntSp = %lx\n", pexi->ContextRecord->IntSp));
|
|
KdPrint(("RsBsp = %lx\n", pexi->ContextRecord->RsBSP));
|
|
#elif defined(_AMD64_)
|
|
/*
|
|
* rip = instruction pointer
|
|
* rsp = stack pointer
|
|
* rbp = stack frame pointer
|
|
*/
|
|
KdPrint(("rip = %lx\n", pexi->ContextRecord->Rip));
|
|
KdPrint(("rsp = %lx\n", pexi->ContextRecord->Rsp));
|
|
KdPrint(("rbp = %lx\n", pexi->ContextRecord->Rbp));
|
|
#else
|
|
#error "No target architecture"
|
|
#endif
|
|
break;
|
|
|
|
/* modify RIP flags */
|
|
case 'f':
|
|
{
|
|
ULONG ulFlags;
|
|
NTSTATUS status;
|
|
DWORD dwRipFlags = GetRipFlags();
|
|
|
|
szT[ARRAY_SIZE(szT) - 1] = 0; /* don't overflow buffer */
|
|
status = GetInteger(szT + 1, 16, &ulFlags, NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
SetRipFlags(ulFlags);
|
|
}
|
|
|
|
KdPrint(("Flags = %.3x\n", (dwRipFlags & RIPF_VALIDUSERFLAGS)));
|
|
KdPrint((" Print Process/Component %sabled\n", (dwRipFlags & RIPF_HIDEPID) ? "dis" : "en"));
|
|
KdPrint((" Print File/Line %sabled\n", (TEST_RIPF(RIPF_PRINTFILELINE)) ? "en" : "dis"));
|
|
KdPrint((" Print on %s\n", szLevels[(dwRipFlags & RIPF_PRINT_MASK) >> RIPF_PRINT_SHIFT]));
|
|
KdPrint((" Prompt on %s\n", szLevels[(dwRipFlags & RIPF_PROMPT_MASK) >> RIPF_PROMPT_SHIFT]));
|
|
|
|
break;
|
|
}
|
|
|
|
/* modify tags */
|
|
case 't':
|
|
{
|
|
NTSTATUS status;
|
|
int tag;
|
|
LPSTR psz;
|
|
DWORD dwDBGTAGFlags;
|
|
int i;
|
|
int iStart, iEnd;
|
|
|
|
szT[ARRAY_SIZE(szT) - 1] = 0; /* don't overflow buffer */
|
|
status = GetInteger(szT + 1, 10, &tag, &psz);
|
|
if (!NT_SUCCESS(status) || tag < 0 || DBGTAG_Max - 1 < tag) {
|
|
tag = -1;
|
|
} else {
|
|
status = GetInteger(psz, 16, &dwDBGTAGFlags, NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
SetDbgTag(tag, dwDBGTAGFlags);
|
|
}
|
|
}
|
|
|
|
KdPrint(("%-5s%-7s%-*s%-*s\n",
|
|
"Tag",
|
|
"Flags",
|
|
DBGTAG_NAMELENGTH,
|
|
"Name",
|
|
DBGTAG_DESCRIPTIONLENGTH,
|
|
"Description"));
|
|
|
|
for (i = 0; i < 12 + DBGTAG_NAMELENGTH + DBGTAG_DESCRIPTIONLENGTH; i++) {
|
|
szT[i] = '-';
|
|
}
|
|
|
|
szT[i++] = '\n';
|
|
szT[i] = 0;
|
|
KdPrint((szT));
|
|
|
|
if (tag != -1) {
|
|
iStart = iEnd = tag;
|
|
} else {
|
|
iStart = 0;
|
|
iEnd = DBGTAG_Max - 1;
|
|
}
|
|
|
|
for (i = iStart; i <= iEnd; i++) {
|
|
KdPrint(("%-5d%-7d%-*s%-*s\n",
|
|
i,
|
|
GetDbgTagFlags(i) & DBGTAG_VALIDUSERFLAGS,
|
|
DBGTAG_NAMELENGTH,
|
|
gadbgtag[i].achName,
|
|
DBGTAG_DESCRIPTIONLENGTH,
|
|
gadbgtag[i].achDescription));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* display help */
|
|
case '?':
|
|
KdPrint(("g - GO, ignore the error and continue execution\n"));
|
|
if (pexi != NULL) {
|
|
KdPrint(("b - BREAK into the debugger at the location of the exception (part impl.)\n"));
|
|
KdPrint(("i - INFO on instruction pointer and stack pointers\n"));
|
|
KdPrint(("x - execute cleanup code and KILL the thread by returning EXECUTE_HANDLER\n"));
|
|
} else {
|
|
KdPrint(("b - BREAK into the debugger at the location of the error (part impl.)\n"));
|
|
KdPrint(("w - display the source code location WHERE the error occured\n"));
|
|
KdPrint(("x - KILL the offending thread by raising an exception\n"));
|
|
}
|
|
|
|
KdPrint(("p - PRINT this message again\n"));
|
|
KdPrint(("f - FLAGS, enter debug flags in format <Detail><Print><Prompt>\n"));
|
|
KdPrint((" <Detail> = [0-3] Print File/Line = 1, Hide PID/Component = 2\n"));
|
|
KdPrint((" <Print> = [0-7] Errors = 1, Warnings = 2, Verbose = 4\n"));
|
|
KdPrint((" <Prompt> = [0-7] Errors = 1, Warnings = 2, Verbose = 4\n"));
|
|
KdPrint((" The default is 031\n"));
|
|
KdPrint(("t - TAGS, display and modify tag flags\n"));
|
|
KdPrint((" no argument displays all tags\n"));
|
|
KdPrint((" <tag> displays one tag\n"));
|
|
KdPrint((" <tag> <flags> modifies one tag\n"));
|
|
KdPrint((" <tag> = 0 - %d\n", DBGTAG_Max - 1));
|
|
KdPrint((" <flags> = [0-3] Disabled = 0, Enabled = 1, Print = 2, Prompt = 3\n"));
|
|
|
|
break;
|
|
|
|
/* prompt again on bad input */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Prompt the user */
|
|
if (!fPrompt) {
|
|
break;
|
|
}
|
|
|
|
if (pexi != NULL) {
|
|
DbgPrompt("[gbipft?]", szT, ARRAY_SIZE(szT));
|
|
} else {
|
|
DbgPrompt("[gbwpft?]", szT, ARRAY_SIZE(szT));
|
|
}
|
|
}
|
|
|
|
return fBreak;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* VRipOutput
|
|
*
|
|
* Formats a variable argument string and calls RipOutput.
|
|
*
|
|
* History:
|
|
* 19-Mar-1996 adams Created.
|
|
\***************************************************************************/
|
|
ULONG _cdecl VRipOutput(
|
|
ULONG idErr,
|
|
ULONG flags,
|
|
LPSTR pszFile,
|
|
int iLine,
|
|
LPSTR pszFunction,
|
|
LPSTR pszFmt,
|
|
...)
|
|
{
|
|
char szT[512];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, pszFmt);
|
|
_vsnprintf(szT, ARRAY_SIZE(szT) - 1, pszFmt, arglist);
|
|
szT[ARRAY_SIZE(szT) - 1] = 0; /* ensure null termination */
|
|
va_end(arglist);
|
|
|
|
return RipOutput(idErr, flags, pszFile, iLine, pszFunction, szT, NULL);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* RipOutput
|
|
*
|
|
* Sets the last error if it is non-zero, prints a message to
|
|
* the debugger, and prompts for more debugging actions.
|
|
*
|
|
* History:
|
|
* 01-23-91 DarrinM Created.
|
|
* 04-15-91 DarrinM Added exception handling support.
|
|
* 03-19-96 adams Made flags a separate argument, cleanup.
|
|
\***************************************************************************/
|
|
ULONG RipOutput(
|
|
ULONG idErr,
|
|
ULONG flags,
|
|
LPSTR pszFile,
|
|
int iLine,
|
|
LPSTR pszFunction,
|
|
LPSTR pszErr,
|
|
PEXCEPTION_POINTERS pexi)
|
|
{
|
|
static CONST struct {
|
|
LPSTR szLevel;
|
|
DWORD dwPrint;
|
|
DWORD dwPrompt;
|
|
} aLevel[] = {
|
|
"?", 0, 0,
|
|
"Err", RIPF_PRINTONERROR, RIPF_PROMPTONERROR,
|
|
"Wrn", RIPF_PRINTONWARNING, RIPF_PROMPTONWARNING,
|
|
"Vrbs", RIPF_PRINTONVERBOSE, RIPF_PROMPTONVERBOSE,
|
|
};
|
|
|
|
int iLevel;
|
|
|
|
DebugAssertion(flags & RIP_LEVELBITS);
|
|
iLevel = ((flags & RIP_LEVELBITS) >> RIP_LEVELBITSSHIFT);
|
|
DebugAssertion(!(flags & RIP_USERTAGBITS));
|
|
|
|
return PrintAndPrompt(
|
|
TEST_RIPF(aLevel[iLevel].dwPrint),
|
|
TEST_RIPF(aLevel[iLevel].dwPrompt),
|
|
idErr,
|
|
flags,
|
|
aLevel[iLevel].szLevel,
|
|
pszFile,
|
|
iLine,
|
|
pszFunction,
|
|
pszErr,
|
|
pexi);
|
|
}
|
|
|
|
BOOL _cdecl VTagOutput(
|
|
DWORD flags,
|
|
LPSTR pszFile,
|
|
int iLine,
|
|
LPSTR pszFunction,
|
|
LPSTR pszFmt,
|
|
...)
|
|
{
|
|
char szT[512];
|
|
va_list arglist;
|
|
int tag;
|
|
DWORD dwDBGTAGFlags;
|
|
|
|
tag = (flags & RIP_USERTAGBITS);
|
|
DebugAssertion(tag < DBGTAG_Max);
|
|
DebugAssertion(!(flags & RIP_LEVELBITS));
|
|
|
|
dwDBGTAGFlags = GetDbgTagFlags(tag) & DBGTAG_VALIDUSERFLAGS;
|
|
|
|
if (dwDBGTAGFlags < DBGTAG_PRINT) {
|
|
return FALSE;
|
|
}
|
|
|
|
va_start(arglist, pszFmt);
|
|
_vsnprintf(szT, ARRAY_SIZE(szT) - 1, pszFmt, arglist);
|
|
szT[ARRAY_SIZE(szT) - 1] = 0; /* ensure null termination */
|
|
va_end(arglist);
|
|
return PrintAndPrompt(
|
|
dwDBGTAGFlags >= DBGTAG_PRINT,
|
|
dwDBGTAGFlags >= DBGTAG_PROMPT,
|
|
0,
|
|
flags,
|
|
gadbgtag[tag].achName,
|
|
pszFile,
|
|
iLine,
|
|
pszFunction,
|
|
szT,
|
|
NULL);
|
|
}
|
|
|
|
#endif
|
|
|
|
VOID UserSetLastError(
|
|
DWORD dwErrCode)
|
|
{
|
|
/*
|
|
* Check if NT Error is directly passed to UserSetLastError.
|
|
* Raid #320555 note: some Win32 error could be
|
|
* 0x4000XXXX, 0x8000XXXX or 0xC000XXXX etc.,
|
|
* but they are still valid. E.g) STATUS_SEGMENT_NOTIFICATION,
|
|
* STATUS_GUARD_PAGE_VIOLATION, etc.
|
|
*
|
|
* The mapper returns the equivalent W32 error value as NT error.
|
|
* So we assert only if mapper routine returns the different w32 error code.
|
|
*/
|
|
UserAssert((dwErrCode & 0xffff0000) == 0 || RtlNtStatusToDosError(dwErrCode) == dwErrCode);
|
|
|
|
try {
|
|
NtCurrentTeb()->LastErrorValue = dwErrCode;
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
}
|
|
}
|
|
|
|
VOID SetLastNtError(
|
|
NTSTATUS Status)
|
|
{
|
|
UserSetLastError(RtlNtStatusToDosError(Status));
|
|
}
|
|
|
|
#if DBG
|
|
VOID ValidateZero(
|
|
VOID)
|
|
{
|
|
static ALWAYSZERO z;
|
|
|
|
UserAssert(RtlCompareMemory(&z, (void *)&gZero, sizeof(z)) == sizeof(z));
|
|
}
|
|
#endif
|
|
|
|
|
|
/***************************************************************************\
|
|
* W32ExceptionHandler
|
|
*
|
|
* To be called from except blocks.
|
|
*
|
|
* History:
|
|
* 07-17-98 GerardoB Created.
|
|
\***************************************************************************/
|
|
ULONG _W32ExceptionHandler(
|
|
NTSTATUS ExceptionCode)
|
|
{
|
|
SetLastNtError(ExceptionCode);
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
#if DBG
|
|
ULONG DBGW32ExceptionHandler(
|
|
PEXCEPTION_POINTERS pexi,
|
|
BOOL fSetLastError,
|
|
ULONG ulflags)
|
|
{
|
|
RIPMSG5(ulflags,
|
|
"Exception %#x at address %#p. flags:%#x. .exr %#p .cxr %#p",
|
|
pexi->ExceptionRecord->ExceptionCode,
|
|
CONTEXT_TO_PROGRAM_COUNTER(pexi->ContextRecord),
|
|
pexi->ExceptionRecord->ExceptionFlags,
|
|
pexi->ExceptionRecord,
|
|
pexi->ContextRecord);
|
|
|
|
if (fSetLastError) {
|
|
SetLastNtError(pexi->ExceptionRecord->ExceptionCode);
|
|
}
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PRERELEASE) || defined(USER_INSTRUMENTATION)
|
|
|
|
/*
|
|
* UserBreakIfDebugged(): software break point that *may* also be available in FRE.
|
|
* Fre: breaks in only if there's a debugger attached.
|
|
* Chk: always breaks in.
|
|
*/
|
|
#if DBG
|
|
#define UserBreakIfDebugged DbgBreakPoint
|
|
#else
|
|
#ifdef _USERK_
|
|
#define IS_DEBUGGER_ATTACHED KD_DEBUGGER_ENABLED
|
|
#else
|
|
#define IS_DEBUGGER_ATTACHED IsDebuggerPresent()
|
|
#endif
|
|
VOID __inline UserBreakIfDebugged(VOID)
|
|
{
|
|
if (IS_DEBUGGER_ATTACHED) {
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Called by FRE_RIPMSGx. This is a partial implementation
|
|
* of RIPMSGx. In the future (Blackcomb?), we'll revisit
|
|
* this to have the fullest support of RIP.
|
|
*/
|
|
VOID FreDbgPrint(
|
|
ULONG flags,
|
|
LPSTR pszFile,
|
|
int iLine,
|
|
LPSTR pszFunction,
|
|
LPSTR pszFmt,
|
|
...)
|
|
{
|
|
static BOOL fSuppressFileLine;
|
|
va_list arglist;
|
|
|
|
if (!fSuppressFileLine) {
|
|
DbgPrintEx(-1, 0, "File: %s, Line: %d in function %s\n -- ", pszFile, iLine, pszFunction);
|
|
} else {
|
|
fSuppressFileLine = FALSE;
|
|
}
|
|
|
|
va_start(arglist, pszFmt);
|
|
vDbgPrintEx(-1, 0, pszFmt, arglist);
|
|
if ((flags & RIP_NONEWLINE) != 0) {
|
|
fSuppressFileLine = TRUE;
|
|
} else {
|
|
DbgPrintEx(-1, 0, "\n");
|
|
}
|
|
|
|
if ((flags & RIP_ERROR) != 0) {
|
|
UserBreakIfDebugged();
|
|
}
|
|
}
|
|
|
|
#endif
|