diff options
author | Namhyung Kim <namhyung.kim@lge.com> | 2013-11-26 01:21:04 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2014-01-02 16:17:43 -0500 |
commit | 5baaa59ef09e8729aef101f7bf7d9d0af00852e3 (patch) | |
tree | adf05e51e33e06d0d9eb9689269364314b754c2c /kernel | |
parent | 3925f4a5afa489e905a08edffc36a435a3434a63 (diff) |
tracing/probes: Implement 'memory' fetch method for uprobes
Use separate method to fetch from memory. Move existing functions to
trace_kprobe.c and make them static. Also add new memory fetch
implementation for uprobes.
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: zhangwei(Jovi) <jovi.zhangwei@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_kprobe.c | 77 | ||||
-rw-r--r-- | kernel/trace/trace_probe.c | 77 | ||||
-rw-r--r-- | kernel/trace/trace_probe.h | 4 | ||||
-rw-r--r-- | kernel/trace/trace_uprobe.c | 52 |
4 files changed, 129 insertions, 81 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index d2a4fd2fd8c1..f94a56915e69 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -148,6 +148,83 @@ DEFINE_BASIC_FETCH_FUNCS(stack) | |||
148 | #define fetch_stack_string NULL | 148 | #define fetch_stack_string NULL |
149 | #define fetch_stack_string_size NULL | 149 | #define fetch_stack_string_size NULL |
150 | 150 | ||
151 | #define DEFINE_FETCH_memory(type) \ | ||
152 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | ||
153 | void *addr, void *dest) \ | ||
154 | { \ | ||
155 | type retval; \ | ||
156 | if (probe_kernel_address(addr, retval)) \ | ||
157 | *(type *)dest = 0; \ | ||
158 | else \ | ||
159 | *(type *)dest = retval; \ | ||
160 | } | ||
161 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
162 | /* | ||
163 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | ||
164 | * length and relative data location. | ||
165 | */ | ||
166 | static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | ||
167 | void *addr, void *dest) | ||
168 | { | ||
169 | long ret; | ||
170 | int maxlen = get_rloc_len(*(u32 *)dest); | ||
171 | u8 *dst = get_rloc_data(dest); | ||
172 | u8 *src = addr; | ||
173 | mm_segment_t old_fs = get_fs(); | ||
174 | |||
175 | if (!maxlen) | ||
176 | return; | ||
177 | |||
178 | /* | ||
179 | * Try to get string again, since the string can be changed while | ||
180 | * probing. | ||
181 | */ | ||
182 | set_fs(KERNEL_DS); | ||
183 | pagefault_disable(); | ||
184 | |||
185 | do | ||
186 | ret = __copy_from_user_inatomic(dst++, src++, 1); | ||
187 | while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen); | ||
188 | |||
189 | dst[-1] = '\0'; | ||
190 | pagefault_enable(); | ||
191 | set_fs(old_fs); | ||
192 | |||
193 | if (ret < 0) { /* Failed to fetch string */ | ||
194 | ((u8 *)get_rloc_data(dest))[0] = '\0'; | ||
195 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); | ||
196 | } else { | ||
197 | *(u32 *)dest = make_data_rloc(src - (u8 *)addr, | ||
198 | get_rloc_offs(*(u32 *)dest)); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | /* Return the length of string -- including null terminal byte */ | ||
203 | static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | ||
204 | void *addr, void *dest) | ||
205 | { | ||
206 | mm_segment_t old_fs; | ||
207 | int ret, len = 0; | ||
208 | u8 c; | ||
209 | |||
210 | old_fs = get_fs(); | ||
211 | set_fs(KERNEL_DS); | ||
212 | pagefault_disable(); | ||
213 | |||
214 | do { | ||
215 | ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); | ||
216 | len++; | ||
217 | } while (c && ret == 0 && len < MAX_STRING_SIZE); | ||
218 | |||
219 | pagefault_enable(); | ||
220 | set_fs(old_fs); | ||
221 | |||
222 | if (ret < 0) /* Failed to check the length */ | ||
223 | *(u32 *)dest = 0; | ||
224 | else | ||
225 | *(u32 *)dest = len; | ||
226 | } | ||
227 | |||
151 | #define DEFINE_FETCH_symbol(type) \ | 228 | #define DEFINE_FETCH_symbol(type) \ |
152 | __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \ | 229 | __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \ |
153 | void *data, void *dest) \ | 230 | void *data, void *dest) \ |
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 8d7231d436da..8f7a2b6d389d 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
@@ -103,83 +103,6 @@ DEFINE_BASIC_FETCH_FUNCS(retval) | |||
103 | #define fetch_retval_string NULL | 103 | #define fetch_retval_string NULL |
104 | #define fetch_retval_string_size NULL | 104 | #define fetch_retval_string_size NULL |
105 | 105 | ||
106 | #define DEFINE_FETCH_memory(type) \ | ||
107 | __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ | ||
108 | void *addr, void *dest) \ | ||
109 | { \ | ||
110 | type retval; \ | ||
111 | if (probe_kernel_address(addr, retval)) \ | ||
112 | *(type *)dest = 0; \ | ||
113 | else \ | ||
114 | *(type *)dest = retval; \ | ||
115 | } | ||
116 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
117 | /* | ||
118 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | ||
119 | * length and relative data location. | ||
120 | */ | ||
121 | __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | ||
122 | void *addr, void *dest) | ||
123 | { | ||
124 | long ret; | ||
125 | int maxlen = get_rloc_len(*(u32 *)dest); | ||
126 | u8 *dst = get_rloc_data(dest); | ||
127 | u8 *src = addr; | ||
128 | mm_segment_t old_fs = get_fs(); | ||
129 | |||
130 | if (!maxlen) | ||
131 | return; | ||
132 | |||
133 | /* | ||
134 | * Try to get string again, since the string can be changed while | ||
135 | * probing. | ||
136 | */ | ||
137 | set_fs(KERNEL_DS); | ||
138 | pagefault_disable(); | ||
139 | |||
140 | do | ||
141 | ret = __copy_from_user_inatomic(dst++, src++, 1); | ||
142 | while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen); | ||
143 | |||
144 | dst[-1] = '\0'; | ||
145 | pagefault_enable(); | ||
146 | set_fs(old_fs); | ||
147 | |||
148 | if (ret < 0) { /* Failed to fetch string */ | ||
149 | ((u8 *)get_rloc_data(dest))[0] = '\0'; | ||
150 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); | ||
151 | } else { | ||
152 | *(u32 *)dest = make_data_rloc(src - (u8 *)addr, | ||
153 | get_rloc_offs(*(u32 *)dest)); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | /* Return the length of string -- including null terminal byte */ | ||
158 | __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | ||
159 | void *addr, void *dest) | ||
160 | { | ||
161 | mm_segment_t old_fs; | ||
162 | int ret, len = 0; | ||
163 | u8 c; | ||
164 | |||
165 | old_fs = get_fs(); | ||
166 | set_fs(KERNEL_DS); | ||
167 | pagefault_disable(); | ||
168 | |||
169 | do { | ||
170 | ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); | ||
171 | len++; | ||
172 | } while (c && ret == 0 && len < MAX_STRING_SIZE); | ||
173 | |||
174 | pagefault_enable(); | ||
175 | set_fs(old_fs); | ||
176 | |||
177 | if (ret < 0) /* Failed to check the length */ | ||
178 | *(u32 *)dest = 0; | ||
179 | else | ||
180 | *(u32 *)dest = len; | ||
181 | } | ||
182 | |||
183 | /* Dereference memory access function */ | 106 | /* Dereference memory access function */ |
184 | struct deref_fetch_param { | 107 | struct deref_fetch_param { |
185 | struct fetch_param orig; | 108 | struct fetch_param orig; |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 8be84550ceb3..2d5b8f5f5310 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
@@ -171,10 +171,6 @@ DECLARE_BASIC_FETCH_FUNCS(retval); | |||
171 | #define fetch_retval_string NULL | 171 | #define fetch_retval_string NULL |
172 | #define fetch_retval_string_size NULL | 172 | #define fetch_retval_string_size NULL |
173 | 173 | ||
174 | DECLARE_BASIC_FETCH_FUNCS(memory); | ||
175 | DECLARE_FETCH_FUNC(memory, string); | ||
176 | DECLARE_FETCH_FUNC(memory, string_size); | ||
177 | |||
178 | DECLARE_BASIC_FETCH_FUNCS(symbol); | 174 | DECLARE_BASIC_FETCH_FUNCS(symbol); |
179 | DECLARE_FETCH_FUNC(symbol, string); | 175 | DECLARE_FETCH_FUNC(symbol, string); |
180 | DECLARE_FETCH_FUNC(symbol, string_size); | 176 | DECLARE_FETCH_FUNC(symbol, string_size); |
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 24ef6a33d93f..bebd2f5d9ea3 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -114,6 +114,58 @@ DEFINE_BASIC_FETCH_FUNCS(stack) | |||
114 | #define fetch_stack_string NULL | 114 | #define fetch_stack_string NULL |
115 | #define fetch_stack_string_size NULL | 115 | #define fetch_stack_string_size NULL |
116 | 116 | ||
117 | #define DEFINE_FETCH_memory(type) \ | ||
118 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | ||
119 | void *addr, void *dest) \ | ||
120 | { \ | ||
121 | type retval; \ | ||
122 | void __user *vaddr = (void __force __user *) addr; \ | ||
123 | \ | ||
124 | if (copy_from_user(&retval, vaddr, sizeof(type))) \ | ||
125 | *(type *)dest = 0; \ | ||
126 | else \ | ||
127 | *(type *) dest = retval; \ | ||
128 | } | ||
129 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
130 | /* | ||
131 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | ||
132 | * length and relative data location. | ||
133 | */ | ||
134 | static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | ||
135 | void *addr, void *dest) | ||
136 | { | ||
137 | long ret; | ||
138 | u32 rloc = *(u32 *)dest; | ||
139 | int maxlen = get_rloc_len(rloc); | ||
140 | u8 *dst = get_rloc_data(dest); | ||
141 | void __user *src = (void __force __user *) addr; | ||
142 | |||
143 | if (!maxlen) | ||
144 | return; | ||
145 | |||
146 | ret = strncpy_from_user(dst, src, maxlen); | ||
147 | |||
148 | if (ret < 0) { /* Failed to fetch string */ | ||
149 | ((u8 *)get_rloc_data(dest))[0] = '\0'; | ||
150 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc)); | ||
151 | } else { | ||
152 | *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc)); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | ||
157 | void *addr, void *dest) | ||
158 | { | ||
159 | int len; | ||
160 | void __user *vaddr = (void __force __user *) addr; | ||
161 | |||
162 | len = strnlen_user(vaddr, MAX_STRING_SIZE); | ||
163 | |||
164 | if (len == 0 || len > MAX_STRING_SIZE) /* Failed to check length */ | ||
165 | *(u32 *)dest = 0; | ||
166 | else | ||
167 | *(u32 *)dest = len; | ||
168 | } | ||
117 | 169 | ||
118 | /* uprobes do not support symbol fetch methods */ | 170 | /* uprobes do not support symbol fetch methods */ |
119 | #define fetch_symbol_u8 NULL | 171 | #define fetch_symbol_u8 NULL |