From fe983e95cab78aee27211a56f4ac6708b35f424c Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Sun, 23 Jun 2013 11:46:23 +0200 Subject: Feather-Trace: add x86 binary rewriting implementation This patch adds the x86-specific implementation of Feather-Trace triggers that works by rewriting jump instructions. --- arch/x86/Kconfig | 2 +- arch/x86/include/asm/feather_trace.h | 17 +++++ arch/x86/include/asm/feather_trace_32.h | 115 +++++++++++++++++++++++++++++ arch/x86/include/asm/feather_trace_64.h | 124 ++++++++++++++++++++++++++++++++ arch/x86/kernel/Makefile | 2 + arch/x86/kernel/ft_event.c | 118 ++++++++++++++++++++++++++++++ litmus/Kconfig | 1 + 7 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/feather_trace.h create mode 100644 arch/x86/include/asm/feather_trace_32.h create mode 100644 arch/x86/include/asm/feather_trace_64.h create mode 100644 arch/x86/kernel/ft_event.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0216c9394949..171cdc9cc5db 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2348,6 +2348,6 @@ source "arch/x86/kvm/Kconfig" source "lib/Kconfig" config ARCH_HAS_FEATHER_TRACE - def_bool n + def_bool y source "litmus/Kconfig" diff --git a/arch/x86/include/asm/feather_trace.h b/arch/x86/include/asm/feather_trace.h new file mode 100644 index 000000000000..4fd31633405d --- /dev/null +++ b/arch/x86/include/asm/feather_trace.h @@ -0,0 +1,17 @@ +#ifndef _ARCH_FEATHER_TRACE_H +#define _ARCH_FEATHER_TRACE_H + +#include + +static inline unsigned long long ft_timestamp(void) +{ + return __native_read_tsc(); +} + +#ifdef CONFIG_X86_32 +#include "feather_trace_32.h" +#else +#include "feather_trace_64.h" +#endif + +#endif diff --git a/arch/x86/include/asm/feather_trace_32.h b/arch/x86/include/asm/feather_trace_32.h new file mode 100644 index 000000000000..75e81a9f9382 --- /dev/null +++ b/arch/x86/include/asm/feather_trace_32.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2007-2012 Björn Brandenburg, + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Do not directly include this file. Include feather_trace.h instead */ + +#define feather_callback __attribute__((regparm(3))) __attribute__((used)) + +/* + * Make the compiler reload any register that is not saved in a cdecl function + * call (minus the registers that we explicitly clobber as output registers). + */ +#define __FT_CLOBBER_LIST0 "memory", "cc", "eax", "edx", "ecx" +#define __FT_CLOBBER_LIST1 "memory", "cc", "eax", "ecx" +#define __FT_CLOBBER_LIST2 "memory", "cc", "eax" +#define __FT_CLOBBER_LIST3 "memory", "cc", "eax" + +#define __FT_TMP1(x) "=d" (x) +#define __FT_ARG1(x) "0" ((long) (x)) +#define __FT_TMP2(x) "=c" (x) +#define __FT_ARG2(x) "1" ((long) (x)) + +#define __FT_ARG3(x) "r" ((long) (x)) + +#define ft_event(id, callback) \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " call " #callback " \n\t" \ + ".section __event_table, \"aw\" \n\t" \ + ".long " #id ", 0, 1b, 2f \n\t" \ + ".previous \n\t" \ + "2: \n\t" \ + : : : __FT_CLOBBER_LIST0) + +#define ft_event0(id, callback) \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movl $" #id ", %%eax \n\t" \ + " call " #callback " \n\t" \ + ".section __event_table, \"aw\" \n\t" \ + ".long " #id ", 0, 1b, 2f \n\t" \ + ".previous \n\t" \ + "2: \n\t" \ + : : : __FT_CLOBBER_LIST0) + +#define ft_event1(id, callback, param) \ + do { \ + long __ft_tmp1; \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movl $" #id ", %%eax \n\t" \ + " call " #callback " \n\t" \ + ".section __event_table, \"aw\" \n\t" \ + ".long " #id ", 0, 1b, 2f \n\t" \ + ".previous \n\t" \ + "2: \n\t" \ + : __FT_TMP1(__ft_tmp1) \ + : __FT_ARG1(param) \ + : __FT_CLOBBER_LIST1); \ + } while (0); + +#define ft_event2(id, callback, param, param2) \ + do { \ + long __ft_tmp1, __ft_tmp2; \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movl $" #id ", %%eax \n\t" \ + " call " #callback " \n\t" \ + ".section __event_table, \"aw\" \n\t" \ + ".long " #id ", 0, 1b, 2f \n\t" \ + ".previous \n\t" \ + "2: \n\t" \ + : __FT_TMP1(__ft_tmp1), __FT_TMP2(__ft_tmp2) \ + : __FT_ARG1(param), __FT_ARG2(param2) \ + : __FT_CLOBBER_LIST2); \ + } while (0); + + +#define ft_event3(id, callback, param, param2, param3) \ + do { \ + long __ft_tmp1, __ft_tmp2; \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " subl $4, %%esp \n\t" \ + " movl $" #id ", %%eax \n\t" \ + " movl %2, (%%esp) \n\t" \ + " call " #callback " \n\t" \ + " addl $4, %%esp \n\t" \ + ".section __event_table, \"aw\" \n\t" \ + ".long " #id ", 0, 1b, 2f \n\t" \ + ".previous \n\t" \ + "2: \n\t" \ + : __FT_TMP1(__ft_tmp1), __FT_TMP2(__ft_tmp2) \ + : __FT_ARG1(param), __FT_ARG2(param2), __FT_ARG3(param3) \ + : __FT_CLOBBER_LIST3); \ + } while (0); diff --git a/arch/x86/include/asm/feather_trace_64.h b/arch/x86/include/asm/feather_trace_64.h new file mode 100644 index 000000000000..5ce49e2eebba --- /dev/null +++ b/arch/x86/include/asm/feather_trace_64.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2010 Andrea Bastoni, + * Copyright (c) 2012 Björn Brandenburg, + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Do not directly include this file. Include feather_trace.h instead */ + +/* regparm is the default on x86_64 */ +#define feather_callback __attribute__((used)) + +#define __FT_EVENT_TABLE(id,from,to) \ + ".section __event_table, \"aw\"\n\t" \ + ".balign 8\n\t" \ + ".quad " #id ", 0, " #from ", " #to " \n\t" \ + ".previous \n\t" + +/* + * x86_64 caller only owns rbp, rbx, r12-r15; + * the callee can freely modify the others. + */ +#define __FT_CLOBBER_LIST0 "memory", "cc", "rdi", "rsi", "rdx", "rcx", \ + "r8", "r9", "r10", "r11", "rax" + +#define __FT_CLOBBER_LIST1 "memory", "cc", "rdi", "rdx", "rcx", \ + "r8", "r9", "r10", "r11", "rax" + +#define __FT_CLOBBER_LIST2 "memory", "cc", "rdi", "rcx", \ + "r8", "r9", "r10", "r11", "rax" + +#define __FT_CLOBBER_LIST3 "memory", "cc", "rdi", \ + "r8", "r9", "r10", "r11", "rax" + +/* The registers RDI, RSI, RDX, RCX, R8 and R9 are used for integer and pointer + * arguments. */ + +/* RSI */ +#define __FT_TMP1(x) "=S" (x) +#define __FT_ARG1(x) "0" ((long) (x)) + +/* RDX */ +#define __FT_TMP2(x) "=d" (x) +#define __FT_ARG2(x) "1" ((long) (x)) + +/* RCX */ +#define __FT_TMP3(x) "=c" (x) +#define __FT_ARG3(x) "2" ((long) (x)) + +#define ft_event(id, callback) \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " call " #callback " \n\t" \ + __FT_EVENT_TABLE(id,1b,2f) \ + "2: \n\t" \ + : : : __FT_CLOBBER_LIST0) + +#define ft_event0(id, callback) \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movq $" #id ", %%rdi \n\t" \ + " call " #callback " \n\t" \ + __FT_EVENT_TABLE(id,1b,2f) \ + "2: \n\t" \ + : : : __FT_CLOBBER_LIST0) + +#define ft_event1(id, callback, param) \ + do { \ + long __ft_tmp1; \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movq $" #id ", %%rdi \n\t" \ + " call " #callback " \n\t" \ + __FT_EVENT_TABLE(id,1b,2f) \ + "2: \n\t" \ + : __FT_TMP1(__ft_tmp1) \ + : __FT_ARG1(param) \ + : __FT_CLOBBER_LIST1); \ + } while (0); + +#define ft_event2(id, callback, param, param2) \ + do { \ + long __ft_tmp1, __ft_tmp2; \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movq $" #id ", %%rdi \n\t" \ + " call " #callback " \n\t" \ + __FT_EVENT_TABLE(id,1b,2f) \ + "2: \n\t" \ + : __FT_TMP1(__ft_tmp1), __FT_TMP2(__ft_tmp2) \ + : __FT_ARG1(param), __FT_ARG2(param2) \ + : __FT_CLOBBER_LIST2); \ + } while (0); + +#define ft_event3(id, callback, param, param2, param3) \ + do { \ + long __ft_tmp1, __ft_tmp2, __ft_tmp3; \ + __asm__ __volatile__( \ + "1: jmp 2f \n\t" \ + " movq $" #id ", %%rdi \n\t" \ + " call " #callback " \n\t" \ + __FT_EVENT_TABLE(id,1b,2f) \ + "2: \n\t" \ + : __FT_TMP1(__ft_tmp1), __FT_TMP2(__ft_tmp2), __FT_TMP3(__ft_tmp3) \ + : __FT_ARG1(param), __FT_ARG2(param2), __FT_ARG3(param3) \ + : __FT_CLOBBER_LIST3); \ + } while (0); diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 7bd3bd310106..d38a5a78bf41 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -103,6 +103,8 @@ obj-$(CONFIG_UPROBES) += uprobes.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o +obj-$(CONFIG_FEATHER_TRACE) += ft_event.o + ### # 64 bit specific files ifeq ($(CONFIG_X86_64),y) diff --git a/arch/x86/kernel/ft_event.c b/arch/x86/kernel/ft_event.c new file mode 100644 index 000000000000..37cc33252713 --- /dev/null +++ b/arch/x86/kernel/ft_event.c @@ -0,0 +1,118 @@ +#include + +#include + +/* the feather trace management functions assume + * exclusive access to the event table + */ + +#ifndef CONFIG_DEBUG_RODATA + +#define BYTE_JUMP 0xeb +#define BYTE_JUMP_LEN 0x02 + +/* for each event, there is an entry in the event table */ +struct trace_event { + long id; + long count; + long start_addr; + long end_addr; +}; + +extern struct trace_event __start___event_table[]; +extern struct trace_event __stop___event_table[]; + +/* Workaround: if no events are defined, then the event_table section does not + * exist and the above references cause linker errors. This could probably be + * fixed by adjusting the linker script, but it is easier to maintain for us if + * we simply create a dummy symbol in the event table section. + */ +int __event_table_dummy[0] __attribute__ ((section("__event_table"))); + +int ft_enable_event(unsigned long id) +{ + struct trace_event* te = __start___event_table; + int count = 0; + char* delta; + unsigned char* instr; + + while (te < __stop___event_table) { + if (te->id == id && ++te->count == 1) { + instr = (unsigned char*) te->start_addr; + /* make sure we don't clobber something wrong */ + if (*instr == BYTE_JUMP) { + delta = (((unsigned char*) te->start_addr) + 1); + *delta = 0; + } + } + if (te->id == id) + count++; + te++; + } + + printk(KERN_DEBUG "ft_enable_event: enabled %d events\n", count); + return count; +} + +int ft_disable_event(unsigned long id) +{ + struct trace_event* te = __start___event_table; + int count = 0; + char* delta; + unsigned char* instr; + + while (te < __stop___event_table) { + if (te->id == id && --te->count == 0) { + instr = (unsigned char*) te->start_addr; + if (*instr == BYTE_JUMP) { + delta = (((unsigned char*) te->start_addr) + 1); + *delta = te->end_addr - te->start_addr - + BYTE_JUMP_LEN; + } + } + if (te->id == id) + count++; + te++; + } + + printk(KERN_DEBUG "ft_disable_event: disabled %d events\n", count); + return count; +} + +int ft_disable_all_events(void) +{ + struct trace_event* te = __start___event_table; + int count = 0; + char* delta; + unsigned char* instr; + + while (te < __stop___event_table) { + if (te->count) { + instr = (unsigned char*) te->start_addr; + if (*instr == BYTE_JUMP) { + delta = (((unsigned char*) te->start_addr) + + 1); + *delta = te->end_addr - te->start_addr - + BYTE_JUMP_LEN; + te->count = 0; + count++; + } + } + te++; + } + return count; +} + +int ft_is_event_enabled(unsigned long id) +{ + struct trace_event* te = __start___event_table; + + while (te < __stop___event_table) { + if (te->id == id) + return te->count; + te++; + } + return 0; +} + +#endif diff --git a/litmus/Kconfig b/litmus/Kconfig index 70ddbaddc06f..7456eb209cf7 100644 --- a/litmus/Kconfig +++ b/litmus/Kconfig @@ -4,6 +4,7 @@ menu "Tracing" config FEATHER_TRACE bool "Feather-Trace Infrastructure" + depends on !RELOCATABLE default y help Feather-Trace basic tracing infrastructure. Includes device file -- cgit v1.2.2