blob: ee1594e78a92599a12e6a6c914ead90c20f7e96c [file] [log] [blame]
// RUN: %empty-directory(%t)
// RUN: %clang %target-cc-options -g -O0 -isysroot %sdk -I %swift_src_root/stdlib/public/Darwin/os -framework Foundation %swift_src_root/stdlib/public/Darwin/os/format.m %swift_src_root/stdlib/public/Darwin/os/os_trace_blob.c %s -o %t/os_log_format
// RUN: %target-run %t/os_log_format | %FileCheck %s
// REQUIRES: objc_interop
// REQUIRES: executable_test
#import <Foundation/Foundation.h>
#import <stdint.h>
#import "format.h"
// CHECK-NOT: FAIL
// CHECK: PASS
static bool
compare_buffers(char *fail_prefix, char *bufa, char *bufb, size_t size)
{
if (!memcmp(bufa, bufb, size)) {
return true;
}
os_log_fmt_hdr_t hdra = (os_log_fmt_hdr_t)bufa;
os_log_fmt_hdr_t hdrb = (os_log_fmt_hdr_t)bufb;
if (hdra->hdr_flags != hdrb->hdr_flags) {
printf("FAIL: %s: header flags mismatch (0x%x != 0x%x)\n", fail_prefix,
hdra->hdr_flags, hdrb->hdr_flags);
return false;
}
if (hdra->hdr_cmd_cnt != hdrb->hdr_cmd_cnt) {
printf("FAIL: %s: command count mismatch (0x%x != 0x%x)\n", fail_prefix,
hdra->hdr_cmd_cnt, hdrb->hdr_cmd_cnt);
return false;
}
os_log_fmt_cmd_t cmda = (os_log_fmt_cmd_t)((uint8_t *)hdra +
sizeof(os_log_fmt_hdr_s));
os_log_fmt_cmd_t cmdb = (os_log_fmt_cmd_t)((uint8_t *)hdrb +
sizeof(os_log_fmt_hdr_s));
for (size_t idx = 0; idx < hdra->hdr_cmd_cnt; idx++) {
if (cmda->cmd_flags != cmdb->cmd_flags) {
printf("FAIL: %s: command %zu flags mismatch (0x%x != 0x%x)\n",
fail_prefix, idx, cmda->cmd_flags, cmdb->cmd_flags);
return false;
}
if (cmda->cmd_type != cmdb->cmd_type) {
printf("FAIL: %s: command %zu type mismatch (0x%x != 0x%x)\n",
fail_prefix, idx, cmda->cmd_type, cmdb->cmd_type);
return false;
}
if (cmda->cmd_size != cmdb->cmd_size) {
printf("FAIL: %s: command %zu size mismatch (0x%x != 0x%x)\n",
fail_prefix, idx, cmda->cmd_size, cmdb->cmd_size);
return false;
}
if (memcmp(cmda->cmd_data, cmdb->cmd_data, cmda->cmd_size)) {
printf("FAIL: %s: command %zu data mismatch\n", fail_prefix, idx);
printf("COMPILER: ");
for (size_t i=0; i<cmda->cmd_size; i++) {
printf("%02x ", cmda->cmd_data[i]);
}
printf("\nOVERLAY: ");
for (size_t i=0; i<cmdb->cmd_size; i++) {
printf("%02x ", cmdb->cmd_data[i]);
}
printf("\n");
return false;
}
cmda = (os_log_fmt_cmd_t)((uint8_t *)cmda + sizeof(os_log_fmt_cmd_s)
+ cmda->cmd_size);
cmdb = (os_log_fmt_cmd_t)((uint8_t *)cmdb + sizeof(os_log_fmt_cmd_s)
+ cmdb->cmd_size);
}
return true;
}
static bool
_t_log_encode(char buf[OS_LOG_FMT_BUF_SIZE], int saved_errno,
os_trace_blob_t blob, const char *format, ...)
{
va_list va;
bool rv;
va_start(va, format);
rv = _os_log_encode(buf, format, va, saved_errno, blob);
va_end(va);
return rv;
}
#define compiler_format(buf, fmt, ...) ({ \
__builtin_os_log_format(buf, fmt, ##__VA_ARGS__); \
(uint32_t)__builtin_os_log_format_buffer_size(fmt, ##__VA_ARGS__); \
})
#define overlay_format(buf, fmt, ...) ({ \
os_trace_blob_s ob = { \
.ob_s = os_trace_buf, \
.ob_size = OS_LOG_FMT_BUF_SIZE, \
.ob_maxsize = OS_LOG_FMT_BUF_SIZE, \
.ob_binary = true \
}; \
_t_log_encode(os_trace_buf, 0, &ob, fmt, ##__VA_ARGS__); \
(uint32_t)ob.ob_len; \
})
int
main(int argc, char **argv)
{
static char compiler_buf[8192];
static char os_trace_buf[OS_LOG_FMT_BUF_SIZE];
uint32_t compiler_size, our_size;
int i;
#define ACCEPT(_fmt, ...) ({ \
compiler_size = compiler_format(compiler_buf, _fmt, ##__VA_ARGS__); \
our_size = overlay_format(os_trace_buf, _fmt, ##__VA_ARGS__); \
if (!compare_buffers("during: \"" _fmt "\"", compiler_buf, os_trace_buf, \
our_size)) { \
exit(1); \
} \
})
ACCEPT("doesn't even have an argument");
ACCEPT("simple char %hhd", (char)10);
ACCEPT("simple short %hd", (short)10);
ACCEPT("simple integer %d", 10);
ACCEPT("simple long long %lld", (long long)10);
ACCEPT("simple pointer %p", "sad");
ACCEPT("simple float %f", (float)1.5);
ACCEPT("simple double %f", 1.5);
#ifdef __LP64__
// Disabled because the upstream clang output for long double changed
// and causes CI fallout
// ACCEPT("simple long double %Lf", (long double)1.5);
#endif
ACCEPT("integer with a static width %666d", 10);
ACCEPT("integer with a static precision %.42d", 10);
ACCEPT("integer with a static width & precision %666.42d", 10);
ACCEPT("integer with dynamic width %*d", 666, 10);
ACCEPT("integer with dynamic precision %.*d", 42, 10);
ACCEPT("integer with dynamic width & precision %*.*d", 666, 42, 10);
// All the %s tests below are disabled for the overlay because
// the overlay assumes %s really means %@.
// ACCEPT("simple string %s", "sad");
// ACCEPT("string with a static width %666s", "sad");
// ACCEPT("string with a static precision %.42s", "sad");
// ACCEPT("string with a static width & precision %666.42s", "sad");
// ACCEPT("string with dynamic width %*s", 666, "sad");
// ACCEPT("string with dynamic precision %.*s", 42, "sad");
// ACCEPT("string with dynamic width & precision %*.*s", 666, 42, "sad");
ACCEPT("data with a static precision %.42P", "sad");
ACCEPT("data with a static width & precision %666.42P", "sad");
ACCEPT("data with dynamic precision %.*P", 42, "sad");
ACCEPT("data with dynamic width & precision %*.*P", 666, 42, "sad");
ACCEPT("simple object %@", @"sad");
ACCEPT("object with a static width %666@", @"sad");
ACCEPT("object with dynamic width %*@", 666, @"sad");
// privacy and annotations
ACCEPT("simple integer %{public}d", 10);
ACCEPT("simple integer %{private}d", 10);
ACCEPT("simple integer %{public, blah}d", 10);
ACCEPT("simple integer %{public, builtin:blah::bluh}d", 10);
ACCEPT("integer with a static width %{private}666d", 10);
ACCEPT("integer with a static precision %{private}.42d", 10);
ACCEPT("integer with a static width & precision %{private}666.42d", 10);
ACCEPT("integer with dynamic width %{private}*d", 666, 10);
ACCEPT("integer with dynamic precision %{private}.*d", 42, 10);
ACCEPT("integer with dynamic width & precision %{private}*.*d", 666, 42, 10);
// ACCEPT("simple string %{private}s", "sad");
// ACCEPT("string with a static width %{private}666s", "sad");
// ACCEPT("string with a static precision %{private}.42s", "sad");
// ACCEPT("string with a static width & precision %{private}666.42s", "sad");
// ACCEPT("string with dynamic width %{private}*s", 666, "sad");
// ACCEPT("string with dynamic precision %{private}.*s", 42, "sad");
// ACCEPT("string with dynamic width & precision %{private}*.*s", 666, 42, "sad");
ACCEPT("data with a static precision %{private}.42P", "sad");
ACCEPT("data with a static width & precision %{private}666.42P", "sad");
ACCEPT("data with dynamic precision %{private}.*P", 42, "sad");
ACCEPT("data with dynamic width & precision %{private}*.*P", 666, 42, "sad");
ACCEPT("simple object %{private}@", @"sad");
ACCEPT("object with a static width %{private}666@", @"sad");
ACCEPT("object with dynamic width %{private}*@", 666, @"sad");
printf("PASS\n");
}