// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "util.h" #pragma GCC visibility push(hidden) #include #include #include #include #include #pragma GCC visibility pop #define LOG_PREFIX "userboot: " #define LOG_WRITE_FAIL \ (LOG_PREFIX "Error printing error message. No error message printed.\n") static char* hexstring(char* s, size_t len, uint64_t n) { char tmp[16]; char* hex = tmp; do { *hex++ = "0123456789abcdef"[n & 15]; n >>= 4; } while (n); if (len > 2) { *s++ = '0'; *s++ = 'x'; len -= 2; } while ((hex > tmp) && (len > 0)) { *s++ = *--hex; len--; } return s; } static char* u64string(char* s, size_t len, uint64_t n) { char tmp[21]; // strlen(maxint64) + 1 char* dec = tmp; do { *dec++ = "0123456789"[n % 10]; n /= 10; } while (n > 0); while ((dec > tmp) && (len > 0)) { *s++ = *--dec; len--; } return s; } static char* i64string(char* s, size_t len, int64_t n) { if (n < 0) { // this will never be called with len < 1 so we // don't need to check for len n = -n; *s++ = '-'; len--; } return u64string(s, len, n); } void vprintl(zx_handle_t log, const char* fmt, va_list ap) { char buffer[ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t)]; static_assert(sizeof(LOG_PREFIX) < sizeof(buffer), "buffer too small"); memcpy(buffer, LOG_PREFIX, sizeof(LOG_PREFIX) - 1); char* p = &buffer[sizeof(LOG_PREFIX) - 1]; size_t avail; const char* s; uint64_t n; int64_t i; while (*fmt && (avail = (size_t)(&buffer[sizeof(buffer)] - p))) { if (*fmt != '%') { *p++ = *fmt++; continue; } switch (*++fmt) { case 's': s = va_arg(ap, const char*); while (avail && *s) { *p++ = *s++; avail--; } break; case '.': fmt++; if (*fmt != '*') goto bad_format; fmt++; if (*fmt != 's') goto bad_format; i = va_arg(ap, int); s = va_arg(ap, const char*); while (avail && *s && i != 0) { *p++ = *s++; avail--; if (i > 0) --i; } break; case 'z': fmt++; switch (*fmt) { case 'u': n = va_arg(ap, uint64_t); goto u64print; case 'd': i = va_arg(ap, int64_t); goto i64print; case 'x': n = va_arg(ap, uint64_t); goto x64print; default: goto bad_format; } break; case 'p': n = va_arg(ap, uint64_t); goto x64print; case 'u': n = va_arg(ap, uint32_t); u64print: p = u64string(p, avail, n); break; case 'd': i = va_arg(ap, int32_t); i64print: p = i64string(p, avail, i); break; case 'x': n = va_arg(ap, uint32_t); x64print: p = hexstring(p, avail, n); break; default: bad_format: printl(log, "printl: invalid fmt char 0x%x", *fmt); zx_process_exit(-1); } fmt++; } if ((log == ZX_HANDLE_INVALID) || (zx_debuglog_write(log, 0, buffer, p - buffer) != ZX_OK)) { zx_debug_write(buffer, p - buffer); zx_debug_write("\n", 1); } } void printl(zx_handle_t log, const char* fmt, ...) { va_list ap; va_start(ap, fmt); vprintl(log, fmt, ap); va_end(ap); } void fail(zx_handle_t log, const char* fmt, ...) { va_list ap; va_start(ap, fmt); vprintl(log, fmt, ap); va_end(ap); zx_process_exit(-1); }