#include <Security/debugsupport.h>
#include <Security/globalizer.h>
#include <cstdarg>
+#include <ctype.h>
#define SYSLOG_NAMES // compile syslog name tables
#include <syslog.h>
-namespace Security {
-namespace Debug {
+#include <cxxabi.h> // for name demangling
+// enable kernel tracing
+#define ENABLE_SECTRACE 1
-#if !defined(NDEBUG)
+
+namespace Security {
+namespace Debug {
//
//
void debug(const char *scope, const char *format, ...)
{
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
va_list args;
va_start(args, format);
Target::get().message(scope, format, args);
void vdebug(const char *scope, const char *format, va_list args)
{
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
Target::get().message(scope, format, args);
#endif
}
-void Scope::operator () (const char *format, ...)
-{
-#if !defined(NDEBUG_STUBS)
- va_list args;
- va_start(args, format);
- Target::get().message(mScope, format, args);
- va_end(args);
-#endif
-}
-
bool debugging(const char *scope)
{
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
return Target::get().debugging(scope);
#else
return false;
}
+//
+// C equivalents for some basic uses
+//
+extern "C" {
+ int __security_debugging(const char *scope);
+ void __security_debug(const char *scope, const char *format, ...);
+};
+
+int __security_debugging(const char *scope)
+{ return debugging(scope); }
+
+void __security_debug(const char *scope, const char *format, ...)
+{
+#if !defined(NDEBUG_CODE)
+ va_list args;
+ va_start(args, format);
+ vdebug(scope, format, args);
+ va_end(args);
+#endif
+}
+
+
//
// Dump facility
//
void dump(const char *format, ...)
{
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
va_list args;
va_start(args, format);
Target::get().dump(format, args);
void dumpData(const void *ptr, size_t size)
{
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
const char *addr = reinterpret_cast<const char *>(ptr);
const char *end = addr + size;
bool isText = true;
} else {
dump("0x");
for (const char *p = addr; p < end; p++)
- dump("%2.2x", *p);
+ dump("%2.2x", static_cast<unsigned char>(*p));
}
#endif //NDEBUG_STUBS
}
void dumpData(const char *title, const void *ptr, size_t size)
{
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
dump("%s: ", title);
dumpData(ptr, size);
dump("\n");
}
+//
+// Turn a C++ typeid into a nice type name.
+// This uses the C++ ABI where available.
+// We're stripping out a few C++ prefixes; they're pretty redundant (and obvious).
+//
+string makeTypeName(const type_info &type)
+{
+ int status;
+ char *cname = abi::__cxa_demangle(type.name(), NULL, NULL, &status);
+ string name = !strncmp(cname, "Security::", 10) ? (cname + 10) :
+ !strncmp(cname, "std::", 5) ? (cname + 5) :
+ cname;
+ ::free(cname); // yes, really (ABI rules)
+ return name;
+}
+
+
//
// Target initialization
//
-#if !defined(NDEBUG_STUBS)
+#if !defined(NDEBUG_CODE)
-Target::Target() : showScope(false), showThread(false), showPid(false), sink(NULL)
+Target::Target()
+ : showScope(false), showThread(false), showPid(false),
+ sink(NULL)
{
// put into singleton slot if first
if (singleton == NULL)
singleton = this;
+
+ // insert terminate handler
+ if (!previousTerminator) // first time we do this
+ previousTerminator = set_terminate(terminator);
}
Target::~Target()
//
void Target::dump(const char *format, va_list args)
{
- sink->dump(format, args);
+ char buffer[messageConstructionSize]; // building the message here
+ vsnprintf(buffer, sizeof(buffer), format, args);
+ for (char *p = buffer; *p; p++)
+ if (!isprint(*p) && !isspace(*p) || *p == '\r')
+ *p = '?';
+ sink->dump(buffer);
}
bool Target::dump(const char *scope)
return dumpSelector(scope);
}
+
//
// Selector objects.
//
Target::Sink::~Sink()
{ }
-void Target::Sink::dump(const char *, va_list)
+void Target::Sink::dump(const char *)
{ }
void Target::Sink::configure(const char *)
{ }
+//
+// The terminate handler installed when a Target is created
+//
+terminate_handler Target::previousTerminator;
+
+void Target::terminator()
+{
+ debug("exception", "uncaught exception terminates program");
+ previousTerminator();
+ debug("exception", "prior termination handler failed to abort; forcing abort");
+ abort();
+}
+
+
//
// File sinks (write to file via stdio)
//
putc('\n', file);
}
-void FileSink::dump(const char *format, va_list args)
+void FileSink::dump(const char *text)
{
StLock<Mutex> locker(lock, false);
if (lockIO)
locker.lock();
- vfprintf(file, format, args);
+ fputs(text, file);
}
void FileSink::configure(const char *options)
{
- if (options == NULL || !strstr(options, "noflush"))
+ if (options == NULL || !strstr(options, "noflush")) {
+ // we mean "if the file isn't unbuffered", but what's the portable way to say that?
+ if (file != stderr)
setlinebuf(file);
+ }
if (options) {
addDate = strstr(options, "date");
lockIO = !strstr(options, "nolock");
syslog(priority, "%s", buffer);
}
-void SyslogSink::dump(const char *format, va_list args)
+void SyslogSink::dump(const char *text)
{
// add to dump buffer
- vsnprintf(dumpPtr, dumpBuffer + dumpBufferSize - dumpPtr, format, args);
+ snprintf(dumpPtr, dumpBuffer + dumpBufferSize - dumpPtr, "%s", text);
// take off full lines and submit
char *p = dumpBase;
{
}
-#endif //NDEBUG_STUBS
+#endif //NDEBUG_CODE
+
+
+//
+// kernel tracing support (C version)
+//
+extern "C" void security_ktrace(int);
-#endif // NDEBUG
+void security_ktrace(int code)
+{
+#if defined(ENABLE_SECTRACE)
+ syscall(180, code, 0, 0, 0, 0);
+#endif
+}
} // end namespace Debug
-
} // end namespace Security