diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2017-06-07 18:24:50 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2017-06-09 10:08:18 -0400 |
commit | eafd7967cdc7f85648d805db674be514a3511984 (patch) | |
tree | 41954cf858e7ef911356ea7119fac6d7f4b319f7 | |
parent | fe94fb01f41e402746d30a23f7a777c7e6785b07 (diff) |
Feather-Trace: make x86 rewriting impl work despite RO text
Mirror what ftrace does to ensure that we can patch up the text
segment.
-rw-r--r-- | arch/x86/kernel/ft_event.c | 62 |
1 files changed, 57 insertions, 5 deletions
diff --git a/arch/x86/kernel/ft_event.c b/arch/x86/kernel/ft_event.c index 37cc33252713..7aa3d0592ff2 100644 --- a/arch/x86/kernel/ft_event.c +++ b/arch/x86/kernel/ft_event.c | |||
@@ -1,4 +1,7 @@ | |||
1 | #include <linux/types.h> | 1 | #include <linux/types.h> |
2 | #include <linux/module.h> | ||
3 | #include <asm/cacheflush.h> | ||
4 | #include <asm/sections.h> | ||
2 | 5 | ||
3 | #include <litmus/feather_trace.h> | 6 | #include <litmus/feather_trace.h> |
4 | 7 | ||
@@ -6,7 +9,7 @@ | |||
6 | * exclusive access to the event table | 9 | * exclusive access to the event table |
7 | */ | 10 | */ |
8 | 11 | ||
9 | #ifndef CONFIG_DEBUG_RODATA | 12 | #ifndef CONFIG_RELOCATABLE |
10 | 13 | ||
11 | #define BYTE_JUMP 0xeb | 14 | #define BYTE_JUMP 0xeb |
12 | #define BYTE_JUMP_LEN 0x02 | 15 | #define BYTE_JUMP_LEN 0x02 |
@@ -22,6 +25,31 @@ struct trace_event { | |||
22 | extern struct trace_event __start___event_table[]; | 25 | extern struct trace_event __start___event_table[]; |
23 | extern struct trace_event __stop___event_table[]; | 26 | extern struct trace_event __stop___event_table[]; |
24 | 27 | ||
28 | |||
29 | /* NOTE: The following two functions have been stolen from ftrace.c */ | ||
30 | |||
31 | static inline int | ||
32 | within(unsigned long addr, unsigned long start, unsigned long end) | ||
33 | { | ||
34 | return addr >= start && addr < end; | ||
35 | } | ||
36 | |||
37 | static unsigned long text_ip_addr(unsigned long ip) | ||
38 | { | ||
39 | /* | ||
40 | * On x86_64, kernel text mappings are mapped read-only, so we use | ||
41 | * the kernel identity mapping instead of the kernel text mapping | ||
42 | * to modify the kernel text. | ||
43 | * | ||
44 | * For 32bit kernels, these mappings are same and we can use | ||
45 | * kernel identity mapping to modify code. | ||
46 | */ | ||
47 | if (within(ip, (unsigned long)_text, (unsigned long)_etext)) | ||
48 | ip = (unsigned long)__va(__pa_symbol(ip)); | ||
49 | |||
50 | return ip; | ||
51 | } | ||
52 | |||
25 | /* Workaround: if no events are defined, then the event_table section does not | 53 | /* Workaround: if no events are defined, then the event_table section does not |
26 | * exist and the above references cause linker errors. This could probably be | 54 | * exist and the above references cause linker errors. This could probably be |
27 | * fixed by adjusting the linker script, but it is easier to maintain for us if | 55 | * fixed by adjusting the linker script, but it is easier to maintain for us if |
@@ -36,12 +64,17 @@ int ft_enable_event(unsigned long id) | |||
36 | char* delta; | 64 | char* delta; |
37 | unsigned char* instr; | 65 | unsigned char* instr; |
38 | 66 | ||
67 | set_kernel_text_rw(); | ||
68 | set_all_modules_text_rw(); | ||
69 | |||
39 | while (te < __stop___event_table) { | 70 | while (te < __stop___event_table) { |
40 | if (te->id == id && ++te->count == 1) { | 71 | if (te->id == id && ++te->count == 1) { |
41 | instr = (unsigned char*) te->start_addr; | 72 | instr = (unsigned char*) te->start_addr; |
42 | /* make sure we don't clobber something wrong */ | 73 | /* make sure we don't clobber something wrong */ |
43 | if (*instr == BYTE_JUMP) { | 74 | if (*instr == BYTE_JUMP) { |
44 | delta = (((unsigned char*) te->start_addr) + 1); | 75 | delta = (unsigned char*) text_ip_addr( |
76 | ((unsigned long) te->start_addr) | ||
77 | + 1); | ||
45 | *delta = 0; | 78 | *delta = 0; |
46 | } | 79 | } |
47 | } | 80 | } |
@@ -50,6 +83,9 @@ int ft_enable_event(unsigned long id) | |||
50 | te++; | 83 | te++; |
51 | } | 84 | } |
52 | 85 | ||
86 | set_all_modules_text_ro(); | ||
87 | set_kernel_text_ro(); | ||
88 | |||
53 | printk(KERN_DEBUG "ft_enable_event: enabled %d events\n", count); | 89 | printk(KERN_DEBUG "ft_enable_event: enabled %d events\n", count); |
54 | return count; | 90 | return count; |
55 | } | 91 | } |
@@ -61,11 +97,16 @@ int ft_disable_event(unsigned long id) | |||
61 | char* delta; | 97 | char* delta; |
62 | unsigned char* instr; | 98 | unsigned char* instr; |
63 | 99 | ||
100 | set_kernel_text_rw(); | ||
101 | set_all_modules_text_rw(); | ||
102 | |||
64 | while (te < __stop___event_table) { | 103 | while (te < __stop___event_table) { |
65 | if (te->id == id && --te->count == 0) { | 104 | if (te->id == id && --te->count == 0) { |
66 | instr = (unsigned char*) te->start_addr; | 105 | instr = (unsigned char*) te->start_addr; |
67 | if (*instr == BYTE_JUMP) { | 106 | if (*instr == BYTE_JUMP) { |
68 | delta = (((unsigned char*) te->start_addr) + 1); | 107 | delta = (unsigned char*) text_ip_addr( |
108 | ((unsigned long) te->start_addr) | ||
109 | + 1); | ||
69 | *delta = te->end_addr - te->start_addr - | 110 | *delta = te->end_addr - te->start_addr - |
70 | BYTE_JUMP_LEN; | 111 | BYTE_JUMP_LEN; |
71 | } | 112 | } |
@@ -75,6 +116,9 @@ int ft_disable_event(unsigned long id) | |||
75 | te++; | 116 | te++; |
76 | } | 117 | } |
77 | 118 | ||
119 | set_all_modules_text_ro(); | ||
120 | set_kernel_text_ro(); | ||
121 | |||
78 | printk(KERN_DEBUG "ft_disable_event: disabled %d events\n", count); | 122 | printk(KERN_DEBUG "ft_disable_event: disabled %d events\n", count); |
79 | return count; | 123 | return count; |
80 | } | 124 | } |
@@ -86,12 +130,16 @@ int ft_disable_all_events(void) | |||
86 | char* delta; | 130 | char* delta; |
87 | unsigned char* instr; | 131 | unsigned char* instr; |
88 | 132 | ||
133 | set_kernel_text_rw(); | ||
134 | set_all_modules_text_rw(); | ||
135 | |||
89 | while (te < __stop___event_table) { | 136 | while (te < __stop___event_table) { |
90 | if (te->count) { | 137 | if (te->count) { |
91 | instr = (unsigned char*) te->start_addr; | 138 | instr = (unsigned char*) te->start_addr; |
92 | if (*instr == BYTE_JUMP) { | 139 | if (*instr == BYTE_JUMP) { |
93 | delta = (((unsigned char*) te->start_addr) | 140 | delta = (unsigned char*) text_ip_addr( |
94 | + 1); | 141 | ((unsigned long) te->start_addr) |
142 | + 1); | ||
95 | *delta = te->end_addr - te->start_addr - | 143 | *delta = te->end_addr - te->start_addr - |
96 | BYTE_JUMP_LEN; | 144 | BYTE_JUMP_LEN; |
97 | te->count = 0; | 145 | te->count = 0; |
@@ -100,6 +148,10 @@ int ft_disable_all_events(void) | |||
100 | } | 148 | } |
101 | te++; | 149 | te++; |
102 | } | 150 | } |
151 | |||
152 | set_all_modules_text_ro(); | ||
153 | set_kernel_text_ro(); | ||
154 | |||
103 | return count; | 155 | return count; |
104 | } | 156 | } |
105 | 157 | ||