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