mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Remove the gratuitous use of the GNU extensions to implement the OS logging module. This allows us to enable `-Werror=gnu` globally, even on macOS builds.
307 lines
11 KiB
Objective-C
307 lines
11 KiB
Objective-C
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 <sys/param.h>
|
|
#include <Foundation/Foundation.h>
|
|
#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
|