blob: 647329628ce831bfb54273dcb5cdf1385e179d48 [file] [log] [blame]
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
To Do:
- Use StackWalk on Windows to optionally print stack frames.
*/
#if 0
#pragma mark == Includes ==
#endif
//===========================================================================================================================
// Includes
//===========================================================================================================================
#if( !KERNEL )
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#endif
#include "CommonServices.h"
#include "DebugServices.h"
#if( DEBUG )
#if( TARGET_OS_VXWORKS )
#include "intLib.h"
#endif
#if( TARGET_OS_WIN32 )
#include <time.h>
#if( !TARGET_OS_WINDOWS_CE )
#include <fcntl.h>
#include <io.h>
#endif
#endif
#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
#include <IOKit/IOLib.h>
#endif
// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
#if( defined( MDNS_DEBUGMSGS ) )
#include "mDNSEmbeddedAPI.h"
#endif
#if 0
#pragma mark == Macros ==
#endif
//===========================================================================================================================
// Macros
//===========================================================================================================================
#define DebugIsPrint( C ) ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
#if 0
#pragma mark == Prototypes ==
#endif
//===========================================================================================================================
// Prototypes
//===========================================================================================================================
static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
// fprintf
#if( DEBUG_FPRINTF_ENABLED )
static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
static void DebugFPrintFPrint( char *inData, size_t inSize );
#endif
// iDebug (Mac OS X user and kernel)
#if( DEBUG_IDEBUG_ENABLED )
static OSStatus DebugiDebugInit( void );
static void DebugiDebugPrint( char *inData, size_t inSize );
#endif
// kprintf (Mac OS X Kernel)
#if( DEBUG_KPRINTF_ENABLED )
static void DebugKPrintFPrint( char *inData, size_t inSize );
#endif
// Mac OS X IOLog (Mac OS X Kernel)
#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
static void DebugMacOSXIOLogPrint( char *inData, size_t inSize );
#endif
// Mac OS X Log
#if( TARGET_OS_MAC )
static OSStatus DebugMacOSXLogInit( void );
static void DebugMacOSXLogPrint( char *inData, size_t inSize );
#endif
// Windows Debugger
#if( TARGET_OS_WIN32 )
static void DebugWindowsDebuggerPrint( char *inData, size_t inSize );
#endif
// Windows Event Log
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
#endif
// DebugLib support
#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
static pascal void
DebugAssertOutputHandler(
OSType inComponentSignature,
UInt32 inOptions,
const char * inAssertionString,
const char * inExceptionString,
const char * inErrorString,
const char * inFileName,
long inLineNumber,
void * inValue,
ConstStr255Param inOutputMsg );
#endif
// Utilities
static char * DebugNumVersionToString( uint32_t inVersion, char *inString );
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
static void DebugWinEnableConsole( void );
#endif
#if( TARGET_OS_WIN32 )
static TCHAR *
DebugWinCharToTCharString(
const char * inCharString,
size_t inCharCount,
TCHAR * outTCharString,
size_t inTCharCountMax,
size_t * outTCharCount );
#endif
#if 0
#pragma mark == Globals ==
#endif
//===========================================================================================================================
// Private Globals
//===========================================================================================================================
#if( TARGET_OS_VXWORKS )
// TCP States for inetstatShow.
extern char ** pTcpstates; // defined in tcpLib.c
const char * kDebugTCPStates[] =
{
"(0) TCPS_CLOSED",
"(1) TCPS_LISTEN",
"(2) TCPS_SYN_SENT",
"(3) TCPS_SYN_RECEIVED",
"(4) TCPS_ESTABLISHED",
"(5) TCPS_CLOSE_WAIT",
"(6) TCPS_FIN_WAIT_1",
"(7) TCPS_CLOSING",
"(8) TCPS_LAST_ACK",
"(9) TCPS_FIN_WAIT_2",
"(10) TCPS_TIME_WAIT",
};
#endif
// General
static bool gDebugInitialized = false;
static DebugOutputType gDebugOutputType = kDebugOutputTypeNone;
static DebugLevel gDebugPrintLevelMin = kDebugLevelInfo;
static DebugLevel gDebugPrintLevelMax = kDebugLevelMax;
static DebugLevel gDebugBreakLevel = kDebugLevelAssert;
#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
static DebugAssertOutputHandlerUPP gDebugAssertOutputHandlerUPP = NULL;
#endif
// Custom
static DebugOutputFunctionPtr gDebugCustomOutputFunction = NULL;
static void * gDebugCustomOutputContext = NULL;
// fprintf
#if( DEBUG_FPRINTF_ENABLED )
static FILE * gDebugFPrintFFile = NULL;
#endif
// MacOSXLog
#if( TARGET_OS_MAC )
typedef int ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
static DebugMacOSXLogFunctionPtr gDebugMacOSXLogFunction = NULL;
#endif
// WindowsEventLog
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
static HANDLE gDebugWindowsEventLogEventSource = NULL;
#endif
#if 0
#pragma mark -
#pragma mark == General ==
#endif
//===========================================================================================================================
// DebugInitialize
//===========================================================================================================================
DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... )
{
OSStatus err;
DebugOutputType type;
va_list args;
va_start( args, inType );
#if( TARGET_OS_VXWORKS )
// Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
if( !pTcpstates )
{
pTcpstates = (char **) kDebugTCPStates;
}
#endif
// Set up DebugLib stuff (if building with Debugging.h).
#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
if( !gDebugAssertOutputHandlerUPP )
{
gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
check( gDebugAssertOutputHandlerUPP );
if( gDebugAssertOutputHandlerUPP )
{
InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
}
}
#endif
// Pre-process meta-output kind to pick an appropriate output kind for the platform.
type = inType;
if( type == kDebugOutputTypeMetaConsole )
{
#if( TARGET_OS_MAC )
type = kDebugOutputTypeMacOSXLog;
#elif( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
#if( DEBUG_FPRINTF_ENABLED )
type = kDebugOutputTypeFPrintF;
#else
type = kDebugOutputTypeWindowsDebugger;
#endif
#elif( TARGET_API_MAC_OSX_KERNEL )
#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
type = kDebugOutputTypeMacOSXIOLog;
#elif( DEBUG_IDEBUG_ENABLED )
type = kDebugOutputTypeiDebug;
#elif( DEBUG_KPRINTF_ENABLED )
type = kDebugOutputTypeKPrintF;
#endif
#elif( TARGET_OS_VXWORKS )
#if( DEBUG_FPRINTF_ENABLED )
type = kDebugOutputTypeFPrintF;
#else
#error target is VxWorks, but fprintf output is disabled
#endif
#else
#if( DEBUG_FPRINTF_ENABLED )
type = kDebugOutputTypeFPrintF;
#endif
#endif
}
// Process output kind.
gDebugOutputType = type;
switch( type )
{
case kDebugOutputTypeNone:
err = kNoErr;
break;
case kDebugOutputTypeCustom:
gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
gDebugCustomOutputContext = va_arg( args, void * );
err = kNoErr;
break;
#if( DEBUG_FPRINTF_ENABLED )
case kDebugOutputTypeFPrintF:
if( inType == kDebugOutputTypeMetaConsole )
{
err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
}
else
{
DebugOutputTypeFlags flags;
const char * filename;
flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
{
filename = va_arg( args, const char * );
}
else
{
filename = NULL;
}
err = DebugFPrintFInit( flags, filename );
}
break;
#endif
#if( DEBUG_IDEBUG_ENABLED )
case kDebugOutputTypeiDebug:
err = DebugiDebugInit();
break;
#endif
#if( DEBUG_KPRINTF_ENABLED )
case kDebugOutputTypeKPrintF:
err = kNoErr;
break;
#endif
#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
case kDebugOutputTypeMacOSXIOLog:
err = kNoErr;
break;
#endif
#if( TARGET_OS_MAC )
case kDebugOutputTypeMacOSXLog:
err = DebugMacOSXLogInit();
break;
#endif
#if( TARGET_OS_WIN32 )
case kDebugOutputTypeWindowsDebugger:
err = kNoErr;
break;
#endif
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
case kDebugOutputTypeWindowsEventLog:
{
const char * name;
HMODULE module;
name = va_arg( args, const char * );
module = va_arg( args, HMODULE );
err = DebugWindowsEventLogInit( name, module );
}
break;
#endif
default:
err = kParamErr;
goto exit;
}
gDebugInitialized = true;
exit:
va_end( args );
return( err );
}
//===========================================================================================================================
// DebugFinalize
//===========================================================================================================================
DEBUG_EXPORT void DebugFinalize( void )
{
#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
check( gDebugAssertOutputHandlerUPP );
if( gDebugAssertOutputHandlerUPP )
{
InstallDebugAssertOutputHandler( NULL );
DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
gDebugAssertOutputHandlerUPP = NULL;
}
#endif
}
//===========================================================================================================================
// DebugGetProperty
//===========================================================================================================================
DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... )
{
OSStatus err;
va_list args;
DebugLevel * level;
va_start( args, inTag );
switch( inTag )
{
case kDebugPropertyTagPrintLevelMin:
level = va_arg( args, DebugLevel * );
*level = gDebugPrintLevelMin;
err = kNoErr;
break;
case kDebugPropertyTagPrintLevelMax:
level = va_arg( args, DebugLevel * );
*level = gDebugPrintLevelMax;
err = kNoErr;
break;
case kDebugPropertyTagBreakLevel:
level = va_arg( args, DebugLevel * );
*level = gDebugBreakLevel;
err = kNoErr;
break;
default:
err = kUnsupportedErr;
break;
}
va_end( args );
return( err );
}
//===========================================================================================================================
// DebugSetProperty
//===========================================================================================================================
DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... )
{
OSStatus err;
va_list args;
DebugLevel level;
va_start( args, inTag );
switch( inTag )
{
case kDebugPropertyTagPrintLevelMin:
level = va_arg( args, DebugLevel );
gDebugPrintLevelMin = level;
err = kNoErr;
break;
case kDebugPropertyTagPrintLevelMax:
level = va_arg( args, DebugLevel );
gDebugPrintLevelMax = level;
err = kNoErr;
break;
case kDebugPropertyTagBreakLevel:
level = va_arg( args, DebugLevel );
gDebugBreakLevel = level;
err = kNoErr;
break;
default:
err = kUnsupportedErr;
break;
}
va_end( args );
return( err );
}
#if 0
#pragma mark -
#pragma mark == Output ==
#endif
//===========================================================================================================================
// DebugPrintF
//===========================================================================================================================
DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
{
va_list args;
size_t n;
// Skip if the level is not in the enabled range..
if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
{
n = 0;
goto exit;
}
va_start( args, inFormat );
n = DebugPrintFVAList( inLevel, inFormat, args );
va_end( args );
exit:
return( n );
}
//===========================================================================================================================
// DebugPrintFVAList
//===========================================================================================================================
DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
{
size_t n;
char buffer[ 512 ];
// Skip if the level is not in the enabled range..
if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
{
n = 0;
goto exit;
}
n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
DebugPrint( inLevel, buffer, (size_t) n );
exit:
return( n );
}
//===========================================================================================================================
// DebugPrint
//===========================================================================================================================
static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
{
OSStatus err;
// Skip if the level is not in the enabled range..
if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
{
err = kRangeErr;
goto exit;
}
// Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
if( DebugTaskLevel() & kDebugInterruptLevelMask )
{
#if( TARGET_OS_VXWORKS )
logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
#endif
err = kExecutionStateErr;
goto exit;
}
// Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
if( !gDebugInitialized )
{
debug_initialize( kDebugOutputTypeMetaConsole );
}
// Print based on the current output type.
switch( gDebugOutputType )
{
case kDebugOutputTypeNone:
break;
case kDebugOutputTypeCustom:
if( gDebugCustomOutputFunction )
{
gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
}
break;
#if( DEBUG_FPRINTF_ENABLED )
case kDebugOutputTypeFPrintF:
DebugFPrintFPrint( inData, inSize );
break;
#endif
#if( DEBUG_IDEBUG_ENABLED )
case kDebugOutputTypeiDebug:
DebugiDebugPrint( inData, inSize );
break;
#endif
#if( DEBUG_KPRINTF_ENABLED )
case kDebugOutputTypeKPrintF:
DebugKPrintFPrint( inData, inSize );
break;
#endif
#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
case kDebugOutputTypeMacOSXIOLog:
DebugMacOSXIOLogPrint( inData, inSize );
break;
#endif
#if( TARGET_OS_MAC )
case kDebugOutputTypeMacOSXLog:
DebugMacOSXLogPrint( inData, inSize );
break;
#endif
#if( TARGET_OS_WIN32 )
case kDebugOutputTypeWindowsDebugger:
DebugWindowsDebuggerPrint( inData, inSize );
break;
#endif
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
case kDebugOutputTypeWindowsEventLog:
DebugWindowsEventLogPrint( inLevel, inData, inSize );
break;
#endif
default:
break;
}
err = kNoErr;
exit:
return( err );
}
//===========================================================================================================================
// DebugPrintAssert
//
// Warning: This routine relies on several of the strings being string constants that will exist forever because the
// underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based
// pointer variables (e.g. local strings). The debug macros that invoke this function only use constant
// constant strings, but if this function is invoked directly from other places, it must use constant strings.
//===========================================================================================================================
DEBUG_EXPORT void
DebugPrintAssert(
int_least32_t inErrorCode,
const char * inAssertString,
const char * inMessage,
const char * inFilename,
int_least32_t inLineNumber,
const char * inFunction )
{
// Skip if the level is not in the enabled range..
if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
{
return;
}
if( inErrorCode != 0 )
{
DebugPrintF(
kDebugLevelAssert,
"\n"
"[ASSERT] error: %ld (%m)\n"
"[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
"\n",
inErrorCode, inErrorCode,
inFilename ? inFilename : "",
inLineNumber,
inFunction ? inFunction : "" );
}
else
{
DebugPrintF(
kDebugLevelAssert,
"\n"
"[ASSERT] assert: \"%s\" %s\n"
"[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
"\n",
inAssertString ? inAssertString : "",
inMessage ? inMessage : "",
inFilename ? inFilename : "",
inLineNumber,
inFunction ? inFunction : "" );
}
// Break into the debugger if enabled.
#if( TARGET_OS_WIN32 )
if( gDebugBreakLevel <= kDebugLevelAssert )
{
if( IsDebuggerPresent() )
{
DebugBreak();
}
}
#endif
}
#if 0
#pragma mark -
#endif
#if( DEBUG_FPRINTF_ENABLED )
//===========================================================================================================================
// DebugFPrintFInit
//===========================================================================================================================
static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
{
OSStatus err;
DebugOutputTypeFlags typeFlags;
typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
if( typeFlags == kDebugOutputTypeFlagsStdOut )
{
#if( TARGET_OS_WIN32 )
DebugWinEnableConsole();
#endif
gDebugFPrintFFile = stdout;
}
else if( typeFlags == kDebugOutputTypeFlagsStdErr )
{
#if( TARGET_OS_WIN32 )
DebugWinEnableConsole();
#endif
gDebugFPrintFFile = stdout;
}
else if( typeFlags == kDebugOutputTypeFlagsFile )
{
require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
gDebugFPrintFFile = fopen( inFilename, "a" );
require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
}
else
{
err = kParamErr;
goto exit;
}
err = kNoErr;
exit:
return( err );
}
//===========================================================================================================================
// DebugFPrintFPrint
//===========================================================================================================================
static void DebugFPrintFPrint( char *inData, size_t inSize )
{
char * p;
char * q;
// Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
p = inData;
q = p + inSize;
while( p < q )
{
if( *p == '\r' )
{
*p = '\n';
}
++p;
}
// Write the data and flush.
if( gDebugFPrintFFile )
{
fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
fflush( gDebugFPrintFFile );
}
}
#endif // DEBUG_FPRINTF_ENABLED
#if( DEBUG_IDEBUG_ENABLED )
//===========================================================================================================================
// DebugiDebugInit
//===========================================================================================================================
static OSStatus DebugiDebugInit( void )
{
OSStatus err;
#if( TARGET_API_MAC_OSX_KERNEL )
extern uint32_t * _giDebugReserved1;
// Emulate the iDebugSetOutputType macro in iDebugServices.h.
// Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
if( !_giDebugReserved1 )
{
_giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
}
*_giDebugReserved1 = 0x00010000U;
err = kNoErr;
exit:
#else
__private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
iDebugSetOutputTypeInternal( 0x00010000U );
err = kNoErr;
#endif
return( err );
}
//===========================================================================================================================
// DebugiDebugPrint
//===========================================================================================================================
static void DebugiDebugPrint( char *inData, size_t inSize )
{
#if( TARGET_API_MAC_OSX_KERNEL )
// Locally declared here so we do not need to include iDebugKext.h.
// Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the
// KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
// _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
extern iDebugLogFunctionPtr _giDebugLogInternal;
if( _giDebugLogInternal )
{
_giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
}
#else
__private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
#endif
}
#endif
#if( DEBUG_KPRINTF_ENABLED )
//===========================================================================================================================
// DebugKPrintFPrint
//===========================================================================================================================
static void DebugKPrintFPrint( char *inData, size_t inSize )
{
extern void kprintf( const char *inFormat, ... );
kprintf( "%.*s", (int) inSize, inData );
}
#endif
#if( DEBUG_MAC_OS_X_IOLOG_ENABLED )
//===========================================================================================================================
// DebugMacOSXIOLogPrint
//===========================================================================================================================
static void DebugMacOSXIOLogPrint( char *inData, size_t inSize )
{
extern void IOLog( const char *inFormat, ... );
IOLog( "%.*s", (int) inSize, inData );
}
#endif
#if( TARGET_OS_MAC )
//===========================================================================================================================
// DebugMacOSXLogInit
//===========================================================================================================================
static OSStatus DebugMacOSXLogInit( void )
{
OSStatus err;
CFStringRef path;
CFURLRef url;
CFBundleRef bundle;
CFStringRef functionName;
void * functionPtr;
bundle = NULL;
// Create a bundle reference for System.framework.
path = CFSTR( "/System/Library/Frameworks/System.framework" );
url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
require_action_quiet( url, exit, err = memFullErr );
bundle = CFBundleCreate( NULL, url );
CFRelease( url );
require_action_quiet( bundle, exit, err = memFullErr );
// Get a ptr to the system's "printf" function from System.framework.
functionName = CFSTR( "printf" );
functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
require_action_quiet( functionPtr, exit, err = memFullErr );
// Success! Note: The bundle cannot be released because it would invalidate the function ptr.
gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
bundle = NULL;
err = noErr;
exit:
if( bundle )
{
CFRelease( bundle );
}
return( err );
}
//===========================================================================================================================
// DebugMacOSXLogPrint
//===========================================================================================================================
static void DebugMacOSXLogPrint( char *inData, size_t inSize )
{
if( gDebugMacOSXLogFunction )
{
gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
}
}
#endif
#if( TARGET_OS_WIN32 )
//===========================================================================================================================
// DebugWindowsDebuggerPrint
//===========================================================================================================================
void DebugWindowsDebuggerPrint( char *inData, size_t inSize )
{
TCHAR buffer[ 512 ];
const char * src;
const char * end;
TCHAR * dst;
char c;
// Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
// building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
src = inData;
if( inSize >= sizeof_array( buffer ) )
{
inSize = sizeof_array( buffer ) - 1;
}
end = src + inSize;
dst = buffer;
while( src < end )
{
c = *src++;
if( c == '\r' )
{
c = '\n';
}
*dst++ = (TCHAR) c;
}
*dst = 0;
// Print out the string to the debugger.
OutputDebugString( buffer );
}
#endif
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
//===========================================================================================================================
// DebugWindowsEventLogInit
//===========================================================================================================================
static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
{
OSStatus err;
HKEY key;
TCHAR name[ 128 ];
const char * src;
TCHAR path[ MAX_PATH ];
size_t size;
DWORD typesSupported;
DWORD n;
key = NULL;
// Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
if( !inName || ( *inName == '\0' ) )
{
inName = "DefaultApp";
}
DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
// Build the path string using the fixed registry path and app name.
src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
// Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
require_noerr_quiet( err, exit );
// Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
n = GetModuleFileName( inModule, path, sizeof_array( path ) );
err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
require_noerr_quiet( err, exit );
n += 1;
n *= sizeof( TCHAR );
err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
require_noerr_quiet( err, exit );
// Set the supported event types in the TypesSupported subkey.
typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
require_noerr_quiet( err, exit );
// Set up the event source.
gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
require_noerr_quiet( err, exit );
exit:
if( key )
{
RegCloseKey( key );
}
return( err );
}
//===========================================================================================================================
// DebugWindowsEventLogPrint
//===========================================================================================================================
static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
{
WORD type;
TCHAR buffer[ 512 ];
const char * src;
const char * end;
TCHAR * dst;
char c;
const TCHAR * array[ 1 ];
// Map the debug level to a Windows EventLog type.
if( inLevel <= kDebugLevelNotice )
{
type = EVENTLOG_INFORMATION_TYPE;
}
else if( inLevel <= kDebugLevelWarning )
{
type = EVENTLOG_WARNING_TYPE;
}
else
{
type = EVENTLOG_ERROR_TYPE;
}
// Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
// building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
src = inData;
if( inSize >= sizeof_array( buffer ) )
{
inSize = sizeof_array( buffer ) - 1;
}
end = src + inSize;
dst = buffer;
while( src < end )
{
c = *src++;
if( c == '\r' )
{
c = '\n';
}
*dst++ = (TCHAR) c;
}
*dst = 0;
// Add the the string to the event log.
array[ 0 ] = buffer;
if( gDebugWindowsEventLogEventSource )
{
ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
}
}
#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
#if( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
//===========================================================================================================================
// DebugAssertOutputHandler
//===========================================================================================================================
static pascal void
DebugAssertOutputHandler(
OSType inComponentSignature,
UInt32 inOptions,
const char * inAssertString,
const char * inExceptionString,
const char * inErrorString,
const char * inFileName,
long inLineNumber,
void * inValue,
ConstStr255Param inOutputMsg )
{
DEBUG_UNUSED( inComponentSignature );
DEBUG_UNUSED( inOptions );
DEBUG_UNUSED( inExceptionString );
DEBUG_UNUSED( inValue );
DEBUG_UNUSED( inOutputMsg );
DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
}
#endif
#if 0
#pragma mark -
#pragma mark == Utilities ==
#endif
//===========================================================================================================================
// DebugSNPrintF
//
// Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
//
// Changed names to avoid name collisions with the mDNS versions.
// Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
// Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
// Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
// Added %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
// Added %.8a - FIbre Channel address. Arg=ptr to address.
// Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
// Added %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
// Added %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
// Added %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
// Added %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
// Added %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
// Added %S - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
// Added %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
// Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
// Added %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
//===========================================================================================================================
DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
{
size_t length;
va_list ptr;
va_start(ptr,fmt);
length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
va_end(ptr);
return(length);
}
//===========================================================================================================================
// DebugSNPrintFVAList - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
//===========================================================================================================================
DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
{
static const struct DebugSNPrintF_format
{
unsigned leftJustify : 1;
unsigned forceSign : 1;
unsigned zeroPad : 1;
unsigned havePrecision : 1;
unsigned hSize : 1;
char lSize;
char altForm;
char sign; // +, - or space
unsigned int fieldWidth;
unsigned int precision;
} DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
size_t nwritten = 0;
int c;
if (buflen == 0) return(0);
buflen--; // Pre-reserve one space in the buffer for the terminating nul
if (buflen == 0) goto exit;
for (c = *fmt; c != 0; c = *++fmt)
{
if (c != '%')
{
*sbuffer++ = (char)c;
if (++nwritten >= buflen) goto exit;
}
else
{
size_t i=0, j;
// The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
// generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
// The size needs to be enough for a 256-byte domain name plus some error text.
#define mDNS_VACB_Size 300
char mDNS_VACB[mDNS_VACB_Size];
#define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
#define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
char *s = mDNS_VACB_Lim;
const char *digits = "0123456789ABCDEF";
struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
for(;;) // decode flags
{
c = *++fmt;
if (c == '-') F.leftJustify = 1;
else if (c == '+') F.forceSign = 1;
else if (c == ' ') F.sign = ' ';
else if (c == '#') F.altForm++;
else if (c == '0') F.zeroPad = 1;
else break;
}
if (c == '*') // decode field width
{
int f = va_arg(arg, int);
if (f < 0) { f = -f; F.leftJustify = 1; }
F.fieldWidth = (unsigned int)f;
c = *++fmt;
}
else
{
for (; c >= '0' && c <= '9'; c = *++fmt)
F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
}
if (c == '.') // decode precision
{
if ((c = *++fmt) == '*')
{ F.precision = va_arg(arg, unsigned int); c = *++fmt; }
else for (; c >= '0' && c <= '9'; c = *++fmt)
F.precision = (10 * F.precision) + (c - '0');
F.havePrecision = 1;
}
if (F.leftJustify) F.zeroPad = 0;
conv:
switch (c) // perform appropriate conversion
{
#if TYPE_LONGLONG_NATIVE
unsigned_long_long_compat n;
unsigned_long_long_compat base;
#else
unsigned long n;
unsigned long base;
#endif
case 'h' : F.hSize = 1; c = *++fmt; goto conv;
case 'l' : // fall through
case 'L' : F.lSize++; c = *++fmt; goto conv;
case 'd' :
case 'i' : base = 10;
goto canBeSigned;
case 'u' : base = 10;
goto notSigned;
case 'o' : base = 8;
goto notSigned;
case 'b' : base = 2;
goto notSigned;
case 'p' : n = va_arg(arg, uintptr_t);
F.havePrecision = 1;
F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
F.sign = 0;
base = 16;
c = 'x';
goto number;
case 'x' : digits = "0123456789abcdef";
case 'X' : base = 16;
goto notSigned;
canBeSigned:
#if TYPE_LONGLONG_NATIVE
if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
else n = (unsigned_long_long_compat)va_arg(arg, int);
#else
if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
else if (F.lSize == 2) goto exit;
else n = (unsigned long)va_arg(arg, int);
#endif
if (F.hSize) n = (short) n;
#if TYPE_LONGLONG_NATIVE
if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
#else
if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
#endif
else if (F.forceSign) F.sign = '+';
goto number;
notSigned: if (F.lSize == 1) n = va_arg(arg, unsigned long);
else if (F.lSize == 2)
{
#if TYPE_LONGLONG_NATIVE
n = va_arg(arg, unsigned_long_long_compat);
#else
goto exit;
#endif
}
else n = va_arg(arg, unsigned int);
if (F.hSize) n = (unsigned short) n;
F.sign = 0;
goto number;
number: if (!F.havePrecision)
{
if (F.zeroPad)
{
F.precision = F.fieldWidth;
if (F.altForm) F.precision -= 2;
if (F.sign) --F.precision;
}
if (F.precision < 1) F.precision = 1;
}
if (F.precision > mDNS_VACB_Size - 1)
F.precision = mDNS_VACB_Size - 1;
for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
for (; i < F.precision; i++) *--s = '0';
if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
if (F.sign) { *--s = F.sign; i++; }
break;
case 'a' : {
unsigned char *a = va_arg(arg, unsigned char *);
char pre[4] = "";
char post[32] = "";
if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
else
{
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
if (F.altForm == 1)
{
#if(defined(MDNS_DEBUGMSGS))
mDNSAddr *ip = (mDNSAddr*)a;
switch (ip->type)
{
case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
default: F.precision = 0; break;
}
#else
F.precision = 0; // mDNSEmbeddedAPI.h not included so no mDNSAddr support
#endif
}
else if (F.altForm == 2)
{
#ifdef AF_INET
const struct sockaddr *sa;
unsigned char *port;
sa = (const struct sockaddr*)a;
switch (sa->sa_family)
{
case AF_INET: F.precision = 4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
#ifdef AF_INET6
case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr;
pre[0] = '['; pre[1] = '\0';
port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
DebugSNPrintF(post, sizeof(post), "%%%d]:%d",
(int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
(port[0] << 8) | port[1]); break;
#endif
default: F.precision = 0; break;
}
#else
F.precision = 0; // socket interfaces not included so no sockaddr support
#endif
}
switch (F.precision)
{
case 4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
a[0], a[1], a[2], a[3], post); break;
case 6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
a[0], a[1], a[2], a[3], a[4], a[5]); break;
case 8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB),
"%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;
default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
"(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
}
}
}
break;
case 'U' : {
unsigned char *a = va_arg(arg, unsigned char *);
if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
else
{
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
*((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]),
a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
}
}
break;
case 'c' : *--s = (char)va_arg(arg, int); i = 1; break;
case 'C' : if (F.lSize) n = va_arg(arg, unsigned long);
else n = va_arg(arg, unsigned int);
if (F.hSize) n = (unsigned short) n;
c = (int)( n & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
c = (int)((n >> 8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
i = 4;
break;
case 's' : s = va_arg(arg, char *);
if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
else switch (F.altForm)
{
case 0: i=0;
if (F.havePrecision) // C string
{
while((i < F.precision) && s[i]) i++;
// Make sure we don't truncate in the middle of a UTF-8 character.
// If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
j=0;
while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break; }
// If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
if((j > 1) && (j <= 6))
{
int test = (0xFF << (8-j)) & 0xFF;
int mask = test | (1 << ((8-j)-1));
if((c & mask) == test) i += j;
}
}
else
while(s[i]) i++;
break;
case 1: i = (unsigned char) *s++; break; // Pascal string
case 2: { // DNS label-sequence name
unsigned char *a = (unsigned char *)s;
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
if (*a == 0) *s++ = '.'; // Special case for root DNS name
while (*a)
{
if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
a += 1 + *a;
}
i = (size_t)(s - mDNS_VACB);
s = mDNS_VACB; // Reset s back to the start of the buffer
break;
}
}
if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
{ i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
break;
case 'S': { // UTF-16 string
unsigned char *a = va_arg(arg, unsigned char *);
uint16_t *u = (uint16_t*)a;
if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
if ((!F.havePrecision || F.precision))
{
if ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; } // Big Endian
else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; } // Little Endian
}
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
switch (F.altForm)
{
case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Host Endian
{ c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
break;
case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Big Endian
{ c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
break;
case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Little Endian
{ c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
break;
}
}
s = mDNS_VACB; // Reset s back to the start of the buffer
break;
#if TARGET_OS_MAC
case '@': { // Cocoa/CoreFoundation object
CFTypeRef cfObj;
CFStringRef cfStr;
cfObj = (CFTypeRef) va_arg(arg, void *);
cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
if (cfStr)
{
CFRange range;
CFIndex m;
range = CFRangeMake(0, CFStringGetLength(cfStr));
m = 0;
CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
CFRelease(cfStr);
i = (size_t) m;
}
else
{
i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
}
}
if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
{ i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
break;
#endif
case 'm' : { // Error Message
long err;
if (F.lSize) err = va_arg(arg, long);
else err = va_arg(arg, int);
if (F.hSize) err = (short)err;
DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
for(i=0;s[i];i++) {}
}
break;
case 'H' : { // Hex Dump
void *a = va_arg(arg, void *);
size_t size = (size_t)va_arg(arg, int);
size_t max = (size_t)va_arg(arg, int);
DebugFlags flags =
kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
size = (max < size) ? max : size;
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
}
break;
case 'v' : { // Version
uint32_t version;
version = va_arg(arg, unsigned int);
DebugNumVersionToString(version, mDNS_VACB);
s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
for(i=0;s[i];i++) {}
}
break;
case 'n' : s = va_arg(arg, char *);
if (F.hSize) * (short *) s = (short)nwritten;
else if (F.lSize) * (long *) s = (long)nwritten;
else * (int *) s = (int)nwritten;
continue;
default: s = mDNS_VACB;
i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
case '%' : *sbuffer++ = (char)c;
if (++nwritten >= buflen) goto exit;
break;
}
if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
do {
*sbuffer++ = ' ';
if (++nwritten >= buflen) goto exit;
} while (i < --F.fieldWidth);
if (i > buflen - nwritten) // Make sure we don't truncate in the middle of a UTF-8 character
{ i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
nwritten += i;
if (nwritten >= buflen) goto exit;
for (; i < F.fieldWidth; i++) // Pad on the right
{
*sbuffer++ = ' ';
if (++nwritten >= buflen) goto exit;
}
}
}
exit:
*sbuffer++ = 0;
return(nwritten);
}
//===========================================================================================================================
// DebugGetErrorString
//===========================================================================================================================
DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
{
const char * s;
char * dst;
char * end;
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
char buffer[ 256 ];
#endif
switch( inErrorCode )
{
#define CaseErrorString( X, STR ) case X: s = STR; break
#define CaseErrorStringify( X ) case X: s = # X; break
#define CaseErrorStringifyHardCode( VALUE, X ) case VALUE: s = # X; break
// General Errors
CaseErrorString( 0, "no error" );
CaseErrorString( 1, "in-progress/waiting" );
CaseErrorString( -1, "catch-all unknown error" );
// ACP Errors
CaseErrorStringifyHardCode( -2, kACPBadRequestErr );
CaseErrorStringifyHardCode( -3, kACPNoMemoryErr );
CaseErrorStringifyHardCode( -4, kACPBadParamErr );
CaseErrorStringifyHardCode( -5, kACPNotFoundErr );
CaseErrorStringifyHardCode( -6, kACPBadChecksumErr );
CaseErrorStringifyHardCode( -7, kACPCommandNotHandledErr );
CaseErrorStringifyHardCode( -8, kACPNetworkErr );
CaseErrorStringifyHardCode( -9, kACPDuplicateCommandHandlerErr );
CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
CaseErrorStringifyHardCode( -23, kACPInUseErr );
CaseErrorStringifyHardCode( -24, kACPParamCountErr );
CaseErrorStringifyHardCode( -25, kACPIDErr );
CaseErrorStringifyHardCode( -26, kACPFormatErr );
CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
// Common Services Errors
CaseErrorStringify( kUnknownErr );
CaseErrorStringify( kOptionErr );
CaseErrorStringify( kSelectorErr );
CaseErrorStringify( kExecutionStateErr );
CaseErrorStringify( kPathErr );
CaseErrorStringify( kParamErr );
CaseErrorStringify( kParamCountErr );
CaseErrorStringify( kCommandErr );
CaseErrorStringify( kIDErr );
CaseErrorStringify( kStateErr );
CaseErrorStringify( kRangeErr );
CaseErrorStringify( kRequestErr );
CaseErrorStringify( kResponseErr );
CaseErrorStringify( kChecksumErr );
CaseErrorStringify( kNotHandledErr );
CaseErrorStringify( kVersionErr );
CaseErrorStringify( kSignatureErr );
CaseErrorStringify( kFormatErr );
CaseErrorStringify( kNotInitializedErr );
CaseErrorStringify( kAlreadyInitializedErr );
CaseErrorStringify( kNotInUseErr );
CaseErrorStringify( kInUseErr );
CaseErrorStringify( kTimeoutErr );
CaseErrorStringify( kCanceledErr );
CaseErrorStringify( kAlreadyCanceledErr );
CaseErrorStringify( kCannotCancelErr );
CaseErrorStringify( kDeletedErr );
CaseErrorStringify( kNotFoundErr );
CaseErrorStringify( kNoMemoryErr );
CaseErrorStringify( kNoResourcesErr );
CaseErrorStringify( kDuplicateErr );
CaseErrorStringify( kImmutableErr );
CaseErrorStringify( kUnsupportedDataErr );
CaseErrorStringify( kIntegrityErr );
CaseErrorStringify( kIncompatibleErr );
CaseErrorStringify( kUnsupportedErr );
CaseErrorStringify( kUnexpectedErr );
CaseErrorStringify( kValueErr );
CaseErrorStringify( kNotReadableErr );
CaseErrorStringify( kNotWritableErr );
CaseErrorStringify( kBadReferenceErr );
CaseErrorStringify( kFlagErr );
CaseErrorStringify( kMalformedErr );
CaseErrorStringify( kSizeErr );
CaseErrorStringify( kNameErr );
CaseErrorStringify( kNotReadyErr );
CaseErrorStringify( kReadErr );
CaseErrorStringify( kWriteErr );
CaseErrorStringify( kMismatchErr );
CaseErrorStringify( kDateErr );
CaseErrorStringify( kUnderrunErr );
CaseErrorStringify( kOverrunErr );
CaseErrorStringify( kEndingErr );
CaseErrorStringify( kConnectionErr );
CaseErrorStringify( kAuthenticationErr );
CaseErrorStringify( kOpenErr );
CaseErrorStringify( kTypeErr );
CaseErrorStringify( kSkipErr );
CaseErrorStringify( kNoAckErr );
CaseErrorStringify( kCollisionErr );
CaseErrorStringify( kBackoffErr );
CaseErrorStringify( kNoAddressAckErr );
CaseErrorStringify( kBusyErr );
CaseErrorStringify( kNoSpaceErr );
// mDNS/DNS-SD Errors
CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
// RSP Errors
CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
CaseErrorStringifyHardCode( -400050, kRSPParamErr );
CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );
CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
CaseErrorStringifyHardCode( -402419, kRSPIDErr );
CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
CaseErrorString( -200000, "kRSPControllerStatusBase - 0x50" );
CaseErrorString( -200080, "kRSPCommandSucceededErr - 0x50" );
CaseErrorString( -200001, "kRSPCommandFailedErr - 0x01" );
CaseErrorString( -200051, "kRSPChecksumErr - 0x33" );
CaseErrorString( -200132, "kRSPCommandTimeoutErr - 0x84" );
CaseErrorString( -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
CaseErrorString( -200128, "kRSPCanceledErr - 0x02 Async" );
// XML Errors
CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
CaseErrorStringifyHardCode( -100050, kXMLParamErr );
CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
CaseErrorStringifyHardCode( -103026, kXMLParseErr );
CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
CaseErrorStringifyHardCode( -102015, kXMLDateErr );
#if( __MACH__ )
// Mach Errors
CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
// Mach OSReturn Errors
CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
// IOKit Errors
CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError );
CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion );
CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted );
CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth );
CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding );
CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld );
CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew );
CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
// IOKit FireWire Errors
CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
// IOKit USB Errors
CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
#endif // __MACH__
// Other Errors
default:
s = NULL;
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
if( inBuffer && ( inBufferSize > 0 ) )
{
DWORD n;
n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL );
if( n > 0 )
{
// Remove any trailing CR's or LF's since some messages have them.
while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) )
{
buffer[ --n ] = '\0';
}
s = buffer;
}
}
#endif
if( !s )
{
#if( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
s = strerror( inErrorCode );
#endif
if( !s )
{
s = "<unknown error code>";
}
}
break;
}
// Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
if( inBuffer && ( inBufferSize > 0 ) )
{
dst = inBuffer;
end = dst + ( inBufferSize - 1 );
while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
{
*dst++ = *s++;
}
*dst = '\0';
s = inBuffer;
}
return( s );
}
//===========================================================================================================================
// DebugHexDump
//===========================================================================================================================
DEBUG_EXPORT size_t
DebugHexDump(
DebugLevel inLevel,
int inIndent,
const char * inLabel,
size_t inLabelSize,
int inLabelMinWidth,
const char * inType,
size_t inTypeSize,
const void * inDataStart,
const void * inData,
size_t inDataSize,
DebugFlags inFlags,
char * outBuffer,
size_t inBufferSize )
{
static const char kHexChars[] = "0123456789ABCDEF";
const uint8_t * start;
const uint8_t * src;
char * dst;
char * end;
size_t n;
int offset;
int width;
const char * newline;
char separator[ 8 ];
char * s;
DEBUG_UNUSED( inType );
DEBUG_UNUSED( inTypeSize );
// Set up the function-wide variables.
if( inLabelSize == kSizeCString )
{
inLabelSize = strlen( inLabel );
}
start = (const uint8_t *) inData;
src = start;
dst = outBuffer;
end = dst + inBufferSize;
offset = (int)( (intptr_t) inData - (intptr_t) inDataStart );
width = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
// Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
s = separator;
if( inFlags & kDebugFlagsNoNewLine )
{
if( inFlags & kDebugFlags8BitSeparator )
{
*s++ = ' ';
}
if( inFlags & kDebugFlags16BitSeparator )
{
*s++ = ' ';
}
if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
{
*s++ = ' ';
}
check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
}
*s = '\0';
for( ;; )
{
char prefixString[ 32 ];
char hexString[ 64 ];
char asciiString[ 32 ];
char byteCountString[ 32 ];
int c;
size_t chunkSize;
size_t i;
// If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
if( inDataSize == 0 )
{
if( inLabel && ( inLabelSize > 0 ) )
{
width = 0;
if( !( inFlags & kDebugFlagsNoAddress ) )
{
width += 8; // "00000000"
if( !( inFlags & kDebugFlagsNoOffset ) )
{
width += 1; // "+"
}
}
if( inFlags & kDebugFlags32BitOffset )
{
width += 8; // "00000000"
}
else if( !( inFlags & kDebugFlagsNoOffset ) )
{
width += 4; // "0000"
}
if( outBuffer )
{
dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s",
width, "",
( width > 0 ) ? ": " : "",
width, (int) inLabelSize, inLabel,
newline );
}
else
{
dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s",
width, "",
( width > 0 ) ? ": " : "",
width, (int) inLabelSize, inLabel,
newline );
}
}
break;
}
// Build the prefix string. It will be in one of the following formats:
//
// 1) "00000000+0000[0000]" (address and offset)
// 2) "00000000" (address only)
// 3) "0000[0000]" (offset only)
// 4) "" (no address or offset)
//
// Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
s = prefixString;
if( !( inFlags & kDebugFlagsNoAddress ) )
{
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 8 ) & 0xF ];
*s++ = kHexChars[ ( ( (uintptr_t) src ) >> 4 ) & 0xF ];
*s++ = kHexChars[ ( (uintptr_t) src ) & 0xF ];
if( !( inFlags & kDebugFlagsNoOffset ) )
{
*s++ = '+';
}
}
if( !( inFlags & kDebugFlagsNoOffset ) )
{
if( inFlags & kDebugFlags32BitOffset )
{
*s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
*s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
*s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
*s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
}
*s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
*s++ = kHexChars[ ( offset >> 8 ) & 0xF ];
*s++ = kHexChars[ ( offset >> 4 ) & 0xF ];
*s++ = kHexChars[ offset & 0xF ];
}
if( s != prefixString )
{
*s++ = ':';
*s++ = ' ';
}
check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
*s = '\0';
// Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
// Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
s = hexString;
chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
for( i = 0; i < n; ++i )
{
if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
{
*s++ = ' ';
}
if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
{
*s++ = ' ';
}
if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
{
*s++ = ' ';
}
if( i < chunkSize )
{
*s++ = kHexChars[ src[ i ] >> 4 ];
*s++ = kHexChars[ src[ i ] & 0xF ];
}
else
{
*s++ = ' ';
*s++ = ' ';
}
}
check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
*s = '\0';
// Build a string with the ASCII version of the data (replaces non-printable characters with '^').
// Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
s = asciiString;
if( !( inFlags & kDebugFlagsNoASCII ) )
{
*s++ = ' ';
*s++ = '|';
for( i = 0; i < n; ++i )
{
if( i < chunkSize )
{
c = src[ i ];
if( !DebugIsPrint( c ) )
{
c = '^';
}
}
else
{
c = '`';
}
*s++ = (char) c;
}
*s++ = '|';
check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
}
*s = '\0';
// Build a string indicating how bytes are in the hex dump. Only printed on the first line.
s = byteCountString;
if( !( inFlags & kDebugFlagsNoByteCount ) )
{
if( src == start )
{
s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
}
}
check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
*s = '\0';
// Build the entire line from all the pieces we've previously built.
if( outBuffer )
{
if( src == start )
{
dst += DebugSNPrintF( dst, (size_t)( end - dst ),
"%*s" // Indention
"%s" // Separator (only if needed)
"%s" // Prefix
"%-*.*s" // Label
"%s" // Separator
"%s" // Hex
"%s" // ASCII
"%s" // Byte Count
"%s", // Newline
inIndent, "",
( src != start ) ? separator : "",
prefixString,
width, (int) inLabelSize, inLabel ? inLabel : "",
( width > 0 ) ? " " : "",
hexString,
asciiString,
byteCountString,
newline );
}
else
{
dst += DebugSNPrintF( dst, (size_t)( end - dst ),
"%*s" // Indention
"%s" // Separator (only if needed)
"%s" // Prefix
"%*s" // Label Spacing
"%s" // Separator
"%s" // Hex
"%s" // ASCII
"%s" // Byte Count
"%s", // Newline
inIndent, "",
( src != start ) ? separator : "",
prefixString,
width, "",
( width > 0 ) ? " " : "",
hexString,
asciiString,
byteCountString,
newline );
}
}
else
{
if( src == start )
{
dst += DebugPrintF( inLevel,
"%*s" // Indention
"%s" // Separator (only if needed)
"%s" // Prefix
"%-*.*s" // Label
"%s" // Separator
"%s" // Hex
"%s" // ASCII
"%s" // Byte Count
"%s", // Newline
inIndent, "",
( src != start ) ? separator : "",
prefixString,
width, (int) inLabelSize, inLabel,
( width > 0 ) ? " " : "",
hexString,
asciiString,
byteCountString,
newline );
}
else
{
dst += DebugPrintF( inLevel,
"%*s" // Indention
"%s" // Separator (only if needed)
"%s" // Prefix
"%*s" // Label Spacing
"%s" // Separator
"%s" // Hex
"%s" // ASCII
"%s" // Byte Count
"%s", // Newline
inIndent, "",
( src != start ) ? separator : "",
prefixString,
width, "",
( width > 0 ) ? " " : "",
hexString,
asciiString,
byteCountString,
newline );
}
}
// Move to the next chunk. Exit if there is no more data.
offset += (int) chunkSize;
src += chunkSize;
inDataSize -= chunkSize;
if( inDataSize == 0 )
{
break;
}
}
// Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
return( (size_t)( dst - outBuffer ) );
}
//===========================================================================================================================
// DebugNumVersionToString
//===========================================================================================================================
static char * DebugNumVersionToString( uint32_t inVersion, char *inString )
{
char * s;
uint8_t majorRev;
uint8_t minor;
uint8_t bugFix;
uint8_t stage;
uint8_t revision;
check( inString );
majorRev = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
minor = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
bugFix = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
stage = (uint8_t)( ( inVersion >> 8 ) & 0xFF );
revision = (uint8_t)( inVersion & 0xFF );
// Convert the major, minor, and bugfix numbers.
s = inString;
s += sprintf( s, "%u", majorRev );
s += sprintf( s, ".%u", minor );
if( bugFix != 0 )
{
s += sprintf( s, ".%u", bugFix );
}
// Convert the version stage and non-release revision number.
switch( stage )
{
case kVersionStageDevelopment:
s += sprintf( s, "d%u", revision );
break;
case kVersionStageAlpha:
s += sprintf( s, "a%u", revision );
break;
case kVersionStageBeta:
s += sprintf( s, "b%u", revision );
break;
case kVersionStageFinal:
// A non-release revision of zero is a special case indicating the software is GM (at the golden master
// stage) and therefore, the non-release revision should not be added to the string.
if( revision != 0 )
{
s += sprintf( s, "f%u", revision );
}
break;
default:
dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
break;
}
return( inString );
}
//===========================================================================================================================
// DebugTaskLevel
//===========================================================================================================================
DEBUG_EXPORT uint32_t DebugTaskLevel( void )
{
uint32_t level;
level = 0;
#if( TARGET_OS_VXWORKS )
if( intContext() )
{
level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
}
#endif
return( level );
}
#if( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
//===========================================================================================================================
// DebugWinEnableConsole
//===========================================================================================================================
#pragma warning( disable:4311 )
static void DebugWinEnableConsole( void )
{
static bool sConsoleEnabled = false;
BOOL result;
int fileHandle;
FILE * file;
int err;
if( sConsoleEnabled )
{
goto exit;
}
// Create console window.
result = AllocConsole();
require_quiet( result, exit );
// Redirect stdin to the console stdin.
fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
#if( defined( __MWERKS__ ) )
file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
require_quiet( file, exit );
#else
file = _fdopen( fileHandle, "r" );
require_quiet( file, exit );
*stdin = *file;
#endif
err = setvbuf( stdin, NULL, _IONBF, 0 );
require_noerr_quiet( err, exit );
// Redirect stdout to the console stdout.
fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
#if( defined( __MWERKS__ ) )
file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
require_quiet( file, exit );
#else
file = _fdopen( fileHandle, "w" );
require_quiet( file, exit );
*stdout = *file;
#endif
err = setvbuf( stdout, NULL, _IONBF, 0 );
require_noerr_quiet( err, exit );
// Redirect stderr to the console stdout.
fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
#if( defined( __MWERKS__ ) )
file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
require_quiet( file, exit );
#else
file = _fdopen( fileHandle, "w" );
require_quiet( file, exit );
*stderr = *file;
#endif
err = setvbuf( stderr, NULL, _IONBF, 0 );
require_noerr_quiet( err, exit );
sConsoleEnabled = true;
exit:
return;
}
#pragma warning( default:4311 )
#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
#if( TARGET_OS_WIN32 )
//===========================================================================================================================
// DebugWinCharToTCharString
//===========================================================================================================================
static TCHAR *
DebugWinCharToTCharString(
const char * inCharString,
size_t inCharCount,
TCHAR * outTCharString,
size_t inTCharCountMax,
size_t * outTCharCount )
{
const char * src;
TCHAR * dst;
TCHAR * end;
if( inCharCount == kSizeCString )
{
inCharCount = strlen( inCharString );
}
src = inCharString;
dst = outTCharString;
if( inTCharCountMax > 0 )
{
inTCharCountMax -= 1;
if( inTCharCountMax > inCharCount )
{
inTCharCountMax = inCharCount;
}
end = dst + inTCharCountMax;
while( dst < end )
{
*dst++ = (TCHAR) *src++;
}
*dst = 0;
}
if( outTCharCount )
{
*outTCharCount = (size_t)( dst - outTCharString );
}
return( outTCharString );
}
#endif
#if