//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include #include #include "format.h" static inline void _os_log_encode_arg(os_trace_blob_t ob, os_log_fmt_cmd_t cmd, const void *data) { os_trace_blob_add(ob, cmd, sizeof(os_log_fmt_cmd_s)); os_trace_blob_add(ob, data, cmd->cmd_size); } bool _os_log_encode(char buf[OS_LOG_FMT_BUF_SIZE], const char *format, va_list args, int saved_errno, os_trace_blob_t ob) { os_log_fmt_hdr_s hdr = {0}; os_trace_blob_add(ob, &hdr, sizeof(hdr)); const char *percent = strchr(format, '%'); while (percent != NULL) { ++percent; if (percent[0] != '%') { os_log_fmt_cmd_s cmd = {0}; os_log_count_type_t widtht = T_C_NONE; os_log_count_type_t prect = T_C_NONE; os_log_fmt_cmd_flags_t flags = 0; int type = T_INT; bool long_double = false; int precision = 0; char ch; if (hdr.hdr_cmd_cnt == OS_LOG_FMT_MAX_CMDS) { break; } for (bool done = false; !done; percent++) { switch (ch = percent[0]) { /* type of types or other */ case 'l': type++; break; // longer case 'h': type--; break; // shorter case 'z': type = T_SIZE; break; case 'j': type = T_INTMAX; break; case 't': type = T_PTRDIFF; break; case '*': // dynamic width widtht = T_C_DYNAMIC; // if the next character is a '.' then increment percent // and fallthrough to the precision handling code if (percent[1] != '.') { break; } percent++; // FALLTHROUGH case '.': // precision if ((percent[1]) == '*') { prect = T_C_DYNAMIC; percent++; } else { while (isdigit(percent[1])) { precision = 10 * precision + (percent[1] - '0'); percent++; } if (precision > 1024) precision = 1024; prect = T_C_STATIC; } break; case '-': // left-align case '+': // force sign case ' ': // prefix non-negative with space case '#': // alternate case '\'': // group by thousands break; case '{': // annotated symbols for (const char *curr2 = percent + 1; (ch = (*curr2)) != 0; curr2++) { if (ch == '}') { if (strncmp(percent + 1, "private", MIN(curr2 - percent - 1, 7)) == 0) { hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_PRIVATE; flags |= OSLF_CMD_FLAG_PRIVATE; } else if (strncmp(percent + 1, "public", MIN(curr2 - percent - 1, 6)) == 0) { flags |= OSLF_CMD_FLAG_PUBLIC; } percent = curr2; break; } } break; #define encode_width() \ do { \ if (widtht == T_C_DYNAMIC) { \ cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; \ encode(int, 0); \ } \ } while (0) // clang inconsistency: static precision counts are still marked with the // privacy bits of the command they preceed #define encode_precision(type) \ do { \ if (prect != T_C_NONE) { \ cmd.cmd_type = type; \ cmd.cmd_size = sizeof(int); \ if (prect == T_C_STATIC && type == OSLF_CMD_TYPE_COUNT) { \ cmd.cmd_flags = flags; \ } else if (prect == T_C_DYNAMIC) { \ precision = va_arg(args, int); \ } \ _os_log_encode_arg(ob, &cmd, &precision); \ hdr.hdr_cmd_cnt++; \ prect = T_C_NONE; \ } \ } while (0) // scalar data types encode their precision as a scalar #define encode_scalar_preamble() \ do { \ encode_width(); \ if (prect == T_C_DYNAMIC) { \ encode_precision(OSLF_CMD_TYPE_SCALAR); \ } \ } while (0) #define encode_pointer_preamble() \ do { \ encode_width(); \ encode_precision(OSLF_CMD_TYPE_COUNT); \ } while (0) #define encode_nsstring(flags) \ do { \ NSString *__arg = va_arg(args, NSString *); \ const char *_Nullable __var = __arg.UTF8String; \ cmd.cmd_flags = flags; \ cmd.cmd_size = sizeof(__var); \ _os_log_encode_arg(ob, &cmd, &__var); \ hdr.hdr_cmd_cnt++; \ } while (0) #define encode_smallint(ty, flags) \ do { \ int __var = va_arg(args, int); \ cmd.cmd_flags = flags; \ cmd.cmd_size = sizeof(__var); \ _os_log_encode_arg(ob, &cmd, &__var); \ hdr.hdr_cmd_cnt++; \ } while (0) #define encode(ty, flags) \ do { \ ty __var = va_arg(args, ty); \ cmd.cmd_flags = flags; \ cmd.cmd_size = sizeof(__var); \ _os_log_encode_arg(ob, &cmd, &__var); \ hdr.hdr_cmd_cnt++; \ } while (0) /* fixed types */ case 'c': // char case 'd': // integer case 'i': // integer case 'o': // octal case 'u': // unsigned case 'x': // hex case 'X': // upper-hex encode_scalar_preamble(); cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; switch (type) { case T_CHAR: encode_smallint(char, flags); break; case T_SHORT: encode_smallint(short, flags); break; case T_INT: encode(int, flags); break; case T_LONG: encode(long, flags); break; case T_LONGLONG: encode(long long, flags); break; case T_SIZE: encode(size_t, flags); break; case T_INTMAX: encode(intmax_t, flags); break; case T_PTRDIFF: encode(ptrdiff_t, flags); break; default: return false; } done = true; break; case 'p': // emit pointers as scalars cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; encode(void *, flags); done = true; break; case 'C': // wchar is treated like %lc encode_scalar_preamble(); cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; encode_smallint(wint_t, flags); done = true; break; case 'P': // pointer data encode_pointer_preamble(); hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR; cmd.cmd_type = OSLF_CMD_TYPE_DATA; cmd.cmd_size = sizeof(void *); encode(void *, flags); done = true; break; 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': encode_scalar_preamble(); cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; if (long_double) { encode(long double, flags); } else { encode(double, flags); } done = true; break; case 's': // Strings sent from Swift as NSString objects encode_pointer_preamble(); hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR; cmd.cmd_type = OSLF_CMD_TYPE_STRING; encode_nsstring(flags); done = true; break; case '@': // CFTypeRef aka NSObject * // %@ does not support precision encode_width(); hdr.hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR; cmd.cmd_type = OSLF_CMD_TYPE_OBJECT; encode(void *, flags); done = true; break; case 'm': cmd.cmd_type = OSLF_CMD_TYPE_SCALAR; cmd.cmd_size = sizeof(int); cmd.cmd_flags = flags; _os_log_encode_arg(ob, &cmd, &saved_errno); hdr.hdr_cmd_cnt++; done = true; break; default: if (isdigit(ch)) { // [0-9] continue; } done = true; break; } if (done) { percent = strchr(percent, '%'); // Find next format break; } } } else { percent = strchr(percent+1, '%'); // Find next format after %% } } *(os_log_fmt_hdr_t)buf = hdr; return true; } #undef encode_nsstring #undef encode_smallint #undef encode