]>
git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/debugging.cpp
a1941e3ebde5956de3b8890dfab481d031a2893b
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // debugging - non-trivial debugging support
22 #include <Security/debugsupport.h>
23 #include <Security/globalizer.h>
26 #define SYSLOG_NAMES // compile syslog name tables
37 // Main debug functions (global and in-scope)
39 void debug(const char *scope
, const char *format
, ...)
41 #if !defined(NDEBUG_STUBS)
43 va_start(args
, format
);
44 Target::get().message(scope
, format
, args
);
49 void vdebug(const char *scope
, const char *format
, va_list args
)
51 #if !defined(NDEBUG_STUBS)
52 Target::get().message(scope
, format
, args
);
56 void Scope::operator () (const char *format
, ...)
58 #if !defined(NDEBUG_STUBS)
60 va_start(args
, format
);
61 Target::get().message(mScope
, format
, args
);
66 bool debugging(const char *scope
)
68 #if !defined(NDEBUG_STUBS)
69 return Target::get().debugging(scope
);
79 bool dumping(const char *scope
)
81 #if defined(NDEBUG_STUBS)
84 return Target::get().dump(scope
);
88 void dump(const char *format
, ...)
90 #if !defined(NDEBUG_STUBS)
92 va_start(args
, format
);
93 Target::get().dump(format
, args
);
98 void dumpData(const void *ptr
, size_t size
)
100 #if !defined(NDEBUG_STUBS)
101 const char *addr
= reinterpret_cast<const char *>(ptr
);
102 const char *end
= addr
+ size
;
104 for (const char *p
= addr
; p
< end
; p
++)
105 if (!isprint(*p
)) { isText
= false; break; }
109 for (const char *p
= addr
; p
< end
; p
++)
114 for (const char *p
= addr
; p
< end
; p
++)
117 #endif //NDEBUG_STUBS
120 void dumpData(const char *title
, const void *ptr
, size_t size
)
122 #if !defined(NDEBUG_STUBS)
126 #endif //NDEBUG_STUBS
131 // Target initialization
133 #if !defined(NDEBUG_STUBS)
135 Target::Target() : showScope(false), showThread(false), showPid(false), sink(NULL
)
137 // put into singleton slot if first
138 if (singleton
== NULL
)
148 // The core logging function of a Target
150 void Target::message(const char *scope
, const char *format
, va_list args
)
152 if (logSelector(scope
)) {
153 // note: messageConstructionSize is big enough for all prefixes constructed
154 char buffer
[messageConstructionSize
]; // building the message here
156 if (showScope
&& scope
) { // add "scope "
157 if (const char *sep
= strchr(scope
, ',')) {
158 bufp
+= sprintf(bufp
, "%-*s", Name::maxLength
, (const char *)Name(scope
, sep
));
159 } else { // single scope
160 bufp
+= sprintf(bufp
, "%-*s", Name::maxLength
, scope
);
163 if (showPid
) { // add "[Pid] "
164 bufp
+= sprintf(bufp
, "[%d] ", getpid());
166 if (showThread
) { // add "#Tthreadid "
168 Thread::Identity::current().getIdString(bufp
);
169 bufp
+= strlen(bufp
);
172 vsnprintf(bufp
, buffer
+ sizeof(buffer
) - bufp
, format
, args
);
173 for (char *p
= bufp
; *p
; p
++)
176 sink
->put(buffer
, bufp
- buffer
);
180 bool Target::debugging(const char *scope
)
182 return logSelector(scope
);
187 // The core debug-dump function of a target
189 void Target::dump(const char *format
, va_list args
)
191 sink
->dump(format
, args
);
194 bool Target::dump(const char *scope
)
196 return dumpSelector(scope
);
202 Target::Selector::Selector() : useSet(false), negate(false)
205 void Target::Selector::operator = (const char *scope
)
209 if (!strcmp(scope
, "all")) {
212 } else if (!strcmp(scope
, "none")) {
213 useSet
= negate
= false;
216 enableSet
.erase(enableSet
.begin(), enableSet
.end());
217 if (scope
[0] == '-') {
222 while (const char *sep
= strchr(scope
, ',')) {
223 enableSet
.insert(Name(scope
, sep
));
226 enableSet
.insert(scope
);
229 useSet
= negate
= false;
233 bool Target::Selector::operator () (const char *scope
) const
235 // a scope of NULL is a special override; it always qualifies
240 while (const char *sep
= strchr(scope
, ',')) {
241 if (enableSet
.find(Name(scope
, sep
)) != enableSet
.end())
245 return (enableSet
.find(scope
) != enableSet
.end()) != negate
;
253 // Establish Target state from the environment
255 void Target::setFromEnvironment()
258 logSelector
= getenv("DEBUGSCOPE");
259 dumpSelector
= getenv("DEBUGDUMP");
262 // Set and configure destination. Currently available:
263 // /some/where -> that file
264 // LOG_SOMETHING -> syslog facility
265 // >&number -> that (already) open file descriptor
266 // anything else -> try as a filename sight unseen
267 // DEBUGDEST not set -> stderr
268 // anything in error -> stderr (with an error message on it)
270 if (const char *dest
= getenv("DEBUGDEST")) {
271 if (dest
[0] == '/') { // full pathname, write to file
273 } else if (!strncmp(dest
, "LOG_", 4)) { // syslog
274 int facility
= LOG_DAEMON
;
275 for (CODE
*cp
= facilitynames
; cp
->c_name
; cp
++)
276 if (!strcmp(dest
, cp
->c_name
))
277 facility
= cp
->c_val
;
278 to(facility
| LOG_DEBUG
);
279 } else if (!strncmp(dest
, ">&", 2)) { // to file descriptor
280 int fd
= atoi(dest
+2);
281 if (FILE *f
= fdopen(fd
, "a")) {
285 ::debug(NULL
, "cannot log to fd[%d]: %s", fd
, strerror(errno
));
287 } else { // if everything else fails, write a file
290 } else { // default destination is stderr
297 void Target::configure()
299 configure(getenv("DEBUGOPTIONS"));
302 void Target::configure(const char *config
)
304 // configure global options
305 showScope
= config
&& strstr(config
, "scope");
306 showThread
= config
&& strstr(config
, "thread");
307 showPid
= config
&& strstr(config
, "pid");
311 sink
->configure(config
);
316 // Explicit destination assignments
318 void Target::to(Sink
*s
)
324 void Target::to(FILE *file
)
326 to(new FileSink(file
));
329 void Target::to(const char *filename
)
331 if (FILE *f
= fopen(filename
, "a")) {
335 ::debug(NULL
, "cannot debug to \"%s\": %s", filename
, strerror(errno
));
339 void Target::to(int syslogPriority
)
341 to(new SyslogSink(syslogPriority
));
346 // Making and retrieving the default singleton
348 Target
*Target::singleton
;
350 Target
&Target::get()
352 if (singleton
== NULL
) {
353 Target
*t
= new Target
;
354 t
->setFromEnvironment();
361 // Standard sink implementations
363 Target::Sink::~Sink()
366 void Target::Sink::dump(const char *, va_list)
369 void Target::Sink::configure(const char *)
374 // File sinks (write to file via stdio)
376 void FileSink::put(const char *buffer
, unsigned int)
378 StLock
<Mutex
> locker(lock
, false);
382 time_t now
= time(NULL
);
383 char *date
= ctime(&now
);
385 fprintf(file
, "%s ", date
+ 4); // Nov 24 18:22:48
391 void FileSink::dump(const char *format
, va_list args
)
393 StLock
<Mutex
> locker(lock
, false);
396 vfprintf(file
, format
, args
);
399 void FileSink::configure(const char *options
)
401 if (options
== NULL
|| !strstr(options
, "noflush"))
404 addDate
= strstr(options
, "date");
405 lockIO
= !strstr(options
, "nolock");
411 // Syslog sinks (write to syslog)
413 void SyslogSink::put(const char *buffer
, unsigned int)
415 syslog(priority
, "%s", buffer
);
418 void SyslogSink::dump(const char *format
, va_list args
)
420 // add to dump buffer
421 vsnprintf(dumpPtr
, dumpBuffer
+ dumpBufferSize
- dumpPtr
, format
, args
);
423 // take off full lines and submit
425 while (char *q
= strchr(p
, '\n')) {
426 *q
++ = '\0'; // terminate/break
427 syslog(priority
, " @@ %s", p
);
431 if (*p
) { // left-over unterminated line segment in buffer
432 dumpPtr
= p
+ strlen(p
);
433 if ((dumpBase
= p
) > dumpBuffer
+ dumpBufferSize
/ 2) {
434 // shift buffer down to make room
435 memmove(dumpBuffer
, dumpBase
, dumpPtr
- dumpBase
);
436 dumpPtr
-= (dumpBase
- dumpBuffer
);
437 dumpBase
= dumpBuffer
;
439 } else { // buffer is empty; reset to start
440 dumpBase
= dumpPtr
= dumpBuffer
;
444 void SyslogSink::configure(const char *options
)
448 #endif //NDEBUG_STUBS
453 } // end namespace Debug
455 } // end namespace Security