aboutsummaryrefslogtreecommitdiff
path: root/src/util/log.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/log.cpp')
-rw-r--r--src/util/log.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/util/log.cpp b/src/util/log.cpp
new file mode 100644
index 00000000..8ab9405d
--- /dev/null
+++ b/src/util/log.cpp
@@ -0,0 +1,244 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define LOGMODULE log
+#include "log.h"
+
+#include <android-base/logging.h>
+
+#if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+/* Microsoft Visual Studio gives internal error C1001 with _builtin_expect */
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+extern "C" {
+
+/**
+ * Compares two strings byte by byte and ignores the
+ * character's case. Stops at the n-th byte of both
+ * strings.
+ *
+ * This is basically a replacement of the POSIX-function
+ * _strncasecmp_. Since tpm2-tss is supposed to be compatible
+ * with ISO C99 and not with POSIX, _strncasecmp_ had to be
+ * replaced. This function creates lowercase representations
+ * of the strings and compares them bytewise.
+ *
+ * @param string1 The first of the two strings to compare
+ * @param string2 The second of the two strings to compare
+ * @param n The maximum number of bytes to compare
+ * @return 0 if both strings are equal (case insensitive),
+ * an integer greater than zero if string1 is greater than
+ * string 2 and an integer smaller than zero if string1 is
+ * smaller than string2
+ *
+ */
+static int
+case_insensitive_strncmp(const char *string1,
+ const char *string2,
+ size_t n)
+{
+ if ((string1 == NULL) && (string2 == NULL)) {
+ return 0;
+ }
+ if ((string1 == NULL) && (string2 != NULL)) {
+ return -1;
+ }
+ if ((string1 != NULL) && (string2 == NULL)) {
+ return 1;
+ }
+ if (n == 0) { // Zero bytes are always equal
+ return 0;
+ }
+ if (string1 == string2) { // return equal if they point to same location
+ return 0;
+ }
+
+ int result;
+ do {
+ result = tolower((unsigned char) *string1) - tolower((unsigned char) *string2);
+ if (result != 0) {
+ break;
+ }
+ } while (*string1++ != '\0' && *string2++ != '\0' && --n );
+ return result;
+}
+
+static log_level
+getLogLevel(const char *module, log_level logdefault);
+
+void
+doLogBlob(log_level loglevel, const char *module, log_level logdefault,
+ log_level *status,
+ const char *file, const char *func, int line,
+ const uint8_t *blob, size_t size, const char *fmt, ...)
+{
+ if (unlikely(*status == LOGLEVEL_UNDEFINED))
+ *status = getLogLevel(module, logdefault);
+ if (loglevel > *status)
+ return;
+
+ va_list vaargs;
+ va_start(vaargs, fmt);
+ /* TODO: Unfortunately, vsnprintf(NULL, 0, ...) do not behave the same as
+ snprintf(NULL, 0, ...). Until there is an alternative, messages on
+ logblob are restricted to 255 characters
+ int msg_len = vsnprintf(NULL, 0, fmt, vaargs); */
+ int msg_len = 255;
+ char msg[msg_len+1];
+ vsnprintf(msg, sizeof(msg), fmt, vaargs);
+ va_end(vaargs);
+
+ doLog(loglevel, module, logdefault, status, file, func, line,
+ "%s (size=%zi):", msg, size);
+
+ unsigned int i, y, x, off, off2;
+ unsigned int width = 16;
+#define LINE_LEN 64
+ char buffer[LINE_LEN];
+
+ for (i = 1, off = 0, off2 = 0; i <= size; i++) {
+ if (i == 1) {
+ sprintf(&buffer[off], "%04x: ", i - 1);
+ off += 6;
+ }
+
+ /* data output */
+ sprintf(&buffer[off], "%02x", blob[i-1]);
+ off += 2;
+
+ /* ASCII output */
+ if ((i % width == 0 && i > 1) || i == size) {
+ sprintf(&buffer[off], " ");
+ off += 2;
+ /* Align to the right */
+ for (x = off; x < width * 2 + 8; x++) {
+ sprintf(&buffer[off], " ");
+ off++;
+ }
+
+ /* Account for a line that is not 'full' */
+ unsigned int less = width - (i % width);
+ if (less == width)
+ less = 0;
+
+ for (y = 0; y < width - less; y++) {
+ if (isgraph(blob[off2 + y])) {
+ sprintf(&buffer[y + off], "%c", blob[off2 + y]);
+ } else {
+ sprintf(&buffer[y + off], "%c", '.');
+ }
+ }
+ /* print the line and restart */
+ fprintf (stderr, "%s\n", buffer);
+ off2 = i;
+ off = 0;
+ memset(buffer, '\0', LINE_LEN);
+ sprintf(&buffer[off], "%04x: ", i);
+ off += 6;
+ }
+ }
+}
+
+void
+doLog(log_level loglevel, const char *module, log_level logdefault,
+ log_level *status,
+ const char *file, const char *func, int line,
+ const char *msg, ...)
+{
+ if (unlikely(*status == LOGLEVEL_UNDEFINED))
+ *status = getLogLevel(module, logdefault);
+
+ if (loglevel > *status)
+ return;
+
+ int size = snprintf(NULL, 0, "%s:%s:%s:%d:%s() %s ",
+ log_strings[loglevel], module, file, line, func, msg);
+ char fmt[size+1];
+ snprintf(fmt, sizeof(fmt), "%s:%s:%s:%d:%s() %s ",
+ log_strings[loglevel], module, file, line, func, msg);
+
+ va_list vaargs;
+ va_start(vaargs, msg);
+ int complete_size = vsnprintf(NULL, 0, fmt, vaargs);
+ va_end(vaargs);
+
+ va_start(vaargs, msg);
+ char complete[complete_size+1];
+ vsnprintf(complete, sizeof(complete), fmt, vaargs);
+ va_end(vaargs);
+
+ fprintf(stderr, "%s\n", complete);
+
+ switch (loglevel) {
+ case LOGLEVEL_NONE:
+ LOG(ERROR) << complete;
+ break;
+ case LOGLEVEL_ERROR:
+ LOG(ERROR) << complete;
+ break;
+ case LOGLEVEL_WARNING:
+ LOG(WARNING) << complete;
+ break;
+ case LOGLEVEL_INFO:
+ LOG(INFO) << complete;
+ break;
+ case LOGLEVEL_DEBUG:
+ LOG(DEBUG) << complete;
+ break;
+ case LOGLEVEL_TRACE:
+ LOG(VERBOSE) << complete;
+ break;
+ case LOGLEVEL_UNDEFINED:
+ default:
+ LOG(WARNING) << complete;
+ break;
+ }
+}
+
+static log_level
+log_stringlevel(const char *n)
+{
+ log_level i;
+ for(i = (log_level) 0; i < sizeof(log_strings)/sizeof(log_strings[0]); i = (log_level) ((int) i + 1)) {
+ if (case_insensitive_strncmp(log_strings[i], n, strlen(log_strings[i])) == 0) {
+ return i;
+ }
+ }
+ return LOGLEVEL_UNDEFINED;
+}
+
+static log_level
+getLogLevel(const char *module, log_level logdefault)
+{
+ log_level loglevel = logdefault;
+ char *envlevel = getenv("TSS2_LOG");
+ char *i = envlevel;
+ if (envlevel == NULL)
+ return loglevel;
+ while ((i = strchr(i, '+')) != NULL) {
+ if ((envlevel <= i - strlen("all") &&
+ case_insensitive_strncmp(i - 3, "all", 3) == 0) ||
+ (envlevel <= i - strlen(module) &&
+ case_insensitive_strncmp(i - strlen(module), module, strlen(module)) == 0)) {
+ log_level tmp = log_stringlevel(i+1);
+ if (tmp != LOGLEVEL_UNDEFINED)
+ loglevel = tmp;
+ }
+ i = i + 1;
+ }
+ return loglevel;
+}
+
+} // extern "C"