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