Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: enable HAVE_REGS_AND_STACK_ACCESS_API feature

Enable HAVE_REGS_AND_STACK_ACCESS_API feature for ARC architecture,
including ARCcompact and ARCv2 flavors. Add supporting functions
and defines.

Signed-off-by: Sergey Matyukevich <sergey.matyukevich@synopsys.com>
Signed-off-by: Vineet Gupta <vgupta@kernel.org>

authored by

Sergey Matyukevich and committed by
Vineet Gupta
b3bbf6a7 af2d861d

+147
+1
arch/arc/Kconfig
··· 36 36 select HAVE_KERNEL_LZMA 37 37 select HAVE_KPROBES 38 38 select HAVE_KRETPROBES 39 + select HAVE_REGS_AND_STACK_ACCESS_API 39 40 select HAVE_MOD_ARCH_SPECIFIC 40 41 select HAVE_PERF_EVENTS 41 42 select IRQ_DOMAIN
+27
arch/arc/include/asm/ptrace.h
··· 8 8 #define __ASM_ARC_PTRACE_H 9 9 10 10 #include <uapi/asm/ptrace.h> 11 + #include <linux/compiler.h> 11 12 12 13 #ifndef __ASSEMBLY__ 13 14 ··· 55 54 56 55 unsigned long user_r25; 57 56 }; 57 + 58 + #define MAX_REG_OFFSET offsetof(struct pt_regs, user_r25) 59 + 58 60 #else 59 61 60 62 struct pt_regs { ··· 105 101 unsigned long ret; 106 102 unsigned long status32; 107 103 }; 104 + 105 + #define MAX_REG_OFFSET offsetof(struct pt_regs, status32) 108 106 109 107 #endif 110 108 ··· 160 154 { 161 155 instruction_pointer(regs) = val; 162 156 } 157 + 158 + static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) 159 + { 160 + return regs->sp; 161 + } 162 + 163 + extern int regs_query_register_offset(const char *name); 164 + extern const char *regs_query_register_name(unsigned int offset); 165 + extern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr); 166 + extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, 167 + unsigned int n); 168 + 169 + static inline unsigned long regs_get_register(struct pt_regs *regs, 170 + unsigned int offset) 171 + { 172 + if (unlikely(offset > MAX_REG_OFFSET)) 173 + return 0; 174 + 175 + return *(unsigned long *)((unsigned long)regs + offset); 176 + } 177 + 163 178 #endif /* !__ASSEMBLY__ */ 164 179 165 180 #endif /* __ASM_PTRACE_H */
+119
arch/arc/kernel/ptrace.c
··· 9 9 #include <linux/unistd.h> 10 10 #include <linux/elf.h> 11 11 12 + struct pt_regs_offset { 13 + const char *name; 14 + int offset; 15 + }; 16 + 17 + #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} 18 + #define REG_OFFSET_END {.name = NULL, .offset = 0} 19 + 20 + #ifdef CONFIG_ISA_ARCOMPACT 21 + static const struct pt_regs_offset regoffset_table[] = { 22 + REG_OFFSET_NAME(bta), 23 + REG_OFFSET_NAME(lp_start), 24 + REG_OFFSET_NAME(lp_end), 25 + REG_OFFSET_NAME(lp_count), 26 + REG_OFFSET_NAME(status32), 27 + REG_OFFSET_NAME(ret), 28 + REG_OFFSET_NAME(blink), 29 + REG_OFFSET_NAME(fp), 30 + REG_OFFSET_NAME(r26), 31 + REG_OFFSET_NAME(r12), 32 + REG_OFFSET_NAME(r11), 33 + REG_OFFSET_NAME(r10), 34 + REG_OFFSET_NAME(r9), 35 + REG_OFFSET_NAME(r8), 36 + REG_OFFSET_NAME(r7), 37 + REG_OFFSET_NAME(r6), 38 + REG_OFFSET_NAME(r5), 39 + REG_OFFSET_NAME(r4), 40 + REG_OFFSET_NAME(r3), 41 + REG_OFFSET_NAME(r2), 42 + REG_OFFSET_NAME(r1), 43 + REG_OFFSET_NAME(r0), 44 + REG_OFFSET_NAME(sp), 45 + REG_OFFSET_NAME(orig_r0), 46 + REG_OFFSET_NAME(event), 47 + REG_OFFSET_NAME(user_r25), 48 + REG_OFFSET_END, 49 + }; 50 + 51 + #else 52 + 53 + static const struct pt_regs_offset regoffset_table[] = { 54 + REG_OFFSET_NAME(orig_r0), 55 + REG_OFFSET_NAME(event), 56 + REG_OFFSET_NAME(bta), 57 + REG_OFFSET_NAME(user_r25), 58 + REG_OFFSET_NAME(r26), 59 + REG_OFFSET_NAME(fp), 60 + REG_OFFSET_NAME(sp), 61 + REG_OFFSET_NAME(r12), 62 + REG_OFFSET_NAME(r30), 63 + #ifdef CONFIG_ARC_HAS_ACCL_REGS 64 + REG_OFFSET_NAME(r58), 65 + REG_OFFSET_NAME(r59), 66 + #endif 67 + #ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS 68 + REG_OFFSET_NAME(DSP_CTRL), 69 + #endif 70 + REG_OFFSET_NAME(r0), 71 + REG_OFFSET_NAME(r1), 72 + REG_OFFSET_NAME(r2), 73 + REG_OFFSET_NAME(r3), 74 + REG_OFFSET_NAME(r4), 75 + REG_OFFSET_NAME(r5), 76 + REG_OFFSET_NAME(r6), 77 + REG_OFFSET_NAME(r7), 78 + REG_OFFSET_NAME(r8), 79 + REG_OFFSET_NAME(r9), 80 + REG_OFFSET_NAME(r10), 81 + REG_OFFSET_NAME(r11), 82 + REG_OFFSET_NAME(blink), 83 + REG_OFFSET_NAME(lp_end), 84 + REG_OFFSET_NAME(lp_start), 85 + REG_OFFSET_NAME(lp_count), 86 + REG_OFFSET_NAME(ei), 87 + REG_OFFSET_NAME(ldi), 88 + REG_OFFSET_NAME(jli), 89 + REG_OFFSET_NAME(ret), 90 + REG_OFFSET_NAME(status32), 91 + REG_OFFSET_END, 92 + }; 93 + #endif 94 + 12 95 static struct callee_regs *task_callee_regs(struct task_struct *tsk) 13 96 { 14 97 struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg; ··· 349 266 asmlinkage void syscall_trace_exit(struct pt_regs *regs) 350 267 { 351 268 ptrace_report_syscall_exit(regs, 0); 269 + } 270 + 271 + int regs_query_register_offset(const char *name) 272 + { 273 + const struct pt_regs_offset *roff; 274 + 275 + for (roff = regoffset_table; roff->name != NULL; roff++) 276 + if (!strcmp(roff->name, name)) 277 + return roff->offset; 278 + return -EINVAL; 279 + } 280 + 281 + const char *regs_query_register_name(unsigned int offset) 282 + { 283 + const struct pt_regs_offset *roff; 284 + for (roff = regoffset_table; roff->name != NULL; roff++) 285 + if (roff->offset == offset) 286 + return roff->name; 287 + return NULL; 288 + } 289 + 290 + bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) 291 + { 292 + return (addr & ~(THREAD_SIZE - 1)) == 293 + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)); 294 + } 295 + 296 + unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) 297 + { 298 + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); 299 + 300 + addr += n; 301 + if (regs_within_kernel_stack(regs, (unsigned long)addr)) 302 + return *addr; 303 + else 304 + return 0; 352 305 }