1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16
17    To Do:
18
19    - Use StackWalk on Windows to optionally print stack frames.
20 */
21
22#if 0
23#pragma mark == Includes ==
24#endif
25
26//===========================================================================================================================
27//	Includes
28//===========================================================================================================================
29
30#if ( !KERNEL )
31    #include    <ctype.h>
32    #include    <stdio.h>
33    #include    <string.h>
34#endif
35
36#include    "CommonServices.h"
37
38#include    "DebugServices.h"
39
40#if ( DEBUG )
41
42#if ( TARGET_OS_VXWORKS )
43    #include    "intLib.h"
44#endif
45
46#if ( TARGET_OS_WIN32 )
47    #include    <time.h>
48
49    #if ( !TARGET_OS_WINDOWS_CE )
50        #include    <fcntl.h>
51        #include    <io.h>
52    #endif
53#endif
54
55#if ( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
56    #include    <IOKit/IOLib.h>
57#endif
58
59// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
60
61#if ( defined( MDNS_DEBUGMSGS ) )
62    #include    "mDNSEmbeddedAPI.h"
63#endif
64
65#if 0
66#pragma mark == Macros ==
67#endif
68
69//===========================================================================================================================
70//	Macros
71//===========================================================================================================================
72
73#define DebugIsPrint( C )       ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
74
75#if 0
76#pragma mark == Prototypes ==
77#endif
78
79//===========================================================================================================================
80//	Prototypes
81//===========================================================================================================================
82
83static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
84
85// fprintf
86
87#if ( DEBUG_FPRINTF_ENABLED )
88static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
89static void     DebugFPrintFPrint( char *inData, size_t inSize );
90#endif
91
92// iDebug (Mac OS X user and kernel)
93
94#if ( DEBUG_IDEBUG_ENABLED )
95static OSStatus DebugiDebugInit( void );
96static void     DebugiDebugPrint( char *inData, size_t inSize );
97#endif
98
99// kprintf (Mac OS X Kernel)
100
101#if ( DEBUG_KPRINTF_ENABLED )
102static void DebugKPrintFPrint( char *inData, size_t inSize );
103#endif
104
105// Mac OS X IOLog (Mac OS X Kernel)
106
107#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
108static void DebugMacOSXIOLogPrint( char *inData, size_t inSize );
109#endif
110
111// Mac OS X Log
112
113#if ( TARGET_OS_MAC )
114static OSStatus DebugMacOSXLogInit( void );
115static void     DebugMacOSXLogPrint( char *inData, size_t inSize );
116#endif
117
118// Windows Debugger
119
120#if ( TARGET_OS_WIN32 )
121static void DebugWindowsDebuggerPrint( char *inData, size_t inSize );
122#endif
123
124// Windows Event Log
125
126#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
127static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
128static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
129#endif
130
131// DebugLib support
132
133#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
134static pascal void
135DebugAssertOutputHandler(
136    OSType inComponentSignature,
137    UInt32 inOptions,
138    const char *        inAssertionString,
139    const char *        inExceptionString,
140    const char *        inErrorString,
141    const char *        inFileName,
142    long inLineNumber,
143    void *              inValue,
144    ConstStr255Param inOutputMsg );
145#endif
146
147// Utilities
148
149static char *   DebugNumVersionToString( uint32_t inVersion, char *inString );
150
151#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
152static void DebugWinEnableConsole( void );
153#endif
154
155#if ( TARGET_OS_WIN32 )
156static TCHAR *
157DebugWinCharToTCharString(
158    const char *    inCharString,
159    size_t inCharCount,
160    TCHAR *         outTCharString,
161    size_t inTCharCountMax,
162    size_t *        outTCharCount );
163#endif
164
165#if 0
166#pragma mark == Globals ==
167#endif
168
169//===========================================================================================================================
170//	Private Globals
171//===========================================================================================================================
172
173#if ( TARGET_OS_VXWORKS )
174// TCP States for inetstatShow.
175
176extern char **  pTcpstates;         // defined in tcpLib.c
177
178const char *        kDebugTCPStates[] =
179{
180    "(0)  TCPS_CLOSED",
181    "(1)  TCPS_LISTEN",
182    "(2)  TCPS_SYN_SENT",
183    "(3)  TCPS_SYN_RECEIVED",
184    "(4)  TCPS_ESTABLISHED",
185    "(5)  TCPS_CLOSE_WAIT",
186    "(6)  TCPS_FIN_WAIT_1",
187    "(7)  TCPS_CLOSING",
188    "(8)  TCPS_LAST_ACK",
189    "(9)  TCPS_FIN_WAIT_2",
190    "(10) TCPS_TIME_WAIT",
191};
192#endif
193
194// General
195
196static bool gDebugInitialized               = false;
197static DebugOutputType gDebugOutputType                = kDebugOutputTypeNone;
198static DebugLevel gDebugPrintLevelMin             = kDebugLevelInfo;
199static DebugLevel gDebugPrintLevelMax             = kDebugLevelMax;
200static DebugLevel gDebugBreakLevel                = kDebugLevelAssert;
201#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
202static DebugAssertOutputHandlerUPP gDebugAssertOutputHandlerUPP    = NULL;
203#endif
204
205// Custom
206
207static DebugOutputFunctionPtr gDebugCustomOutputFunction      = NULL;
208static void *                               gDebugCustomOutputContext       = NULL;
209
210// fprintf
211
212#if ( DEBUG_FPRINTF_ENABLED )
213static FILE *                           gDebugFPrintFFile               = NULL;
214#endif
215
216// MacOSXLog
217
218#if ( TARGET_OS_MAC )
219typedef int ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
220
221static DebugMacOSXLogFunctionPtr gDebugMacOSXLogFunction         = NULL;
222#endif
223
224// WindowsEventLog
225
226
227#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
228static HANDLE gDebugWindowsEventLogEventSource = NULL;
229#endif
230
231#if 0
232#pragma mark -
233#pragma mark == General ==
234#endif
235
236//===========================================================================================================================
237//	DebugInitialize
238//===========================================================================================================================
239
240DEBUG_EXPORT OSStatus   DebugInitialize( DebugOutputType inType, ... )
241{
242    OSStatus err;
243    DebugOutputType type;
244    va_list args;
245
246    va_start( args, inType );
247
248#if ( TARGET_OS_VXWORKS )
249    // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
250
251    if( !pTcpstates )
252    {
253        pTcpstates = (char **) kDebugTCPStates;
254    }
255#endif
256
257    // Set up DebugLib stuff (if building with Debugging.h).
258
259#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
260    if( !gDebugAssertOutputHandlerUPP )
261    {
262        gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
263        check( gDebugAssertOutputHandlerUPP );
264        if( gDebugAssertOutputHandlerUPP )
265        {
266            InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
267        }
268    }
269#endif
270
271    // Pre-process meta-output kind to pick an appropriate output kind for the platform.
272
273    type = inType;
274    if( type == kDebugOutputTypeMetaConsole )
275    {
276        #if ( TARGET_OS_MAC )
277        type = kDebugOutputTypeMacOSXLog;
278        #elif ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
279            #if ( DEBUG_FPRINTF_ENABLED )
280        type = kDebugOutputTypeFPrintF;
281            #else
282        type = kDebugOutputTypeWindowsDebugger;
283            #endif
284        #elif ( TARGET_API_MAC_OSX_KERNEL )
285            #if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
286        type = kDebugOutputTypeMacOSXIOLog;
287            #elif ( DEBUG_IDEBUG_ENABLED )
288        type = kDebugOutputTypeiDebug;
289            #elif ( DEBUG_KPRINTF_ENABLED )
290        type = kDebugOutputTypeKPrintF;
291            #endif
292        #elif ( TARGET_OS_VXWORKS )
293            #if ( DEBUG_FPRINTF_ENABLED )
294        type = kDebugOutputTypeFPrintF;
295            #else
296                #error target is VxWorks, but fprintf output is disabled
297            #endif
298        #else
299            #if ( DEBUG_FPRINTF_ENABLED )
300        type = kDebugOutputTypeFPrintF;
301            #endif
302        #endif
303    }
304
305    // Process output kind.
306
307    gDebugOutputType = type;
308    switch( type )
309    {
310    case kDebugOutputTypeNone:
311        err = kNoErr;
312        break;
313
314    case kDebugOutputTypeCustom:
315        gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
316        gDebugCustomOutputContext  = va_arg( args, void * );
317        err = kNoErr;
318        break;
319
320#if ( DEBUG_FPRINTF_ENABLED )
321    case kDebugOutputTypeFPrintF:
322        if( inType == kDebugOutputTypeMetaConsole )
323        {
324            err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
325        }
326        else
327        {
328            DebugOutputTypeFlags flags;
329            const char *                filename;
330
331            flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
332            if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
333            {
334                filename = va_arg( args, const char * );
335            }
336            else
337            {
338                filename = NULL;
339            }
340            err = DebugFPrintFInit( flags, filename );
341        }
342        break;
343#endif
344
345#if ( DEBUG_IDEBUG_ENABLED )
346    case kDebugOutputTypeiDebug:
347        err = DebugiDebugInit();
348        break;
349#endif
350
351#if ( DEBUG_KPRINTF_ENABLED )
352    case kDebugOutputTypeKPrintF:
353        err = kNoErr;
354        break;
355#endif
356
357#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
358    case kDebugOutputTypeMacOSXIOLog:
359        err = kNoErr;
360        break;
361#endif
362
363#if ( TARGET_OS_MAC )
364    case kDebugOutputTypeMacOSXLog:
365        err = DebugMacOSXLogInit();
366        break;
367#endif
368
369#if ( TARGET_OS_WIN32 )
370    case kDebugOutputTypeWindowsDebugger:
371        err = kNoErr;
372        break;
373#endif
374
375#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
376    case kDebugOutputTypeWindowsEventLog:
377    {
378        const char *        name;
379        HMODULE module;
380
381        name   = va_arg( args, const char * );
382        module = va_arg( args, HMODULE );
383        err = DebugWindowsEventLogInit( name, module );
384    }
385    break;
386#endif
387
388    default:
389        err = kParamErr;
390        goto exit;
391    }
392    gDebugInitialized = true;
393
394exit:
395    va_end( args );
396    return( err );
397}
398
399//===========================================================================================================================
400//	DebugFinalize
401//===========================================================================================================================
402
403DEBUG_EXPORT void       DebugFinalize( void )
404{
405#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
406    check( gDebugAssertOutputHandlerUPP );
407    if( gDebugAssertOutputHandlerUPP )
408    {
409        InstallDebugAssertOutputHandler( NULL );
410        DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
411        gDebugAssertOutputHandlerUPP = NULL;
412    }
413#endif
414}
415
416//===========================================================================================================================
417//	DebugGetProperty
418//===========================================================================================================================
419
420DEBUG_EXPORT OSStatus   DebugGetProperty( DebugPropertyTag inTag, ... )
421{
422    OSStatus err;
423    va_list args;
424    DebugLevel *        level;
425
426    va_start( args, inTag );
427    switch( inTag )
428    {
429    case kDebugPropertyTagPrintLevelMin:
430        level  = va_arg( args, DebugLevel * );
431        *level = gDebugPrintLevelMin;
432        err = kNoErr;
433        break;
434
435    case kDebugPropertyTagPrintLevelMax:
436        level  = va_arg( args, DebugLevel * );
437        *level = gDebugPrintLevelMax;
438        err = kNoErr;
439        break;
440
441    case kDebugPropertyTagBreakLevel:
442        level  = va_arg( args, DebugLevel * );
443        *level = gDebugBreakLevel;
444        err = kNoErr;
445        break;
446
447    default:
448        err = kUnsupportedErr;
449        break;
450    }
451    va_end( args );
452    return( err );
453}
454
455//===========================================================================================================================
456//	DebugSetProperty
457//===========================================================================================================================
458
459DEBUG_EXPORT OSStatus   DebugSetProperty( DebugPropertyTag inTag, ... )
460{
461    OSStatus err;
462    va_list args;
463    DebugLevel level;
464
465    va_start( args, inTag );
466    switch( inTag )
467    {
468    case kDebugPropertyTagPrintLevelMin:
469        level  = va_arg( args, DebugLevel );
470        gDebugPrintLevelMin = level;
471        err = kNoErr;
472        break;
473
474    case kDebugPropertyTagPrintLevelMax:
475        level  = va_arg( args, DebugLevel );
476        gDebugPrintLevelMax = level;
477        err = kNoErr;
478        break;
479
480    case kDebugPropertyTagBreakLevel:
481        level  = va_arg( args, DebugLevel );
482        gDebugBreakLevel = level;
483        err = kNoErr;
484        break;
485
486    default:
487        err = kUnsupportedErr;
488        break;
489    }
490    va_end( args );
491    return( err );
492}
493
494#if 0
495#pragma mark -
496#pragma mark == Output ==
497#endif
498
499//===========================================================================================================================
500//	DebugPrintF
501//===========================================================================================================================
502
503DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
504{
505    va_list args;
506    size_t n;
507
508    // Skip if the level is not in the enabled range..
509
510    if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
511    {
512        n = 0;
513        goto exit;
514    }
515
516    va_start( args, inFormat );
517    n = DebugPrintFVAList( inLevel, inFormat, args );
518    va_end( args );
519
520exit:
521    return( n );
522}
523
524//===========================================================================================================================
525//	DebugPrintFVAList
526//===========================================================================================================================
527
528DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
529{
530    size_t n;
531    char buffer[ 512 ];
532
533    // Skip if the level is not in the enabled range..
534
535    if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
536    {
537        n = 0;
538        goto exit;
539    }
540
541    n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
542    DebugPrint( inLevel, buffer, (size_t) n );
543
544exit:
545    return( n );
546}
547
548//===========================================================================================================================
549//	DebugPrint
550//===========================================================================================================================
551
552static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
553{
554    OSStatus err;
555
556    // Skip if the level is not in the enabled range..
557
558    if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
559    {
560        err = kRangeErr;
561        goto exit;
562    }
563
564    // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
565
566    if( DebugTaskLevel() & kDebugInterruptLevelMask )
567    {
568        #if ( TARGET_OS_VXWORKS )
569        logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
570        #endif
571
572        err = kExecutionStateErr;
573        goto exit;
574    }
575
576    // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
577
578    if( !gDebugInitialized )
579    {
580        debug_initialize( kDebugOutputTypeMetaConsole );
581    }
582
583    // Print based on the current output type.
584
585    switch( gDebugOutputType )
586    {
587    case kDebugOutputTypeNone:
588        break;
589
590    case kDebugOutputTypeCustom:
591        if( gDebugCustomOutputFunction )
592        {
593            gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
594        }
595        break;
596
597#if ( DEBUG_FPRINTF_ENABLED )
598    case kDebugOutputTypeFPrintF:
599        DebugFPrintFPrint( inData, inSize );
600        break;
601#endif
602
603#if ( DEBUG_IDEBUG_ENABLED )
604    case kDebugOutputTypeiDebug:
605        DebugiDebugPrint( inData, inSize );
606        break;
607#endif
608
609#if ( DEBUG_KPRINTF_ENABLED )
610    case kDebugOutputTypeKPrintF:
611        DebugKPrintFPrint( inData, inSize );
612        break;
613#endif
614
615#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
616    case kDebugOutputTypeMacOSXIOLog:
617        DebugMacOSXIOLogPrint( inData, inSize );
618        break;
619#endif
620
621#if ( TARGET_OS_MAC )
622    case kDebugOutputTypeMacOSXLog:
623        DebugMacOSXLogPrint( inData, inSize );
624        break;
625#endif
626
627#if ( TARGET_OS_WIN32 )
628    case kDebugOutputTypeWindowsDebugger:
629        DebugWindowsDebuggerPrint( inData, inSize );
630        break;
631#endif
632
633#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
634    case kDebugOutputTypeWindowsEventLog:
635        DebugWindowsEventLogPrint( inLevel, inData, inSize );
636        break;
637#endif
638
639    default:
640        break;
641    }
642    err = kNoErr;
643
644exit:
645    return( err );
646}
647
648//===========================================================================================================================
649//	DebugPrintAssert
650//
651//	Warning: This routine relies on several of the strings being string constants that will exist forever because the
652//           underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based
653//           pointer variables (e.g. local strings). The debug macros that invoke this function only use constant
654//           constant strings, but if this function is invoked directly from other places, it must use constant strings.
655//===========================================================================================================================
656
657DEBUG_EXPORT void
658DebugPrintAssert(
659    int_least32_t inErrorCode,
660    const char *    inAssertString,
661    const char *    inMessage,
662    const char *    inFilename,
663    int_least32_t inLineNumber,
664    const char *    inFunction )
665{
666    // Skip if the level is not in the enabled range..
667
668    if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
669    {
670        return;
671    }
672
673    if( inErrorCode != 0 )
674    {
675        DebugPrintF(
676            kDebugLevelAssert,
677            "\n"
678            "[ASSERT] error:  %ld (%m)\n"
679            "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
680            "\n",
681            inErrorCode, inErrorCode,
682            inFilename ? inFilename : "",
683            inLineNumber,
684            inFunction ? inFunction : "" );
685    }
686    else
687    {
688        DebugPrintF(
689            kDebugLevelAssert,
690            "\n"
691            "[ASSERT] assert: \"%s\" %s\n"
692            "[ASSERT] where:  \"%s\", line %ld, \"%s\"\n"
693            "\n",
694            inAssertString ? inAssertString : "",
695            inMessage ? inMessage : "",
696            inFilename ? inFilename : "",
697            inLineNumber,
698            inFunction ? inFunction : "" );
699    }
700
701    // Break into the debugger if enabled.
702
703    #if ( TARGET_OS_WIN32 )
704    if( gDebugBreakLevel <= kDebugLevelAssert )
705    {
706        if( IsDebuggerPresent() )
707        {
708            DebugBreak();
709        }
710    }
711    #endif
712}
713
714#if 0
715#pragma mark -
716#endif
717
718#if ( DEBUG_FPRINTF_ENABLED )
719//===========================================================================================================================
720//	DebugFPrintFInit
721//===========================================================================================================================
722
723static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
724{
725    OSStatus err;
726    DebugOutputTypeFlags typeFlags;
727
728    typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
729    if( typeFlags == kDebugOutputTypeFlagsStdOut )
730    {
731        #if ( TARGET_OS_WIN32 )
732        DebugWinEnableConsole();
733        #endif
734
735        gDebugFPrintFFile = stdout;
736    }
737    else if( typeFlags == kDebugOutputTypeFlagsStdErr )
738    {
739        #if ( TARGET_OS_WIN32 )
740        DebugWinEnableConsole();
741        #endif
742
743        gDebugFPrintFFile = stdout;
744    }
745    else if( typeFlags == kDebugOutputTypeFlagsFile )
746    {
747        require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
748
749        gDebugFPrintFFile = fopen( inFilename, "a" );
750        require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
751    }
752    else
753    {
754        err = kParamErr;
755        goto exit;
756    }
757    err = kNoErr;
758
759exit:
760    return( err );
761}
762
763//===========================================================================================================================
764//	DebugFPrintFPrint
765//===========================================================================================================================
766
767static void DebugFPrintFPrint( char *inData, size_t inSize )
768{
769    char *      p;
770    char *      q;
771
772    // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
773
774    p = inData;
775    q = p + inSize;
776    while( p < q )
777    {
778        if( *p == '\r' )
779        {
780            *p = '\n';
781        }
782        ++p;
783    }
784
785    // Write the data and flush.
786
787    if( gDebugFPrintFFile )
788    {
789        fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
790        fflush( gDebugFPrintFFile );
791    }
792}
793#endif  // DEBUG_FPRINTF_ENABLED
794
795#if ( DEBUG_IDEBUG_ENABLED )
796//===========================================================================================================================
797//	DebugiDebugInit
798//===========================================================================================================================
799
800static OSStatus DebugiDebugInit( void )
801{
802    OSStatus err;
803
804    #if ( TARGET_API_MAC_OSX_KERNEL )
805
806    extern uint32_t *       _giDebugReserved1;
807
808    // Emulate the iDebugSetOutputType macro in iDebugServices.h.
809    // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
810
811    if( !_giDebugReserved1 )
812    {
813        _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
814        require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
815    }
816    *_giDebugReserved1 = 0x00010000U;
817    err = kNoErr;
818exit:
819    #else
820
821    __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
822
823    iDebugSetOutputTypeInternal( 0x00010000U );
824    err = kNoErr;
825
826    #endif
827
828    return( err );
829}
830
831//===========================================================================================================================
832//	DebugiDebugPrint
833//===========================================================================================================================
834
835static void DebugiDebugPrint( char *inData, size_t inSize )
836{
837    #if ( TARGET_API_MAC_OSX_KERNEL )
838
839    // Locally declared here so we do not need to include iDebugKext.h.
840    // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the
841    // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
842    // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
843
844    typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
845
846    extern iDebugLogFunctionPtr _giDebugLogInternal;
847
848    if( _giDebugLogInternal )
849    {
850        _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
851    }
852
853    #else
854
855    __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
856
857    iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
858
859    #endif
860}
861#endif
862
863#if ( DEBUG_KPRINTF_ENABLED )
864//===========================================================================================================================
865//	DebugKPrintFPrint
866//===========================================================================================================================
867
868static void DebugKPrintFPrint( char *inData, size_t inSize )
869{
870    extern void kprintf( const char *inFormat, ... );
871
872    kprintf( "%.*s", (int) inSize, inData );
873}
874#endif
875
876#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
877//===========================================================================================================================
878//	DebugMacOSXIOLogPrint
879//===========================================================================================================================
880
881static void DebugMacOSXIOLogPrint( char *inData, size_t inSize )
882{
883    extern void IOLog( const char *inFormat, ... );
884
885    IOLog( "%.*s", (int) inSize, inData );
886}
887#endif
888
889#if ( TARGET_OS_MAC )
890//===========================================================================================================================
891//	DebugMacOSXLogInit
892//===========================================================================================================================
893
894static OSStatus DebugMacOSXLogInit( void )
895{
896    OSStatus err;
897    CFStringRef path;
898    CFURLRef url;
899    CFBundleRef bundle;
900    CFStringRef functionName;
901    void *          functionPtr;
902
903    bundle = NULL;
904
905    // Create a bundle reference for System.framework.
906
907    path = CFSTR( "/System/Library/Frameworks/System.framework" );
908    url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
909    require_action_quiet( url, exit, err = memFullErr );
910
911    bundle = CFBundleCreate( NULL, url );
912    CFRelease( url );
913    require_action_quiet( bundle, exit, err = memFullErr );
914
915    // Get a ptr to the system's "printf" function from System.framework.
916
917    functionName = CFSTR( "printf" );
918    functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
919    require_action_quiet( functionPtr, exit, err = memFullErr );
920
921    // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
922
923    gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
924    bundle = NULL;
925    err = noErr;
926
927exit:
928    if( bundle )
929    {
930        CFRelease( bundle );
931    }
932    return( err );
933}
934
935//===========================================================================================================================
936//	DebugMacOSXLogPrint
937//===========================================================================================================================
938
939static void DebugMacOSXLogPrint( char *inData, size_t inSize )
940{
941    if( gDebugMacOSXLogFunction )
942    {
943        gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
944    }
945}
946#endif
947
948#if ( TARGET_OS_WIN32 )
949//===========================================================================================================================
950//	DebugWindowsDebuggerPrint
951//===========================================================================================================================
952
953void    DebugWindowsDebuggerPrint( char *inData, size_t inSize )
954{
955    TCHAR buffer[ 512 ];
956    const char *        src;
957    const char *        end;
958    TCHAR *             dst;
959    char c;
960
961    // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
962    // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
963
964    src = inData;
965    if( inSize >= sizeof_array( buffer ) )
966    {
967        inSize = sizeof_array( buffer ) - 1;
968    }
969    end = src + inSize;
970    dst = buffer;
971    while( src < end )
972    {
973        c = *src++;
974        if( c == '\r' )
975        {
976            c = '\n';
977        }
978        *dst++ = (TCHAR) c;
979    }
980    *dst = 0;
981
982    // Print out the string to the debugger.
983
984    OutputDebugString( buffer );
985}
986#endif
987
988#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
989//===========================================================================================================================
990//	DebugWindowsEventLogInit
991//===========================================================================================================================
992
993static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
994{
995    OSStatus err;
996    HKEY key;
997    TCHAR name[ 128 ];
998    const char *        src;
999    TCHAR path[ MAX_PATH ];
1000    size_t size;
1001    DWORD typesSupported;
1002    DWORD n;
1003
1004    key = NULL;
1005
1006    // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
1007
1008    if( !inName || ( *inName == '\0' ) )
1009    {
1010        inName = "DefaultApp";
1011    }
1012    DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
1013
1014    // Build the path string using the fixed registry path and app name.
1015
1016    src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
1017    DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
1018    DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
1019
1020    // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
1021
1022    err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
1023    require_noerr_quiet( err, exit );
1024
1025    // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
1026
1027    n = GetModuleFileName( inModule, path, sizeof_array( path ) );
1028    err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
1029    require_noerr_quiet( err, exit );
1030    n += 1;
1031    n *= sizeof( TCHAR );
1032
1033    err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
1034    require_noerr_quiet( err, exit );
1035
1036    // Set the supported event types in the TypesSupported subkey.
1037
1038    typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
1039                     EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
1040    err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
1041    require_noerr_quiet( err, exit );
1042
1043    // Set up the event source.
1044
1045    gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
1046    err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
1047    require_noerr_quiet( err, exit );
1048
1049exit:
1050    if( key )
1051    {
1052        RegCloseKey( key );
1053    }
1054    return( err );
1055}
1056
1057//===========================================================================================================================
1058//	DebugWindowsEventLogPrint
1059//===========================================================================================================================
1060
1061static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
1062{
1063    WORD type;
1064    TCHAR buffer[ 512 ];
1065    const char *        src;
1066    const char *        end;
1067    TCHAR *             dst;
1068    char c;
1069    const TCHAR *       array[ 1 ];
1070
1071    // Map the debug level to a Windows EventLog type.
1072
1073    if( inLevel <= kDebugLevelNotice )
1074    {
1075        type = EVENTLOG_INFORMATION_TYPE;
1076    }
1077    else if( inLevel <= kDebugLevelWarning )
1078    {
1079        type = EVENTLOG_WARNING_TYPE;
1080    }
1081    else
1082    {
1083        type = EVENTLOG_ERROR_TYPE;
1084    }
1085
1086    // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
1087    // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
1088
1089    src = inData;
1090    if( inSize >= sizeof_array( buffer ) )
1091    {
1092        inSize = sizeof_array( buffer ) - 1;
1093    }
1094    end = src + inSize;
1095    dst = buffer;
1096    while( src < end )
1097    {
1098        c = *src++;
1099        if( c == '\r' )
1100        {
1101            c = '\n';
1102        }
1103        *dst++ = (TCHAR) c;
1104    }
1105    *dst = 0;
1106
1107    // Add the the string to the event log.
1108
1109    array[ 0 ] = buffer;
1110    if( gDebugWindowsEventLogEventSource )
1111    {
1112        ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
1113    }
1114}
1115#endif  // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
1116
1117#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
1118//===========================================================================================================================
1119//	DebugAssertOutputHandler
1120//===========================================================================================================================
1121
1122static pascal void
1123DebugAssertOutputHandler(
1124    OSType inComponentSignature,
1125    UInt32 inOptions,
1126    const char *        inAssertString,
1127    const char *        inExceptionString,
1128    const char *        inErrorString,
1129    const char *        inFileName,
1130    long inLineNumber,
1131    void *              inValue,
1132    ConstStr255Param inOutputMsg )
1133{
1134    DEBUG_UNUSED( inComponentSignature );
1135    DEBUG_UNUSED( inOptions );
1136    DEBUG_UNUSED( inExceptionString );
1137    DEBUG_UNUSED( inValue );
1138    DEBUG_UNUSED( inOutputMsg );
1139
1140    DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
1141}
1142#endif
1143
1144#if 0
1145#pragma mark -
1146#pragma mark == Utilities ==
1147#endif
1148
1149//===========================================================================================================================
1150//	DebugSNPrintF
1151//
1152//	Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
1153//
1154//	Changed names to avoid name collisions with the mDNS versions.
1155//	Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
1156//	Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
1157//	Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
1158//	Added %@   - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
1159//	Added %.8a - FIbre Channel address. Arg=ptr to address.
1160//	Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
1161//	Added %b   - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
1162//	Added %C   - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
1163//	Added %H   - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
1164//	Added %#H  - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
1165//	Added %m   - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
1166//	Added %S   - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
1167//	Added %#S  - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
1168//	Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
1169//	Added %U   - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
1170//===========================================================================================================================
1171
1172DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
1173{
1174    size_t length;
1175
1176    va_list ptr;
1177    va_start(ptr,fmt);
1178    length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
1179    va_end(ptr);
1180
1181    return(length);
1182}
1183
1184//===========================================================================================================================
1185//	DebugSNPrintFVAList	- va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
1186//===========================================================================================================================
1187
1188DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
1189{
1190    static const struct DebugSNPrintF_format
1191    {
1192        unsigned leftJustify : 1;
1193        unsigned forceSign : 1;
1194        unsigned zeroPad : 1;
1195        unsigned havePrecision : 1;
1196        unsigned hSize : 1;
1197        char lSize;
1198        char altForm;
1199        char sign;              // +, - or space
1200        unsigned int fieldWidth;
1201        unsigned int precision;
1202    } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1203
1204    size_t nwritten = 0;
1205    int c;
1206    if (buflen == 0) return(0);
1207    buflen--;       // Pre-reserve one space in the buffer for the terminating nul
1208    if (buflen == 0) goto exit;
1209
1210    for (c = *fmt; c != 0; c = *++fmt)
1211    {
1212        if (c != '%')
1213        {
1214            *sbuffer++ = (char)c;
1215            if (++nwritten >= buflen) goto exit;
1216        }
1217        else
1218        {
1219            size_t i=0, j;
1220            // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
1221            // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
1222            // The size needs to be enough for a 256-byte domain name plus some error text.
1223            #define mDNS_VACB_Size 300
1224            char mDNS_VACB[mDNS_VACB_Size];
1225            #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
1226            #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
1227            char *s = mDNS_VACB_Lim;
1228            const char *digits = "0123456789ABCDEF";
1229            struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
1230
1231            for(;;) //  decode flags
1232            {
1233                c = *++fmt;
1234                if      (c == '-') F.leftJustify = 1;
1235                else if (c == '+') F.forceSign = 1;
1236                else if (c == ' ') F.sign = ' ';
1237                else if (c == '#') F.altForm++;
1238                else if (c == '0') F.zeroPad = 1;
1239                else break;
1240            }
1241
1242            if (c == '*')   //  decode field width
1243            {
1244                int f = va_arg(arg, int);
1245                if (f < 0) { f = -f; F.leftJustify = 1; }
1246                F.fieldWidth = (unsigned int)f;
1247                c = *++fmt;
1248            }
1249            else
1250            {
1251                for (; c >= '0' && c <= '9'; c = *++fmt)
1252                    F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
1253            }
1254
1255            if (c == '.')   //  decode precision
1256            {
1257                if ((c = *++fmt) == '*')
1258                { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
1259                else for (; c >= '0' && c <= '9'; c = *++fmt)
1260                        F.precision = (10 * F.precision) + (c - '0');
1261                F.havePrecision = 1;
1262            }
1263
1264            if (F.leftJustify) F.zeroPad = 0;
1265
1266conv:
1267            switch (c)  //  perform appropriate conversion
1268            {
1269                #if TYPE_LONGLONG_NATIVE
1270                unsigned_long_long_compat n;
1271                unsigned_long_long_compat base;
1272                #else
1273                unsigned long n;
1274                unsigned long base;
1275                #endif
1276            case 'h':  F.hSize = 1; c = *++fmt; goto conv;
1277            case 'l':       // fall through
1278            case 'L':  F.lSize++; c = *++fmt; goto conv;
1279            case 'd':
1280            case 'i':  base = 10;
1281                goto canBeSigned;
1282            case 'u':  base = 10;
1283                goto notSigned;
1284            case 'o':  base = 8;
1285                goto notSigned;
1286            case 'b':  base = 2;
1287                goto notSigned;
1288            case 'p':  n = va_arg(arg, uintptr_t);
1289                F.havePrecision = 1;
1290                F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
1291                F.sign = 0;
1292                base = 16;
1293                c = 'x';
1294                goto number;
1295            case 'x':  digits = "0123456789abcdef";
1296            case 'X':  base = 16;
1297                goto notSigned;
1298canBeSigned:
1299                            #if TYPE_LONGLONG_NATIVE
1300                if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
1301                else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
1302                else n = (unsigned_long_long_compat)va_arg(arg, int);
1303                            #else
1304                if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
1305                else if (F.lSize == 2) goto exit;
1306                else n = (unsigned long)va_arg(arg, int);
1307                            #endif
1308                if (F.hSize) n = (short) n;
1309                            #if TYPE_LONGLONG_NATIVE
1310                if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
1311                            #else
1312                if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
1313                            #endif
1314                else if (F.forceSign) F.sign = '+';
1315                goto number;
1316
1317notSigned:  if (F.lSize == 1) n = va_arg(arg, unsigned long);
1318                else if (F.lSize == 2)
1319                {
1320                                #if TYPE_LONGLONG_NATIVE
1321                    n = va_arg(arg, unsigned_long_long_compat);
1322                                #else
1323                    goto exit;
1324                                #endif
1325                }
1326                else n = va_arg(arg, unsigned int);
1327                if (F.hSize) n = (unsigned short) n;
1328                F.sign = 0;
1329                goto number;
1330
1331number:     if (!F.havePrecision)
1332                {
1333                    if (F.zeroPad)
1334                    {
1335                        F.precision = F.fieldWidth;
1336                        if (F.altForm) F.precision -= 2;
1337                        if (F.sign) --F.precision;
1338                    }
1339                    if (F.precision < 1) F.precision = 1;
1340                }
1341                if (F.precision > mDNS_VACB_Size - 1)
1342                    F.precision = mDNS_VACB_Size - 1;
1343                for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
1344                for (; i < F.precision; i++) *--s = '0';
1345                if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
1346                if (F.sign) { *--s = F.sign; i++; }
1347                break;
1348
1349            case 'a':  {
1350                unsigned char *a = va_arg(arg, unsigned char *);
1351                char pre[4] = "";
1352                char post[32] = "";
1353                if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1354                else
1355                {
1356                    s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1357                    if (F.altForm == 1)
1358                    {
1359                                    #if (defined(MDNS_DEBUGMSGS))
1360                        mDNSAddr *ip = (mDNSAddr*)a;
1361                        switch (ip->type)
1362                        {
1363                        case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
1364                        case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
1365                        default:                F.precision =  0; break;
1366                        }
1367                                    #else
1368                        F.precision = 0;                    // mDNSEmbeddedAPI.h not included so no mDNSAddr support
1369                                    #endif
1370                    }
1371                    else if (F.altForm == 2)
1372                    {
1373                                    #ifdef AF_INET
1374                        const struct sockaddr *sa;
1375                        unsigned char *port;
1376                        sa = (const struct sockaddr*)a;
1377                        switch (sa->sa_family)
1378                        {
1379                        case AF_INET:  F.precision =  4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
1380                            port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
1381                            DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
1382                                            #ifdef AF_INET6
1383                        case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr;
1384                            pre[0] = '['; pre[1] = '\0';
1385                            port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
1386                            DebugSNPrintF(post, sizeof(post), "%%%d]:%d",
1387                                          (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
1388                                          (port[0] << 8) | port[1]); break;
1389                                            #endif
1390                        default:       F.precision =  0; break;
1391                        }
1392                                    #else
1393                        F.precision = 0;                    // socket interfaces not included so no sockaddr support
1394                                    #endif
1395                    }
1396                    switch (F.precision)
1397                    {
1398                    case  4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
1399                                               a[0], a[1], a[2], a[3], post); break;
1400                    case  6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
1401                                               a[0], a[1], a[2], a[3], a[4], a[5]); break;
1402                    case  8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
1403                                               a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
1404                    case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB),
1405                                               "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
1406                                               pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
1407                                               a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;
1408                    default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
1409                                               "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
1410                    }
1411                }
1412            }
1413            break;
1414
1415            case 'U':  {
1416                unsigned char *a = va_arg(arg, unsigned char *);
1417                if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1418                else
1419                {
1420                    s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1421                    i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1422                                      *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]),
1423                                      a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
1424                }
1425            }
1426            break;
1427
1428            case 'c':  *--s = (char)va_arg(arg, int); i = 1; break;
1429
1430            case 'C':  if (F.lSize) n = va_arg(arg, unsigned long);
1431                else n = va_arg(arg, unsigned int);
1432                if (F.hSize) n = (unsigned short) n;
1433                c = (int)( n        & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
1434                c = (int)((n >>  8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
1435                c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
1436                c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
1437                i = 4;
1438                break;
1439
1440            case 's':  s = va_arg(arg, char *);
1441                if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1442                else switch (F.altForm)
1443                    {
1444                    case 0: i=0;
1445                        if (F.havePrecision)                                // C string
1446                        {
1447                            while((i < F.precision) && s[i]) i++;
1448                            // Make sure we don't truncate in the middle of a UTF-8 character.
1449                            // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
1450                            j=0;
1451                            while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break;}
1452                            // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
1453                            if((j > 1) && (j <= 6))
1454                            {
1455                                int test = (0xFF << (8-j)) & 0xFF;
1456                                int mask = test | (1 << ((8-j)-1));
1457                                if((c & mask) == test) i += j;
1458                            }
1459                        }
1460                        else
1461                            while(s[i]) i++;
1462                        break;
1463                    case 1: i = (unsigned char) *s++; break;                // Pascal string
1464                    case 2: {                                               // DNS label-sequence name
1465                        unsigned char *a = (unsigned char *)s;
1466                        s = mDNS_VACB;                  // Adjust s to point to the start of the buffer, not the end
1467                        if (*a == 0) *s++ = '.';                    // Special case for root DNS name
1468                        while (*a)
1469                        {
1470                            if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
1471                            if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
1472                            s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
1473                            a += 1 + *a;
1474                        }
1475                        i = (size_t)(s - mDNS_VACB);
1476                        s = mDNS_VACB;                  // Reset s back to the start of the buffer
1477                        break;
1478                    }
1479                    }
1480                if (F.havePrecision && i > F.precision)                 // Make sure we don't truncate in the middle of a UTF-8 character
1481                { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
1482                break;
1483
1484            case 'S':   {       // UTF-16 string
1485                unsigned char *a = va_arg(arg, unsigned char *);
1486                uint16_t      *u = (uint16_t*)a;
1487                if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
1488                if ((!F.havePrecision || F.precision))
1489                {
1490                    if      ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; }                // Big Endian
1491                    else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; }                // Little Endian
1492                }
1493                s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1494                switch (F.altForm)
1495                {
1496                case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))                  // Host Endian
1497                    { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
1498                    break;
1499                case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))                  // Big Endian
1500                    { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
1501                    break;
1502                case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s))                  // Little Endian
1503                    { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
1504                    break;
1505                }
1506            }
1507                s = mDNS_VACB;              // Reset s back to the start of the buffer
1508                break;
1509
1510            #if TARGET_OS_MAC
1511            case '@':   {       // Cocoa/CoreFoundation object
1512                CFTypeRef cfObj;
1513                CFStringRef cfStr;
1514                cfObj = (CFTypeRef) va_arg(arg, void *);
1515                cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
1516                s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1517                if (cfStr)
1518                {
1519                    CFRange range;
1520                    CFIndex m;
1521                    range = CFRangeMake(0, CFStringGetLength(cfStr));
1522                    m = 0;
1523                    CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
1524                    CFRelease(cfStr);
1525                    i = (size_t) m;
1526                }
1527                else
1528                {
1529                    i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
1530                }
1531            }
1532                if (F.havePrecision && i > F.precision)                 // Make sure we don't truncate in the middle of a UTF-8 character
1533                { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
1534                break;
1535            #endif
1536
1537            case 'm':  {        // Error Message
1538                long err;
1539                if (F.lSize) err = va_arg(arg, long);
1540                else err = va_arg(arg, int);
1541                if (F.hSize) err = (short)err;
1542                DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
1543                s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1544                for(i=0; s[i]; i++) {}
1545            }
1546            break;
1547
1548            case 'H':  {        // Hex Dump
1549                void *a = va_arg(arg, void *);
1550                size_t size = (size_t)va_arg(arg, int);
1551                size_t max = (size_t)va_arg(arg, int);
1552                DebugFlags flags =
1553                    kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
1554                    kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
1555                    kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
1556                if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
1557                size = (max < size) ? max : size;
1558                s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1559                i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
1560            }
1561            break;
1562
1563            case 'v':  {        // Version
1564                uint32_t version;
1565                version = va_arg(arg, unsigned int);
1566                DebugNumVersionToString(version, mDNS_VACB);
1567                s = mDNS_VACB;              // Adjust s to point to the start of the buffer, not the end
1568                for(i=0; s[i]; i++) {}
1569            }
1570            break;
1571
1572            case 'n':  s = va_arg(arg, char *);
1573                if      (F.hSize) *(short *) s = (short)nwritten;
1574                else if (F.lSize) *(long  *) s = (long)nwritten;
1575                else *(int   *) s = (int)nwritten;
1576                continue;
1577
1578            default:    s = mDNS_VACB;
1579                i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
1580
1581            case '%':  *sbuffer++ = (char)c;
1582                if (++nwritten >= buflen) goto exit;
1583                break;
1584            }
1585
1586            if (i < F.fieldWidth && !F.leftJustify)         // Pad on the left
1587                do  {
1588                    *sbuffer++ = ' ';
1589                    if (++nwritten >= buflen) goto exit;
1590                } while (i < --F.fieldWidth);
1591
1592            if (i > buflen - nwritten)  // Make sure we don't truncate in the middle of a UTF-8 character
1593            { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
1594            for (j=0; j<i; j++) *sbuffer++ = *s++;          // Write the converted result
1595            nwritten += i;
1596            if (nwritten >= buflen) goto exit;
1597
1598            for (; i < F.fieldWidth; i++)                   // Pad on the right
1599            {
1600                *sbuffer++ = ' ';
1601                if (++nwritten >= buflen) goto exit;
1602            }
1603        }
1604    }
1605exit:
1606    *sbuffer++ = 0;
1607    return(nwritten);
1608}
1609
1610//===========================================================================================================================
1611//	DebugGetErrorString
1612//===========================================================================================================================
1613
1614DEBUG_EXPORT const char *   DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
1615{
1616    const char *        s;
1617    char *              dst;
1618    char *              end;
1619#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
1620    char buffer[ 256 ];
1621#endif
1622
1623    switch( inErrorCode )
1624    {
1625        #define CaseErrorString( X, STR )                   case X: s = STR; break
1626        #define CaseErrorStringify( X )                     case X: s = # X; break
1627        #define CaseErrorStringifyHardCode( VALUE, X )      case VALUE: s = # X; break
1628
1629        // General Errors
1630
1631        CaseErrorString( 0,  "no error" );
1632        CaseErrorString( 1,  "in-progress/waiting" );
1633        CaseErrorString( -1, "catch-all unknown error" );
1634
1635        // ACP Errors
1636
1637        CaseErrorStringifyHardCode( -2,  kACPBadRequestErr );
1638        CaseErrorStringifyHardCode( -3,  kACPNoMemoryErr );
1639        CaseErrorStringifyHardCode( -4,  kACPBadParamErr );
1640        CaseErrorStringifyHardCode( -5,  kACPNotFoundErr );
1641        CaseErrorStringifyHardCode( -6,  kACPBadChecksumErr );
1642        CaseErrorStringifyHardCode( -7,  kACPCommandNotHandledErr );
1643        CaseErrorStringifyHardCode( -8,  kACPNetworkErr );
1644        CaseErrorStringifyHardCode( -9,  kACPDuplicateCommandHandlerErr );
1645        CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
1646        CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
1647        CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
1648        CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
1649        CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
1650        CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
1651        CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
1652        CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
1653        CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
1654        CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
1655        CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
1656        CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
1657        CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
1658        CaseErrorStringifyHardCode( -23, kACPInUseErr );
1659        CaseErrorStringifyHardCode( -24, kACPParamCountErr );
1660        CaseErrorStringifyHardCode( -25, kACPIDErr );
1661        CaseErrorStringifyHardCode( -26, kACPFormatErr );
1662        CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
1663        CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
1664        CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
1665
1666        // Common Services Errors
1667
1668        CaseErrorStringify( kUnknownErr );
1669        CaseErrorStringify( kOptionErr );
1670        CaseErrorStringify( kSelectorErr );
1671        CaseErrorStringify( kExecutionStateErr );
1672        CaseErrorStringify( kPathErr );
1673        CaseErrorStringify( kParamErr );
1674        CaseErrorStringify( kParamCountErr );
1675        CaseErrorStringify( kCommandErr );
1676        CaseErrorStringify( kIDErr );
1677        CaseErrorStringify( kStateErr );
1678        CaseErrorStringify( kRangeErr );
1679        CaseErrorStringify( kRequestErr );
1680        CaseErrorStringify( kResponseErr );
1681        CaseErrorStringify( kChecksumErr );
1682        CaseErrorStringify( kNotHandledErr );
1683        CaseErrorStringify( kVersionErr );
1684        CaseErrorStringify( kSignatureErr );
1685        CaseErrorStringify( kFormatErr );
1686        CaseErrorStringify( kNotInitializedErr );
1687        CaseErrorStringify( kAlreadyInitializedErr );
1688        CaseErrorStringify( kNotInUseErr );
1689        CaseErrorStringify( kInUseErr );
1690        CaseErrorStringify( kTimeoutErr );
1691        CaseErrorStringify( kCanceledErr );
1692        CaseErrorStringify( kAlreadyCanceledErr );
1693        CaseErrorStringify( kCannotCancelErr );
1694        CaseErrorStringify( kDeletedErr );
1695        CaseErrorStringify( kNotFoundErr );
1696        CaseErrorStringify( kNoMemoryErr );
1697        CaseErrorStringify( kNoResourcesErr );
1698        CaseErrorStringify( kDuplicateErr );
1699        CaseErrorStringify( kImmutableErr );
1700        CaseErrorStringify( kUnsupportedDataErr );
1701        CaseErrorStringify( kIntegrityErr );
1702        CaseErrorStringify( kIncompatibleErr );
1703        CaseErrorStringify( kUnsupportedErr );
1704        CaseErrorStringify( kUnexpectedErr );
1705        CaseErrorStringify( kValueErr );
1706        CaseErrorStringify( kNotReadableErr );
1707        CaseErrorStringify( kNotWritableErr );
1708        CaseErrorStringify( kBadReferenceErr );
1709        CaseErrorStringify( kFlagErr );
1710        CaseErrorStringify( kMalformedErr );
1711        CaseErrorStringify( kSizeErr );
1712        CaseErrorStringify( kNameErr );
1713        CaseErrorStringify( kNotReadyErr );
1714        CaseErrorStringify( kReadErr );
1715        CaseErrorStringify( kWriteErr );
1716        CaseErrorStringify( kMismatchErr );
1717        CaseErrorStringify( kDateErr );
1718        CaseErrorStringify( kUnderrunErr );
1719        CaseErrorStringify( kOverrunErr );
1720        CaseErrorStringify( kEndingErr );
1721        CaseErrorStringify( kConnectionErr );
1722        CaseErrorStringify( kAuthenticationErr );
1723        CaseErrorStringify( kOpenErr );
1724        CaseErrorStringify( kTypeErr );
1725        CaseErrorStringify( kSkipErr );
1726        CaseErrorStringify( kNoAckErr );
1727        CaseErrorStringify( kCollisionErr );
1728        CaseErrorStringify( kBackoffErr );
1729        CaseErrorStringify( kNoAddressAckErr );
1730        CaseErrorStringify( kBusyErr );
1731        CaseErrorStringify( kNoSpaceErr );
1732
1733        // mDNS/DNS-SD Errors
1734
1735        CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
1736        CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
1737        CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
1738        CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
1739        CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
1740        CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
1741        CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
1742        CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
1743        CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
1744        CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
1745        CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
1746        CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
1747        CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
1748        CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
1749        CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
1750        CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
1751        CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
1752        CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
1753
1754        // RSP Errors
1755
1756        CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
1757        CaseErrorStringifyHardCode( -400050, kRSPParamErr );
1758        CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
1759        CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
1760        CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
1761        CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
1762        CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );
1763        CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
1764        CaseErrorStringifyHardCode( -402419, kRSPIDErr );
1765        CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
1766        CaseErrorString(            -200000, "kRSPControllerStatusBase - 0x50" );
1767        CaseErrorString(            -200080, "kRSPCommandSucceededErr - 0x50" );
1768        CaseErrorString(            -200001, "kRSPCommandFailedErr - 0x01" );
1769        CaseErrorString(            -200051, "kRSPChecksumErr - 0x33" );
1770        CaseErrorString(            -200132, "kRSPCommandTimeoutErr - 0x84" );
1771        CaseErrorString(            -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
1772        CaseErrorString(            -200128, "kRSPCanceledErr - 0x02 Async" );
1773
1774        // XML Errors
1775
1776        CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
1777        CaseErrorStringifyHardCode( -100050, kXMLParamErr );
1778        CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
1779        CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
1780        CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
1781        CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
1782        CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
1783        CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
1784        CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
1785        CaseErrorStringifyHardCode( -103026, kXMLParseErr );
1786        CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
1787        CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
1788        CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
1789        CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
1790        CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
1791        CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
1792        CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
1793        CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
1794        CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
1795        CaseErrorStringifyHardCode( -102015, kXMLDateErr );
1796
1797    #if ( __MACH__ )
1798
1799        // Mach Errors
1800
1801        CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
1802        CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
1803        CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
1804        CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
1805        CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
1806        CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
1807        CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
1808        CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
1809        CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
1810        CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
1811        CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
1812        CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
1813        CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
1814        CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
1815        CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
1816        CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
1817        CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
1818        CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
1819        CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
1820        CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
1821        CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
1822        CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
1823        CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
1824        CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
1825        CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
1826        CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
1827        CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
1828        CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
1829        CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
1830        CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
1831        CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
1832        CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
1833        CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
1834        CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
1835        CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
1836        CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
1837
1838        // Mach OSReturn Errors
1839
1840        CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
1841        CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
1842        CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
1843        CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
1844        CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
1845        CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
1846        CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
1847        CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
1848        CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
1849        CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
1850        CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
1851
1852        // IOKit Errors
1853
1854        CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
1855        CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
1856        CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
1857        CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
1858        CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
1859        CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
1860        CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
1861        CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
1862        CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
1863        CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
1864        CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
1865        CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
1866        CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
1867        CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
1868        CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
1869        CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
1870        CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
1871        CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
1872        CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
1873        CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
1874        CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
1875        CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
1876        CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
1877        CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
1878        CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
1879        CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
1880        CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
1881        CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
1882        CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
1883        CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
1884        CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
1885        CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
1886        CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
1887        CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
1888        CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
1889        CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
1890        CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
1891        CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
1892        CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
1893        CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
1894        CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
1895        CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
1896        CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
1897        CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError     );
1898        CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion    );
1899        CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted     );
1900        CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth     );
1901        CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding   );
1902        CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld   );
1903        CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew   );
1904        CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
1905        CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
1906
1907        // IOKit FireWire Errors
1908
1909        CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
1910        CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
1911        CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
1912        CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
1913        CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
1914        CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
1915        CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
1916        CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
1917        CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
1918        CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
1919        CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
1920        CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
1921        CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
1922        CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
1923        CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
1924        CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
1925        CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
1926        CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
1927        CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
1928        CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
1929        CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
1930        CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
1931        CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
1932
1933        // IOKit USB Errors
1934
1935        CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
1936        CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
1937        CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
1938        CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
1939        CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
1940        CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
1941        CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
1942        CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
1943        CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
1944        CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
1945        CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
1946        CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
1947        CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
1948        CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
1949        CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
1950        CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
1951        CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
1952        CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
1953        CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
1954        CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
1955        CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
1956        CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
1957        CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
1958        CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
1959        CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
1960        CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
1961
1962    #endif  // __MACH__
1963
1964    // Other Errors
1965
1966    default:
1967        s = NULL;
1968            #if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
1969        if( inBuffer && ( inBufferSize > 0 ) )
1970        {
1971            DWORD n;
1972
1973            n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode,
1974                                MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL );
1975            if( n > 0 )
1976            {
1977                // Remove any trailing CR's or LF's since some messages have them.
1978
1979                while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) )
1980                {
1981                    buffer[ --n ] = '\0';
1982                }
1983                s = buffer;
1984            }
1985        }
1986            #endif
1987
1988        if( !s )
1989        {
1990                #if ( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
1991            s = strerror( inErrorCode );
1992                #endif
1993            if( !s )
1994            {
1995                s = "<unknown error code>";
1996            }
1997        }
1998        break;
1999    }
2000
2001    // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
2002
2003    if( inBuffer && ( inBufferSize > 0 ) )
2004    {
2005        dst = inBuffer;
2006        end = dst + ( inBufferSize - 1 );
2007        while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
2008        {
2009            *dst++ = *s++;
2010        }
2011        *dst = '\0';
2012        s = inBuffer;
2013    }
2014    return( s );
2015}
2016
2017//===========================================================================================================================
2018//	DebugHexDump
2019//===========================================================================================================================
2020
2021DEBUG_EXPORT size_t
2022DebugHexDump(
2023    DebugLevel inLevel,
2024    int inIndent,
2025    const char *    inLabel,
2026    size_t inLabelSize,
2027    int inLabelMinWidth,
2028    const char *    inType,
2029    size_t inTypeSize,
2030    const void *    inDataStart,
2031    const void *    inData,
2032    size_t inDataSize,
2033    DebugFlags inFlags,
2034    char *          outBuffer,
2035    size_t inBufferSize )
2036{
2037    static const char kHexChars[] = "0123456789ABCDEF";
2038    const uint8_t *         start;
2039    const uint8_t *         src;
2040    char *                  dst;
2041    char *                  end;
2042    size_t n;
2043    int offset;
2044    int width;
2045    const char *            newline;
2046    char separator[ 8 ];
2047    char *                  s;
2048
2049    DEBUG_UNUSED( inType );
2050    DEBUG_UNUSED( inTypeSize );
2051
2052    // Set up the function-wide variables.
2053
2054    if( inLabelSize == kSizeCString )
2055    {
2056        inLabelSize = strlen( inLabel );
2057    }
2058    start   = (const uint8_t *) inData;
2059    src     = start;
2060    dst     = outBuffer;
2061    end     = dst + inBufferSize;
2062    offset  = (int)( (intptr_t) inData - (intptr_t) inDataStart );
2063    width   = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
2064    newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
2065
2066    // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
2067
2068    s = separator;
2069    if( inFlags & kDebugFlagsNoNewLine )
2070    {
2071        if( inFlags & kDebugFlags8BitSeparator )
2072        {
2073            *s++ = ' ';
2074        }
2075        if( inFlags & kDebugFlags16BitSeparator )
2076        {
2077            *s++ = ' ';
2078        }
2079        if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
2080        {
2081            *s++ = ' ';
2082        }
2083        check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
2084    }
2085    *s = '\0';
2086
2087    for( ;; )
2088    {
2089        char prefixString[ 32 ];
2090        char hexString[ 64 ];
2091        char asciiString[ 32 ];
2092        char byteCountString[ 32 ];
2093        int c;
2094        size_t chunkSize;
2095        size_t i;
2096
2097        // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
2098
2099        if( inDataSize == 0 )
2100        {
2101            if( inLabel && ( inLabelSize > 0 ) )
2102            {
2103                width = 0;
2104                if( !( inFlags & kDebugFlagsNoAddress ) )
2105                {
2106                    width += 8;         // "00000000"
2107                    if( !( inFlags & kDebugFlagsNoOffset ) )
2108                    {
2109                        width += 1;     // "+"
2110                    }
2111                }
2112                if( inFlags & kDebugFlags32BitOffset )
2113                {
2114                    width += 8;         // "00000000"
2115                }
2116                else if( !( inFlags & kDebugFlagsNoOffset ) )
2117                {
2118                    width += 4;         // "0000"
2119                }
2120
2121                if( outBuffer )
2122                {
2123                    dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s",
2124                                          width, "",
2125                                          ( width > 0 ) ? ": " : "",
2126                                          width, (int) inLabelSize, inLabel,
2127                                          newline );
2128                }
2129                else
2130                {
2131                    dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s",
2132                                        width, "",
2133                                        ( width > 0 ) ? ": " : "",
2134                                        width, (int) inLabelSize, inLabel,
2135                                        newline );
2136                }
2137            }
2138            break;
2139        }
2140
2141        // Build the prefix string. It will be in one of the following formats:
2142        //
2143        // 1) "00000000+0000[0000]"	(address and offset)
2144        // 2) "00000000"			(address only)
2145        // 3) "0000[0000]"			(offset only)
2146        // 4) ""					(no address or offset)
2147        //
2148        // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
2149
2150        s = prefixString;
2151        if( !( inFlags & kDebugFlagsNoAddress ) )
2152        {
2153            *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
2154            *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
2155            *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
2156            *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
2157            *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
2158            *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  8 ) & 0xF ];
2159            *s++ = kHexChars[ ( ( (uintptr_t) src ) >>  4 ) & 0xF ];
2160            *s++ = kHexChars[   ( (uintptr_t) src )         & 0xF ];
2161
2162            if( !( inFlags & kDebugFlagsNoOffset ) )
2163            {
2164                *s++ = '+';
2165            }
2166        }
2167        if( !( inFlags & kDebugFlagsNoOffset ) )
2168        {
2169            if( inFlags & kDebugFlags32BitOffset )
2170            {
2171                *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
2172                *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
2173                *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
2174                *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
2175            }
2176            *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
2177            *s++ = kHexChars[ ( offset >>  8 ) & 0xF ];
2178            *s++ = kHexChars[ ( offset >>  4 ) & 0xF ];
2179            *s++ = kHexChars[   offset         & 0xF ];
2180        }
2181        if( s != prefixString )
2182        {
2183            *s++ = ':';
2184            *s++ = ' ';
2185        }
2186        check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
2187        *s = '\0';
2188
2189        // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
2190        // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
2191
2192        s = hexString;
2193        chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
2194        n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
2195        for( i = 0; i < n; ++i )
2196        {
2197            if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
2198            {
2199                *s++ = ' ';
2200            }
2201            if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
2202            {
2203                *s++ = ' ';
2204            }
2205            if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
2206            {
2207                *s++ = ' ';
2208            }
2209            if( i < chunkSize )
2210            {
2211                *s++ = kHexChars[ src[ i ] >> 4   ];
2212                *s++ = kHexChars[ src[ i ] &  0xF ];
2213            }
2214            else
2215            {
2216                *s++ = ' ';
2217                *s++ = ' ';
2218            }
2219        }
2220        check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
2221        *s = '\0';
2222
2223        // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
2224        // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
2225
2226        s = asciiString;
2227        if( !( inFlags & kDebugFlagsNoASCII ) )
2228        {
2229            *s++ = ' ';
2230            *s++ = '|';
2231            for( i = 0; i < n; ++i )
2232            {
2233                if( i < chunkSize )
2234                {
2235                    c = src[ i ];
2236                    if( !DebugIsPrint( c ) )
2237                    {
2238                        c = '^';
2239                    }
2240                }
2241                else
2242                {
2243                    c = '`';
2244                }
2245                *s++ = (char) c;
2246            }
2247            *s++ = '|';
2248            check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
2249        }
2250        *s = '\0';
2251
2252        // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
2253
2254        s = byteCountString;
2255        if( !( inFlags & kDebugFlagsNoByteCount ) )
2256        {
2257            if( src == start )
2258            {
2259                s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
2260            }
2261        }
2262        check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
2263        *s = '\0';
2264
2265        // Build the entire line from all the pieces we've previously built.
2266
2267        if( outBuffer )
2268        {
2269            if( src == start )
2270            {
2271                dst += DebugSNPrintF( dst, (size_t)( end - dst ),
2272                                      "%*s" // Indention
2273                                      "%s" // Separator (only if needed)
2274                                      "%s" // Prefix
2275                                      "%-*.*s" // Label
2276                                      "%s" // Separator
2277                                      "%s" // Hex
2278                                      "%s" // ASCII
2279                                      "%s" // Byte Count
2280                                      "%s", // Newline
2281                                      inIndent, "",
2282                                      ( src != start ) ? separator : "",
2283                                      prefixString,
2284                                      width, (int) inLabelSize, inLabel ? inLabel : "",
2285                                      ( width > 0 ) ? " " : "",
2286                                      hexString,
2287                                      asciiString,
2288                                      byteCountString,
2289                                      newline );
2290            }
2291            else
2292            {
2293                dst += DebugSNPrintF( dst, (size_t)( end - dst ),
2294                                      "%*s" // Indention
2295                                      "%s" // Separator (only if needed)
2296                                      "%s" // Prefix
2297                                      "%*s" // Label Spacing
2298                                      "%s" // Separator
2299                                      "%s" // Hex
2300                                      "%s" // ASCII
2301                                      "%s" // Byte Count
2302                                      "%s", // Newline
2303                                      inIndent, "",
2304                                      ( src != start ) ? separator : "",
2305                                      prefixString,
2306                                      width, "",
2307                                      ( width > 0 ) ? " " : "",
2308                                      hexString,
2309                                      asciiString,
2310                                      byteCountString,
2311                                      newline );
2312            }
2313        }
2314        else
2315        {
2316            if( src == start )
2317            {
2318                dst += DebugPrintF( inLevel,
2319                                    "%*s" // Indention
2320                                    "%s" // Separator (only if needed)
2321                                    "%s" // Prefix
2322                                    "%-*.*s" // Label
2323                                    "%s" // Separator
2324                                    "%s" // Hex
2325                                    "%s" // ASCII
2326                                    "%s" // Byte Count
2327                                    "%s", // Newline
2328                                    inIndent, "",
2329                                    ( src != start ) ? separator : "",
2330                                    prefixString,
2331                                    width, (int) inLabelSize, inLabel,
2332                                    ( width > 0 ) ? " " : "",
2333                                    hexString,
2334                                    asciiString,
2335                                    byteCountString,
2336                                    newline );
2337            }
2338            else
2339            {
2340                dst += DebugPrintF( inLevel,
2341                                    "%*s" // Indention
2342                                    "%s" // Separator (only if needed)
2343                                    "%s" // Prefix
2344                                    "%*s" // Label Spacing
2345                                    "%s" // Separator
2346                                    "%s" // Hex
2347                                    "%s" // ASCII
2348                                    "%s" // Byte Count
2349                                    "%s", // Newline
2350                                    inIndent, "",
2351                                    ( src != start ) ? separator : "",
2352                                    prefixString,
2353                                    width, "",
2354                                    ( width > 0 ) ? " " : "",
2355                                    hexString,
2356                                    asciiString,
2357                                    byteCountString,
2358                                    newline );
2359            }
2360        }
2361
2362        // Move to the next chunk. Exit if there is no more data.
2363
2364        offset      += (int) chunkSize;
2365        src         += chunkSize;
2366        inDataSize  -= chunkSize;
2367        if( inDataSize == 0 )
2368        {
2369            break;
2370        }
2371    }
2372
2373    // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
2374
2375    return( (size_t)( dst - outBuffer ) );
2376}
2377
2378//===========================================================================================================================
2379//	DebugNumVersionToString
2380//===========================================================================================================================
2381
2382static char *   DebugNumVersionToString( uint32_t inVersion, char *inString )
2383{
2384    char *      s;
2385    uint8_t majorRev;
2386    uint8_t minor;
2387    uint8_t bugFix;
2388    uint8_t stage;
2389    uint8_t revision;
2390
2391    check( inString );
2392
2393    majorRev    = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
2394    minor       = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
2395    bugFix      = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
2396    stage       = (uint8_t)( ( inVersion >>  8 ) & 0xFF );
2397    revision    = (uint8_t)(   inVersion         & 0xFF );
2398
2399    // Convert the major, minor, and bugfix numbers.
2400
2401    s  = inString;
2402    s += sprintf( s, "%u", majorRev );
2403    s += sprintf( s, ".%u", minor );
2404    if( bugFix != 0 )
2405    {
2406        s += sprintf( s, ".%u", bugFix );
2407    }
2408
2409    // Convert the version stage and non-release revision number.
2410
2411    switch( stage )
2412    {
2413    case kVersionStageDevelopment:
2414        s += sprintf( s, "d%u", revision );
2415        break;
2416
2417    case kVersionStageAlpha:
2418        s += sprintf( s, "a%u", revision );
2419        break;
2420
2421    case kVersionStageBeta:
2422        s += sprintf( s, "b%u", revision );
2423        break;
2424
2425    case kVersionStageFinal:
2426
2427        // A non-release revision of zero is a special case indicating the software is GM (at the golden master
2428        // stage) and therefore, the non-release revision should not be added to the string.
2429
2430        if( revision != 0 )
2431        {
2432            s += sprintf( s, "f%u", revision );
2433        }
2434        break;
2435
2436    default:
2437        dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
2438        break;
2439    }
2440    return( inString );
2441}
2442
2443//===========================================================================================================================
2444//	DebugTaskLevel
2445//===========================================================================================================================
2446
2447DEBUG_EXPORT uint32_t   DebugTaskLevel( void )
2448{
2449    uint32_t level;
2450
2451    level = 0;
2452
2453#if ( TARGET_OS_VXWORKS )
2454    if( intContext() )
2455    {
2456        level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
2457    }
2458#endif
2459
2460    return( level );
2461}
2462
2463#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
2464//===========================================================================================================================
2465//	DebugWinEnableConsole
2466//===========================================================================================================================
2467
2468#pragma warning( disable:4311 )
2469
2470static void DebugWinEnableConsole( void )
2471{
2472    static bool sConsoleEnabled = false;
2473    BOOL result;
2474    int fileHandle;
2475    FILE *          file;
2476    int err;
2477
2478    if( sConsoleEnabled )
2479    {
2480        goto exit;
2481    }
2482
2483    // Create console window.
2484
2485    result = AllocConsole();
2486    require_quiet( result, exit );
2487
2488    // Redirect stdin to the console stdin.
2489
2490    fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
2491
2492    #if ( defined( __MWERKS__ ) )
2493    file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
2494    require_quiet( file, exit );
2495    #else
2496    file = _fdopen( fileHandle, "r" );
2497    require_quiet( file, exit );
2498
2499    *stdin = *file;
2500    #endif
2501
2502    err = setvbuf( stdin, NULL, _IONBF, 0 );
2503    require_noerr_quiet( err, exit );
2504
2505    // Redirect stdout to the console stdout.
2506
2507    fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
2508
2509    #if ( defined( __MWERKS__ ) )
2510    file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
2511    require_quiet( file, exit );
2512    #else
2513    file = _fdopen( fileHandle, "w" );
2514    require_quiet( file, exit );
2515
2516    *stdout = *file;
2517    #endif
2518
2519    err = setvbuf( stdout, NULL, _IONBF, 0 );
2520    require_noerr_quiet( err, exit );
2521
2522    // Redirect stderr to the console stdout.
2523
2524    fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
2525
2526    #if ( defined( __MWERKS__ ) )
2527    file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
2528    require_quiet( file, exit );
2529    #else
2530    file = _fdopen( fileHandle, "w" );
2531    require_quiet( file, exit );
2532
2533    *stderr = *file;
2534    #endif
2535
2536    err = setvbuf( stderr, NULL, _IONBF, 0 );
2537    require_noerr_quiet( err, exit );
2538
2539    sConsoleEnabled = true;
2540
2541exit:
2542    return;
2543}
2544
2545#pragma warning( default:4311 )
2546
2547#endif  // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
2548
2549#if ( TARGET_OS_WIN32 )
2550//===========================================================================================================================
2551//	DebugWinCharToTCharString
2552//===========================================================================================================================
2553
2554static TCHAR *
2555DebugWinCharToTCharString(
2556    const char *    inCharString,
2557    size_t inCharCount,
2558    TCHAR *         outTCharString,
2559    size_t inTCharCountMax,
2560    size_t *        outTCharCount )
2561{
2562    const char *        src;
2563    TCHAR *             dst;
2564    TCHAR *             end;
2565
2566    if( inCharCount == kSizeCString )
2567    {
2568        inCharCount = strlen( inCharString );
2569    }
2570    src = inCharString;
2571    dst = outTCharString;
2572    if( inTCharCountMax > 0 )
2573    {
2574        inTCharCountMax -= 1;
2575        if( inTCharCountMax > inCharCount )
2576        {
2577            inTCharCountMax = inCharCount;
2578        }
2579
2580        end = dst + inTCharCountMax;
2581        while( dst < end )
2582        {
2583            *dst++ = (TCHAR) *src++;
2584        }
2585        *dst = 0;
2586    }
2587    if( outTCharCount )
2588    {
2589        *outTCharCount = (size_t)( dst - outTCharString );
2590    }
2591    return( outTCharString );
2592}
2593#endif
2594
2595#if 0
2596#pragma mark -
2597#pragma mark == Debugging ==
2598#endif
2599
2600//===========================================================================================================================
2601//	DebugServicesTest
2602//===========================================================================================================================
2603
2604DEBUG_EXPORT OSStatus   DebugServicesTest( void )
2605{
2606    OSStatus err;
2607    char s[ 512 ];
2608    uint8_t *       p;
2609    uint8_t data[] =
2610    {
2611        0x11, 0x22, 0x33, 0x44,
2612        0x55, 0x66,
2613        0x77, 0x88, 0x99, 0xAA,
2614        0xBB, 0xCC, 0xDD,
2615        0xEE,
2616        0xFF,
2617        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
2618        0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,
2619        0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1
2620    };
2621
2622    debug_initialize( kDebugOutputTypeMetaConsole );
2623
2624    // check's
2625
2626    check( 0 && "SHOULD SEE: check" );
2627    check( 1 && "SHOULD *NOT* SEE: check (valid)" );
2628    check_string( 0, "SHOULD SEE: check_string" );
2629    check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
2630    check_noerr( -123 );
2631    check_noerr( 10038 );
2632    check_noerr( 22 );
2633    check_noerr( 0 );
2634    check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
2635    check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
2636    check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
2637    check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
2638    check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
2639    check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
2640    check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10,  5, 10 );
2641    check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12,  6 );
2642    check_ptr_overlap( "SHOULD SEE" ? 12 : 0,  6, 10, 10 );
2643    check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
2644    check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
2645    check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
2646    check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
2647
2648    // require's
2649
2650    require( 0 && "SHOULD SEE", require1 );
2651    { err = kResponseErr; goto exit; }
2652require1:
2653    require( 1 && "SHOULD *NOT* SEE", require2 );
2654    goto require2Good;
2655require2:
2656    { err = kResponseErr; goto exit; }
2657require2Good:
2658    require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
2659    { err = kResponseErr; goto exit; }
2660require3:
2661    require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
2662    goto require4Good;
2663require4:
2664    { err = kResponseErr; goto exit; }
2665require4Good:
2666    require_quiet( 0 && "SHOULD SEE", require5 );
2667    { err = kResponseErr; goto exit; }
2668require5:
2669    require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
2670    goto require6Good;
2671require6:
2672    { err = kResponseErr; goto exit; }
2673require6Good:
2674    require_noerr( -1, require7 );
2675    { err = kResponseErr; goto exit; }
2676require7:
2677    require_noerr( 0, require8 );
2678    goto require8Good;
2679require8:
2680    { err = kResponseErr; goto exit; }
2681require8Good:
2682    require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
2683    { err = kResponseErr; goto exit; }
2684require9:
2685    require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
2686    goto require10Good;
2687require10:
2688    { err = kResponseErr; goto exit; }
2689require10Good:
2690    require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
2691    { err = kResponseErr; goto exit; }
2692require11:
2693    require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
2694    goto require12Good;
2695require12:
2696    { err = kResponseErr; goto exit; }
2697require12Good:
2698    require_noerr_quiet( -4, require13 );
2699    { err = kResponseErr; goto exit; }
2700require13:
2701    require_noerr_quiet( 0, require14 );
2702    goto require14Good;
2703require14:
2704    { err = kResponseErr; goto exit; }
2705require14Good:
2706    require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
2707    { err = kResponseErr; goto exit; }
2708require15:
2709    require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
2710    goto require16Good;
2711require16:
2712    { err = kResponseErr; goto exit; }
2713require16Good:
2714    require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
2715    { err = kResponseErr; goto exit; }
2716require17:
2717    require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
2718    goto require18Good;
2719require18:
2720    { err = kResponseErr; goto exit; }
2721require18Good:
2722    require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
2723    { err = kResponseErr; goto exit; }
2724require19:
2725    require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
2726    goto require20Good;
2727require20:
2728    { err = kResponseErr; goto exit; }
2729require20Good:
2730    require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
2731    { err = kResponseErr; goto exit; }
2732require21:
2733    require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
2734    goto require22Good;
2735require22:
2736    { err = kResponseErr; goto exit; }
2737require22Good:
2738    require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
2739    { err = kResponseErr; goto exit; }
2740require23:
2741    require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
2742    goto require24Good;
2743require24:
2744    { err = kResponseErr; goto exit; }
2745require24Good:
2746
2747#if ( defined( __MWERKS__ )  )
2748    #if ( defined( __cplusplus ) && __option( exceptions ) )
2749        #define COMPILER_HAS_EXCEPTIONS     1
2750    #else
2751        #define COMPILER_HAS_EXCEPTIONS     0
2752    #endif
2753#else
2754    #if ( defined( __cplusplus ) )
2755        #define COMPILER_HAS_EXCEPTIONS     1
2756    #else
2757        #define COMPILER_HAS_EXCEPTIONS     0
2758    #endif
2759#endif
2760
2761#if ( COMPILER_HAS_EXCEPTIONS )
2762    try
2763    {
2764        require_throw( 1 && "SHOULD *NOT* SEE" );
2765        require_throw( 0 && "SHOULD SEE" );
2766    }
2767    catch(... )
2768    {
2769        goto require26Good;
2770    }
2771    { err = kResponseErr; goto exit; }
2772require26Good:
2773#endif
2774
2775    // translate_errno
2776
2777    err = translate_errno( 1 != -1, -123, -567 );
2778    require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
2779
2780    err = translate_errno( -1 != -1, -123, -567 );
2781    require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
2782
2783    err = translate_errno( -1 != -1, 0, -567 );
2784    require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
2785
2786    // debug_string
2787
2788    debug_string( "debug_string" );
2789
2790    // DebugSNPrintF
2791
2792    DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
2793    require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
2794
2795    DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
2796    require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
2797
2798    DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
2799    require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
2800
2801    DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
2802    require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
2803
2804    DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
2805    require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
2806
2807    DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
2808    require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
2809
2810    #if ( TYPE_LONGLONG_NATIVE )
2811    DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
2812    require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
2813
2814    DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
2815    require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
2816
2817    DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
2818    require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
2819    #endif
2820
2821    DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
2822    require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
2823
2824    DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 );  // 'AbCd'
2825    require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
2826
2827    #if ( defined( MDNS_DEBUGMSGS ) )
2828    {
2829        mDNSAddr maddr;
2830
2831        memset( &maddr, 0, sizeof( maddr ) );
2832        maddr.type = mDNSAddrType_IPv4;
2833        maddr.ip.v4.b[ 0 ] = 127;
2834        maddr.ip.v4.b[ 1 ] = 0;
2835        maddr.ip.v4.b[ 2 ] = 0;
2836        maddr.ip.v4.b[ 3 ] = 1;
2837        DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
2838        require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
2839
2840        memset( &maddr, 0, sizeof( maddr ) );
2841        maddr.type = mDNSAddrType_IPv6;
2842        maddr.ip.v6.b[  0 ] = 0xFE;
2843        maddr.ip.v6.b[  1 ] = 0x80;
2844        maddr.ip.v6.b[ 15 ] = 0x01;
2845        DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
2846        require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
2847    }
2848    #endif
2849
2850    #if ( AF_INET )
2851    {
2852        struct sockaddr_in sa4;
2853
2854        memset( &sa4, 0, sizeof( sa4 ) );
2855        sa4.sin_family      = AF_INET;
2856        p                   = (uint8_t *) &sa4.sin_port;
2857        p[ 0 ]              = (uint8_t)( ( 80 >> 8 ) & 0xFF );
2858        p[ 1 ]              = (uint8_t)(   80        & 0xFF );
2859        p                   = (uint8_t *) &sa4.sin_addr.s_addr;
2860        p[ 0 ]              = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
2861        p[ 1 ]              = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
2862        p[ 2 ]              = (uint8_t)( ( INADDR_LOOPBACK >>  8 ) & 0xFF );
2863        p[ 3 ]              = (uint8_t)(   INADDR_LOOPBACK         & 0xFF );
2864        DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
2865        require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
2866    }
2867    #endif
2868
2869    #if ( AF_INET6 )
2870    {
2871        struct sockaddr_in6 sa6;
2872
2873        memset( &sa6, 0, sizeof( sa6 ) );
2874        sa6.sin6_family             = AF_INET6;
2875        p                           = (uint8_t *) &sa6.sin6_port;
2876        p[ 0 ]                      = (uint8_t)( ( 80 >> 8 ) & 0xFF );
2877        p[ 1 ]                      = (uint8_t)(   80        & 0xFF );
2878        sa6.sin6_addr.s6_addr[  0 ] = 0xFE;
2879        sa6.sin6_addr.s6_addr[  1 ] = 0x80;
2880        sa6.sin6_addr.s6_addr[ 15 ] = 0x01;
2881        sa6.sin6_scope_id           = 2;
2882        DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
2883        require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
2884    }
2885    #endif
2886
2887    // Unicode
2888
2889    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
2890    require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
2891
2892    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
2893    require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
2894
2895    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
2896    require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
2897
2898    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
2899    require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
2900
2901    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
2902    require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
2903
2904    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
2905    require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
2906
2907    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
2908    require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
2909
2910    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
2911    require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
2912
2913    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
2914    require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
2915
2916    DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
2917    require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
2918
2919    DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
2920    require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
2921
2922    DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
2923    require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
2924
2925    DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
2926    require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
2927
2928    #if ( TARGET_RT_BIG_ENDIAN )
2929    DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
2930    require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
2931    #else
2932    DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
2933    require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
2934    #endif
2935
2936    DebugSNPrintF( s, sizeof( s ), "%S",
2937                   "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
2938    require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
2939
2940    DebugSNPrintF( s, sizeof( s ), "%S",
2941                   "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
2942    require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
2943
2944    DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );  // Big Endian
2945    require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
2946
2947    DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian
2948    require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
2949
2950    DebugSNPrintF( s, sizeof( s ), "%.*S",
2951                   4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian BOM
2952    require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
2953
2954    DebugSNPrintF( s, sizeof( s ), "%.*S",
2955                   4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian BOM
2956    require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
2957
2958    #if ( TARGET_RT_BIG_ENDIAN )
2959    DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
2960    require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
2961    #else
2962    DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
2963    require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
2964    #endif
2965
2966    DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );   // Big Endian
2967    require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
2968
2969    DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );  // Little Endian
2970    require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
2971
2972    // Misc
2973
2974    DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
2975    require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
2976
2977    DebugSNPrintF( s, sizeof( s ), "%m", 0 );
2978    require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
2979
2980    DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
2981    require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
2982
2983    DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
2984    DebugPrintF( kDebugLevelMax, "%s\n\n", s );
2985
2986    DebugSNPrintF( s, sizeof( s ), "\"%H\"",
2987                   "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
2988                   "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8",
2989                   32, 32 );
2990    DebugPrintF( kDebugLevelMax, "%s\n\n", s );
2991
2992    DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
2993    DebugPrintF( kDebugLevelMax, "%s\n\n", s );
2994
2995    // Hex Dumps
2996
2997    s[ 0 ] = '\0';
2998    DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
2999                  kDebugFlagsNone, s, sizeof( s ) );
3000    DebugPrintF( kDebugLevelMax, "%s\n", s );
3001
3002    s[ 0 ] = '\0';
3003    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
3004                  kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
3005    DebugPrintF( kDebugLevelMax, "%s\n", s );
3006
3007    s[ 0 ] = '\0';
3008    DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
3009                  kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
3010    DebugPrintF( kDebugLevelMax, "%s\n", s );
3011
3012    s[ 0 ] = '\0';
3013    DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
3014                  kDebugFlagsNoAddress, s, sizeof( s ) );
3015    DebugPrintF( kDebugLevelMax, "%s\n", s );
3016
3017    s[ 0 ] = '\0';
3018    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
3019                  kDebugFlagsNoOffset, s, sizeof( s ) );
3020    DebugPrintF( kDebugLevelMax, "%s\n", s );
3021
3022    s[ 0 ] = '\0';
3023    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
3024                  kDebugFlagsNoAddress, s, sizeof( s ) );
3025    DebugPrintF( kDebugLevelMax, "%s\n", s );
3026
3027    s[ 0 ] = '\0';
3028    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
3029                  kDebugFlagsNoOffset, s, sizeof( s ) );
3030    DebugPrintF( kDebugLevelMax, "%s\n", s );
3031
3032    s[ 0 ] = '\0';
3033    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
3034                  kDebugFlagsNoByteCount, s, sizeof( s ) );
3035    DebugPrintF( kDebugLevelMax, "%s\n", s );
3036
3037    s[ 0 ] = '\0';
3038    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4,    // 'AbCd'
3039                  kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
3040                  kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount,
3041                  s, sizeof( s ) );
3042    DebugPrintF( kDebugLevelMax, "%s\n", s );
3043
3044    s[ 0 ] = '\0';
3045    DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
3046                  kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
3047                  kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
3048                  kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
3049    DebugPrintF( kDebugLevelMax, "%s\n", s );
3050
3051    s[ 0 ] = '\0';
3052    DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
3053    DebugPrintF( kDebugLevelMax, "%s\n", s );
3054
3055    // dlog's
3056
3057    dlog( kDebugLevelNotice, "dlog\n" );
3058    dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
3059    dlog( kDebugLevelNotice, "dlog string:  \"%s\"\n", "test string" );
3060    dlogmem( kDebugLevelNotice, data, sizeof( data ) );
3061
3062    // Done
3063
3064    DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
3065    err = kNoErr;
3066
3067exit:
3068    if( err )
3069    {
3070        DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
3071    }
3072    return( err );
3073}
3074
3075#endif  // DEBUG
3076