| /* -*- 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 0 |
| #pragma mark - |
| #pragma mark == Debugging == |
| #endif |
| |
| //=========================================================================================================================== |
| // DebugServicesTest |
| //=========================================================================================================================== |
| |
| DEBUG_EXPORT OSStatus DebugServicesTest( void ) |
| { |
| OSStatus err; |
| char s[ 512 ]; |
| uint8_t * p; |
| uint8_t data[] = |
| { |
| 0x11, 0x22, 0x33, 0x44, |
| 0x55, 0x66, |
| 0x77, 0x88, 0x99, 0xAA, |
| 0xBB, 0xCC, 0xDD, |
| 0xEE, |
| 0xFF, |
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, |
| 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, |
| 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1 |
| }; |
| |
| debug_initialize( kDebugOutputTypeMetaConsole ); |
| |
| // check's |
| |
| check( 0 && "SHOULD SEE: check" ); |
| check( 1 && "SHOULD *NOT* SEE: check (valid)" ); |
| check_string( 0, "SHOULD SEE: check_string" ); |
| check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" ); |
| check_noerr( -123 ); |
| check_noerr( 10038 ); |
| check_noerr( 22 ); |
| check_noerr( 0 ); |
| check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" ); |
| check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" ); |
| check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 ); |
| check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 ); |
| check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 ); |
| check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 ); |
| check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 5, 10 ); |
| check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12, 6 ); |
| check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 6, 10, 10 ); |
| check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 ); |
| check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 ); |
| check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 ); |
| check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 ); |
| |
| // require's |
| |
| require( 0 && "SHOULD SEE", require1 ); |
| { err = kResponseErr; goto exit; } |
| require1: |
| require( 1 && "SHOULD *NOT* SEE", require2 ); |
| goto require2Good; |
| require2: |
| { err = kResponseErr; goto exit; } |
| require2Good: |
| require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" ); |
| { err = kResponseErr; goto exit; } |
| require3: |
| require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" ); |
| goto require4Good; |
| require4: |
| { err = kResponseErr; goto exit; } |
| require4Good: |
| require_quiet( 0 && "SHOULD SEE", require5 ); |
| { err = kResponseErr; goto exit; } |
| require5: |
| require_quiet( 1 && "SHOULD *NOT* SEE", require6 ); |
| goto require6Good; |
| require6: |
| { err = kResponseErr; goto exit; } |
| require6Good: |
| require_noerr( -1, require7 ); |
| { err = kResponseErr; goto exit; } |
| require7: |
| require_noerr( 0, require8 ); |
| goto require8Good; |
| require8: |
| { err = kResponseErr; goto exit; } |
| require8Good: |
| require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string"); |
| { err = kResponseErr; goto exit; } |
| require9: |
| require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" ); |
| goto require10Good; |
| require10: |
| { err = kResponseErr; goto exit; } |
| require10Good: |
| require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" ); |
| { err = kResponseErr; goto exit; } |
| require11: |
| require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" ); |
| goto require12Good; |
| require12: |
| { err = kResponseErr; goto exit; } |
| require12Good: |
| require_noerr_quiet( -4, require13 ); |
| { err = kResponseErr; goto exit; } |
| require13: |
| require_noerr_quiet( 0, require14 ); |
| goto require14Good; |
| require14: |
| { err = kResponseErr; goto exit; } |
| require14Good: |
| require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) ); |
| { err = kResponseErr; goto exit; } |
| require15: |
| require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) ); |
| goto require16Good; |
| require16: |
| { err = kResponseErr; goto exit; } |
| require16Good: |
| require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) ); |
| { err = kResponseErr; goto exit; } |
| require17: |
| require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) ); |
| goto require18Good; |
| require18: |
| { err = kResponseErr; goto exit; } |
| require18Good: |
| require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) ); |
| { err = kResponseErr; goto exit; } |
| require19: |
| require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) ); |
| goto require20Good; |
| require20: |
| { err = kResponseErr; goto exit; } |
| require20Good: |
| require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) ); |
| { err = kResponseErr; goto exit; } |
| require21: |
| require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) ); |
| goto require22Good; |
| require22: |
| { err = kResponseErr; goto exit; } |
| require22Good: |
| require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" ); |
| { err = kResponseErr; goto exit; } |
| require23: |
| require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" ); |
| goto require24Good; |
| require24: |
| { err = kResponseErr; goto exit; } |
| require24Good: |
| |
| #if( defined( __MWERKS__ ) ) |
| #if( defined( __cplusplus ) && __option( exceptions ) ) |
| #define COMPILER_HAS_EXCEPTIONS 1 |
| #else |
| #define COMPILER_HAS_EXCEPTIONS 0 |
| #endif |
| #else |
| #if( defined( __cplusplus ) ) |
| #define COMPILER_HAS_EXCEPTIONS 1 |
| #else |
| #define COMPILER_HAS_EXCEPTIONS 0 |
| #endif |
| #endif |
| |
| #if( COMPILER_HAS_EXCEPTIONS ) |
| try |
| { |
| require_throw( 1 && "SHOULD *NOT* SEE" ); |
| require_throw( 0 && "SHOULD SEE" ); |
| } |
| catch( ... ) |
| { |
| goto require26Good; |
| } |
| { err = kResponseErr; goto exit; } |
| require26Good: |
| #endif |
| |
| // translate_errno |
| |
| err = translate_errno( 1 != -1, -123, -567 ); |
| require( ( err == 0 ) && "SHOULD *NOT* SEE", exit ); |
| |
| err = translate_errno( -1 != -1, -123, -567 ); |
| require( ( err == -123 ) && "SHOULD *NOT* SEE", exit ); |
| |
| err = translate_errno( -1 != -1, 0, -567 ); |
| require( ( err == -567 ) && "SHOULD *NOT* SEE", exit ); |
| |
| // debug_string |
| |
| debug_string( "debug_string" ); |
| |
| // DebugSNPrintF |
| |
| DebugSNPrintF( s, sizeof( s ), "%d", 1234 ); |
| require_action( strcmp( s, "1234" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 ); |
| require_action( strcmp( s, "2345" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" ); |
| require_action( strcmp( s, "test" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" ); |
| require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) ); |
| require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) ); |
| require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 ); |
| |
| #if( TYPE_LONGLONG_NATIVE ) |
| DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) ); |
| require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) ); |
| require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) ); |
| require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 ); |
| #endif |
| |
| DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) ); |
| require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 ); // 'AbCd' |
| require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 ); |
| |
| #if( defined( MDNS_DEBUGMSGS ) ) |
| { |
| mDNSAddr maddr; |
| |
| memset( &maddr, 0, sizeof( maddr ) ); |
| maddr.type = mDNSAddrType_IPv4; |
| maddr.ip.v4.b[ 0 ] = 127; |
| maddr.ip.v4.b[ 1 ] = 0; |
| maddr.ip.v4.b[ 2 ] = 0; |
| maddr.ip.v4.b[ 3 ] = 1; |
| DebugSNPrintF( s, sizeof( s ), "%#a", &maddr ); |
| require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 ); |
| |
| memset( &maddr, 0, sizeof( maddr ) ); |
| maddr.type = mDNSAddrType_IPv6; |
| maddr.ip.v6.b[ 0 ] = 0xFE; |
| maddr.ip.v6.b[ 1 ] = 0x80; |
| maddr.ip.v6.b[ 15 ] = 0x01; |
| DebugSNPrintF( s, sizeof( s ), "%#a", &maddr ); |
| require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 ); |
| } |
| #endif |
| |
| #if( AF_INET ) |
| { |
| struct sockaddr_in sa4; |
| |
| memset( &sa4, 0, sizeof( sa4 ) ); |
| sa4.sin_family = AF_INET; |
| p = (uint8_t *) &sa4.sin_port; |
| p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF ); |
| p[ 1 ] = (uint8_t)( 80 & 0xFF ); |
| p = (uint8_t *) &sa4.sin_addr.s_addr; |
| p[ 0 ] = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF ); |
| p[ 1 ] = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF ); |
| p[ 2 ] = (uint8_t)( ( INADDR_LOOPBACK >> 8 ) & 0xFF ); |
| p[ 3 ] = (uint8_t)( INADDR_LOOPBACK & 0xFF ); |
| DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 ); |
| require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 ); |
| } |
| #endif |
| |
| #if( AF_INET6 ) |
| { |
| struct sockaddr_in6 sa6; |
| |
| memset( &sa6, 0, sizeof( sa6 ) ); |
| sa6.sin6_family = AF_INET6; |
| p = (uint8_t *) &sa6.sin6_port; |
| p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF ); |
| p[ 1 ] = (uint8_t)( 80 & 0xFF ); |
| sa6.sin6_addr.s6_addr[ 0 ] = 0xFE; |
| sa6.sin6_addr.s6_addr[ 1 ] = 0x80; |
| sa6.sin6_addr.s6_addr[ 15 ] = 0x01; |
| sa6.sin6_scope_id = 2; |
| DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 ); |
| require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 ); |
| } |
| #endif |
| |
| // Unicode |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" ); |
| require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" ); |
| require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" ); |
| require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" ); |
| require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" ); |
| require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" ); |
| require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" ); |
| require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" ); |
| require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" ); |
| require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" ); |
| require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" ); |
| require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" ); |
| require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); |
| |
| DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" ); |
| require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr ); |
| |
| #if( TARGET_RT_BIG_ENDIAN ) |
| DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); |
| require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); |
| #else |
| DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); |
| require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); |
| #endif |
| |
| DebugSNPrintF( s, sizeof( s ), "%S", |
| "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM |
| require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%S", |
| "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM |
| require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian |
| require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian |
| require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%.*S", |
| 4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian BOM |
| require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%.*S", |
| 4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian BOM |
| require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); |
| |
| #if( TARGET_RT_BIG_ENDIAN ) |
| DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); |
| require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); |
| #else |
| DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); |
| require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); |
| #endif |
| |
| DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian |
| require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian |
| require_action( strcmp( s, "abc" ) == 0, exit, err = -1 ); |
| |
| // Misc |
| |
| DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" ); |
| require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%m", 0 ); |
| require_action( strcmp( s, "no error" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 ); |
| require_action( strcmp( s, "no error" ) == 0, exit, err = -1 ); |
| |
| DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 ); |
| DebugPrintF( kDebugLevelMax, "%s\n\n", s ); |
| |
| DebugSNPrintF( s, sizeof( s ), "\"%H\"", |
| "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" |
| "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", |
| 32, 32 ); |
| DebugPrintF( kDebugLevelMax, "%s\n\n", s ); |
| |
| DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 ); |
| DebugPrintF( kDebugLevelMax, "%s\n\n", s ); |
| |
| // Hex Dumps |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNone, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoAddress, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoOffset, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoAddress, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoOffset, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoByteCount, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4, // 'AbCd' |
| kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine | |
| kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, |
| s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), |
| kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine | |
| kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator | |
| kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| s[ 0 ] = '\0'; |
| DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) ); |
| DebugPrintF( kDebugLevelMax, "%s\n", s ); |
| |
| // dlog's |
| |
| dlog( kDebugLevelNotice, "dlog\n" ); |
| dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 ); |
| dlog( kDebugLevelNotice, "dlog string: \"%s\"\n", "test string" ); |
| dlogmem( kDebugLevelNotice, data, sizeof( data ) ); |
| |
| // Done |
| |
| DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" ); |
| err = kNoErr; |
| |
| exit: |
| if( err ) |
| { |
| DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" ); |
| } |
| return( err ); |
| } |
| |
| #endif // DEBUG |