/* * Save the context of an error report. */ void kmemcheck_error_save(enum kmemcheck_shadow state, unsigned long address, unsigned int size, struct pt_regs *regs) { static unsigned long prev_ip; struct kmemcheck_error *e; void *shadow_copy; void *memory_copy; /* Don't report several adjacent errors from the same EIP. */ if (regs->ip == prev_ip) return; prev_ip = regs->ip; e = error_next_wr(); if (!e) return; e->type = KMEMCHECK_ERROR_INVALID_ACCESS; e->state = state; e->address = address; e->size = size; /* Save regs */ memcpy(&e->regs, regs, sizeof(*regs)); /* Save stack trace */ e->trace.nr_entries = 0; e->trace.entries = e->trace_entries; e->trace.max_entries = ARRAY_SIZE(e->trace_entries); e->trace.skip = 0; save_stack_trace_regs(&e->trace, regs); /* Round address down to nearest 16 bytes */ shadow_copy = kmemcheck_shadow_lookup(address & ~(SHADOW_COPY_SIZE - 1)); BUG_ON(!shadow_copy); memcpy(e->shadow_copy, shadow_copy, SHADOW_COPY_SIZE); kmemcheck_show_addr(address); memory_copy = (void *) (address & ~(SHADOW_COPY_SIZE - 1)); memcpy(e->memory_copy, memory_copy, SHADOW_COPY_SIZE); kmemcheck_hide_addr(address); tasklet_hi_schedule_first(&kmemcheck_tasklet); }
/** * stack_trace_save - Save a stack trace into a storage array * @store: Pointer to storage array * @size: Size of the storage array * @skipnr: Number of entries to skip at the start of the stack trace * * Return: Number of trace entries stored */ unsigned int stack_trace_save(unsigned long *store, unsigned int size, unsigned int skipnr) { struct stack_trace trace = { .entries = store, .max_entries = size, .skip = skipnr + 1, }; save_stack_trace(&trace); return trace.nr_entries; } EXPORT_SYMBOL_GPL(stack_trace_save); /** * stack_trace_save_tsk - Save a task stack trace into a storage array * @task: The task to examine * @store: Pointer to storage array * @size: Size of the storage array * @skipnr: Number of entries to skip at the start of the stack trace * * Return: Number of trace entries stored */ unsigned int stack_trace_save_tsk(struct task_struct *task, unsigned long *store, unsigned int size, unsigned int skipnr) { struct stack_trace trace = { .entries = store, .max_entries = size, .skip = skipnr + 1, }; save_stack_trace_tsk(task, &trace); return trace.nr_entries; } /** * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array * @regs: Pointer to pt_regs to examine * @store: Pointer to storage array * @size: Size of the storage array * @skipnr: Number of entries to skip at the start of the stack trace * * Return: Number of trace entries stored */ unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store, unsigned int size, unsigned int skipnr) { struct stack_trace trace = { .entries = store, .max_entries = size, .skip = skipnr, }; save_stack_trace_regs(regs, &trace); return trace.nr_entries; } #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE /** * stack_trace_save_tsk_reliable - Save task stack with verification * @tsk: Pointer to the task to examine * @store: Pointer to storage array * @size: Size of the storage array * * Return: An error if it detects any unreliable features of the * stack. Otherwise it guarantees that the stack trace is * reliable and returns the number of entries stored. * * If the task is not 'current', the caller *must* ensure the task is inactive. */ int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store, unsigned int size) { struct stack_trace trace = { .entries = store, .max_entries = size, }; int ret = save_stack_trace_tsk_reliable(tsk, &trace); return ret ? ret : trace.nr_entries; } #endif #ifdef CONFIG_USER_STACKTRACE_SUPPORT /** * stack_trace_save_user - Save a user space stack trace into a storage array * @store: Pointer to storage array * @size: Size of the storage array * * Return: Number of trace entries stored */ unsigned int stack_trace_save_user(unsigned long *store, unsigned int size) { struct stack_trace trace = { .entries = store, .max_entries = size, }; save_stack_trace_user(&trace); return trace.nr_entries; }