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.
2366 lines
58 KiB
2366 lines
58 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
inetdbg.cxx
|
|
|
|
Abstract:
|
|
|
|
Debugging functions for internet DLL
|
|
|
|
Author:
|
|
|
|
Venkatraman Kudallur (venkatk)
|
|
( Ripped off from wininet )
|
|
|
|
Revision History:
|
|
|
|
3-10-2000 venkatk
|
|
Created
|
|
--*/
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
/* Exchanging the order of these 2 gives following error:
|
|
Linking Executable - dll\daytona\objd\i386\urlmon.dll for i386
|
|
dll\daytona\utils.lib(inetdbg.obj) : error LNK2001: unresolved external
|
|
symbol "
|
|
int __cdecl _sprintf(char *,char *,char *)" (?_sprintf@@YAHPAD00@Z)
|
|
dll\daytona\objd\i386\urlmon.dll() : error LNK1120: 1 unresolved externals
|
|
dll\daytona\binplace() : error BNP0000: Unable to place file objd\i386\urlmon.
|
|
dll - exiting.
|
|
*/
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!! Why?
|
|
|
|
#include <urlint.h>
|
|
#include "rprintf.h"
|
|
#include "registry.h"
|
|
#include "tls.h"
|
|
#include <imagehlp.h>
|
|
#include <wininet.h> //only for InternetVersionInfo!
|
|
#include <ieverp.h> //for version strings
|
|
|
|
#ifdef ENABLE_DEBUG
|
|
|
|
//from macros.h
|
|
#define PRIVATE
|
|
#define PUBLIC
|
|
|
|
//from util.cxx
|
|
|
|
DWORD
|
|
GetTickCountWrap()
|
|
{
|
|
#ifdef DEBUG_GETTICKCOUNT
|
|
static BOOL fInit = FALSE;
|
|
static DWORD dwDelta = 0;
|
|
static DWORD dwBasis = 0;
|
|
|
|
if (!fInit)
|
|
{
|
|
HKEY clientKey;
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
|
|
0, // reserved
|
|
KEY_QUERY_VALUE,
|
|
&clientKey))
|
|
{
|
|
DWORD dwSize = sizeof(dwDelta);
|
|
RegQueryValueEx(clientKey, "RollOverDelta", NULL, NULL, (LPBYTE)&dwDelta, &dwSize);
|
|
}
|
|
dwBasis = GetTickCount();
|
|
fInit = TRUE;
|
|
}
|
|
DWORD dwResult = GetTickCount() - dwBasis + dwDelta;
|
|
return dwResult;
|
|
#else
|
|
return GetTickCount();
|
|
#endif
|
|
}
|
|
|
|
|
|
//forward declaration
|
|
BOOL
|
|
InternetDebugGetLocalTime(
|
|
OUT SYSTEMTIME * pstLocalTime,
|
|
OUT DWORD * pdwMicroSec
|
|
);
|
|
|
|
//from debugmem.h
|
|
#if defined(USE_DEBUG_MEMORY)
|
|
//no debugmem capabilities yet.
|
|
#define ALLOCATOR(Flags, Size) \
|
|
LocalAlloc(Flags, Size)
|
|
#define DEALLOCATOR(hLocal) \
|
|
LocalFree(hLocal)
|
|
#else //Retail
|
|
#if USE_PRIVATE_HEAP_IN_RETAIL
|
|
#error no other memory allocation schemes defined
|
|
#else
|
|
#ifndef WININET_UNIX_PRVATE_ALLOCATOR
|
|
#define ALLOCATOR(Flags, Size) \
|
|
LocalAlloc(Flags, Size)
|
|
#define DEALLOCATOR(hLocal) \
|
|
LocalFree(hLocal)
|
|
#else
|
|
HLOCAL IEUnixLocalAlloc(UINT wFlags, UINT wBytes);
|
|
HLOCAL IEUnixLocalFree(HLOCAL hMem);
|
|
|
|
#define ALLOCATOR(Flags, Size)\
|
|
IEUnixLocalAlloc(Flags, Size)
|
|
#define DEALLOCATOR(hLocal)\
|
|
IEUnixLocalFree(hLocal)
|
|
#endif //WININET_UNIX_PRVATE_ALLOCATOR
|
|
#endif //USE_PRIVATE_HEAP_IN_RETAIL
|
|
#endif //defined(USE_DEBUG_MEMORY)
|
|
|
|
//from debugmem.h
|
|
#define ALLOCATE_ZERO_MEMORY(Size) \
|
|
ALLOCATE_MEMORY(LPTR, (Size))
|
|
#define ALLOCATE_MEMORY(Flags, Size) \
|
|
ALLOCATOR((UINT)(Flags), (UINT)(Size))
|
|
#define FREE_MEMORY(hLocal) \
|
|
DEALLOCATOR((HLOCAL)(hLocal))
|
|
|
|
//from macros.h
|
|
#define NEW(object) \
|
|
(object FAR *)ALLOCATE_ZERO_MEMORY(sizeof(object))
|
|
#define DEL(object) \
|
|
FREE_MEMORY(object)
|
|
|
|
//from Nttypes.h
|
|
#define ARGUMENT_PRESENT(ArgumentPointer) (\
|
|
(CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
|
|
|
|
#define INTERNET_SETTINGS_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
|
|
|
|
//from globals.cxx
|
|
#if !defined(VER_PRODUCTBUILD)
|
|
#define VER_PRODUCTBUILD 0
|
|
#endif
|
|
|
|
PRIVATE DWORD InternetBuildNumber = VER_PRODUCTBUILD;
|
|
|
|
#if !defined(VER_PRODUCTVERSION_STRING)
|
|
#define VER_PRODUCTVERSION_STRING " "
|
|
#endif
|
|
|
|
#if !defined(URLMON_MAJOR_VERSION)
|
|
#define URLMON_MAJOR_VERSION 1
|
|
#endif
|
|
|
|
#if !defined(URLMON_MINOR_VERSION)
|
|
#define URLMON_MINOR_VERSION 2
|
|
#endif
|
|
|
|
PRIVATE INTERNET_VERSION_INFO InternetVersionInfo = {
|
|
URLMON_MAJOR_VERSION,
|
|
URLMON_MINOR_VERSION
|
|
};
|
|
|
|
#if 0
|
|
#endif //0
|
|
|
|
//
|
|
// private manifests
|
|
//
|
|
#define SWITCH_VARIABLE_NAME "UrlmonDebugging"
|
|
#define CONTROL_VARIABLE_NAME "UrlmonControl"
|
|
#define CATEGORY_VARIABLE_NAME "UrlmonCategory"
|
|
#define ERROR_VARIABLE_NAME "UrlmonError"
|
|
#define BREAK_VARIABLE_NAME "UrlmonBreak"
|
|
#define DEFAULT_LOG_VARIABLE_NAME "UrlmonLog"
|
|
#define CHECK_LIST_VARIABLE_NAME "UrlmonCheckSerializedList"
|
|
#define LOG_FILE_VARIABLE_NAME "UrlmonLogFile"
|
|
#define INDENT_VARIABLE_NAME "UrlmonLogIndent"
|
|
#define NO_PID_IN_LOG_FILENAME "UrlmonNoPidInLogFilename"
|
|
#define NO_EXCEPTION_HANDLER "UrlmonNoExceptionHandler"
|
|
|
|
#define DEFAULT_LOG_FILE_NAME "URLMON.LOG"
|
|
|
|
#define ENVIRONMENT_VARIABLE_BUFFER_LENGTH 80
|
|
|
|
#define PRINTF_STACK_BUFFER_LENGTH 4096
|
|
|
|
//
|
|
// private macros
|
|
//
|
|
|
|
#define CASE_OF(constant) case constant: return # constant
|
|
|
|
//
|
|
// private prototypes
|
|
//
|
|
|
|
PRIVATE
|
|
VOID
|
|
InternetDebugPrintString(
|
|
IN LPSTR String
|
|
);
|
|
|
|
PRIVATE
|
|
VOID
|
|
InternetGetDebugVariableString(
|
|
IN LPSTR lpszVariableName,
|
|
OUT LPSTR lpszVariable,
|
|
IN DWORD dwVariableLen
|
|
);
|
|
|
|
PRIVATE
|
|
LPSTR
|
|
ExtractFileName(
|
|
IN LPSTR Module,
|
|
OUT LPSTR Buf
|
|
);
|
|
|
|
PRIVATE
|
|
LPSTR
|
|
SetDebugPrefix(
|
|
IN LPSTR Buffer
|
|
);
|
|
|
|
//
|
|
//
|
|
// these variables are employed in macros, so must be public
|
|
//
|
|
|
|
PUBLIC DWORD InternetDebugErrorLevel = DBG_ERROR;
|
|
PUBLIC DWORD InternetDebugControlFlags = DBG_NO_DEBUG;
|
|
PUBLIC DWORD InternetDebugCategoryFlags = 0;
|
|
PUBLIC DWORD InternetDebugBreakFlags = 0;
|
|
|
|
//
|
|
// these variables are only accessed in this module, so can be private
|
|
//
|
|
|
|
PRIVATE int InternetDebugIndentIncrement = 2;
|
|
PRIVATE HANDLE InternetDebugFileHandle = INVALID_HANDLE_VALUE;
|
|
PRIVATE char InternetDebugFilename[MAX_PATH + 1] = DEFAULT_LOG_FILE_NAME;
|
|
PRIVATE BOOL InternetDebugEnabled = TRUE;
|
|
PRIVATE DWORD InternetDebugStartTime = 0;
|
|
|
|
extern "C" {
|
|
#if defined(UNIX) && defined(ux10)
|
|
/* Temporary fix for Apogee Compiler bug on HP only */
|
|
extern BOOL fCheckEntryOnList;
|
|
#else
|
|
BOOL fCheckEntryOnList;
|
|
#endif /* UNIX */
|
|
}
|
|
|
|
//
|
|
// high frequency performance counter globals
|
|
//
|
|
|
|
PRIVATE LONGLONG ftInit; // initial local time
|
|
PRIVATE LONGLONG pcInit; // initial perf counter
|
|
PRIVATE LONGLONG pcFreq; // perf counter frequency
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
|
|
VOID
|
|
InternetDebugInitialize(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
reads environment INETDBG flags and opens debug log file if required
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// ensure registry key open
|
|
//
|
|
|
|
OpenInternetSettingsKey();
|
|
|
|
//
|
|
// record the starting tick count for cumulative deltas
|
|
//
|
|
|
|
InternetDebugStartTime = GetTickCountWrap();
|
|
|
|
if (QueryPerformanceFrequency ((LARGE_INTEGER *) &pcFreq) && pcFreq) {
|
|
|
|
QueryPerformanceCounter ((LARGE_INTEGER *) &pcInit);
|
|
SYSTEMTIME st;
|
|
GetLocalTime (&st);
|
|
SystemTimeToFileTime (&st, (FILETIME *) &ftInit);
|
|
}
|
|
|
|
// check see if there are any debug variable overrides in the environment
|
|
// or the registry. If "UrlmonLog=<!0>" is set then we use the flags that
|
|
// are most commonly used to generate URLMON.LOG, with no console or
|
|
// debugger output. We allow the other variables to be overridden
|
|
//
|
|
|
|
BOOL defaultDebugVariables = FALSE;
|
|
|
|
InternetGetDebugVariable(DEFAULT_LOG_VARIABLE_NAME, (LPDWORD)&defaultDebugVariables);
|
|
if (defaultDebugVariables) {
|
|
InternetDebugEnabled = TRUE;
|
|
InternetDebugControlFlags = INTERNET_DEBUG_CONTROL_DEFAULT;
|
|
InternetDebugCategoryFlags = INTERNET_DEBUG_CATEGORY_DEFAULT;
|
|
InternetDebugErrorLevel = INTERNET_DEBUG_ERROR_LEVEL_DEFAULT;
|
|
InternetDebugBreakFlags = 0;
|
|
}
|
|
InternetGetDebugVariable(SWITCH_VARIABLE_NAME, (LPDWORD)&InternetDebugEnabled);
|
|
InternetGetDebugVariable(CONTROL_VARIABLE_NAME, &InternetDebugControlFlags);
|
|
InternetGetDebugVariable(CATEGORY_VARIABLE_NAME, &InternetDebugCategoryFlags);
|
|
InternetGetDebugVariable(ERROR_VARIABLE_NAME, &InternetDebugErrorLevel);
|
|
InternetGetDebugVariable(BREAK_VARIABLE_NAME, &InternetDebugBreakFlags);
|
|
InternetGetDebugVariable(CHECK_LIST_VARIABLE_NAME, (LPDWORD)&fCheckEntryOnList);
|
|
InternetGetDebugVariable(INDENT_VARIABLE_NAME, (LPDWORD)&InternetDebugIndentIncrement);
|
|
InternetGetDebugVariableString(LOG_FILE_VARIABLE_NAME,
|
|
InternetDebugFilename,
|
|
sizeof(InternetDebugFilename)
|
|
);
|
|
|
|
DWORD InternetNoPidInLogFilename=0;
|
|
InternetGetDebugVariable(NO_PID_IN_LOG_FILENAME, &InternetNoPidInLogFilename);
|
|
|
|
if (!InternetNoPidInLogFilename)
|
|
{
|
|
char szFullPathName[MAX_PATH + 1];
|
|
LPSTR szExecutableName;
|
|
|
|
if (GetModuleFileName(NULL, szFullPathName, sizeof(szFullPathName)))
|
|
{
|
|
szExecutableName = strrchr(szFullPathName, '\\');
|
|
if (szExecutableName != NULL)
|
|
++szExecutableName;
|
|
else
|
|
szExecutableName = szFullPathName;
|
|
}
|
|
else
|
|
szExecutableName = "";
|
|
|
|
DWORD cbFilenameLen = strlen(InternetDebugFilename);
|
|
// ".xxxxx.yyy.#########.LOG"
|
|
DWORD cbProcessInfoLenMax = 1 + strlen(szExecutableName) + 1 + 9 + 1 + 3;
|
|
|
|
if (cbProcessInfoLenMax < sizeof(InternetDebugFilename))
|
|
wsprintf(InternetDebugFilename+cbFilenameLen, ".%s.%u.LOG",
|
|
szExecutableName,
|
|
GetCurrentProcessId());
|
|
};
|
|
|
|
if ((InternetDebugIndentIncrement < 0) || (InternetDebugIndentIncrement > 32)) {
|
|
InternetDebugIndentIncrement = 2;
|
|
}
|
|
|
|
//
|
|
// quit now if debugging is disabled
|
|
//
|
|
|
|
if (!InternetDebugEnabled) {
|
|
InternetDebugControlFlags |= (DBG_NO_DEBUG | DBG_NO_DATA_DUMP);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if we want to write debug output to file, open URLMON.LOG in the current
|
|
// directory. Open it in text mode, for write-only (by this process)
|
|
//
|
|
|
|
if (InternetDebugControlFlags & DBG_TO_FILE) {
|
|
if (!InternetReopenDebugFile(InternetDebugFilename)) {
|
|
InternetDebugControlFlags &= ~DBG_TO_FILE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugTerminate(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs any required debug termination
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//moved into this function bcos we don't this only for debugging.
|
|
CloseInternetSettingsKey();
|
|
|
|
if (InternetDebugControlFlags & DBG_TO_FILE) {
|
|
InternetCloseDebugFile();
|
|
}
|
|
InternetDebugControlFlags = DBG_NO_DEBUG;
|
|
}
|
|
|
|
BOOL
|
|
InternetOpenDebugFile(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens debug filename if not already open. Use InternetDebugFilename
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - file was opened
|
|
|
|
FALSE - file not opened (already open or error)
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugFileHandle == INVALID_HANDLE_VALUE) {
|
|
InternetDebugFileHandle = CreateFile(
|
|
InternetDebugFilename,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL, // lpSecurityAttributes
|
|
(InternetDebugControlFlags & DBG_APPEND_FILE)
|
|
? OPEN_ALWAYS
|
|
: CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL
|
|
| FILE_FLAG_SEQUENTIAL_SCAN
|
|
| ((InternetDebugControlFlags & DBG_FLUSH_OUTPUT)
|
|
? FILE_FLAG_WRITE_THROUGH
|
|
: 0),
|
|
NULL
|
|
);
|
|
return InternetDebugFileHandle != INVALID_HANDLE_VALUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
InternetReopenDebugFile(
|
|
IN LPSTR Filename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Re)opens a debug log file. Closes the current one if it is open
|
|
|
|
Arguments:
|
|
|
|
Filename - new file to open
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
|
|
InternetCloseDebugFile();
|
|
}
|
|
if (Filename && *Filename) {
|
|
InternetDebugFileHandle = CreateFile(
|
|
Filename,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL, // lpSecurityAttributes
|
|
(InternetDebugControlFlags & DBG_APPEND_FILE)
|
|
? OPEN_ALWAYS
|
|
: CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL
|
|
| FILE_FLAG_SEQUENTIAL_SCAN
|
|
| ((InternetDebugControlFlags & DBG_FLUSH_OUTPUT)
|
|
? FILE_FLAG_WRITE_THROUGH
|
|
: 0),
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// put our start info in the log file. Mainly useful when we're
|
|
// appending to the file
|
|
//
|
|
|
|
if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
|
|
|
|
SYSTEMTIME currentTime;
|
|
char filespec[MAX_PATH + 1];
|
|
LPSTR filename;
|
|
|
|
if (GetModuleFileName(NULL, filespec, sizeof(filespec))) {
|
|
filename = strrchr(filespec, '\\');
|
|
if (filename != NULL) {
|
|
++filename;
|
|
} else {
|
|
filename = filespec;
|
|
}
|
|
} else {
|
|
filename = "";
|
|
}
|
|
|
|
InternetDebugGetLocalTime(¤tTime, NULL);
|
|
|
|
InternetDebugPrintf("\n"
|
|
">>>> Urlmon Version %d.%d Build %s.%d " __DATE__ " " __TIME__ "\n"
|
|
">>>> Process %s [%d (%#x)] started at %02d:%02d:%02d.%03d %02d/%02d/%d\n",
|
|
InternetVersionInfo.dwMajorVersion,
|
|
InternetVersionInfo.dwMinorVersion,
|
|
VER_PRODUCTVERSION_STRING,
|
|
InternetBuildNumber,
|
|
filename,
|
|
GetCurrentProcessId(),
|
|
GetCurrentProcessId(),
|
|
currentTime.wHour,
|
|
currentTime.wMinute,
|
|
currentTime.wSecond,
|
|
currentTime.wMilliseconds,
|
|
currentTime.wMonth,
|
|
currentTime.wDay,
|
|
currentTime.wYear
|
|
);
|
|
|
|
InternetDebugPrintf(">>>> Command line = %q\n", GetCommandLine());
|
|
|
|
InternetDebugPrintf("\n"
|
|
" InternetDebugErrorLevel = %s [%d]\n"
|
|
" InternetDebugControlFlags = %#08x\n"
|
|
" InternetDebugCategoryFlags = %#08x\n"
|
|
" InternetDebugBreakFlags = %#08x\n"
|
|
" InternetDebugIndentIncrement = %d\n"
|
|
"\n",
|
|
(InternetDebugErrorLevel == DBG_INFO) ? "Info"
|
|
: (InternetDebugErrorLevel == DBG_WARNING) ? "Warning"
|
|
: (InternetDebugErrorLevel == DBG_ERROR) ? "Error"
|
|
: (InternetDebugErrorLevel == DBG_FATAL) ? "Fatal"
|
|
: (InternetDebugErrorLevel == DBG_ALWAYS) ? "Always"
|
|
: "?",
|
|
InternetDebugErrorLevel,
|
|
InternetDebugControlFlags,
|
|
InternetDebugCategoryFlags,
|
|
InternetDebugBreakFlags,
|
|
InternetDebugIndentIncrement
|
|
);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetCloseDebugFile(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes the current debug log file
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
|
|
if (InternetDebugControlFlags & DBG_FLUSH_OUTPUT) {
|
|
InternetFlushDebugFile();
|
|
}
|
|
CloseHandle(InternetDebugFileHandle);
|
|
InternetDebugFileHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetFlushDebugFile(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
description-of-function.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugFileHandle != INVALID_HANDLE_VALUE) {
|
|
FlushFileBuffers(InternetDebugFileHandle);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugSetControlFlags(
|
|
IN DWORD dwFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets debug control flags
|
|
|
|
Arguments:
|
|
|
|
dwFlags - flags to set
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
InternetDebugControlFlags |= dwFlags;
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugResetControlFlags(
|
|
IN DWORD dwFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets debug control flags
|
|
|
|
Arguments:
|
|
|
|
dwFlags - flags to reset
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
InternetDebugControlFlags &= ~dwFlags;
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugEnter(
|
|
IN DWORD Category,
|
|
IN DEBUG_FUNCTION_RETURN_TYPE ReturnType,
|
|
IN LPCSTR Function,
|
|
IN LPCSTR ParameterList OPTIONAL,
|
|
IN ...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates an INTERNET_DEBUG_RECORD for the current function and adds it to
|
|
the per-thread (debug) call-tree
|
|
|
|
Arguments:
|
|
|
|
Category - category flags, e.g. DBG_FTP
|
|
|
|
ReturnType - type of data it returns
|
|
|
|
Function - name of the function. Must be global, static string
|
|
|
|
ParameterList - string describing parameters to function, or NULL if none
|
|
|
|
... - parameters to function
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CUrlMkTls tls(hr); // hr passed by reference!
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction;
|
|
pCurrentFunction = NEW(DEBUG_URLMON_FUNC_RECORD);
|
|
|
|
pCurrentFunction->Stack = tls->Stack;
|
|
pCurrentFunction->Category = Category;
|
|
pCurrentFunction->ReturnType = ReturnType;
|
|
pCurrentFunction->Function = Function;
|
|
pCurrentFunction->LastTime = GetTickCountWrap();
|
|
tls->Stack = pCurrentFunction;
|
|
++tls->CallDepth;
|
|
|
|
//
|
|
// if the function's category (FTP, GOPHER, HTTP) is selected in the
|
|
// category flags, then we dump the function entry information
|
|
//
|
|
|
|
if (InternetDebugCategoryFlags & Category) {
|
|
|
|
char buf[4096];
|
|
LPSTR bufptr;
|
|
|
|
bufptr = buf;
|
|
bufptr += rsprintf(bufptr, "%s(", Function);
|
|
__try
|
|
{
|
|
if (ARGUMENT_PRESENT(ParameterList)) {
|
|
|
|
va_list parms;
|
|
|
|
va_start(parms, ParameterList);
|
|
bufptr += _sprintf(bufptr, (char*)ParameterList, parms);
|
|
va_end(parms);
|
|
}
|
|
rsprintf(bufptr, ")\n");
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
if (((DWORD(bufptr-buf) < (sizeof("*********Exception occured!!\n")+1)))
|
|
&& (bufptr>buf))
|
|
wsprintf(bufptr, "*********Exception occured!!\n");
|
|
else
|
|
wsprintf(buf, "*********Exception occured!!\n");
|
|
}
|
|
InternetDebugPrintString(buf);
|
|
|
|
//
|
|
// only increase the indentation if we will display debug information
|
|
// for this category
|
|
//
|
|
|
|
tls->IndentIncrement += InternetDebugIndentIncrement;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugLeave(
|
|
IN DWORD_PTR Variable,
|
|
IN LPCSTR Filename,
|
|
IN DWORD LineNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroys the INTERNET_DEBUG_RECORD for the current function and dumps info
|
|
about what the function is returning, if requested to do so
|
|
|
|
Arguments:
|
|
|
|
Variable - variable containing value being returned by function
|
|
|
|
Filename - name of file where DEBUG_LEAVE() invoked
|
|
|
|
LineNumber - and line number in Filename
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSTR format;
|
|
LPSTR errstr;
|
|
BOOL noVar;
|
|
char formatBuf[128];
|
|
DWORD lastError;
|
|
char hexnumBuf[15];
|
|
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// seems that something in this path can nuke the last error, so we must
|
|
// refresh it
|
|
//
|
|
|
|
lastError = GetLastError();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CUrlMkTls tls(hr); // hr passed by reference!
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction = tls->Stack;
|
|
|
|
if (!pCurrentFunction) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// we are about to output a diagnostic message to the debug log, debugger,
|
|
// or console. First check that we are required to display messages at
|
|
// this level. The level for function ENTER and LEAVE is INFO
|
|
//
|
|
|
|
{
|
|
|
|
//
|
|
// only display the string and reduce the indent if we are requested
|
|
// for information about this category
|
|
//
|
|
|
|
errstr = NULL;
|
|
noVar = FALSE;
|
|
if (InternetDebugCategoryFlags & pCurrentFunction->Category) {
|
|
switch (pCurrentFunction->ReturnType) {
|
|
case None:
|
|
format = "%s() returning VOID";
|
|
noVar = TRUE;
|
|
break;
|
|
|
|
case Bool:
|
|
Variable = (DWORD_PTR)(Variable ? "TRUE" : "FALSE");
|
|
|
|
//
|
|
// *** FALL THROUGH ***
|
|
//
|
|
|
|
case String:
|
|
format = "%s() returning %s";
|
|
break;
|
|
|
|
case Int:
|
|
format = "%s() returning %d";
|
|
break;
|
|
|
|
case Dword:
|
|
format = "%s() returning %u";
|
|
break;
|
|
|
|
case Hresult:
|
|
format = "%s() returning %u";
|
|
errstr = InternetMapError((DWORD)Variable);
|
|
if (errstr != NULL) {
|
|
if (*errstr == '?') {
|
|
rsprintf(hexnumBuf, "%#x", Variable);
|
|
errstr = hexnumBuf;
|
|
format = "%s() returning %u [?] (%s)";
|
|
} else {
|
|
format = "%s() returning %u [%s]";
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Handle:
|
|
case Pointer:
|
|
if (Variable == 0) {
|
|
format = "%s() returning NULL";
|
|
noVar = TRUE;
|
|
} else {
|
|
if (pCurrentFunction->ReturnType == Handle) {
|
|
format = "%s() returning handle %#x";
|
|
} else {
|
|
format = "%s() returning %#x";
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
INET_ASSERT(FALSE);
|
|
|
|
break;
|
|
}
|
|
|
|
tls->IndentIncrement -= InternetDebugIndentIncrement;
|
|
if (tls->IndentIncrement < 0) {
|
|
tls->IndentIncrement = 0;
|
|
}
|
|
|
|
//
|
|
// add line number info, if requested
|
|
//
|
|
|
|
strcpy(formatBuf, format);
|
|
if (!(InternetDebugControlFlags & DBG_NO_LINE_NUMBER)) {
|
|
strcat(formatBuf, " (line %d)");
|
|
}
|
|
strcat(formatBuf, "\n");
|
|
|
|
//
|
|
// output an empty line if we are required to separate API calls in
|
|
// the log. Only do this if this is an API level function, and it
|
|
// is the top-level function
|
|
//
|
|
|
|
if ((InternetDebugControlFlags & DBG_SEPARATE_APIS)
|
|
&& (pCurrentFunction->Stack == NULL)) {
|
|
strcat(formatBuf, "\n");
|
|
}
|
|
|
|
//
|
|
// dump the line, depending on requirements and number of arguments
|
|
//
|
|
|
|
if (noVar) {
|
|
InternetDebugPrint(formatBuf,
|
|
pCurrentFunction->Function,
|
|
LineNumber
|
|
);
|
|
} else if (errstr != NULL) {
|
|
InternetDebugPrint(formatBuf,
|
|
pCurrentFunction->Function,
|
|
Variable,
|
|
errstr,
|
|
LineNumber
|
|
);
|
|
} else {
|
|
InternetDebugPrint(formatBuf,
|
|
pCurrentFunction->Function,
|
|
Variable,
|
|
LineNumber
|
|
);
|
|
}
|
|
/*
|
|
//
|
|
// output an empty line if we are required to separate API calls in
|
|
// the log. Only do this if this is an API level function, and it
|
|
// is the top-level function
|
|
//
|
|
|
|
if ((InternetDebugControlFlags & DBG_SEPARATE_APIS)
|
|
&& (pCurrentFunction->Stack == NULL)) {
|
|
|
|
//
|
|
// don't call InternetDebugPrint - we don't need timing, thread,
|
|
// level etc. information just for the separator
|
|
//
|
|
|
|
InternetDebugOut("\n", FALSE);
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
//
|
|
// regardless of whether we are outputting debug info for this category,
|
|
// remove the debug record and reduce the call-depth
|
|
//
|
|
|
|
--tls->CallDepth;
|
|
tls->Stack = pCurrentFunction->Stack;
|
|
|
|
DEL(pCurrentFunction);
|
|
|
|
//
|
|
// refresh the last error, in case it was nuked
|
|
//
|
|
|
|
SetLastError(lastError);
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugError(
|
|
IN DWORD Error
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used to display that a function is returning an error. We try to display a
|
|
symbolic name for the error too (as when we are returning a DWORD from a
|
|
function, using DEBUG_LEAVE)
|
|
|
|
Displays a string of the form:
|
|
|
|
Foo() returning error 87 [ERROR_INVALID_PARAMETER]
|
|
|
|
Arguments:
|
|
|
|
Error - the error code
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSTR errstr;
|
|
DWORD lastError;
|
|
char hexnumBuf[15];
|
|
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// seems that something in this path can nuke the last error, so we must
|
|
// refresh it
|
|
//
|
|
|
|
lastError = GetLastError();
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CUrlMkTls tls(hr); // hr passed by reference!
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction = tls->Stack;
|
|
|
|
if (pCurrentFunction == NULL) {
|
|
return;
|
|
}
|
|
|
|
errstr = InternetMapError(Error);
|
|
if ((errstr == NULL) || (*errstr == '?')) {
|
|
rsprintf(hexnumBuf, "%#x", Error);
|
|
errstr = hexnumBuf;
|
|
}
|
|
InternetDebugPrint("%s() returning %d [%s]\n",
|
|
pCurrentFunction->Function,
|
|
Error,
|
|
errstr
|
|
);
|
|
|
|
//
|
|
// refresh the last error, in case it was nuked
|
|
//
|
|
|
|
SetLastError(lastError);
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugPrint(
|
|
IN LPSTR Format,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internet equivalent of printf()
|
|
|
|
Arguments:
|
|
|
|
Format - printf format string
|
|
|
|
... - any extra args
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
char buf[PRINTF_STACK_BUFFER_LENGTH];
|
|
LPSTR bufptr;
|
|
|
|
bufptr = SetDebugPrefix(buf);
|
|
if (bufptr == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// now append the string that the DEBUG_PRINT originally gave us
|
|
//
|
|
|
|
va_list list;
|
|
|
|
va_start(list, Format);
|
|
_sprintf(bufptr, Format, list);
|
|
va_end(list);
|
|
|
|
InternetDebugOut(buf, FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugPrintValist(
|
|
IN LPSTR Format,
|
|
va_list list
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internet equivalent of printf(), but takes valist as the args
|
|
|
|
Arguments:
|
|
|
|
Format - printf format string
|
|
|
|
list - stack frame of variable arguments
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
char buf[PRINTF_STACK_BUFFER_LENGTH];
|
|
LPSTR bufptr;
|
|
|
|
bufptr = SetDebugPrefix(buf);
|
|
if (bufptr == NULL) {
|
|
return;
|
|
}
|
|
|
|
_sprintf(bufptr, Format, list);
|
|
|
|
InternetDebugOut(buf, FALSE);
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
VOID
|
|
InternetDebugPrintString(
|
|
IN LPSTR String
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Same as InternetDebugPrint(), except we perform no expansion on the string
|
|
|
|
Arguments:
|
|
|
|
String - already formatted string (may contain %s)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
char buf[PRINTF_STACK_BUFFER_LENGTH];
|
|
LPSTR bufptr;
|
|
|
|
bufptr = SetDebugPrefix(buf);
|
|
if (bufptr == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// now append the string that the DEBUG_PRINT originally gave us
|
|
//
|
|
|
|
strcpy(bufptr, String);
|
|
|
|
InternetDebugOut(buf, FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugPrintf(
|
|
IN LPSTR Format,
|
|
IN ...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Same as InternetDebugPrint(), but we don't access the per-thread info
|
|
(because we may not have any)
|
|
|
|
Arguments:
|
|
|
|
Format - printf format string
|
|
|
|
... - any extra args
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (InternetDebugControlFlags & DBG_NO_DEBUG) {
|
|
return;
|
|
}
|
|
|
|
va_list list;
|
|
char buf[PRINTF_STACK_BUFFER_LENGTH];
|
|
|
|
va_start(list, Format);
|
|
_sprintf(buf, Format, list);
|
|
va_end(list);
|
|
|
|
InternetDebugOut(buf, FALSE);
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugOut(
|
|
IN LPSTR Buffer,
|
|
IN BOOL Assert
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes a string somewhere - to the debug log file, to the console, or via
|
|
the debugger, or any combination
|
|
|
|
Arguments:
|
|
|
|
Buffer - pointer to formatted buffer to write
|
|
|
|
Assert - TRUE if this function is being called from InternetAssert(), in
|
|
which case we *always* write to the debugger. Of course, there
|
|
may be no debugger attached, in which case no action is taken
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
int buflen;
|
|
DWORD written;
|
|
|
|
buflen = strlen(Buffer);
|
|
if ((InternetDebugControlFlags & DBG_TO_FILE)
|
|
&& (InternetDebugFileHandle != INVALID_HANDLE_VALUE)) {
|
|
WriteFile(InternetDebugFileHandle, Buffer, buflen, &written, NULL);
|
|
if (InternetDebugControlFlags & DBG_FLUSH_OUTPUT) {
|
|
InternetFlushDebugFile();
|
|
}
|
|
}
|
|
|
|
if (InternetDebugControlFlags & DBG_TO_CONSOLE) {
|
|
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
|
|
Buffer,
|
|
buflen,
|
|
&written,
|
|
0
|
|
);
|
|
}
|
|
|
|
if (Assert || (InternetDebugControlFlags & DBG_TO_DEBUGGER)) {
|
|
OutputDebugString(Buffer);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetDebugDump(
|
|
IN LPSTR Text,
|
|
IN LPBYTE Address,
|
|
IN DWORD Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps Size bytes at Address, in the time-honoured debug tradition
|
|
|
|
Arguments:
|
|
|
|
Text - to display before dumping data
|
|
|
|
Address - start of buffer
|
|
|
|
Size - number of bytes
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// if flags say no data dumps then quit
|
|
//
|
|
|
|
if (InternetDebugControlFlags & (DBG_NO_DEBUG | DBG_NO_DATA_DUMP)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// display the introduction text, if any
|
|
//
|
|
|
|
if (Text) {
|
|
if (InternetDebugControlFlags & DBG_INDENT_DUMP) {
|
|
InternetDebugPrint(Text);
|
|
} else {
|
|
InternetDebugOut(Text, FALSE);
|
|
}
|
|
}
|
|
|
|
char buf[128];
|
|
|
|
//
|
|
// display a line telling us how much data there is, if requested to
|
|
//
|
|
|
|
if (InternetDebugControlFlags & DBG_DUMP_LENGTH) {
|
|
rsprintf(buf, "%d (%#x) bytes @ %#x\n", Size, Size, Address);
|
|
if (InternetDebugControlFlags & DBG_INDENT_DUMP) {
|
|
InternetDebugPrintString(buf);
|
|
} else {
|
|
InternetDebugOut(buf, FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// dump out the data, debug style
|
|
//
|
|
|
|
while (Size) {
|
|
|
|
int len = InternetDebugDumpFormat(Address, Size, sizeof(BYTE), buf);
|
|
|
|
//
|
|
// if we are to indent the data to the current level, then display the
|
|
// buffer via InternetDebugPrint() which will apply all the thread id,
|
|
// indentation, and other options selected, else just display the data
|
|
// via InternetDebugOut(), which will simply send it to the output media
|
|
//
|
|
|
|
if (InternetDebugControlFlags & DBG_INDENT_DUMP) {
|
|
InternetDebugPrintString(buf);
|
|
} else {
|
|
InternetDebugOut(buf, FALSE);
|
|
}
|
|
|
|
Address += len;
|
|
Size -= len;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
InternetDebugDumpFormat(
|
|
IN LPBYTE Address,
|
|
IN DWORD Size,
|
|
IN DWORD ElementSize,
|
|
OUT LPSTR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Formats Size bytes at Address, in the time-honoured debug tradition, for
|
|
data dump purposes
|
|
|
|
Arguments:
|
|
|
|
Address - start of buffer
|
|
|
|
Size - number of bytes
|
|
|
|
ElementSize - size of each word element in bytes
|
|
|
|
Buffer - pointer to output buffer, assumed to be large enough
|
|
|
|
Return Value:
|
|
|
|
DWORD - number of bytes formatted
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// we (currently) only understand DWORD, WORD and BYTE dumps
|
|
//
|
|
|
|
if ((ElementSize != sizeof(DWORD)) && (ElementSize != sizeof(WORD))) {
|
|
ElementSize = sizeof(BYTE);
|
|
}
|
|
|
|
static char spaces[] = " "; // 15 * 3 + 2
|
|
int i, len;
|
|
|
|
len = min(Size, 16);
|
|
rsprintf(Buffer, "%08x ", Address);
|
|
|
|
//
|
|
// dump the hex representation of each character or word - up to 16 per line
|
|
//
|
|
|
|
DWORD offset = 10;
|
|
|
|
for (i = 0; i < len; i += ElementSize) {
|
|
|
|
DWORD value;
|
|
LPSTR formatString;
|
|
|
|
switch (ElementSize) {
|
|
case 4:
|
|
formatString = "%08x ";
|
|
value = *(LPDWORD)&Address[i];
|
|
break;
|
|
|
|
case 2:
|
|
formatString = "%04x ";
|
|
value = *(LPWORD)&Address[i] & 0xffff;
|
|
break;
|
|
|
|
default:
|
|
formatString = ((i & 15) == 7) ? "%02.2x-" : "%02.2x ";
|
|
value = Address[i] & 0xff;
|
|
break;
|
|
}
|
|
rsprintf(&Buffer[offset], formatString, value);
|
|
offset += ElementSize * 2 + 1;
|
|
}
|
|
|
|
//
|
|
// write as many spaces as required to tab to ASCII field
|
|
//
|
|
|
|
memcpy(&Buffer[offset], spaces, (16 - len) * 3 + 2);
|
|
offset += (16 - len) * 3 + 2;
|
|
|
|
//
|
|
// dump ASCII representation of each character
|
|
//
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
|
|
char ch;
|
|
|
|
ch = Address[i];
|
|
Buffer[offset + i] = ((ch < 32) || (ch > 127)) ? '.' : ch;
|
|
}
|
|
|
|
Buffer[offset + i++] = '\r';
|
|
Buffer[offset + i++] = '\n';
|
|
Buffer[offset + i] = '\0';
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetAssert(
|
|
IN LPSTR Assertion,
|
|
IN LPSTR FileName,
|
|
IN DWORD LineNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
displays assertion message at debugger and raised breakpoint exception
|
|
|
|
Arguments:
|
|
|
|
Assertion - string describing assertion which failed
|
|
|
|
FileName - module where assertion failure occurred
|
|
|
|
LineNumber - at this line number
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
char buffer[512];
|
|
|
|
rsprintf(buffer,
|
|
"\n"
|
|
"*** Urlmon Assertion failed: %s\n"
|
|
"*** Source file: %s\n"
|
|
"*** Source line: %d\n"
|
|
"*** Thread %08x\n"
|
|
"\n",
|
|
Assertion,
|
|
FileName,
|
|
LineNumber,
|
|
GetCurrentThreadId()
|
|
);
|
|
InternetDebugOut(buffer, TRUE);
|
|
|
|
//
|
|
// break to the debugger, unless it is requested that we don't
|
|
//
|
|
|
|
if (!(InternetDebugControlFlags & DBG_NO_ASSERT_BREAK)) {
|
|
DebugBreak();
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
InternetGetDebugVariable(
|
|
IN LPSTR lpszVariableName,
|
|
OUT LPDWORD lpdwVariable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get debug variable. First examine environment, then registry
|
|
|
|
Arguments:
|
|
|
|
lpszVariableName - variable name
|
|
|
|
lpdwVariable - returned variable
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD len;
|
|
char varbuf[ENVIRONMENT_VARIABLE_BUFFER_LENGTH];
|
|
|
|
//
|
|
// get the debug variables first from the environment, then - if not there -
|
|
// from the registry
|
|
//
|
|
|
|
len = GetEnvironmentVariable(lpszVariableName, varbuf, sizeof(varbuf));
|
|
if (len && len < sizeof(varbuf)) {
|
|
*lpdwVariable = (DWORD)strtoul(varbuf, NULL, 0);
|
|
} else {
|
|
InternetReadRegistryDword(lpszVariableName, lpdwVariable);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PRIVATE
|
|
VOID
|
|
InternetGetDebugVariableString(
|
|
IN LPSTR lpszVariableName,
|
|
OUT LPSTR lpszVariable,
|
|
IN DWORD dwVariableLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get debug variable string. First examine environment, then registry
|
|
|
|
Arguments:
|
|
|
|
lpszVariableName - variable name
|
|
|
|
lpszVariable - returned string variable
|
|
|
|
dwVariableLen - size of buffer
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (GetEnvironmentVariable(lpszVariableName, lpszVariable, dwVariableLen) == 0) {
|
|
|
|
char buf[MAX_PATH + 1];
|
|
DWORD len = min(sizeof(buf), dwVariableLen);
|
|
|
|
if (InternetReadRegistryString(lpszVariableName, buf, &len) == ERROR_SUCCESS) {
|
|
memcpy(lpszVariable, buf, len + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
LPSTR
|
|
InternetMapError(
|
|
IN DWORD Error
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map error code to string. Try to get all errors that might ever be returned
|
|
by an Internet function
|
|
|
|
Arguments:
|
|
|
|
Error - code to map
|
|
|
|
Return Value:
|
|
|
|
LPSTR - pointer to symbolic error name
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Error) {
|
|
|
|
//
|
|
// WINERROR errors
|
|
//
|
|
|
|
CASE_OF(ERROR_SUCCESS);
|
|
CASE_OF(S_FALSE);
|
|
CASE_OF(ERROR_FILE_NOT_FOUND);
|
|
CASE_OF(ERROR_PATH_NOT_FOUND);
|
|
CASE_OF(ERROR_TOO_MANY_OPEN_FILES);
|
|
CASE_OF(ERROR_ACCESS_DENIED);
|
|
CASE_OF(ERROR_INVALID_HANDLE);
|
|
CASE_OF(ERROR_ARENA_TRASHED);
|
|
CASE_OF(ERROR_NOT_ENOUGH_MEMORY);
|
|
CASE_OF(ERROR_INVALID_BLOCK);
|
|
CASE_OF(ERROR_BAD_ENVIRONMENT);
|
|
CASE_OF(ERROR_BAD_FORMAT);
|
|
CASE_OF(ERROR_INVALID_ACCESS);
|
|
CASE_OF(ERROR_INVALID_DATA);
|
|
CASE_OF(ERROR_OUTOFMEMORY);
|
|
CASE_OF(ERROR_INVALID_DRIVE);
|
|
CASE_OF(ERROR_CURRENT_DIRECTORY);
|
|
CASE_OF(ERROR_NOT_SAME_DEVICE);
|
|
CASE_OF(ERROR_NO_MORE_FILES);
|
|
CASE_OF(ERROR_WRITE_PROTECT);
|
|
CASE_OF(ERROR_BAD_UNIT);
|
|
CASE_OF(ERROR_NOT_READY);
|
|
CASE_OF(ERROR_BAD_COMMAND);
|
|
CASE_OF(ERROR_CRC);
|
|
CASE_OF(ERROR_BAD_LENGTH);
|
|
CASE_OF(ERROR_SEEK);
|
|
CASE_OF(ERROR_NOT_DOS_DISK);
|
|
CASE_OF(ERROR_SECTOR_NOT_FOUND);
|
|
CASE_OF(ERROR_OUT_OF_PAPER);
|
|
CASE_OF(ERROR_WRITE_FAULT);
|
|
CASE_OF(ERROR_READ_FAULT);
|
|
CASE_OF(ERROR_GEN_FAILURE);
|
|
CASE_OF(ERROR_SHARING_VIOLATION);
|
|
CASE_OF(ERROR_LOCK_VIOLATION);
|
|
CASE_OF(ERROR_WRONG_DISK);
|
|
CASE_OF(ERROR_SHARING_BUFFER_EXCEEDED);
|
|
CASE_OF(ERROR_HANDLE_EOF);
|
|
CASE_OF(ERROR_HANDLE_DISK_FULL);
|
|
CASE_OF(ERROR_NOT_SUPPORTED);
|
|
CASE_OF(ERROR_REM_NOT_LIST);
|
|
CASE_OF(ERROR_DUP_NAME);
|
|
CASE_OF(ERROR_BAD_NETPATH);
|
|
CASE_OF(ERROR_NETWORK_BUSY);
|
|
CASE_OF(ERROR_DEV_NOT_EXIST);
|
|
CASE_OF(ERROR_TOO_MANY_CMDS);
|
|
CASE_OF(ERROR_ADAP_HDW_ERR);
|
|
CASE_OF(ERROR_BAD_NET_RESP);
|
|
CASE_OF(ERROR_UNEXP_NET_ERR);
|
|
CASE_OF(ERROR_BAD_REM_ADAP);
|
|
CASE_OF(ERROR_PRINTQ_FULL);
|
|
CASE_OF(ERROR_NO_SPOOL_SPACE);
|
|
CASE_OF(ERROR_PRINT_CANCELLED);
|
|
CASE_OF(ERROR_NETNAME_DELETED);
|
|
CASE_OF(ERROR_NETWORK_ACCESS_DENIED);
|
|
CASE_OF(ERROR_BAD_DEV_TYPE);
|
|
CASE_OF(ERROR_BAD_NET_NAME);
|
|
CASE_OF(ERROR_TOO_MANY_NAMES);
|
|
CASE_OF(ERROR_TOO_MANY_SESS);
|
|
CASE_OF(ERROR_SHARING_PAUSED);
|
|
CASE_OF(ERROR_REQ_NOT_ACCEP);
|
|
CASE_OF(ERROR_REDIR_PAUSED);
|
|
CASE_OF(ERROR_FILE_EXISTS);
|
|
CASE_OF(ERROR_CANNOT_MAKE);
|
|
CASE_OF(ERROR_FAIL_I24);
|
|
CASE_OF(ERROR_OUT_OF_STRUCTURES);
|
|
CASE_OF(ERROR_ALREADY_ASSIGNED);
|
|
CASE_OF(ERROR_INVALID_PASSWORD);
|
|
CASE_OF(ERROR_INVALID_PARAMETER);
|
|
CASE_OF(ERROR_NET_WRITE_FAULT);
|
|
CASE_OF(ERROR_NO_PROC_SLOTS);
|
|
CASE_OF(ERROR_TOO_MANY_SEMAPHORES);
|
|
CASE_OF(ERROR_EXCL_SEM_ALREADY_OWNED);
|
|
CASE_OF(ERROR_SEM_IS_SET);
|
|
CASE_OF(ERROR_TOO_MANY_SEM_REQUESTS);
|
|
CASE_OF(ERROR_INVALID_AT_INTERRUPT_TIME);
|
|
CASE_OF(ERROR_SEM_OWNER_DIED);
|
|
CASE_OF(ERROR_SEM_USER_LIMIT);
|
|
CASE_OF(ERROR_DISK_CHANGE);
|
|
CASE_OF(ERROR_DRIVE_LOCKED);
|
|
CASE_OF(ERROR_BROKEN_PIPE);
|
|
CASE_OF(ERROR_OPEN_FAILED);
|
|
CASE_OF(ERROR_BUFFER_OVERFLOW);
|
|
CASE_OF(ERROR_DISK_FULL);
|
|
CASE_OF(ERROR_NO_MORE_SEARCH_HANDLES);
|
|
CASE_OF(ERROR_INVALID_TARGET_HANDLE);
|
|
CASE_OF(ERROR_INVALID_CATEGORY);
|
|
CASE_OF(ERROR_INVALID_VERIFY_SWITCH);
|
|
CASE_OF(ERROR_BAD_DRIVER_LEVEL);
|
|
CASE_OF(ERROR_CALL_NOT_IMPLEMENTED);
|
|
CASE_OF(ERROR_SEM_TIMEOUT);
|
|
CASE_OF(ERROR_INSUFFICIENT_BUFFER);
|
|
CASE_OF(ERROR_INVALID_NAME);
|
|
CASE_OF(ERROR_INVALID_LEVEL);
|
|
CASE_OF(ERROR_NO_VOLUME_LABEL);
|
|
CASE_OF(ERROR_MOD_NOT_FOUND);
|
|
CASE_OF(ERROR_PROC_NOT_FOUND);
|
|
CASE_OF(ERROR_WAIT_NO_CHILDREN);
|
|
CASE_OF(ERROR_CHILD_NOT_COMPLETE);
|
|
CASE_OF(ERROR_DIRECT_ACCESS_HANDLE);
|
|
CASE_OF(ERROR_NEGATIVE_SEEK);
|
|
CASE_OF(ERROR_SEEK_ON_DEVICE);
|
|
CASE_OF(ERROR_DIR_NOT_ROOT);
|
|
CASE_OF(ERROR_DIR_NOT_EMPTY);
|
|
CASE_OF(ERROR_PATH_BUSY);
|
|
CASE_OF(ERROR_SYSTEM_TRACE);
|
|
CASE_OF(ERROR_INVALID_EVENT_COUNT);
|
|
CASE_OF(ERROR_TOO_MANY_MUXWAITERS);
|
|
CASE_OF(ERROR_INVALID_LIST_FORMAT);
|
|
CASE_OF(ERROR_BAD_ARGUMENTS);
|
|
CASE_OF(ERROR_BAD_PATHNAME);
|
|
CASE_OF(ERROR_BUSY);
|
|
CASE_OF(ERROR_CANCEL_VIOLATION);
|
|
CASE_OF(ERROR_ALREADY_EXISTS);
|
|
CASE_OF(ERROR_FILENAME_EXCED_RANGE);
|
|
CASE_OF(ERROR_LOCKED);
|
|
CASE_OF(ERROR_NESTING_NOT_ALLOWED);
|
|
CASE_OF(ERROR_BAD_PIPE);
|
|
CASE_OF(ERROR_PIPE_BUSY);
|
|
CASE_OF(ERROR_NO_DATA);
|
|
CASE_OF(ERROR_PIPE_NOT_CONNECTED);
|
|
CASE_OF(ERROR_MORE_DATA);
|
|
CASE_OF(ERROR_NO_MORE_ITEMS);
|
|
CASE_OF(ERROR_NOT_OWNER);
|
|
CASE_OF(ERROR_PARTIAL_COPY);
|
|
CASE_OF(ERROR_MR_MID_NOT_FOUND);
|
|
CASE_OF(ERROR_INVALID_ADDRESS);
|
|
CASE_OF(ERROR_PIPE_CONNECTED);
|
|
CASE_OF(ERROR_PIPE_LISTENING);
|
|
CASE_OF(ERROR_OPERATION_ABORTED);
|
|
CASE_OF(ERROR_IO_INCOMPLETE);
|
|
CASE_OF(ERROR_IO_PENDING);
|
|
CASE_OF(ERROR_NOACCESS);
|
|
CASE_OF(ERROR_STACK_OVERFLOW);
|
|
CASE_OF(ERROR_INVALID_FLAGS);
|
|
CASE_OF(ERROR_NO_TOKEN);
|
|
CASE_OF(ERROR_BADDB);
|
|
CASE_OF(ERROR_BADKEY);
|
|
CASE_OF(ERROR_CANTOPEN);
|
|
CASE_OF(ERROR_CANTREAD);
|
|
CASE_OF(ERROR_CANTWRITE);
|
|
CASE_OF(ERROR_REGISTRY_RECOVERED);
|
|
CASE_OF(ERROR_REGISTRY_CORRUPT);
|
|
CASE_OF(ERROR_REGISTRY_IO_FAILED);
|
|
CASE_OF(ERROR_NOT_REGISTRY_FILE);
|
|
CASE_OF(ERROR_KEY_DELETED);
|
|
CASE_OF(ERROR_CIRCULAR_DEPENDENCY);
|
|
CASE_OF(ERROR_SERVICE_NOT_ACTIVE);
|
|
CASE_OF(ERROR_DLL_INIT_FAILED);
|
|
CASE_OF(ERROR_CANCELLED);
|
|
CASE_OF(ERROR_BAD_USERNAME);
|
|
CASE_OF(ERROR_LOGON_FAILURE);
|
|
|
|
CASE_OF(WAIT_FAILED);
|
|
//CASE_OF(WAIT_ABANDONED_0);
|
|
CASE_OF(WAIT_TIMEOUT);
|
|
CASE_OF(WAIT_IO_COMPLETION);
|
|
//CASE_OF(STILL_ACTIVE);
|
|
|
|
CASE_OF(RPC_S_INVALID_STRING_BINDING);
|
|
CASE_OF(RPC_S_WRONG_KIND_OF_BINDING);
|
|
CASE_OF(RPC_S_INVALID_BINDING);
|
|
CASE_OF(RPC_S_PROTSEQ_NOT_SUPPORTED);
|
|
CASE_OF(RPC_S_INVALID_RPC_PROTSEQ);
|
|
CASE_OF(RPC_S_INVALID_STRING_UUID);
|
|
CASE_OF(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
CASE_OF(RPC_S_INVALID_NET_ADDR);
|
|
CASE_OF(RPC_S_NO_ENDPOINT_FOUND);
|
|
CASE_OF(RPC_S_INVALID_TIMEOUT);
|
|
CASE_OF(RPC_S_OBJECT_NOT_FOUND);
|
|
CASE_OF(RPC_S_ALREADY_REGISTERED);
|
|
CASE_OF(RPC_S_TYPE_ALREADY_REGISTERED);
|
|
CASE_OF(RPC_S_ALREADY_LISTENING);
|
|
CASE_OF(RPC_S_NO_PROTSEQS_REGISTERED);
|
|
CASE_OF(RPC_S_NOT_LISTENING);
|
|
CASE_OF(RPC_S_UNKNOWN_MGR_TYPE);
|
|
CASE_OF(RPC_S_UNKNOWN_IF);
|
|
CASE_OF(RPC_S_NO_BINDINGS);
|
|
CASE_OF(RPC_S_NO_PROTSEQS);
|
|
CASE_OF(RPC_S_CANT_CREATE_ENDPOINT);
|
|
CASE_OF(RPC_S_OUT_OF_RESOURCES);
|
|
CASE_OF(RPC_S_SERVER_UNAVAILABLE);
|
|
CASE_OF(RPC_S_SERVER_TOO_BUSY);
|
|
CASE_OF(RPC_S_INVALID_NETWORK_OPTIONS);
|
|
CASE_OF(RPC_S_NO_CALL_ACTIVE);
|
|
CASE_OF(RPC_S_CALL_FAILED);
|
|
CASE_OF(RPC_S_CALL_FAILED_DNE);
|
|
CASE_OF(RPC_S_PROTOCOL_ERROR);
|
|
CASE_OF(RPC_S_UNSUPPORTED_TRANS_SYN);
|
|
CASE_OF(RPC_S_UNSUPPORTED_TYPE);
|
|
CASE_OF(RPC_S_INVALID_TAG);
|
|
CASE_OF(RPC_S_INVALID_BOUND);
|
|
CASE_OF(RPC_S_NO_ENTRY_NAME);
|
|
CASE_OF(RPC_S_INVALID_NAME_SYNTAX);
|
|
CASE_OF(RPC_S_UNSUPPORTED_NAME_SYNTAX);
|
|
CASE_OF(RPC_S_UUID_NO_ADDRESS);
|
|
CASE_OF(RPC_S_DUPLICATE_ENDPOINT);
|
|
CASE_OF(RPC_S_UNKNOWN_AUTHN_TYPE);
|
|
CASE_OF(RPC_S_MAX_CALLS_TOO_SMALL);
|
|
CASE_OF(RPC_S_STRING_TOO_LONG);
|
|
CASE_OF(RPC_S_PROTSEQ_NOT_FOUND);
|
|
CASE_OF(RPC_S_PROCNUM_OUT_OF_RANGE);
|
|
CASE_OF(RPC_S_BINDING_HAS_NO_AUTH);
|
|
CASE_OF(RPC_S_UNKNOWN_AUTHN_SERVICE);
|
|
CASE_OF(RPC_S_UNKNOWN_AUTHN_LEVEL);
|
|
CASE_OF(RPC_S_INVALID_AUTH_IDENTITY);
|
|
CASE_OF(RPC_S_UNKNOWN_AUTHZ_SERVICE);
|
|
CASE_OF(EPT_S_INVALID_ENTRY);
|
|
CASE_OF(EPT_S_CANT_PERFORM_OP);
|
|
CASE_OF(EPT_S_NOT_REGISTERED);
|
|
CASE_OF(RPC_S_NOTHING_TO_EXPORT);
|
|
CASE_OF(RPC_S_INCOMPLETE_NAME);
|
|
CASE_OF(RPC_S_INVALID_VERS_OPTION);
|
|
CASE_OF(RPC_S_NO_MORE_MEMBERS);
|
|
CASE_OF(RPC_S_NOT_ALL_OBJS_UNEXPORTED);
|
|
CASE_OF(RPC_S_INTERFACE_NOT_FOUND);
|
|
CASE_OF(RPC_S_ENTRY_ALREADY_EXISTS);
|
|
CASE_OF(RPC_S_ENTRY_NOT_FOUND);
|
|
CASE_OF(RPC_S_NAME_SERVICE_UNAVAILABLE);
|
|
CASE_OF(RPC_S_INVALID_NAF_ID);
|
|
CASE_OF(RPC_S_CANNOT_SUPPORT);
|
|
CASE_OF(RPC_S_NO_CONTEXT_AVAILABLE);
|
|
CASE_OF(RPC_S_INTERNAL_ERROR);
|
|
CASE_OF(RPC_S_ZERO_DIVIDE);
|
|
CASE_OF(RPC_S_ADDRESS_ERROR);
|
|
CASE_OF(RPC_S_FP_DIV_ZERO);
|
|
CASE_OF(RPC_S_FP_UNDERFLOW);
|
|
CASE_OF(RPC_S_FP_OVERFLOW);
|
|
CASE_OF(RPC_X_NO_MORE_ENTRIES);
|
|
CASE_OF(RPC_X_SS_CHAR_TRANS_OPEN_FAIL);
|
|
CASE_OF(RPC_X_SS_CHAR_TRANS_SHORT_FILE);
|
|
CASE_OF(RPC_X_SS_IN_NULL_CONTEXT);
|
|
CASE_OF(RPC_X_SS_CONTEXT_DAMAGED);
|
|
CASE_OF(RPC_X_SS_HANDLES_MISMATCH);
|
|
CASE_OF(RPC_X_SS_CANNOT_GET_CALL_HANDLE);
|
|
CASE_OF(RPC_X_NULL_REF_POINTER);
|
|
CASE_OF(RPC_X_ENUM_VALUE_OUT_OF_RANGE);
|
|
CASE_OF(RPC_X_BYTE_COUNT_TOO_SMALL);
|
|
CASE_OF(RPC_X_BAD_STUB_DATA);
|
|
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
|
|
//
|
|
// private functions
|
|
//
|
|
|
|
|
|
PRIVATE
|
|
LPSTR
|
|
ExtractFileName(
|
|
IN LPSTR Module,
|
|
OUT LPSTR Buf
|
|
)
|
|
{
|
|
LPSTR filename;
|
|
LPSTR extension;
|
|
int len;
|
|
|
|
filename = strrchr(Module, '\\');
|
|
extension = strrchr(Module, '.');
|
|
if (filename) {
|
|
++filename;
|
|
} else {
|
|
filename = Module;
|
|
}
|
|
if (!extension) {
|
|
extension = filename + strlen(filename);
|
|
}
|
|
len = (int) (extension - filename);
|
|
memcpy(Buf, filename, len);
|
|
Buf[len] = '\0';
|
|
return Buf;
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
LPSTR
|
|
SetDebugPrefix(
|
|
IN LPSTR Buffer
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CUrlMkTls tls(hr); // hr passed by reference!
|
|
if (FAILED(hr))
|
|
return NULL;
|
|
|
|
LPDEBUG_URLMON_FUNC_RECORD pCurrentFunction = tls->Stack;
|
|
|
|
if (!pCurrentFunction) {
|
|
return NULL;
|
|
}
|
|
|
|
if (InternetDebugControlFlags & DBG_ENTRY_TIME) {
|
|
if (InternetDebugControlFlags & (DBG_DELTA_TIME | DBG_CUMULATIVE_TIME))
|
|
{
|
|
|
|
DWORD ticks;
|
|
DWORD ticksNow;
|
|
|
|
ticksNow = GetTickCountWrap();
|
|
ticks = ticksNow - ((InternetDebugControlFlags & DBG_CUMULATIVE_TIME)
|
|
? InternetDebugStartTime
|
|
: pCurrentFunction->LastTime);
|
|
|
|
Buffer += rsprintf(Buffer,
|
|
"% 5d.%3d ",
|
|
ticks / 1000,
|
|
ticks % 1000
|
|
);
|
|
if (InternetDebugControlFlags & DBG_DELTA_TIME) {
|
|
pCurrentFunction->LastTime = ticksNow;
|
|
}
|
|
} else {
|
|
|
|
SYSTEMTIME timeNow;
|
|
|
|
InternetDebugGetLocalTime(&timeNow, NULL);
|
|
|
|
Buffer += rsprintf(Buffer,
|
|
"%02d:%02d:%02d.%03d ",
|
|
timeNow.wHour,
|
|
timeNow.wMinute,
|
|
timeNow.wSecond,
|
|
timeNow.wMilliseconds
|
|
);
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (InternetDebugControlFlags & DBG_LEVEL_INDICATOR) {
|
|
Buffer += rsprintf(Buffer, );
|
|
}
|
|
*/
|
|
|
|
if (InternetDebugControlFlags & DBG_THREAD_INFO) {
|
|
|
|
//
|
|
// thread id
|
|
//
|
|
|
|
Buffer += rsprintf(Buffer, "%08x", tls->ThreadId);
|
|
|
|
//
|
|
// INTERNET_THREAD_INFO address
|
|
//
|
|
|
|
if (InternetDebugControlFlags & DBG_THREAD_INFO_ADR) {
|
|
Buffer += rsprintf(Buffer, ":%08x", tls);
|
|
}
|
|
|
|
*Buffer++ = ' ';
|
|
}
|
|
|
|
if (InternetDebugControlFlags & DBG_CALL_DEPTH) {
|
|
Buffer += rsprintf(Buffer, "%03d ", tls->CallDepth);
|
|
}
|
|
|
|
for (int i = 0; i < tls->IndentIncrement; ++i) {
|
|
*Buffer++ = ' ';
|
|
}
|
|
|
|
//
|
|
// if we are not debugging the category - i.e we got here via a requirement
|
|
// to display an error, or we are in a function that does not have a
|
|
// DEBUG_ENTER - then prefix the string with the current function name
|
|
// (obviously misleading if the function doesn't have a DEBUG_ENTER)
|
|
//
|
|
|
|
if (pCurrentFunction != NULL) {
|
|
if (!(pCurrentFunction->Category & InternetDebugCategoryFlags)) {
|
|
Buffer += rsprintf(Buffer, "%s(): ", pCurrentFunction->Function);
|
|
}
|
|
}
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
int dprintf(char * format, ...) {
|
|
|
|
va_list args;
|
|
char buf[PRINTF_STACK_BUFFER_LENGTH];
|
|
int n;
|
|
|
|
va_start(args, format);
|
|
n = _sprintf(buf, format, args);
|
|
va_end(args);
|
|
OutputDebugString(buf);
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
SourceFilename(
|
|
LPSTR Filespec
|
|
)
|
|
{
|
|
if (!Filespec) {
|
|
return "?";
|
|
}
|
|
|
|
LPSTR p;
|
|
|
|
if (p = strrchr(Filespec, '\\')) {
|
|
|
|
//
|
|
// we want e.g. common\debugmem.cxx, but get
|
|
// common\..\win32\debugmem.cxx. Bah!
|
|
//
|
|
|
|
//LPSTR q;
|
|
//
|
|
//if (q = strrchr(p - 1, '\\')) {
|
|
// p = q;
|
|
//}
|
|
}
|
|
return p ? p + 1 : Filespec;
|
|
}
|
|
|
|
|
|
typedef BOOL (* SYMINITIALIZE)(HANDLE, LPSTR, BOOL);
|
|
typedef BOOL (* SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD);
|
|
typedef BOOL (* SYMGETSYMFROMADDR)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL);
|
|
typedef BOOL (* SYMCLEANUP)(HANDLE);
|
|
|
|
PRIVATE HMODULE hSymLib = NULL;
|
|
PRIVATE SYMINITIALIZE pSymInitialize = NULL;
|
|
PRIVATE SYMLOADMODULE pSymLoadModule = NULL;
|
|
PRIVATE SYMGETSYMFROMADDR pSymGetSymFromAddr = NULL;
|
|
PRIVATE SYMCLEANUP pSymCleanup = NULL;
|
|
|
|
|
|
VOID
|
|
InitSymLib(
|
|
VOID
|
|
)
|
|
{
|
|
if (hSymLib == NULL) {
|
|
hSymLib = LoadLibrary("IMAGEHLP.DLL");
|
|
if (hSymLib != NULL) {
|
|
pSymInitialize = (SYMINITIALIZE)GetProcAddress(hSymLib,
|
|
"SymInitialize"
|
|
);
|
|
pSymLoadModule = (SYMLOADMODULE)GetProcAddress(hSymLib,
|
|
"SymLoadModule"
|
|
);
|
|
pSymGetSymFromAddr = (SYMGETSYMFROMADDR)GetProcAddress(hSymLib,
|
|
"SymGetSymFromAddr"
|
|
);
|
|
pSymCleanup = (SYMCLEANUP)GetProcAddress(hSymLib,
|
|
"SymCleanup"
|
|
);
|
|
if (!pSymInitialize
|
|
|| !pSymLoadModule
|
|
|| !pSymGetSymFromAddr
|
|
|| !pSymCleanup) {
|
|
FreeLibrary(hSymLib);
|
|
hSymLib = NULL;
|
|
pSymInitialize = NULL;
|
|
pSymLoadModule = NULL;
|
|
pSymGetSymFromAddr = NULL;
|
|
pSymCleanup = NULL;
|
|
return;
|
|
}
|
|
}
|
|
pSymInitialize(GetCurrentProcess(), NULL, FALSE);
|
|
//SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
|
pSymLoadModule(GetCurrentProcess(), NULL, "URLMON.DLL", "URLMON", 0, 0);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
TermSymLib(
|
|
VOID
|
|
)
|
|
{
|
|
if (pSymCleanup) {
|
|
pSymCleanup(GetCurrentProcess());
|
|
FreeLibrary(hSymLib);
|
|
}
|
|
}
|
|
|
|
|
|
LPSTR
|
|
GetDebugSymbol(
|
|
DWORD Address,
|
|
LPDWORD Offset
|
|
)
|
|
{
|
|
*Offset = Address;
|
|
if (!pSymGetSymFromAddr) {
|
|
return "";
|
|
}
|
|
|
|
//
|
|
// BUGBUG - only one caller at a time please
|
|
//
|
|
|
|
static char symBuf[512];
|
|
|
|
//((PIMAGEHLP_SYMBOL)symBuf)->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
|
|
((PIMAGEHLP_SYMBOL)symBuf)->SizeOfStruct = sizeof(symBuf);
|
|
((PIMAGEHLP_SYMBOL)symBuf)->MaxNameLength = sizeof(symBuf) - sizeof(IMAGEHLP_SYMBOL);
|
|
if (!pSymGetSymFromAddr(GetCurrentProcess(),
|
|
Address,
|
|
Offset,
|
|
(PIMAGEHLP_SYMBOL)symBuf)) {
|
|
((PIMAGEHLP_SYMBOL)symBuf)->Name[0] = '\0';
|
|
}
|
|
return ((PIMAGEHLP_SYMBOL)symBuf)->Name;
|
|
}
|
|
|
|
|
|
#if defined(i386)
|
|
|
|
VOID
|
|
x86SleazeCallStack(
|
|
OUT LPVOID * lplpvStack,
|
|
IN DWORD dwStackCount,
|
|
IN LPVOID * Ebp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Similar to x86SleazeCallersAddress but gathers a variable number of return
|
|
addresses. We assume all functions have stack frame
|
|
|
|
Arguments:
|
|
|
|
lplpvStack - pointer to returned array of caller's addresses
|
|
|
|
dwStackCount - number of elements in lplpvStack
|
|
|
|
Ebp - starting Ebp if not 0, else use current stack
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD my_esp;
|
|
|
|
_asm mov my_esp, esp;
|
|
|
|
__try {
|
|
if (Ebp == 0) {
|
|
Ebp = (LPVOID *)(&lplpvStack - 2);
|
|
}
|
|
while (dwStackCount--) {
|
|
if (((DWORD)Ebp > my_esp + 0x10000) || ((DWORD)Ebp < my_esp - 0x10000)) {
|
|
break;
|
|
}
|
|
*lplpvStack++ = *(Ebp + 1);
|
|
Ebp = (LPVOID *)*Ebp;
|
|
if (((DWORD)Ebp <= 0x10000)
|
|
|| ((DWORD)Ebp >= 0x80000000)
|
|
|| ((DWORD)Ebp & 3)
|
|
|| ((DWORD)Ebp > my_esp + 0x10000)
|
|
|| ((DWORD)Ebp < my_esp - 0x10000)) {
|
|
break;
|
|
}
|
|
}
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
x86SleazeCallersAddress(
|
|
LPVOID* pCaller,
|
|
LPVOID* pCallersCaller
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a sleazy function that reads return addresses out of the stack/
|
|
frame pointer (ebp). We pluck out the return address of the function
|
|
that called THE FUNCTION THAT CALLED THIS FUNCTION, and the caller of
|
|
that function. Returning the return address of the function that called
|
|
this function is not interesting to that caller (almost worthy of Sir
|
|
Humphrey Appleby isn't it?)
|
|
|
|
Assumes:
|
|
|
|
my ebp => | caller's ebp |
|
|
| caller's eip |
|
|
| arg #1 | (pCaller)
|
|
| arg #2 | (pCallersCaller
|
|
|
|
Arguments:
|
|
|
|
pCaller - place where we return addres of function that called
|
|
the function that called this function
|
|
pCallersCaller - place where we return caller of above
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// this only works on x86 and only if not fpo functions!
|
|
//
|
|
|
|
LPVOID* ebp;
|
|
|
|
ebp = (PVOID*)&pCaller - 2; // told you it was sleazy
|
|
ebp = (PVOID*)*(PVOID*)ebp;
|
|
*pCaller = *(ebp + 1);
|
|
ebp = (PVOID*)*(PVOID*)ebp;
|
|
*pCallersCaller = *(ebp + 1);
|
|
}
|
|
|
|
#endif // defined(i386)
|
|
|
|
|
|
BOOL
|
|
InternetDebugGetLocalTime(
|
|
OUT SYSTEMTIME * pstLocalTime,
|
|
OUT DWORD * pdwMicroSec
|
|
)
|
|
{
|
|
#ifndef ENABLE_DEBUG
|
|
// QUICK HACK TO KEEP THINGS CLEAN AND STILL MEASURE WITH HIGH PERFORMANCE
|
|
// COUNTER
|
|
|
|
static BOOL pcTested = FALSE;
|
|
static LONGLONG ftInit; // initial local time
|
|
static LONGLONG pcInit; // initial perf counter
|
|
static LONGLONG pcFreq; // perf counter frequency
|
|
|
|
if (!pcTested)
|
|
{
|
|
pcTested = TRUE;
|
|
if (QueryPerformanceFrequency ((LARGE_INTEGER *) &pcFreq) && pcFreq)
|
|
{
|
|
QueryPerformanceCounter ((LARGE_INTEGER *) &pcInit);
|
|
SYSTEMTIME st;
|
|
GetLocalTime (&st);
|
|
SystemTimeToFileTime (&st, (FILETIME *) &ftInit);
|
|
}
|
|
}
|
|
|
|
if (!pcFreq)
|
|
GetLocalTime (pstLocalTime);
|
|
else
|
|
{
|
|
LONGLONG pcCurrent, ftCurrent;
|
|
QueryPerformanceCounter ((LARGE_INTEGER *) &pcCurrent);
|
|
ftCurrent = ftInit + ((10000000 * (pcCurrent - pcInit)) / pcFreq);
|
|
FileTimeToSystemTime ((FILETIME *) &ftCurrent, pstLocalTime);
|
|
}
|
|
|
|
return TRUE;
|
|
#else
|
|
if (!pcFreq)
|
|
GetLocalTime (pstLocalTime);
|
|
else
|
|
{
|
|
LONGLONG pcCurrent, ftCurrent;
|
|
QueryPerformanceCounter ((LARGE_INTEGER *) &pcCurrent);
|
|
ftCurrent = ftInit + ((10000000 * (pcCurrent - pcInit)) / pcFreq);
|
|
FileTimeToSystemTime ((FILETIME *) &ftCurrent, pstLocalTime);
|
|
}
|
|
|
|
return TRUE;
|
|
#endif // ENABLE_DEBUG
|
|
}
|
|
|
|
#endif // ENABLE_DEBUG
|