1*5c2921b0SApple OSS Distributions /*
2*5c2921b0SApple OSS Distributions * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
3*5c2921b0SApple OSS Distributions *
4*5c2921b0SApple OSS Distributions * @APPLE_LICENSE_HEADER_START@
5*5c2921b0SApple OSS Distributions *
6*5c2921b0SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*5c2921b0SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*5c2921b0SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*5c2921b0SApple OSS Distributions * compliance with the License. Please obtain a copy of the License at
10*5c2921b0SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this
11*5c2921b0SApple OSS Distributions * file.
12*5c2921b0SApple OSS Distributions *
13*5c2921b0SApple OSS Distributions * The Original Code and all software distributed under the License are
14*5c2921b0SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15*5c2921b0SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16*5c2921b0SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17*5c2921b0SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18*5c2921b0SApple OSS Distributions * Please see the License for the specific language governing rights and
19*5c2921b0SApple OSS Distributions * limitations under the License.
20*5c2921b0SApple OSS Distributions *
21*5c2921b0SApple OSS Distributions * @APPLE_LICENSE_HEADER_END@
22*5c2921b0SApple OSS Distributions */
23*5c2921b0SApple OSS Distributions
24*5c2921b0SApple OSS Distributions #include <stdbool.h>
25*5c2921b0SApple OSS Distributions #include <firehose/tracepoint_private.h>
26*5c2921b0SApple OSS Distributions #include <kern/assert.h>
27*5c2921b0SApple OSS Distributions #include <kern/counter.h>
28*5c2921b0SApple OSS Distributions #include <kern/locks.h>
29*5c2921b0SApple OSS Distributions #include <pexpert/pexpert.h>
30*5c2921b0SApple OSS Distributions #include <sys/param.h>
31*5c2921b0SApple OSS Distributions
32*5c2921b0SApple OSS Distributions #if __has_feature(ptrauth_calls)
33*5c2921b0SApple OSS Distributions #include <mach/vm_param.h>
34*5c2921b0SApple OSS Distributions #include <ptrauth.h>
35*5c2921b0SApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
36*5c2921b0SApple OSS Distributions
37*5c2921b0SApple OSS Distributions #include "log_encode.h"
38*5c2921b0SApple OSS Distributions #include "log_mem.h"
39*5c2921b0SApple OSS Distributions
40*5c2921b0SApple OSS Distributions #define LOG_FMT_MAX_PRECISION (1024)
41*5c2921b0SApple OSS Distributions #define log_context_cursor(ctx) &(ctx)->ctx_hdr->hdr_data[(ctx)->ctx_content_off]
42*5c2921b0SApple OSS Distributions
43*5c2921b0SApple OSS Distributions extern boolean_t doprnt_hide_pointers;
44*5c2921b0SApple OSS Distributions
45*5c2921b0SApple OSS Distributions SCALABLE_COUNTER_DEFINE(oslog_p_fmt_invalid_msgcount);
46*5c2921b0SApple OSS Distributions SCALABLE_COUNTER_DEFINE(oslog_p_fmt_max_args_msgcount);
47*5c2921b0SApple OSS Distributions SCALABLE_COUNTER_DEFINE(oslog_p_truncated_msgcount);
48*5c2921b0SApple OSS Distributions
49*5c2921b0SApple OSS Distributions static bool
is_digit(char ch)50*5c2921b0SApple OSS Distributions is_digit(char ch)
51*5c2921b0SApple OSS Distributions {
52*5c2921b0SApple OSS Distributions return (ch >= '0') && (ch <= '9');
53*5c2921b0SApple OSS Distributions }
54*5c2921b0SApple OSS Distributions
55*5c2921b0SApple OSS Distributions static bool
is_kernel_pointer(void * arg,size_t arg_len)56*5c2921b0SApple OSS Distributions is_kernel_pointer(void *arg, size_t arg_len)
57*5c2921b0SApple OSS Distributions {
58*5c2921b0SApple OSS Distributions if (arg_len < sizeof(void *)) {
59*5c2921b0SApple OSS Distributions return false;
60*5c2921b0SApple OSS Distributions }
61*5c2921b0SApple OSS Distributions
62*5c2921b0SApple OSS Distributions unsigned long long value = 0;
63*5c2921b0SApple OSS Distributions assert(arg_len <= sizeof(value));
64*5c2921b0SApple OSS Distributions (void) memcpy(&value, arg, arg_len);
65*5c2921b0SApple OSS Distributions
66*5c2921b0SApple OSS Distributions #if __has_feature(ptrauth_calls)
67*5c2921b0SApple OSS Distributions /**
68*5c2921b0SApple OSS Distributions * Strip out the pointer authentication code before
69*5c2921b0SApple OSS Distributions * checking whether the pointer is a kernel address.
70*5c2921b0SApple OSS Distributions */
71*5c2921b0SApple OSS Distributions value = (unsigned long long)VM_KERNEL_STRIP_PTR(value);
72*5c2921b0SApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
73*5c2921b0SApple OSS Distributions
74*5c2921b0SApple OSS Distributions return value >= VM_MIN_KERNEL_AND_KEXT_ADDRESS && value <= VM_MAX_KERNEL_ADDRESS;
75*5c2921b0SApple OSS Distributions }
76*5c2921b0SApple OSS Distributions
77*5c2921b0SApple OSS Distributions static void
log_context_cursor_advance(os_log_context_t ctx,size_t amount)78*5c2921b0SApple OSS Distributions log_context_cursor_advance(os_log_context_t ctx, size_t amount)
79*5c2921b0SApple OSS Distributions {
80*5c2921b0SApple OSS Distributions ctx->ctx_content_off += amount;
81*5c2921b0SApple OSS Distributions assert(log_context_cursor(ctx) <= (ctx->ctx_buffer + ctx->ctx_buffer_sz));
82*5c2921b0SApple OSS Distributions }
83*5c2921b0SApple OSS Distributions
84*5c2921b0SApple OSS Distributions static bool
log_fits(os_log_context_t ctx,size_t data_size)85*5c2921b0SApple OSS Distributions log_fits(os_log_context_t ctx, size_t data_size)
86*5c2921b0SApple OSS Distributions {
87*5c2921b0SApple OSS Distributions return (ctx->ctx_content_off + data_size) <= ctx->ctx_content_sz;
88*5c2921b0SApple OSS Distributions }
89*5c2921b0SApple OSS Distributions
90*5c2921b0SApple OSS Distributions static bool
log_fits_cmd(os_log_context_t ctx,size_t data_size)91*5c2921b0SApple OSS Distributions log_fits_cmd(os_log_context_t ctx, size_t data_size)
92*5c2921b0SApple OSS Distributions {
93*5c2921b0SApple OSS Distributions return log_fits(ctx, sizeof(*ctx->ctx_hdr) + data_size);
94*5c2921b0SApple OSS Distributions }
95*5c2921b0SApple OSS Distributions
96*5c2921b0SApple OSS Distributions static void
log_range_update(os_log_fmt_range_t range,uint16_t offset,uint16_t length)97*5c2921b0SApple OSS Distributions log_range_update(os_log_fmt_range_t range, uint16_t offset, uint16_t length)
98*5c2921b0SApple OSS Distributions {
99*5c2921b0SApple OSS Distributions range->offset = offset;
100*5c2921b0SApple OSS Distributions /*
101*5c2921b0SApple OSS Distributions * Truncated flag may have already been set earlier, hence do not
102*5c2921b0SApple OSS Distributions * overwrite it blindly.
103*5c2921b0SApple OSS Distributions */
104*5c2921b0SApple OSS Distributions if (length < range->length) {
105*5c2921b0SApple OSS Distributions range->truncated = true;
106*5c2921b0SApple OSS Distributions }
107*5c2921b0SApple OSS Distributions range->length = length;
108*5c2921b0SApple OSS Distributions }
109*5c2921b0SApple OSS Distributions
110*5c2921b0SApple OSS Distributions /*
111*5c2921b0SApple OSS Distributions * Stores a command in the main section. The value itself is wrapped in
112*5c2921b0SApple OSS Distributions * the os_log_fmt_cmd_t struct.
113*5c2921b0SApple OSS Distributions */
114*5c2921b0SApple OSS Distributions static void
log_add_cmd(os_log_context_t ctx,os_log_fmt_cmd_type_t type,uint8_t flags,void * arg,size_t arg_size)115*5c2921b0SApple OSS Distributions log_add_cmd(os_log_context_t ctx, os_log_fmt_cmd_type_t type, uint8_t flags,
116*5c2921b0SApple OSS Distributions void *arg, size_t arg_size)
117*5c2921b0SApple OSS Distributions {
118*5c2921b0SApple OSS Distributions os_log_fmt_cmd_t cmd;
119*5c2921b0SApple OSS Distributions const size_t cmd_sz = sizeof(*cmd) + arg_size;
120*5c2921b0SApple OSS Distributions
121*5c2921b0SApple OSS Distributions assert(log_fits_cmd(ctx, cmd_sz));
122*5c2921b0SApple OSS Distributions assert(arg_size <= UINT8_MAX);
123*5c2921b0SApple OSS Distributions
124*5c2921b0SApple OSS Distributions cmd = (os_log_fmt_cmd_t)log_context_cursor(ctx);
125*5c2921b0SApple OSS Distributions cmd->cmd_type = type;
126*5c2921b0SApple OSS Distributions cmd->cmd_flags = flags;
127*5c2921b0SApple OSS Distributions cmd->cmd_size = (uint8_t)arg_size;
128*5c2921b0SApple OSS Distributions (void) memcpy(cmd->cmd_data, arg, cmd->cmd_size);
129*5c2921b0SApple OSS Distributions
130*5c2921b0SApple OSS Distributions assert(cmd_sz == sizeof(*cmd) + cmd->cmd_size);
131*5c2921b0SApple OSS Distributions log_context_cursor_advance(ctx, cmd_sz);
132*5c2921b0SApple OSS Distributions }
133*5c2921b0SApple OSS Distributions
134*5c2921b0SApple OSS Distributions /*
135*5c2921b0SApple OSS Distributions * Collect details about argument which needs to be stored in the pubdata
136*5c2921b0SApple OSS Distributions * section.
137*5c2921b0SApple OSS Distributions */
138*5c2921b0SApple OSS Distributions static void
log_collect_public_range_data(os_log_context_t ctx,os_log_fmt_range_t range,void * arg)139*5c2921b0SApple OSS Distributions log_collect_public_range_data(os_log_context_t ctx, os_log_fmt_range_t range, void *arg)
140*5c2921b0SApple OSS Distributions {
141*5c2921b0SApple OSS Distributions ctx->ctx_pubdata[ctx->ctx_pubdata_cnt++] = (char *)arg;
142*5c2921b0SApple OSS Distributions ctx->ctx_pubdata_sz += range->length;
143*5c2921b0SApple OSS Distributions }
144*5c2921b0SApple OSS Distributions
145*5c2921b0SApple OSS Distributions static void
log_add_range_data(os_log_context_t ctx,os_log_fmt_range_t range,void * arg)146*5c2921b0SApple OSS Distributions log_add_range_data(os_log_context_t ctx, os_log_fmt_range_t range, void *arg)
147*5c2921b0SApple OSS Distributions {
148*5c2921b0SApple OSS Distributions assert(log_fits(ctx, range->length));
149*5c2921b0SApple OSS Distributions (void) memcpy(log_context_cursor(ctx), arg, range->length);
150*5c2921b0SApple OSS Distributions log_context_cursor_advance(ctx, range->length);
151*5c2921b0SApple OSS Distributions }
152*5c2921b0SApple OSS Distributions
153*5c2921b0SApple OSS Distributions static struct os_log_fmt_range_s
log_create_range(os_log_context_t ctx,size_t arg_len)154*5c2921b0SApple OSS Distributions log_create_range(os_log_context_t ctx, size_t arg_len)
155*5c2921b0SApple OSS Distributions {
156*5c2921b0SApple OSS Distributions const size_t final_arg_len = MIN(arg_len, UINT16_MAX);
157*5c2921b0SApple OSS Distributions
158*5c2921b0SApple OSS Distributions return (struct os_log_fmt_range_s) {
159*5c2921b0SApple OSS Distributions .offset = ctx->ctx_pubdata_sz,
160*5c2921b0SApple OSS Distributions .length = (uint16_t)final_arg_len,
161*5c2921b0SApple OSS Distributions .truncated = (final_arg_len < arg_len)
162*5c2921b0SApple OSS Distributions };
163*5c2921b0SApple OSS Distributions }
164*5c2921b0SApple OSS Distributions
165*5c2921b0SApple OSS Distributions static int
log_add_range_arg(os_log_context_t ctx,os_log_fmt_cmd_type_t type,os_log_fmt_cmd_flags_t flags,void * arg,size_t arg_len)166*5c2921b0SApple OSS Distributions log_add_range_arg(os_log_context_t ctx, os_log_fmt_cmd_type_t type, os_log_fmt_cmd_flags_t flags,
167*5c2921b0SApple OSS Distributions void *arg, size_t arg_len)
168*5c2921b0SApple OSS Distributions {
169*5c2921b0SApple OSS Distributions struct os_log_fmt_range_s range;
170*5c2921b0SApple OSS Distributions
171*5c2921b0SApple OSS Distributions if (!log_fits_cmd(ctx, sizeof(range))) {
172*5c2921b0SApple OSS Distributions return ENOMEM;
173*5c2921b0SApple OSS Distributions }
174*5c2921b0SApple OSS Distributions
175*5c2921b0SApple OSS Distributions range = log_create_range(ctx, arg_len);
176*5c2921b0SApple OSS Distributions
177*5c2921b0SApple OSS Distributions if (flags == OSLF_CMD_FLAG_PUBLIC) {
178*5c2921b0SApple OSS Distributions if (ctx->ctx_pubdata_cnt == OS_LOG_MAX_PUB_ARGS) {
179*5c2921b0SApple OSS Distributions return ENOMEM;
180*5c2921b0SApple OSS Distributions }
181*5c2921b0SApple OSS Distributions assert(ctx->ctx_pubdata_cnt < OS_LOG_MAX_PUB_ARGS);
182*5c2921b0SApple OSS Distributions log_collect_public_range_data(ctx, &range, arg);
183*5c2921b0SApple OSS Distributions }
184*5c2921b0SApple OSS Distributions log_add_cmd(ctx, type, flags, &range, sizeof(range));
185*5c2921b0SApple OSS Distributions ctx->ctx_hdr->hdr_cmd_cnt++;
186*5c2921b0SApple OSS Distributions
187*5c2921b0SApple OSS Distributions return 0;
188*5c2921b0SApple OSS Distributions }
189*5c2921b0SApple OSS Distributions
190*5c2921b0SApple OSS Distributions /*
191*5c2921b0SApple OSS Distributions * Adds a scalar argument value to the main section.
192*5c2921b0SApple OSS Distributions */
193*5c2921b0SApple OSS Distributions static int
log_add_arg(os_log_context_t ctx,os_log_fmt_cmd_type_t type,void * arg,size_t arg_len)194*5c2921b0SApple OSS Distributions log_add_arg(os_log_context_t ctx, os_log_fmt_cmd_type_t type, void *arg, size_t arg_len)
195*5c2921b0SApple OSS Distributions {
196*5c2921b0SApple OSS Distributions assert(type == OSLF_CMD_TYPE_COUNT || type == OSLF_CMD_TYPE_SCALAR);
197*5c2921b0SApple OSS Distributions assert(arg_len < UINT16_MAX);
198*5c2921b0SApple OSS Distributions
199*5c2921b0SApple OSS Distributions if (log_fits_cmd(ctx, arg_len)) {
200*5c2921b0SApple OSS Distributions log_add_cmd(ctx, type, OSLF_CMD_FLAG_PUBLIC, arg, arg_len);
201*5c2921b0SApple OSS Distributions ctx->ctx_hdr->hdr_cmd_cnt++;
202*5c2921b0SApple OSS Distributions return 0;
203*5c2921b0SApple OSS Distributions }
204*5c2921b0SApple OSS Distributions
205*5c2921b0SApple OSS Distributions return ENOMEM;
206*5c2921b0SApple OSS Distributions }
207*5c2921b0SApple OSS Distributions
208*5c2921b0SApple OSS Distributions static void
log_encode_public_data(os_log_context_t ctx)209*5c2921b0SApple OSS Distributions log_encode_public_data(os_log_context_t ctx)
210*5c2921b0SApple OSS Distributions {
211*5c2921b0SApple OSS Distributions const uint16_t orig_content_off = ctx->ctx_content_off;
212*5c2921b0SApple OSS Distributions os_log_fmt_hdr_t const hdr = ctx->ctx_hdr;
213*5c2921b0SApple OSS Distributions os_log_fmt_cmd_t cmd = (os_log_fmt_cmd_t)hdr->hdr_data;
214*5c2921b0SApple OSS Distributions
215*5c2921b0SApple OSS Distributions assert(ctx->ctx_pubdata_cnt <= hdr->hdr_cmd_cnt);
216*5c2921b0SApple OSS Distributions
217*5c2921b0SApple OSS Distributions for (int i = 0, pub_i = 0; i < hdr->hdr_cmd_cnt; i++, cmd = (os_log_fmt_cmd_t)(cmd->cmd_data + cmd->cmd_size)) {
218*5c2921b0SApple OSS Distributions if (cmd->cmd_type != OSLF_CMD_TYPE_STRING) {
219*5c2921b0SApple OSS Distributions continue;
220*5c2921b0SApple OSS Distributions }
221*5c2921b0SApple OSS Distributions
222*5c2921b0SApple OSS Distributions os_log_fmt_range_t const range __attribute__((aligned(8))) = (os_log_fmt_range_t)&cmd->cmd_data;
223*5c2921b0SApple OSS Distributions
224*5c2921b0SApple OSS Distributions // Fix offset and length of the argument data in the hdr.
225*5c2921b0SApple OSS Distributions log_range_update(range, ctx->ctx_content_off - orig_content_off,
226*5c2921b0SApple OSS Distributions MIN(range->length, ctx->ctx_content_sz - ctx->ctx_content_off));
227*5c2921b0SApple OSS Distributions
228*5c2921b0SApple OSS Distributions if (range->truncated) {
229*5c2921b0SApple OSS Distributions ctx->ctx_truncated = true;
230*5c2921b0SApple OSS Distributions }
231*5c2921b0SApple OSS Distributions
232*5c2921b0SApple OSS Distributions assert(pub_i < ctx->ctx_pubdata_cnt);
233*5c2921b0SApple OSS Distributions log_add_range_data(ctx, range, ctx->ctx_pubdata[pub_i++]);
234*5c2921b0SApple OSS Distributions }
235*5c2921b0SApple OSS Distributions }
236*5c2921b0SApple OSS Distributions
237*5c2921b0SApple OSS Distributions static bool
log_expand(os_log_context_t ctx,size_t new_size)238*5c2921b0SApple OSS Distributions log_expand(os_log_context_t ctx, size_t new_size)
239*5c2921b0SApple OSS Distributions {
240*5c2921b0SApple OSS Distributions assert(new_size > ctx->ctx_buffer_sz);
241*5c2921b0SApple OSS Distributions
242*5c2921b0SApple OSS Distributions if (!oslog_is_safe()) {
243*5c2921b0SApple OSS Distributions return false;
244*5c2921b0SApple OSS Distributions }
245*5c2921b0SApple OSS Distributions
246*5c2921b0SApple OSS Distributions size_t final_size = new_size;
247*5c2921b0SApple OSS Distributions
248*5c2921b0SApple OSS Distributions void *buf = logmem_alloc_locked(ctx->ctx_logmem, &final_size);
249*5c2921b0SApple OSS Distributions if (!buf) {
250*5c2921b0SApple OSS Distributions return false;
251*5c2921b0SApple OSS Distributions }
252*5c2921b0SApple OSS Distributions assert(final_size >= new_size);
253*5c2921b0SApple OSS Distributions
254*5c2921b0SApple OSS Distributions // address length header + already stored data
255*5c2921b0SApple OSS Distributions const size_t hdr_size = (uint8_t *)ctx->ctx_hdr - ctx->ctx_buffer;
256*5c2921b0SApple OSS Distributions const size_t copy_size = hdr_size + sizeof(*ctx->ctx_hdr) + ctx->ctx_content_sz;
257*5c2921b0SApple OSS Distributions assert(copy_size <= new_size);
258*5c2921b0SApple OSS Distributions (void) memcpy(buf, ctx->ctx_buffer, copy_size);
259*5c2921b0SApple OSS Distributions
260*5c2921b0SApple OSS Distributions if (ctx->ctx_allocated) {
261*5c2921b0SApple OSS Distributions logmem_free_locked(ctx->ctx_logmem, ctx->ctx_buffer, ctx->ctx_buffer_sz);
262*5c2921b0SApple OSS Distributions }
263*5c2921b0SApple OSS Distributions
264*5c2921b0SApple OSS Distributions ctx->ctx_buffer = buf;
265*5c2921b0SApple OSS Distributions ctx->ctx_buffer_sz = final_size;
266*5c2921b0SApple OSS Distributions ctx->ctx_content_sz = (uint16_t)(ctx->ctx_buffer_sz - hdr_size - sizeof(*ctx->ctx_hdr));
267*5c2921b0SApple OSS Distributions ctx->ctx_hdr = (os_log_fmt_hdr_t)&ctx->ctx_buffer[hdr_size];
268*5c2921b0SApple OSS Distributions ctx->ctx_allocated = true;
269*5c2921b0SApple OSS Distributions
270*5c2921b0SApple OSS Distributions return true;
271*5c2921b0SApple OSS Distributions }
272*5c2921b0SApple OSS Distributions
273*5c2921b0SApple OSS Distributions static int
log_encode_fmt_arg(void * arg,size_t arg_len,os_log_fmt_cmd_type_t type,os_log_context_t ctx)274*5c2921b0SApple OSS Distributions log_encode_fmt_arg(void *arg, size_t arg_len, os_log_fmt_cmd_type_t type, os_log_context_t ctx)
275*5c2921b0SApple OSS Distributions {
276*5c2921b0SApple OSS Distributions int rc = 0;
277*5c2921b0SApple OSS Distributions
278*5c2921b0SApple OSS Distributions switch (type) {
279*5c2921b0SApple OSS Distributions case OSLF_CMD_TYPE_COUNT:
280*5c2921b0SApple OSS Distributions case OSLF_CMD_TYPE_SCALAR:
281*5c2921b0SApple OSS Distributions // Scrub kernel pointers.
282*5c2921b0SApple OSS Distributions if (doprnt_hide_pointers && is_kernel_pointer(arg, arg_len)) {
283*5c2921b0SApple OSS Distributions rc = log_add_range_arg(ctx, type, OSLF_CMD_FLAG_PRIVATE, NULL, 0);
284*5c2921b0SApple OSS Distributions ctx->ctx_hdr->hdr_flags |= OSLF_HDR_FLAG_HAS_PRIVATE;
285*5c2921b0SApple OSS Distributions } else {
286*5c2921b0SApple OSS Distributions rc = log_add_arg(ctx, type, arg, arg_len);
287*5c2921b0SApple OSS Distributions }
288*5c2921b0SApple OSS Distributions break;
289*5c2921b0SApple OSS Distributions case OSLF_CMD_TYPE_STRING:
290*5c2921b0SApple OSS Distributions rc = log_add_range_arg(ctx, type, OSLF_CMD_FLAG_PUBLIC, arg, arg_len);
291*5c2921b0SApple OSS Distributions ctx->ctx_hdr->hdr_flags |= OSLF_HDR_FLAG_HAS_NON_SCALAR;
292*5c2921b0SApple OSS Distributions break;
293*5c2921b0SApple OSS Distributions default:
294*5c2921b0SApple OSS Distributions panic("Unsupported log value type");
295*5c2921b0SApple OSS Distributions }
296*5c2921b0SApple OSS Distributions
297*5c2921b0SApple OSS Distributions return rc;
298*5c2921b0SApple OSS Distributions }
299*5c2921b0SApple OSS Distributions
300*5c2921b0SApple OSS Distributions static int
log_encode_fmt(os_log_context_t ctx,const char * format,va_list args)301*5c2921b0SApple OSS Distributions log_encode_fmt(os_log_context_t ctx, const char *format, va_list args)
302*5c2921b0SApple OSS Distributions {
303*5c2921b0SApple OSS Distributions const char *position = format;
304*5c2921b0SApple OSS Distributions
305*5c2921b0SApple OSS Distributions while ((position = strchr(position, '%'))) {
306*5c2921b0SApple OSS Distributions position++; // Look at character(s) after %.
307*5c2921b0SApple OSS Distributions
308*5c2921b0SApple OSS Distributions int type = OST_INT;
309*5c2921b0SApple OSS Distributions boolean_t has_precision = false;
310*5c2921b0SApple OSS Distributions int precision = 0;
311*5c2921b0SApple OSS Distributions
312*5c2921b0SApple OSS Distributions for (bool done = false; !done; position++) {
313*5c2921b0SApple OSS Distributions union os_log_fmt_types_u value;
314*5c2921b0SApple OSS Distributions size_t str_length;
315*5c2921b0SApple OSS Distributions int err = 0;
316*5c2921b0SApple OSS Distributions
317*5c2921b0SApple OSS Distributions switch (position[0]) {
318*5c2921b0SApple OSS Distributions case '%':
319*5c2921b0SApple OSS Distributions // %% prints % character
320*5c2921b0SApple OSS Distributions done = true;
321*5c2921b0SApple OSS Distributions break;
322*5c2921b0SApple OSS Distributions
323*5c2921b0SApple OSS Distributions /* type of types or other */
324*5c2921b0SApple OSS Distributions case 'l': // longer
325*5c2921b0SApple OSS Distributions type++;
326*5c2921b0SApple OSS Distributions break;
327*5c2921b0SApple OSS Distributions
328*5c2921b0SApple OSS Distributions case 'h': // shorter
329*5c2921b0SApple OSS Distributions type--;
330*5c2921b0SApple OSS Distributions break;
331*5c2921b0SApple OSS Distributions
332*5c2921b0SApple OSS Distributions case 'z':
333*5c2921b0SApple OSS Distributions type = OST_SIZE;
334*5c2921b0SApple OSS Distributions break;
335*5c2921b0SApple OSS Distributions
336*5c2921b0SApple OSS Distributions case 'j':
337*5c2921b0SApple OSS Distributions type = OST_INTMAX;
338*5c2921b0SApple OSS Distributions break;
339*5c2921b0SApple OSS Distributions
340*5c2921b0SApple OSS Distributions case 't':
341*5c2921b0SApple OSS Distributions type = OST_PTRDIFF;
342*5c2921b0SApple OSS Distributions break;
343*5c2921b0SApple OSS Distributions
344*5c2921b0SApple OSS Distributions case 'q':
345*5c2921b0SApple OSS Distributions type = OST_LONGLONG;
346*5c2921b0SApple OSS Distributions break;
347*5c2921b0SApple OSS Distributions
348*5c2921b0SApple OSS Distributions case '.': // precision
349*5c2921b0SApple OSS Distributions if (position[1] == '*') {
350*5c2921b0SApple OSS Distributions // Dynamic precision, argument holds actual value.
351*5c2921b0SApple OSS Distributions precision = va_arg(args, int);
352*5c2921b0SApple OSS Distributions position++;
353*5c2921b0SApple OSS Distributions } else {
354*5c2921b0SApple OSS Distributions // Static precision, the value follows in the fmt.
355*5c2921b0SApple OSS Distributions precision = 0;
356*5c2921b0SApple OSS Distributions while (is_digit(position[1])) {
357*5c2921b0SApple OSS Distributions if (precision < LOG_FMT_MAX_PRECISION) {
358*5c2921b0SApple OSS Distributions precision = 10 * precision + (position[1] - '0');
359*5c2921b0SApple OSS Distributions }
360*5c2921b0SApple OSS Distributions position++;
361*5c2921b0SApple OSS Distributions }
362*5c2921b0SApple OSS Distributions precision = MIN(precision, LOG_FMT_MAX_PRECISION);
363*5c2921b0SApple OSS Distributions }
364*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&precision, sizeof(precision), OSLF_CMD_TYPE_COUNT, ctx);
365*5c2921b0SApple OSS Distributions // A negative precision is treated as though it were missing.
366*5c2921b0SApple OSS Distributions if (precision >= 0) {
367*5c2921b0SApple OSS Distributions has_precision = true;
368*5c2921b0SApple OSS Distributions }
369*5c2921b0SApple OSS Distributions break;
370*5c2921b0SApple OSS Distributions
371*5c2921b0SApple OSS Distributions case '-': // left-align
372*5c2921b0SApple OSS Distributions case '+': // force sign
373*5c2921b0SApple OSS Distributions case ' ': // prefix non-negative with space
374*5c2921b0SApple OSS Distributions case '#': // alternate
375*5c2921b0SApple OSS Distributions case '\'': // group by thousands
376*5c2921b0SApple OSS Distributions break;
377*5c2921b0SApple OSS Distributions
378*5c2921b0SApple OSS Distributions /* fixed types */
379*5c2921b0SApple OSS Distributions case 'd': // integer
380*5c2921b0SApple OSS Distributions case 'i': // integer
381*5c2921b0SApple OSS Distributions case 'o': // octal
382*5c2921b0SApple OSS Distributions case 'u': // unsigned
383*5c2921b0SApple OSS Distributions case 'x': // hex
384*5c2921b0SApple OSS Distributions case 'X': // upper-hex
385*5c2921b0SApple OSS Distributions switch (type) {
386*5c2921b0SApple OSS Distributions case OST_CHAR:
387*5c2921b0SApple OSS Distributions value.ch = (char) va_arg(args, int);
388*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.ch, sizeof(value.ch), OSLF_CMD_TYPE_SCALAR, ctx);
389*5c2921b0SApple OSS Distributions break;
390*5c2921b0SApple OSS Distributions
391*5c2921b0SApple OSS Distributions case OST_SHORT:
392*5c2921b0SApple OSS Distributions value.s = (short) va_arg(args, int);
393*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.s, sizeof(value.s), OSLF_CMD_TYPE_SCALAR, ctx);
394*5c2921b0SApple OSS Distributions break;
395*5c2921b0SApple OSS Distributions
396*5c2921b0SApple OSS Distributions case OST_INT:
397*5c2921b0SApple OSS Distributions value.i = va_arg(args, int);
398*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.i, sizeof(value.i), OSLF_CMD_TYPE_SCALAR, ctx);
399*5c2921b0SApple OSS Distributions break;
400*5c2921b0SApple OSS Distributions
401*5c2921b0SApple OSS Distributions case OST_LONG:
402*5c2921b0SApple OSS Distributions value.l = va_arg(args, long);
403*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.l, sizeof(value.l), OSLF_CMD_TYPE_SCALAR, ctx);
404*5c2921b0SApple OSS Distributions break;
405*5c2921b0SApple OSS Distributions
406*5c2921b0SApple OSS Distributions case OST_LONGLONG:
407*5c2921b0SApple OSS Distributions value.ll = va_arg(args, long long);
408*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.ll, sizeof(value.ll), OSLF_CMD_TYPE_SCALAR, ctx);
409*5c2921b0SApple OSS Distributions break;
410*5c2921b0SApple OSS Distributions
411*5c2921b0SApple OSS Distributions case OST_SIZE:
412*5c2921b0SApple OSS Distributions value.z = va_arg(args, size_t);
413*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.z, sizeof(value.z), OSLF_CMD_TYPE_SCALAR, ctx);
414*5c2921b0SApple OSS Distributions break;
415*5c2921b0SApple OSS Distributions
416*5c2921b0SApple OSS Distributions case OST_INTMAX:
417*5c2921b0SApple OSS Distributions value.im = va_arg(args, intmax_t);
418*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.im, sizeof(value.im), OSLF_CMD_TYPE_SCALAR, ctx);
419*5c2921b0SApple OSS Distributions break;
420*5c2921b0SApple OSS Distributions
421*5c2921b0SApple OSS Distributions case OST_PTRDIFF:
422*5c2921b0SApple OSS Distributions value.pd = va_arg(args, ptrdiff_t);
423*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.pd, sizeof(value.pd), OSLF_CMD_TYPE_SCALAR, ctx);
424*5c2921b0SApple OSS Distributions break;
425*5c2921b0SApple OSS Distributions
426*5c2921b0SApple OSS Distributions default:
427*5c2921b0SApple OSS Distributions return EINVAL;
428*5c2921b0SApple OSS Distributions }
429*5c2921b0SApple OSS Distributions done = true;
430*5c2921b0SApple OSS Distributions break;
431*5c2921b0SApple OSS Distributions
432*5c2921b0SApple OSS Distributions case 'p': // pointer
433*5c2921b0SApple OSS Distributions value.p = va_arg(args, void *);
434*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.p, sizeof(value.p), OSLF_CMD_TYPE_SCALAR, ctx);
435*5c2921b0SApple OSS Distributions done = true;
436*5c2921b0SApple OSS Distributions break;
437*5c2921b0SApple OSS Distributions
438*5c2921b0SApple OSS Distributions case 'c': // char
439*5c2921b0SApple OSS Distributions value.ch = (char) va_arg(args, int);
440*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.ch, sizeof(value.ch), OSLF_CMD_TYPE_SCALAR, ctx);
441*5c2921b0SApple OSS Distributions done = true;
442*5c2921b0SApple OSS Distributions break;
443*5c2921b0SApple OSS Distributions
444*5c2921b0SApple OSS Distributions case 's': // string
445*5c2921b0SApple OSS Distributions value.pch = va_arg(args, char *);
446*5c2921b0SApple OSS Distributions if (!value.pch) {
447*5c2921b0SApple OSS Distributions str_length = 0;
448*5c2921b0SApple OSS Distributions } else if (has_precision) {
449*5c2921b0SApple OSS Distributions assert(precision >= 0);
450*5c2921b0SApple OSS Distributions str_length = strnlen(value.pch, precision);
451*5c2921b0SApple OSS Distributions } else {
452*5c2921b0SApple OSS Distributions str_length = strlen(value.pch) + 1;
453*5c2921b0SApple OSS Distributions }
454*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(value.pch, str_length, OSLF_CMD_TYPE_STRING, ctx);
455*5c2921b0SApple OSS Distributions done = true;
456*5c2921b0SApple OSS Distributions break;
457*5c2921b0SApple OSS Distributions
458*5c2921b0SApple OSS Distributions case 'm':
459*5c2921b0SApple OSS Distributions value.i = 0; // Does %m make sense in the kernel?
460*5c2921b0SApple OSS Distributions err = log_encode_fmt_arg(&value.i, sizeof(value.i), OSLF_CMD_TYPE_SCALAR, ctx);
461*5c2921b0SApple OSS Distributions done = true;
462*5c2921b0SApple OSS Distributions break;
463*5c2921b0SApple OSS Distributions
464*5c2921b0SApple OSS Distributions case '0' ... '9':
465*5c2921b0SApple OSS Distributions // Skipping field width, libtrace takes care of it.
466*5c2921b0SApple OSS Distributions break;
467*5c2921b0SApple OSS Distributions
468*5c2921b0SApple OSS Distributions default:
469*5c2921b0SApple OSS Distributions return EINVAL;
470*5c2921b0SApple OSS Distributions }
471*5c2921b0SApple OSS Distributions
472*5c2921b0SApple OSS Distributions if (slowpath(err)) {
473*5c2921b0SApple OSS Distributions return err;
474*5c2921b0SApple OSS Distributions }
475*5c2921b0SApple OSS Distributions }
476*5c2921b0SApple OSS Distributions }
477*5c2921b0SApple OSS Distributions
478*5c2921b0SApple OSS Distributions return 0;
479*5c2921b0SApple OSS Distributions }
480*5c2921b0SApple OSS Distributions
481*5c2921b0SApple OSS Distributions static inline size_t
write_address_location(uint8_t buf[static sizeof (uint64_t)],uintptr_t loc,size_t loc_size)482*5c2921b0SApple OSS Distributions write_address_location(uint8_t buf[static sizeof(uint64_t)], uintptr_t loc, size_t loc_size)
483*5c2921b0SApple OSS Distributions {
484*5c2921b0SApple OSS Distributions if (loc_size == sizeof(uintptr_t)) {
485*5c2921b0SApple OSS Distributions #if __LP64__
486*5c2921b0SApple OSS Distributions loc_size = 6; // 48 bits are enough
487*5c2921b0SApple OSS Distributions #endif
488*5c2921b0SApple OSS Distributions memcpy(buf, (uintptr_t[]){ loc }, loc_size);
489*5c2921b0SApple OSS Distributions } else {
490*5c2921b0SApple OSS Distributions assert(loc_size == sizeof(uint32_t));
491*5c2921b0SApple OSS Distributions memcpy(buf, (uint32_t[]){ (uint32_t)loc }, loc_size);
492*5c2921b0SApple OSS Distributions }
493*5c2921b0SApple OSS Distributions return loc_size;
494*5c2921b0SApple OSS Distributions }
495*5c2921b0SApple OSS Distributions
496*5c2921b0SApple OSS Distributions static void
os_log_encode_location(os_log_context_t ctx,uintptr_t loc,size_t loc_size)497*5c2921b0SApple OSS Distributions os_log_encode_location(os_log_context_t ctx, uintptr_t loc, size_t loc_size)
498*5c2921b0SApple OSS Distributions {
499*5c2921b0SApple OSS Distributions const size_t hdr_size = write_address_location(ctx->ctx_buffer, loc, loc_size);
500*5c2921b0SApple OSS Distributions ctx->ctx_hdr = (os_log_fmt_hdr_t)&ctx->ctx_buffer[hdr_size];
501*5c2921b0SApple OSS Distributions bzero(ctx->ctx_hdr, sizeof(*ctx->ctx_hdr));
502*5c2921b0SApple OSS Distributions ctx->ctx_content_sz = (uint16_t)(ctx->ctx_buffer_sz - hdr_size - sizeof(*ctx->ctx_hdr));
503*5c2921b0SApple OSS Distributions }
504*5c2921b0SApple OSS Distributions
505*5c2921b0SApple OSS Distributions /*
506*5c2921b0SApple OSS Distributions * Encodes argument (meta)data into a format consumed by libtrace. Stores
507*5c2921b0SApple OSS Distributions * metadada for all arguments first. Metadata also include scalar argument
508*5c2921b0SApple OSS Distributions * values. Second step saves data which are encoded separately from respective
509*5c2921b0SApple OSS Distributions * metadata (like strings).
510*5c2921b0SApple OSS Distributions */
511*5c2921b0SApple OSS Distributions bool
os_log_context_encode(os_log_context_t ctx,const char * fmt,va_list args,uintptr_t loc,size_t loc_size)512*5c2921b0SApple OSS Distributions os_log_context_encode(os_log_context_t ctx, const char *fmt, va_list args,
513*5c2921b0SApple OSS Distributions uintptr_t loc, size_t loc_size)
514*5c2921b0SApple OSS Distributions {
515*5c2921b0SApple OSS Distributions os_log_encode_location(ctx, loc, loc_size);
516*5c2921b0SApple OSS Distributions
517*5c2921b0SApple OSS Distributions va_list args_copy;
518*5c2921b0SApple OSS Distributions va_copy(args_copy, args);
519*5c2921b0SApple OSS Distributions
520*5c2921b0SApple OSS Distributions int rc = log_encode_fmt(ctx, fmt, args);
521*5c2921b0SApple OSS Distributions
522*5c2921b0SApple OSS Distributions va_end(args_copy);
523*5c2921b0SApple OSS Distributions
524*5c2921b0SApple OSS Distributions switch (rc) {
525*5c2921b0SApple OSS Distributions case EINVAL:
526*5c2921b0SApple OSS Distributions // Bogus/Unsupported fmt string
527*5c2921b0SApple OSS Distributions counter_inc(&oslog_p_fmt_invalid_msgcount);
528*5c2921b0SApple OSS Distributions return false;
529*5c2921b0SApple OSS Distributions case ENOMEM:
530*5c2921b0SApple OSS Distributions /*
531*5c2921b0SApple OSS Distributions * The fmt contains unreasonable number of arguments (> 32) and
532*5c2921b0SApple OSS Distributions * we ran out of space. We could call log_expand()
533*5c2921b0SApple OSS Distributions * here and retry. However, using such formatting strings rather
534*5c2921b0SApple OSS Distributions * seem like a misuse of the logging system, hence error.
535*5c2921b0SApple OSS Distributions */
536*5c2921b0SApple OSS Distributions counter_inc(&oslog_p_fmt_max_args_msgcount);
537*5c2921b0SApple OSS Distributions return false;
538*5c2921b0SApple OSS Distributions case 0:
539*5c2921b0SApple OSS Distributions break;
540*5c2921b0SApple OSS Distributions default:
541*5c2921b0SApple OSS Distributions panic("unhandled return value");
542*5c2921b0SApple OSS Distributions }
543*5c2921b0SApple OSS Distributions
544*5c2921b0SApple OSS Distributions if (ctx->ctx_pubdata_sz == 0) {
545*5c2921b0SApple OSS Distributions goto finish;
546*5c2921b0SApple OSS Distributions }
547*5c2921b0SApple OSS Distributions
548*5c2921b0SApple OSS Distributions /*
549*5c2921b0SApple OSS Distributions * Logmem may not have been set up yet when logging very early during
550*5c2921b0SApple OSS Distributions * the boot. Be sure to check its state.
551*5c2921b0SApple OSS Distributions */
552*5c2921b0SApple OSS Distributions if (!log_fits(ctx, ctx->ctx_pubdata_sz) && logmem_ready(ctx->ctx_logmem)) {
553*5c2921b0SApple OSS Distributions size_t space_needed = log_context_cursor(ctx) + ctx->ctx_pubdata_sz - ctx->ctx_buffer;
554*5c2921b0SApple OSS Distributions space_needed = MIN(space_needed, logmem_max_size(ctx->ctx_logmem));
555*5c2921b0SApple OSS Distributions (void) log_expand(ctx, space_needed);
556*5c2921b0SApple OSS Distributions }
557*5c2921b0SApple OSS Distributions
558*5c2921b0SApple OSS Distributions log_encode_public_data(ctx);
559*5c2921b0SApple OSS Distributions
560*5c2921b0SApple OSS Distributions if (ctx->ctx_truncated) {
561*5c2921b0SApple OSS Distributions counter_inc(&oslog_p_truncated_msgcount);
562*5c2921b0SApple OSS Distributions }
563*5c2921b0SApple OSS Distributions finish:
564*5c2921b0SApple OSS Distributions ctx->ctx_content_sz = (uint16_t)(log_context_cursor(ctx) - ctx->ctx_buffer);
565*5c2921b0SApple OSS Distributions ctx->ctx_content_off = 0;
566*5c2921b0SApple OSS Distributions return true;
567*5c2921b0SApple OSS Distributions }
568*5c2921b0SApple OSS Distributions
569*5c2921b0SApple OSS Distributions void
os_log_context_init(os_log_context_t ctx,logmem_t * logmem,uint8_t * buffer,size_t buffer_sz)570*5c2921b0SApple OSS Distributions os_log_context_init(os_log_context_t ctx, logmem_t *logmem, uint8_t *buffer, size_t buffer_sz)
571*5c2921b0SApple OSS Distributions {
572*5c2921b0SApple OSS Distributions assert(logmem);
573*5c2921b0SApple OSS Distributions assert(buffer);
574*5c2921b0SApple OSS Distributions assert(buffer_sz > 0);
575*5c2921b0SApple OSS Distributions
576*5c2921b0SApple OSS Distributions bzero(ctx, sizeof(*ctx));
577*5c2921b0SApple OSS Distributions ctx->ctx_logmem = logmem;
578*5c2921b0SApple OSS Distributions ctx->ctx_buffer = buffer;
579*5c2921b0SApple OSS Distributions ctx->ctx_buffer_sz = buffer_sz;
580*5c2921b0SApple OSS Distributions }
581*5c2921b0SApple OSS Distributions
582*5c2921b0SApple OSS Distributions void
os_log_context_free(os_log_context_t ctx)583*5c2921b0SApple OSS Distributions os_log_context_free(os_log_context_t ctx)
584*5c2921b0SApple OSS Distributions {
585*5c2921b0SApple OSS Distributions if (ctx->ctx_allocated) {
586*5c2921b0SApple OSS Distributions logmem_free_locked(ctx->ctx_logmem, ctx->ctx_buffer, ctx->ctx_buffer_sz);
587*5c2921b0SApple OSS Distributions }
588*5c2921b0SApple OSS Distributions }
589