]> git.saurik.com Git - apple/xnu.git/blobdiff - libkern/os/log_encode.h
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libkern / os / log_encode.h
index 82f2ac21d12e59331c511c8a5e5b66b260e9fb7f..40be98626d92477a5eb41d83c7e7619f2ea332f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 #define log_encode_h
 
 #include "log_encode_types.h"
-#include <sys/param.h>
 
-#if __has_feature(ptrauth_calls)
-#include <mach/vm_param.h>
-#include <ptrauth.h>
-#endif /* __has_feature(ptrauth_calls) */
-
-#ifdef KERNEL
-#define isdigit(ch) (((ch) >= '0') && ((ch) <= '9'))
-extern boolean_t doprnt_hide_pointers;
-#endif
-
-static bool
-_encode_data(os_log_buffer_value_t content, const void *arg, size_t arg_len, os_log_buffer_context_t context)
-{
-       struct os_log_arginfo_s arginfo;
-       void *databuf;
-
-       arg_len = MIN(arg_len, UINT16_MAX);
-
-       if (content->flags & OS_LOG_CONTENT_FLAG_PRIVATE) {
-               databuf = context->privdata + context->privdata_off;
-               arginfo.length = MIN((uint16_t)arg_len, (context->privdata_sz - context->privdata_off));
-               arginfo.offset = context->privdata_off;
-       } else {
-               databuf = context->pubdata + context->pubdata_off;
-               arginfo.length = MIN((uint16_t)arg_len, (context->pubdata_sz - context->pubdata_off));
-               arginfo.offset = context->pubdata_off;
-       }
-
-       if (context->arg_content_sz > 0) {
-               arginfo.length = MIN((uint16_t)context->arg_content_sz, arginfo.length);
-       }
-
-       memcpy(content->value, &arginfo, sizeof(arginfo));
-       content->size = sizeof(arginfo);
-
-       if (arginfo.length) {
-               if (content->type == OS_LOG_BUFFER_VALUE_TYPE_STRING
-#ifndef KERNEL
-                   || content->type == OS_LOG_BUFFER_VALUE_TYPE_OBJECT
-#endif
-                   ) {
-                       strlcpy(databuf, arg, arginfo.length);
-               } else {
-                       memcpy(databuf, arg, arginfo.length);
-               }
-       }
-
-       if (content->flags & OS_LOG_CONTENT_FLAG_PRIVATE) {
-               context->privdata_off += arginfo.length;
-       } else {
-               context->pubdata_off += arginfo.length;
-       }
-
-       context->content_off += sizeof(*content) + content->size;
-       context->arg_content_sz = 0;
-
-       return true;
-}
-
-#ifndef KERNEL
-static void
-_os_log_parse_annotated(char *annotated, const char **visibility, const char **library, const char **type)
-{
-       char *values[3] = { NULL };
-       int cnt = 0;
-       int idx = 0;
-
-       for (; cnt < 3;) {
-               char *token = strsep(&annotated, ", {}");
-               if (token == NULL) {
-                       break;
-               }
-
-               if (*token == '\0') {
-                       continue;
-               }
-
-               values[cnt++] = token;
-       }
-
-       if ((cnt > 0) && (!strcmp(values[0], "public") || !strcmp(values[0], "private"))) {
-               if (visibility != NULL) {
-                       (*visibility) = values[0];
-               }
-
-               idx++;
-       }
-
-       if (idx < cnt && (library != NULL) && (type != NULL)) {
-               char *decoder = values[idx];
-
-               for (cnt = 0; cnt < 3;) {
-                       char *token = strsep(&decoder, ": {}");
-                       if (token == NULL) {
-                               break;
-                       }
-
-                       if (*token == '\0') {
-                               continue;
-                       }
-
-                       values[cnt++] = token;
-               }
-
-               if (cnt == 2) {
-                       (*library) = values[0];
-                       (*type) = values[1];
-               }
-
-               if (cnt == 1) {
-                       (*library) = "builtin";
-                       (*type) = values[0];
-               }
-       }
-}
-#endif /* !KERNEL */
-
-OS_ALWAYS_INLINE
-static inline bool
-_os_log_encode_arg(void *arg, size_t arg_len, os_log_value_type_t ctype, bool is_private, os_log_buffer_context_t context)
-{
-       os_log_buffer_value_t content = (os_log_buffer_value_t) &context->buffer->content[context->content_off];
-       size_t content_sz = sizeof(*content) + arg_len;
-       char tempString[OS_LOG_BUFFER_MAX_SIZE] = {};
-#ifndef KERNEL
-       bool obj_private = true;
-#endif
-
-#ifdef KERNEL
-       /* scrub kernel pointers */
-       if (doprnt_hide_pointers &&
-           ctype == OS_LOG_BUFFER_VALUE_TYPE_SCALAR &&
-           arg_len >= sizeof(void *)) {
-               unsigned long long value = 0;
-               memcpy(&value, arg, arg_len);
-
-#if __has_feature(ptrauth_calls)
-               /**
-                * Strip out the pointer authentication code before
-                * checking whether the pointer is a kernel address.
-                */
-               value = (unsigned long long)VM_KERNEL_STRIP_PTR(value);
-#endif /* __has_feature(ptrauth_calls) */
-
-               if (value >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && value <= VM_MAX_KERNEL_ADDRESS) {
-                       is_private = true;
-                       bzero(arg, arg_len);
-               }
-       }
-#endif
-
-       content->type = ctype;
-       content->flags = (is_private ? OS_LOG_CONTENT_FLAG_PRIVATE : 0);
-
-#ifndef KERNEL
-       if (context->annotated != NULL) {
-               const char *visibility = NULL;
-
-               _os_log_parse_annotated(context->annotated, &visibility, NULL, NULL);
-               if (visibility) {
-                       if (!strcasecmp(visibility, "private")) {
-                               content->flags |= OS_LOG_CONTENT_FLAG_PRIVATE;
-                       } else if (!strcasecmp(visibility, "public")) {
-                               content->flags &= ~OS_LOG_CONTENT_FLAG_PRIVATE;
-                       }
-               }
-
-               context->annotated = NULL;
-       }
-#endif /* !KERNEL */
-
-       switch (ctype) {
-       case OS_LOG_BUFFER_VALUE_TYPE_COUNT:
-       case OS_LOG_BUFFER_VALUE_TYPE_SCALAR:
-               if (is_private) {
-                       _encode_data(content, tempString, strlen(tempString) + 1, context);
-               } else {
-                       if ((context->content_off + content_sz) > context->content_sz) {
-                               return false;
-                       }
-
-                       memcpy(content->value, arg, arg_len);
-                       content->size = (uint8_t)arg_len;
-                       context->content_off += content_sz;
-               }
-               break;
-
-       case OS_LOG_BUFFER_VALUE_TYPE_STRING:
-               context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-               if (_os_log_string_is_public(arg)) {
-                       content->flags &= ~OS_LOG_CONTENT_FLAG_PRIVATE;
-               }
-
-               _encode_data(content, arg, arg_len, context);
-               break;
-
-#ifndef KERNEL
-       case OS_LOG_BUFFER_VALUE_TYPE_POINTER:
-               context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-               _encode_data(content, arg, arg_len, context);
-               break;
-
-       case OS_LOG_BUFFER_VALUE_TYPE_OBJECT:
-               context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-               if (!_NSCF2data(arg, tempString, sizeof(tempString), &obj_private)) {
-                       tempString[0] = '\0';
-               }
-
-               if (!obj_private) {
-                       content->flags &= ~OS_LOG_CONTENT_FLAG_PRIVATE;
-               }
-
-               _encode_data(content, tempString, strlen(tempString) + 1, context);
-               break;
-#endif /* !KERNEL */
-       }
-
-       if (content->flags & OS_LOG_CONTENT_FLAG_PRIVATE) {
-               context->buffer->flags |= OS_LOG_BUFFER_HAS_PRIVATE;
-       }
-
-       context->arg_idx++;
-
-       return true;
-}
-
-static bool
-_os_log_encode(const char *format, va_list args, int saved_errno, os_log_buffer_context_t context)
-{
-       const char *percent = strchr(format, '%');
-#ifndef KERNEL
-       char annotated[256];
-#endif
-
-       while (percent != NULL) {
-               ++percent;
-               if (percent[0] != '%') {
-                       struct os_log_format_value_s value;
-                       int     type = OST_INT;
-#ifndef KERNEL
-                       bool    long_double = false;
-#endif
-                       int     prec = 0;
-                       char    ch;
-
-                       for (bool done = false; !done; percent++) {
-                               switch (ch = percent[0]) {
-                               /* type of types or other */
-                               case 'l': // longer
-                                       type++;
-                                       break;
-
-                               case 'h': // shorter
-                                       type--;
-                                       break;
-
-                               case 'z':
-                                       type = OST_SIZE;
-                                       break;
-
-                               case 'j':
-                                       type = OST_INTMAX;
-                                       break;
-
-                               case 't':
-                                       type = OST_PTRDIFF;
-                                       break;
-
-                               case '.': // precision
-                                       if ((percent[1]) == '*') {
-                                               prec = va_arg(args, int);
-                                               _os_log_encode_arg(&prec, sizeof(prec), OS_LOG_BUFFER_VALUE_TYPE_COUNT, false, context);
-                                               percent++;
-                                               continue;
-                                       } else {
-                                               // we have to read the precision and do the right thing
-                                               const char *fmt = percent + 1;
-                                               prec = 0;
-                                               while (isdigit(ch = *fmt++)) {
-                                                       prec = 10 * prec + (ch - '0');
-                                               }
-
-                                               if (prec > 1024) {
-                                                       prec = 1024;
-                                               }
-
-                                               _os_log_encode_arg(&prec, sizeof(prec), OS_LOG_BUFFER_VALUE_TYPE_COUNT, false, context);
-                                       }
-                                       break;
-
-                               case '-': // left-align
-                               case '+': // force sign
-                               case ' ': // prefix non-negative with space
-                               case '#': // alternate
-                               case '\'': // group by thousands
-                                       break;
-
-                               /* fixed types */
-                               case 'd': // integer
-                               case 'i': // integer
-                               case 'o': // octal
-                               case 'u': // unsigned
-                               case 'x': // hex
-                               case 'X': // upper-hex
-                                       switch (type) {
-                                       case OST_CHAR:
-                                               value.type.ch = (char) va_arg(args, int);
-                                               _os_log_encode_arg(&value.type.ch, sizeof(value.type.ch), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_SHORT:
-                                               value.type.s = (short) va_arg(args, int);
-                                               _os_log_encode_arg(&value.type.s, sizeof(value.type.s), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_INT:
-                                               value.type.i = va_arg(args, int);
-                                               _os_log_encode_arg(&value.type.i, sizeof(value.type.i), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_LONG:
-                                               value.type.l = va_arg(args, long);
-                                               _os_log_encode_arg(&value.type.l, sizeof(value.type.l), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_LONGLONG:
-                                               value.type.ll = va_arg(args, long long);
-                                               _os_log_encode_arg(&value.type.ll, sizeof(value.type.ll), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_SIZE:
-                                               value.type.z = va_arg(args, size_t);
-                                               _os_log_encode_arg(&value.type.z, sizeof(value.type.z), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_INTMAX:
-                                               value.type.im = va_arg(args, intmax_t);
-                                               _os_log_encode_arg(&value.type.im, sizeof(value.type.im), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       case OST_PTRDIFF:
-                                               value.type.pd = va_arg(args, ptrdiff_t);
-                                               _os_log_encode_arg(&value.type.pd, sizeof(value.type.pd), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                               break;
-
-                                       default:
-                                               return false;
-                                       }
-                                       done = true;
-                                       break;
-
-#ifndef KERNEL
-                               case '{':
-                                       // we do not support this for shimmed code
-                                       if (context->shimmed) {
-                                               return false;
-                                       }
-
-                                       for (const char *curr2 = percent + 1; (ch = (*curr2)) != NUL; curr2++) {
-                                               if (ch == '}') {
-                                                       strlcpy(annotated, percent, MIN(curr2 - (percent + 1), sizeof(annotated)));
-                                                       context->annotated = annotated;
-                                                       percent = curr2;
-                                                       break;
-                                               }
-                                       }
-                                       break;
-#endif /* !KERNEL */
-
-                               case 'p': // pointer
-                                       value.type.p = va_arg(args, void *);
-                                       _os_log_encode_arg(&value.type.p, sizeof(value.type.p), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                       done = true;
-                                       break;
-
-#ifndef KERNEL
-                               case 'P': // pointer data
-                                       if (context->shimmed) { // we do not support this for shimmed code
-                                               return false;
-                                       }
-
-                                       context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-                                       value.type.p = va_arg(args, void *);
-
-                                       // capture the string pointer to generate a symptom
-                                       if (context->log && context->log->generate_symptoms && context->arg_idx == 1 && value.type.pch && prec) {
-                                               context->symptom_ptr = value.type.p;
-                                               context->symptom_ptr_len = prec;
-                                       }
-
-                                       _os_log_encode_arg(value.type.p, prec, OS_LOG_BUFFER_VALUE_TYPE_POINTER, false, context);
-                                       prec = 0;
-                                       done = true;
-                                       break;
-#endif /* !KERNEL */
-
-#ifndef KERNEL
-                               case 'L': // long double
-                                       long_double = true;
-                                       break;
-
-                               case 'a': case 'A': case 'e': case 'E': // floating types
-                               case 'f': case 'F': case 'g': case 'G':
-                                       if (long_double) {
-                                               value.type.ld = va_arg(args, long double);
-                                               _os_log_encode_arg(&value.type.ld, sizeof(value.type.ld), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                       } else {
-                                               value.type.d = va_arg(args, double);
-                                               _os_log_encode_arg(&value.type.d, sizeof(value.type.d), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                       }
-                                       done = true;
-                                       break;
-#endif /* !KERNEL */
-
-                               case 'c': // char
-                                       value.type.ch = (char) va_arg(args, int);
-                                       _os_log_encode_arg(&value.type.ch, sizeof(value.type.ch), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                       done = true;
-                                       break;
-
-#ifndef KERNEL
-                               case 'C': // wide-char
-                                       value.type.wch = va_arg(args, wint_t);
-                                       _os_log_encode_arg(&value.type.wch, sizeof(value.type.wch), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                       done = true;
-                                       break;
-#endif /* !KERNEL */
-
-                               case 's': // string
-                                       value.type.pch = va_arg(args, char *);
-                                       if (!prec && value.type.pch != NULL) {
-                                               prec = (int) strlen(value.type.pch) + 1;
-                                       }
-
-#ifndef KERNEL
-                                       // capture the string pointer to generate a symptom
-                                       if (context->log && context->log->generate_symptoms && context->arg_idx == 0 && value.type.pch) {
-                                               context->symptom_str = value.type.pch;
-                                       }
-#endif
-
-                                       context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-                                       _os_log_encode_arg(value.type.pch, prec, OS_LOG_BUFFER_VALUE_TYPE_STRING, false, context);
-                                       prec = 0;
-                                       done = true;
-                                       break;
-
-#ifndef KERNEL
-                               case 'S': // wide-string
-                                       value.type.pwch = va_arg(args, wchar_t *);
-                                       if (!prec && value.type.pwch != NULL) {
-                                               prec = (int) wcslen(value.type.pwch) + 1;
-                                       }
-
-                                       context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-                                       _os_log_encode_arg(value.type.pwch, prec, OS_LOG_BUFFER_VALUE_TYPE_STRING, false, context);
-                                       prec = 0;
-                                       done = true;
-                                       break;
-#endif /* !KERNEL */
-
-#ifndef KERNEL
-                               case '@': // CFTypeRef aka NSObject *
-                                       context->buffer->flags |= OS_LOG_BUFFER_HAS_NON_SCALAR;
-                                       _os_log_encode_arg(va_arg(args, void *), 0, OS_LOG_BUFFER_VALUE_TYPE_OBJECT, false, context);
-                                       done = true;
-                                       break;
-#endif /* !KERNEL */
-
-                               case 'm':
-                                       value.type.i = saved_errno;
-                                       _os_log_encode_arg(&value.type.i, sizeof(value.type.i), OS_LOG_BUFFER_VALUE_TYPE_SCALAR, false, context);
-                                       done = true;
-                                       break;
-
-                               default:
-                                       if (isdigit(ch)) { // [0-9]
-                                               continue;
-                                       }
-                                       return false;
-                               }
-
-                               if (done) {
-                                       percent = strchr(percent, '%'); // Find next format
-                                       break;
-                               }
-                       }
-               } else {
-                       percent = strchr(percent + 1, '%'); // Find next format after %%
-               }
-       }
-
-       context->buffer->arg_cnt = context->arg_idx;
-       context->content_sz = context->content_off;
-       context->pubdata_sz = context->pubdata_off;
-       context->privdata_sz = context->privdata_off;
-       context->arg_idx = context->content_off = context->pubdata_off = context->privdata_off = 0;
-
-       return true;
-}
+void os_log_context_init(os_log_context_t, logmem_t *, uint8_t *, size_t);
+void os_log_context_free(os_log_context_t);
+bool os_log_context_encode(os_log_context_t, const char *, va_list, void *, void *, bool);
 
 #endif /* log_encode_h */