| /* -*- 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. |
| */ |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @header DebugServices |
| |
| Debugging Library |
| */ |
| |
| #ifndef __DEBUG_SERVICES__ |
| #define __DEBUG_SERVICES__ |
| |
| #include <stdarg.h> |
| |
| #include "CommonServices.h" |
| |
| #if ( TARGET_OS_VXWORKS ) |
| #include "logLib.h" |
| #endif |
| |
| #if 0 |
| #pragma mark == Settings == |
| #endif |
| |
| //=========================================================================================================================== |
| // Settings |
| //=========================================================================================================================== |
| |
| // General |
| |
| #if ( !defined( DEBUG ) ) |
| #define DEBUG 0 |
| #endif |
| |
| #if ( defined( NDEBUG ) && DEBUG ) |
| #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync |
| #endif |
| |
| // AssertMacros.h/Debugging.h overrides. |
| |
| #if ( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) ) |
| #define DEBUG_OVERRIDE_APPLE_MACROS 1 |
| #endif |
| |
| // Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything). |
| |
| #if ( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) ) |
| #define __ROUTINE__ __func__ |
| #elif ( defined( __GNUC__ ) ) |
| #define __ROUTINE__ __PRETTY_FUNCTION__ |
| #elif ( defined( _MSC_VER ) && !defined( _WIN32_WCE ) ) |
| #define __ROUTINE__ __FUNCTION__ |
| #else |
| #define __ROUTINE__ "" |
| #endif |
| |
| // Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing. |
| |
| #if ( defined( __GNUC__ ) ) |
| #if ( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) ) |
| #define DEBUG_C99_VA_ARGS 1 |
| #define DEBUG_GNU_VA_ARGS 0 |
| #else |
| #define DEBUG_C99_VA_ARGS 0 |
| #define DEBUG_GNU_VA_ARGS 1 |
| #endif |
| #elif ( defined( __MWERKS__ ) ) |
| #define DEBUG_C99_VA_ARGS 1 |
| #define DEBUG_GNU_VA_ARGS 0 |
| #else |
| #define DEBUG_C99_VA_ARGS 0 |
| #define DEBUG_GNU_VA_ARGS 0 |
| #endif |
| |
| #if 0 |
| #pragma mark == Output == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_FPRINTF_ENABLED |
| |
| @abstract Enables ANSI C fprintf output. |
| */ |
| |
| #if ( !defined( DEBUG_FPRINTF_ENABLED ) ) |
| #if ( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE ) |
| #define DEBUG_FPRINTF_ENABLED 1 |
| #else |
| #define DEBUG_FPRINTF_ENABLED 0 |
| #endif |
| #else |
| #if ( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE ) |
| #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_MAC_OS_X_IOLOG_ENABLED |
| |
| @abstract Enables IOLog (Mac OS X Kernel) output. |
| */ |
| |
| #if ( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) ) |
| #define DEBUG_MAC_OS_X_IOLOG_ENABLED TARGET_API_MAC_OSX_KERNEL |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_KPRINTF_ENABLED |
| |
| @abstract Enables kprintf (Mac OS X Kernel) output. |
| */ |
| |
| #if ( !defined( DEBUG_KPRINTF_ENABLED ) ) |
| #define DEBUG_KPRINTF_ENABLED TARGET_API_MAC_OSX_KERNEL |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_IDEBUG_ENABLED |
| |
| @abstract Enables iDebug (Mac OS X user and Kernel) output. |
| |
| @discussion |
| |
| For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence |
| of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies |
| on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug. |
| */ |
| |
| #if ( !defined( DEBUG_IDEBUG_ENABLED ) ) |
| #define DEBUG_IDEBUG_ENABLED TARGET_API_MAC_OSX_KERNEL |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_CORE_SERVICE_ASSERTS_ENABLED |
| |
| @abstract Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework. |
| */ |
| |
| #if ( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) ) |
| #if ( defined( __DEBUGGING__ ) ) |
| #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 1 |
| #else |
| #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 0 |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef DebugOutputType |
| |
| @abstract Type of debug output (i.e. where the output goes). |
| */ |
| |
| typedef uint32_t DebugOutputType; |
| |
| #define kDebugOutputTypeNone 0x6E6F6E65U // 'none' - no params |
| #define kDebugOutputTypeCustom 0x63757374U // 'cust' - 1st param = function ptr, 2nd param = context |
| #define kDebugOutputTypeFPrintF 0x66707269U // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename] |
| #define kDebugOutputTypeiDebug 0x69646267U // 'idbg' - no params |
| #define kDebugOutputTypeKPrintF 0x6B707266U // 'kprf' - no params |
| #define kDebugOutputTypeMacOSXIOLog 0x696C6F67U // 'ilog' - no params |
| #define kDebugOutputTypeMacOSXLog 0x786C6F67U // 'xlog' - no params |
| #define kDebugOutputTypeWindowsDebugger 0x77696E64U // 'wind' - no params |
| #define kDebugOutputTypeWindowsEventLog 0x7765766CU // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL. |
| |
| // Console meta output kind - Any kind of Console output (in horizontal order of preference): |
| // |
| // Mac OS X = ANSI printf (viewable in Console.app) |
| // Mac OS X Kernel = IOLog (/var/log/system.log) or kprintf (serial). |
| // Windows = ANSI printf (Console window) or OutputDebugString (debugger). |
| // Other = ANSI printf (viewer varies). |
| |
| #define kDebugOutputTypeMetaConsole 0x434F4E53U // 'CONS' - no params |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef DebugOutputTypeFlags |
| |
| @abstract Flags controlling how the output type is configured. |
| |
| @constant kDebugOutputTypeFlagsTypeMask Bit mask for the output type (e.g. stdout, stderr, file, etc.). |
| @constant kDebugOutputTypeFlagsStdOut fprintf should go to stdout. |
| @constant kDebugOutputTypeFlagsStdErr fprintf should go to stderr. |
| @constant kDebugOutputTypeFlagsFile fprintf should go to a specific file (filename passed as va_arg). |
| */ |
| |
| typedef unsigned int DebugOutputTypeFlags; |
| |
| #define kDebugOutputTypeFlagsTypeMask 0xF |
| #define kDebugOutputTypeFlagsStdOut 1 |
| #define kDebugOutputTypeFlagsStdErr 2 |
| #define kDebugOutputTypeFlagsFile 10 |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef DebugOutputFunctionPtr |
| |
| @abstract Function ptr for a custom callback to print debug output. |
| */ |
| |
| typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext ); |
| |
| //=========================================================================================================================== |
| // Constants |
| //=========================================================================================================================== |
| |
| #if 0 |
| #pragma mark == Flags == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef DebugFlags |
| |
| @abstract Flags controlling how output is printed. |
| */ |
| |
| typedef uint32_t DebugFlags; |
| |
| #define kDebugFlagsNone 0 |
| #define kDebugFlagsNoAddress ( 1 << 0 ) |
| #define kDebugFlagsNoOffset ( 1 << 1 ) |
| #define kDebugFlags32BitOffset ( 1 << 2 ) |
| #define kDebugFlagsNoASCII ( 1 << 3 ) |
| #define kDebugFlagsNoNewLine ( 1 << 4 ) |
| #define kDebugFlags8BitSeparator ( 1 << 5 ) |
| #define kDebugFlags16BitSeparator ( 1 << 6 ) |
| #define kDebugFlagsNo32BitSeparator ( 1 << 7 ) |
| #define kDebugFlagsNo16ByteHexPad ( 1 << 8 ) |
| #define kDebugFlagsNoByteCount ( 1 << 9 ) |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @enum DebugTaskLevelFlags |
| |
| @abstract Flags indicating the task level. |
| */ |
| |
| enum |
| { |
| kDebugInterruptLevelShift = 0, |
| kDebugInterruptLevelMask = 0x00000007, |
| kDebugInVBLTaskMask = 0x00000010, |
| kDebugInDeferredTaskMask = 0x00000020, |
| kDebugInSecondaryInterruptHandlerMask = 0x00000040, |
| kDebugPageFaultFatalMask = 0x00000100, // There should be a "kPageFaultFatalMask" in Debugging.h. |
| kDebugMPTaskLevelMask = 0x00000200, // There should be a "kMPTaskLevelMask" in Debugging.h. |
| kDebugInterruptDepthShift = 16, |
| kDebugInterruptDepthMask = 0x00FF0000 |
| }; |
| |
| #define DebugExtractTaskLevelInterruptLevel( LEVEL ) \ |
| ( ( ( LEVEL ) &kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift ) |
| |
| #define DebugExtractTaskLevelInterruptDepth( LEVEL ) \ |
| ( ( ( LEVEL ) &kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift ) |
| |
| #if 0 |
| #pragma mark == Levels == |
| #endif |
| |
| //=========================================================================================================================== |
| // Constants & Types - Levels |
| //=========================================================================================================================== |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef DebugLevel |
| |
| @abstract Level used to control debug logging. |
| */ |
| |
| typedef int32_t DebugLevel; |
| |
| // Levels |
| |
| #define kDebugLevelMask 0x0000FFFF |
| #define kDebugLevelChatty 100 |
| #define kDebugLevelVerbose 500 |
| #define kDebugLevelTrace 800 |
| #define kDebugLevelInfo 1000 |
| #define kDebugLevelNotice 3000 |
| #define kDebugLevelWarning 5000 |
| #define kDebugLevelAssert 6000 |
| #define kDebugLevelRequire 7000 |
| #define kDebugLevelError 8000 |
| #define kDebugLevelCritical 9000 |
| #define kDebugLevelAlert 10000 |
| #define kDebugLevelEmergency 11000 |
| #define kDebugLevelTragic 12000 |
| #define kDebugLevelMax 0x0000FFFF |
| |
| // Level Flags |
| |
| #define kDebugLevelFlagMask 0xFFFF0000 |
| #define kDebugLevelFlagStackTrace 0x00010000 |
| #define kDebugLevelFlagDebugBreak 0x00020000 |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef LogLevel |
| |
| @abstract Level used to control which events are logged. |
| */ |
| |
| typedef int32_t LogLevel; |
| |
| #define kLogLevelUninitialized -1L |
| #define kLogLevelAll 0L |
| #define kLogLevelChatty 100L |
| #define kLogLevelVerbose 500L |
| #define kLogLevelTrace 800L |
| #define kLogLevelInfo 1000L |
| #define kLogLevelNotice 3000L |
| #define kLogLevelWarning 4000L |
| #define kLogLevelAssert 6000L |
| #define kLogLevelRequire 7000L |
| #define kLogLevelError 8000L |
| #define kLogLevelCritical 9000L |
| #define kLogLevelAlert 10000L |
| #define kLogLevelEmergency 11000L |
| #define kLogLevelTragic 12000L |
| #define kLogLevelOff 0x0000FFFEL |
| |
| #if 0 |
| #pragma mark == Properties == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @typedef DebugPropertyTag |
| |
| @abstract Tag for properties. |
| */ |
| |
| typedef uint32_t DebugPropertyTag; |
| |
| #define kDebugPropertyTagPrintLevelMin 0x6D696E70U // 'minp' Get: 1st param = DebugLevel * |
| // Set: 1st param = DebugLevel |
| |
| #define kDebugPropertyTagPrintLevel kDebugPropertyTagPrintLevelMin |
| |
| #define kDebugPropertyTagPrintLevelMax 0x706D786CU // 'maxp' Get: 1st param = DebugLevel * |
| // Set: 1st param = DebugLevel |
| |
| #define kDebugPropertyTagBreakLevel 0x62726B6CU // 'brkl' Get: 1st param = DebugLevel * |
| // Set: 1st param = DebugLevel |
| #if 0 |
| #pragma mark == General macros == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_UNUSED |
| |
| @abstract Macro to mark a paramter as unused to avoid unused parameter warnings. |
| |
| @discussion |
| |
| There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us |
| indicate a variable is unused in a manner that is supported by most compilers. |
| */ |
| |
| #define DEBUG_UNUSED( X ) (void)( X ) |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_USE_ONLY |
| |
| @abstract Macro to mark a variable as used only when debugging is enabled. |
| |
| @discussion |
| |
| Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate |
| compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that |
| are only used for debugging. |
| */ |
| |
| #if ( DEBUG ) |
| #define DEBUG_USE_ONLY( X ) |
| #else |
| #define DEBUG_USE_ONLY( X ) (void)( X ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_LOCAL |
| |
| @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on. |
| |
| @discussion |
| |
| Rather than using "static" directly, using this macros allows you to access these variables external while |
| debugging without being penalized for production builds. |
| */ |
| |
| #if ( DEBUG ) |
| #define DEBUG_LOCAL |
| #else |
| #define DEBUG_LOCAL static |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_STATIC |
| |
| @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on. |
| |
| @discussion |
| |
| Rather than using "static" directly, using this macros allows you to access these variables external while |
| debugging without being penalized for production builds. |
| */ |
| |
| #if ( DEBUG ) |
| #define DEBUG_STATIC |
| #else |
| #define DEBUG_STATIC static |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DEBUG_EXPORT |
| |
| @abstract Macros to export variables. |
| |
| @discussion |
| |
| "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but |
| // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not |
| // solve the problem of multiple drivers in the same dependency chain since they share symbols. |
| */ |
| |
| #if ( TARGET_API_MAC_OSX_KERNEL ) |
| #define DEBUG_EXPORT __private_extern__ |
| #else |
| #define DEBUG_EXPORT extern |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined debug_add |
| |
| @abstract Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off. |
| */ |
| |
| #if ( DEBUG ) |
| #define debug_add( A, B ) ( A ) += ( B ) |
| #else |
| #define debug_add( A, B ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined debug_perform |
| |
| @abstract Macro to perform something in debug-only builds. |
| */ |
| |
| #if ( DEBUG ) |
| #define debug_perform( X ) do { X; } while( 0 ) |
| #else |
| #define debug_perform( X ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function translate_errno |
| |
| @abstract Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error. |
| */ |
| |
| #define translate_errno( TEST, ERRNO, ALTERNATE_ERROR ) ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) ) |
| |
| #if 0 |
| #pragma mark == Compile Time macros == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_compile_time |
| |
| @abstract Performs a compile-time check of something such as the size of an int. |
| |
| @discussion |
| |
| This declares an array with a size that is determined by a compile-time expression. If the expression evaluates |
| to 0, the array has a size of -1, which is illegal and generates a compile-time error. |
| |
| For example: |
| |
| check_compile_time( sizeof( int ) == 4 ); |
| |
| Note: This only works with compile-time expressions. |
| Note: This only works in places where extern declarations are allowed (e.g. global scope). |
| |
| References: |
| |
| <http://www.jaggersoft.com/pubs/CVu11_3.html> |
| <http://www.jaggersoft.com/pubs/CVu11_5.html> |
| |
| Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not |
| work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable. |
| */ |
| |
| #define check_compile_time( X ) extern int debug_compile_time_name[ ( X ) ? 1 : -1 ] |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_compile_time_code |
| |
| @abstract Perform a compile-time check, suitable for placement in code, of something such as the size of an int. |
| |
| @discussion |
| |
| This creates a switch statement with an existing case for 0 and an additional case using the result of a |
| compile-time expression. A switch statement cannot have two case labels with the same constant so if the |
| compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time |
| expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error. |
| |
| For example: |
| |
| check_compile_time_code( sizeof( int ) == 4 ); |
| |
| Note: This only works with compile-time expressions. |
| Note: This does not work in a global scope so it must be inside a function. |
| |
| References: |
| |
| <http://www.jaggersoft.com/pubs/CVu11_3.html> |
| <http://www.jaggersoft.com/pubs/CVu11_5.html> |
| */ |
| |
| #define check_compile_time_code( X ) switch( 0 ) { case 0: case X:; } |
| |
| #if 0 |
| #pragma mark == check macros == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check |
| |
| @abstract Check that an expression is true (non-zero). |
| |
| @discussion |
| |
| If expression evalulates to false, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) using the default debugging output method. |
| |
| Code inside check() statements is not compiled into production builds. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef check |
| #endif |
| #if ( !defined( check ) ) |
| #if ( DEBUG ) |
| #define check( X ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| } \ |
| } while( 0 ) |
| #else |
| #define check( X ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_string |
| |
| @abstract Check that an expression is true (non-zero) with an explanation. |
| |
| @discussion |
| |
| If expression evalulates to false, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) and a custom explanation string using the default debugging output method. |
| |
| Code inside check_string() statements is not compiled into production builds. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef check_string |
| #endif |
| #if ( !defined( check_string ) ) |
| #if ( DEBUG ) |
| #define check_string( X, STR ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| } \ |
| \ |
| } while( 0 ) |
| #else |
| #define check_string( X, STR ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_noerr |
| |
| @abstract Check that an error code is noErr (0). |
| |
| @discussion |
| |
| If the error code is non-0, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) using the default debugging output method. |
| |
| Code inside check_noerr() statements is not compiled into production builds. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef check_noerr |
| #endif |
| #if ( !defined( check_noerr ) ) |
| #if ( DEBUG ) |
| #define check_noerr( ERR ) \ |
| do \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERR ); \ |
| if( localErr != 0 ) \ |
| { \ |
| debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| } \ |
| \ |
| } while( 0 ) |
| #else |
| #define check_noerr( ERR ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_noerr_string |
| |
| @abstract Check that an error code is noErr (0) with an explanation. |
| |
| @discussion |
| |
| If the error code is non-0, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) and a custom explanation string using the default debugging output method. |
| |
| Code inside check_noerr_string() statements is not compiled into production builds. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef check_noerr_string |
| #endif |
| #if ( !defined( check_noerr_string ) ) |
| #if ( DEBUG ) |
| #define check_noerr_string( ERR, STR ) \ |
| do \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERR ); \ |
| if( localErr != 0 ) \ |
| { \ |
| debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| } \ |
| \ |
| } while( 0 ) |
| #else |
| #define check_noerr_string( ERR, STR ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_translated_errno |
| |
| @abstract Check a condition and prints errno (if non-zero) to the log. |
| |
| @discussion |
| |
| Code inside check_translated_errno() statements is not compiled into production builds. |
| */ |
| |
| #if ( !defined( check_translated_errno ) ) |
| #if ( DEBUG ) |
| #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) \ |
| do \ |
| { \ |
| if( !( TEST ) ) \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERRNO ); \ |
| localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR ); \ |
| debug_print_assert( localErr, # TEST, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| } \ |
| \ |
| } while( 0 ) |
| #else |
| #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined check_ptr_overlap |
| |
| @abstract Checks that two ptrs do not overlap. |
| */ |
| |
| #define check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE ) \ |
| do \ |
| { \ |
| check( !( ( (uintptr_t)( P1 ) >= (uintptr_t)( P2 ) ) && \ |
| ( (uintptr_t)( P1 ) < ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) ); \ |
| check( !( ( (uintptr_t)( P2 ) >= (uintptr_t)( P1 ) ) && \ |
| ( (uintptr_t)( P2 ) < ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) ); \ |
| \ |
| } while( 0 ) |
| |
| #if 0 |
| #pragma mark == require macros == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require |
| |
| @abstract Requires that an expression evaluate to true. |
| |
| @discussion |
| |
| If expression evalulates to false, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) using the default debugging output method then jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require |
| #endif |
| #if ( !defined( require ) ) |
| #define require( X, LABEL ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_string |
| |
| @abstract Requires that an expression evaluate to true with an explanation. |
| |
| @discussion |
| |
| If expression evalulates to false, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_string |
| #endif |
| #if ( !defined( require_string ) ) |
| #define require_string( X, LABEL, STR ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_quiet |
| |
| @abstract Requires that an expression evaluate to true. |
| |
| @discussion |
| |
| If expression evalulates to false, this jumps to a label. No debugging information is printed. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_quiet |
| #endif |
| #if ( !defined( require_quiet ) ) |
| #define require_quiet( X, LABEL ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_noerr |
| |
| @abstract Require that an error code is noErr (0). |
| |
| @discussion |
| |
| If the error code is non-0, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) using the default debugging output method then jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_noerr |
| #endif |
| #if ( !defined( require_noerr ) ) |
| #define require_noerr( ERR, LABEL ) \ |
| do \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERR ); \ |
| if( localErr != 0 ) \ |
| { \ |
| debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_noerr_string |
| |
| @abstract Require that an error code is noErr (0). |
| |
| @discussion |
| |
| If the error code is non-0, this prints debugging information (actual expression string, file, line number, |
| function name, etc.), and a custom explanation string using the default debugging output method using the |
| default debugging output method then jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_noerr_string |
| #endif |
| #if ( !defined( require_noerr_string ) ) |
| #define require_noerr_string( ERR, LABEL, STR ) \ |
| do \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERR ); \ |
| if( localErr != 0 ) \ |
| { \ |
| debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_noerr_action_string |
| |
| @abstract Require that an error code is noErr (0). |
| |
| @discussion |
| |
| If the error code is non-0, this prints debugging information (actual expression string, file, line number, |
| function name, etc.), and a custom explanation string using the default debugging output method using the |
| default debugging output method then executes an action and jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_noerr_action_string |
| #endif |
| #if ( !defined( require_noerr_action_string ) ) |
| #define require_noerr_action_string( ERR, LABEL, ACTION, STR ) \ |
| do \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERR ); \ |
| if( localErr != 0 ) \ |
| { \ |
| debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| { ACTION; } \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_noerr_quiet |
| |
| @abstract Require that an error code is noErr (0). |
| |
| @discussion |
| |
| If the error code is non-0, this jumps to a label. No debugging information is printed. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_noerr_quiet |
| #endif |
| #if ( !defined( require_noerr_quiet ) ) |
| #define require_noerr_quiet( ERR, LABEL ) \ |
| do \ |
| { \ |
| if( ( ERR ) != 0 ) \ |
| { \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_noerr_action |
| |
| @abstract Require that an error code is noErr (0) with an action to execute otherwise. |
| |
| @discussion |
| |
| If the error code is non-0, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) using the default debugging output method then executes an action and jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_noerr_action |
| #endif |
| #if ( !defined( require_noerr_action ) ) |
| #define require_noerr_action( ERR, LABEL, ACTION ) \ |
| do \ |
| { \ |
| int_least32_t localErr; \ |
| \ |
| localErr = (int_least32_t)( ERR ); \ |
| if( localErr != 0 ) \ |
| { \ |
| debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| { ACTION; } \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_noerr_action_quiet |
| |
| @abstract Require that an error code is noErr (0) with an action to execute otherwise. |
| |
| @discussion |
| |
| If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_noerr_action_quiet |
| #endif |
| #if ( !defined( require_noerr_action_quiet ) ) |
| #define require_noerr_action_quiet( ERR, LABEL, ACTION ) \ |
| do \ |
| { \ |
| if( ( ERR ) != 0 ) \ |
| { \ |
| { ACTION; } \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_action |
| |
| @abstract Requires that an expression evaluate to true with an action to execute otherwise. |
| |
| @discussion |
| |
| If expression evalulates to false, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) using the default debugging output method then executes an action and jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_action |
| #endif |
| #if ( !defined( require_action ) ) |
| #define require_action( X, LABEL, ACTION ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| { ACTION; } \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_action_quiet |
| |
| @abstract Requires that an expression evaluate to true with an action to execute otherwise. |
| |
| @discussion |
| |
| If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_action_quiet |
| #endif |
| #if ( !defined( require_action_quiet ) ) |
| #define require_action_quiet( X, LABEL, ACTION ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| { ACTION; } \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_action_string |
| |
| @abstract Requires that an expression evaluate to true with an explanation and action to execute otherwise. |
| |
| @discussion |
| |
| If expression evalulates to false, this prints debugging information (actual expression string, file, line number, |
| function name, etc.) and a custom explanation string using the default debugging output method then executes an |
| action and jumps to a label. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef require_action_string |
| #endif |
| #if ( !defined( require_action_string ) ) |
| #define require_action_string( X, LABEL, ACTION, STR ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| { ACTION; } \ |
| goto LABEL; \ |
| } \ |
| \ |
| } while( 0 ) |
| |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined require_throw |
| |
| @abstract Requires that an expression evaluates to true or an exception is thrown. |
| |
| @discussion |
| |
| If the expression evaluates to false, this prints debugging information (actual expression string, file, |
| line number, function name, etc.) using the default debugging output method then throws an exception. |
| */ |
| |
| #if ( defined( __cplusplus ) ) |
| #define require_throw( X ) \ |
| do \ |
| { \ |
| if( !( X ) ) \ |
| { \ |
| debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \ |
| throw kUnknownErr; \ |
| } \ |
| \ |
| } while( 0 ) |
| #endif |
| |
| #if 0 |
| #pragma mark == Design-By-Contract macros == |
| #endif |
| |
| //=========================================================================================================================== |
| // Design-By-Contract macros |
| //=========================================================================================================================== |
| |
| #define ensure( X ) check( X ) |
| #define ensure_string( X, STR ) check_string( X, STR ) |
| #define ensure_noerr( ERR ) check_noerr( ERR ) |
| #define ensure_noerr_string( ERR, STR ) check_noerr_string( ERR, STR ) |
| #define ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) |
| |
| // Note: Design-By-Contract "require" macros are already defined elsewhere. |
| |
| #if 0 |
| #pragma mark == Expect macros == |
| #endif |
| |
| //=========================================================================================================================== |
| // Expect macros |
| //=========================================================================================================================== |
| |
| // Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal |
| // programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly |
| // without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can |
| // also be useful to measure the cost of error checking code by profiling with it enable and with it disabled. |
| |
| #if ( DEBUG_EXPECT_VERIFIED ) |
| #define require_expect |
| #define require_string_expect |
| #define require_quiet_expect |
| #define require_noerr_expect |
| #define require_noerr_string_expect |
| #define require_noerr_action_string_expect |
| #define require_noerr_quiet_expect |
| #define require_noerr_action_expect |
| #define require_noerr_action_quiet_expect |
| #define require_action_expect |
| #define require_action_quiet_expect |
| #define require_action_string_expect |
| #else |
| #define require_expect require |
| #define require_string_expect require_string |
| #define require_quiet_expect require_quiet |
| #define require_noerr_expect require_noerr |
| #define require_noerr_string_expect require_noerr_string |
| #define require_noerr_action_string_expect require_noerr_action_string |
| #define require_noerr_quiet_expect require_noerr_quiet |
| #define require_noerr_action_expect require_noerr_action |
| #define require_noerr_action_quiet_expect require_noerr_action_quiet |
| #define require_action_expect require_action |
| #define require_action_quiet_expect require_action_quiet |
| #define require_action_string_expect require_action_string |
| #endif |
| |
| #if 0 |
| #pragma mark == Output macros == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined debug_string |
| |
| @abstract Prints a debugging C string. |
| */ |
| |
| #if ( DEBUG_OVERRIDE_APPLE_MACROS ) |
| #undef debug_string |
| #endif |
| #if ( !defined( debug_string ) ) |
| #if ( DEBUG ) |
| #define debug_string( STR ) \ |
| do \ |
| { \ |
| debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \ |
| \ |
| } while( 0 ) |
| #else |
| #define debug_string( STR ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined debug_print_assert |
| |
| @abstract Prints an assertion. |
| */ |
| |
| #if ( DEBUG ) |
| #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION ) \ |
| DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION ) |
| #else |
| #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined dlog |
| |
| @abstract Prints a debug-only message. |
| */ |
| |
| #if ( DEBUG ) |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define dlog(... ) DebugPrintF( __VA_ARGS__ ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define dlog( ARGS... ) DebugPrintF( ## ARGS ) |
| #else |
| #define dlog DebugPrintF |
| #endif |
| #else |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define dlog(... ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define dlog( ARGS... ) |
| #else |
| #define dlog while( 0 ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined dlogv |
| |
| @abstract Prints a debug-only message. |
| */ |
| |
| #if ( DEBUG ) |
| #define dlogv( LEVEL, FORMAT, LIST ) DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) ) |
| #else |
| #define dlogv( LEVEL, FORMAT, LIST ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined dlogmem |
| |
| @abstract Prints a debug-only dump of memory. |
| */ |
| |
| #if ( DEBUG ) |
| #define dlogmem( LEVEL, PTR, SIZE ) \ |
| DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 ) |
| #else |
| #define dlogmem( LEVEL, PTR, SIZE ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DebugNSLog |
| |
| @abstract Debug-only macro for the Cocoa NSLog function. |
| */ |
| |
| #if ( DEBUG ) |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define DebugNSLog(... ) NSLog( __VA_ARGS__ ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define DebugNSLog( ARGS... ) NSLog( ## ARGS ) |
| #else |
| #define DebugNSLog NSLog |
| #endif |
| #else |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define DebugNSLog(... ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define DebugNSLog( ARGS... ) |
| #else |
| #define DebugNSLog while( 0 ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @defined DebugLogMsg |
| |
| @abstract Debug-only macro for the VxWorks logMsg function. |
| */ |
| |
| #if ( TARGET_OS_VXWORKS ) |
| #if ( DEBUG ) |
| #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 ) \ |
| do \ |
| { \ |
| if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) ) \ |
| { \ |
| logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) ); \ |
| } \ |
| \ |
| } while( 0 ) |
| #else |
| #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 ) |
| #endif |
| #else |
| #define DebugLogMsg dlog |
| #endif |
| |
| #if 0 |
| #pragma mark == Routines - General == |
| #endif |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugInitialize |
| |
| @abstract Initializes the debugging library for a specific kind of output. |
| |
| @param inType |
| @param varArg Variable number parameters, controlled by the "inType" parameter. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... ); |
| #endif |
| |
| #if ( DEBUG ) |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define debug_initialize(... ) DebugInitialize( __VA_ARGS__ ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define debug_initialize( ARGS... ) DebugInitialize( ## ARGS ) |
| #else |
| #define debug_initialize DebugInitialize |
| #endif |
| #else |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define debug_initialize(... ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define debug_initialize( ARGS... ) |
| #else |
| #define debug_initialize while( 0 ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugFinalize |
| |
| @abstract Releases any resources used by the debugging library |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT void DebugFinalize( void ); |
| #endif |
| |
| #if ( DEBUG ) |
| #define debug_terminate() DebugFinalize() |
| #else |
| #define debug_terminate() |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugGetProperty |
| |
| @abstract Gets the specified property from the debugging library. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... ); |
| #endif |
| |
| #if ( DEBUG ) |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define debug_get_property(... ) DebugGetProperty( __VA_ARGS__ ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define debug_get_property( ARGS... ) DebugGetProperty( ## ARGS ) |
| #else |
| #define debug_get_property DebugGetProperty |
| #endif |
| #else |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define debug_get_property(... ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define debug_get_property( ARGS... ) |
| #else |
| #define debug_get_property while( 0 ) |
| #endif |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugSetProperty |
| |
| @abstract Sets the specified property from the debugging library. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... ); |
| #endif |
| |
| #if ( DEBUG ) |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define debug_set_property(... ) DebugSetProperty( __VA_ARGS__ ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define debug_set_property( ARGS... ) DebugSetProperty( ## ARGS ) |
| #else |
| #define debug_set_property DebugSetProperty |
| #endif |
| #else |
| #if ( DEBUG_C99_VA_ARGS ) |
| #define debug_set_property(... ) |
| #elif ( DEBUG_GNU_VA_ARGS ) |
| #define debug_set_property( ARGS... ) |
| #else |
| #define debug_set_property while( 0 ) |
| #endif |
| #endif |
| |
| #if 0 |
| #pragma mark == Routines - Debugging Output == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugPrintF |
| |
| @abstract Prints a debug message with printf-style formatting. |
| |
| @param inLevel Error that generated this assert or noErr. |
| |
| @param inFormatString |
| C string containing assertion text. |
| |
| @param VAR_ARG |
| Variable number of arguments depending on the format string. |
| |
| @result Number of bytes printed or -1 on error. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... ); |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugPrintFVAList |
| |
| @abstract va_list version of DebugPrintF. See DebugPrintF for more info. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs ); |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugPrintAssert |
| |
| @abstract Prints a message describing the reason the (e.g. an assert failed), an optional error message, |
| an optional source filename, an optional source line number. |
| |
| @param inErrorCode Error that generated this assert or noErr. |
| @param inAssertString C string containing assertion text. |
| @param inMessage C string containing a message about the assert. |
| @param inFileName C string containing path of file where the error occurred. |
| @param inLineNumber Line number in source file where the error occurred. |
| @param inFunction C string containing name of function where assert occurred. |
| |
| @discussion |
| |
| Example output: |
| |
| [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed |
| [ASSERT] where: "MyFile.c", line 123, ("MyFunction") |
| |
| OR |
| |
| [ASSERT] error: -6728 (kNoMemoryErr) |
| [ASSERT] where: "MyFile.c", line 123, ("MyFunction") |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT void |
| DebugPrintAssert( |
| int_least32_t inErrorCode, |
| const char * inAssertString, |
| const char * inMessage, |
| const char * inFilename, |
| int_least32_t inLineNumber, |
| const char * inFunction ); |
| #endif |
| |
| #if 0 |
| #pragma mark == Routines - Utilities == |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugSNPrintF |
| |
| @abstract Debugging versions of standard C snprintf with extra features. |
| |
| @param sbuffer Buffer to receive result. Null terminated unless the buffer size is 0. |
| @param buflen Size of the buffer including space for the null terminator. |
| @param fmt printf-style format string. |
| @param VAR_ARG Variable number of arguments depending on the format string. |
| |
| @result Number of characters written (minus the null terminator). |
| |
| @discussion |
| |
| Extra features over the standard C snprintf: |
| <pre> |
| 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb). |
| %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription. |
| %a - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address. |
| %#a - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr. |
| %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr. |
| %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc. |
| %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode. |
| %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size. |
| %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size. |
| %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc. |
| %#s - Pascal-style length-prefixed string. Arg=ptr to string. |
| %##s - DNS label-sequence name. Arg=ptr to name. |
| %S - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM. |
| %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S. |
| %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S. |
| %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID. |
| </pre> |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...); |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugSNPrintFVAList |
| |
| @abstract va_list version of DebugSNPrintF. See DebugSNPrintF for more info. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg); |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugGetErrorString |
| |
| @abstract Gets an error string from an error code. |
| |
| @param inStatus Error code to get the string for. |
| @param inBuffer Optional buffer to copy the string to for non-static strings. May be null. |
| @param inBufferSize Size of optional buffer. May be 0. |
| |
| @result C string containing error string for the error code. Guaranteed to be a valid, static string. If a |
| buffer is supplied, the return value will always be a pointer to the supplied buffer, which will |
| contain the best available description of the error code. If a buffer is not supplied, the return |
| value will be the best available description of the error code that can be represented as a static |
| string. This allows code that cannot use a temporary buffer to hold the result to still get a useful |
| error string in most cases, but also allows code that can use a temporary buffer to get the best |
| available description. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize ); |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugHexDump |
| |
| @abstract Hex dumps data to a string or to the output device. |
| */ |
| |
| #if ( DEBUG ) |
| 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 ); |
| #endif |
| |
| #if ( DEBUG ) |
| #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE ) \ |
| DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ), \ |
| ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) ) |
| #else |
| #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE ) |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugTaskLevel |
| |
| @abstract Returns the current task level. |
| |
| @result Current task level |
| |
| @discussion |
| |
| Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify): |
| <pre> |
| kDebugInterruptLevelMask - Indicates the current interrupt level (> 0 means interrupt time). |
| kDebugInVBLTaskMask - Indicates if a VBL task is currently being executed. |
| kDebugInDeferredTaskMask - Indicates if a Deferred Task is currently being executed. |
| kDebugInSecondaryInterruptHandlerMask - Indicates if a Secondary Interrupt Handler is currently being executed. |
| kDebugPageFaultFatalMask - Indicates if it is unsafe to cause a page fault (worse than interrupt time). |
| kDebugMPTaskLevelMask - Indicates if being called from an MP task. |
| kDebugInterruptDepthMask - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt. |
| </pre> |
| |
| Helpers: |
| <pre> |
| DebugExtractTaskLevelInterruptDepth() - Macro to extract interrupt depth from task level value. |
| </pre> |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT uint32_t DebugTaskLevel( void ); |
| #endif |
| |
| //--------------------------------------------------------------------------------------------------------------------------- |
| /*! @function DebugServicesTest |
| |
| @abstract Unit test. |
| */ |
| |
| #if ( DEBUG ) |
| DEBUG_EXPORT OSStatus DebugServicesTest( void ); |
| #endif |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif // __DEBUG_SERVICES__ |