diff options
Diffstat (limited to 'kernel/trace/trace_kprobe.c')
-rw-r--r-- | kernel/trace/trace_kprobe.c | 77 |
1 files changed, 77 insertions, 0 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) \ |