]> git.saurik.com Git - apple/security.git/blobdiff - utilities/src/debugging.c
Security-55471.tar.gz
[apple/security.git] / utilities / src / debugging.c
diff --git a/utilities/src/debugging.c b/utilities/src/debugging.c
new file mode 100644 (file)
index 0000000..462de8b
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * debugging.c - non-trivial debug support
+ */
+#include "utilities/debugging.h"
+#include "utilities/SecCFWrappers.h"
+#include <CoreFoundation/CFSet.h>
+#include <CoreFoundation/CFString.h>
+
+#include <dispatch/dispatch.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <asl.h>
+
+/** begin: For SimulateCrash **/
+#include <dlfcn.h>
+#include <mach/mach.h>
+/// Type to represent a boolean value.
+#if TARGET_OS_IPHONE  &&  __LP64__
+typedef bool BOOL;
+#else
+typedef signed char BOOL;
+// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
+// even if -funsigned-char is used.
+#endif
+/** end: For SimulateCrash **/
+
+#define MAX_SCOPE_LENGTH  12
+
+#if !defined(NDEBUG)
+static CFStringRef copyScopeName(const char *scope, CFIndex scopeLen) {
+       if (scopeLen > MAX_SCOPE_LENGTH)
+               scopeLen = MAX_SCOPE_LENGTH - 1;
+       return CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)scope,
+               scopeLen, kCFStringEncodingUTF8, false);
+}
+
+pthread_once_t __security_debug_once = PTHREAD_ONCE_INIT;
+static const char *gDebugScope;
+static CFMutableSetRef scopeSet;
+static bool negate = false;
+
+static void __security_debug_init(void) {
+       const char *cur_scope = gDebugScope = getenv("DEBUGSCOPE");
+       if (cur_scope) {
+               if (!strcmp(cur_scope, "all")) {
+                       scopeSet = NULL;
+                       negate = true;
+               } else if (!strcmp(cur_scope, "none")) {
+                       scopeSet = NULL;
+                       negate = false;
+               } else {
+                       scopeSet = CFSetCreateMutable(kCFAllocatorDefault, 0,
+                               &kCFTypeSetCallBacks);
+                       if (cur_scope[0] == '-') {
+                               negate = true;
+                               cur_scope++;
+                       } else {
+                               negate = false;
+                       }
+
+                       const char *sep;
+                       while ((sep = strchr(cur_scope, ','))) {
+                               CFStringRef scopeName = copyScopeName(cur_scope,
+                                       sep - cur_scope);
+                               CFSetAddValue(scopeSet, scopeName);
+                               CFRelease(scopeName);
+                               cur_scope = sep + 1;
+                       }
+
+                       CFStringRef scopeName = copyScopeName(cur_scope,
+                               strlen(cur_scope));
+                       CFSetAddValue(scopeSet, scopeName);
+                       CFRelease(scopeName);
+               }
+       } else {
+               scopeSet = NULL;
+               negate = false;
+       }
+}
+
+#endif
+
+static CFMutableArrayRef sSecurityLogHandlers;
+
+static CFMutableArrayRef get_log_handlers()
+{
+    static dispatch_once_t handlers_once;
+    
+    dispatch_once(&handlers_once, ^{
+        sSecurityLogHandlers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
+        
+        CFArrayAppendValue(sSecurityLogHandlers, ^(const char *level, CFStringRef scope, const char *function,
+                                                   const char *file, int line, CFStringRef message){
+            CFStringRef logStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %s %@\n"), scope ? scope : CFSTR(""), function, message);
+            CFStringPerformWithCString(logStr, ^(const char *logMsg) {
+                aslmsg msg = asl_new(ASL_TYPE_MSG);
+                if (scope) {
+                    CFStringPerformWithCString(scope, ^(const char *scopeStr) {
+                        asl_set(msg, ASL_KEY_FACILITY, scopeStr);
+                    });
+                }
+                asl_set(msg, ASL_KEY_LEVEL, level);
+                asl_set(msg, ASL_KEY_MSG, logMsg);
+                asl_send(NULL, msg);
+                asl_free(msg);
+            });
+            CFReleaseSafe(logStr);
+        });
+    });
+    
+    return sSecurityLogHandlers;
+}
+
+static void clean_aslclient(void *client)
+{
+    asl_close(client);
+}
+
+static aslclient get_aslclient()
+{
+    static dispatch_once_t once;
+    static pthread_key_t asl_client_key;
+    dispatch_once(&once, ^{
+        pthread_key_create(&asl_client_key, clean_aslclient);
+    });
+    aslclient client = pthread_getspecific(asl_client_key);
+    if (!client) {
+        client = asl_open(NULL, "SecAPI", 0);
+        asl_set_filter(client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+        pthread_setspecific(asl_client_key, client);
+    }
+    
+    return client;
+}
+
+void __security_trace_enter_api(const char *api, CFStringRef format, ...)
+{
+    aslmsg msg = asl_new(ASL_TYPE_MSG);
+    asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG);
+    asl_set(msg, "SecAPITrace", api);
+    asl_set(msg, "ENTER", "");
+       va_list args;
+       va_start(args, format);
+    if (format) {
+        CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
+        va_end(args);
+        CFStringPerformWithCString(message, ^(const char *utf8Str) {
+            asl_set(msg, ASL_KEY_MSG, utf8Str);
+        });
+        CFReleaseSafe(message);
+    }
+    
+    {
+        char stack_info[80];
+        
+        snprintf(stack_info, sizeof(stack_info), "C%p F%p", __builtin_return_address(1), __builtin_frame_address(2));
+        asl_set(msg, "CALLER", stack_info);
+    }
+    
+    asl_send(get_aslclient(), msg);
+    asl_free(msg);
+}
+
+void __security_trace_return_api(const char *api, CFStringRef format, ...)
+{
+    aslmsg msg = asl_new(ASL_TYPE_MSG);
+    asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG);
+    asl_set(msg, "SecAPITrace", api);
+    asl_set(msg, "RETURN", "");
+       va_list args;
+       va_start(args, format);
+    if (format) {
+        CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
+        va_end(args);
+        CFStringPerformWithCString(message, ^(const char *utf8Str) {
+            asl_set(msg, ASL_KEY_MSG, utf8Str);
+        });
+        CFReleaseSafe(message);
+    }
+    asl_send(get_aslclient(), msg);
+    asl_free(msg);
+}
+
+
+void add_security_log_hanlder(security_log_handler handler)
+{
+    CFArrayAppendValue(get_log_handlers(), handler);
+}
+
+static void __security_log_msg(const char *level, CFStringRef scope, const char *function,
+                    const char *file, int line, CFStringRef message)
+{
+    
+    CFArrayForEach(get_log_handlers(), ^(const void *value) {
+        security_log_handler handler = (security_log_handler) value;
+        
+        handler(level, scope, function, file, line, message);
+    });
+}
+
+void __security_debug(CFStringRef scope, const char *function,
+                      const char *file, int line, CFStringRef format, ...)
+{
+#if !defined(NDEBUG)
+       pthread_once(&__security_debug_once, __security_debug_init);
+
+    /* Check if scope is enabled. */
+    if (scope && ((scopeSet && negate == CFSetContainsValue(scopeSet, scope)) ||
+                  (!scopeSet && !negate)))
+        return;
+#endif
+
+       va_list args;
+       va_start(args, format);
+       CFStringRef message = CFStringCreateWithFormatAndArguments(
+        kCFAllocatorDefault, NULL, format, args);
+       va_end(args);
+
+    /* DEBUG scopes are logged as notice when enabled. */
+    __security_log_msg(ASL_STRING_NOTICE, scope, function, file, line, message);
+    CFRelease(message);
+}
+
+void __security_log(const char *level, CFStringRef scope, const char *function,
+    const char *file, int line, CFStringRef format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       CFStringRef message = CFStringCreateWithFormatAndArguments(
+               kCFAllocatorDefault, NULL, format, args);
+       va_end(args);
+    __security_log_msg(level, scope, function, file, line, message);
+    CFRelease(message);
+}
+
+static void __security_simulatecrash_link(CFStringRef reason, uint32_t code)
+{
+#if !TARGET_IPHONE_SIMULATOR
+    // Prototype defined in <CrashReporterSupport/CrashReporterSupport.h>, but objC only.
+    // Soft linking here so we don't link unless we hit this.
+    static BOOL (*__SimulateCrash)(pid_t pid, mach_exception_data_type_t exceptionCode, CFStringRef description);
+
+    static dispatch_once_t once = 0;
+    dispatch_once(&once, ^{
+        void *image = dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport", RTLD_NOW);
+        if (image)
+            __SimulateCrash = dlsym(image, "SimulateCrash");
+        else
+            __SimulateCrash = NULL;
+    });
+
+    if (__SimulateCrash)
+        __SimulateCrash(getpid(), code, reason);
+    else
+        secerror("SimulateCrash not available");
+#else
+    secerror("SimulateCrash not available in iOS simulator");
+#endif
+}
+
+
+void __security_simulatecrash(CFStringRef reason, uint32_t code)
+{
+    secerror("Simulating crash, reason: %@, code=%08x", reason, code);
+    __security_simulatecrash_link(reason, code);
+}