You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1608 lines
55 KiB
1608 lines
55 KiB
8 months ago
|
/* -*- 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__
|