xref: /linux/kernel/unwind/deferred.c (revision 5e32d0f15cc5c843a4115c4644d984d42524c794)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Deferred user space unwinding
4  */
5 #include <linux/kernel.h>
6 #include <linux/sched.h>
7 #include <linux/slab.h>
8 #include <linux/unwind_deferred.h>
9 
10 #define UNWIND_MAX_ENTRIES 512
11 
12 /**
13  * unwind_user_faultable - Produce a user stacktrace in faultable context
14  * @trace: The descriptor that will store the user stacktrace
15  *
16  * This must be called in a known faultable context (usually when entering
17  * or exiting user space). Depending on the available implementations
18  * the @trace will be loaded with the addresses of the user space stacktrace
19  * if it can be found.
20  *
21  * Return: 0 on success and negative on error
22  *         On success @trace will contain the user space stacktrace
23  */
24 int unwind_user_faultable(struct unwind_stacktrace *trace)
25 {
26 	struct unwind_task_info *info = &current->unwind_info;
27 
28 	/* Should always be called from faultable context */
29 	might_fault();
30 
31 	if (current->flags & PF_EXITING)
32 		return -EINVAL;
33 
34 	if (!info->entries) {
35 		info->entries = kmalloc_array(UNWIND_MAX_ENTRIES, sizeof(long),
36 					      GFP_KERNEL);
37 		if (!info->entries)
38 			return -ENOMEM;
39 	}
40 
41 	trace->nr = 0;
42 	trace->entries = info->entries;
43 	unwind_user(trace, UNWIND_MAX_ENTRIES);
44 
45 	return 0;
46 }
47 
48 void unwind_task_init(struct task_struct *task)
49 {
50 	struct unwind_task_info *info = &task->unwind_info;
51 
52 	memset(info, 0, sizeof(*info));
53 }
54 
55 void unwind_task_free(struct task_struct *task)
56 {
57 	struct unwind_task_info *info = &task->unwind_info;
58 
59 	kfree(info->entries);
60 }
61