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