aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2017-06-07 18:24:50 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2017-06-09 10:08:18 -0400
commiteafd7967cdc7f85648d805db674be514a3511984 (patch)
tree41954cf858e7ef911356ea7119fac6d7f4b319f7
parentfe94fb01f41e402746d30a23f7a777c7e6785b07 (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.c62
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 {
22extern struct trace_event __start___event_table[]; 25extern struct trace_event __start___event_table[];
23extern struct trace_event __stop___event_table[]; 26extern struct trace_event __stop___event_table[];
24 27
28
29/* NOTE: The following two functions have been stolen from ftrace.c */
30
31static inline int
32within(unsigned long addr, unsigned long start, unsigned long end)
33{
34 return addr >= start && addr < end;
35}
36
37static 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