diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-12 22:18:49 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-12 22:18:49 -0400 |
| commit | 3737a12761636ebde0f09ef49daebb8eed18cc8a (patch) | |
| tree | 965057f4bccd97049f8c0140f8670c5d4278ca3e /kernel/trace | |
| parent | c29deef32e3699e40da3e9e82267610de04e6b54 (diff) | |
| parent | 82b897782d10fcc4930c9d4a15b175348fdd2871 (diff) | |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull more perf updates from Ingo Molnar:
"A second round of perf updates:
- wide reaching kprobes sanitization and robustization, with the hope
of fixing all 'probe this function crashes the kernel' bugs, by
Masami Hiramatsu.
- uprobes updates from Oleg Nesterov: tmpfs support, corner case
fixes and robustization work.
- perf tooling updates and fixes from Jiri Olsa, Namhyung Ki, Arnaldo
et al:
* Add support to accumulate hist periods (Namhyung Kim)
* various fixes, refactorings and enhancements"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (101 commits)
perf: Differentiate exec() and non-exec() comm events
perf: Fix perf_event_comm() vs. exec() assumption
uprobes/x86: Rename arch_uprobe->def to ->defparam, minor comment updates
perf/documentation: Add description for conditional branch filter
perf/x86: Add conditional branch filtering support
perf/tool: Add conditional branch filter 'cond' to perf record
perf: Add new conditional branch filter 'PERF_SAMPLE_BRANCH_COND'
uprobes: Teach copy_insn() to support tmpfs
uprobes: Shift ->readpage check from __copy_insn() to uprobe_register()
perf/x86: Use common PMU interrupt disabled code
perf/ARM: Use common PMU interrupt disabled code
perf: Disable sampled events if no PMU interrupt
perf: Fix use after free in perf_remove_from_context()
perf tools: Fix 'make help' message error
perf record: Fix poll return value propagation
perf tools: Move elide bool into perf_hpp_fmt struct
perf tools: Remove elide setup for SORT_MODE__MEMORY mode
perf tools: Fix "==" into "=" in ui_browser__warning assignment
perf tools: Allow overriding sysfs and proc finding with env var
perf tools: Consider header files outside perf directory in tags target
...
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace_event_perf.c | 5 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 71 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.c | 65 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.h | 15 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 66 |
5 files changed, 121 insertions, 101 deletions
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index c894614de14d..5d12bb407b44 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
| @@ -248,8 +248,8 @@ void perf_trace_del(struct perf_event *p_event, int flags) | |||
| 248 | tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); | 248 | tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, | 251 | void *perf_trace_buf_prepare(int size, unsigned short type, |
| 252 | struct pt_regs *regs, int *rctxp) | 252 | struct pt_regs *regs, int *rctxp) |
| 253 | { | 253 | { |
| 254 | struct trace_entry *entry; | 254 | struct trace_entry *entry; |
| 255 | unsigned long flags; | 255 | unsigned long flags; |
| @@ -281,6 +281,7 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, | |||
| 281 | return raw_data; | 281 | return raw_data; |
| 282 | } | 282 | } |
| 283 | EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); | 283 | EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); |
| 284 | NOKPROBE_SYMBOL(perf_trace_buf_prepare); | ||
| 284 | 285 | ||
| 285 | #ifdef CONFIG_FUNCTION_TRACER | 286 | #ifdef CONFIG_FUNCTION_TRACER |
| 286 | static void | 287 | static void |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index ef2fba1f46b5..282f6e4e5539 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -40,27 +40,27 @@ struct trace_kprobe { | |||
| 40 | (sizeof(struct probe_arg) * (n))) | 40 | (sizeof(struct probe_arg) * (n))) |
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | static __kprobes bool trace_kprobe_is_return(struct trace_kprobe *tk) | 43 | static nokprobe_inline bool trace_kprobe_is_return(struct trace_kprobe *tk) |
| 44 | { | 44 | { |
| 45 | return tk->rp.handler != NULL; | 45 | return tk->rp.handler != NULL; |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | static __kprobes const char *trace_kprobe_symbol(struct trace_kprobe *tk) | 48 | static nokprobe_inline const char *trace_kprobe_symbol(struct trace_kprobe *tk) |
| 49 | { | 49 | { |
| 50 | return tk->symbol ? tk->symbol : "unknown"; | 50 | return tk->symbol ? tk->symbol : "unknown"; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static __kprobes unsigned long trace_kprobe_offset(struct trace_kprobe *tk) | 53 | static nokprobe_inline unsigned long trace_kprobe_offset(struct trace_kprobe *tk) |
| 54 | { | 54 | { |
| 55 | return tk->rp.kp.offset; | 55 | return tk->rp.kp.offset; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | static __kprobes bool trace_kprobe_has_gone(struct trace_kprobe *tk) | 58 | static nokprobe_inline bool trace_kprobe_has_gone(struct trace_kprobe *tk) |
| 59 | { | 59 | { |
| 60 | return !!(kprobe_gone(&tk->rp.kp)); | 60 | return !!(kprobe_gone(&tk->rp.kp)); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static __kprobes bool trace_kprobe_within_module(struct trace_kprobe *tk, | 63 | static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk, |
| 64 | struct module *mod) | 64 | struct module *mod) |
| 65 | { | 65 | { |
| 66 | int len = strlen(mod->name); | 66 | int len = strlen(mod->name); |
| @@ -68,7 +68,7 @@ static __kprobes bool trace_kprobe_within_module(struct trace_kprobe *tk, | |||
| 68 | return strncmp(mod->name, name, len) == 0 && name[len] == ':'; | 68 | return strncmp(mod->name, name, len) == 0 && name[len] == ':'; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static __kprobes bool trace_kprobe_is_on_module(struct trace_kprobe *tk) | 71 | static nokprobe_inline bool trace_kprobe_is_on_module(struct trace_kprobe *tk) |
| 72 | { | 72 | { |
| 73 | return !!strchr(trace_kprobe_symbol(tk), ':'); | 73 | return !!strchr(trace_kprobe_symbol(tk), ':'); |
| 74 | } | 74 | } |
| @@ -132,19 +132,21 @@ struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) | |||
| 132 | * Kprobes-specific fetch functions | 132 | * Kprobes-specific fetch functions |
| 133 | */ | 133 | */ |
| 134 | #define DEFINE_FETCH_stack(type) \ | 134 | #define DEFINE_FETCH_stack(type) \ |
| 135 | static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ | 135 | static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ |
| 136 | void *offset, void *dest) \ | 136 | void *offset, void *dest) \ |
| 137 | { \ | 137 | { \ |
| 138 | *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ | 138 | *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ |
| 139 | (unsigned int)((unsigned long)offset)); \ | 139 | (unsigned int)((unsigned long)offset)); \ |
| 140 | } | 140 | } \ |
| 141 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(stack, type)); | ||
| 142 | |||
| 141 | DEFINE_BASIC_FETCH_FUNCS(stack) | 143 | DEFINE_BASIC_FETCH_FUNCS(stack) |
| 142 | /* No string on the stack entry */ | 144 | /* No string on the stack entry */ |
| 143 | #define fetch_stack_string NULL | 145 | #define fetch_stack_string NULL |
| 144 | #define fetch_stack_string_size NULL | 146 | #define fetch_stack_string_size NULL |
| 145 | 147 | ||
| 146 | #define DEFINE_FETCH_memory(type) \ | 148 | #define DEFINE_FETCH_memory(type) \ |
| 147 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | 149 | static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ |
| 148 | void *addr, void *dest) \ | 150 | void *addr, void *dest) \ |
| 149 | { \ | 151 | { \ |
| 150 | type retval; \ | 152 | type retval; \ |
| @@ -152,14 +154,16 @@ static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | |||
| 152 | *(type *)dest = 0; \ | 154 | *(type *)dest = 0; \ |
| 153 | else \ | 155 | else \ |
| 154 | *(type *)dest = retval; \ | 156 | *(type *)dest = retval; \ |
| 155 | } | 157 | } \ |
| 158 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, type)); | ||
| 159 | |||
| 156 | DEFINE_BASIC_FETCH_FUNCS(memory) | 160 | DEFINE_BASIC_FETCH_FUNCS(memory) |
| 157 | /* | 161 | /* |
| 158 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | 162 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max |
| 159 | * length and relative data location. | 163 | * length and relative data location. |
| 160 | */ | 164 | */ |
| 161 | static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | 165 | static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, |
| 162 | void *addr, void *dest) | 166 | void *addr, void *dest) |
| 163 | { | 167 | { |
| 164 | long ret; | 168 | long ret; |
| 165 | int maxlen = get_rloc_len(*(u32 *)dest); | 169 | int maxlen = get_rloc_len(*(u32 *)dest); |
| @@ -193,10 +197,11 @@ static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | |||
| 193 | get_rloc_offs(*(u32 *)dest)); | 197 | get_rloc_offs(*(u32 *)dest)); |
| 194 | } | 198 | } |
| 195 | } | 199 | } |
| 200 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string)); | ||
| 196 | 201 | ||
| 197 | /* Return the length of string -- including null terminal byte */ | 202 | /* Return the length of string -- including null terminal byte */ |
| 198 | static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | 203 | static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, |
| 199 | void *addr, void *dest) | 204 | void *addr, void *dest) |
| 200 | { | 205 | { |
| 201 | mm_segment_t old_fs; | 206 | mm_segment_t old_fs; |
| 202 | int ret, len = 0; | 207 | int ret, len = 0; |
| @@ -219,17 +224,19 @@ static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | |||
| 219 | else | 224 | else |
| 220 | *(u32 *)dest = len; | 225 | *(u32 *)dest = len; |
| 221 | } | 226 | } |
| 227 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string_size)); | ||
| 222 | 228 | ||
| 223 | #define DEFINE_FETCH_symbol(type) \ | 229 | #define DEFINE_FETCH_symbol(type) \ |
| 224 | __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \ | 230 | void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, void *data, void *dest)\ |
| 225 | void *data, void *dest) \ | ||
| 226 | { \ | 231 | { \ |
| 227 | struct symbol_cache *sc = data; \ | 232 | struct symbol_cache *sc = data; \ |
| 228 | if (sc->addr) \ | 233 | if (sc->addr) \ |
| 229 | fetch_memory_##type(regs, (void *)sc->addr, dest); \ | 234 | fetch_memory_##type(regs, (void *)sc->addr, dest); \ |
| 230 | else \ | 235 | else \ |
| 231 | *(type *)dest = 0; \ | 236 | *(type *)dest = 0; \ |
| 232 | } | 237 | } \ |
| 238 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(symbol, type)); | ||
| 239 | |||
| 233 | DEFINE_BASIC_FETCH_FUNCS(symbol) | 240 | DEFINE_BASIC_FETCH_FUNCS(symbol) |
| 234 | DEFINE_FETCH_symbol(string) | 241 | DEFINE_FETCH_symbol(string) |
| 235 | DEFINE_FETCH_symbol(string_size) | 242 | DEFINE_FETCH_symbol(string_size) |
| @@ -907,7 +914,7 @@ static const struct file_operations kprobe_profile_ops = { | |||
| 907 | }; | 914 | }; |
| 908 | 915 | ||
| 909 | /* Kprobe handler */ | 916 | /* Kprobe handler */ |
| 910 | static __kprobes void | 917 | static nokprobe_inline void |
| 911 | __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, | 918 | __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, |
| 912 | struct ftrace_event_file *ftrace_file) | 919 | struct ftrace_event_file *ftrace_file) |
| 913 | { | 920 | { |
| @@ -943,7 +950,7 @@ __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, | |||
| 943 | entry, irq_flags, pc, regs); | 950 | entry, irq_flags, pc, regs); |
| 944 | } | 951 | } |
| 945 | 952 | ||
| 946 | static __kprobes void | 953 | static void |
| 947 | kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) | 954 | kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) |
| 948 | { | 955 | { |
| 949 | struct event_file_link *link; | 956 | struct event_file_link *link; |
| @@ -951,9 +958,10 @@ kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) | |||
| 951 | list_for_each_entry_rcu(link, &tk->tp.files, list) | 958 | list_for_each_entry_rcu(link, &tk->tp.files, list) |
| 952 | __kprobe_trace_func(tk, regs, link->file); | 959 | __kprobe_trace_func(tk, regs, link->file); |
| 953 | } | 960 | } |
| 961 | NOKPROBE_SYMBOL(kprobe_trace_func); | ||
| 954 | 962 | ||
| 955 | /* Kretprobe handler */ | 963 | /* Kretprobe handler */ |
| 956 | static __kprobes void | 964 | static nokprobe_inline void |
| 957 | __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | 965 | __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
| 958 | struct pt_regs *regs, | 966 | struct pt_regs *regs, |
| 959 | struct ftrace_event_file *ftrace_file) | 967 | struct ftrace_event_file *ftrace_file) |
| @@ -991,7 +999,7 @@ __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | |||
| 991 | entry, irq_flags, pc, regs); | 999 | entry, irq_flags, pc, regs); |
| 992 | } | 1000 | } |
| 993 | 1001 | ||
| 994 | static __kprobes void | 1002 | static void |
| 995 | kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | 1003 | kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
| 996 | struct pt_regs *regs) | 1004 | struct pt_regs *regs) |
| 997 | { | 1005 | { |
| @@ -1000,6 +1008,7 @@ kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | |||
| 1000 | list_for_each_entry_rcu(link, &tk->tp.files, list) | 1008 | list_for_each_entry_rcu(link, &tk->tp.files, list) |
| 1001 | __kretprobe_trace_func(tk, ri, regs, link->file); | 1009 | __kretprobe_trace_func(tk, ri, regs, link->file); |
| 1002 | } | 1010 | } |
| 1011 | NOKPROBE_SYMBOL(kretprobe_trace_func); | ||
| 1003 | 1012 | ||
| 1004 | /* Event entry printers */ | 1013 | /* Event entry printers */ |
| 1005 | static enum print_line_t | 1014 | static enum print_line_t |
| @@ -1131,7 +1140,7 @@ static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
| 1131 | #ifdef CONFIG_PERF_EVENTS | 1140 | #ifdef CONFIG_PERF_EVENTS |
| 1132 | 1141 | ||
| 1133 | /* Kprobe profile handler */ | 1142 | /* Kprobe profile handler */ |
| 1134 | static __kprobes void | 1143 | static void |
| 1135 | kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) | 1144 | kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) |
| 1136 | { | 1145 | { |
| 1137 | struct ftrace_event_call *call = &tk->tp.call; | 1146 | struct ftrace_event_call *call = &tk->tp.call; |
| @@ -1158,9 +1167,10 @@ kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) | |||
| 1158 | store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize); | 1167 | store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize); |
| 1159 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); | 1168 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); |
| 1160 | } | 1169 | } |
| 1170 | NOKPROBE_SYMBOL(kprobe_perf_func); | ||
| 1161 | 1171 | ||
| 1162 | /* Kretprobe profile handler */ | 1172 | /* Kretprobe profile handler */ |
| 1163 | static __kprobes void | 1173 | static void |
| 1164 | kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | 1174 | kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
| 1165 | struct pt_regs *regs) | 1175 | struct pt_regs *regs) |
| 1166 | { | 1176 | { |
| @@ -1188,6 +1198,7 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | |||
| 1188 | store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize); | 1198 | store_trace_args(sizeof(*entry), &tk->tp, regs, (u8 *)&entry[1], dsize); |
| 1189 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); | 1199 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); |
| 1190 | } | 1200 | } |
| 1201 | NOKPROBE_SYMBOL(kretprobe_perf_func); | ||
| 1191 | #endif /* CONFIG_PERF_EVENTS */ | 1202 | #endif /* CONFIG_PERF_EVENTS */ |
| 1192 | 1203 | ||
| 1193 | /* | 1204 | /* |
| @@ -1196,9 +1207,8 @@ kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, | |||
| 1196 | * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe | 1207 | * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe |
| 1197 | * lockless, but we can't race with this __init function. | 1208 | * lockless, but we can't race with this __init function. |
| 1198 | */ | 1209 | */ |
| 1199 | static __kprobes | 1210 | static int kprobe_register(struct ftrace_event_call *event, |
| 1200 | int kprobe_register(struct ftrace_event_call *event, | 1211 | enum trace_reg type, void *data) |
| 1201 | enum trace_reg type, void *data) | ||
| 1202 | { | 1212 | { |
| 1203 | struct trace_kprobe *tk = (struct trace_kprobe *)event->data; | 1213 | struct trace_kprobe *tk = (struct trace_kprobe *)event->data; |
| 1204 | struct ftrace_event_file *file = data; | 1214 | struct ftrace_event_file *file = data; |
| @@ -1224,8 +1234,7 @@ int kprobe_register(struct ftrace_event_call *event, | |||
| 1224 | return 0; | 1234 | return 0; |
| 1225 | } | 1235 | } |
| 1226 | 1236 | ||
| 1227 | static __kprobes | 1237 | static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) |
| 1228 | int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) | ||
| 1229 | { | 1238 | { |
| 1230 | struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); | 1239 | struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); |
| 1231 | 1240 | ||
| @@ -1239,9 +1248,10 @@ int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) | |||
| 1239 | #endif | 1248 | #endif |
| 1240 | return 0; /* We don't tweek kernel, so just return 0 */ | 1249 | return 0; /* We don't tweek kernel, so just return 0 */ |
| 1241 | } | 1250 | } |
| 1251 | NOKPROBE_SYMBOL(kprobe_dispatcher); | ||
| 1242 | 1252 | ||
| 1243 | static __kprobes | 1253 | static int |
| 1244 | int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) | 1254 | kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) |
| 1245 | { | 1255 | { |
| 1246 | struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp); | 1256 | struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp); |
| 1247 | 1257 | ||
| @@ -1255,6 +1265,7 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) | |||
| 1255 | #endif | 1265 | #endif |
| 1256 | return 0; /* We don't tweek kernel, so just return 0 */ | 1266 | return 0; /* We don't tweek kernel, so just return 0 */ |
| 1257 | } | 1267 | } |
| 1268 | NOKPROBE_SYMBOL(kretprobe_dispatcher); | ||
| 1258 | 1269 | ||
| 1259 | static struct trace_event_functions kretprobe_funcs = { | 1270 | static struct trace_event_functions kretprobe_funcs = { |
| 1260 | .trace = print_kretprobe_event | 1271 | .trace = print_kretprobe_event |
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 8364a421b4df..d4b9fc22cd27 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
| @@ -37,13 +37,13 @@ const char *reserved_field_names[] = { | |||
| 37 | 37 | ||
| 38 | /* Printing in basic type function template */ | 38 | /* Printing in basic type function template */ |
| 39 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt) \ | 39 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt) \ |
| 40 | __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ | 40 | int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name, \ |
| 41 | const char *name, \ | 41 | void *data, void *ent) \ |
| 42 | void *data, void *ent) \ | ||
| 43 | { \ | 42 | { \ |
| 44 | return trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ | 43 | return trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ |
| 45 | } \ | 44 | } \ |
| 46 | const char PRINT_TYPE_FMT_NAME(type)[] = fmt; | 45 | const char PRINT_TYPE_FMT_NAME(type)[] = fmt; \ |
| 46 | NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(type)); | ||
| 47 | 47 | ||
| 48 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8 , "0x%x") | 48 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8 , "0x%x") |
| 49 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "0x%x") | 49 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "0x%x") |
| @@ -55,9 +55,8 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%d") | |||
| 55 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%Ld") | 55 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%Ld") |
| 56 | 56 | ||
| 57 | /* Print type function for string type */ | 57 | /* Print type function for string type */ |
| 58 | __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, | 58 | int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name, |
| 59 | const char *name, | 59 | void *data, void *ent) |
| 60 | void *data, void *ent) | ||
| 61 | { | 60 | { |
| 62 | int len = *(u32 *)data >> 16; | 61 | int len = *(u32 *)data >> 16; |
| 63 | 62 | ||
| @@ -67,6 +66,7 @@ __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, | |||
| 67 | return trace_seq_printf(s, " %s=\"%s\"", name, | 66 | return trace_seq_printf(s, " %s=\"%s\"", name, |
| 68 | (const char *)get_loc_data(data, ent)); | 67 | (const char *)get_loc_data(data, ent)); |
| 69 | } | 68 | } |
| 69 | NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string)); | ||
| 70 | 70 | ||
| 71 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; | 71 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
| 72 | 72 | ||
| @@ -81,23 +81,24 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; | |||
| 81 | 81 | ||
| 82 | /* Data fetch function templates */ | 82 | /* Data fetch function templates */ |
| 83 | #define DEFINE_FETCH_reg(type) \ | 83 | #define DEFINE_FETCH_reg(type) \ |
| 84 | __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ | 84 | void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \ |
| 85 | void *offset, void *dest) \ | ||
| 86 | { \ | 85 | { \ |
| 87 | *(type *)dest = (type)regs_get_register(regs, \ | 86 | *(type *)dest = (type)regs_get_register(regs, \ |
| 88 | (unsigned int)((unsigned long)offset)); \ | 87 | (unsigned int)((unsigned long)offset)); \ |
| 89 | } | 88 | } \ |
| 89 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type)); | ||
| 90 | DEFINE_BASIC_FETCH_FUNCS(reg) | 90 | DEFINE_BASIC_FETCH_FUNCS(reg) |
| 91 | /* No string on the register */ | 91 | /* No string on the register */ |
| 92 | #define fetch_reg_string NULL | 92 | #define fetch_reg_string NULL |
| 93 | #define fetch_reg_string_size NULL | 93 | #define fetch_reg_string_size NULL |
| 94 | 94 | ||
| 95 | #define DEFINE_FETCH_retval(type) \ | 95 | #define DEFINE_FETCH_retval(type) \ |
| 96 | __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ | 96 | void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ |
| 97 | void *dummy, void *dest) \ | 97 | void *dummy, void *dest) \ |
| 98 | { \ | 98 | { \ |
| 99 | *(type *)dest = (type)regs_return_value(regs); \ | 99 | *(type *)dest = (type)regs_return_value(regs); \ |
| 100 | } | 100 | } \ |
| 101 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type)); | ||
| 101 | DEFINE_BASIC_FETCH_FUNCS(retval) | 102 | DEFINE_BASIC_FETCH_FUNCS(retval) |
| 102 | /* No string on the retval */ | 103 | /* No string on the retval */ |
| 103 | #define fetch_retval_string NULL | 104 | #define fetch_retval_string NULL |
| @@ -112,8 +113,8 @@ struct deref_fetch_param { | |||
| 112 | }; | 113 | }; |
| 113 | 114 | ||
| 114 | #define DEFINE_FETCH_deref(type) \ | 115 | #define DEFINE_FETCH_deref(type) \ |
| 115 | __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ | 116 | void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ |
| 116 | void *data, void *dest) \ | 117 | void *data, void *dest) \ |
| 117 | { \ | 118 | { \ |
| 118 | struct deref_fetch_param *dprm = data; \ | 119 | struct deref_fetch_param *dprm = data; \ |
| 119 | unsigned long addr; \ | 120 | unsigned long addr; \ |
| @@ -123,12 +124,13 @@ __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ | |||
| 123 | dprm->fetch(regs, (void *)addr, dest); \ | 124 | dprm->fetch(regs, (void *)addr, dest); \ |
| 124 | } else \ | 125 | } else \ |
| 125 | *(type *)dest = 0; \ | 126 | *(type *)dest = 0; \ |
| 126 | } | 127 | } \ |
| 128 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type)); | ||
| 127 | DEFINE_BASIC_FETCH_FUNCS(deref) | 129 | DEFINE_BASIC_FETCH_FUNCS(deref) |
| 128 | DEFINE_FETCH_deref(string) | 130 | DEFINE_FETCH_deref(string) |
| 129 | 131 | ||
| 130 | __kprobes void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, | 132 | void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, |
| 131 | void *data, void *dest) | 133 | void *data, void *dest) |
| 132 | { | 134 | { |
| 133 | struct deref_fetch_param *dprm = data; | 135 | struct deref_fetch_param *dprm = data; |
| 134 | unsigned long addr; | 136 | unsigned long addr; |
| @@ -140,16 +142,18 @@ __kprobes void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, | |||
| 140 | } else | 142 | } else |
| 141 | *(string_size *)dest = 0; | 143 | *(string_size *)dest = 0; |
| 142 | } | 144 | } |
| 145 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size)); | ||
| 143 | 146 | ||
| 144 | static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) | 147 | static void update_deref_fetch_param(struct deref_fetch_param *data) |
| 145 | { | 148 | { |
| 146 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | 149 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
| 147 | update_deref_fetch_param(data->orig.data); | 150 | update_deref_fetch_param(data->orig.data); |
| 148 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | 151 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) |
| 149 | update_symbol_cache(data->orig.data); | 152 | update_symbol_cache(data->orig.data); |
| 150 | } | 153 | } |
| 154 | NOKPROBE_SYMBOL(update_deref_fetch_param); | ||
| 151 | 155 | ||
| 152 | static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) | 156 | static void free_deref_fetch_param(struct deref_fetch_param *data) |
| 153 | { | 157 | { |
| 154 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | 158 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) |
| 155 | free_deref_fetch_param(data->orig.data); | 159 | free_deref_fetch_param(data->orig.data); |
| @@ -157,6 +161,7 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) | |||
| 157 | free_symbol_cache(data->orig.data); | 161 | free_symbol_cache(data->orig.data); |
| 158 | kfree(data); | 162 | kfree(data); |
| 159 | } | 163 | } |
| 164 | NOKPROBE_SYMBOL(free_deref_fetch_param); | ||
| 160 | 165 | ||
| 161 | /* Bitfield fetch function */ | 166 | /* Bitfield fetch function */ |
| 162 | struct bitfield_fetch_param { | 167 | struct bitfield_fetch_param { |
| @@ -166,8 +171,8 @@ struct bitfield_fetch_param { | |||
| 166 | }; | 171 | }; |
| 167 | 172 | ||
| 168 | #define DEFINE_FETCH_bitfield(type) \ | 173 | #define DEFINE_FETCH_bitfield(type) \ |
| 169 | __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ | 174 | void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ |
| 170 | void *data, void *dest) \ | 175 | void *data, void *dest) \ |
| 171 | { \ | 176 | { \ |
| 172 | struct bitfield_fetch_param *bprm = data; \ | 177 | struct bitfield_fetch_param *bprm = data; \ |
| 173 | type buf = 0; \ | 178 | type buf = 0; \ |
| @@ -177,13 +182,13 @@ __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ | |||
| 177 | buf >>= bprm->low_shift; \ | 182 | buf >>= bprm->low_shift; \ |
| 178 | } \ | 183 | } \ |
| 179 | *(type *)dest = buf; \ | 184 | *(type *)dest = buf; \ |
| 180 | } | 185 | } \ |
| 181 | 186 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type)); | |
| 182 | DEFINE_BASIC_FETCH_FUNCS(bitfield) | 187 | DEFINE_BASIC_FETCH_FUNCS(bitfield) |
| 183 | #define fetch_bitfield_string NULL | 188 | #define fetch_bitfield_string NULL |
| 184 | #define fetch_bitfield_string_size NULL | 189 | #define fetch_bitfield_string_size NULL |
| 185 | 190 | ||
| 186 | static __kprobes void | 191 | static void |
| 187 | update_bitfield_fetch_param(struct bitfield_fetch_param *data) | 192 | update_bitfield_fetch_param(struct bitfield_fetch_param *data) |
| 188 | { | 193 | { |
| 189 | /* | 194 | /* |
| @@ -196,7 +201,7 @@ update_bitfield_fetch_param(struct bitfield_fetch_param *data) | |||
| 196 | update_symbol_cache(data->orig.data); | 201 | update_symbol_cache(data->orig.data); |
| 197 | } | 202 | } |
| 198 | 203 | ||
| 199 | static __kprobes void | 204 | static void |
| 200 | free_bitfield_fetch_param(struct bitfield_fetch_param *data) | 205 | free_bitfield_fetch_param(struct bitfield_fetch_param *data) |
| 201 | { | 206 | { |
| 202 | /* | 207 | /* |
| @@ -255,17 +260,17 @@ fail: | |||
| 255 | } | 260 | } |
| 256 | 261 | ||
| 257 | /* Special function : only accept unsigned long */ | 262 | /* Special function : only accept unsigned long */ |
| 258 | static __kprobes void fetch_kernel_stack_address(struct pt_regs *regs, | 263 | static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
| 259 | void *dummy, void *dest) | ||
| 260 | { | 264 | { |
| 261 | *(unsigned long *)dest = kernel_stack_pointer(regs); | 265 | *(unsigned long *)dest = kernel_stack_pointer(regs); |
| 262 | } | 266 | } |
| 267 | NOKPROBE_SYMBOL(fetch_kernel_stack_address); | ||
| 263 | 268 | ||
| 264 | static __kprobes void fetch_user_stack_address(struct pt_regs *regs, | 269 | static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
| 265 | void *dummy, void *dest) | ||
| 266 | { | 270 | { |
| 267 | *(unsigned long *)dest = user_stack_pointer(regs); | 271 | *(unsigned long *)dest = user_stack_pointer(regs); |
| 268 | } | 272 | } |
| 273 | NOKPROBE_SYMBOL(fetch_user_stack_address); | ||
| 269 | 274 | ||
| 270 | static fetch_func_t get_fetch_size_function(const struct fetch_type *type, | 275 | static fetch_func_t get_fetch_size_function(const struct fetch_type *type, |
| 271 | fetch_func_t orig_fn, | 276 | fetch_func_t orig_fn, |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index fb1ab5dfbd42..4f815fbce16d 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
| @@ -81,13 +81,13 @@ | |||
| 81 | */ | 81 | */ |
| 82 | #define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs)) | 82 | #define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs)) |
| 83 | 83 | ||
| 84 | static inline void *get_rloc_data(u32 *dl) | 84 | static nokprobe_inline void *get_rloc_data(u32 *dl) |
| 85 | { | 85 | { |
| 86 | return (u8 *)dl + get_rloc_offs(*dl); | 86 | return (u8 *)dl + get_rloc_offs(*dl); |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | /* For data_loc conversion */ | 89 | /* For data_loc conversion */ |
| 90 | static inline void *get_loc_data(u32 *dl, void *ent) | 90 | static nokprobe_inline void *get_loc_data(u32 *dl, void *ent) |
| 91 | { | 91 | { |
| 92 | return (u8 *)ent + get_rloc_offs(*dl); | 92 | return (u8 *)ent + get_rloc_offs(*dl); |
| 93 | } | 93 | } |
| @@ -136,9 +136,8 @@ typedef u32 string_size; | |||
| 136 | 136 | ||
| 137 | /* Printing in basic type function template */ | 137 | /* Printing in basic type function template */ |
| 138 | #define DECLARE_BASIC_PRINT_TYPE_FUNC(type) \ | 138 | #define DECLARE_BASIC_PRINT_TYPE_FUNC(type) \ |
| 139 | __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ | 139 | int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name, \ |
| 140 | const char *name, \ | 140 | void *data, void *ent); \ |
| 141 | void *data, void *ent); \ | ||
| 142 | extern const char PRINT_TYPE_FMT_NAME(type)[] | 141 | extern const char PRINT_TYPE_FMT_NAME(type)[] |
| 143 | 142 | ||
| 144 | DECLARE_BASIC_PRINT_TYPE_FUNC(u8); | 143 | DECLARE_BASIC_PRINT_TYPE_FUNC(u8); |
| @@ -303,7 +302,7 @@ static inline bool trace_probe_is_registered(struct trace_probe *tp) | |||
| 303 | return !!(tp->flags & TP_FLAG_REGISTERED); | 302 | return !!(tp->flags & TP_FLAG_REGISTERED); |
| 304 | } | 303 | } |
| 305 | 304 | ||
| 306 | static inline __kprobes void call_fetch(struct fetch_param *fprm, | 305 | static nokprobe_inline void call_fetch(struct fetch_param *fprm, |
| 307 | struct pt_regs *regs, void *dest) | 306 | struct pt_regs *regs, void *dest) |
| 308 | { | 307 | { |
| 309 | return fprm->fn(regs, fprm->data, dest); | 308 | return fprm->fn(regs, fprm->data, dest); |
| @@ -351,7 +350,7 @@ extern ssize_t traceprobe_probes_write(struct file *file, | |||
| 351 | extern int traceprobe_command(const char *buf, int (*createfn)(int, char**)); | 350 | extern int traceprobe_command(const char *buf, int (*createfn)(int, char**)); |
| 352 | 351 | ||
| 353 | /* Sum up total data length for dynamic arraies (strings) */ | 352 | /* Sum up total data length for dynamic arraies (strings) */ |
| 354 | static inline __kprobes int | 353 | static nokprobe_inline int |
| 355 | __get_data_size(struct trace_probe *tp, struct pt_regs *regs) | 354 | __get_data_size(struct trace_probe *tp, struct pt_regs *regs) |
| 356 | { | 355 | { |
| 357 | int i, ret = 0; | 356 | int i, ret = 0; |
| @@ -367,7 +366,7 @@ __get_data_size(struct trace_probe *tp, struct pt_regs *regs) | |||
| 367 | } | 366 | } |
| 368 | 367 | ||
| 369 | /* Store the value of each argument */ | 368 | /* Store the value of each argument */ |
| 370 | static inline __kprobes void | 369 | static nokprobe_inline void |
| 371 | store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, | 370 | store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, |
| 372 | u8 *data, int maxlen) | 371 | u8 *data, int maxlen) |
| 373 | { | 372 | { |
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index c082a7441345..04fdb5de823c 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
| @@ -108,8 +108,8 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n) | |||
| 108 | * Uprobes-specific fetch functions | 108 | * Uprobes-specific fetch functions |
| 109 | */ | 109 | */ |
| 110 | #define DEFINE_FETCH_stack(type) \ | 110 | #define DEFINE_FETCH_stack(type) \ |
| 111 | static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ | 111 | static void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs, \ |
| 112 | void *offset, void *dest) \ | 112 | void *offset, void *dest) \ |
| 113 | { \ | 113 | { \ |
| 114 | *(type *)dest = (type)get_user_stack_nth(regs, \ | 114 | *(type *)dest = (type)get_user_stack_nth(regs, \ |
| 115 | ((unsigned long)offset)); \ | 115 | ((unsigned long)offset)); \ |
| @@ -120,8 +120,8 @@ DEFINE_BASIC_FETCH_FUNCS(stack) | |||
| 120 | #define fetch_stack_string_size NULL | 120 | #define fetch_stack_string_size NULL |
| 121 | 121 | ||
| 122 | #define DEFINE_FETCH_memory(type) \ | 122 | #define DEFINE_FETCH_memory(type) \ |
| 123 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | 123 | static void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \ |
| 124 | void *addr, void *dest) \ | 124 | void *addr, void *dest) \ |
| 125 | { \ | 125 | { \ |
| 126 | type retval; \ | 126 | type retval; \ |
| 127 | void __user *vaddr = (void __force __user *) addr; \ | 127 | void __user *vaddr = (void __force __user *) addr; \ |
| @@ -136,8 +136,8 @@ DEFINE_BASIC_FETCH_FUNCS(memory) | |||
| 136 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | 136 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max |
| 137 | * length and relative data location. | 137 | * length and relative data location. |
| 138 | */ | 138 | */ |
| 139 | static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | 139 | static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, |
| 140 | void *addr, void *dest) | 140 | void *addr, void *dest) |
| 141 | { | 141 | { |
| 142 | long ret; | 142 | long ret; |
| 143 | u32 rloc = *(u32 *)dest; | 143 | u32 rloc = *(u32 *)dest; |
| @@ -158,8 +158,8 @@ static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | |||
| 158 | } | 158 | } |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | 161 | static void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, |
| 162 | void *addr, void *dest) | 162 | void *addr, void *dest) |
| 163 | { | 163 | { |
| 164 | int len; | 164 | int len; |
| 165 | void __user *vaddr = (void __force __user *) addr; | 165 | void __user *vaddr = (void __force __user *) addr; |
| @@ -184,8 +184,8 @@ static unsigned long translate_user_vaddr(void *file_offset) | |||
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | #define DEFINE_FETCH_file_offset(type) \ | 186 | #define DEFINE_FETCH_file_offset(type) \ |
| 187 | static __kprobes void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs,\ | 187 | static void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs, \ |
| 188 | void *offset, void *dest) \ | 188 | void *offset, void *dest)\ |
| 189 | { \ | 189 | { \ |
| 190 | void *vaddr = (void *)translate_user_vaddr(offset); \ | 190 | void *vaddr = (void *)translate_user_vaddr(offset); \ |
| 191 | \ | 191 | \ |
| @@ -1009,56 +1009,60 @@ uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event) | |||
| 1009 | return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm); | 1009 | return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm); |
| 1010 | } | 1010 | } |
| 1011 | 1011 | ||
| 1012 | static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) | 1012 | static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) |
| 1013 | { | 1013 | { |
| 1014 | bool done; | 1014 | bool done; |
| 1015 | 1015 | ||
| 1016 | write_lock(&tu->filter.rwlock); | 1016 | write_lock(&tu->filter.rwlock); |
| 1017 | if (event->hw.tp_target) { | 1017 | if (event->hw.tp_target) { |
| 1018 | /* | 1018 | list_del(&event->hw.tp_list); |
| 1019 | * event->parent != NULL means copy_process(), we can avoid | ||
| 1020 | * uprobe_apply(). current->mm must be probed and we can rely | ||
| 1021 | * on dup_mmap() which preserves the already installed bp's. | ||
| 1022 | * | ||
| 1023 | * attr.enable_on_exec means that exec/mmap will install the | ||
| 1024 | * breakpoints we need. | ||
| 1025 | */ | ||
| 1026 | done = tu->filter.nr_systemwide || | 1019 | done = tu->filter.nr_systemwide || |
| 1027 | event->parent || event->attr.enable_on_exec || | 1020 | (event->hw.tp_target->flags & PF_EXITING) || |
| 1028 | uprobe_filter_event(tu, event); | 1021 | uprobe_filter_event(tu, event); |
| 1029 | list_add(&event->hw.tp_list, &tu->filter.perf_events); | ||
| 1030 | } else { | 1022 | } else { |
| 1023 | tu->filter.nr_systemwide--; | ||
| 1031 | done = tu->filter.nr_systemwide; | 1024 | done = tu->filter.nr_systemwide; |
| 1032 | tu->filter.nr_systemwide++; | ||
| 1033 | } | 1025 | } |
| 1034 | write_unlock(&tu->filter.rwlock); | 1026 | write_unlock(&tu->filter.rwlock); |
| 1035 | 1027 | ||
| 1036 | if (!done) | 1028 | if (!done) |
| 1037 | uprobe_apply(tu->inode, tu->offset, &tu->consumer, true); | 1029 | return uprobe_apply(tu->inode, tu->offset, &tu->consumer, false); |
| 1038 | 1030 | ||
| 1039 | return 0; | 1031 | return 0; |
| 1040 | } | 1032 | } |
| 1041 | 1033 | ||
| 1042 | static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event) | 1034 | static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event) |
| 1043 | { | 1035 | { |
| 1044 | bool done; | 1036 | bool done; |
| 1037 | int err; | ||
| 1045 | 1038 | ||
| 1046 | write_lock(&tu->filter.rwlock); | 1039 | write_lock(&tu->filter.rwlock); |
| 1047 | if (event->hw.tp_target) { | 1040 | if (event->hw.tp_target) { |
| 1048 | list_del(&event->hw.tp_list); | 1041 | /* |
| 1042 | * event->parent != NULL means copy_process(), we can avoid | ||
| 1043 | * uprobe_apply(). current->mm must be probed and we can rely | ||
| 1044 | * on dup_mmap() which preserves the already installed bp's. | ||
| 1045 | * | ||
| 1046 | * attr.enable_on_exec means that exec/mmap will install the | ||
| 1047 | * breakpoints we need. | ||
| 1048 | */ | ||
| 1049 | done = tu->filter.nr_systemwide || | 1049 | done = tu->filter.nr_systemwide || |
| 1050 | (event->hw.tp_target->flags & PF_EXITING) || | 1050 | event->parent || event->attr.enable_on_exec || |
| 1051 | uprobe_filter_event(tu, event); | 1051 | uprobe_filter_event(tu, event); |
| 1052 | list_add(&event->hw.tp_list, &tu->filter.perf_events); | ||
| 1052 | } else { | 1053 | } else { |
| 1053 | tu->filter.nr_systemwide--; | ||
| 1054 | done = tu->filter.nr_systemwide; | 1054 | done = tu->filter.nr_systemwide; |
| 1055 | tu->filter.nr_systemwide++; | ||
| 1055 | } | 1056 | } |
| 1056 | write_unlock(&tu->filter.rwlock); | 1057 | write_unlock(&tu->filter.rwlock); |
| 1057 | 1058 | ||
| 1058 | if (!done) | 1059 | err = 0; |
| 1059 | uprobe_apply(tu->inode, tu->offset, &tu->consumer, false); | 1060 | if (!done) { |
| 1060 | 1061 | err = uprobe_apply(tu->inode, tu->offset, &tu->consumer, true); | |
| 1061 | return 0; | 1062 | if (err) |
| 1063 | uprobe_perf_close(tu, event); | ||
| 1064 | } | ||
| 1065 | return err; | ||
| 1062 | } | 1066 | } |
| 1063 | 1067 | ||
| 1064 | static bool uprobe_perf_filter(struct uprobe_consumer *uc, | 1068 | static bool uprobe_perf_filter(struct uprobe_consumer *uc, |
