diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2010-02-12 07:38:40 -0500 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2010-02-17 07:19:26 -0500 |
commit | 952974ac61f686896bd4134dae106a886a5589f1 (patch) | |
tree | c5eaebb466cddc7c6b29c3bc3f3da4807b279f29 | |
parent | f850c30c8b426ba1688cb63b1a3e534eed03a138 (diff) |
s390: Add pt_regs register and stack access API
This API is needed for the kprobe-based event tracer.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Reviewed-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
LKML-Reference: <20100212123840.GB27548@osiris.boeblingen.de.ibm.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/ptrace.h | 13 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 58 |
3 files changed, 71 insertions, 1 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index c80235206c01..2590ce20157d 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -87,6 +87,7 @@ config S390 | |||
87 | select HAVE_SYSCALL_TRACEPOINTS | 87 | select HAVE_SYSCALL_TRACEPOINTS |
88 | select HAVE_DYNAMIC_FTRACE | 88 | select HAVE_DYNAMIC_FTRACE |
89 | select HAVE_FUNCTION_GRAPH_TRACER | 89 | select HAVE_FUNCTION_GRAPH_TRACER |
90 | select HAVE_REGS_AND_STACK_ACCESS_API | ||
90 | select HAVE_DEFAULT_NO_SPIN_MUTEXES | 91 | select HAVE_DEFAULT_NO_SPIN_MUTEXES |
91 | select HAVE_OPROFILE | 92 | select HAVE_OPROFILE |
92 | select HAVE_KPROBES | 93 | select HAVE_KPROBES |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 95dcf183a28d..dd2d913afcae 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -492,13 +492,24 @@ struct user_regs_struct | |||
492 | struct task_struct; | 492 | struct task_struct; |
493 | extern void user_enable_single_step(struct task_struct *); | 493 | extern void user_enable_single_step(struct task_struct *); |
494 | extern void user_disable_single_step(struct task_struct *); | 494 | extern void user_disable_single_step(struct task_struct *); |
495 | extern void show_regs(struct pt_regs * regs); | ||
495 | 496 | ||
496 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) | 497 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) |
497 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) | 498 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) |
498 | #define user_stack_pointer(regs)((regs)->gprs[15]) | 499 | #define user_stack_pointer(regs)((regs)->gprs[15]) |
499 | #define regs_return_value(regs)((regs)->gprs[2]) | 500 | #define regs_return_value(regs)((regs)->gprs[2]) |
500 | #define profile_pc(regs) instruction_pointer(regs) | 501 | #define profile_pc(regs) instruction_pointer(regs) |
501 | extern void show_regs(struct pt_regs * regs); | 502 | |
503 | int regs_query_register_offset(const char *name); | ||
504 | const char *regs_query_register_name(unsigned int offset); | ||
505 | unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset); | ||
506 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n); | ||
507 | |||
508 | static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) | ||
509 | { | ||
510 | return regs->gprs[15] & PSW_ADDR_INSN; | ||
511 | } | ||
512 | |||
502 | #endif /* __KERNEL__ */ | 513 | #endif /* __KERNEL__ */ |
503 | #endif /* __ASSEMBLY__ */ | 514 | #endif /* __ASSEMBLY__ */ |
504 | 515 | ||
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 13815d39f7dd..1720f380add5 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -984,3 +984,61 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
984 | #endif | 984 | #endif |
985 | return &user_s390_view; | 985 | return &user_s390_view; |
986 | } | 986 | } |
987 | |||
988 | static const char *gpr_names[NUM_GPRS] = { | ||
989 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | ||
990 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | ||
991 | }; | ||
992 | |||
993 | unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset) | ||
994 | { | ||
995 | if (offset >= NUM_GPRS) | ||
996 | return 0; | ||
997 | return regs->gprs[offset]; | ||
998 | } | ||
999 | |||
1000 | int regs_query_register_offset(const char *name) | ||
1001 | { | ||
1002 | unsigned long offset; | ||
1003 | |||
1004 | if (!name || *name != 'r') | ||
1005 | return -EINVAL; | ||
1006 | if (strict_strtoul(name + 1, 10, &offset)) | ||
1007 | return -EINVAL; | ||
1008 | if (offset >= NUM_GPRS) | ||
1009 | return -EINVAL; | ||
1010 | return offset; | ||
1011 | } | ||
1012 | |||
1013 | const char *regs_query_register_name(unsigned int offset) | ||
1014 | { | ||
1015 | if (offset >= NUM_GPRS) | ||
1016 | return NULL; | ||
1017 | return gpr_names[offset]; | ||
1018 | } | ||
1019 | |||
1020 | static int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) | ||
1021 | { | ||
1022 | unsigned long ksp = kernel_stack_pointer(regs); | ||
1023 | |||
1024 | return (addr & ~(THREAD_SIZE - 1)) == (ksp & ~(THREAD_SIZE - 1)); | ||
1025 | } | ||
1026 | |||
1027 | /** | ||
1028 | * regs_get_kernel_stack_nth() - get Nth entry of the stack | ||
1029 | * @regs:pt_regs which contains kernel stack pointer. | ||
1030 | * @n:stack entry number. | ||
1031 | * | ||
1032 | * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | ||
1033 | * is specifined by @regs. If the @n th entry is NOT in the kernel stack, | ||
1034 | * this returns 0. | ||
1035 | */ | ||
1036 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) | ||
1037 | { | ||
1038 | unsigned long addr; | ||
1039 | |||
1040 | addr = kernel_stack_pointer(regs) + n * sizeof(long); | ||
1041 | if (!regs_within_kernel_stack(regs, addr)) | ||
1042 | return 0; | ||
1043 | return *(unsigned long *)addr; | ||
1044 | } | ||