in Source/PLCrashLogWriter.m [1228:1429]
plcrash_error_t plcrash_log_writer_write (plcrash_log_writer_t *writer,
thread_t crashed_thread,
plcrash_async_image_list_t *image_list,
plcrash_async_file_t *file,
plcrash_log_signal_info_t *siginfo,
plcrash_async_thread_state_t *current_state)
{
thread_act_array_t threads;
mach_msg_type_number_t thread_count;
/* A context must be supplied if the current thread is marked as the crashed thread; otherwise,
* the thread's stack can not be safely walked. */
PLCF_ASSERT(pl_mach_thread_self() != crashed_thread || current_state != NULL);
/* Get a list of all threads */
if (task_threads(mach_task_self(), &threads, &thread_count) != KERN_SUCCESS) {
PLCF_DEBUG("Fetching thread list failed");
thread_count = 0;
}
/* Suspend all but the current thread. */
for (mach_msg_type_number_t i = 0; i < thread_count; i++) {
if (threads[i] != pl_mach_thread_self())
thread_suspend(threads[i]);
}
/* Set up a symbol-finding context. */
plcrash_async_symbol_cache_t findContext;
plcrash_error_t err = plcrash_async_symbol_cache_init(&findContext);
/* Abort if it failed, although that should never actually happen, ever. */
if (err != PLCRASH_ESUCCESS)
return err;
/* Write the file header */
{
uint8_t version = PLCRASH_REPORT_FILE_VERSION;
/* Write the magic string (with no trailing NULL) and the version number */
plcrash_async_file_write(file, PLCRASH_REPORT_FILE_MAGIC, strlen(PLCRASH_REPORT_FILE_MAGIC));
plcrash_async_file_write(file, &version, sizeof(version));
}
/* Report Info */
{
uint32_t size;
/* Determine size */
size = (uint32_t) plcrash_writer_write_report_info(NULL, writer);
/* Write message */
plcrash_writer_pack(file, PLCRASH_PROTO_REPORT_INFO_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_report_info(file, writer);
}
/* System Info */
{
time_t timestamp;
uint32_t size;
/* Must stay the same across both calls, so get the timestamp here */
if (time(×tamp) == (time_t)-1) {
PLCF_DEBUG("Failed to fetch timestamp: %s", strerror(errno));
timestamp = 0;
}
/* Determine size */
size = (uint32_t) plcrash_writer_write_system_info(NULL, writer, timestamp);
/* Write message */
plcrash_writer_pack(file, PLCRASH_PROTO_SYSTEM_INFO_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_system_info(file, writer, timestamp);
}
/* Machine Info */
{
uint32_t size;
/* Determine size */
size = (uint32_t) plcrash_writer_write_machine_info(NULL, writer);
/* Write message */
plcrash_writer_pack(file, PLCRASH_PROTO_MACHINE_INFO_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_machine_info(file, writer);
}
/* App info */
{
uint32_t size;
/* Determine size */
size = (uint32_t) plcrash_writer_write_app_info(NULL, &writer->application_info.app_identifier, &writer->application_info.app_version, &writer->application_info.app_marketing_version);
/* Write message */
plcrash_writer_pack(file, PLCRASH_PROTO_APP_INFO_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_app_info(file, &writer->application_info.app_identifier, &writer->application_info.app_version, &writer->application_info.app_marketing_version);
}
/* Process info */
{
uint32_t size;
/* Determine size */
size = (uint32_t) plcrash_writer_write_process_info(NULL, &writer->process_info.process_name, writer->process_info.process_id,
&writer->process_info.process_path, &writer->process_info.parent_process_name,
writer->process_info.parent_process_id, writer->process_info.native,
writer->process_info.start_time);
/* Write message */
plcrash_writer_pack(file, PLCRASH_PROTO_PROCESS_INFO_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_process_info(file, &writer->process_info.process_name, writer->process_info.process_id,
&writer->process_info.process_path, &writer->process_info.parent_process_name,
writer->process_info.parent_process_id, writer->process_info.native,
writer->process_info.start_time);
}
/* Threads */
uint32_t thread_number = 0;
for (mach_msg_type_number_t i = 0; i < thread_count; i++) {
thread_t thread = threads[i];
plcrash_async_thread_state_t *thr_ctx = NULL;
bool crashed = false;
uint32_t size;
/* If executing on the target thread, we need to a valid context to walk */
if (pl_mach_thread_self() == thread) {
/* Can't log a report for the current thread without a valid context. */
if (current_state == NULL)
continue;
thr_ctx = current_state;
}
/* Check if this is the crashed thread */
if (crashed_thread == thread) {
crashed = true;
}
/* Determine the size */
size = (uint32_t) plcrash_writer_write_thread(NULL, writer, mach_task_self(), thread, thread_number, thr_ctx, image_list, &findContext, crashed);
/* Write message */
plcrash_writer_pack(file, PLCRASH_PROTO_THREADS_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_thread(file, writer, mach_task_self(), thread, thread_number, thr_ctx, image_list, &findContext, crashed);
thread_number++;
}
/* Binary Images */
plcrash_async_image_list_set_reading(image_list, true);
plcrash_async_image_t *image = NULL;
while ((image = plcrash_async_image_list_next(image_list, image)) != NULL) {
uint32_t size;
/* Calculate the message size */
size = (uint32_t) plcrash_writer_write_binary_image(NULL, &image->macho_image);
plcrash_writer_pack(file, PLCRASH_PROTO_BINARY_IMAGES_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_binary_image(file, &image->macho_image);
}
plcrash_async_image_list_set_reading(image_list, false);
/* Exception */
if (writer->uncaught_exception.has_exception) {
uint32_t size;
/* Calculate the message size */
size = (uint32_t) plcrash_writer_write_exception(NULL, writer, image_list, &findContext);
plcrash_writer_pack(file, PLCRASH_PROTO_EXCEPTION_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_exception(file, writer, image_list, &findContext);
}
/* Signal */
{
uint32_t size;
/* Calculate the message size */
size = (uint32_t) plcrash_writer_write_signal(NULL, siginfo);
plcrash_writer_pack(file, PLCRASH_PROTO_SIGNAL_ID, PLPROTOBUF_C_TYPE_MESSAGE, &size);
plcrash_writer_write_signal(file, siginfo);
}
/* Custom data */
if (writer->custom_data.data) {
plcrash_writer_pack(file, PLCRASH_PROTO_CUSTOM_DATA_ID, PLPROTOBUF_C_TYPE_BYTES, &writer->custom_data);
}
plcrash_async_symbol_cache_free(&findContext);
/* Clean up the thread array */
for (mach_msg_type_number_t i = 0; i < thread_count; i++) {
if (threads[i] != pl_mach_thread_self())
thread_resume(threads[i]);
mach_port_deallocate(mach_task_self(), threads[i]);
}
vm_deallocate(mach_task_self(), (vm_address_t)threads, sizeof(thread_t) * thread_count);
return PLCRASH_ESUCCESS;
}