in Source/PLCrashLogWriter.m [935:1019]
static size_t plcrash_writer_write_thread (plcrash_async_file_t *file,
plcrash_log_writer_t *writer,
task_t task,
thread_t thread,
uint32_t thread_number,
plcrash_async_thread_state_t *thread_ctx,
plcrash_async_image_list_t *image_list,
plcrash_async_symbol_cache_t *findContext,
bool crashed)
{
size_t rv = 0;
plframe_cursor_t cursor;
plframe_error_t ferr;
/* A context must be supplied when walking the current thread */
PLCF_ASSERT(task != mach_task_self() || thread_ctx != NULL || thread != pl_mach_thread_self());
/* Write the required elements first; fatal errors may occur below, in which case we need to have
* written out required elements before returning. */
{
/* Write the thread ID */
rv += plcrash_writer_pack(file, PLCRASH_PROTO_THREAD_THREAD_NUMBER_ID, PLPROTOBUF_C_TYPE_UINT32, &thread_number);
/* Note crashed status */
rv += plcrash_writer_pack(file, PLCRASH_PROTO_THREAD_CRASHED_ID, PLPROTOBUF_C_TYPE_BOOL, &crashed);
}
/* Write out the stack frames. */
{
/* Set up the frame cursor. */
{
/* Use the provided context if available, otherwise initialize a new thread context
* from the target thread's state. */
plcrash_async_thread_state_t cursor_thr_state;
if (thread_ctx) {
cursor_thr_state = *thread_ctx;
} else {
plcrash_async_thread_state_mach_thread_init(&cursor_thr_state, thread);
}
/* Initialize the cursor */
ferr = plframe_cursor_init(&cursor, task, &cursor_thr_state, image_list);
if (ferr != PLFRAME_ESUCCESS) {
PLCF_DEBUG("An error occured initializing the frame cursor: %s", plframe_strerror(ferr));
return rv;
}
}
/* Walk the stack, limiting the total number of frames that are output. */
uint32_t frame_count = 0;
while ((ferr = plframe_cursor_next(&cursor)) == PLFRAME_ESUCCESS && frame_count < MAX_THREAD_FRAMES) {
uint32_t frame_size;
/* On the first frame, dump registers for the crashed thread */
if (frame_count == 0 && crashed) {
rv += plcrash_writer_write_thread_registers(file, task, &cursor);
}
/* Fetch the PC value */
plcrash_greg_t pc = 0;
if ((ferr = plframe_cursor_get_reg(&cursor, PLCRASH_REG_IP, &pc)) != PLFRAME_ESUCCESS) {
PLCF_DEBUG("Could not retrieve frame PC register: %s", plframe_strerror(ferr));
break;
}
/* Determine the size */
frame_size = (uint32_t) plcrash_writer_write_thread_frame(NULL, writer, pc, image_list, findContext);
rv += plcrash_writer_pack(file, PLCRASH_PROTO_THREAD_FRAMES_ID, PLPROTOBUF_C_TYPE_MESSAGE, &frame_size);
rv += plcrash_writer_write_thread_frame(file, writer, pc, image_list, findContext);
frame_count++;
}
/* Did we reach the end successfully? */
if (ferr != PLFRAME_ENOFRAME) {
/* This is non-fatal, and in some circumstances -could- be caused by reaching the end of the stack if the
* final frame pointer is not NULL. */
PLCF_DEBUG("Terminated stack walking early: %s", plframe_strerror(ferr));
}
}
plframe_cursor_free(&cursor);
return rv;
}