/** * Write all bytes from @a data to the file buffer. Returns true on success, * or false if an error occurs. */ bool plcrash_async_file_write (plcrash_async_file_t *file, const void *data, size_t len) { /* Check and update output limit */ if (file->limit_bytes != 0 && len + file->total_bytes > file->limit_bytes) { return false; } else if (file->limit_bytes != 0) { file->total_bytes += len; } /* Check if the buffer will fill */ if (file->buflen + len > sizeof(file->buffer)) { /* Flush the buffer */ if (writen(file->fd, file->buffer, file->buflen) < 0) { return false; } file->buflen = 0; } /* Check if the new data fits within the buffer, if so, buffer it */ if (len + file->buflen <= sizeof(file->buffer)) { plcrash_async_memcpy(file->buffer + file->buflen, data, len); file->buflen += len; return true; } else { /* Won't fit in the buffer, just write it */ if (writen(file->fd, data, len) < 0) { return false; } return true; } }
/** * Initialize the @a thread_state using the provided context. * * @param thread_state The thread state to be initialized. * @param uap The context to use for cursor initialization. * * All registers will be marked as available. */ void plcrash_async_thread_state_mcontext_init (plcrash_async_thread_state_t *thread_state, pl_mcontext_t *mctx) { /* * Copy in the thread state. Unlike the mach thread variants, mcontext_t may only represent * the thread state of the host process, and we may assume that the compilation target matches the mcontext_t * thread type. */ #if defined(PLCRASH_ASYNC_THREAD_ARM_SUPPORT) && defined(__LP64__) plcrash_async_thread_state_init(thread_state, CPU_TYPE_ARM64); /* Sanity check. */ PLCF_ASSERT(sizeof(mctx->__ss) == sizeof(thread_state->arm_state.thread.ts_64)); plcrash_async_memcpy(&thread_state->arm_state.thread.ts_64, &mctx->__ss, sizeof(thread_state->arm_state.thread.ts_64)); #elif defined(PLCRASH_ASYNC_THREAD_ARM_SUPPORT) plcrash_async_thread_state_init(thread_state, CPU_TYPE_ARM); /* Sanity check. */ PLCF_ASSERT(sizeof(mctx->__ss) == sizeof(thread_state->arm_state.thread.ts_32)); plcrash_async_memcpy(&thread_state->arm_state.thread.ts_32, &mctx->__ss, sizeof(thread_state->arm_state.thread.ts_32)); #elif defined(PLCRASH_ASYNC_THREAD_X86_SUPPORT) && defined(__LP64__) plcrash_async_thread_state_init(thread_state, CPU_TYPE_X86_64); /* Sanity check. */ PLCF_ASSERT(sizeof(mctx->__ss) == sizeof(thread_state->x86_state.thread.uts.ts64)); PLCF_ASSERT(sizeof(mctx->__es) == sizeof(thread_state->x86_state.exception.ues.es64)); plcrash_async_memcpy(&thread_state->x86_state.thread.uts.ts64, &mctx->__ss, sizeof(thread_state->x86_state.thread.uts.ts64)); plcrash_async_memcpy(&thread_state->x86_state.exception.ues.es64, &mctx->__es, sizeof(thread_state->x86_state.exception.ues.es64)); #elif defined(PLCRASH_ASYNC_THREAD_X86_SUPPORT) plcrash_async_thread_state_init(thread_state, CPU_TYPE_X86); /* Sanity check. */ PLCF_ASSERT(sizeof(mctx->__ss) == sizeof(thread_state->x86_state.thread.uts.ts32)); PLCF_ASSERT(sizeof(mctx->__es) == sizeof(thread_state->x86_state.exception.ues.es32)); plcrash_async_memcpy(&thread_state->x86_state.thread.uts.ts32, &mctx->__ss, sizeof(thread_state->x86_state.thread.uts.ts32)); plcrash_async_memcpy(&thread_state->x86_state.exception.ues.es32, &mctx->__es, sizeof(thread_state->x86_state.exception.ues.es32)); #else #error Add platform support #endif /* Mark all registers as available */ memset(&thread_state->valid_regs, 0xFF, sizeof(thread_state->valid_regs)); }
/** * Copy thread state @a source to @a dest. * * @param dest The destination to which the thread state will be copied. * @param source The thread state to be copied. * * @note If @a dest and @a source overlap, behavior is undefined. */ void plcrash_async_thread_state_copy (plcrash_async_thread_state_t *dest, const plcrash_async_thread_state_t *source) { plcrash_async_memcpy(dest, source, sizeof(*dest)); }