2 * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #include "log_encode_types.h"
28 #include <sys/param.h>
31 #define isdigit(ch) (((ch) >= '0') && ((ch) <= '9'))
35 _encode_data(os_log_buffer_value_t content
, const void *arg
, uint16_t arg_len
, os_log_buffer_context_t context
)
37 struct os_log_arginfo_s arginfo
;
40 if (content
->flags
& OS_LOG_CONTENT_FLAG_PRIVATE
) {
41 databuf
= context
->privdata
+ context
->privdata_off
;
42 arginfo
.length
= MIN(arg_len
, (context
->privdata_sz
- context
->privdata_off
));
43 arginfo
.offset
= context
->privdata_off
;
45 databuf
= context
->pubdata
+ context
->pubdata_off
;
46 arginfo
.length
= MIN(arg_len
, (context
->pubdata_sz
- context
->pubdata_off
));
47 arginfo
.offset
= context
->pubdata_off
;
50 if (context
->arg_content_sz
> 0) {
51 arginfo
.length
= MIN(context
->arg_content_sz
, arginfo
.length
);
54 memcpy(content
->value
, &arginfo
, sizeof(arginfo
));
55 content
->size
= sizeof(arginfo
);
58 if (content
->type
== OS_LOG_BUFFER_VALUE_TYPE_STRING
60 || content
->type
== OS_LOG_BUFFER_VALUE_TYPE_OBJECT
63 strlcpy(databuf
, arg
, arginfo
.length
);
65 memcpy(databuf
, arg
, arginfo
.length
);
69 if (content
->flags
& OS_LOG_CONTENT_FLAG_PRIVATE
) {
70 context
->privdata_off
+= arginfo
.length
;
72 context
->pubdata_off
+= arginfo
.length
;
75 context
->content_off
+= sizeof(*content
) + content
->size
;
76 context
->arg_content_sz
= 0;
83 _os_log_parse_annotated(char *annotated
, const char **visibility
, const char **library
, const char **type
)
85 char *values
[3] = { NULL
};
90 char *token
= strsep(&annotated
, ", {}");
99 values
[cnt
++] = token
;
102 if ((cnt
> 0) && (!strcmp(values
[0], "public") || !strcmp(values
[0], "private"))) {
103 if (visibility
!= NULL
) {
104 (*visibility
) = values
[0];
110 if (idx
< cnt
&& (library
!= NULL
) && (type
!= NULL
)) {
111 char *decoder
= values
[idx
];
113 for (cnt
= 0; cnt
< 3; ) {
114 char *token
= strsep(&decoder
, ": {}");
119 if (*token
== '\0') {
123 values
[cnt
++] = token
;
127 (*library
) = values
[0];
132 (*library
) = "builtin";
141 _os_log_encode_arg(const void *arg
, uint16_t arg_len
, os_log_value_type_t ctype
, bool is_private
, os_log_buffer_context_t context
)
143 os_log_buffer_value_t content
= (os_log_buffer_value_t
) &context
->buffer
->content
[context
->content_off
];
144 size_t content_sz
= sizeof(*content
) + arg_len
;
145 char tempString
[OS_LOG_BUFFER_MAX_SIZE
] = {};
147 bool obj_private
= true;
150 content
->type
= ctype
;
151 content
->flags
= (is_private
? OS_LOG_CONTENT_FLAG_PRIVATE
: 0);
154 if (context
->annotated
!= NULL
) {
155 const char *visibility
= NULL
;
157 _os_log_parse_annotated(context
->annotated
, &visibility
, NULL
, NULL
);
159 if (!strcasecmp(visibility
, "private")) {
160 content
->flags
|= OS_LOG_CONTENT_FLAG_PRIVATE
;
161 } else if (!strcasecmp(visibility
, "public")) {
162 content
->flags
&= ~OS_LOG_CONTENT_FLAG_PRIVATE
;
166 context
->annotated
= NULL
;
171 case OS_LOG_BUFFER_VALUE_TYPE_COUNT
:
172 case OS_LOG_BUFFER_VALUE_TYPE_SCALAR
:
174 _encode_data(content
, tempString
, strlen(tempString
) + 1, context
);
176 if ((context
->content_off
+ content_sz
) > context
->content_sz
) {
180 memcpy(content
->value
, arg
, arg_len
);
181 content
->size
= arg_len
;
182 context
->content_off
+= content_sz
;
186 case OS_LOG_BUFFER_VALUE_TYPE_STRING
:
187 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
188 if (_os_log_string_is_public(arg
)) {
189 content
->flags
&= ~OS_LOG_CONTENT_FLAG_PRIVATE
;
192 _encode_data(content
, arg
, arg_len
, context
);
196 case OS_LOG_BUFFER_VALUE_TYPE_POINTER
:
197 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
198 _encode_data(content
, arg
, arg_len
, context
);
201 case OS_LOG_BUFFER_VALUE_TYPE_OBJECT
:
202 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
203 if (!_NSCF2data(arg
, tempString
, sizeof(tempString
), &obj_private
)) {
204 tempString
[0] = '\0';
208 content
->flags
&= ~OS_LOG_CONTENT_FLAG_PRIVATE
;
211 _encode_data(content
, tempString
, strlen(tempString
) + 1, context
);
216 if (content
->flags
& OS_LOG_CONTENT_FLAG_PRIVATE
) {
217 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_PRIVATE
;
226 _os_log_encode(const char *format
, va_list args
, int saved_errno
, os_log_buffer_context_t context
)
228 const char *percent
= strchr(format
, '%');
233 while (percent
!= NULL
) {
235 if (percent
[0] != '%') {
236 struct os_log_format_value_s value
;
239 bool long_double
= false;
244 for (bool done
= false; !done
; percent
++) {
245 switch (ch
= percent
[0]) {
246 /* type of types or other */
267 case '.': // precision
268 if ((percent
[1]) == '*') {
269 prec
= va_arg(args
, int);
270 _os_log_encode_arg(&prec
, sizeof(prec
), OS_LOG_BUFFER_VALUE_TYPE_COUNT
, false, context
);
274 // we have to read the precision and do the right thing
275 const char *fmt
= percent
+ 1;
277 while (isdigit(ch
= *fmt
++)) {
278 prec
= 10 * prec
+ (ch
- '0');
285 _os_log_encode_arg(&prec
, sizeof(prec
), OS_LOG_BUFFER_VALUE_TYPE_COUNT
, false, context
);
289 case '-': // left-align
290 case '+': // force sign
291 case ' ': // prefix non-negative with space
292 case '#': // alternate
293 case '\'': // group by thousands
300 case 'u': // unsigned
302 case 'X': // upper-hex
305 value
.type
.ch
= va_arg(args
, int);
306 _os_log_encode_arg(&value
.type
.ch
, sizeof(value
.type
.ch
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
310 value
.type
.s
= va_arg(args
, int);
311 _os_log_encode_arg(&value
.type
.s
, sizeof(value
.type
.s
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
315 value
.type
.i
= va_arg(args
, int);
316 _os_log_encode_arg(&value
.type
.i
, sizeof(value
.type
.i
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
320 value
.type
.l
= va_arg(args
, long);
321 _os_log_encode_arg(&value
.type
.l
, sizeof(value
.type
.l
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
325 value
.type
.ll
= va_arg(args
, long long);
326 _os_log_encode_arg(&value
.type
.ll
, sizeof(value
.type
.ll
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
330 value
.type
.z
= va_arg(args
, size_t);
331 _os_log_encode_arg(&value
.type
.z
, sizeof(value
.type
.z
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
335 value
.type
.im
= va_arg(args
, intmax_t);
336 _os_log_encode_arg(&value
.type
.im
, sizeof(value
.type
.im
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
340 value
.type
.pd
= va_arg(args
, ptrdiff_t);
341 _os_log_encode_arg(&value
.type
.pd
, sizeof(value
.type
.pd
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
352 // we do not support this for shimmed code
353 if (context
->shimmed
) {
357 for (const char *curr2
= percent
+ 1; (ch
= (*curr2
)) != NUL
; curr2
++) {
359 strlcpy(annotated
, percent
, MIN(curr2
- (percent
+ 1), sizeof(annotated
)));
360 context
->annotated
= annotated
;
369 value
.type
.p
= va_arg(args
, void *);
370 _os_log_encode_arg(&value
.type
.p
, sizeof(value
.type
.p
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
375 case 'P': // pointer data
376 if (context
->shimmed
) { // we do not support this for shimmed code
380 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
381 value
.type
.p
= va_arg(args
, void *);
383 // capture the string pointer to generate a symptom
384 if (context
->log
&& context
->log
->generate_symptoms
&& context
->arg_idx
== 1 && value
.type
.pch
&& prec
) {
385 context
->symptom_ptr
= value
.type
.p
;
386 context
->symptom_ptr_len
= prec
;
389 _os_log_encode_arg(value
.type
.p
, prec
, OS_LOG_BUFFER_VALUE_TYPE_POINTER
, false, context
);
396 case 'L': // long double
400 case 'a': case 'A': case 'e': case 'E': // floating types
401 case 'f': case 'F': case 'g': case 'G':
403 value
.type
.ld
= va_arg(args
, long double);
404 _os_log_encode_arg(&value
.type
.ld
, sizeof(value
.type
.ld
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
406 value
.type
.d
= va_arg(args
, double);
407 _os_log_encode_arg(&value
.type
.d
, sizeof(value
.type
.d
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
414 value
.type
.ch
= va_arg(args
, int);
415 _os_log_encode_arg(&value
.type
.ch
, sizeof(value
.type
.ch
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
420 case 'C': // wide-char
421 value
.type
.wch
= va_arg(args
, wint_t);
422 _os_log_encode_arg(&value
.type
.wch
, sizeof(value
.type
.wch
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
428 value
.type
.pch
= va_arg(args
, char *);
429 if (!prec
&& value
.type
.pch
!= NULL
) {
430 prec
= (int) strlen(value
.type
.pch
) + 1;
434 // capture the string pointer to generate a symptom
435 if (context
->log
&& context
->log
->generate_symptoms
&& context
->arg_idx
== 0 && value
.type
.pch
) {
436 context
->symptom_str
= value
.type
.pch
;
440 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
441 _os_log_encode_arg(value
.type
.pch
, prec
, OS_LOG_BUFFER_VALUE_TYPE_STRING
, false, context
);
447 case 'S': // wide-string
448 value
.type
.pwch
= va_arg(args
, wchar_t *);
449 if (!prec
&& value
.type
.pwch
!= NULL
) {
450 prec
= (int) wcslen(value
.type
.pwch
) + 1;
453 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
454 _os_log_encode_arg(value
.type
.pwch
, prec
, OS_LOG_BUFFER_VALUE_TYPE_STRING
, false, context
);
461 case '@': // CFTypeRef aka NSObject *
462 context
->buffer
->flags
|= OS_LOG_BUFFER_HAS_NON_SCALAR
;
463 _os_log_encode_arg(va_arg(args
, void *), 0, OS_LOG_BUFFER_VALUE_TYPE_OBJECT
, false, context
);
469 value
.type
.i
= saved_errno
;
470 _os_log_encode_arg(&value
.type
.i
, sizeof(value
.type
.i
), OS_LOG_BUFFER_VALUE_TYPE_SCALAR
, false, context
);
475 if (isdigit(ch
)) { // [0-9]
482 percent
= strchr(percent
, '%'); // Find next format
487 percent
= strchr(percent
+1, '%'); // Find next format after %%
491 context
->buffer
->arg_cnt
= context
->arg_idx
;
492 context
->content_sz
= context
->content_off
;
493 context
->pubdata_sz
= context
->pubdata_off
;
494 context
->privdata_sz
= context
->privdata_off
;
495 context
->arg_idx
= context
->content_off
= context
->pubdata_off
= context
->privdata_off
= 0;
500 #endif /* log_encode_h */