2 * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 * debugging.c - non-trivial debug support
28 #include "utilities/debugging.h"
29 #include "utilities/SecCFWrappers.h"
30 #include <CoreFoundation/CFSet.h>
31 #include <CoreFoundation/CFString.h>
33 #include <dispatch/dispatch.h>
42 /** begin: For SimulateCrash **/
44 #include <mach/mach.h>
45 /// Type to represent a boolean value.
46 #if TARGET_OS_IPHONE && __LP64__
49 typedef signed char BOOL
;
50 // BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
51 // even if -funsigned-char is used.
53 /** end: For SimulateCrash **/
55 #define MAX_SCOPE_LENGTH 12
58 static CFStringRef
copyScopeName(const char *scope
, CFIndex scopeLen
) {
59 if (scopeLen
> MAX_SCOPE_LENGTH
)
60 scopeLen
= MAX_SCOPE_LENGTH
- 1;
61 return CFStringCreateWithBytes(kCFAllocatorDefault
, (const UInt8
*)scope
,
62 scopeLen
, kCFStringEncodingUTF8
, false);
65 pthread_once_t __security_debug_once
= PTHREAD_ONCE_INIT
;
66 static const char *gDebugScope
;
67 static CFMutableSetRef scopeSet
;
68 static bool negate
= false;
70 static void __security_debug_init(void) {
71 const char *cur_scope
= gDebugScope
= getenv("DEBUGSCOPE");
73 if (!strcmp(cur_scope
, "all")) {
76 } else if (!strcmp(cur_scope
, "none")) {
80 scopeSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0,
81 &kCFTypeSetCallBacks
);
82 if (cur_scope
[0] == '-') {
90 while ((sep
= strchr(cur_scope
, ','))) {
91 CFStringRef scopeName
= copyScopeName(cur_scope
,
93 CFSetAddValue(scopeSet
, scopeName
);
98 CFStringRef scopeName
= copyScopeName(cur_scope
,
100 CFSetAddValue(scopeSet
, scopeName
);
101 CFRelease(scopeName
);
111 static CFMutableArrayRef sSecurityLogHandlers
;
113 static CFMutableArrayRef
get_log_handlers()
115 static dispatch_once_t handlers_once
;
117 dispatch_once(&handlers_once
, ^{
118 sSecurityLogHandlers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
120 CFArrayAppendValue(sSecurityLogHandlers
, ^(const char *level
, CFStringRef scope
, const char *function
,
121 const char *file
, int line
, CFStringRef message
){
122 CFStringRef logStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@ %s %@\n"), scope
? scope
: CFSTR(""), function
, message
);
123 CFStringPerformWithCString(logStr
, ^(const char *logMsg
) {
124 aslmsg msg
= asl_new(ASL_TYPE_MSG
);
126 CFStringPerformWithCString(scope
, ^(const char *scopeStr
) {
127 asl_set(msg
, ASL_KEY_FACILITY
, scopeStr
);
130 asl_set(msg
, ASL_KEY_LEVEL
, level
);
131 asl_set(msg
, ASL_KEY_MSG
, logMsg
);
135 CFReleaseSafe(logStr
);
139 return sSecurityLogHandlers
;
142 static void clean_aslclient(void *client
)
147 static aslclient
get_aslclient()
149 static dispatch_once_t once
;
150 static pthread_key_t asl_client_key
;
151 dispatch_once(&once
, ^{
152 pthread_key_create(&asl_client_key
, clean_aslclient
);
154 aslclient client
= pthread_getspecific(asl_client_key
);
156 client
= asl_open(NULL
, "SecAPI", 0);
157 asl_set_filter(client
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
158 pthread_setspecific(asl_client_key
, client
);
164 void __security_trace_enter_api(const char *api
, CFStringRef format
, ...)
166 aslmsg msg
= asl_new(ASL_TYPE_MSG
);
167 asl_set(msg
, ASL_KEY_LEVEL
, ASL_STRING_DEBUG
);
168 asl_set(msg
, "SecAPITrace", api
);
169 asl_set(msg
, "ENTER", "");
171 va_start(args
, format
);
173 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
175 CFStringPerformWithCString(message
, ^(const char *utf8Str
) {
176 asl_set(msg
, ASL_KEY_MSG
, utf8Str
);
178 CFReleaseSafe(message
);
184 snprintf(stack_info
, sizeof(stack_info
), "C%p F%p", __builtin_return_address(1), __builtin_frame_address(2));
185 asl_set(msg
, "CALLER", stack_info
);
188 asl_send(get_aslclient(), msg
);
192 void __security_trace_return_api(const char *api
, CFStringRef format
, ...)
194 aslmsg msg
= asl_new(ASL_TYPE_MSG
);
195 asl_set(msg
, ASL_KEY_LEVEL
, ASL_STRING_DEBUG
);
196 asl_set(msg
, "SecAPITrace", api
);
197 asl_set(msg
, "RETURN", "");
199 va_start(args
, format
);
201 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
203 CFStringPerformWithCString(message
, ^(const char *utf8Str
) {
204 asl_set(msg
, ASL_KEY_MSG
, utf8Str
);
206 CFReleaseSafe(message
);
208 asl_send(get_aslclient(), msg
);
213 void add_security_log_hanlder(security_log_handler handler
)
215 CFArrayAppendValue(get_log_handlers(), handler
);
218 static void __security_log_msg(const char *level
, CFStringRef scope
, const char *function
,
219 const char *file
, int line
, CFStringRef message
)
222 CFArrayForEach(get_log_handlers(), ^(const void *value
) {
223 security_log_handler handler
= (security_log_handler
) value
;
225 handler(level
, scope
, function
, file
, line
, message
);
229 void __security_debug(CFStringRef scope
, const char *function
,
230 const char *file
, int line
, CFStringRef format
, ...)
233 pthread_once(&__security_debug_once
, __security_debug_init
);
235 /* Check if scope is enabled. */
236 if (scope
&& ((scopeSet
&& negate
== CFSetContainsValue(scopeSet
, scope
)) ||
237 (!scopeSet
&& !negate
)))
242 va_start(args
, format
);
243 CFStringRef message
= CFStringCreateWithFormatAndArguments(
244 kCFAllocatorDefault
, NULL
, format
, args
);
247 /* DEBUG scopes are logged as notice when enabled. */
248 __security_log_msg(ASL_STRING_NOTICE
, scope
, function
, file
, line
, message
);
252 void __security_log(const char *level
, CFStringRef scope
, const char *function
,
253 const char *file
, int line
, CFStringRef format
, ...)
256 va_start(args
, format
);
257 CFStringRef message
= CFStringCreateWithFormatAndArguments(
258 kCFAllocatorDefault
, NULL
, format
, args
);
260 __security_log_msg(level
, scope
, function
, file
, line
, message
);
264 static void __security_simulatecrash_link(CFStringRef reason
, uint32_t code
)
266 #if !TARGET_IPHONE_SIMULATOR
267 // Prototype defined in <CrashReporterSupport/CrashReporterSupport.h>, but objC only.
268 // Soft linking here so we don't link unless we hit this.
269 static BOOL (*__SimulateCrash
)(pid_t pid
, mach_exception_data_type_t exceptionCode
, CFStringRef description
);
271 static dispatch_once_t once
= 0;
272 dispatch_once(&once
, ^{
273 void *image
= dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport", RTLD_NOW
);
275 __SimulateCrash
= dlsym(image
, "SimulateCrash");
277 __SimulateCrash
= NULL
;
281 __SimulateCrash(getpid(), code
, reason
);
283 secerror("SimulateCrash not available");
285 secerror("SimulateCrash not available in iOS simulator");
290 void __security_simulatecrash(CFStringRef reason
, uint32_t code
)
292 secerror("Simulating crash, reason: %@, code=%08x", reason
, code
);
293 __security_simulatecrash_link(reason
, code
);