diff options
| -rw-r--r-- | Documentation/trace/ftrace-design.txt | 5 | ||||
| -rw-r--r-- | arch/Kconfig | 8 | ||||
| -rw-r--r-- | arch/s390/Kconfig | 1 | ||||
| -rw-r--r-- | arch/s390/include/asm/ptrace.h | 13 | ||||
| -rw-r--r-- | arch/s390/include/asm/syscall.h | 7 | ||||
| -rw-r--r-- | arch/s390/kernel/ftrace.c | 10 | ||||
| -rw-r--r-- | arch/s390/kernel/ptrace.c | 58 | ||||
| -rw-r--r-- | arch/sh/include/asm/syscall.h | 2 | ||||
| -rw-r--r-- | arch/sh/kernel/ftrace.c | 9 | ||||
| -rw-r--r-- | arch/sparc/include/asm/syscall.h | 7 | ||||
| -rw-r--r-- | arch/sparc/kernel/ftrace.c | 11 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/syscall.h | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/ftrace.c | 10 | ||||
| -rw-r--r-- | include/linux/ftrace.h | 6 | ||||
| -rw-r--r-- | kernel/trace/Kconfig | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 5 |
17 files changed, 112 insertions, 45 deletions
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 6a5a579126b..f1f81afee8a 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt | |||
| @@ -238,11 +238,10 @@ HAVE_SYSCALL_TRACEPOINTS | |||
| 238 | 238 | ||
| 239 | You need very few things to get the syscalls tracing in an arch. | 239 | You need very few things to get the syscalls tracing in an arch. |
| 240 | 240 | ||
| 241 | - Support HAVE_ARCH_TRACEHOOK (see arch/Kconfig). | ||
| 241 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number | 242 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number |
| 242 | of syscalls supported by the arch. | 243 | of syscalls supported by the arch. |
| 243 | - Implement arch_syscall_addr() that resolves a syscall address from a | 244 | - Support the TIF_SYSCALL_TRACEPOINT thread flags. |
| 244 | syscall number. | ||
| 245 | - Support the TIF_SYSCALL_TRACEPOINT thread flags | ||
| 246 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace | 245 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace |
| 247 | in the ptrace syscalls tracing path. | 246 | in the ptrace syscalls tracing path. |
| 248 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. | 247 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. |
diff --git a/arch/Kconfig b/arch/Kconfig index 9d055b4f058..50877ef2584 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
| @@ -121,6 +121,14 @@ config HAVE_DMA_ATTRS | |||
| 121 | config USE_GENERIC_SMP_HELPERS | 121 | config USE_GENERIC_SMP_HELPERS |
| 122 | bool | 122 | bool |
| 123 | 123 | ||
| 124 | config HAVE_REGS_AND_STACK_ACCESS_API | ||
| 125 | bool | ||
| 126 | help | ||
| 127 | This symbol should be selected by an architecure if it supports | ||
| 128 | the API needed to access registers and stack entries from pt_regs, | ||
| 129 | declared in asm/ptrace.h | ||
| 130 | For example the kprobes-based event tracer needs this API. | ||
| 131 | |||
| 124 | config HAVE_CLK | 132 | config HAVE_CLK |
| 125 | bool | 133 | bool |
| 126 | help | 134 | help |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index c80235206c0..2590ce20157 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 95dcf183a28..dd2d913afca 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/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index e0a73d3eb83..8429686951f 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
| @@ -15,6 +15,13 @@ | |||
| 15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
| 16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
| 17 | 17 | ||
| 18 | /* | ||
| 19 | * The syscall table always contains 32 bit pointers since we know that the | ||
| 20 | * address of the function to be called is (way) below 4GB. So the "int" | ||
| 21 | * type here is what we want [need] for both 32 bit and 64 bit systems. | ||
| 22 | */ | ||
| 23 | extern const unsigned int sys_call_table[]; | ||
| 24 | |||
| 18 | static inline long syscall_get_nr(struct task_struct *task, | 25 | static inline long syscall_get_nr(struct task_struct *task, |
| 19 | struct pt_regs *regs) | 26 | struct pt_regs *regs) |
| 20 | { | 27 | { |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 5a82bc68193..9e69449e77a 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
| @@ -200,13 +200,3 @@ out: | |||
| 200 | return parent; | 200 | return parent; |
| 201 | } | 201 | } |
| 202 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 202 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
| 203 | |||
| 204 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
| 205 | |||
| 206 | extern unsigned int sys_call_table[]; | ||
| 207 | |||
| 208 | unsigned long __init arch_syscall_addr(int nr) | ||
| 209 | { | ||
| 210 | return (unsigned long)sys_call_table[nr]; | ||
| 211 | } | ||
| 212 | #endif | ||
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 7cf46423441..33fdc5a7976 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
| @@ -992,3 +992,61 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) | |||
| 992 | #endif | 992 | #endif |
| 993 | return &user_s390_view; | 993 | return &user_s390_view; |
| 994 | } | 994 | } |
| 995 | |||
| 996 | static const char *gpr_names[NUM_GPRS] = { | ||
| 997 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | ||
| 998 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | ||
| 999 | }; | ||
| 1000 | |||
| 1001 | unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset) | ||
| 1002 | { | ||
| 1003 | if (offset >= NUM_GPRS) | ||
| 1004 | return 0; | ||
| 1005 | return regs->gprs[offset]; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | int regs_query_register_offset(const char *name) | ||
| 1009 | { | ||
| 1010 | unsigned long offset; | ||
| 1011 | |||
| 1012 | if (!name || *name != 'r') | ||
| 1013 | return -EINVAL; | ||
| 1014 | if (strict_strtoul(name + 1, 10, &offset)) | ||
| 1015 | return -EINVAL; | ||
| 1016 | if (offset >= NUM_GPRS) | ||
| 1017 | return -EINVAL; | ||
| 1018 | return offset; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | const char *regs_query_register_name(unsigned int offset) | ||
| 1022 | { | ||
| 1023 | if (offset >= NUM_GPRS) | ||
| 1024 | return NULL; | ||
| 1025 | return gpr_names[offset]; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | static int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) | ||
| 1029 | { | ||
| 1030 | unsigned long ksp = kernel_stack_pointer(regs); | ||
| 1031 | |||
| 1032 | return (addr & ~(THREAD_SIZE - 1)) == (ksp & ~(THREAD_SIZE - 1)); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | /** | ||
| 1036 | * regs_get_kernel_stack_nth() - get Nth entry of the stack | ||
| 1037 | * @regs:pt_regs which contains kernel stack pointer. | ||
| 1038 | * @n:stack entry number. | ||
| 1039 | * | ||
| 1040 | * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which | ||
| 1041 | * is specifined by @regs. If the @n th entry is NOT in the kernel stack, | ||
| 1042 | * this returns 0. | ||
| 1043 | */ | ||
| 1044 | unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) | ||
| 1045 | { | ||
| 1046 | unsigned long addr; | ||
| 1047 | |||
| 1048 | addr = kernel_stack_pointer(regs) + n * sizeof(long); | ||
| 1049 | if (!regs_within_kernel_stack(regs, addr)) | ||
| 1050 | return 0; | ||
| 1051 | return *(unsigned long *)addr; | ||
| 1052 | } | ||
diff --git a/arch/sh/include/asm/syscall.h b/arch/sh/include/asm/syscall.h index 6a381429ee9..aa7777bdc37 100644 --- a/arch/sh/include/asm/syscall.h +++ b/arch/sh/include/asm/syscall.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #ifndef __ASM_SH_SYSCALL_H | 1 | #ifndef __ASM_SH_SYSCALL_H |
| 2 | #define __ASM_SH_SYSCALL_H | 2 | #define __ASM_SH_SYSCALL_H |
| 3 | 3 | ||
| 4 | extern const unsigned long sys_call_table[]; | ||
| 5 | |||
| 4 | #ifdef CONFIG_SUPERH32 | 6 | #ifdef CONFIG_SUPERH32 |
| 5 | # include "syscall_32.h" | 7 | # include "syscall_32.h" |
| 6 | #else | 8 | #else |
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index a48cdedc73b..30e13196d35 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c | |||
| @@ -399,12 +399,3 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | |||
| 399 | } | 399 | } |
| 400 | } | 400 | } |
| 401 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 401 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
| 402 | |||
| 403 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
| 404 | extern unsigned long *sys_call_table; | ||
| 405 | |||
| 406 | unsigned long __init arch_syscall_addr(int nr) | ||
| 407 | { | ||
| 408 | return (unsigned long)sys_call_table[nr]; | ||
| 409 | } | ||
| 410 | #endif /* CONFIG_FTRACE_SYSCALLS */ | ||
diff --git a/arch/sparc/include/asm/syscall.h b/arch/sparc/include/asm/syscall.h index 7486c605e23..025a02ad2e3 100644 --- a/arch/sparc/include/asm/syscall.h +++ b/arch/sparc/include/asm/syscall.h | |||
| @@ -5,6 +5,13 @@ | |||
| 5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
| 6 | #include <asm/ptrace.h> | 6 | #include <asm/ptrace.h> |
| 7 | 7 | ||
| 8 | /* | ||
| 9 | * The syscall table always contains 32 bit pointers since we know that the | ||
| 10 | * address of the function to be called is (way) below 4GB. So the "int" | ||
| 11 | * type here is what we want [need] for both 32 bit and 64 bit systems. | ||
| 12 | */ | ||
| 13 | extern const unsigned int sys_call_table[]; | ||
| 14 | |||
| 8 | /* The system call number is given by the user in %g1 */ | 15 | /* The system call number is given by the user in %g1 */ |
| 9 | static inline long syscall_get_nr(struct task_struct *task, | 16 | static inline long syscall_get_nr(struct task_struct *task, |
| 10 | struct pt_regs *regs) | 17 | struct pt_regs *regs) |
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index 29973daa993..9103a56b39e 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c | |||
| @@ -91,14 +91,3 @@ int __init ftrace_dyn_arch_init(void *data) | |||
| 91 | return 0; | 91 | return 0; |
| 92 | } | 92 | } |
| 93 | #endif | 93 | #endif |
| 94 | |||
| 95 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
| 96 | |||
| 97 | extern unsigned int sys_call_table[]; | ||
| 98 | |||
| 99 | unsigned long __init arch_syscall_addr(int nr) | ||
| 100 | { | ||
| 101 | return (unsigned long)sys_call_table[nr]; | ||
| 102 | } | ||
| 103 | |||
| 104 | #endif | ||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index eb4092568f9..0896008f750 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -45,6 +45,7 @@ config X86 | |||
| 45 | select HAVE_GENERIC_DMA_COHERENT if X86_32 | 45 | select HAVE_GENERIC_DMA_COHERENT if X86_32 |
| 46 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | 46 | select HAVE_EFFICIENT_UNALIGNED_ACCESS |
| 47 | select USER_STACKTRACE_SUPPORT | 47 | select USER_STACKTRACE_SUPPORT |
| 48 | select HAVE_REGS_AND_STACK_ACCESS_API | ||
| 48 | select HAVE_DMA_API_DEBUG | 49 | select HAVE_DMA_API_DEBUG |
| 49 | select HAVE_KERNEL_GZIP | 50 | select HAVE_KERNEL_GZIP |
| 50 | select HAVE_KERNEL_BZIP2 | 51 | select HAVE_KERNEL_BZIP2 |
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index 8d33bc5462d..c4a348f7bd4 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
| 17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
| 18 | 18 | ||
| 19 | extern const unsigned long sys_call_table[]; | ||
| 20 | |||
| 19 | /* | 21 | /* |
| 20 | * Only the low 32 bits of orig_ax are meaningful, so we return int. | 22 | * Only the low 32 bits of orig_ax are meaningful, so we return int. |
| 21 | * This importantly ignores the high bits on 64-bit, so comparisons | 23 | * This importantly ignores the high bits on 64-bit, so comparisons |
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 605ef196fdd..cd37469b54e 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
| @@ -510,13 +510,3 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
| 510 | } | 510 | } |
| 511 | } | 511 | } |
| 512 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 512 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
| 513 | |||
| 514 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
| 515 | |||
| 516 | extern unsigned long *sys_call_table; | ||
| 517 | |||
| 518 | unsigned long __init arch_syscall_addr(int nr) | ||
| 519 | { | ||
| 520 | return (unsigned long)(&sys_call_table)[nr]; | ||
| 521 | } | ||
| 522 | #endif | ||
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 0b4f97d24d7..1cbb36f2759 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
| @@ -511,4 +511,10 @@ static inline void trace_hw_branch_oops(void) {} | |||
| 511 | 511 | ||
| 512 | #endif /* CONFIG_HW_BRANCH_TRACER */ | 512 | #endif /* CONFIG_HW_BRANCH_TRACER */ |
| 513 | 513 | ||
| 514 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
| 515 | |||
| 516 | unsigned long arch_syscall_addr(int nr); | ||
| 517 | |||
| 518 | #endif /* CONFIG_FTRACE_SYSCALLS */ | ||
| 519 | |||
| 514 | #endif /* _LINUX_FTRACE_H */ | 520 | #endif /* _LINUX_FTRACE_H */ |
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index e6b99b8c3d3..13e13d428cd 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
| @@ -440,7 +440,7 @@ config BLK_DEV_IO_TRACE | |||
| 440 | 440 | ||
| 441 | config KPROBE_EVENT | 441 | config KPROBE_EVENT |
| 442 | depends on KPROBES | 442 | depends on KPROBES |
| 443 | depends on X86 | 443 | depends on HAVE_REGS_AND_STACK_ACCESS_API |
| 444 | bool "Enable kprobes-based dynamic events" | 444 | bool "Enable kprobes-based dynamic events" |
| 445 | select TRACING | 445 | select TRACING |
| 446 | default y | 446 | default y |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 8cdda95da81..a1834dda85f 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
| @@ -394,6 +394,11 @@ int init_syscall_trace(struct ftrace_event_call *call) | |||
| 394 | return id; | 394 | return id; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | unsigned long __init arch_syscall_addr(int nr) | ||
| 398 | { | ||
| 399 | return (unsigned long)sys_call_table[nr]; | ||
| 400 | } | ||
| 401 | |||
| 397 | int __init init_ftrace_syscalls(void) | 402 | int __init init_ftrace_syscalls(void) |
| 398 | { | 403 | { |
| 399 | struct syscall_metadata *meta; | 404 | struct syscall_metadata *meta; |
