diff options
author | Masami Hiramatsu <mhiramat@kernel.org> | 2018-04-25 08:18:03 -0400 |
---|---|---|
committer | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2018-10-10 22:19:07 -0400 |
commit | 533059281ee594f9fbb9e58042aaec77083ef251 (patch) | |
tree | 92019727bc72f3253f5e9de7152ced000cc4f27b | |
parent | 7bfbc63eda08b8158c040d6882c807f62b0750bb (diff) |
tracing: probeevent: Introduce new argument fetching code
Replace {k,u}probe event argument fetching framework with switch-case based.
Currently that is implemented with structures, macros and chain of
function-pointers, which is more complicated than necessary and may get a
performance penalty by retpoline.
This simplify that with an array of "fetch_insn" (opcode and oprands), and
make process_fetch_insn() just interprets it. No function pointers are used.
Link: http://lkml.kernel.org/r/152465868340.26224.2551120475197839464.stgit@devbox
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-rw-r--r-- | kernel/trace/trace_kprobe.c | 291 | ||||
-rw-r--r-- | kernel/trace/trace_probe.c | 401 | ||||
-rw-r--r-- | kernel/trace/trace_probe.h | 230 | ||||
-rw-r--r-- | kernel/trace/trace_probe_tmpl.h | 120 | ||||
-rw-r--r-- | kernel/trace/trace_uprobe.c | 127 |
5 files changed, 491 insertions, 678 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 1356927e32d0..c024cc40d509 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #include "trace_kprobe_selftest.h" | 15 | #include "trace_kprobe_selftest.h" |
16 | #include "trace_probe.h" | 16 | #include "trace_probe.h" |
17 | #include "trace_probe_tmpl.h" | ||
17 | 18 | ||
18 | #define KPROBE_EVENT_SYSTEM "kprobes" | 19 | #define KPROBE_EVENT_SYSTEM "kprobes" |
19 | #define KRETPROBE_MAXACTIVE_MAX 4096 | 20 | #define KRETPROBE_MAXACTIVE_MAX 4096 |
@@ -120,160 +121,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); | |||
120 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, | 121 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, |
121 | struct pt_regs *regs); | 122 | struct pt_regs *regs); |
122 | 123 | ||
123 | /* Memory fetching by symbol */ | ||
124 | struct symbol_cache { | ||
125 | char *symbol; | ||
126 | long offset; | ||
127 | unsigned long addr; | ||
128 | }; | ||
129 | |||
130 | unsigned long update_symbol_cache(struct symbol_cache *sc) | ||
131 | { | ||
132 | sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol); | ||
133 | |||
134 | if (sc->addr) | ||
135 | sc->addr += sc->offset; | ||
136 | |||
137 | return sc->addr; | ||
138 | } | ||
139 | |||
140 | void free_symbol_cache(struct symbol_cache *sc) | ||
141 | { | ||
142 | kfree(sc->symbol); | ||
143 | kfree(sc); | ||
144 | } | ||
145 | |||
146 | struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) | ||
147 | { | ||
148 | struct symbol_cache *sc; | ||
149 | |||
150 | if (!sym || strlen(sym) == 0) | ||
151 | return NULL; | ||
152 | |||
153 | sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL); | ||
154 | if (!sc) | ||
155 | return NULL; | ||
156 | |||
157 | sc->symbol = kstrdup(sym, GFP_KERNEL); | ||
158 | if (!sc->symbol) { | ||
159 | kfree(sc); | ||
160 | return NULL; | ||
161 | } | ||
162 | sc->offset = offset; | ||
163 | update_symbol_cache(sc); | ||
164 | |||
165 | return sc; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Kprobes-specific fetch functions | ||
170 | */ | ||
171 | #define DEFINE_FETCH_stack(type) \ | ||
172 | static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ | ||
173 | void *offset, void *dest) \ | ||
174 | { \ | ||
175 | *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ | ||
176 | (unsigned int)((unsigned long)offset)); \ | ||
177 | } \ | ||
178 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(stack, type)); | ||
179 | |||
180 | DEFINE_BASIC_FETCH_FUNCS(stack) | ||
181 | /* No string on the stack entry */ | ||
182 | #define fetch_stack_string NULL | ||
183 | #define fetch_stack_string_size NULL | ||
184 | |||
185 | #define DEFINE_FETCH_memory(type) \ | ||
186 | static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ | ||
187 | void *addr, void *dest) \ | ||
188 | { \ | ||
189 | type retval; \ | ||
190 | if (probe_kernel_address(addr, retval)) \ | ||
191 | *(type *)dest = 0; \ | ||
192 | else \ | ||
193 | *(type *)dest = retval; \ | ||
194 | } \ | ||
195 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, type)); | ||
196 | |||
197 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
198 | /* | ||
199 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | ||
200 | * length and relative data location. | ||
201 | */ | ||
202 | static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | ||
203 | void *addr, void *dest) | ||
204 | { | ||
205 | int maxlen = get_rloc_len(*(u32 *)dest); | ||
206 | u8 *dst = get_rloc_data(dest); | ||
207 | long ret; | ||
208 | |||
209 | if (!maxlen) | ||
210 | return; | ||
211 | |||
212 | /* | ||
213 | * Try to get string again, since the string can be changed while | ||
214 | * probing. | ||
215 | */ | ||
216 | ret = strncpy_from_unsafe(dst, addr, maxlen); | ||
217 | |||
218 | if (ret < 0) { /* Failed to fetch string */ | ||
219 | dst[0] = '\0'; | ||
220 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); | ||
221 | } else { | ||
222 | *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); | ||
223 | } | ||
224 | } | ||
225 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string)); | ||
226 | |||
227 | /* Return the length of string -- including null terminal byte */ | ||
228 | static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | ||
229 | void *addr, void *dest) | ||
230 | { | ||
231 | mm_segment_t old_fs; | ||
232 | int ret, len = 0; | ||
233 | u8 c; | ||
234 | |||
235 | old_fs = get_fs(); | ||
236 | set_fs(KERNEL_DS); | ||
237 | pagefault_disable(); | ||
238 | |||
239 | do { | ||
240 | ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); | ||
241 | len++; | ||
242 | } while (c && ret == 0 && len < MAX_STRING_SIZE); | ||
243 | |||
244 | pagefault_enable(); | ||
245 | set_fs(old_fs); | ||
246 | |||
247 | if (ret < 0) /* Failed to check the length */ | ||
248 | *(u32 *)dest = 0; | ||
249 | else | ||
250 | *(u32 *)dest = len; | ||
251 | } | ||
252 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string_size)); | ||
253 | |||
254 | #define DEFINE_FETCH_symbol(type) \ | ||
255 | void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, void *data, void *dest)\ | ||
256 | { \ | ||
257 | struct symbol_cache *sc = data; \ | ||
258 | if (sc->addr) \ | ||
259 | fetch_memory_##type(regs, (void *)sc->addr, dest); \ | ||
260 | else \ | ||
261 | *(type *)dest = 0; \ | ||
262 | } \ | ||
263 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(symbol, type)); | ||
264 | |||
265 | DEFINE_BASIC_FETCH_FUNCS(symbol) | ||
266 | DEFINE_FETCH_symbol(string) | ||
267 | DEFINE_FETCH_symbol(string_size) | ||
268 | |||
269 | /* kprobes don't support file_offset fetch methods */ | ||
270 | #define fetch_file_offset_u8 NULL | ||
271 | #define fetch_file_offset_u16 NULL | ||
272 | #define fetch_file_offset_u32 NULL | ||
273 | #define fetch_file_offset_u64 NULL | ||
274 | #define fetch_file_offset_string NULL | ||
275 | #define fetch_file_offset_string_size NULL | ||
276 | |||
277 | /* Fetch type information table */ | 124 | /* Fetch type information table */ |
278 | static const struct fetch_type kprobes_fetch_type_table[] = { | 125 | static const struct fetch_type kprobes_fetch_type_table[] = { |
279 | /* Special types */ | 126 | /* Special types */ |
@@ -529,7 +376,7 @@ static bool within_notrace_func(struct trace_kprobe *tk) | |||
529 | /* Internal register function - just handle k*probes and flags */ | 376 | /* Internal register function - just handle k*probes and flags */ |
530 | static int __register_trace_kprobe(struct trace_kprobe *tk) | 377 | static int __register_trace_kprobe(struct trace_kprobe *tk) |
531 | { | 378 | { |
532 | int i, ret; | 379 | int ret; |
533 | 380 | ||
534 | if (trace_probe_is_registered(&tk->tp)) | 381 | if (trace_probe_is_registered(&tk->tp)) |
535 | return -EINVAL; | 382 | return -EINVAL; |
@@ -540,9 +387,6 @@ static int __register_trace_kprobe(struct trace_kprobe *tk) | |||
540 | return -EINVAL; | 387 | return -EINVAL; |
541 | } | 388 | } |
542 | 389 | ||
543 | for (i = 0; i < tk->tp.nr_args; i++) | ||
544 | traceprobe_update_arg(&tk->tp.args[i]); | ||
545 | |||
546 | /* Set/clear disabled flag according to tp->flag */ | 390 | /* Set/clear disabled flag according to tp->flag */ |
547 | if (trace_probe_is_enabled(&tk->tp)) | 391 | if (trace_probe_is_enabled(&tk->tp)) |
548 | tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; | 392 | tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; |
@@ -876,8 +720,8 @@ static int create_trace_kprobe(int argc, char **argv) | |||
876 | 720 | ||
877 | /* Parse fetch argument */ | 721 | /* Parse fetch argument */ |
878 | ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg, | 722 | ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg, |
879 | is_return, true, | 723 | is_return, true, |
880 | kprobes_fetch_type_table); | 724 | kprobes_fetch_type_table); |
881 | if (ret) { | 725 | if (ret) { |
882 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | 726 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
883 | goto error; | 727 | goto error; |
@@ -1031,6 +875,133 @@ static const struct file_operations kprobe_profile_ops = { | |||
1031 | .release = seq_release, | 875 | .release = seq_release, |
1032 | }; | 876 | }; |
1033 | 877 | ||
878 | /* Kprobe specific fetch functions */ | ||
879 | |||
880 | /* Return the length of string -- including null terminal byte */ | ||
881 | static nokprobe_inline void | ||
882 | fetch_store_strlen(unsigned long addr, void *dest) | ||
883 | { | ||
884 | mm_segment_t old_fs; | ||
885 | int ret, len = 0; | ||
886 | u8 c; | ||
887 | |||
888 | old_fs = get_fs(); | ||
889 | set_fs(KERNEL_DS); | ||
890 | pagefault_disable(); | ||
891 | |||
892 | do { | ||
893 | ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); | ||
894 | len++; | ||
895 | } while (c && ret == 0 && len < MAX_STRING_SIZE); | ||
896 | |||
897 | pagefault_enable(); | ||
898 | set_fs(old_fs); | ||
899 | |||
900 | if (ret < 0) /* Failed to check the length */ | ||
901 | *(u32 *)dest = 0; | ||
902 | else | ||
903 | *(u32 *)dest = len; | ||
904 | } | ||
905 | |||
906 | /* | ||
907 | * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max | ||
908 | * length and relative data location. | ||
909 | */ | ||
910 | static nokprobe_inline void | ||
911 | fetch_store_string(unsigned long addr, void *dest) | ||
912 | { | ||
913 | int maxlen = get_rloc_len(*(u32 *)dest); | ||
914 | u8 *dst = get_rloc_data(dest); | ||
915 | long ret; | ||
916 | |||
917 | if (!maxlen) | ||
918 | return; | ||
919 | |||
920 | /* | ||
921 | * Try to get string again, since the string can be changed while | ||
922 | * probing. | ||
923 | */ | ||
924 | ret = strncpy_from_unsafe(dst, (void *)addr, maxlen); | ||
925 | |||
926 | if (ret < 0) { /* Failed to fetch string */ | ||
927 | dst[0] = '\0'; | ||
928 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); | ||
929 | } else { | ||
930 | *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | /* Note that we don't verify it, since the code does not come from user space */ | ||
935 | static int | ||
936 | process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, | ||
937 | bool pre) | ||
938 | { | ||
939 | unsigned long val; | ||
940 | int ret; | ||
941 | |||
942 | /* 1st stage: get value from context */ | ||
943 | switch (code->op) { | ||
944 | case FETCH_OP_REG: | ||
945 | val = regs_get_register(regs, code->param); | ||
946 | break; | ||
947 | case FETCH_OP_STACK: | ||
948 | val = regs_get_kernel_stack_nth(regs, code->param); | ||
949 | break; | ||
950 | case FETCH_OP_STACKP: | ||
951 | val = kernel_stack_pointer(regs); | ||
952 | break; | ||
953 | case FETCH_OP_RETVAL: | ||
954 | val = regs_return_value(regs); | ||
955 | break; | ||
956 | case FETCH_OP_IMM: | ||
957 | val = code->immediate; | ||
958 | break; | ||
959 | case FETCH_OP_COMM: | ||
960 | val = (unsigned long)current->comm; | ||
961 | break; | ||
962 | default: | ||
963 | return -EILSEQ; | ||
964 | } | ||
965 | code++; | ||
966 | |||
967 | /* 2nd stage: dereference memory if needed */ | ||
968 | while (code->op == FETCH_OP_DEREF) { | ||
969 | ret = probe_kernel_read(&val, (void *)val + code->offset, | ||
970 | sizeof(val)); | ||
971 | if (ret) | ||
972 | return ret; | ||
973 | code++; | ||
974 | } | ||
975 | |||
976 | /* 3rd stage: store value to buffer */ | ||
977 | switch (code->op) { | ||
978 | case FETCH_OP_ST_RAW: | ||
979 | fetch_store_raw(val, code, dest); | ||
980 | break; | ||
981 | case FETCH_OP_ST_MEM: | ||
982 | probe_kernel_read(dest, (void *)val + code->offset, code->size); | ||
983 | break; | ||
984 | case FETCH_OP_ST_STRING: | ||
985 | if (pre) | ||
986 | fetch_store_strlen(val + code->offset, dest); | ||
987 | else | ||
988 | fetch_store_string(val + code->offset, dest); | ||
989 | break; | ||
990 | default: | ||
991 | return -EILSEQ; | ||
992 | } | ||
993 | code++; | ||
994 | |||
995 | /* 4th stage: modify stored value if needed */ | ||
996 | if (code->op == FETCH_OP_MOD_BF) { | ||
997 | fetch_apply_bitfield(code, dest); | ||
998 | code++; | ||
999 | } | ||
1000 | |||
1001 | return code->op == FETCH_OP_END ? 0 : -EILSEQ; | ||
1002 | } | ||
1003 | NOKPROBE_SYMBOL(process_fetch_insn) | ||
1004 | |||
1034 | /* Kprobe handler */ | 1005 | /* Kprobe handler */ |
1035 | static nokprobe_inline void | 1006 | static nokprobe_inline void |
1036 | __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, | 1007 | __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, |
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 5f3b5b3fd2cd..c59c69cb2f2e 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
@@ -61,174 +61,6 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) | |||
61 | 61 | ||
62 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; | 62 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
63 | 63 | ||
64 | #define CHECK_FETCH_FUNCS(method, fn) \ | ||
65 | (((FETCH_FUNC_NAME(method, u8) == fn) || \ | ||
66 | (FETCH_FUNC_NAME(method, u16) == fn) || \ | ||
67 | (FETCH_FUNC_NAME(method, u32) == fn) || \ | ||
68 | (FETCH_FUNC_NAME(method, u64) == fn) || \ | ||
69 | (FETCH_FUNC_NAME(method, string) == fn) || \ | ||
70 | (FETCH_FUNC_NAME(method, string_size) == fn)) \ | ||
71 | && (fn != NULL)) | ||
72 | |||
73 | /* Data fetch function templates */ | ||
74 | #define DEFINE_FETCH_reg(type) \ | ||
75 | void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \ | ||
76 | { \ | ||
77 | *(type *)dest = (type)regs_get_register(regs, \ | ||
78 | (unsigned int)((unsigned long)offset)); \ | ||
79 | } \ | ||
80 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type)); | ||
81 | DEFINE_BASIC_FETCH_FUNCS(reg) | ||
82 | /* No string on the register */ | ||
83 | #define fetch_reg_string NULL | ||
84 | #define fetch_reg_string_size NULL | ||
85 | |||
86 | #define DEFINE_FETCH_retval(type) \ | ||
87 | void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ | ||
88 | void *dummy, void *dest) \ | ||
89 | { \ | ||
90 | *(type *)dest = (type)regs_return_value(regs); \ | ||
91 | } \ | ||
92 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type)); | ||
93 | DEFINE_BASIC_FETCH_FUNCS(retval) | ||
94 | /* No string on the retval */ | ||
95 | #define fetch_retval_string NULL | ||
96 | #define fetch_retval_string_size NULL | ||
97 | |||
98 | /* Dereference memory access function */ | ||
99 | struct deref_fetch_param { | ||
100 | struct fetch_param orig; | ||
101 | long offset; | ||
102 | fetch_func_t fetch; | ||
103 | fetch_func_t fetch_size; | ||
104 | }; | ||
105 | |||
106 | #define DEFINE_FETCH_deref(type) \ | ||
107 | void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ | ||
108 | void *data, void *dest) \ | ||
109 | { \ | ||
110 | struct deref_fetch_param *dprm = data; \ | ||
111 | unsigned long addr; \ | ||
112 | call_fetch(&dprm->orig, regs, &addr); \ | ||
113 | if (addr) { \ | ||
114 | addr += dprm->offset; \ | ||
115 | dprm->fetch(regs, (void *)addr, dest); \ | ||
116 | } else \ | ||
117 | *(type *)dest = 0; \ | ||
118 | } \ | ||
119 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type)); | ||
120 | DEFINE_BASIC_FETCH_FUNCS(deref) | ||
121 | DEFINE_FETCH_deref(string) | ||
122 | |||
123 | void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, | ||
124 | void *data, void *dest) | ||
125 | { | ||
126 | struct deref_fetch_param *dprm = data; | ||
127 | unsigned long addr; | ||
128 | |||
129 | call_fetch(&dprm->orig, regs, &addr); | ||
130 | if (addr && dprm->fetch_size) { | ||
131 | addr += dprm->offset; | ||
132 | dprm->fetch_size(regs, (void *)addr, dest); | ||
133 | } else | ||
134 | *(string_size *)dest = 0; | ||
135 | } | ||
136 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size)); | ||
137 | |||
138 | static void update_deref_fetch_param(struct deref_fetch_param *data) | ||
139 | { | ||
140 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | ||
141 | update_deref_fetch_param(data->orig.data); | ||
142 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | ||
143 | update_symbol_cache(data->orig.data); | ||
144 | } | ||
145 | NOKPROBE_SYMBOL(update_deref_fetch_param); | ||
146 | |||
147 | static void free_deref_fetch_param(struct deref_fetch_param *data) | ||
148 | { | ||
149 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | ||
150 | free_deref_fetch_param(data->orig.data); | ||
151 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | ||
152 | free_symbol_cache(data->orig.data); | ||
153 | kfree(data); | ||
154 | } | ||
155 | NOKPROBE_SYMBOL(free_deref_fetch_param); | ||
156 | |||
157 | /* Bitfield fetch function */ | ||
158 | struct bitfield_fetch_param { | ||
159 | struct fetch_param orig; | ||
160 | unsigned char hi_shift; | ||
161 | unsigned char low_shift; | ||
162 | }; | ||
163 | |||
164 | #define DEFINE_FETCH_bitfield(type) \ | ||
165 | void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ | ||
166 | void *data, void *dest) \ | ||
167 | { \ | ||
168 | struct bitfield_fetch_param *bprm = data; \ | ||
169 | type buf = 0; \ | ||
170 | call_fetch(&bprm->orig, regs, &buf); \ | ||
171 | if (buf) { \ | ||
172 | buf <<= bprm->hi_shift; \ | ||
173 | buf >>= bprm->low_shift; \ | ||
174 | } \ | ||
175 | *(type *)dest = buf; \ | ||
176 | } \ | ||
177 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type)); | ||
178 | DEFINE_BASIC_FETCH_FUNCS(bitfield) | ||
179 | #define fetch_bitfield_string NULL | ||
180 | #define fetch_bitfield_string_size NULL | ||
181 | |||
182 | static void | ||
183 | update_bitfield_fetch_param(struct bitfield_fetch_param *data) | ||
184 | { | ||
185 | /* | ||
186 | * Don't check the bitfield itself, because this must be the | ||
187 | * last fetch function. | ||
188 | */ | ||
189 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | ||
190 | update_deref_fetch_param(data->orig.data); | ||
191 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | ||
192 | update_symbol_cache(data->orig.data); | ||
193 | } | ||
194 | |||
195 | static void | ||
196 | free_bitfield_fetch_param(struct bitfield_fetch_param *data) | ||
197 | { | ||
198 | /* | ||
199 | * Don't check the bitfield itself, because this must be the | ||
200 | * last fetch function. | ||
201 | */ | ||
202 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | ||
203 | free_deref_fetch_param(data->orig.data); | ||
204 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | ||
205 | free_symbol_cache(data->orig.data); | ||
206 | |||
207 | kfree(data); | ||
208 | } | ||
209 | |||
210 | void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs, | ||
211 | void *data, void *dest) | ||
212 | { | ||
213 | int maxlen = get_rloc_len(*(u32 *)dest); | ||
214 | u8 *dst = get_rloc_data(dest); | ||
215 | long ret; | ||
216 | |||
217 | if (!maxlen) | ||
218 | return; | ||
219 | |||
220 | ret = strlcpy(dst, current->comm, maxlen); | ||
221 | *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); | ||
222 | } | ||
223 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string)); | ||
224 | |||
225 | void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs, | ||
226 | void *data, void *dest) | ||
227 | { | ||
228 | *(u32 *)dest = strlen(current->comm) + 1; | ||
229 | } | ||
230 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size)); | ||
231 | |||
232 | static const struct fetch_type *find_fetch_type(const char *type, | 64 | static const struct fetch_type *find_fetch_type(const char *type, |
233 | const struct fetch_type *ftbl) | 65 | const struct fetch_type *ftbl) |
234 | { | 66 | { |
@@ -272,37 +104,6 @@ fail: | |||
272 | return NULL; | 104 | return NULL; |
273 | } | 105 | } |
274 | 106 | ||
275 | /* Special function : only accept unsigned long */ | ||
276 | static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest) | ||
277 | { | ||
278 | *(unsigned long *)dest = kernel_stack_pointer(regs); | ||
279 | } | ||
280 | NOKPROBE_SYMBOL(fetch_kernel_stack_address); | ||
281 | |||
282 | static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest) | ||
283 | { | ||
284 | *(unsigned long *)dest = user_stack_pointer(regs); | ||
285 | } | ||
286 | NOKPROBE_SYMBOL(fetch_user_stack_address); | ||
287 | |||
288 | static fetch_func_t get_fetch_size_function(const struct fetch_type *type, | ||
289 | fetch_func_t orig_fn, | ||
290 | const struct fetch_type *ftbl) | ||
291 | { | ||
292 | int i; | ||
293 | |||
294 | if (type != &ftbl[FETCH_TYPE_STRING]) | ||
295 | return NULL; /* Only string type needs size function */ | ||
296 | |||
297 | for (i = 0; i < FETCH_MTD_END; i++) | ||
298 | if (type->fetch[i] == orig_fn) | ||
299 | return ftbl[FETCH_TYPE_STRSIZE].fetch[i]; | ||
300 | |||
301 | WARN_ON(1); /* This should not happen */ | ||
302 | |||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | /* Split symbol and offset. */ | 107 | /* Split symbol and offset. */ |
307 | int traceprobe_split_symbol_offset(char *symbol, long *offset) | 108 | int traceprobe_split_symbol_offset(char *symbol, long *offset) |
308 | { | 109 | { |
@@ -327,7 +128,7 @@ int traceprobe_split_symbol_offset(char *symbol, long *offset) | |||
327 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | 128 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
328 | 129 | ||
329 | static int parse_probe_vars(char *arg, const struct fetch_type *t, | 130 | static int parse_probe_vars(char *arg, const struct fetch_type *t, |
330 | struct fetch_param *f, bool is_return, | 131 | struct fetch_insn *code, bool is_return, |
331 | bool is_kprobe) | 132 | bool is_kprobe) |
332 | { | 133 | { |
333 | int ret = 0; | 134 | int ret = 0; |
@@ -335,33 +136,24 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, | |||
335 | 136 | ||
336 | if (strcmp(arg, "retval") == 0) { | 137 | if (strcmp(arg, "retval") == 0) { |
337 | if (is_return) | 138 | if (is_return) |
338 | f->fn = t->fetch[FETCH_MTD_retval]; | 139 | code->op = FETCH_OP_RETVAL; |
339 | else | 140 | else |
340 | ret = -EINVAL; | 141 | ret = -EINVAL; |
341 | } else if (strncmp(arg, "stack", 5) == 0) { | 142 | } else if (strncmp(arg, "stack", 5) == 0) { |
342 | if (arg[5] == '\0') { | 143 | if (arg[5] == '\0') { |
343 | if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR)) | 144 | code->op = FETCH_OP_STACKP; |
344 | return -EINVAL; | ||
345 | |||
346 | if (is_kprobe) | ||
347 | f->fn = fetch_kernel_stack_address; | ||
348 | else | ||
349 | f->fn = fetch_user_stack_address; | ||
350 | } else if (isdigit(arg[5])) { | 145 | } else if (isdigit(arg[5])) { |
351 | ret = kstrtoul(arg + 5, 10, ¶m); | 146 | ret = kstrtoul(arg + 5, 10, ¶m); |
352 | if (ret || (is_kprobe && param > PARAM_MAX_STACK)) | 147 | if (ret || (is_kprobe && param > PARAM_MAX_STACK)) |
353 | ret = -EINVAL; | 148 | ret = -EINVAL; |
354 | else { | 149 | else { |
355 | f->fn = t->fetch[FETCH_MTD_stack]; | 150 | code->op = FETCH_OP_STACK; |
356 | f->data = (void *)param; | 151 | code->param = (unsigned int)param; |
357 | } | 152 | } |
358 | } else | 153 | } else |
359 | ret = -EINVAL; | 154 | ret = -EINVAL; |
360 | } else if (strcmp(arg, "comm") == 0) { | 155 | } else if (strcmp(arg, "comm") == 0) { |
361 | if (strcmp(t->name, "string") != 0 && | 156 | code->op = FETCH_OP_COMM; |
362 | strcmp(t->name, "string_size") != 0) | ||
363 | return -EINVAL; | ||
364 | f->fn = t->fetch[FETCH_MTD_comm]; | ||
365 | } else | 157 | } else |
366 | ret = -EINVAL; | 158 | ret = -EINVAL; |
367 | 159 | ||
@@ -369,10 +161,13 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, | |||
369 | } | 161 | } |
370 | 162 | ||
371 | /* Recursive argument parser */ | 163 | /* Recursive argument parser */ |
372 | static int parse_probe_arg(char *arg, const struct fetch_type *t, | 164 | static int |
373 | struct fetch_param *f, bool is_return, bool is_kprobe, | 165 | parse_probe_arg(char *arg, const struct fetch_type *type, |
374 | const struct fetch_type *ftbl) | 166 | struct fetch_insn **pcode, struct fetch_insn *end, |
167 | bool is_return, bool is_kprobe, | ||
168 | const struct fetch_type *ftbl) | ||
375 | { | 169 | { |
170 | struct fetch_insn *code = *pcode; | ||
376 | unsigned long param; | 171 | unsigned long param; |
377 | long offset; | 172 | long offset; |
378 | char *tmp; | 173 | char *tmp; |
@@ -380,14 +175,15 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
380 | 175 | ||
381 | switch (arg[0]) { | 176 | switch (arg[0]) { |
382 | case '$': | 177 | case '$': |
383 | ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); | 178 | ret = parse_probe_vars(arg + 1, type, code, |
179 | is_return, is_kprobe); | ||
384 | break; | 180 | break; |
385 | 181 | ||
386 | case '%': /* named register */ | 182 | case '%': /* named register */ |
387 | ret = regs_query_register_offset(arg + 1); | 183 | ret = regs_query_register_offset(arg + 1); |
388 | if (ret >= 0) { | 184 | if (ret >= 0) { |
389 | f->fn = t->fetch[FETCH_MTD_reg]; | 185 | code->op = FETCH_OP_REG; |
390 | f->data = (void *)(unsigned long)ret; | 186 | code->param = (unsigned int)ret; |
391 | ret = 0; | 187 | ret = 0; |
392 | } | 188 | } |
393 | break; | 189 | break; |
@@ -397,9 +193,9 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
397 | ret = kstrtoul(arg + 1, 0, ¶m); | 193 | ret = kstrtoul(arg + 1, 0, ¶m); |
398 | if (ret) | 194 | if (ret) |
399 | break; | 195 | break; |
400 | 196 | /* load address */ | |
401 | f->fn = t->fetch[FETCH_MTD_memory]; | 197 | code->op = FETCH_OP_IMM; |
402 | f->data = (void *)param; | 198 | code->immediate = param; |
403 | } else if (arg[1] == '+') { | 199 | } else if (arg[1] == '+') { |
404 | /* kprobes don't support file offsets */ | 200 | /* kprobes don't support file offsets */ |
405 | if (is_kprobe) | 201 | if (is_kprobe) |
@@ -409,8 +205,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
409 | if (ret) | 205 | if (ret) |
410 | break; | 206 | break; |
411 | 207 | ||
412 | f->fn = t->fetch[FETCH_MTD_file_offset]; | 208 | code->op = FETCH_OP_FOFFS; |
413 | f->data = (void *)offset; | 209 | code->immediate = (unsigned long)offset; // imm64? |
414 | } else { | 210 | } else { |
415 | /* uprobes don't support symbols */ | 211 | /* uprobes don't support symbols */ |
416 | if (!is_kprobe) | 212 | if (!is_kprobe) |
@@ -420,10 +216,19 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
420 | if (ret) | 216 | if (ret) |
421 | break; | 217 | break; |
422 | 218 | ||
423 | f->data = alloc_symbol_cache(arg + 1, offset); | 219 | code->op = FETCH_OP_IMM; |
424 | if (f->data) | 220 | code->immediate = |
425 | f->fn = t->fetch[FETCH_MTD_symbol]; | 221 | (unsigned long)kallsyms_lookup_name(arg + 1); |
222 | if (!code->immediate) | ||
223 | return -ENOENT; | ||
224 | code->immediate += offset; | ||
426 | } | 225 | } |
226 | /* These are fetching from memory */ | ||
227 | if (++code == end) | ||
228 | return -E2BIG; | ||
229 | *pcode = code; | ||
230 | code->op = FETCH_OP_DEREF; | ||
231 | code->offset = offset; | ||
427 | break; | 232 | break; |
428 | 233 | ||
429 | case '+': /* deref memory */ | 234 | case '+': /* deref memory */ |
@@ -431,11 +236,10 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
431 | case '-': | 236 | case '-': |
432 | tmp = strchr(arg, '('); | 237 | tmp = strchr(arg, '('); |
433 | if (!tmp) | 238 | if (!tmp) |
434 | break; | 239 | return -EINVAL; |
435 | 240 | ||
436 | *tmp = '\0'; | 241 | *tmp = '\0'; |
437 | ret = kstrtol(arg, 0, &offset); | 242 | ret = kstrtol(arg, 0, &offset); |
438 | |||
439 | if (ret) | 243 | if (ret) |
440 | break; | 244 | break; |
441 | 245 | ||
@@ -443,36 +247,29 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
443 | tmp = strrchr(arg, ')'); | 247 | tmp = strrchr(arg, ')'); |
444 | 248 | ||
445 | if (tmp) { | 249 | if (tmp) { |
446 | struct deref_fetch_param *dprm; | 250 | const struct fetch_type *t2; |
447 | const struct fetch_type *t2; | ||
448 | 251 | ||
449 | t2 = find_fetch_type(NULL, ftbl); | 252 | t2 = find_fetch_type(NULL, ftbl); |
450 | *tmp = '\0'; | 253 | *tmp = '\0'; |
451 | dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); | 254 | ret = parse_probe_arg(arg, t2, &code, end, is_return, |
452 | 255 | is_kprobe, ftbl); | |
453 | if (!dprm) | ||
454 | return -ENOMEM; | ||
455 | |||
456 | dprm->offset = offset; | ||
457 | dprm->fetch = t->fetch[FETCH_MTD_memory]; | ||
458 | dprm->fetch_size = get_fetch_size_function(t, | ||
459 | dprm->fetch, ftbl); | ||
460 | ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, | ||
461 | is_kprobe, ftbl); | ||
462 | if (ret) | 256 | if (ret) |
463 | kfree(dprm); | 257 | break; |
464 | else { | 258 | if (code->op == FETCH_OP_COMM) |
465 | f->fn = t->fetch[FETCH_MTD_deref]; | 259 | return -EINVAL; |
466 | f->data = (void *)dprm; | 260 | if (++code == end) |
467 | } | 261 | return -E2BIG; |
262 | *pcode = code; | ||
263 | |||
264 | code->op = FETCH_OP_DEREF; | ||
265 | code->offset = offset; | ||
468 | } | 266 | } |
469 | break; | 267 | break; |
470 | } | 268 | } |
471 | if (!ret && !f->fn) { /* Parsed, but do not find fetch method */ | 269 | if (!ret && code->op == FETCH_OP_NOP) { |
472 | pr_info("%s type has no corresponding fetch method.\n", t->name); | 270 | /* Parsed, but do not find fetch method */ |
473 | ret = -EINVAL; | 271 | ret = -EINVAL; |
474 | } | 272 | } |
475 | |||
476 | return ret; | 273 | return ret; |
477 | } | 274 | } |
478 | 275 | ||
@@ -481,22 +278,15 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
481 | /* Bitfield type needs to be parsed into a fetch function */ | 278 | /* Bitfield type needs to be parsed into a fetch function */ |
482 | static int __parse_bitfield_probe_arg(const char *bf, | 279 | static int __parse_bitfield_probe_arg(const char *bf, |
483 | const struct fetch_type *t, | 280 | const struct fetch_type *t, |
484 | struct fetch_param *f) | 281 | struct fetch_insn **pcode) |
485 | { | 282 | { |
486 | struct bitfield_fetch_param *bprm; | 283 | struct fetch_insn *code = *pcode; |
487 | unsigned long bw, bo; | 284 | unsigned long bw, bo; |
488 | char *tail; | 285 | char *tail; |
489 | 286 | ||
490 | if (*bf != 'b') | 287 | if (*bf != 'b') |
491 | return 0; | 288 | return 0; |
492 | 289 | ||
493 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | ||
494 | if (!bprm) | ||
495 | return -ENOMEM; | ||
496 | |||
497 | bprm->orig = *f; | ||
498 | f->fn = t->fetch[FETCH_MTD_bitfield]; | ||
499 | f->data = (void *)bprm; | ||
500 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ | 290 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
501 | 291 | ||
502 | if (bw == 0 || *tail != '@') | 292 | if (bw == 0 || *tail != '@') |
@@ -507,9 +297,15 @@ static int __parse_bitfield_probe_arg(const char *bf, | |||
507 | 297 | ||
508 | if (tail == bf || *tail != '/') | 298 | if (tail == bf || *tail != '/') |
509 | return -EINVAL; | 299 | return -EINVAL; |
300 | code++; | ||
301 | if (code->op != FETCH_OP_NOP) | ||
302 | return -E2BIG; | ||
303 | *pcode = code; | ||
510 | 304 | ||
511 | bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); | 305 | code->op = FETCH_OP_MOD_BF; |
512 | bprm->low_shift = bprm->hi_shift + bo; | 306 | code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); |
307 | code->rshift = BYTES_TO_BITS(t->size) - bw; | ||
308 | code->basesize = t->size; | ||
513 | 309 | ||
514 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | 310 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; |
515 | } | 311 | } |
@@ -519,6 +315,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |||
519 | struct probe_arg *parg, bool is_return, bool is_kprobe, | 315 | struct probe_arg *parg, bool is_return, bool is_kprobe, |
520 | const struct fetch_type *ftbl) | 316 | const struct fetch_type *ftbl) |
521 | { | 317 | { |
318 | struct fetch_insn *code, *tmp = NULL; | ||
522 | const char *t; | 319 | const char *t; |
523 | int ret; | 320 | int ret; |
524 | 321 | ||
@@ -549,18 +346,60 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |||
549 | } | 346 | } |
550 | parg->offset = *size; | 347 | parg->offset = *size; |
551 | *size += parg->type->size; | 348 | *size += parg->type->size; |
552 | ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, | ||
553 | is_kprobe, ftbl); | ||
554 | |||
555 | if (ret >= 0 && t != NULL) | ||
556 | ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); | ||
557 | 349 | ||
558 | if (ret >= 0) { | 350 | code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL); |
559 | parg->fetch_size.fn = get_fetch_size_function(parg->type, | 351 | if (!code) |
560 | parg->fetch.fn, | 352 | return -ENOMEM; |
561 | ftbl); | 353 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; |
562 | parg->fetch_size.data = parg->fetch.data; | 354 | |
355 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], | ||
356 | is_return, is_kprobe, ftbl); | ||
357 | if (ret) | ||
358 | goto fail; | ||
359 | |||
360 | /* Store operation */ | ||
361 | if (!strcmp(parg->type->name, "string")) { | ||
362 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && | ||
363 | code->op != FETCH_OP_COMM) { | ||
364 | pr_info("string only accepts memory or address.\n"); | ||
365 | ret = -EINVAL; | ||
366 | goto fail; | ||
367 | } | ||
368 | /* Since IMM or COMM must be the 1st insn, this is safe */ | ||
369 | if (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) | ||
370 | code++; | ||
371 | code->op = FETCH_OP_ST_STRING; /* In DEREF case, replace it */ | ||
372 | parg->dynamic = true; | ||
373 | } else if (code->op == FETCH_OP_DEREF) { | ||
374 | code->op = FETCH_OP_ST_MEM; | ||
375 | code->size = parg->type->size; | ||
376 | } else { | ||
377 | code++; | ||
378 | if (code->op != FETCH_OP_NOP) { | ||
379 | ret = -E2BIG; | ||
380 | goto fail; | ||
381 | } | ||
382 | code->op = FETCH_OP_ST_RAW; | ||
383 | code->size = parg->type->size; | ||
384 | } | ||
385 | /* Modify operation */ | ||
386 | if (t != NULL) { | ||
387 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); | ||
388 | if (ret) | ||
389 | goto fail; | ||
563 | } | 390 | } |
391 | code++; | ||
392 | code->op = FETCH_OP_END; | ||
393 | |||
394 | /* Shrink down the code buffer */ | ||
395 | parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL); | ||
396 | if (!parg->code) | ||
397 | ret = -ENOMEM; | ||
398 | else | ||
399 | memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); | ||
400 | |||
401 | fail: | ||
402 | kfree(tmp); | ||
564 | 403 | ||
565 | return ret; | 404 | return ret; |
566 | } | 405 | } |
@@ -582,25 +421,9 @@ int traceprobe_conflict_field_name(const char *name, | |||
582 | return 0; | 421 | return 0; |
583 | } | 422 | } |
584 | 423 | ||
585 | void traceprobe_update_arg(struct probe_arg *arg) | ||
586 | { | ||
587 | if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) | ||
588 | update_bitfield_fetch_param(arg->fetch.data); | ||
589 | else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) | ||
590 | update_deref_fetch_param(arg->fetch.data); | ||
591 | else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) | ||
592 | update_symbol_cache(arg->fetch.data); | ||
593 | } | ||
594 | |||
595 | void traceprobe_free_probe_arg(struct probe_arg *arg) | 424 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
596 | { | 425 | { |
597 | if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) | 426 | kfree(arg->code); |
598 | free_bitfield_fetch_param(arg->fetch.data); | ||
599 | else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) | ||
600 | free_deref_fetch_param(arg->fetch.data); | ||
601 | else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) | ||
602 | free_symbol_cache(arg->fetch.data); | ||
603 | |||
604 | kfree(arg->name); | 427 | kfree(arg->name); |
605 | kfree(arg->comm); | 428 | kfree(arg->comm); |
606 | } | 429 | } |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index a1df7763b797..42c724a7ad11 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
@@ -79,25 +79,50 @@ static nokprobe_inline void *get_loc_data(u32 *dl, void *ent) | |||
79 | return (u8 *)ent + get_rloc_offs(*dl); | 79 | return (u8 *)ent + get_rloc_offs(*dl); |
80 | } | 80 | } |
81 | 81 | ||
82 | /* Data fetch function type */ | ||
83 | typedef void (*fetch_func_t)(struct pt_regs *, void *, void *); | ||
84 | /* Printing function type */ | 82 | /* Printing function type */ |
85 | typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); | 83 | typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); |
86 | 84 | ||
87 | /* Fetch types */ | 85 | enum fetch_op { |
88 | enum { | 86 | FETCH_OP_NOP = 0, |
89 | FETCH_MTD_reg = 0, | 87 | // Stage 1 (load) ops |
90 | FETCH_MTD_stack, | 88 | FETCH_OP_REG, /* Register : .param = offset */ |
91 | FETCH_MTD_retval, | 89 | FETCH_OP_STACK, /* Stack : .param = index */ |
92 | FETCH_MTD_comm, | 90 | FETCH_OP_STACKP, /* Stack pointer */ |
93 | FETCH_MTD_memory, | 91 | FETCH_OP_RETVAL, /* Return value */ |
94 | FETCH_MTD_symbol, | 92 | FETCH_OP_IMM, /* Immediate : .immediate */ |
95 | FETCH_MTD_deref, | 93 | FETCH_OP_COMM, /* Current comm */ |
96 | FETCH_MTD_bitfield, | 94 | FETCH_OP_FOFFS, /* File offset: .immediate */ |
97 | FETCH_MTD_file_offset, | 95 | // Stage 2 (dereference) op |
98 | FETCH_MTD_END, | 96 | FETCH_OP_DEREF, /* Dereference: .offset */ |
97 | // Stage 3 (store) ops | ||
98 | FETCH_OP_ST_RAW, /* Raw: .size */ | ||
99 | FETCH_OP_ST_MEM, /* Mem: .offset, .size */ | ||
100 | FETCH_OP_ST_STRING, /* String: .offset, .size */ | ||
101 | // Stage 4 (modify) op | ||
102 | FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */ | ||
103 | FETCH_OP_END, | ||
99 | }; | 104 | }; |
100 | 105 | ||
106 | struct fetch_insn { | ||
107 | enum fetch_op op; | ||
108 | union { | ||
109 | unsigned int param; | ||
110 | struct { | ||
111 | unsigned int size; | ||
112 | int offset; | ||
113 | }; | ||
114 | struct { | ||
115 | unsigned char basesize; | ||
116 | unsigned char lshift; | ||
117 | unsigned char rshift; | ||
118 | }; | ||
119 | unsigned long immediate; | ||
120 | }; | ||
121 | }; | ||
122 | |||
123 | /* fetch + deref*N + store + mod + end <= 16, this allows N=12, enough */ | ||
124 | #define FETCH_INSN_MAX 16 | ||
125 | |||
101 | /* Fetch type information table */ | 126 | /* Fetch type information table */ |
102 | struct fetch_type { | 127 | struct fetch_type { |
103 | const char *name; /* Name of type */ | 128 | const char *name; /* Name of type */ |
@@ -106,13 +131,6 @@ struct fetch_type { | |||
106 | print_type_func_t print; /* Print functions */ | 131 | print_type_func_t print; /* Print functions */ |
107 | const char *fmt; /* Fromat string */ | 132 | const char *fmt; /* Fromat string */ |
108 | const char *fmttype; /* Name in format file */ | 133 | const char *fmttype; /* Name in format file */ |
109 | /* Fetch functions */ | ||
110 | fetch_func_t fetch[FETCH_MTD_END]; | ||
111 | }; | ||
112 | |||
113 | struct fetch_param { | ||
114 | fetch_func_t fn; | ||
115 | void *data; | ||
116 | }; | 134 | }; |
117 | 135 | ||
118 | /* For defining macros, define string/string_size types */ | 136 | /* For defining macros, define string/string_size types */ |
@@ -142,66 +160,12 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x64); | |||
142 | 160 | ||
143 | DECLARE_BASIC_PRINT_TYPE_FUNC(string); | 161 | DECLARE_BASIC_PRINT_TYPE_FUNC(string); |
144 | 162 | ||
145 | #define FETCH_FUNC_NAME(method, type) fetch_##method##_##type | ||
146 | |||
147 | /* Declare macro for basic types */ | ||
148 | #define DECLARE_FETCH_FUNC(method, type) \ | ||
149 | extern void FETCH_FUNC_NAME(method, type)(struct pt_regs *regs, \ | ||
150 | void *data, void *dest) | ||
151 | |||
152 | #define DECLARE_BASIC_FETCH_FUNCS(method) \ | ||
153 | DECLARE_FETCH_FUNC(method, u8); \ | ||
154 | DECLARE_FETCH_FUNC(method, u16); \ | ||
155 | DECLARE_FETCH_FUNC(method, u32); \ | ||
156 | DECLARE_FETCH_FUNC(method, u64) | ||
157 | |||
158 | DECLARE_BASIC_FETCH_FUNCS(reg); | ||
159 | #define fetch_reg_string NULL | ||
160 | #define fetch_reg_string_size NULL | ||
161 | |||
162 | DECLARE_BASIC_FETCH_FUNCS(retval); | ||
163 | #define fetch_retval_string NULL | ||
164 | #define fetch_retval_string_size NULL | ||
165 | |||
166 | DECLARE_BASIC_FETCH_FUNCS(symbol); | ||
167 | DECLARE_FETCH_FUNC(symbol, string); | ||
168 | DECLARE_FETCH_FUNC(symbol, string_size); | ||
169 | |||
170 | DECLARE_BASIC_FETCH_FUNCS(deref); | ||
171 | DECLARE_FETCH_FUNC(deref, string); | ||
172 | DECLARE_FETCH_FUNC(deref, string_size); | ||
173 | |||
174 | DECLARE_BASIC_FETCH_FUNCS(bitfield); | ||
175 | #define fetch_bitfield_string NULL | ||
176 | #define fetch_bitfield_string_size NULL | ||
177 | |||
178 | /* comm only makes sense as a string */ | ||
179 | #define fetch_comm_u8 NULL | ||
180 | #define fetch_comm_u16 NULL | ||
181 | #define fetch_comm_u32 NULL | ||
182 | #define fetch_comm_u64 NULL | ||
183 | DECLARE_FETCH_FUNC(comm, string); | ||
184 | DECLARE_FETCH_FUNC(comm, string_size); | ||
185 | |||
186 | /* | ||
187 | * Define macro for basic types - we don't need to define s* types, because | ||
188 | * we have to care only about bitwidth at recording time. | ||
189 | */ | ||
190 | #define DEFINE_BASIC_FETCH_FUNCS(method) \ | ||
191 | DEFINE_FETCH_##method(u8) \ | ||
192 | DEFINE_FETCH_##method(u16) \ | ||
193 | DEFINE_FETCH_##method(u32) \ | ||
194 | DEFINE_FETCH_##method(u64) | ||
195 | |||
196 | /* Default (unsigned long) fetch type */ | 163 | /* Default (unsigned long) fetch type */ |
197 | #define __DEFAULT_FETCH_TYPE(t) x##t | 164 | #define __DEFAULT_FETCH_TYPE(t) x##t |
198 | #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) | 165 | #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) |
199 | #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) | 166 | #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) |
200 | #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) | 167 | #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) |
201 | 168 | ||
202 | #define ASSIGN_FETCH_FUNC(method, type) \ | ||
203 | [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type) | ||
204 | |||
205 | #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \ | 169 | #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \ |
206 | {.name = _name, \ | 170 | {.name = _name, \ |
207 | .size = _size, \ | 171 | .size = _size, \ |
@@ -209,17 +173,6 @@ DEFINE_FETCH_##method(u64) | |||
209 | .print = PRINT_TYPE_FUNC_NAME(ptype), \ | 173 | .print = PRINT_TYPE_FUNC_NAME(ptype), \ |
210 | .fmt = PRINT_TYPE_FMT_NAME(ptype), \ | 174 | .fmt = PRINT_TYPE_FMT_NAME(ptype), \ |
211 | .fmttype = _fmttype, \ | 175 | .fmttype = _fmttype, \ |
212 | .fetch = { \ | ||
213 | ASSIGN_FETCH_FUNC(reg, ftype), \ | ||
214 | ASSIGN_FETCH_FUNC(stack, ftype), \ | ||
215 | ASSIGN_FETCH_FUNC(retval, ftype), \ | ||
216 | ASSIGN_FETCH_FUNC(comm, ftype), \ | ||
217 | ASSIGN_FETCH_FUNC(memory, ftype), \ | ||
218 | ASSIGN_FETCH_FUNC(symbol, ftype), \ | ||
219 | ASSIGN_FETCH_FUNC(deref, ftype), \ | ||
220 | ASSIGN_FETCH_FUNC(bitfield, ftype), \ | ||
221 | ASSIGN_FETCH_FUNC(file_offset, ftype), \ | ||
222 | } \ | ||
223 | } | 176 | } |
224 | 177 | ||
225 | #define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \ | 178 | #define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \ |
@@ -231,42 +184,13 @@ ASSIGN_FETCH_FUNC(file_offset, ftype), \ | |||
231 | 184 | ||
232 | #define ASSIGN_FETCH_TYPE_END {} | 185 | #define ASSIGN_FETCH_TYPE_END {} |
233 | 186 | ||
234 | #define FETCH_TYPE_STRING 0 | 187 | #define FETCH_TYPE_STRING 0 |
235 | #define FETCH_TYPE_STRSIZE 1 | 188 | #define FETCH_TYPE_STRSIZE 1 |
236 | 189 | ||
237 | #ifdef CONFIG_KPROBE_EVENTS | 190 | #ifdef CONFIG_KPROBE_EVENTS |
238 | struct symbol_cache; | ||
239 | unsigned long update_symbol_cache(struct symbol_cache *sc); | ||
240 | void free_symbol_cache(struct symbol_cache *sc); | ||
241 | struct symbol_cache *alloc_symbol_cache(const char *sym, long offset); | ||
242 | bool trace_kprobe_on_func_entry(struct trace_event_call *call); | 191 | bool trace_kprobe_on_func_entry(struct trace_event_call *call); |
243 | bool trace_kprobe_error_injectable(struct trace_event_call *call); | 192 | bool trace_kprobe_error_injectable(struct trace_event_call *call); |
244 | #else | 193 | #else |
245 | /* uprobes do not support symbol fetch methods */ | ||
246 | #define fetch_symbol_u8 NULL | ||
247 | #define fetch_symbol_u16 NULL | ||
248 | #define fetch_symbol_u32 NULL | ||
249 | #define fetch_symbol_u64 NULL | ||
250 | #define fetch_symbol_string NULL | ||
251 | #define fetch_symbol_string_size NULL | ||
252 | |||
253 | struct symbol_cache { | ||
254 | }; | ||
255 | static inline unsigned long __used update_symbol_cache(struct symbol_cache *sc) | ||
256 | { | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static inline void __used free_symbol_cache(struct symbol_cache *sc) | ||
261 | { | ||
262 | } | ||
263 | |||
264 | static inline struct symbol_cache * __used | ||
265 | alloc_symbol_cache(const char *sym, long offset) | ||
266 | { | ||
267 | return NULL; | ||
268 | } | ||
269 | |||
270 | static inline bool trace_kprobe_on_func_entry(struct trace_event_call *call) | 194 | static inline bool trace_kprobe_on_func_entry(struct trace_event_call *call) |
271 | { | 195 | { |
272 | return false; | 196 | return false; |
@@ -279,8 +203,8 @@ static inline bool trace_kprobe_error_injectable(struct trace_event_call *call) | |||
279 | #endif /* CONFIG_KPROBE_EVENTS */ | 203 | #endif /* CONFIG_KPROBE_EVENTS */ |
280 | 204 | ||
281 | struct probe_arg { | 205 | struct probe_arg { |
282 | struct fetch_param fetch; | 206 | struct fetch_insn *code; |
283 | struct fetch_param fetch_size; | 207 | bool dynamic;/* Dynamic array (string) is used */ |
284 | unsigned int offset; /* Offset from argument entry */ | 208 | unsigned int offset; /* Offset from argument entry */ |
285 | const char *name; /* Name of this argument */ | 209 | const char *name; /* Name of this argument */ |
286 | const char *comm; /* Command of this argument */ | 210 | const char *comm; /* Command of this argument */ |
@@ -312,12 +236,6 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp) | |||
312 | return !!(tp->flags & TP_FLAG_REGISTERED); | 236 | return !!(tp->flags & TP_FLAG_REGISTERED); |
313 | } | 237 | } |
314 | 238 | ||
315 | static nokprobe_inline void call_fetch(struct fetch_param *fprm, | ||
316 | struct pt_regs *regs, void *dest) | ||
317 | { | ||
318 | return fprm->fn(regs, fprm->data, dest); | ||
319 | } | ||
320 | |||
321 | /* Check the name is good for event/group/fields */ | 239 | /* Check the name is good for event/group/fields */ |
322 | static inline bool is_good_name(const char *name) | 240 | static inline bool is_good_name(const char *name) |
323 | { | 241 | { |
@@ -354,68 +272,6 @@ extern void traceprobe_free_probe_arg(struct probe_arg *arg); | |||
354 | 272 | ||
355 | extern int traceprobe_split_symbol_offset(char *symbol, long *offset); | 273 | extern int traceprobe_split_symbol_offset(char *symbol, long *offset); |
356 | 274 | ||
357 | /* Sum up total data length for dynamic arraies (strings) */ | ||
358 | static nokprobe_inline int | ||
359 | __get_data_size(struct trace_probe *tp, struct pt_regs *regs) | ||
360 | { | ||
361 | int i, ret = 0; | ||
362 | u32 len; | ||
363 | |||
364 | for (i = 0; i < tp->nr_args; i++) | ||
365 | if (unlikely(tp->args[i].fetch_size.fn)) { | ||
366 | call_fetch(&tp->args[i].fetch_size, regs, &len); | ||
367 | ret += len; | ||
368 | } | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | /* Store the value of each argument */ | ||
374 | static nokprobe_inline void | ||
375 | store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, | ||
376 | u8 *data, int maxlen) | ||
377 | { | ||
378 | int i; | ||
379 | u32 end = tp->size; | ||
380 | u32 *dl; /* Data (relative) location */ | ||
381 | |||
382 | for (i = 0; i < tp->nr_args; i++) { | ||
383 | if (unlikely(tp->args[i].fetch_size.fn)) { | ||
384 | /* | ||
385 | * First, we set the relative location and | ||
386 | * maximum data length to *dl | ||
387 | */ | ||
388 | dl = (u32 *)(data + tp->args[i].offset); | ||
389 | *dl = make_data_rloc(maxlen, end - tp->args[i].offset); | ||
390 | /* Then try to fetch string or dynamic array data */ | ||
391 | call_fetch(&tp->args[i].fetch, regs, dl); | ||
392 | /* Reduce maximum length */ | ||
393 | end += get_rloc_len(*dl); | ||
394 | maxlen -= get_rloc_len(*dl); | ||
395 | /* Trick here, convert data_rloc to data_loc */ | ||
396 | *dl = convert_rloc_to_loc(*dl, | ||
397 | ent_size + tp->args[i].offset); | ||
398 | } else | ||
399 | /* Just fetching data normally */ | ||
400 | call_fetch(&tp->args[i].fetch, regs, | ||
401 | data + tp->args[i].offset); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | static inline int | ||
406 | print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args, | ||
407 | u8 *data, void *field) | ||
408 | { | ||
409 | int i; | ||
410 | |||
411 | for (i = 0; i < nr_args; i++) { | ||
412 | trace_seq_printf(s, " %s=", args[i].name); | ||
413 | if (!args[i].type->print(s, data + args[i].offset, field)) | ||
414 | return -ENOMEM; | ||
415 | } | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | extern int set_print_fmt(struct trace_probe *tp, bool is_return); | 275 | extern int set_print_fmt(struct trace_probe *tp, bool is_return); |
420 | 276 | ||
421 | #ifdef CONFIG_PERF_EVENTS | 277 | #ifdef CONFIG_PERF_EVENTS |
diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h new file mode 100644 index 000000000000..c8a5272abf01 --- /dev/null +++ b/kernel/trace/trace_probe_tmpl.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Traceprobe fetch helper inlines | ||
4 | */ | ||
5 | |||
6 | static nokprobe_inline void | ||
7 | fetch_store_raw(unsigned long val, struct fetch_insn *code, void *buf) | ||
8 | { | ||
9 | switch (code->size) { | ||
10 | case 1: | ||
11 | *(u8 *)buf = (u8)val; | ||
12 | break; | ||
13 | case 2: | ||
14 | *(u16 *)buf = (u16)val; | ||
15 | break; | ||
16 | case 4: | ||
17 | *(u32 *)buf = (u32)val; | ||
18 | break; | ||
19 | case 8: | ||
20 | //TBD: 32bit signed | ||
21 | *(u64 *)buf = (u64)val; | ||
22 | break; | ||
23 | default: | ||
24 | *(unsigned long *)buf = val; | ||
25 | } | ||
26 | } | ||
27 | |||
28 | static nokprobe_inline void | ||
29 | fetch_apply_bitfield(struct fetch_insn *code, void *buf) | ||
30 | { | ||
31 | switch (code->basesize) { | ||
32 | case 1: | ||
33 | *(u8 *)buf <<= code->lshift; | ||
34 | *(u8 *)buf >>= code->rshift; | ||
35 | break; | ||
36 | case 2: | ||
37 | *(u16 *)buf <<= code->lshift; | ||
38 | *(u16 *)buf >>= code->rshift; | ||
39 | break; | ||
40 | case 4: | ||
41 | *(u32 *)buf <<= code->lshift; | ||
42 | *(u32 *)buf >>= code->rshift; | ||
43 | break; | ||
44 | case 8: | ||
45 | *(u64 *)buf <<= code->lshift; | ||
46 | *(u64 *)buf >>= code->rshift; | ||
47 | break; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | /* Define this for each callsite */ | ||
52 | static int | ||
53 | process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, | ||
54 | void *dest, bool pre); | ||
55 | |||
56 | /* Sum up total data length for dynamic arraies (strings) */ | ||
57 | static nokprobe_inline int | ||
58 | __get_data_size(struct trace_probe *tp, struct pt_regs *regs) | ||
59 | { | ||
60 | struct probe_arg *arg; | ||
61 | int i, ret = 0; | ||
62 | u32 len; | ||
63 | |||
64 | for (i = 0; i < tp->nr_args; i++) { | ||
65 | arg = tp->args + i; | ||
66 | if (unlikely(arg->dynamic)) { | ||
67 | process_fetch_insn(arg->code, regs, &len, true); | ||
68 | ret += len; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | /* Store the value of each argument */ | ||
76 | static nokprobe_inline void | ||
77 | store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, | ||
78 | u8 *data, int maxlen) | ||
79 | { | ||
80 | struct probe_arg *arg; | ||
81 | u32 end = tp->size; | ||
82 | u32 *dl; /* Data (relative) location */ | ||
83 | int i; | ||
84 | |||
85 | for (i = 0; i < tp->nr_args; i++) { | ||
86 | arg = tp->args + i; | ||
87 | if (unlikely(arg->dynamic)) { | ||
88 | /* | ||
89 | * First, we set the relative location and | ||
90 | * maximum data length to *dl | ||
91 | */ | ||
92 | dl = (u32 *)(data + arg->offset); | ||
93 | *dl = make_data_rloc(maxlen, end - arg->offset); | ||
94 | /* Then try to fetch string or dynamic array data */ | ||
95 | process_fetch_insn(arg->code, regs, dl, false); | ||
96 | /* Reduce maximum length */ | ||
97 | end += get_rloc_len(*dl); | ||
98 | maxlen -= get_rloc_len(*dl); | ||
99 | /* Trick here, convert data_rloc to data_loc */ | ||
100 | *dl = convert_rloc_to_loc(*dl, ent_size + arg->offset); | ||
101 | } else | ||
102 | /* Just fetching data normally */ | ||
103 | process_fetch_insn(arg->code, regs, data + arg->offset, | ||
104 | false); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static inline int | ||
109 | print_probe_args(struct trace_seq *s, struct probe_arg *args, int nr_args, | ||
110 | u8 *data, void *field) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | for (i = 0; i < nr_args; i++) { | ||
115 | trace_seq_printf(s, " %s=", args[i].name); | ||
116 | if (!args[i].type->print(s, data + args[i].offset, field)) | ||
117 | return -ENOMEM; | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 28a8f69cec89..e076f89ab33a 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/rculist.h> | 15 | #include <linux/rculist.h> |
16 | 16 | ||
17 | #include "trace_probe.h" | 17 | #include "trace_probe.h" |
18 | #include "trace_probe_tmpl.h" | ||
18 | 19 | ||
19 | #define UPROBE_EVENT_SYSTEM "uprobes" | 20 | #define UPROBE_EVENT_SYSTEM "uprobes" |
20 | 21 | ||
@@ -99,37 +100,19 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n) | |||
99 | /* | 100 | /* |
100 | * Uprobes-specific fetch functions | 101 | * Uprobes-specific fetch functions |
101 | */ | 102 | */ |
102 | #define DEFINE_FETCH_stack(type) \ | 103 | static nokprobe_inline int |
103 | static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ | 104 | probe_user_read(void *dest, void *src, size_t size) |
104 | void *offset, void *dest) \ | 105 | { |
105 | { \ | 106 | void __user *vaddr = (void __force __user *)src; |
106 | *(type *)dest = (type)get_user_stack_nth(regs, \ | 107 | |
107 | ((unsigned long)offset)); \ | 108 | return copy_from_user(dest, vaddr, size); |
108 | } | ||
109 | DEFINE_BASIC_FETCH_FUNCS(stack) | ||
110 | /* No string on the stack entry */ | ||
111 | #define fetch_stack_string NULL | ||
112 | #define fetch_stack_string_size NULL | ||
113 | |||
114 | #define DEFINE_FETCH_memory(type) \ | ||
115 | static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ | ||
116 | void *addr, void *dest) \ | ||
117 | { \ | ||
118 | type retval; \ | ||
119 | void __user *vaddr = (void __force __user *) addr; \ | ||
120 | \ | ||
121 | if (copy_from_user(&retval, vaddr, sizeof(type))) \ | ||
122 | *(type *)dest = 0; \ | ||
123 | else \ | ||
124 | *(type *) dest = retval; \ | ||
125 | } | 109 | } |
126 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
127 | /* | 110 | /* |
128 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | 111 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max |
129 | * length and relative data location. | 112 | * length and relative data location. |
130 | */ | 113 | */ |
131 | static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | 114 | static nokprobe_inline void |
132 | void *addr, void *dest) | 115 | fetch_store_string(unsigned long addr, void *dest) |
133 | { | 116 | { |
134 | long ret; | 117 | long ret; |
135 | u32 rloc = *(u32 *)dest; | 118 | u32 rloc = *(u32 *)dest; |
@@ -152,8 +135,9 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | |||
152 | } | 135 | } |
153 | } | 136 | } |
154 | 137 | ||
155 | static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | 138 | /* Return the length of string -- including null terminal byte */ |
156 | void *addr, void *dest) | 139 | static nokprobe_inline void |
140 | fetch_store_strlen(unsigned long addr, void *dest) | ||
157 | { | 141 | { |
158 | int len; | 142 | int len; |
159 | void __user *vaddr = (void __force __user *) addr; | 143 | void __user *vaddr = (void __force __user *) addr; |
@@ -166,7 +150,7 @@ static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | |||
166 | *(u32 *)dest = len; | 150 | *(u32 *)dest = len; |
167 | } | 151 | } |
168 | 152 | ||
169 | static unsigned long translate_user_vaddr(void *file_offset) | 153 | static unsigned long translate_user_vaddr(unsigned long file_offset) |
170 | { | 154 | { |
171 | unsigned long base_addr; | 155 | unsigned long base_addr; |
172 | struct uprobe_dispatch_data *udd; | 156 | struct uprobe_dispatch_data *udd; |
@@ -174,21 +158,9 @@ static unsigned long translate_user_vaddr(void *file_offset) | |||
174 | udd = (void *) current->utask->vaddr; | 158 | udd = (void *) current->utask->vaddr; |
175 | 159 | ||
176 | base_addr = udd->bp_addr - udd->tu->offset; | 160 | base_addr = udd->bp_addr - udd->tu->offset; |
177 | return base_addr + (unsigned long)file_offset; | 161 | return base_addr + file_offset; |
178 | } | 162 | } |
179 | 163 | ||
180 | #define DEFINE_FETCH_file_offset(type) \ | ||
181 | static void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs, \ | ||
182 | void *offset, void *dest)\ | ||
183 | { \ | ||
184 | void *vaddr = (void *)translate_user_vaddr(offset); \ | ||
185 | \ | ||
186 | FETCH_FUNC_NAME(memory, type)(regs, vaddr, dest); \ | ||
187 | } | ||
188 | DEFINE_BASIC_FETCH_FUNCS(file_offset) | ||
189 | DEFINE_FETCH_file_offset(string) | ||
190 | DEFINE_FETCH_file_offset(string_size) | ||
191 | |||
192 | /* Fetch type information table */ | 164 | /* Fetch type information table */ |
193 | static const struct fetch_type uprobes_fetch_type_table[] = { | 165 | static const struct fetch_type uprobes_fetch_type_table[] = { |
194 | /* Special types */ | 166 | /* Special types */ |
@@ -213,6 +185,77 @@ static const struct fetch_type uprobes_fetch_type_table[] = { | |||
213 | ASSIGN_FETCH_TYPE_END | 185 | ASSIGN_FETCH_TYPE_END |
214 | }; | 186 | }; |
215 | 187 | ||
188 | /* Note that we don't verify it, since the code does not come from user space */ | ||
189 | static int | ||
190 | process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, | ||
191 | bool pre) | ||
192 | { | ||
193 | unsigned long val; | ||
194 | int ret; | ||
195 | |||
196 | /* 1st stage: get value from context */ | ||
197 | switch (code->op) { | ||
198 | case FETCH_OP_REG: | ||
199 | val = regs_get_register(regs, code->param); | ||
200 | break; | ||
201 | case FETCH_OP_STACK: | ||
202 | val = get_user_stack_nth(regs, code->param); | ||
203 | break; | ||
204 | case FETCH_OP_STACKP: | ||
205 | val = user_stack_pointer(regs); | ||
206 | break; | ||
207 | case FETCH_OP_RETVAL: | ||
208 | val = regs_return_value(regs); | ||
209 | break; | ||
210 | case FETCH_OP_IMM: | ||
211 | val = code->immediate; | ||
212 | break; | ||
213 | case FETCH_OP_FOFFS: | ||
214 | val = translate_user_vaddr(code->immediate); | ||
215 | break; | ||
216 | default: | ||
217 | return -EILSEQ; | ||
218 | } | ||
219 | code++; | ||
220 | |||
221 | /* 2nd stage: dereference memory if needed */ | ||
222 | while (code->op == FETCH_OP_DEREF) { | ||
223 | ret = probe_user_read(&val, (void *)val + code->offset, | ||
224 | sizeof(val)); | ||
225 | if (ret) | ||
226 | return ret; | ||
227 | code++; | ||
228 | } | ||
229 | |||
230 | /* 3rd stage: store value to buffer */ | ||
231 | switch (code->op) { | ||
232 | case FETCH_OP_ST_RAW: | ||
233 | fetch_store_raw(val, code, dest); | ||
234 | break; | ||
235 | case FETCH_OP_ST_MEM: | ||
236 | probe_user_read(dest, (void *)val + code->offset, code->size); | ||
237 | break; | ||
238 | case FETCH_OP_ST_STRING: | ||
239 | if (pre) | ||
240 | fetch_store_strlen(val + code->offset, dest); | ||
241 | else | ||
242 | fetch_store_string(val + code->offset, dest); | ||
243 | break; | ||
244 | default: | ||
245 | return -EILSEQ; | ||
246 | } | ||
247 | code++; | ||
248 | |||
249 | /* 4th stage: modify stored value if needed */ | ||
250 | if (code->op == FETCH_OP_MOD_BF) { | ||
251 | fetch_apply_bitfield(code, dest); | ||
252 | code++; | ||
253 | } | ||
254 | |||
255 | return code->op == FETCH_OP_END ? 0 : -EILSEQ; | ||
256 | } | ||
257 | NOKPROBE_SYMBOL(process_fetch_insn) | ||
258 | |||
216 | static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter) | 259 | static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter) |
217 | { | 260 | { |
218 | rwlock_init(&filter->rwlock); | 261 | rwlock_init(&filter->rwlock); |