|  | 
| 48 | 48 | #define CREATE_TRACE_POINTS | 
| 49 | 49 | #include <trace/events/syscalls.h> | 
| 50 | 50 | 
 | 
|  | 51 | +struct pt_regs_offset { | 
|  | 52 | +	const char *name; | 
|  | 53 | +	int offset; | 
|  | 54 | +}; | 
|  | 55 | + | 
|  | 56 | +#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} | 
|  | 57 | +#define REG_OFFSET_END {.name = NULL, .offset = 0} | 
|  | 58 | +#define GPR_OFFSET_NAME(r) \ | 
|  | 59 | +	{.name = "x" #r, .offset = offsetof(struct pt_regs, regs[r])} | 
|  | 60 | + | 
|  | 61 | +static const struct pt_regs_offset regoffset_table[] = { | 
|  | 62 | +	GPR_OFFSET_NAME(0), | 
|  | 63 | +	GPR_OFFSET_NAME(1), | 
|  | 64 | +	GPR_OFFSET_NAME(2), | 
|  | 65 | +	GPR_OFFSET_NAME(3), | 
|  | 66 | +	GPR_OFFSET_NAME(4), | 
|  | 67 | +	GPR_OFFSET_NAME(5), | 
|  | 68 | +	GPR_OFFSET_NAME(6), | 
|  | 69 | +	GPR_OFFSET_NAME(7), | 
|  | 70 | +	GPR_OFFSET_NAME(8), | 
|  | 71 | +	GPR_OFFSET_NAME(9), | 
|  | 72 | +	GPR_OFFSET_NAME(10), | 
|  | 73 | +	GPR_OFFSET_NAME(11), | 
|  | 74 | +	GPR_OFFSET_NAME(12), | 
|  | 75 | +	GPR_OFFSET_NAME(13), | 
|  | 76 | +	GPR_OFFSET_NAME(14), | 
|  | 77 | +	GPR_OFFSET_NAME(15), | 
|  | 78 | +	GPR_OFFSET_NAME(16), | 
|  | 79 | +	GPR_OFFSET_NAME(17), | 
|  | 80 | +	GPR_OFFSET_NAME(18), | 
|  | 81 | +	GPR_OFFSET_NAME(19), | 
|  | 82 | +	GPR_OFFSET_NAME(20), | 
|  | 83 | +	GPR_OFFSET_NAME(21), | 
|  | 84 | +	GPR_OFFSET_NAME(22), | 
|  | 85 | +	GPR_OFFSET_NAME(23), | 
|  | 86 | +	GPR_OFFSET_NAME(24), | 
|  | 87 | +	GPR_OFFSET_NAME(25), | 
|  | 88 | +	GPR_OFFSET_NAME(26), | 
|  | 89 | +	GPR_OFFSET_NAME(27), | 
|  | 90 | +	GPR_OFFSET_NAME(28), | 
|  | 91 | +	GPR_OFFSET_NAME(29), | 
|  | 92 | +	GPR_OFFSET_NAME(30), | 
|  | 93 | +	{.name = "lr", .offset = offsetof(struct pt_regs, regs[30])}, | 
|  | 94 | +	REG_OFFSET_NAME(sp), | 
|  | 95 | +	REG_OFFSET_NAME(pc), | 
|  | 96 | +	REG_OFFSET_NAME(pstate), | 
|  | 97 | +	REG_OFFSET_END, | 
|  | 98 | +}; | 
|  | 99 | + | 
|  | 100 | +/** | 
|  | 101 | + * regs_query_register_offset() - query register offset from its name | 
|  | 102 | + * @name:	the name of a register | 
|  | 103 | + * | 
|  | 104 | + * regs_query_register_offset() returns the offset of a register in struct | 
|  | 105 | + * pt_regs from its name. If the name is invalid, this returns -EINVAL; | 
|  | 106 | + */ | 
|  | 107 | +int regs_query_register_offset(const char *name) | 
|  | 108 | +{ | 
|  | 109 | +	const struct pt_regs_offset *roff; | 
|  | 110 | + | 
|  | 111 | +	for (roff = regoffset_table; roff->name != NULL; roff++) | 
|  | 112 | +		if (!strcmp(roff->name, name)) | 
|  | 113 | +			return roff->offset; | 
|  | 114 | +	return -EINVAL; | 
|  | 115 | +} | 
|  | 116 | + | 
|  | 117 | +/** | 
|  | 118 | + * regs_within_kernel_stack() - check the address in the stack | 
|  | 119 | + * @regs:      pt_regs which contains kernel stack pointer. | 
|  | 120 | + * @addr:      address which is checked. | 
|  | 121 | + * | 
|  | 122 | + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). | 
|  | 123 | + * If @addr is within the kernel stack, it returns true. If not, returns false. | 
|  | 124 | + */ | 
|  | 125 | +static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) | 
|  | 126 | +{ | 
|  | 127 | +	return ((addr & ~(THREAD_SIZE - 1))  == | 
|  | 128 | +		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))) || | 
|  | 129 | +		on_irq_stack(addr, raw_smp_processor_id()); | 
|  | 130 | +} | 
|  | 131 | + | 
|  | 132 | +/** | 
|  | 133 | + * regs_get_kernel_stack_nth() - get Nth entry of the stack | 
|  | 134 | + * @regs:	pt_regs which contains kernel stack pointer. | 
|  | 135 | + * @n:		stack entry number. | 
|  | 136 | + * | 
|  | 137 | + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | 
|  | 138 | + * is specified by @regs. If the @n th entry is NOT in the kernel stack, | 
|  | 139 | + * this returns 0. | 
|  | 140 | + */ | 
|  | 141 | +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) | 
|  | 142 | +{ | 
|  | 143 | +	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); | 
|  | 144 | + | 
|  | 145 | +	addr += n; | 
|  | 146 | +	if (regs_within_kernel_stack(regs, (unsigned long)addr)) | 
|  | 147 | +		return *addr; | 
|  | 148 | +	else | 
|  | 149 | +		return 0; | 
|  | 150 | +} | 
|  | 151 | + | 
| 51 | 152 | /* | 
| 52 | 153 |  * TODO: does not yet catch signals sent when the child dies. | 
| 53 | 154 |  * in exit.c or in signal.c. | 
|  | 
0 commit comments