1845 lines
53 KiB
C++
1845 lines
53 KiB
C++
#include "stdinc.h"
|
|
#include <limits.h>
|
|
#include "fusiontrace.h"
|
|
#include <stdio.h>
|
|
#include "fusionheap.h"
|
|
#include "imagehlp.h"
|
|
#include "debmacro.h"
|
|
#include "util.h"
|
|
|
|
#if !defined(FUSION_BREAK_ON_BAD_PARAMETERS)
|
|
#define FUSION_BREAK_ON_BAD_PARAMETERS false
|
|
#endif // !defined(FUSION_BREAK_ON_BAD_PARAMETERS);
|
|
|
|
bool g_FusionBreakOnBadParameters = FUSION_BREAK_ON_BAD_PARAMETERS;
|
|
|
|
static HANDLE s_hFile; // trace file handle
|
|
|
|
#if DBG
|
|
#define FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hr) /* nothing */
|
|
#else
|
|
bool FusionpSuppressErrorReportInOsSetup(HRESULT hr)
|
|
{
|
|
//
|
|
// Some of these are unfortunately expected (early) in guimode setup, actually
|
|
// concurrent with early guimode setup, but not otherwise.
|
|
//
|
|
if ( hr != HRESULT_FROM_WIN32(ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED)
|
|
&& hr != HRESULT_FROM_WIN32(ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED)
|
|
)
|
|
return false;
|
|
BOOL fAreWeInOSSetupMode = FALSE;
|
|
//
|
|
// If we can't determine this, then let the first error through.
|
|
//
|
|
if (!::FusionpAreWeInOSSetupMode(&fAreWeInOSSetupMode))
|
|
return false;
|
|
if (!fAreWeInOSSetupMode)
|
|
return false;
|
|
return true;
|
|
}
|
|
#define FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hr) if (FusionpSuppressErrorReportInOsSetup(hr)) return;
|
|
#endif
|
|
|
|
bool
|
|
__fastcall
|
|
FusionpGetActiveFrameInfo(
|
|
FRAME_INFO &rFrameInfo
|
|
)
|
|
{
|
|
bool fFoundAnyData = false;
|
|
|
|
rFrameInfo.pszFile = "";
|
|
rFrameInfo.pszFunction = "";
|
|
rFrameInfo.nLine = 0;
|
|
|
|
const PTEB_ACTIVE_FRAME ptaf =
|
|
#if FUSION_WIN
|
|
::RtlGetFrame();
|
|
#else
|
|
NULL;
|
|
#endif
|
|
|
|
const PTEB_ACTIVE_FRAME_EX ptafe =
|
|
((ptaf != NULL) && (ptaf->Flags & TEB_ACTIVE_FRAME_FLAG_EXTENDED)) ?
|
|
reinterpret_cast<PTEB_ACTIVE_FRAME_EX>(ptaf) : NULL;
|
|
|
|
if (ptaf != NULL)
|
|
{
|
|
if (ptaf->Context != NULL)
|
|
{
|
|
if (ptaf->Context->FrameName != NULL)
|
|
{
|
|
rFrameInfo.pszFunction = ptaf->Context->FrameName;
|
|
fFoundAnyData = true;
|
|
}
|
|
|
|
if (ptaf->Context->Flags & TEB_ACTIVE_FRAME_CONTEXT_FLAG_EXTENDED)
|
|
{
|
|
const PCTEB_ACTIVE_FRAME_CONTEXT_EX ptafce =
|
|
reinterpret_cast<PCTEB_ACTIVE_FRAME_CONTEXT_EX>(ptaf->Context);
|
|
|
|
if (ptafce->SourceLocation != NULL)
|
|
{
|
|
rFrameInfo.pszFile = ptafce->SourceLocation;
|
|
fFoundAnyData = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is one of our frames, we can even downcast and get the line number...
|
|
if ((ptafe != NULL) && (ptafe->ExtensionIdentifier == (PVOID) (' sxS')))
|
|
{
|
|
const CFrame *pFrame = static_cast<CFrame *>(ptafe);
|
|
if (pFrame->m_nLine != 0)
|
|
{
|
|
rFrameInfo.nLine = pFrame->m_nLine;
|
|
fFoundAnyData = true;
|
|
}
|
|
}
|
|
|
|
return fFoundAnyData;
|
|
}
|
|
|
|
bool
|
|
__fastcall
|
|
FusionpPopulateFrameInfo(
|
|
FRAME_INFO &rFrameInfo,
|
|
PCTEB_ACTIVE_FRAME ptaf
|
|
)
|
|
{
|
|
bool fFoundAnyData = false;
|
|
|
|
rFrameInfo.pszFile = "";
|
|
rFrameInfo.pszFunction = "";
|
|
rFrameInfo.nLine = 0;
|
|
|
|
const PCTEB_ACTIVE_FRAME_EX ptafe =
|
|
((ptaf != NULL) && (ptaf->Flags & TEB_ACTIVE_FRAME_FLAG_EXTENDED)) ?
|
|
reinterpret_cast<PCTEB_ACTIVE_FRAME_EX>(ptaf) : NULL;
|
|
|
|
if (ptaf != NULL)
|
|
{
|
|
if (ptaf->Context != NULL)
|
|
{
|
|
if (ptaf->Context->FrameName != NULL)
|
|
{
|
|
rFrameInfo.pszFunction = ptaf->Context->FrameName;
|
|
fFoundAnyData = true;
|
|
}
|
|
|
|
if (ptaf->Context->Flags & TEB_ACTIVE_FRAME_CONTEXT_FLAG_EXTENDED)
|
|
{
|
|
const PCTEB_ACTIVE_FRAME_CONTEXT_EX ptafce =
|
|
reinterpret_cast<PCTEB_ACTIVE_FRAME_CONTEXT_EX>(ptaf->Context);
|
|
|
|
if (ptafce->SourceLocation != NULL)
|
|
{
|
|
rFrameInfo.pszFile = ptafce->SourceLocation;
|
|
fFoundAnyData = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is one of our frames, we can even downcast and get the line number...
|
|
if ((ptafe != NULL) && (ptafe->ExtensionIdentifier == ((PVOID) (' sxS'))))
|
|
{
|
|
const CFrame *pFrame = static_cast<const CFrame *>(ptafe);
|
|
if (pFrame->m_nLine != 0)
|
|
{
|
|
rFrameInfo.nLine = pFrame->m_nLine;
|
|
fFoundAnyData = true;
|
|
}
|
|
}
|
|
|
|
return fFoundAnyData;
|
|
}
|
|
|
|
bool
|
|
FusionpPopulateFrameInfo(
|
|
FRAME_INFO &rFrameInfo,
|
|
PCSTR pszFile,
|
|
PCSTR pszFunction,
|
|
INT nLine
|
|
)
|
|
{
|
|
bool fFoundAnyData = false;
|
|
|
|
if (pszFile != NULL)
|
|
{
|
|
rFrameInfo.pszFile = pszFile;
|
|
fFoundAnyData = true;
|
|
}
|
|
else
|
|
rFrameInfo.pszFile = NULL;
|
|
|
|
if (nLine != 0)
|
|
fFoundAnyData = true;
|
|
|
|
rFrameInfo.nLine = nLine;
|
|
|
|
if (pszFunction != NULL)
|
|
{
|
|
rFrameInfo.pszFunction = pszFunction;
|
|
fFoundAnyData = true;
|
|
}
|
|
else
|
|
rFrameInfo.pszFunction = NULL;
|
|
|
|
return fFoundAnyData;
|
|
}
|
|
|
|
int STDAPIVCALLTYPE _DebugTraceA(LPCSTR pszMsg, ...)
|
|
{
|
|
int iResult;
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
iResult = _DebugTraceExVaA(0, TRACETYPE_INFO, NOERROR, pszMsg, ap);
|
|
va_end(ap);
|
|
return iResult;
|
|
}
|
|
|
|
int STDAPICALLTYPE
|
|
_DebugTraceVaA(LPCSTR pszMsg, va_list ap)
|
|
{
|
|
return _DebugTraceExVaA(0, TRACETYPE_INFO, NOERROR, pszMsg, ap);
|
|
}
|
|
|
|
int STDAPIVCALLTYPE
|
|
_DebugTraceExA(DWORD dwFlags, TRACETYPE tt, HRESULT hr, LPCSTR pszMsg, ...)
|
|
{
|
|
int iResult;
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
iResult = _DebugTraceExVaA(dwFlags, tt, hr, pszMsg, ap);
|
|
va_end(ap);
|
|
return iResult;
|
|
}
|
|
|
|
int STDAPICALLTYPE
|
|
_DebugTraceExVaA(DWORD dwFlags, TRACETYPE tt, HRESULT hr, LPCSTR pszMsg, va_list ap)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szBuffer[512];
|
|
CHAR szMsgBuffer[512];
|
|
static const char szFormat_Info_NoFunc[] = "%s(%d): Message: \"%s\"\n";
|
|
static const char szFormat_Info_Func[] = "%s(%d): Function %s. Message: \"%s\"\n";
|
|
static const char szFormat_CallEntry[] = "%s(%d): Entered %s\n";
|
|
static const char szFormat_CallExitVoid[] = "%s(%d): Exited %s\n";
|
|
static const char szFormat_CallExitHRESULT[] = "%s(%d): Exited %s with HRESULT 0x%08lx\n";
|
|
|
|
FRAME_INFO FrameInfo;
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
|
|
if (pszMsg != NULL)
|
|
{
|
|
::_snprintf(szMsgBuffer, NUMBER_OF(szMsgBuffer), pszMsg, ap);
|
|
szMsgBuffer[NUMBER_OF(szMsgBuffer) - 1] = '\0';
|
|
}
|
|
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
switch (tt)
|
|
{
|
|
default:
|
|
case TRACETYPE_INFO:
|
|
if (FrameInfo.pszFunction != NULL)
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), szFormat_Info_Func, FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction, szMsgBuffer);
|
|
else
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), szFormat_Info_NoFunc, FrameInfo.pszFile, FrameInfo.nLine, szMsgBuffer);
|
|
break;
|
|
|
|
case TRACETYPE_CALL_START:
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), szFormat_CallEntry, FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction);
|
|
break;
|
|
|
|
case TRACETYPE_CALL_EXIT_NOHRESULT:
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), szFormat_CallExitVoid, FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction);
|
|
break;
|
|
|
|
case TRACETYPE_CALL_EXIT_HRESULT:
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), szFormat_CallExitHRESULT, FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction, hr);
|
|
break;
|
|
}
|
|
|
|
szBuffer[NUMBER_OF(szBuffer) - 1] = '\0';
|
|
|
|
::OutputDebugStringA(szBuffer);
|
|
|
|
ple.Restore();
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceAllocFailure(
|
|
PCSTR pszFile,
|
|
int nLine,
|
|
PCSTR pszFunction,
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szBuffer[512];
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), "%s(%d): Memory allocation failed in function %s\n Expression: %s\n", pszFile, nLine, pszFunction, pszExpression);
|
|
szBuffer[NUMBER_OF(szBuffer) - 1] = '\0';
|
|
::OutputDebugStringA(szBuffer);
|
|
ple.Restore();
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceAllocFailure(
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
::FusionpTraceAllocFailure(FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction, pszExpression);
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceNull(
|
|
PCSTR pszFile,
|
|
int nLine,
|
|
PCSTR pszFunction,
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szBuffer[512];
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), "%s(%d): Expression evaluated to NULL in function %s\n Expression: %s\n", pszFile, nLine, pszFunction, pszExpression);
|
|
szBuffer[NUMBER_OF(szBuffer) - 1] = '\0';
|
|
::OutputDebugStringA(szBuffer);
|
|
ple.Restore();
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceNull(
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
::FusionpTraceNull(FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction, pszExpression);
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceZero(
|
|
PCSTR pszFile,
|
|
int nLine,
|
|
PCSTR pszFunction,
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szBuffer[512];
|
|
::_snprintf(szBuffer, NUMBER_OF(szBuffer), "%s(%d): Expression evaluated to zero in function %s\n Expression: %s\n", pszFile, nLine, pszFunction, pszExpression);
|
|
szBuffer[NUMBER_OF(szBuffer) - 1] = '\0';
|
|
::OutputDebugStringA(szBuffer);
|
|
ple.Restore();
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceZero(
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
::FusionpTraceZero(FrameInfo.pszFile, FrameInfo.nLine, FrameInfo.pszFunction, pszExpression);
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceParameterCheck(
|
|
const FRAME_INFO &rFrameInfo,
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szBuffer[512];
|
|
::_snprintf(
|
|
szBuffer,
|
|
NUMBER_OF(szBuffer),
|
|
"%s(%d): Input parameter validation failed in function %s\n Validation expression: %s\n",
|
|
rFrameInfo.pszFile,
|
|
rFrameInfo.nLine,
|
|
rFrameInfo.pszFunction,
|
|
pszExpression);
|
|
szBuffer[NUMBER_OF(szBuffer) - 1] = '\0';
|
|
::OutputDebugStringA(szBuffer);
|
|
if (g_FusionBreakOnBadParameters)
|
|
FUSION_DEBUG_BREAK_IN_FREE_BUILD();
|
|
ple.Restore();
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceParameterCheck(
|
|
PCSTR pszFile,
|
|
PCSTR pszFunction,
|
|
int nLine,
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpPopulateFrameInfo(FrameInfo, pszFile, pszFunction, nLine);
|
|
::FusionpTraceParameterCheck(FrameInfo, pszExpression);
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceParameterCheck(
|
|
PCSTR pszExpression
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
::FusionpTraceParameterCheck(FrameInfo, pszExpression);
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceInvalidFlags(
|
|
const FRAME_INFO &rFrameInfo,
|
|
DWORD dwFlagsPassed,
|
|
DWORD dwFlagsExpected
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szBuffer[512];
|
|
|
|
::_snprintf(
|
|
szBuffer,
|
|
NUMBER_OF(szBuffer),
|
|
"%s(%d): Function %s received invalid flags\n"
|
|
" Flags passed: 0x%08lx\n"
|
|
" Flags allowed: 0x%08lx\n",
|
|
rFrameInfo.pszFile, rFrameInfo.nLine, rFrameInfo.pszFunction,
|
|
dwFlagsPassed,
|
|
dwFlagsExpected);
|
|
|
|
szBuffer[NUMBER_OF(szBuffer) - 1] = '\0';
|
|
|
|
::OutputDebugStringA(szBuffer);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceInvalidFlags(
|
|
PCSTR pszFile,
|
|
PCSTR pszFunction,
|
|
INT nLine,
|
|
DWORD dwFlagsPassed,
|
|
DWORD dwFlagsExpected
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpPopulateFrameInfo(FrameInfo, pszFile, pszFunction, nLine);
|
|
::FusionpTraceInvalidFlags(FrameInfo, dwFlagsPassed, dwFlagsExpected);
|
|
}
|
|
|
|
VOID
|
|
FusionpTraceInvalidFlags(
|
|
DWORD dwFlagsPassed,
|
|
DWORD dwFlagsExpected
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
::FusionpTraceInvalidFlags(FrameInfo, dwFlagsPassed, dwFlagsExpected);
|
|
}
|
|
|
|
void
|
|
FusionpGetProcessImageFileName(
|
|
PUNICODE_STRING ProcessImageFileName
|
|
)
|
|
{
|
|
#if !defined(FUSION_WIN)
|
|
ProcessImageFileName->Length = 0;
|
|
#else
|
|
USHORT PrefixLength;
|
|
*ProcessImageFileName = NtCurrentPeb()->ProcessParameters->ImagePathName;
|
|
|
|
if (NT_SUCCESS(RtlFindCharInUnicodeString(
|
|
RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
|
|
ProcessImageFileName,
|
|
&RtlDosPathSeperatorsString,
|
|
&PrefixLength)))
|
|
{
|
|
PrefixLength += sizeof(ProcessImageFileName->Buffer[0]);
|
|
ProcessImageFileName->Length = static_cast<USHORT>(ProcessImageFileName->Length - PrefixLength);
|
|
ProcessImageFileName->Buffer += PrefixLength / sizeof(ProcessImageFileName->Buffer[0]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
class CFusionProcessImageFileName : public UNICODE_STRING
|
|
{
|
|
public:
|
|
CFusionProcessImageFileName()
|
|
{
|
|
::FusionpGetProcessImageFileName(this);
|
|
}
|
|
};
|
|
|
|
void __fastcall FusionpTraceWin32LastErrorFailureExV(const CALL_SITE_INFO &rCallSiteInfo, PCSTR Format, va_list Args)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR Buffer[256];
|
|
CALL_SITE_INFO CallSiteInfo = rCallSiteInfo;
|
|
CallSiteInfo.pszApiName = Buffer;
|
|
SIZE_T i = 1;
|
|
|
|
Buffer[0] = '\0';
|
|
if (rCallSiteInfo.pszApiName != NULL && rCallSiteInfo.pszApiName[0] != '\0')
|
|
{
|
|
::_snprintf(Buffer, NUMBER_OF(Buffer) - i, "%s", rCallSiteInfo.pszApiName);
|
|
Buffer[NUMBER_OF(Buffer) - 1] = '\0';
|
|
i = 1 + ::StringLength(Buffer);
|
|
}
|
|
if (i < NUMBER_OF(Buffer))
|
|
{
|
|
::_vsnprintf(&Buffer[i - 1], NUMBER_OF(Buffer) - i, Format, Args);
|
|
Buffer[NUMBER_OF(Buffer) - 1] = '\0';
|
|
}
|
|
|
|
::FusionpTraceWin32LastErrorFailure(CallSiteInfo);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void __fastcall FusionpTraceWin32LastErrorFailureOriginationExV(const CALL_SITE_INFO &rCallSiteInfo, PCSTR Format, va_list Args)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR Buffer[128];
|
|
CALL_SITE_INFO CallSiteInfo = rCallSiteInfo;
|
|
CallSiteInfo.pszApiName = Buffer;
|
|
|
|
Buffer[0] = '\0';
|
|
::_vsnprintf(Buffer, NUMBER_OF(Buffer) - 1, Format, Args);
|
|
Buffer[NUMBER_OF(Buffer) - 1] = '\0';
|
|
|
|
::FusionpTraceWin32LastErrorFailureOrigination(CallSiteInfo);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void __fastcall
|
|
FusionpTraceWin32LastErrorFailure(
|
|
const CALL_SITE_INFO &rSite
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szErrorBuffer[128];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
const DWORD dwWin32Status = ::FusionpGetLastWin32Error();
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(HRESULT_FROM_WIN32(dwWin32Status));
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
dwWin32Status, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable Win32 status %d (0x%08lx)>",
|
|
dwWin32Status, dwWin32Status);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
if (rSite.pszApiName != NULL)
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s) %s\n";
|
|
else
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s)\n";
|
|
|
|
::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROREXITPATH, pszFormatString, rSite.pszFile, rSite.nLine,
|
|
rSite.pszFunction, sizeof(PVOID) * CHAR_BIT, &ProcessImageFileName, dwThreadId,
|
|
dwWin32Status, szErrorBuffer, rSite.pszApiName);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void
|
|
__fastcall
|
|
FusionpTraceWin32LastErrorFailureOrigination(
|
|
const CALL_SITE_INFO &rSite
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
CHAR szErrorBuffer[128];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
const DWORD dwWin32Status = ::FusionpGetLastWin32Error();
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(HRESULT_FROM_WIN32(dwWin32Status));
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
dwWin32Status, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable Win32 status %d (0x%08lx)>",
|
|
dwWin32Status, dwWin32Status);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
if (rSite.pszApiName != NULL)
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s) %s\n";
|
|
else
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s)\n";
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR, // FUSION_DBG_LEVEL_ERROR vs. FUSION_DBG_LEVEL_ERROREXITPATH
|
|
// is the difference between "origination" or not
|
|
// origination always prints in DBG, the point is to get only one line
|
|
// or the stack trace only one
|
|
pszFormatString,
|
|
rSite.pszFile,
|
|
rSite.nLine,
|
|
rSite.pszFunction,
|
|
sizeof(PVOID)*CHAR_BIT,
|
|
&ProcessImageFileName,
|
|
dwThreadId,
|
|
dwWin32Status,
|
|
szErrorBuffer,
|
|
rSite.pszApiName);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void
|
|
FusionpTraceWin32FailureNoFormatting(
|
|
const FRAME_INFO &rFrameInfo,
|
|
DWORD dwWin32Status,
|
|
PCSTR pszMessage
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(HRESULT_FROM_WIN32(dwWin32Status));
|
|
CHAR szErrorBuffer[128];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
dwWin32Status, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable Win32 status %d (0x%08lx)>",
|
|
dwWin32Status, dwWin32Status);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
if (pszMessage != NULL)
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s) %s\n";
|
|
else
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s)\n";
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROREXITPATH, pszFormatString, rFrameInfo.pszFile, rFrameInfo.nLine,
|
|
rFrameInfo.pszFunction, sizeof(PVOID)*CHAR_BIT, &ProcessImageFileName, dwThreadId, dwWin32Status,
|
|
szErrorBuffer, pszMessage
|
|
);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void
|
|
FusionpTraceWin32FailureOriginationNoFormatting(
|
|
const FRAME_INFO &rFrameInfo,
|
|
DWORD dwWin32Status,
|
|
PCSTR pszMessage
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(HRESULT_FROM_WIN32(dwWin32Status));
|
|
CHAR szErrorBuffer[128];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
dwWin32Status, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable Win32 status %d (0x%08lx)>",
|
|
dwWin32Status, dwWin32Status);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
if (pszMessage != NULL)
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s) %s\n";
|
|
else
|
|
pszFormatString = "%s(%lu): [function %s %Iubit process %wZ tid 0x%lx] Win32 Error %d (%s)\n";
|
|
|
|
::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, pszFormatString, rFrameInfo.pszFile, rFrameInfo.nLine,
|
|
rFrameInfo.pszFunction, sizeof(PVOID) * CHAR_BIT, &ProcessImageFileName, dwThreadId,
|
|
dwWin32Status, szErrorBuffer, pszMessage);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void
|
|
FusionpTraceWin32Failure(
|
|
DWORD dwWin32Status,
|
|
LPCSTR pszMsg,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
::FusionpTraceWin32FailureVa(dwWin32Status, pszMsg, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
#if 0
|
|
|
|
void
|
|
FusionpTraceWin32Failure(
|
|
const FRAME_INFO &rFrameInfo,
|
|
DWORD dwWin32Status,
|
|
LPCSTR pszMsg,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
::FusionpTraceWin32FailureVa(rFrameInfo, dwWin32Status, pszMsg, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceWin32Failure(
|
|
PCSTR pszFile,
|
|
PCSTR pszFunction,
|
|
INT nLine,
|
|
DWORD dwWin32Status,
|
|
LPCSTR pszMsg,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
::FusionpTraceWin32FailureVa(pszFile, pszFunction, nLine, dwWin32Status, pszMsg, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
FusionpTraceWin32FailureVa(
|
|
const FRAME_INFO &rFrameInfo,
|
|
DWORD dwWin32Status,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
CSxsPreserveLastError ple;
|
|
|
|
CHAR szMessageBuffer[128];
|
|
|
|
szMessageBuffer[0] = '\0';
|
|
|
|
if (pszMsg != NULL)
|
|
::_vsnprintf(szMessageBuffer, NUMBER_OF(szMessageBuffer), pszMsg, ap);
|
|
else
|
|
szMessageBuffer[0] = '\0';
|
|
|
|
szMessageBuffer[NUMBER_OF(szMessageBuffer) - 1] = '\0';
|
|
|
|
::FusionpTraceWin32FailureNoFormatting(rFrameInfo, dwWin32Status, szMessageBuffer);
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
void
|
|
FusionpTraceWin32FailureVa(
|
|
DWORD dwWin32Status,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
::FusionpTraceWin32FailureVa(FrameInfo, dwWin32Status, pszMsg, ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceWin32FailureVa(
|
|
PCSTR pszFile,
|
|
PCSTR pszFunction,
|
|
INT nLine,
|
|
DWORD dwWin32Status,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpPopulateFrameInfo(FrameInfo, pszFile, pszFunction, nLine);
|
|
::FusionpTraceWin32FailureVa(FrameInfo, dwWin32Status, pszMsg, ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallCOMSuccessfulExit(
|
|
HRESULT hrIn,
|
|
PCSTR pszFormat,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pszFormat);
|
|
::FusionpTraceCallCOMSuccessfulExitVa(hrIn, pszFormat, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallCOMSuccessfulExitSmall(
|
|
HRESULT hrIn
|
|
)
|
|
{
|
|
/*
|
|
This is a forked version of FusionpTraceCOMSuccessfulExitVaBig that we expect to get called.
|
|
This function uses about 256 bytes of stack.
|
|
FusionpTraceCOMSuccessfulExitVaBug uses about 1k of stack.
|
|
*/
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hrIn);
|
|
CHAR szErrorBuffer[256];
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
hrIn, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable(non-existed or too long) HRESULT: 0x%08lx>",
|
|
hrIn);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
PCSTR pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx\n";
|
|
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ENTEREXIT,
|
|
pszFormatString,
|
|
FrameInfo.pszFile,
|
|
FrameInfo.nLine,
|
|
FrameInfo.pszFunction,
|
|
sizeof(PVOID) * CHAR_BIT,
|
|
&ProcessImageFileName,
|
|
dwThreadId,
|
|
hrIn,
|
|
szErrorBuffer);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallCOMSuccessfulExitVaBig(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
/*
|
|
This is a forked version of FusionpTraceCOMSuccessfulExitVaSmall that we don't expect to get called.
|
|
FusionpTraceCOMSuccessfulExitVaSmall uses about 256 bytes of stack.
|
|
This function uses about 1k of stack.
|
|
*/
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hrIn);
|
|
CHAR szMsgBuffer[128];
|
|
CHAR szErrorBuffer[128];
|
|
CHAR szOutputBuffer[256];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
FRAME_INFO FrameInfo;
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
szErrorBuffer[0] = '\0';
|
|
szOutputBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
hrIn, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable(non-existed or too long) HRESULT: 0x%08lx>",
|
|
hrIn);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
|
|
if (pszMsg != NULL)
|
|
{
|
|
pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx (%s) %s\n";
|
|
::_snprintf(szMsgBuffer, NUMBER_OF(szMsgBuffer), pszMsg, ap);
|
|
szMsgBuffer[NUMBER_OF(szMsgBuffer) - 1] = '\0';
|
|
}
|
|
else
|
|
pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx (%s)\n";
|
|
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
::_snprintf(szOutputBuffer, NUMBER_OF(szOutputBuffer), pszFormatString, FrameInfo.pszFile,
|
|
FrameInfo.nLine, FrameInfo.pszFunction, sizeof(PVOID) * CHAR_BIT, &ProcessImageFileName, dwThreadId,
|
|
hrIn, szErrorBuffer, szMsgBuffer);
|
|
|
|
szOutputBuffer[NUMBER_OF(szOutputBuffer) - 1] = '\0';
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ENTEREXIT,
|
|
"%s",
|
|
szOutputBuffer);
|
|
|
|
if ((s_hFile != NULL) && (s_hFile != INVALID_HANDLE_VALUE))
|
|
{
|
|
DWORD cBytesWritten = 0;
|
|
if (!::WriteFile(s_hFile, szOutputBuffer, static_cast<DWORD>((::strlen(szOutputBuffer) + 1) * sizeof(CHAR)), &cBytesWritten, NULL))
|
|
{
|
|
// Avoid infinite loop if s_hFile is trashed...
|
|
HANDLE hFileSaved = s_hFile;
|
|
s_hFile = NULL;
|
|
TRACE_WIN32_FAILURE_ORIGINATION(WriteFile);
|
|
s_hFile = hFileSaved;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallCOMSuccessfulExitVa(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
/*
|
|
This function has been split into FusionpTraceCOMSuccessfulExitVaBig and FusionpTraceCOMSuccessfulExitVaSmall, so that
|
|
the usual case uses about 768 fewer bytes on the stack.
|
|
*/
|
|
if ((pszMsg == NULL) &&
|
|
((s_hFile == NULL) ||
|
|
(s_hFile == INVALID_HANDLE_VALUE)))
|
|
{
|
|
::FusionpTraceCallCOMSuccessfulExitVaBig(hrIn, pszMsg, ap);
|
|
}
|
|
else
|
|
{
|
|
::FusionpTraceCallCOMSuccessfulExitSmall(hrIn);
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailure(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
::FusionpTraceCOMFailureVa(hrIn, pszMsg, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureSmall(
|
|
HRESULT hrIn
|
|
)
|
|
{
|
|
/*
|
|
This is a forked version of FusionpTraceCOMFailureVaBig that we expect to get called.
|
|
This function uses about 256 bytes of stack.
|
|
FusionpTraceCOMFailureVaBug uses about 1k of stack.
|
|
*/
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hrIn);
|
|
CHAR szErrorBuffer[256];
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
hrIn, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable(non-existed or too long) HRESULT: 0x%08lx>",
|
|
hrIn);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
PCSTR pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx\n";
|
|
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROREXITPATH,
|
|
pszFormatString,
|
|
FrameInfo.pszFile,
|
|
FrameInfo.nLine,
|
|
FrameInfo.pszFunction,
|
|
sizeof(PVOID) * CHAR_BIT,
|
|
&ProcessImageFileName,
|
|
dwThreadId,
|
|
hrIn,
|
|
szErrorBuffer);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureVaBig(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
/*
|
|
This is a forked version of FusionpTraceCOMFailureVaSmall that we don't expect to get called.
|
|
FusionpTraceCOMFailureVaSmall uses about 256 bytes of stack.
|
|
This function uses about 1k of stack.
|
|
*/
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hrIn);
|
|
CHAR szMsgBuffer[256];
|
|
CHAR szErrorBuffer[256];
|
|
CHAR szOutputBuffer[512];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
FRAME_INFO FrameInfo;
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
szErrorBuffer[0] = '\0';
|
|
szOutputBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
hrIn, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable(non-existed or too long) HRESULT: 0x%08lx>",
|
|
hrIn);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
|
|
if (pszMsg != NULL)
|
|
{
|
|
pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx (%s) %s\n";
|
|
::_snprintf(szMsgBuffer, NUMBER_OF(szMsgBuffer), pszMsg, ap);
|
|
szMsgBuffer[NUMBER_OF(szMsgBuffer) - 1] = '\0';
|
|
}
|
|
else
|
|
pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx (%s)\n";
|
|
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
::_snprintf(szOutputBuffer, NUMBER_OF(szOutputBuffer), pszFormatString, FrameInfo.pszFile,
|
|
FrameInfo.nLine, FrameInfo.pszFunction, sizeof(PVOID) * CHAR_BIT, &ProcessImageFileName,
|
|
dwThreadId, hrIn, szErrorBuffer, szMsgBuffer);
|
|
|
|
szOutputBuffer[NUMBER_OF(szOutputBuffer) - 1] = '\0';
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROREXITPATH,
|
|
"%s",
|
|
szOutputBuffer);
|
|
|
|
if ((s_hFile != NULL) && (s_hFile != INVALID_HANDLE_VALUE))
|
|
{
|
|
DWORD cBytesWritten = 0;
|
|
if (!::WriteFile(s_hFile, szOutputBuffer, static_cast<DWORD>((::strlen(szOutputBuffer) + 1) * sizeof(CHAR)), &cBytesWritten, NULL))
|
|
{
|
|
// Avoid infinite loop if s_hFile is trashed...
|
|
HANDLE hFileSaved = s_hFile;
|
|
s_hFile = NULL;
|
|
TRACE_WIN32_FAILURE_ORIGINATION(WriteFile);
|
|
s_hFile = hFileSaved;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureVa(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
/*
|
|
This function has been split into FusionpTraceCOMFailureVaBig and FusionpTraceCOMFailureVaSmall, so that
|
|
the usual case uses about 768 fewer bytes on the stack.
|
|
*/
|
|
if ((pszMsg == NULL) &&
|
|
((s_hFile == NULL) ||
|
|
(s_hFile == INVALID_HANDLE_VALUE)))
|
|
{
|
|
::FusionpTraceCOMFailureVaBig(hrIn, pszMsg, ap);
|
|
}
|
|
else
|
|
{
|
|
::FusionpTraceCOMFailureSmall(hrIn);
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureOrigination(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, pszMsg);
|
|
::FusionpTraceCOMFailureOriginationVa(hrIn, pszMsg, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureOriginationSmall(
|
|
HRESULT hrIn
|
|
)
|
|
{
|
|
/*
|
|
This is a forked version of FusionpTraceCOMFailureVaBig that we expect to get called.
|
|
This function uses about 256 bytes of stack.
|
|
FusionpTraceCOMFailureVaBug uses about 1k of stack.
|
|
*/
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hrIn);
|
|
CHAR szErrorBuffer[256];
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szErrorBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
hrIn, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable(non-existed or too long) HRESULT: 0x%08lx>",
|
|
hrIn);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
PCSTR pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx\n";
|
|
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, pszFormatString, FrameInfo.pszFile,
|
|
FrameInfo.nLine, FrameInfo.pszFunction, sizeof(PVOID) * CHAR_BIT, &ProcessImageFileName,
|
|
dwThreadId, hrIn, szErrorBuffer);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureOriginationVaBig(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
/*
|
|
This is a forked version of FusionpTraceCOMFailureVaSmall that we don't expect to get called.
|
|
FusionpTraceCOMFailureVaSmall uses about 256 bytes of stack.
|
|
This function uses about 1k of stack.
|
|
*/
|
|
FUSIONP_SUPPRESS_ERROR_REPORT_IN_OS_SETUP(hrIn);
|
|
CHAR szMsgBuffer[256];
|
|
CHAR szErrorBuffer[256];
|
|
CHAR szOutputBuffer[512];
|
|
PCSTR pszFormatString = NULL;
|
|
const DWORD dwThreadId = ::GetCurrentThreadId();
|
|
FRAME_INFO FrameInfo;
|
|
CFusionProcessImageFileName ProcessImageFileName;
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
szErrorBuffer[0] = '\0';
|
|
szOutputBuffer[0] = '\0';
|
|
|
|
DWORD dwTemp = ::FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_MAX_WIDTH_MASK, // dwFlags
|
|
NULL, // lpSource - not used with system messages
|
|
hrIn, // dwMessageId
|
|
0, // langid - 0 uses system default search path of languages
|
|
szErrorBuffer, // lpBuffer
|
|
NUMBER_OF(szErrorBuffer), // nSize
|
|
NULL); // Arguments
|
|
if (dwTemp == 0)
|
|
{
|
|
::_snprintf(
|
|
szErrorBuffer,
|
|
NUMBER_OF(szErrorBuffer),
|
|
"<Untranslatable(non-existed or too long) HRESULT: 0x%08lx>",
|
|
hrIn);
|
|
szErrorBuffer[NUMBER_OF(szErrorBuffer) - 1] = '\0';
|
|
}
|
|
|
|
szMsgBuffer[0] = '\0';
|
|
|
|
if (pszMsg != NULL)
|
|
{
|
|
pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx (%s) %s\n";
|
|
::_snprintf(szMsgBuffer, NUMBER_OF(szMsgBuffer), pszMsg, ap);
|
|
szMsgBuffer[NUMBER_OF(szMsgBuffer) - 1] = '\0';
|
|
}
|
|
else
|
|
pszFormatString = "%s(%d): [function %s %Iubit process %wZ tid 0x%lx] COM Error 0x%08lx (%s)\n";
|
|
|
|
::FusionpGetActiveFrameInfo(FrameInfo);
|
|
|
|
::_snprintf(szOutputBuffer, NUMBER_OF(szOutputBuffer), pszFormatString, FrameInfo.pszFile,
|
|
FrameInfo.nLine, FrameInfo.pszFunction, sizeof(PVOID) * CHAR_BIT, &ProcessImageFileName,
|
|
dwThreadId, hrIn, szErrorBuffer, szMsgBuffer);
|
|
|
|
szOutputBuffer[NUMBER_OF(szOutputBuffer) - 1] = '\0';
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ERROR,
|
|
"%s",
|
|
szOutputBuffer);
|
|
|
|
if ((s_hFile != NULL) && (s_hFile != INVALID_HANDLE_VALUE))
|
|
{
|
|
DWORD cBytesWritten = 0;
|
|
if (!::WriteFile(s_hFile, szOutputBuffer, static_cast<DWORD>((::strlen(szOutputBuffer) + 1) * sizeof(CHAR)), &cBytesWritten, NULL))
|
|
{
|
|
// Avoid infinite loop if s_hFile is trashed...
|
|
HANDLE hFileSaved = s_hFile;
|
|
s_hFile = NULL;
|
|
TRACE_WIN32_FAILURE_ORIGINATION(WriteFile);
|
|
s_hFile = hFileSaved;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCOMFailureOriginationVa(
|
|
HRESULT hrIn,
|
|
LPCSTR pszMsg,
|
|
va_list ap
|
|
)
|
|
{
|
|
/*
|
|
This function has been split into FusionpTraceCOMFailureVaBig and FusionpTraceCOMFailureVaSmall, so that
|
|
the usual case uses about 768 fewer bytes on the stack.
|
|
*/
|
|
if ((pszMsg == NULL) &&
|
|
((s_hFile == NULL) ||
|
|
(s_hFile == INVALID_HANDLE_VALUE)))
|
|
{
|
|
::FusionpTraceCOMFailureOriginationVaBig(hrIn, pszMsg, ap);
|
|
}
|
|
else
|
|
{
|
|
::FusionpTraceCOMFailureOriginationSmall(hrIn);
|
|
}
|
|
}
|
|
|
|
struct ILogFile;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// TRACEMACROTYPE
|
|
// --------------------------------------------------------------------------------
|
|
typedef enum tagTRACEMACROTYPE {
|
|
TRACE_INFO,
|
|
TRACE_CALL,
|
|
TRACE_RESULT
|
|
} TRACEMACROTYPE;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// These Traces are for c++ only
|
|
// --------------------------------------------------------------------------------
|
|
typedef DWORD SHOWTRACEMASK;
|
|
#define SHOW_TRACE_NONE 0x00000000
|
|
#define SHOW_TRACE_INFO 0x00000001
|
|
#define SHOW_TRACE_CALL 0x00000002
|
|
#define SHOW_TRACE_ALL 0xffffffff
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// TRACELOGINFOINFO
|
|
// --------------------------------------------------------------------------------
|
|
typedef struct tagTRACELOGINFO {
|
|
SHOWTRACEMASK dwMask;
|
|
ILogFile *pLog;
|
|
} TRACELOGINFO, *LPTRACELOGINFO;
|
|
|
|
// function to make directdb happy
|
|
HRESULT DebugTraceEx(SHOWTRACEMASK dwMask, TRACEMACROTYPE tracetype, LPTRACELOGINFO pLog,
|
|
HRESULT hr, LPSTR pszFile, INT nLine, LPCSTR pszMsg, LPCSTR pszFunc)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallEntry()
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
|
|
if (::FusionpGetActiveFrameInfo(FrameInfo))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ENTEREXIT,
|
|
"%s(%d): Entered %s\n",
|
|
FrameInfo.pszFile,
|
|
FrameInfo.nLine,
|
|
FrameInfo.pszFunction);
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallExit()
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
|
|
if (::FusionpGetActiveFrameInfo(FrameInfo))
|
|
{
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ENTEREXIT,
|
|
"%s(%d): Exited %s\n",
|
|
FrameInfo.pszFile,
|
|
FrameInfo.nLine,
|
|
FrameInfo.pszFunction);
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallSuccessfulExitVa(
|
|
PCSTR szFormat,
|
|
va_list ap
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
|
|
if (::FusionpGetActiveFrameInfo(FrameInfo))
|
|
{
|
|
CHAR Buffer[256];
|
|
|
|
Buffer[0] = '\0';
|
|
|
|
if (szFormat != NULL)
|
|
{
|
|
::_vsnprintf(Buffer, NUMBER_OF(Buffer), szFormat, ap);
|
|
Buffer[NUMBER_OF(Buffer) - 1] = '\0';
|
|
}
|
|
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_ENTEREXIT,
|
|
"%s(%d): Successfully exiting %s%s%s\n",
|
|
FrameInfo.pszFile,
|
|
FrameInfo.nLine,
|
|
FrameInfo.pszFunction,
|
|
Buffer[0] == '\0' ? "" : " - ",
|
|
Buffer);
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallSuccessfulExit(
|
|
PCSTR szFormat,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, szFormat);
|
|
::FusionpTraceCallSuccessfulExitVa(szFormat, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallWin32UnsuccessfulExitVa(
|
|
DWORD dwError,
|
|
PCSTR szFormat,
|
|
va_list ap
|
|
)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
|
|
if (::FusionpGetActiveFrameInfo(FrameInfo))
|
|
{
|
|
::FusionpTraceWin32FailureVa(
|
|
FrameInfo,
|
|
dwError,
|
|
szFormat,
|
|
ap);
|
|
}
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallWin32UnsuccessfulExit(
|
|
DWORD dwError,
|
|
PCSTR szFormat,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, szFormat);
|
|
::FusionpTraceCallWin32UnsuccessfulExitVa(dwError, szFormat, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallCOMUnsuccessfulExitVa(
|
|
HRESULT hrError,
|
|
PCSTR szFormat,
|
|
va_list ap
|
|
)
|
|
{
|
|
::FusionpTraceCOMFailureVa(
|
|
hrError,
|
|
szFormat,
|
|
ap);
|
|
}
|
|
|
|
void
|
|
FusionpTraceCallCOMUnsuccessfulExit(
|
|
HRESULT hrError,
|
|
PCSTR szFormat,
|
|
...
|
|
)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, szFormat);
|
|
::FusionpTraceCallCOMUnsuccessfulExitVa(hrError, szFormat, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
#if FUSION_FREEZE_STACK_ENABLED
|
|
|
|
BOOL
|
|
FusionpFreezeStack(
|
|
DWORD dwFlags,
|
|
IN PFROZEN_STACK pFrozenStack
|
|
)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
PTRACECONTEXT pStackCursor = NULL;
|
|
|
|
//
|
|
// If they supplied a frozen stack structure, then start it out as having
|
|
// zero depth.
|
|
//
|
|
if ( pFrozenStack ) pFrozenStack->ulDepth = 0;
|
|
|
|
//
|
|
// No frozen stack, or flags != 0 is an error.
|
|
//
|
|
if ( !pFrozenStack || ( dwFlags != 0 ) ) {
|
|
::SetLastError( ERROR_INVALID_PARAMETER );
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// If there's no stack so far, then we're done here.
|
|
//
|
|
if ( !ptcs || !ptcs->m_StackHead )
|
|
{
|
|
bSuccess = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
if ( pFrozenStack->ulMaxDepth < ptcs->m_StackDepth )
|
|
{
|
|
pFrozenStack->ulMaxDepth = ptcs->m_StackDepth;
|
|
::SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|
goto Exit;
|
|
}
|
|
|
|
pStackCursor = ptcs->m_StackHead;
|
|
while ( pStackCursor && ( pFrozenStack->ulDepth < pFrozenStack->ulMaxDepth ) )
|
|
{
|
|
pFrozenStack->Contexts[pFrozenStack->ulDepth] = *pStackCursor;
|
|
|
|
//
|
|
// This little bit verifies that the pointers we have in the stack frame
|
|
// are really inside our process. We need to do this so that when we go
|
|
// and store them (actually above) for later, we are sure to clear ones
|
|
// that aren't under our control.
|
|
//
|
|
// Since no processes have their base address at NULL, we can use this
|
|
// test to ensure that the basic information has been set up. Cases
|
|
// in which this is not set up include running in sxstest or in
|
|
// another module that doesn't call VirtualQueryEx to find out this
|
|
// information.
|
|
//
|
|
/* if ( g_SxsDllMemoryBasicInformation.BaseAddress != NULL )
|
|
{
|
|
PBYTE pvBase = (PBYTE)g_SxsDllMemoryBasicInformation.AllocationBase;
|
|
PBYTE pvLimit = pvBase + g_SxsDllMemoryBasicInformation.RegionSize;
|
|
|
|
#define PTR_IN_RANGE_CHECK( member, parent, target, base, limit ) \
|
|
{ PVOID pv = (PVOID)((parent).##member); if ( ( pv < base ) || ( pv > limit ) ) (target).##member = NULL; }
|
|
PTR_IN_RANGE_CHECK( m_szComponentName, *pStackCursor, pFrozenStack->Contexts[pFrozenStack->ulDepth], pvBase, pvLimit )
|
|
PTR_IN_RANGE_CHECK( m_szFile, *pStackCursor, pFrozenStack->Contexts[pFrozenStack->ulDepth], pvBase, pvLimit );
|
|
PTR_IN_RANGE_CHECK( m_szFunctionName, *pStackCursor, pFrozenStack->Contexts[pFrozenStack->ulDepth], pvBase, pvLimit );
|
|
#undef PTR_IN_RANGE_CHECK
|
|
}
|
|
*/
|
|
pStackCursor = pStackCursor->m_pCtxOld;
|
|
pFrozenStack->ulDepth++;
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
Exit:
|
|
return bSuccess;
|
|
}
|
|
|
|
#endif // FUSION_FREEZE_STACK_ENABLED
|
|
|
|
VOID
|
|
FusionpDumpStack(
|
|
IN DWORD dwFlags,
|
|
IN ULONG ulLevel,
|
|
IN PCWSTR pcwszLinePrefix,
|
|
IN ULONG ulStackDepth
|
|
)
|
|
{
|
|
ULONG ulCurrentFrameDepth = 0;
|
|
ULONG ulFormat = FUSIONP_DUMP_STACK_FORMAT_MEDIUM;
|
|
PCTEB_ACTIVE_FRAME ptaf = NULL;
|
|
|
|
if (dwFlags == 0)
|
|
{
|
|
dwFlags = FUSIONP_DUMP_STACK_FORMAT_MEDIUM;
|
|
}
|
|
else if ((dwFlags & ~(FUSIONP_DUMP_STACK_FORMAT_MASK)) != 0)
|
|
{
|
|
#if DBG
|
|
OutputDebugStringA("SXS.DLL: Someone called FusionpDumpStack with invalid parameters!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
ulFormat = (dwFlags & FUSIONP_DUMP_STACK_FORMAT_MASK);
|
|
|
|
if ((ulFormat != FUSIONP_DUMP_STACK_FORMAT_SHORT) &&
|
|
(ulFormat != FUSIONP_DUMP_STACK_FORMAT_MEDIUM) &&
|
|
(ulFormat != FUSIONP_DUMP_STACK_FORMAT_LONG))
|
|
{
|
|
#if DBG
|
|
OutputDebugStringA("Invalid format passed in call to FusionpDumpStack()\n");
|
|
DebugBreak();
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (pcwszLinePrefix == NULL)
|
|
pcwszLinePrefix = L"SXS";
|
|
|
|
#if FUSION_WIN
|
|
ptaf = ::RtlGetFrame();
|
|
#else
|
|
ptaf = NULL;
|
|
#endif
|
|
|
|
while ((ptaf != NULL) && ulStackDepth--)
|
|
{
|
|
FRAME_INFO FrameInfo;
|
|
::FusionpPopulateFrameInfo(FrameInfo, ptaf);
|
|
|
|
switch (dwFlags & FUSIONP_DUMP_STACK_FORMAT_MASK)
|
|
{
|
|
case FUSIONP_DUMP_STACK_FORMAT_SHORT:
|
|
::FusionpDbgPrintEx(
|
|
ulLevel,
|
|
"%ls: %s\n",
|
|
pcwszLinePrefix,
|
|
FrameInfo.pszFunction);
|
|
break;
|
|
|
|
case FUSIONP_DUMP_STACK_FORMAT_MEDIUM:
|
|
::FusionpDbgPrintEx(
|
|
ulLevel,
|
|
"%ls%s: %s (Line %d)\n",
|
|
pcwszLinePrefix,
|
|
FrameInfo.pszFile,
|
|
FrameInfo.pszFunction,
|
|
FrameInfo.nLine);
|
|
break;
|
|
|
|
case FUSIONP_DUMP_STACK_FORMAT_LONG:
|
|
::FusionpDbgPrintEx(
|
|
ulLevel,
|
|
"%lsFunction %s called from file %s line %d (depth %lu)\n",
|
|
pcwszLinePrefix,
|
|
FrameInfo.pszFunction,
|
|
FrameInfo.pszFile,
|
|
FrameInfo.nLine,
|
|
ulCurrentFrameDepth++);
|
|
break;
|
|
}
|
|
|
|
ptaf = ptaf->Previous;
|
|
}
|
|
}
|
|
|
|
#if FUSION_ENABLE_FROZEN_STACK
|
|
|
|
BOOL
|
|
FusionpOutputFrozenStack(
|
|
DWORD dwFlags,
|
|
PCSTR Prefix,
|
|
PFROZEN_STACK pFrozenStack
|
|
)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if ( !pFrozenStack ) {
|
|
::SetLastError( ERROR_INVALID_PARAMETER );
|
|
goto Exit;
|
|
}
|
|
|
|
if ( !Prefix ) Prefix = "SXS";
|
|
|
|
for ( ULONG ul = 0; ul < pFrozenStack->ulDepth; ul++ )
|
|
{
|
|
FusionpDbgPrintEx(
|
|
dwFlags,
|
|
"%s: %s [%s(%d)]\n",
|
|
Prefix,
|
|
pFrozenStack->Contexts[ul].m_StaticTraceContext->m_Function,
|
|
pFrozenStack->Contexts[ul].m_StaticTraceContext->m_File,
|
|
pFrozenStack->Contexts[ul].m_nLine);
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
Exit:
|
|
return bSuccess;
|
|
}
|
|
|
|
#endif // FUSION_ENABLE_FROZEN_STACK
|
|
|
|
#ifdef _SXS_FUTURE_STACK_FREEZING_WORK
|
|
|
|
typedef struct _SUPER_FROZEN_STACK
|
|
{
|
|
SIZE_T cStackFrames;
|
|
SIZE_T cMaxStackFrames;
|
|
STACKFRAME StackFrames[1];
|
|
}
|
|
SUPER_FROZEN_STACK, *PSUPER_FROZEN_STACK;
|
|
|
|
BOOL
|
|
pResolveLineFromAddress(
|
|
PIMAGEHLP_LINE Line,
|
|
DWORD_PTR Address,
|
|
DWORD *pOffset
|
|
)
|
|
{
|
|
HPROCESS Proc = GetCurrentProcess();
|
|
DWORD Offset = 0;
|
|
|
|
while ( !SymGetLineFromAddr( Proc, Address - Offset, pOffset, Line ) )
|
|
{
|
|
if ( Offset++ == MAX_BACKTRACK )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
FusionpPrintSuperFrozenStack(
|
|
PSUPER_FROZEN_STACK pStack
|
|
)
|
|
{
|
|
IMAGEHLP_LINE Line;
|
|
|
|
for ( SIZE_T cb = 0; cb < pStack->cStackFrames; cb++ )
|
|
{
|
|
IMAGEHLP_LINE Line;
|
|
IMAGEHLP_SYMBOL Symbol;
|
|
|
|
Line.SizeOfStuct = sizeof( Line );
|
|
Symbol.SizeOfStruct = sizeof( Symbol );
|
|
|
|
if ( pResolveLineFromAddress(
|
|
&Line,
|
|
pStack->StackFrames[cb].AddrPC.Offset
|
|
&dwOffset
|
|
) )
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
FusionpSuperFreezeStack(
|
|
DWORD dwFlags,
|
|
PSUPER_FROZEN_STACK pStack
|
|
)
|
|
{
|
|
STACKFRAME CurrentStack;
|
|
CONTEXT Context;
|
|
BOOL bOk = FALSE;
|
|
const HANDLE hThisThread = ::GetCurrentThread();
|
|
ULONG ulStackSize = 0;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if ( !pStack || dwFlags )
|
|
{
|
|
::SetLastError( ERROR_INVALID_PARAMETER );
|
|
goto Exit;
|
|
}
|
|
|
|
ZeroMemory( &CurrentStack, sizeof(CurrentStack) );
|
|
ZeroMemory( &Context, sizeof(Context) );
|
|
|
|
Context.ContextFlags = CONTEXT_FULL;
|
|
GetThreadContext( hThisThread, &Context );
|
|
|
|
CurrentStack.AddrPC.Offset = Context.Eip;
|
|
CurrentStack.AddrPC.Mode = AddrModeFlat;
|
|
CurrentStack.AddrStack.Offset = Context.Esp;
|
|
CurrentStack.AddrStack.Mode = AddrModeFlat;
|
|
CurrentStack.AddrFrame.Offset = Context.Ebp;
|
|
CurrentStack.AddrFrame.Mode = AddrModeFlat;
|
|
|
|
pStack->cStackFrames = 0;
|
|
|
|
for ( ulStackSize = 0; ; ulStackSize++ )
|
|
{
|
|
bOk = ::StackWalk(
|
|
IMAGE_FILE_MACHINE_I386,
|
|
GetCurrentProcess(),
|
|
hThisThread,
|
|
&CurrentStack,
|
|
&Context,
|
|
NULL,
|
|
SymFunctionTableAccess,
|
|
SymGetModuleBase,
|
|
NULL);
|
|
|
|
if ( CurrentStack.AddrPC.Offset == 0 )
|
|
{
|
|
break;
|
|
}
|
|
//
|
|
// Skip the first
|
|
//
|
|
else if ( ulStackSize == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
//
|
|
// If we have space in the stack...
|
|
//
|
|
else if ( pStack->cStackFrames < pStack->cMaxStackFrames )
|
|
{
|
|
pStack->StackFrames[pStack->cStackFrames++] = CurrentStack;
|
|
}
|
|
}
|
|
|
|
if ( pStack->cMaxStackFrames < ulStackSize )
|
|
{
|
|
pStack->cMaxStackFrames = ulStackSize;
|
|
pStack->cStackFrames = 0;
|
|
|
|
::SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|
goto Exit;
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
Exit:
|
|
return bSuccess;
|
|
|
|
}
|
|
#endif _SXS_FUTURE_STACK_FREEZING_WORK
|
|
|