plframe_error_t plframe_cursor_next_with_readers()

in Source/PLCrashFrameWalker.c [134:177]


plframe_error_t plframe_cursor_next_with_readers (plframe_cursor_t *cursor, plframe_cursor_frame_reader_t *readers[], size_t reader_count) {
    /* The first frame is already available via existing thread state. */
    if (cursor->depth == 0) {
        cursor->depth++;
        return PLFRAME_ESUCCESS;
    }
    
    /* A previous frame is only available if we're on the second frame */
    plframe_stackframe_t *prev_frame = NULL;
    if (cursor->depth >= 2)
        prev_frame = &cursor->prev_frame;
    
    /* Read in the next frame using the first successful frame reader. */
    plframe_stackframe_t frame;
    plframe_error_t ferr = PLFRAME_EINVAL; // default return value if reader_count is 0.
    
    for (size_t i = 0; i < reader_count; i++) {
        ferr = readers[i](cursor->task, cursor->image_list, &cursor->frame, prev_frame, &frame);
        if (ferr == PLFRAME_ESUCCESS)
            break;
    }
    
    if (ferr != PLFRAME_ESUCCESS) {
        return ferr;
    }

    /* Check for completion */
    if (!plcrash_async_thread_state_has_reg(&frame.thread_state, PLCRASH_REG_IP)) {
        PLCF_DEBUG("Missing expected IP value in successfully read frame");
        return PLFRAME_ENOFRAME;
    }
    
    /* A pc within the NULL page is a terminating frame */
    plcrash_greg_t ip = plcrash_async_thread_state_get_reg(&frame.thread_state, PLCRASH_REG_IP);
    if (ip <= PAGE_SIZE)
        return PLFRAME_ENOFRAME;
    
    /* Save the newly fetched frame */
    cursor->prev_frame = cursor->frame;
    cursor->frame = frame;
    cursor->depth++;
    
    return PLFRAME_ESUCCESS;
}