4 #include <kern/cpu_data.h>
11 #include <vm/vm_kern.h>
12 #include <mach/vm_statistics.h>
13 #include <kern/debug.h>
14 #include <libkern/libkern.h>
15 #include <libkern/kernel_mach_header.h>
16 #include <pexpert/pexpert.h>
17 #include <uuid/uuid.h>
18 #include <sys/msgbuf.h>
20 #include <mach/mach_time.h>
21 #include <kern/thread.h>
22 #include <kern/simple_lock.h>
23 #include <kern/kalloc.h>
24 #include <kern/clock.h>
25 #include <kern/assert.h>
27 #include <firehose/tracepoint_private.h>
28 #include <firehose/chunk_private.h>
29 #include <os/firehose_buffer_private.h>
30 #include <os/firehose.h>
32 #include <os/log_private.h>
33 #include "trace_internal.h"
35 #include "log_encode.h"
37 /* on embedded, with no kext loading or unloads,
38 * make the kernel use the libtrace shared cache path for logging
40 #define FIREHOSE_USES_SHARED_CACHE NO_KEXTD
42 #if FIREHOSE_USES_SHARED_CACHE
43 extern vm_offset_t segLOWESTTEXT
;
50 struct os_log_s _os_log_default
;
51 struct os_log_s _os_log_replay
;
52 extern vm_offset_t kernel_firehose_addr
;
53 extern firehose_chunk_t firehose_boot_chunk
;
55 extern void bsd_log_lock(void);
56 extern void bsd_log_unlock(void);
57 extern void logwakeup(struct msgbuf
*);
59 decl_lck_spin_data(extern, oslog_stream_lock
)
60 #define stream_lock() lck_spin_lock(&oslog_stream_lock)
61 #define stream_unlock() lck_spin_unlock(&oslog_stream_lock)
63 extern void oslog_streamwakeup(void);
64 void oslog_streamwrite_locked(firehose_tracepoint_id_u ftid
,
65 uint64_t stamp
, const void *pubdata
, size_t publen
);
66 extern void oslog_streamwrite_metadata_locked(oslog_stream_buf_entry_t m_entry
);
68 extern int oslog_stream_open
;
70 extern void *OSKextKextForAddress(const void *);
72 /* Counters for persistence mode */
73 uint32_t oslog_p_total_msgcount
= 0;
74 uint32_t oslog_p_metadata_saved_msgcount
= 0;
75 uint32_t oslog_p_metadata_dropped_msgcount
= 0;
76 uint32_t oslog_p_error_count
= 0;
77 uint32_t oslog_p_saved_msgcount
= 0;
78 uint32_t oslog_p_dropped_msgcount
= 0;
79 uint32_t oslog_p_boot_dropped_msgcount
= 0;
81 /* Counters for streaming mode */
82 uint32_t oslog_s_total_msgcount
= 0;
83 uint32_t oslog_s_error_count
= 0;
84 uint32_t oslog_s_metadata_msgcount
= 0;
86 static bool oslog_boot_done
= false;
87 extern boolean_t early_boot_complete
;
89 #ifdef XNU_KERNEL_PRIVATE
90 bool startup_serial_logging_active
= true;
91 uint64_t startup_serial_num_procs
= 300;
92 #endif /* XNU_KERNEL_PRIVATE */
95 firehose_tracepoint_id_t
96 firehose_debug_trace(firehose_stream_t stream
, firehose_tracepoint_id_t trace_id
,
97 uint64_t timestamp
, const char *format
, const void *pubdata
, size_t publen
);
99 static inline firehose_tracepoint_id_t
100 _firehose_trace(firehose_stream_t stream
, firehose_tracepoint_id_u ftid
,
101 uint64_t stamp
, const void *pubdata
, size_t publen
);
103 static oslog_stream_buf_entry_t
104 oslog_stream_create_buf_entry(oslog_stream_link_type_t type
, firehose_tracepoint_id_u ftid
,
105 uint64_t stamp
, const void* pubdata
, size_t publen
);
108 _os_log_with_args_internal(os_log_t oslog __unused
, os_log_type_t type __unused
,
109 const char *format
, va_list args
, void *addr
, void *dso
);
112 _os_log_to_msgbuf_internal(const char *format
, va_list args
, bool safe
, bool logging
);
115 _os_log_to_log_internal(os_log_t oslog
, os_log_type_t type
,
116 const char *format
, va_list args
, void *addr
, void *dso
);
120 _os_log_actual(os_log_t oslog
, os_log_type_t type
, const char *format
, void
121 *dso
, void *addr
, os_log_buffer_context_t context
);
124 os_log_info_enabled(os_log_t log __unused
)
130 os_log_debug_enabled(os_log_t log __unused
)
136 os_log_create(const char *subsystem __unused
, const char *category __unused
)
138 return &_os_log_default
;
142 _os_log_string_is_public(const char *str __unused
)
147 __attribute__((noinline
, not_tail_called
)) void
148 _os_log_internal(void *dso
, os_log_t log
, uint8_t type
, const char *message
, ...)
151 void *addr
= __builtin_return_address(0);
153 va_start(args
, message
);
155 _os_log_with_args_internal(log
, type
, message
, args
, addr
, dso
);
162 #pragma mark - shim functions
164 __attribute__((noinline
, not_tail_called
)) void
165 os_log_with_args(os_log_t oslog
, os_log_type_t type
, const char *format
, va_list args
, void *addr
)
167 // if no address passed, look it up
169 addr
= __builtin_return_address(0);
172 _os_log_with_args_internal(oslog
, type
, format
, args
, addr
, NULL
);
176 _os_log_with_args_internal(os_log_t oslog
, os_log_type_t type
,
177 const char *format
, va_list args
, void *addr
, void *dso
)
179 uint32_t logging_config
= atm_get_diagnostic_config();
183 if (format
[0] == '\0') {
187 /* early boot can log to dmesg for later replay (27307943) */
188 safe
= (!early_boot_complete
|| oslog_is_safe());
190 if (logging_config
& ATM_TRACE_DISABLE
|| logging_config
& ATM_TRACE_OFF
) {
196 if (oslog
!= &_os_log_replay
) {
197 _os_log_to_msgbuf_internal(format
, args
, safe
, logging
);
200 if (safe
&& logging
) {
201 _os_log_to_log_internal(oslog
, type
, format
, args
, addr
, dso
);
206 _os_log_to_msgbuf_internal(const char *format
, va_list args
, bool safe
, bool logging
)
208 static int msgbufreplay
= -1;
211 #if DEVELOPMENT || DEBUG
220 if (-1 == msgbufreplay
) {
221 msgbufreplay
= msgbufp
->msg_bufx
;
223 } else if (logging
&& (-1 != msgbufreplay
)) {
225 uint32_t localbuff_size
;
227 char *localbuff
, *p
, *s
, *next
, ch
;
229 position
= msgbufreplay
;
231 localbuff_size
= (msgbufp
->msg_size
+ 2); /* + '\n' + '\0' */
232 /* Size for non-blocking */
233 if (localbuff_size
> 4096) {
234 localbuff_size
= 4096;
237 /* Allocate a temporary non-circular buffer */
238 if ((localbuff
= (char *)kalloc_noblock(localbuff_size
))) {
239 /* in between here, the log could become bigger, but that's fine */
242 * The message buffer is circular; start at the replay pointer, and
243 * make one loop up to write pointer - 1.
245 p
= msgbufp
->msg_bufc
+ position
;
246 for (i
= newl
= 0; p
!= msgbufp
->msg_bufc
+ msgbufp
->msg_bufx
- 1; ++p
) {
247 if (p
>= msgbufp
->msg_bufc
+ msgbufp
->msg_size
) {
248 p
= msgbufp
->msg_bufc
;
256 if (i
>= (localbuff_size
- 2)) {
263 localbuff
[i
++] = '\n';
268 while ((next
= strchr(s
, '\n'))) {
272 os_log(&_os_log_replay
, "%s", s
);
276 kfree(localbuff
, localbuff_size
);
281 va_copy(args_copy
, args
);
282 vprintf_log_locked(format
, args_copy
);
285 #if DEVELOPMENT || DEBUG
299 _os_log_to_log_internal(os_log_t oslog
, os_log_type_t type
,
300 const char *format
, va_list args
, void *addr
, void *dso
)
302 struct os_log_buffer_context_s context
;
303 unsigned char buffer_data
[OS_LOG_BUFFER_MAX_SIZE
] __attribute__((aligned(8)));
304 os_log_buffer_t buffer
= (os_log_buffer_t
)buffer_data
;
305 uint8_t pubdata
[OS_LOG_BUFFER_MAX_SIZE
];
312 #if FIREHOSE_USES_SHARED_CACHE
313 dso
= (void *) segLOWESTTEXT
;
314 #else /* FIREHOSE_USES_SHARED_CACHE */
316 dso
= (void *) OSKextKextForAddress(format
);
322 if (!_os_trace_addr_in_text_segment(dso
, format
)) {
326 void *dso_addr
= (void *) OSKextKextForAddress(addr
);
327 if (dso
!= dso_addr
) {
330 #endif /* FIREHOSE_USES_SHARED_CACHE */
332 memset(&context
, 0, sizeof(context
));
333 memset(buffer
, 0, OS_LOG_BUFFER_MAX_SIZE
);
335 context
.shimmed
= true;
336 context
.buffer
= buffer
;
337 context
.content_sz
= OS_LOG_BUFFER_MAX_SIZE
- sizeof(*buffer
);
338 context
.pubdata
= pubdata
;
339 context
.pubdata_sz
= sizeof(pubdata
);
341 va_copy(args_copy
, args
);
343 (void)hw_atomic_add(&oslog_p_total_msgcount
, 1);
344 if (_os_log_encode(format
, args_copy
, 0, &context
)) {
345 _os_log_actual(oslog
, type
, format
, dso
, addr
, &context
);
347 (void)hw_atomic_add(&oslog_p_error_count
, 1);
354 _os_trace_write_location_for_address(uint8_t buf
[static sizeof(uint64_t)],
355 void *dso
, const void *address
, firehose_tracepoint_flags_t
*flags
)
357 #if FIREHOSE_USES_SHARED_CACHE
358 *flags
= _firehose_tracepoint_flags_pc_style_shared_cache
;
359 memcpy(buf
, (uint32_t[]){ (uintptr_t)address
- (uintptr_t)dso
},
361 return sizeof(uint32_t);
363 #else /* FIREHOSE_USES_SHARED_CACHE */
364 kernel_mach_header_t
*mh
= dso
;
366 if (mh
->filetype
== MH_EXECUTE
) {
367 *flags
= _firehose_tracepoint_flags_pc_style_main_exe
;
369 memcpy(buf
, (uint32_t[]){ (uintptr_t)address
- (uintptr_t)dso
},
371 return sizeof(uint32_t);
373 *flags
= _firehose_tracepoint_flags_pc_style_absolute
;
374 memcpy(buf
, (uintptr_t[]){ VM_KERNEL_UNSLIDE(address
) }, sizeof(uintptr_t));
376 return 6; // 48 bits are enough
378 return sizeof(uintptr_t);
381 #endif /* !FIREHOSE_USES_SHARED_CACHE */
387 _os_log_buffer_pack(uint8_t *buffdata
, size_t buffdata_sz
,
388 os_log_buffer_context_t ctx
)
390 os_log_buffer_t buffer
= ctx
->buffer
;
391 size_t buffer_sz
= sizeof(*ctx
->buffer
) + ctx
->content_sz
;
392 size_t total_sz
= buffer_sz
+ ctx
->pubdata_sz
;
394 if (total_sz
> buffdata_sz
) {
398 memcpy(buffdata
, buffer
, buffer_sz
);
399 memcpy(&buffdata
[buffer_sz
], ctx
->pubdata
, ctx
->pubdata_sz
);
404 _os_log_actual(os_log_t oslog __unused
, os_log_type_t type
, const char *format
,
405 void *dso
, void *addr
, os_log_buffer_context_t context
)
407 firehose_stream_t stream
;
408 firehose_tracepoint_flags_t flags
= 0;
409 firehose_tracepoint_id_u trace_id
;
410 uint8_t buffdata
[OS_LOG_BUFFER_MAX_SIZE
];
411 size_t addr_len
= 0, buffdata_sz
;
415 // dso == the start of the binary that was loaded
416 addr_len
= _os_trace_write_location_for_address(buffdata
, dso
, addr
, &flags
);
417 buffdata_sz
= _os_log_buffer_pack(buffdata
+ addr_len
,
418 sizeof(buffdata
) - addr_len
, context
);
419 if (buffdata_sz
== 0) {
422 buffdata_sz
+= addr_len
;
424 timestamp
= firehose_tracepoint_time(firehose_activity_flags_default
);
425 thread_id
= thread_tid(current_thread());
427 // create trace_id after we've set additional flags
428 trace_id
.ftid_value
= FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_log
,
429 type
, flags
, _os_trace_offset(dso
, format
, flags
));
432 firehose_debug_trace(stream
, trace_id
.ftid_value
, timestamp
,
433 format
, buffdata
, buffdata_sz
);
435 if (type
== OS_LOG_TYPE_INFO
|| type
== OS_LOG_TYPE_DEBUG
) {
436 stream
= firehose_stream_memory
;
438 stream
= firehose_stream_persist
;
440 _firehose_trace(stream
, trace_id
, timestamp
, buffdata
, buffdata_sz
);
443 static inline firehose_tracepoint_id_t
444 _firehose_trace(firehose_stream_t stream
, firehose_tracepoint_id_u ftid
,
445 uint64_t stamp
, const void *pubdata
, size_t publen
)
447 const uint16_t ft_size
= offsetof(struct firehose_tracepoint_s
, ft_data
);
448 const size_t _firehose_chunk_payload_size
=
449 sizeof(((struct firehose_chunk_s
*)0)->fc_data
);
451 firehose_tracepoint_t ft
;
453 if (slowpath(ft_size
+ publen
> _firehose_chunk_payload_size
)) {
454 // We'll need to have some handling here. For now - return 0
455 (void)hw_atomic_add(&oslog_p_error_count
, 1);
459 if (oslog_stream_open
&& (stream
!= firehose_stream_metadata
)) {
461 if (!oslog_stream_open
) {
466 oslog_s_total_msgcount
++;
467 oslog_streamwrite_locked(ftid
, stamp
, pubdata
, publen
);
469 oslog_streamwakeup();
473 ft
= __firehose_buffer_tracepoint_reserve(stamp
, stream
, (uint16_t)publen
, 0, NULL
);
475 if (oslog_boot_done
) {
476 if (stream
== firehose_stream_metadata
) {
477 (void)hw_atomic_add(&oslog_p_metadata_dropped_msgcount
, 1);
479 // If we run out of space in the persistence buffer we're
480 // dropping the message.
481 (void)hw_atomic_add(&oslog_p_dropped_msgcount
, 1);
485 firehose_chunk_t fbc
= firehose_boot_chunk
;
488 //only stream available during boot is persist
489 offset
= firehose_chunk_tracepoint_try_reserve(fbc
, stamp
,
490 firehose_stream_persist
, 0, publen
, 0, NULL
);
492 (void)hw_atomic_add(&oslog_p_boot_dropped_msgcount
, 1);
496 ft
= firehose_chunk_tracepoint_begin(fbc
, stamp
, publen
,
497 thread_tid(current_thread()), offset
);
498 memcpy(ft
->ft_data
, pubdata
, publen
);
499 firehose_chunk_tracepoint_end(fbc
, ft
, ftid
);
500 (void)hw_atomic_add(&oslog_p_saved_msgcount
, 1);
501 return ftid
.ftid_value
;
503 if (!oslog_boot_done
) {
504 oslog_boot_done
= true;
506 memcpy(ft
->ft_data
, pubdata
, publen
);
508 __firehose_buffer_tracepoint_flush(ft
, ftid
);
509 if (stream
== firehose_stream_metadata
) {
510 (void)hw_atomic_add(&oslog_p_metadata_saved_msgcount
, 1);
512 (void)hw_atomic_add(&oslog_p_saved_msgcount
, 1);
514 return ftid
.ftid_value
;
517 static oslog_stream_buf_entry_t
518 oslog_stream_create_buf_entry(oslog_stream_link_type_t type
, firehose_tracepoint_id_u ftid
,
519 uint64_t stamp
, const void* pubdata
, size_t publen
)
521 oslog_stream_buf_entry_t m_entry
= NULL
;
522 firehose_tracepoint_t ft
= NULL
;
523 size_t m_entry_len
= 0;
529 m_entry_len
= sizeof(struct oslog_stream_buf_entry_s
) +
530 sizeof(struct firehose_tracepoint_s
) + publen
;
531 m_entry
= (oslog_stream_buf_entry_t
) kalloc(m_entry_len
);
536 m_entry
->type
= type
;
537 m_entry
->timestamp
= stamp
;
538 m_entry
->size
= sizeof(struct firehose_tracepoint_s
) + publen
;
540 ft
= m_entry
->metadata
;
541 ft
->ft_thread
= thread_tid(current_thread());
542 ft
->ft_id
.ftid_value
= ftid
.ftid_value
;
543 ft
->ft_length
= publen
;
544 memcpy(ft
->ft_data
, pubdata
, publen
);
551 firehose_trace_metadata(firehose_stream_t stream
, firehose_tracepoint_id_u ftid
,
552 uint64_t stamp
, const void *pubdata
, size_t publen
)
554 oslog_stream_buf_entry_t m_entry
= NULL
;
556 // If streaming mode is not on, only log the metadata
557 // in the persistence buffer
560 if (!oslog_stream_open
) {
566 // Setup and write the stream metadata entry
567 m_entry
= oslog_stream_create_buf_entry(oslog_stream_link_type_metadata
, ftid
,
568 stamp
, pubdata
, publen
);
570 (void)hw_atomic_add(&oslog_s_error_count
, 1);
575 if (!oslog_stream_open
) {
577 kfree(m_entry
, sizeof(struct oslog_stream_buf_entry_s
) +
578 sizeof(struct firehose_tracepoint_s
) + publen
);
581 oslog_s_metadata_msgcount
++;
582 oslog_streamwrite_metadata_locked(m_entry
);
586 _firehose_trace(stream
, ftid
, stamp
, pubdata
, publen
);
590 firehose_tracepoint_id_t
591 firehose_debug_trace(firehose_stream_t stream
, firehose_tracepoint_id_t trace_id
,
592 uint64_t timestamp
, const char *format
, const void *pubdata
, size_t publen
)
594 kprintf("[os_log stream 0x%x trace_id 0x%llx timestamp %llu format '%s' data %p len %lu]\n",
595 (unsigned int)stream
, (unsigned long long)trace_id
, timestamp
,
596 format
, pubdata
, publen
);
598 const unsigned char *cdata
= (const unsigned char *)pubdata
;
599 for (i
= 0; i
< publen
; i
+= 8) {
600 kprintf(">oslog 0x%08x: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
602 (i
+ 0) < publen
? cdata
[i
+ 0] : 0,
603 (i
+ 1) < publen
? cdata
[i
+ 1] : 0,
604 (i
+ 2) < publen
? cdata
[i
+ 2] : 0,
605 (i
+ 3) < publen
? cdata
[i
+ 3] : 0,
606 (i
+ 4) < publen
? cdata
[i
+ 4] : 0,
607 (i
+ 5) < publen
? cdata
[i
+ 5] : 0,
608 (i
+ 6) < publen
? cdata
[i
+ 6] : 0,
609 (i
+ 7) < publen
? cdata
[i
+ 7] : 0
616 __firehose_buffer_push_to_logd(firehose_buffer_t fb __unused
, bool for_io __unused
)
623 __firehose_allocate(vm_offset_t
*addr
, vm_size_t size __unused
)
625 firehose_chunk_t kernel_buffer
= (firehose_chunk_t
)kernel_firehose_addr
;
627 if (kernel_firehose_addr
) {
628 *addr
= kernel_firehose_addr
;
633 // Now that we are done adding logs to this chunk, set the number of writers to 0
634 // Without this, logd won't flush when the page is full
635 firehose_boot_chunk
->fc_pos
.fcp_refcnt
= 0;
636 memcpy(&kernel_buffer
[FIREHOSE_BUFFER_KERNEL_CHUNK_COUNT
- 1], (const void *)firehose_boot_chunk
, FIREHOSE_CHUNK_SIZE
);
639 // There isnt a lock held in this case.
641 __firehose_critical_region_enter(void)
643 disable_preemption();
648 __firehose_critical_region_leave(void)
654 #ifdef CONFIG_XNUPOST
656 #include <tests/xnupost.h>
657 #define TESTOSLOGFMT(fn_name) "%u^%llu/%llu^kernel^0^test^" fn_name
658 #define TESTOSLOGPFX "TESTLOG:%u#"
659 #define TESTOSLOG(fn_name) TESTOSLOGPFX TESTOSLOGFMT(fn_name "#")
661 extern u_int32_t
RandomULong(void);
662 extern uint32_t find_pattern_in_buffer(char * pattern
, uint32_t len
, int expected_count
);
663 void test_oslog_default_helper(uint32_t uniqid
, uint64_t count
);
664 void test_oslog_info_helper(uint32_t uniqid
, uint64_t count
);
665 void test_oslog_debug_helper(uint32_t uniqid
, uint64_t count
);
666 void test_oslog_error_helper(uint32_t uniqid
, uint64_t count
);
667 void test_oslog_fault_helper(uint32_t uniqid
, uint64_t count
);
668 void _test_log_loop(void * arg __unused
, wait_result_t wres __unused
);
669 void test_oslog_handleOSLogCtl(int32_t * in
, int32_t * out
, int32_t len
);
670 kern_return_t
test_stresslog_dropmsg(uint32_t uniqid
);
672 kern_return_t
test_os_log(void);
673 kern_return_t
test_os_log_parallel(void);
675 #define GENOSLOGHELPER(fname, ident, callout_f) \
676 void fname(uint32_t uniqid, uint64_t count) \
678 int32_t datalen = 0; \
679 uint32_t checksum = 0; \
680 char databuffer[256]; \
681 T_LOG("Doing os_log of %llu TESTLOG msgs for fn " ident, count); \
682 for (uint64_t i = 0; i < count; i++) \
684 datalen = snprintf(databuffer, sizeof(databuffer), TESTOSLOGFMT(ident), uniqid, i + 1, count); \
685 checksum = crc32(0, databuffer, datalen); \
686 callout_f(OS_LOG_DEFAULT, TESTOSLOG(ident), checksum, uniqid, i + 1, count); \
687 /*T_LOG(TESTOSLOG(ident), checksum, uniqid, i + 1, count);*/ \
691 GENOSLOGHELPER(test_oslog_info_helper
, "oslog_info_helper", os_log_info
);
692 GENOSLOGHELPER(test_oslog_fault_helper
, "oslog_fault_helper", os_log_fault
);
693 GENOSLOGHELPER(test_oslog_debug_helper
, "oslog_debug_helper", os_log_debug
);
694 GENOSLOGHELPER(test_oslog_error_helper
, "oslog_error_helper", os_log_error
);
695 GENOSLOGHELPER(test_oslog_default_helper
, "oslog_default_helper", os_log
);
700 char databuffer
[256];
701 uint32_t uniqid
= RandomULong();
702 uint32_t match_count
= 0;
703 uint32_t checksum
= 0;
704 uint32_t total_msg
= 0;
705 uint32_t saved_msg
= 0;
706 uint32_t dropped_msg
= 0;
708 uint64_t a
= mach_absolute_time();
710 uint64_t total_seqno
= 2;
712 os_log_t log_handle
= os_log_create("com.apple.xnu.test.t1", "kpost");
714 T_ASSERT_EQ_PTR(&_os_log_default
, log_handle
, "os_log_create returns valid value.");
715 T_ASSERT_EQ_INT(TRUE
, os_log_info_enabled(log_handle
), "os_log_info is enabled");
716 T_ASSERT_EQ_INT(TRUE
, os_log_debug_enabled(log_handle
), "os_log_debug is enabled");
717 T_ASSERT_EQ_PTR(&_os_log_default
, OS_LOG_DEFAULT
, "ensure OS_LOG_DEFAULT is _os_log_default");
719 total_msg
= oslog_p_total_msgcount
;
720 saved_msg
= oslog_p_saved_msgcount
;
721 dropped_msg
= oslog_p_dropped_msgcount
;
722 T_LOG("oslog internal counters total %u , saved %u, dropped %u", total_msg
, saved_msg
, dropped_msg
);
724 T_LOG("Validating with uniqid %u u64 %llu", uniqid
, a
);
725 T_ASSERT_NE_UINT(0, uniqid
, "random number should not be zero");
726 T_ASSERT_NE_ULLONG(0, a
, "absolute time should not be zero");
728 datalen
= snprintf(databuffer
, sizeof(databuffer
), TESTOSLOGFMT("printf_only"), uniqid
, seqno
, total_seqno
);
729 checksum
= crc32(0, databuffer
, datalen
);
730 printf(TESTOSLOG("printf_only") "mat%llu\n", checksum
, uniqid
, seqno
, total_seqno
, a
);
733 datalen
= snprintf(databuffer
, sizeof(databuffer
), TESTOSLOGFMT("printf_only"), uniqid
, seqno
, total_seqno
);
734 checksum
= crc32(0, databuffer
, datalen
);
735 printf(TESTOSLOG("printf_only") "mat%llu\n", checksum
, uniqid
, seqno
, total_seqno
, a
);
737 datalen
= snprintf(databuffer
, sizeof(databuffer
), "kernel^0^test^printf_only#mat%llu", a
);
738 match_count
= find_pattern_in_buffer(databuffer
, datalen
, total_seqno
);
739 T_EXPECT_EQ_UINT(match_count
, 2, "verify printf_only goes to systemlog buffer");
741 uint32_t logging_config
= atm_get_diagnostic_config();
742 T_LOG("checking atm_diagnostic_config 0x%X", logging_config
);
744 if ((logging_config
& ATM_TRACE_OFF
) || (logging_config
& ATM_TRACE_DISABLE
)) {
745 T_LOG("ATM_TRACE_OFF / ATM_TRACE_DISABLE is set. Would not see oslog messages. skipping the rest of test.");
749 /* for enabled logging printfs should be saved in oslog as well */
750 T_EXPECT_GE_UINT((oslog_p_total_msgcount
- total_msg
), 2, "atleast 2 msgs should be seen by oslog system");
752 a
= mach_absolute_time();
755 total_msg
= oslog_p_total_msgcount
;
756 saved_msg
= oslog_p_saved_msgcount
;
757 dropped_msg
= oslog_p_dropped_msgcount
;
758 datalen
= snprintf(databuffer
, sizeof(databuffer
), TESTOSLOGFMT("oslog_info"), uniqid
, seqno
, total_seqno
);
759 checksum
= crc32(0, databuffer
, datalen
);
760 os_log_info(log_handle
, TESTOSLOG("oslog_info") "mat%llu", checksum
, uniqid
, seqno
, total_seqno
, a
);
761 T_EXPECT_GE_UINT((oslog_p_total_msgcount
- total_msg
), 1, "total message count in buffer");
763 datalen
= snprintf(databuffer
, sizeof(databuffer
), "kernel^0^test^oslog_info#mat%llu", a
);
764 match_count
= find_pattern_in_buffer(databuffer
, datalen
, total_seqno
);
765 T_EXPECT_EQ_UINT(match_count
, 1, "verify oslog_info does not go to systemlog buffer");
767 total_msg
= oslog_p_total_msgcount
;
768 test_oslog_info_helper(uniqid
, 10);
769 T_EXPECT_GE_UINT(oslog_p_total_msgcount
- total_msg
, 10, "test_oslog_info_helper: Should have seen 10 msgs");
771 total_msg
= oslog_p_total_msgcount
;
772 test_oslog_debug_helper(uniqid
, 10);
773 T_EXPECT_GE_UINT(oslog_p_total_msgcount
- total_msg
, 10, "test_oslog_debug_helper:Should have seen 10 msgs");
775 total_msg
= oslog_p_total_msgcount
;
776 test_oslog_error_helper(uniqid
, 10);
777 T_EXPECT_GE_UINT(oslog_p_total_msgcount
- total_msg
, 10, "test_oslog_error_helper:Should have seen 10 msgs");
779 total_msg
= oslog_p_total_msgcount
;
780 test_oslog_default_helper(uniqid
, 10);
781 T_EXPECT_GE_UINT(oslog_p_total_msgcount
- total_msg
, 10, "test_oslog_default_helper:Should have seen 10 msgs");
783 total_msg
= oslog_p_total_msgcount
;
784 test_oslog_fault_helper(uniqid
, 10);
785 T_EXPECT_GE_UINT(oslog_p_total_msgcount
- total_msg
, 10, "test_oslog_fault_helper:Should have seen 10 msgs");
787 T_LOG("oslog internal counters total %u , saved %u, dropped %u", oslog_p_total_msgcount
, oslog_p_saved_msgcount
,
788 oslog_p_dropped_msgcount
);
793 static uint32_t _test_log_loop_count
= 0;
795 _test_log_loop(void * arg __unused
, wait_result_t wres __unused
)
797 uint32_t uniqid
= RandomULong();
798 test_oslog_debug_helper(uniqid
, 100);
799 (void)hw_atomic_add(&_test_log_loop_count
, 100);
803 test_os_log_parallel(void)
807 uint32_t uniqid
= RandomULong();
809 printf("oslog internal counters total %u , saved %u, dropped %u", oslog_p_total_msgcount
, oslog_p_saved_msgcount
,
810 oslog_p_dropped_msgcount
);
812 kr
= kernel_thread_start(_test_log_loop
, NULL
, &thread
[0]);
813 T_ASSERT_EQ_INT(kr
, KERN_SUCCESS
, "kernel_thread_start returned successfully");
815 kr
= kernel_thread_start(_test_log_loop
, NULL
, &thread
[1]);
816 T_ASSERT_EQ_INT(kr
, KERN_SUCCESS
, "kernel_thread_start returned successfully");
818 test_oslog_info_helper(uniqid
, 100);
820 /* wait until other thread has also finished */
821 while (_test_log_loop_count
< 200) {
825 thread_deallocate(thread
[0]);
826 thread_deallocate(thread
[1]);
828 T_LOG("oslog internal counters total %u , saved %u, dropped %u", oslog_p_total_msgcount
, oslog_p_saved_msgcount
,
829 oslog_p_dropped_msgcount
);
830 T_PASS("parallel_logging tests is now complete");
836 test_oslog_handleOSLogCtl(int32_t * in
, int32_t * out
, int32_t len
)
838 if (!in
|| !out
|| len
!= 4) {
844 /* send out counters */
845 out
[1] = oslog_p_total_msgcount
;
846 out
[2] = oslog_p_saved_msgcount
;
847 out
[3] = oslog_p_dropped_msgcount
;
848 out
[0] = KERN_SUCCESS
;
853 /* mini stress run */
854 out
[0] = test_os_log_parallel();
860 out
[1] = RandomULong();
861 out
[0] = test_stresslog_dropmsg(out
[1]);
866 /* invoke log helpers */
867 uint32_t uniqid
= in
[3];
868 int32_t msgcount
= in
[2];
869 if (uniqid
== 0 || msgcount
== 0) {
870 out
[0] = KERN_INVALID_VALUE
;
875 case OS_LOG_TYPE_INFO
: test_oslog_info_helper(uniqid
, msgcount
); break;
876 case OS_LOG_TYPE_DEBUG
: test_oslog_debug_helper(uniqid
, msgcount
); break;
877 case OS_LOG_TYPE_ERROR
: test_oslog_error_helper(uniqid
, msgcount
); break;
878 case OS_LOG_TYPE_FAULT
: test_oslog_fault_helper(uniqid
, msgcount
); break;
879 case OS_LOG_TYPE_DEFAULT
:
880 default: test_oslog_default_helper(uniqid
, msgcount
); break;
882 out
[0] = KERN_SUCCESS
;
888 out
[0] = KERN_INVALID_VALUE
;
896 test_stresslog_dropmsg(uint32_t uniqid
)
898 uint32_t total
, saved
, dropped
;
899 total
= oslog_p_total_msgcount
;
900 saved
= oslog_p_saved_msgcount
;
901 dropped
= oslog_p_dropped_msgcount
;
902 uniqid
= RandomULong();
903 test_oslog_debug_helper(uniqid
, 100);
904 while ((oslog_p_dropped_msgcount
- dropped
) == 0) {
905 test_oslog_debug_helper(uniqid
, 100);
907 printf("test_stresslog_dropmsg: logged %u msgs, saved %u and caused a drop of %u msgs. \n", oslog_p_total_msgcount
- total
,
908 oslog_p_saved_msgcount
- saved
, oslog_p_dropped_msgcount
- dropped
);