diff options
| -rw-r--r-- | include/linux/ftrace.h | 3 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 59 |
2 files changed, 60 insertions, 2 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 9962e954a633..3e711122f66c 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
| @@ -317,6 +317,8 @@ struct dyn_ftrace { | |||
| 317 | }; | 317 | }; |
| 318 | 318 | ||
| 319 | int ftrace_force_update(void); | 319 | int ftrace_force_update(void); |
| 320 | int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip, | ||
| 321 | int remove, int reset); | ||
| 320 | int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, | 322 | int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, |
| 321 | int len, int reset); | 323 | int len, int reset); |
| 322 | int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, | 324 | int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, |
| @@ -544,6 +546,7 @@ static inline int ftrace_text_reserved(void *start, void *end) | |||
| 544 | */ | 546 | */ |
| 545 | #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) | 547 | #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) |
| 546 | #define ftrace_set_early_filter(ops, buf, enable) do { } while (0) | 548 | #define ftrace_set_early_filter(ops, buf, enable) do { } while (0) |
| 549 | #define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; }) | ||
| 547 | #define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; }) | 550 | #define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; }) |
| 548 | #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; }) | 551 | #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; }) |
| 549 | #define ftrace_free_filter(ops) do { } while (0) | 552 | #define ftrace_free_filter(ops) do { } while (0) |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 528d997c7f99..9dcf15d38380 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -3242,8 +3242,27 @@ ftrace_notrace_write(struct file *file, const char __user *ubuf, | |||
| 3242 | } | 3242 | } |
| 3243 | 3243 | ||
| 3244 | static int | 3244 | static int |
| 3245 | ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, | 3245 | ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove) |
| 3246 | int reset, int enable) | 3246 | { |
| 3247 | struct ftrace_func_entry *entry; | ||
| 3248 | |||
| 3249 | if (!ftrace_location(ip)) | ||
| 3250 | return -EINVAL; | ||
| 3251 | |||
| 3252 | if (remove) { | ||
| 3253 | entry = ftrace_lookup_ip(hash, ip); | ||
| 3254 | if (!entry) | ||
| 3255 | return -ENOENT; | ||
| 3256 | free_hash_entry(hash, entry); | ||
| 3257 | return 0; | ||
| 3258 | } | ||
| 3259 | |||
| 3260 | return add_hash_entry(hash, ip); | ||
| 3261 | } | ||
| 3262 | |||
| 3263 | static int | ||
| 3264 | ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, | ||
| 3265 | unsigned long ip, int remove, int reset, int enable) | ||
| 3247 | { | 3266 | { |
| 3248 | struct ftrace_hash **orig_hash; | 3267 | struct ftrace_hash **orig_hash; |
| 3249 | struct ftrace_hash *hash; | 3268 | struct ftrace_hash *hash; |
| @@ -3272,6 +3291,11 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
| 3272 | ret = -EINVAL; | 3291 | ret = -EINVAL; |
| 3273 | goto out_regex_unlock; | 3292 | goto out_regex_unlock; |
| 3274 | } | 3293 | } |
| 3294 | if (ip) { | ||
| 3295 | ret = ftrace_match_addr(hash, ip, remove); | ||
| 3296 | if (ret < 0) | ||
| 3297 | goto out_regex_unlock; | ||
| 3298 | } | ||
| 3275 | 3299 | ||
| 3276 | mutex_lock(&ftrace_lock); | 3300 | mutex_lock(&ftrace_lock); |
| 3277 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); | 3301 | ret = ftrace_hash_move(ops, enable, orig_hash, hash); |
| @@ -3288,6 +3312,37 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, | |||
| 3288 | return ret; | 3312 | return ret; |
| 3289 | } | 3313 | } |
| 3290 | 3314 | ||
| 3315 | static int | ||
| 3316 | ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove, | ||
| 3317 | int reset, int enable) | ||
| 3318 | { | ||
| 3319 | return ftrace_set_hash(ops, 0, 0, ip, remove, reset, enable); | ||
| 3320 | } | ||
| 3321 | |||
| 3322 | /** | ||
| 3323 | * ftrace_set_filter_ip - set a function to filter on in ftrace by address | ||
| 3324 | * @ops - the ops to set the filter with | ||
| 3325 | * @ip - the address to add to or remove from the filter. | ||
| 3326 | * @remove - non zero to remove the ip from the filter | ||
| 3327 | * @reset - non zero to reset all filters before applying this filter. | ||
| 3328 | * | ||
| 3329 | * Filters denote which functions should be enabled when tracing is enabled | ||
| 3330 | * If @ip is NULL, it failes to update filter. | ||
| 3331 | */ | ||
| 3332 | int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip, | ||
| 3333 | int remove, int reset) | ||
| 3334 | { | ||
| 3335 | return ftrace_set_addr(ops, ip, remove, reset, 1); | ||
| 3336 | } | ||
| 3337 | EXPORT_SYMBOL_GPL(ftrace_set_filter_ip); | ||
| 3338 | |||
| 3339 | static int | ||
| 3340 | ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, | ||
| 3341 | int reset, int enable) | ||
| 3342 | { | ||
| 3343 | return ftrace_set_hash(ops, buf, len, 0, 0, reset, enable); | ||
| 3344 | } | ||
| 3345 | |||
| 3291 | /** | 3346 | /** |
| 3292 | * ftrace_set_filter - set a function to filter on in ftrace | 3347 | * ftrace_set_filter - set a function to filter on in ftrace |
| 3293 | * @ops - the ops to set the filter with | 3348 | * @ops - the ops to set the filter with |
