diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_event.c | 82 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 370 | ||||
-rw-r--r-- | kernel/trace/ring_buffer.c | 15 | ||||
-rw-r--r-- | kernel/trace/trace.c | 4 | ||||
-rw-r--r-- | kernel/trace/trace.h | 48 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 47 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 423 | ||||
-rw-r--r-- | kernel/trace/trace_export.c | 25 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 106 |
9 files changed, 781 insertions, 339 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 9d0b5c665883..9ecaa45ab6b2 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/anon_inodes.h> | 28 | #include <linux/anon_inodes.h> |
29 | #include <linux/kernel_stat.h> | 29 | #include <linux/kernel_stat.h> |
30 | #include <linux/perf_event.h> | 30 | #include <linux/perf_event.h> |
31 | #include <linux/ftrace_event.h> | ||
31 | 32 | ||
32 | #include <asm/irq_regs.h> | 33 | #include <asm/irq_regs.h> |
33 | 34 | ||
@@ -1355,7 +1356,7 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx) | |||
1355 | u64 interrupts, freq; | 1356 | u64 interrupts, freq; |
1356 | 1357 | ||
1357 | spin_lock(&ctx->lock); | 1358 | spin_lock(&ctx->lock); |
1358 | list_for_each_entry(event, &ctx->group_list, group_entry) { | 1359 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { |
1359 | if (event->state != PERF_EVENT_STATE_ACTIVE) | 1360 | if (event->state != PERF_EVENT_STATE_ACTIVE) |
1360 | continue; | 1361 | continue; |
1361 | 1362 | ||
@@ -1658,6 +1659,8 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu) | |||
1658 | return ERR_PTR(err); | 1659 | return ERR_PTR(err); |
1659 | } | 1660 | } |
1660 | 1661 | ||
1662 | static void perf_event_free_filter(struct perf_event *event); | ||
1663 | |||
1661 | static void free_event_rcu(struct rcu_head *head) | 1664 | static void free_event_rcu(struct rcu_head *head) |
1662 | { | 1665 | { |
1663 | struct perf_event *event; | 1666 | struct perf_event *event; |
@@ -1665,6 +1668,7 @@ static void free_event_rcu(struct rcu_head *head) | |||
1665 | event = container_of(head, struct perf_event, rcu_head); | 1668 | event = container_of(head, struct perf_event, rcu_head); |
1666 | if (event->ns) | 1669 | if (event->ns) |
1667 | put_pid_ns(event->ns); | 1670 | put_pid_ns(event->ns); |
1671 | perf_event_free_filter(event); | ||
1668 | kfree(event); | 1672 | kfree(event); |
1669 | } | 1673 | } |
1670 | 1674 | ||
@@ -1974,7 +1978,8 @@ unlock: | |||
1974 | return ret; | 1978 | return ret; |
1975 | } | 1979 | } |
1976 | 1980 | ||
1977 | int perf_event_set_output(struct perf_event *event, int output_fd); | 1981 | static int perf_event_set_output(struct perf_event *event, int output_fd); |
1982 | static int perf_event_set_filter(struct perf_event *event, void __user *arg); | ||
1978 | 1983 | ||
1979 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1984 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1980 | { | 1985 | { |
@@ -2002,6 +2007,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2002 | case PERF_EVENT_IOC_SET_OUTPUT: | 2007 | case PERF_EVENT_IOC_SET_OUTPUT: |
2003 | return perf_event_set_output(event, arg); | 2008 | return perf_event_set_output(event, arg); |
2004 | 2009 | ||
2010 | case PERF_EVENT_IOC_SET_FILTER: | ||
2011 | return perf_event_set_filter(event, (void __user *)arg); | ||
2012 | |||
2005 | default: | 2013 | default: |
2006 | return -ENOTTY; | 2014 | return -ENOTTY; |
2007 | } | 2015 | } |
@@ -3806,9 +3814,14 @@ static int perf_swevent_is_counting(struct perf_event *event) | |||
3806 | return 1; | 3814 | return 1; |
3807 | } | 3815 | } |
3808 | 3816 | ||
3817 | static int perf_tp_event_match(struct perf_event *event, | ||
3818 | struct perf_sample_data *data); | ||
3819 | |||
3809 | static int perf_swevent_match(struct perf_event *event, | 3820 | static int perf_swevent_match(struct perf_event *event, |
3810 | enum perf_type_id type, | 3821 | enum perf_type_id type, |
3811 | u32 event_id, struct pt_regs *regs) | 3822 | u32 event_id, |
3823 | struct perf_sample_data *data, | ||
3824 | struct pt_regs *regs) | ||
3812 | { | 3825 | { |
3813 | if (!perf_swevent_is_counting(event)) | 3826 | if (!perf_swevent_is_counting(event)) |
3814 | return 0; | 3827 | return 0; |
@@ -3826,6 +3839,10 @@ static int perf_swevent_match(struct perf_event *event, | |||
3826 | return 0; | 3839 | return 0; |
3827 | } | 3840 | } |
3828 | 3841 | ||
3842 | if (event->attr.type == PERF_TYPE_TRACEPOINT && | ||
3843 | !perf_tp_event_match(event, data)) | ||
3844 | return 0; | ||
3845 | |||
3829 | return 1; | 3846 | return 1; |
3830 | } | 3847 | } |
3831 | 3848 | ||
@@ -3842,7 +3859,7 @@ static void perf_swevent_ctx_event(struct perf_event_context *ctx, | |||
3842 | 3859 | ||
3843 | rcu_read_lock(); | 3860 | rcu_read_lock(); |
3844 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { | 3861 | list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { |
3845 | if (perf_swevent_match(event, type, event_id, regs)) | 3862 | if (perf_swevent_match(event, type, event_id, data, regs)) |
3846 | perf_swevent_add(event, nr, nmi, data, regs); | 3863 | perf_swevent_add(event, nr, nmi, data, regs); |
3847 | } | 3864 | } |
3848 | rcu_read_unlock(); | 3865 | rcu_read_unlock(); |
@@ -4086,6 +4103,7 @@ static const struct pmu perf_ops_task_clock = { | |||
4086 | }; | 4103 | }; |
4087 | 4104 | ||
4088 | #ifdef CONFIG_EVENT_PROFILE | 4105 | #ifdef CONFIG_EVENT_PROFILE |
4106 | |||
4089 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 4107 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, |
4090 | int entry_size) | 4108 | int entry_size) |
4091 | { | 4109 | { |
@@ -4109,8 +4127,15 @@ void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | |||
4109 | } | 4127 | } |
4110 | EXPORT_SYMBOL_GPL(perf_tp_event); | 4128 | EXPORT_SYMBOL_GPL(perf_tp_event); |
4111 | 4129 | ||
4112 | extern int ftrace_profile_enable(int); | 4130 | static int perf_tp_event_match(struct perf_event *event, |
4113 | extern void ftrace_profile_disable(int); | 4131 | struct perf_sample_data *data) |
4132 | { | ||
4133 | void *record = data->raw->data; | ||
4134 | |||
4135 | if (likely(!event->filter) || filter_match_preds(event->filter, record)) | ||
4136 | return 1; | ||
4137 | return 0; | ||
4138 | } | ||
4114 | 4139 | ||
4115 | static void tp_perf_event_destroy(struct perf_event *event) | 4140 | static void tp_perf_event_destroy(struct perf_event *event) |
4116 | { | 4141 | { |
@@ -4135,12 +4160,53 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event) | |||
4135 | 4160 | ||
4136 | return &perf_ops_generic; | 4161 | return &perf_ops_generic; |
4137 | } | 4162 | } |
4163 | |||
4164 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
4165 | { | ||
4166 | char *filter_str; | ||
4167 | int ret; | ||
4168 | |||
4169 | if (event->attr.type != PERF_TYPE_TRACEPOINT) | ||
4170 | return -EINVAL; | ||
4171 | |||
4172 | filter_str = strndup_user(arg, PAGE_SIZE); | ||
4173 | if (IS_ERR(filter_str)) | ||
4174 | return PTR_ERR(filter_str); | ||
4175 | |||
4176 | ret = ftrace_profile_set_filter(event, event->attr.config, filter_str); | ||
4177 | |||
4178 | kfree(filter_str); | ||
4179 | return ret; | ||
4180 | } | ||
4181 | |||
4182 | static void perf_event_free_filter(struct perf_event *event) | ||
4183 | { | ||
4184 | ftrace_profile_free_filter(event); | ||
4185 | } | ||
4186 | |||
4138 | #else | 4187 | #else |
4188 | |||
4189 | static int perf_tp_event_match(struct perf_event *event, | ||
4190 | struct perf_sample_data *data) | ||
4191 | { | ||
4192 | return 1; | ||
4193 | } | ||
4194 | |||
4139 | static const struct pmu *tp_perf_event_init(struct perf_event *event) | 4195 | static const struct pmu *tp_perf_event_init(struct perf_event *event) |
4140 | { | 4196 | { |
4141 | return NULL; | 4197 | return NULL; |
4142 | } | 4198 | } |
4143 | #endif | 4199 | |
4200 | static int perf_event_set_filter(struct perf_event *event, void __user *arg) | ||
4201 | { | ||
4202 | return -ENOENT; | ||
4203 | } | ||
4204 | |||
4205 | static void perf_event_free_filter(struct perf_event *event) | ||
4206 | { | ||
4207 | } | ||
4208 | |||
4209 | #endif /* CONFIG_EVENT_PROFILE */ | ||
4144 | 4210 | ||
4145 | atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; | 4211 | atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; |
4146 | 4212 | ||
@@ -4394,7 +4460,7 @@ err_size: | |||
4394 | goto out; | 4460 | goto out; |
4395 | } | 4461 | } |
4396 | 4462 | ||
4397 | int perf_event_set_output(struct perf_event *event, int output_fd) | 4463 | static int perf_event_set_output(struct perf_event *event, int output_fd) |
4398 | { | 4464 | { |
4399 | struct perf_event *output_event = NULL; | 4465 | struct perf_event *output_event = NULL; |
4400 | struct file *output_file = NULL; | 4466 | struct file *output_file = NULL; |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 37ba67e33265..b10c0d90a6ff 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -60,6 +60,13 @@ static int last_ftrace_enabled; | |||
60 | /* Quick disabling of function tracer. */ | 60 | /* Quick disabling of function tracer. */ |
61 | int function_trace_stop; | 61 | int function_trace_stop; |
62 | 62 | ||
63 | /* List for set_ftrace_pid's pids. */ | ||
64 | LIST_HEAD(ftrace_pids); | ||
65 | struct ftrace_pid { | ||
66 | struct list_head list; | ||
67 | struct pid *pid; | ||
68 | }; | ||
69 | |||
63 | /* | 70 | /* |
64 | * ftrace_disabled is set when an anomaly is discovered. | 71 | * ftrace_disabled is set when an anomaly is discovered. |
65 | * ftrace_disabled is much stronger than ftrace_enabled. | 72 | * ftrace_disabled is much stronger than ftrace_enabled. |
@@ -78,6 +85,10 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | |||
78 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 85 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
79 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 86 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
80 | 87 | ||
88 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
89 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | ||
90 | #endif | ||
91 | |||
81 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) | 92 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
82 | { | 93 | { |
83 | struct ftrace_ops *op = ftrace_list; | 94 | struct ftrace_ops *op = ftrace_list; |
@@ -155,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
155 | else | 166 | else |
156 | func = ftrace_list_func; | 167 | func = ftrace_list_func; |
157 | 168 | ||
158 | if (ftrace_pid_trace) { | 169 | if (!list_empty(&ftrace_pids)) { |
159 | set_ftrace_pid_function(func); | 170 | set_ftrace_pid_function(func); |
160 | func = ftrace_pid_func; | 171 | func = ftrace_pid_func; |
161 | } | 172 | } |
@@ -203,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
203 | if (ftrace_list->next == &ftrace_list_end) { | 214 | if (ftrace_list->next == &ftrace_list_end) { |
204 | ftrace_func_t func = ftrace_list->func; | 215 | ftrace_func_t func = ftrace_list->func; |
205 | 216 | ||
206 | if (ftrace_pid_trace) { | 217 | if (!list_empty(&ftrace_pids)) { |
207 | set_ftrace_pid_function(func); | 218 | set_ftrace_pid_function(func); |
208 | func = ftrace_pid_func; | 219 | func = ftrace_pid_func; |
209 | } | 220 | } |
@@ -231,7 +242,7 @@ static void ftrace_update_pid_func(void) | |||
231 | func = __ftrace_trace_function; | 242 | func = __ftrace_trace_function; |
232 | #endif | 243 | #endif |
233 | 244 | ||
234 | if (ftrace_pid_trace) { | 245 | if (!list_empty(&ftrace_pids)) { |
235 | set_ftrace_pid_function(func); | 246 | set_ftrace_pid_function(func); |
236 | func = ftrace_pid_func; | 247 | func = ftrace_pid_func; |
237 | } else { | 248 | } else { |
@@ -821,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer) | |||
821 | } | 832 | } |
822 | #endif /* CONFIG_FUNCTION_PROFILER */ | 833 | #endif /* CONFIG_FUNCTION_PROFILER */ |
823 | 834 | ||
824 | /* set when tracing only a pid */ | ||
825 | struct pid *ftrace_pid_trace; | ||
826 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | 835 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; |
827 | 836 | ||
828 | #ifdef CONFIG_DYNAMIC_FTRACE | 837 | #ifdef CONFIG_DYNAMIC_FTRACE |
@@ -1261,12 +1270,34 @@ static int ftrace_update_code(struct module *mod) | |||
1261 | ftrace_new_addrs = p->newlist; | 1270 | ftrace_new_addrs = p->newlist; |
1262 | p->flags = 0L; | 1271 | p->flags = 0L; |
1263 | 1272 | ||
1264 | /* convert record (i.e, patch mcount-call with NOP) */ | 1273 | /* |
1265 | if (ftrace_code_disable(mod, p)) { | 1274 | * Do the initial record convertion from mcount jump |
1266 | p->flags |= FTRACE_FL_CONVERTED; | 1275 | * to the NOP instructions. |
1267 | ftrace_update_cnt++; | 1276 | */ |
1268 | } else | 1277 | if (!ftrace_code_disable(mod, p)) { |
1269 | ftrace_free_rec(p); | 1278 | ftrace_free_rec(p); |
1279 | continue; | ||
1280 | } | ||
1281 | |||
1282 | p->flags |= FTRACE_FL_CONVERTED; | ||
1283 | ftrace_update_cnt++; | ||
1284 | |||
1285 | /* | ||
1286 | * If the tracing is enabled, go ahead and enable the record. | ||
1287 | * | ||
1288 | * The reason not to enable the record immediatelly is the | ||
1289 | * inherent check of ftrace_make_nop/ftrace_make_call for | ||
1290 | * correct previous instructions. Making first the NOP | ||
1291 | * conversion puts the module to the correct state, thus | ||
1292 | * passing the ftrace_make_call check. | ||
1293 | */ | ||
1294 | if (ftrace_start_up) { | ||
1295 | int failed = __ftrace_replace_code(p, 1); | ||
1296 | if (failed) { | ||
1297 | ftrace_bug(failed, p->ip); | ||
1298 | ftrace_free_rec(p); | ||
1299 | } | ||
1300 | } | ||
1270 | } | 1301 | } |
1271 | 1302 | ||
1272 | stop = ftrace_now(raw_smp_processor_id()); | 1303 | stop = ftrace_now(raw_smp_processor_id()); |
@@ -1656,60 +1687,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) | |||
1656 | return ret; | 1687 | return ret; |
1657 | } | 1688 | } |
1658 | 1689 | ||
1659 | enum { | ||
1660 | MATCH_FULL, | ||
1661 | MATCH_FRONT_ONLY, | ||
1662 | MATCH_MIDDLE_ONLY, | ||
1663 | MATCH_END_ONLY, | ||
1664 | }; | ||
1665 | |||
1666 | /* | ||
1667 | * (static function - no need for kernel doc) | ||
1668 | * | ||
1669 | * Pass in a buffer containing a glob and this function will | ||
1670 | * set search to point to the search part of the buffer and | ||
1671 | * return the type of search it is (see enum above). | ||
1672 | * This does modify buff. | ||
1673 | * | ||
1674 | * Returns enum type. | ||
1675 | * search returns the pointer to use for comparison. | ||
1676 | * not returns 1 if buff started with a '!' | ||
1677 | * 0 otherwise. | ||
1678 | */ | ||
1679 | static int | ||
1680 | ftrace_setup_glob(char *buff, int len, char **search, int *not) | ||
1681 | { | ||
1682 | int type = MATCH_FULL; | ||
1683 | int i; | ||
1684 | |||
1685 | if (buff[0] == '!') { | ||
1686 | *not = 1; | ||
1687 | buff++; | ||
1688 | len--; | ||
1689 | } else | ||
1690 | *not = 0; | ||
1691 | |||
1692 | *search = buff; | ||
1693 | |||
1694 | for (i = 0; i < len; i++) { | ||
1695 | if (buff[i] == '*') { | ||
1696 | if (!i) { | ||
1697 | *search = buff + 1; | ||
1698 | type = MATCH_END_ONLY; | ||
1699 | } else { | ||
1700 | if (type == MATCH_END_ONLY) | ||
1701 | type = MATCH_MIDDLE_ONLY; | ||
1702 | else | ||
1703 | type = MATCH_FRONT_ONLY; | ||
1704 | buff[i] = 0; | ||
1705 | break; | ||
1706 | } | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | return type; | ||
1711 | } | ||
1712 | |||
1713 | static int ftrace_match(char *str, char *regex, int len, int type) | 1690 | static int ftrace_match(char *str, char *regex, int len, int type) |
1714 | { | 1691 | { |
1715 | int matched = 0; | 1692 | int matched = 0; |
@@ -1758,7 +1735,7 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
1758 | int not; | 1735 | int not; |
1759 | 1736 | ||
1760 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1737 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
1761 | type = ftrace_setup_glob(buff, len, &search, ¬); | 1738 | type = filter_parse_regex(buff, len, &search, ¬); |
1762 | 1739 | ||
1763 | search_len = strlen(search); | 1740 | search_len = strlen(search); |
1764 | 1741 | ||
@@ -1826,7 +1803,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
1826 | } | 1803 | } |
1827 | 1804 | ||
1828 | if (strlen(buff)) { | 1805 | if (strlen(buff)) { |
1829 | type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | 1806 | type = filter_parse_regex(buff, strlen(buff), &search, ¬); |
1830 | search_len = strlen(search); | 1807 | search_len = strlen(search); |
1831 | } | 1808 | } |
1832 | 1809 | ||
@@ -1991,7 +1968,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
1991 | int count = 0; | 1968 | int count = 0; |
1992 | char *search; | 1969 | char *search; |
1993 | 1970 | ||
1994 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 1971 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
1995 | len = strlen(search); | 1972 | len = strlen(search); |
1996 | 1973 | ||
1997 | /* we do not support '!' for function probes */ | 1974 | /* we do not support '!' for function probes */ |
@@ -2068,7 +2045,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
2068 | else if (glob) { | 2045 | else if (glob) { |
2069 | int not; | 2046 | int not; |
2070 | 2047 | ||
2071 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2048 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
2072 | len = strlen(search); | 2049 | len = strlen(search); |
2073 | 2050 | ||
2074 | /* we do not support '!' for function probes */ | 2051 | /* we do not support '!' for function probes */ |
@@ -2297,6 +2274,7 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset) | |||
2297 | #define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE | 2274 | #define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE |
2298 | static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; | 2275 | static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; |
2299 | static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; | 2276 | static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; |
2277 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | ||
2300 | 2278 | ||
2301 | static int __init set_ftrace_notrace(char *str) | 2279 | static int __init set_ftrace_notrace(char *str) |
2302 | { | 2280 | { |
@@ -2312,6 +2290,31 @@ static int __init set_ftrace_filter(char *str) | |||
2312 | } | 2290 | } |
2313 | __setup("ftrace_filter=", set_ftrace_filter); | 2291 | __setup("ftrace_filter=", set_ftrace_filter); |
2314 | 2292 | ||
2293 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
2294 | static int __init set_graph_function(char *str) | ||
2295 | { | ||
2296 | strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); | ||
2297 | return 1; | ||
2298 | } | ||
2299 | __setup("ftrace_graph_filter=", set_graph_function); | ||
2300 | |||
2301 | static void __init set_ftrace_early_graph(char *buf) | ||
2302 | { | ||
2303 | int ret; | ||
2304 | char *func; | ||
2305 | |||
2306 | while (buf) { | ||
2307 | func = strsep(&buf, ","); | ||
2308 | /* we allow only one expression at a time */ | ||
2309 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | ||
2310 | func); | ||
2311 | if (ret) | ||
2312 | printk(KERN_DEBUG "ftrace: function %s not " | ||
2313 | "traceable\n", func); | ||
2314 | } | ||
2315 | } | ||
2316 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
2317 | |||
2315 | static void __init set_ftrace_early_filter(char *buf, int enable) | 2318 | static void __init set_ftrace_early_filter(char *buf, int enable) |
2316 | { | 2319 | { |
2317 | char *func; | 2320 | char *func; |
@@ -2328,6 +2331,10 @@ static void __init set_ftrace_early_filters(void) | |||
2328 | set_ftrace_early_filter(ftrace_filter_buf, 1); | 2331 | set_ftrace_early_filter(ftrace_filter_buf, 1); |
2329 | if (ftrace_notrace_buf[0]) | 2332 | if (ftrace_notrace_buf[0]) |
2330 | set_ftrace_early_filter(ftrace_notrace_buf, 0); | 2333 | set_ftrace_early_filter(ftrace_notrace_buf, 0); |
2334 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
2335 | if (ftrace_graph_buf[0]) | ||
2336 | set_ftrace_early_graph(ftrace_graph_buf); | ||
2337 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
2331 | } | 2338 | } |
2332 | 2339 | ||
2333 | static int | 2340 | static int |
@@ -2513,7 +2520,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2513 | return -ENODEV; | 2520 | return -ENODEV; |
2514 | 2521 | ||
2515 | /* decode regex */ | 2522 | /* decode regex */ |
2516 | type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); | 2523 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
2517 | if (not) | 2524 | if (not) |
2518 | return -EINVAL; | 2525 | return -EINVAL; |
2519 | 2526 | ||
@@ -2624,7 +2631,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | |||
2624 | return 0; | 2631 | return 0; |
2625 | } | 2632 | } |
2626 | 2633 | ||
2627 | static int ftrace_convert_nops(struct module *mod, | 2634 | static int ftrace_process_locs(struct module *mod, |
2628 | unsigned long *start, | 2635 | unsigned long *start, |
2629 | unsigned long *end) | 2636 | unsigned long *end) |
2630 | { | 2637 | { |
@@ -2684,7 +2691,7 @@ static void ftrace_init_module(struct module *mod, | |||
2684 | { | 2691 | { |
2685 | if (ftrace_disabled || start == end) | 2692 | if (ftrace_disabled || start == end) |
2686 | return; | 2693 | return; |
2687 | ftrace_convert_nops(mod, start, end); | 2694 | ftrace_process_locs(mod, start, end); |
2688 | } | 2695 | } |
2689 | 2696 | ||
2690 | static int ftrace_module_notify(struct notifier_block *self, | 2697 | static int ftrace_module_notify(struct notifier_block *self, |
@@ -2745,7 +2752,7 @@ void __init ftrace_init(void) | |||
2745 | 2752 | ||
2746 | last_ftrace_enabled = ftrace_enabled = 1; | 2753 | last_ftrace_enabled = ftrace_enabled = 1; |
2747 | 2754 | ||
2748 | ret = ftrace_convert_nops(NULL, | 2755 | ret = ftrace_process_locs(NULL, |
2749 | __start_mcount_loc, | 2756 | __start_mcount_loc, |
2750 | __stop_mcount_loc); | 2757 | __stop_mcount_loc); |
2751 | 2758 | ||
@@ -2778,23 +2785,6 @@ static inline void ftrace_startup_enable(int command) { } | |||
2778 | # define ftrace_shutdown_sysctl() do { } while (0) | 2785 | # define ftrace_shutdown_sysctl() do { } while (0) |
2779 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 2786 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
2780 | 2787 | ||
2781 | static ssize_t | ||
2782 | ftrace_pid_read(struct file *file, char __user *ubuf, | ||
2783 | size_t cnt, loff_t *ppos) | ||
2784 | { | ||
2785 | char buf[64]; | ||
2786 | int r; | ||
2787 | |||
2788 | if (ftrace_pid_trace == ftrace_swapper_pid) | ||
2789 | r = sprintf(buf, "swapper tasks\n"); | ||
2790 | else if (ftrace_pid_trace) | ||
2791 | r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace)); | ||
2792 | else | ||
2793 | r = sprintf(buf, "no pid\n"); | ||
2794 | |||
2795 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
2796 | } | ||
2797 | |||
2798 | static void clear_ftrace_swapper(void) | 2788 | static void clear_ftrace_swapper(void) |
2799 | { | 2789 | { |
2800 | struct task_struct *p; | 2790 | struct task_struct *p; |
@@ -2845,14 +2835,12 @@ static void set_ftrace_pid(struct pid *pid) | |||
2845 | rcu_read_unlock(); | 2835 | rcu_read_unlock(); |
2846 | } | 2836 | } |
2847 | 2837 | ||
2848 | static void clear_ftrace_pid_task(struct pid **pid) | 2838 | static void clear_ftrace_pid_task(struct pid *pid) |
2849 | { | 2839 | { |
2850 | if (*pid == ftrace_swapper_pid) | 2840 | if (pid == ftrace_swapper_pid) |
2851 | clear_ftrace_swapper(); | 2841 | clear_ftrace_swapper(); |
2852 | else | 2842 | else |
2853 | clear_ftrace_pid(*pid); | 2843 | clear_ftrace_pid(pid); |
2854 | |||
2855 | *pid = NULL; | ||
2856 | } | 2844 | } |
2857 | 2845 | ||
2858 | static void set_ftrace_pid_task(struct pid *pid) | 2846 | static void set_ftrace_pid_task(struct pid *pid) |
@@ -2863,11 +2851,140 @@ static void set_ftrace_pid_task(struct pid *pid) | |||
2863 | set_ftrace_pid(pid); | 2851 | set_ftrace_pid(pid); |
2864 | } | 2852 | } |
2865 | 2853 | ||
2854 | static int ftrace_pid_add(int p) | ||
2855 | { | ||
2856 | struct pid *pid; | ||
2857 | struct ftrace_pid *fpid; | ||
2858 | int ret = -EINVAL; | ||
2859 | |||
2860 | mutex_lock(&ftrace_lock); | ||
2861 | |||
2862 | if (!p) | ||
2863 | pid = ftrace_swapper_pid; | ||
2864 | else | ||
2865 | pid = find_get_pid(p); | ||
2866 | |||
2867 | if (!pid) | ||
2868 | goto out; | ||
2869 | |||
2870 | ret = 0; | ||
2871 | |||
2872 | list_for_each_entry(fpid, &ftrace_pids, list) | ||
2873 | if (fpid->pid == pid) | ||
2874 | goto out_put; | ||
2875 | |||
2876 | ret = -ENOMEM; | ||
2877 | |||
2878 | fpid = kmalloc(sizeof(*fpid), GFP_KERNEL); | ||
2879 | if (!fpid) | ||
2880 | goto out_put; | ||
2881 | |||
2882 | list_add(&fpid->list, &ftrace_pids); | ||
2883 | fpid->pid = pid; | ||
2884 | |||
2885 | set_ftrace_pid_task(pid); | ||
2886 | |||
2887 | ftrace_update_pid_func(); | ||
2888 | ftrace_startup_enable(0); | ||
2889 | |||
2890 | mutex_unlock(&ftrace_lock); | ||
2891 | return 0; | ||
2892 | |||
2893 | out_put: | ||
2894 | if (pid != ftrace_swapper_pid) | ||
2895 | put_pid(pid); | ||
2896 | |||
2897 | out: | ||
2898 | mutex_unlock(&ftrace_lock); | ||
2899 | return ret; | ||
2900 | } | ||
2901 | |||
2902 | static void ftrace_pid_reset(void) | ||
2903 | { | ||
2904 | struct ftrace_pid *fpid, *safe; | ||
2905 | |||
2906 | mutex_lock(&ftrace_lock); | ||
2907 | list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) { | ||
2908 | struct pid *pid = fpid->pid; | ||
2909 | |||
2910 | clear_ftrace_pid_task(pid); | ||
2911 | |||
2912 | list_del(&fpid->list); | ||
2913 | kfree(fpid); | ||
2914 | } | ||
2915 | |||
2916 | ftrace_update_pid_func(); | ||
2917 | ftrace_startup_enable(0); | ||
2918 | |||
2919 | mutex_unlock(&ftrace_lock); | ||
2920 | } | ||
2921 | |||
2922 | static void *fpid_start(struct seq_file *m, loff_t *pos) | ||
2923 | { | ||
2924 | mutex_lock(&ftrace_lock); | ||
2925 | |||
2926 | if (list_empty(&ftrace_pids) && (!*pos)) | ||
2927 | return (void *) 1; | ||
2928 | |||
2929 | return seq_list_start(&ftrace_pids, *pos); | ||
2930 | } | ||
2931 | |||
2932 | static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) | ||
2933 | { | ||
2934 | if (v == (void *)1) | ||
2935 | return NULL; | ||
2936 | |||
2937 | return seq_list_next(v, &ftrace_pids, pos); | ||
2938 | } | ||
2939 | |||
2940 | static void fpid_stop(struct seq_file *m, void *p) | ||
2941 | { | ||
2942 | mutex_unlock(&ftrace_lock); | ||
2943 | } | ||
2944 | |||
2945 | static int fpid_show(struct seq_file *m, void *v) | ||
2946 | { | ||
2947 | const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list); | ||
2948 | |||
2949 | if (v == (void *)1) { | ||
2950 | seq_printf(m, "no pid\n"); | ||
2951 | return 0; | ||
2952 | } | ||
2953 | |||
2954 | if (fpid->pid == ftrace_swapper_pid) | ||
2955 | seq_printf(m, "swapper tasks\n"); | ||
2956 | else | ||
2957 | seq_printf(m, "%u\n", pid_vnr(fpid->pid)); | ||
2958 | |||
2959 | return 0; | ||
2960 | } | ||
2961 | |||
2962 | static const struct seq_operations ftrace_pid_sops = { | ||
2963 | .start = fpid_start, | ||
2964 | .next = fpid_next, | ||
2965 | .stop = fpid_stop, | ||
2966 | .show = fpid_show, | ||
2967 | }; | ||
2968 | |||
2969 | static int | ||
2970 | ftrace_pid_open(struct inode *inode, struct file *file) | ||
2971 | { | ||
2972 | int ret = 0; | ||
2973 | |||
2974 | if ((file->f_mode & FMODE_WRITE) && | ||
2975 | (file->f_flags & O_TRUNC)) | ||
2976 | ftrace_pid_reset(); | ||
2977 | |||
2978 | if (file->f_mode & FMODE_READ) | ||
2979 | ret = seq_open(file, &ftrace_pid_sops); | ||
2980 | |||
2981 | return ret; | ||
2982 | } | ||
2983 | |||
2866 | static ssize_t | 2984 | static ssize_t |
2867 | ftrace_pid_write(struct file *filp, const char __user *ubuf, | 2985 | ftrace_pid_write(struct file *filp, const char __user *ubuf, |
2868 | size_t cnt, loff_t *ppos) | 2986 | size_t cnt, loff_t *ppos) |
2869 | { | 2987 | { |
2870 | struct pid *pid; | ||
2871 | char buf[64]; | 2988 | char buf[64]; |
2872 | long val; | 2989 | long val; |
2873 | int ret; | 2990 | int ret; |
@@ -2880,57 +2997,38 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf, | |||
2880 | 2997 | ||
2881 | buf[cnt] = 0; | 2998 | buf[cnt] = 0; |
2882 | 2999 | ||
3000 | /* | ||
3001 | * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" | ||
3002 | * to clean the filter quietly. | ||
3003 | */ | ||
3004 | strstrip(buf); | ||
3005 | if (strlen(buf) == 0) | ||
3006 | return 1; | ||
3007 | |||
2883 | ret = strict_strtol(buf, 10, &val); | 3008 | ret = strict_strtol(buf, 10, &val); |
2884 | if (ret < 0) | 3009 | if (ret < 0) |
2885 | return ret; | 3010 | return ret; |
2886 | 3011 | ||
2887 | mutex_lock(&ftrace_lock); | 3012 | ret = ftrace_pid_add(val); |
2888 | if (val < 0) { | ||
2889 | /* disable pid tracing */ | ||
2890 | if (!ftrace_pid_trace) | ||
2891 | goto out; | ||
2892 | |||
2893 | clear_ftrace_pid_task(&ftrace_pid_trace); | ||
2894 | |||
2895 | } else { | ||
2896 | /* swapper task is special */ | ||
2897 | if (!val) { | ||
2898 | pid = ftrace_swapper_pid; | ||
2899 | if (pid == ftrace_pid_trace) | ||
2900 | goto out; | ||
2901 | } else { | ||
2902 | pid = find_get_pid(val); | ||
2903 | 3013 | ||
2904 | if (pid == ftrace_pid_trace) { | 3014 | return ret ? ret : cnt; |
2905 | put_pid(pid); | 3015 | } |
2906 | goto out; | ||
2907 | } | ||
2908 | } | ||
2909 | |||
2910 | if (ftrace_pid_trace) | ||
2911 | clear_ftrace_pid_task(&ftrace_pid_trace); | ||
2912 | |||
2913 | if (!pid) | ||
2914 | goto out; | ||
2915 | |||
2916 | ftrace_pid_trace = pid; | ||
2917 | |||
2918 | set_ftrace_pid_task(ftrace_pid_trace); | ||
2919 | } | ||
2920 | |||
2921 | /* update the function call */ | ||
2922 | ftrace_update_pid_func(); | ||
2923 | ftrace_startup_enable(0); | ||
2924 | 3016 | ||
2925 | out: | 3017 | static int |
2926 | mutex_unlock(&ftrace_lock); | 3018 | ftrace_pid_release(struct inode *inode, struct file *file) |
3019 | { | ||
3020 | if (file->f_mode & FMODE_READ) | ||
3021 | seq_release(inode, file); | ||
2927 | 3022 | ||
2928 | return cnt; | 3023 | return 0; |
2929 | } | 3024 | } |
2930 | 3025 | ||
2931 | static const struct file_operations ftrace_pid_fops = { | 3026 | static const struct file_operations ftrace_pid_fops = { |
2932 | .read = ftrace_pid_read, | 3027 | .open = ftrace_pid_open, |
2933 | .write = ftrace_pid_write, | 3028 | .write = ftrace_pid_write, |
3029 | .read = seq_read, | ||
3030 | .llseek = seq_lseek, | ||
3031 | .release = ftrace_pid_release, | ||
2934 | }; | 3032 | }; |
2935 | 3033 | ||
2936 | static __init int ftrace_init_debugfs(void) | 3034 | static __init int ftrace_init_debugfs(void) |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index d4ff01970547..e43c928356ee 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -397,18 +397,21 @@ int ring_buffer_print_page_header(struct trace_seq *s) | |||
397 | int ret; | 397 | int ret; |
398 | 398 | ||
399 | ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t" | 399 | ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t" |
400 | "offset:0;\tsize:%u;\n", | 400 | "offset:0;\tsize:%u;\tsigned:%u;\n", |
401 | (unsigned int)sizeof(field.time_stamp)); | 401 | (unsigned int)sizeof(field.time_stamp), |
402 | (unsigned int)is_signed_type(u64)); | ||
402 | 403 | ||
403 | ret = trace_seq_printf(s, "\tfield: local_t commit;\t" | 404 | ret = trace_seq_printf(s, "\tfield: local_t commit;\t" |
404 | "offset:%u;\tsize:%u;\n", | 405 | "offset:%u;\tsize:%u;\tsigned:%u;\n", |
405 | (unsigned int)offsetof(typeof(field), commit), | 406 | (unsigned int)offsetof(typeof(field), commit), |
406 | (unsigned int)sizeof(field.commit)); | 407 | (unsigned int)sizeof(field.commit), |
408 | (unsigned int)is_signed_type(long)); | ||
407 | 409 | ||
408 | ret = trace_seq_printf(s, "\tfield: char data;\t" | 410 | ret = trace_seq_printf(s, "\tfield: char data;\t" |
409 | "offset:%u;\tsize:%u;\n", | 411 | "offset:%u;\tsize:%u;\tsigned:%u;\n", |
410 | (unsigned int)offsetof(typeof(field), data), | 412 | (unsigned int)offsetof(typeof(field), data), |
411 | (unsigned int)BUF_PAGE_SIZE); | 413 | (unsigned int)BUF_PAGE_SIZE, |
414 | (unsigned int)is_signed_type(char)); | ||
412 | 415 | ||
413 | return ret; | 416 | return ret; |
414 | } | 417 | } |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c820b0310a12..026e715a0c7a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -129,7 +129,7 @@ static int tracing_set_tracer(const char *buf); | |||
129 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; | 129 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; |
130 | static char *default_bootup_tracer; | 130 | static char *default_bootup_tracer; |
131 | 131 | ||
132 | static int __init set_ftrace(char *str) | 132 | static int __init set_cmdline_ftrace(char *str) |
133 | { | 133 | { |
134 | strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); | 134 | strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); |
135 | default_bootup_tracer = bootup_tracer_buf; | 135 | default_bootup_tracer = bootup_tracer_buf; |
@@ -137,7 +137,7 @@ static int __init set_ftrace(char *str) | |||
137 | ring_buffer_expanded = 1; | 137 | ring_buffer_expanded = 1; |
138 | return 1; | 138 | return 1; |
139 | } | 139 | } |
140 | __setup("ftrace=", set_ftrace); | 140 | __setup("ftrace=", set_cmdline_ftrace); |
141 | 141 | ||
142 | static int __init set_ftrace_dump_on_oops(char *str) | 142 | static int __init set_ftrace_dump_on_oops(char *str) |
143 | { | 143 | { |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 104c1a72418f..b4e4212e66d7 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -506,10 +506,6 @@ static inline int ftrace_graph_addr(unsigned long addr) | |||
506 | return 0; | 506 | return 0; |
507 | } | 507 | } |
508 | #else | 508 | #else |
509 | static inline int ftrace_trace_addr(unsigned long addr) | ||
510 | { | ||
511 | return 1; | ||
512 | } | ||
513 | static inline int ftrace_graph_addr(unsigned long addr) | 509 | static inline int ftrace_graph_addr(unsigned long addr) |
514 | { | 510 | { |
515 | return 1; | 511 | return 1; |
@@ -523,12 +519,12 @@ print_graph_function(struct trace_iterator *iter) | |||
523 | } | 519 | } |
524 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 520 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
525 | 521 | ||
526 | extern struct pid *ftrace_pid_trace; | 522 | extern struct list_head ftrace_pids; |
527 | 523 | ||
528 | #ifdef CONFIG_FUNCTION_TRACER | 524 | #ifdef CONFIG_FUNCTION_TRACER |
529 | static inline int ftrace_trace_task(struct task_struct *task) | 525 | static inline int ftrace_trace_task(struct task_struct *task) |
530 | { | 526 | { |
531 | if (!ftrace_pid_trace) | 527 | if (list_empty(&ftrace_pids)) |
532 | return 1; | 528 | return 1; |
533 | 529 | ||
534 | return test_tsk_trace_trace(task); | 530 | return test_tsk_trace_trace(task); |
@@ -710,7 +706,6 @@ struct event_filter { | |||
710 | int n_preds; | 706 | int n_preds; |
711 | struct filter_pred **preds; | 707 | struct filter_pred **preds; |
712 | char *filter_string; | 708 | char *filter_string; |
713 | bool no_reset; | ||
714 | }; | 709 | }; |
715 | 710 | ||
716 | struct event_subsystem { | 711 | struct event_subsystem { |
@@ -722,22 +717,40 @@ struct event_subsystem { | |||
722 | }; | 717 | }; |
723 | 718 | ||
724 | struct filter_pred; | 719 | struct filter_pred; |
720 | struct regex; | ||
725 | 721 | ||
726 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, | 722 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, |
727 | int val1, int val2); | 723 | int val1, int val2); |
728 | 724 | ||
725 | typedef int (*regex_match_func)(char *str, struct regex *r, int len); | ||
726 | |||
727 | enum regex_type { | ||
728 | MATCH_FULL = 0, | ||
729 | MATCH_FRONT_ONLY, | ||
730 | MATCH_MIDDLE_ONLY, | ||
731 | MATCH_END_ONLY, | ||
732 | }; | ||
733 | |||
734 | struct regex { | ||
735 | char pattern[MAX_FILTER_STR_VAL]; | ||
736 | int len; | ||
737 | int field_len; | ||
738 | regex_match_func match; | ||
739 | }; | ||
740 | |||
729 | struct filter_pred { | 741 | struct filter_pred { |
730 | filter_pred_fn_t fn; | 742 | filter_pred_fn_t fn; |
731 | u64 val; | 743 | u64 val; |
732 | char str_val[MAX_FILTER_STR_VAL]; | 744 | struct regex regex; |
733 | int str_len; | 745 | char *field_name; |
734 | char *field_name; | 746 | int offset; |
735 | int offset; | 747 | int not; |
736 | int not; | 748 | int op; |
737 | int op; | 749 | int pop_n; |
738 | int pop_n; | ||
739 | }; | 750 | }; |
740 | 751 | ||
752 | extern enum regex_type | ||
753 | filter_parse_regex(char *buff, int len, char **search, int *not); | ||
741 | extern void print_event_filter(struct ftrace_event_call *call, | 754 | extern void print_event_filter(struct ftrace_event_call *call, |
742 | struct trace_seq *s); | 755 | struct trace_seq *s); |
743 | extern int apply_event_filter(struct ftrace_event_call *call, | 756 | extern int apply_event_filter(struct ftrace_event_call *call, |
@@ -753,7 +766,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
753 | struct ring_buffer *buffer, | 766 | struct ring_buffer *buffer, |
754 | struct ring_buffer_event *event) | 767 | struct ring_buffer_event *event) |
755 | { | 768 | { |
756 | if (unlikely(call->filter_active) && !filter_match_preds(call, rec)) { | 769 | if (unlikely(call->filter_active) && |
770 | !filter_match_preds(call->filter, rec)) { | ||
757 | ring_buffer_discard_commit(buffer, event); | 771 | ring_buffer_discard_commit(buffer, event); |
758 | return 1; | 772 | return 1; |
759 | } | 773 | } |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index f2f5064701e5..1d18315dc836 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -503,7 +503,7 @@ extern char *__bad_type_size(void); | |||
503 | #define FIELD(type, name) \ | 503 | #define FIELD(type, name) \ |
504 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ | 504 | sizeof(type) != sizeof(field.name) ? __bad_type_size() : \ |
505 | #type, "common_" #name, offsetof(typeof(field), name), \ | 505 | #type, "common_" #name, offsetof(typeof(field), name), \ |
506 | sizeof(field.name) | 506 | sizeof(field.name), is_signed_type(type) |
507 | 507 | ||
508 | static int trace_write_header(struct trace_seq *s) | 508 | static int trace_write_header(struct trace_seq *s) |
509 | { | 509 | { |
@@ -511,17 +511,17 @@ static int trace_write_header(struct trace_seq *s) | |||
511 | 511 | ||
512 | /* struct trace_entry */ | 512 | /* struct trace_entry */ |
513 | return trace_seq_printf(s, | 513 | return trace_seq_printf(s, |
514 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 514 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
515 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 515 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
516 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 516 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
517 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 517 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
518 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 518 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\tsigned:%u;\n" |
519 | "\n", | 519 | "\n", |
520 | FIELD(unsigned short, type), | 520 | FIELD(unsigned short, type), |
521 | FIELD(unsigned char, flags), | 521 | FIELD(unsigned char, flags), |
522 | FIELD(unsigned char, preempt_count), | 522 | FIELD(unsigned char, preempt_count), |
523 | FIELD(int, pid), | 523 | FIELD(int, pid), |
524 | FIELD(int, lock_depth)); | 524 | FIELD(int, lock_depth)); |
525 | } | 525 | } |
526 | 526 | ||
527 | static ssize_t | 527 | static ssize_t |
@@ -874,9 +874,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
874 | "'%s/filter' entry\n", name); | 874 | "'%s/filter' entry\n", name); |
875 | } | 875 | } |
876 | 876 | ||
877 | entry = trace_create_file("enable", 0644, system->entry, | 877 | trace_create_file("enable", 0644, system->entry, |
878 | (void *)system->name, | 878 | (void *)system->name, |
879 | &ftrace_system_enable_fops); | 879 | &ftrace_system_enable_fops); |
880 | 880 | ||
881 | return system->entry; | 881 | return system->entry; |
882 | } | 882 | } |
@@ -888,7 +888,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
888 | const struct file_operations *filter, | 888 | const struct file_operations *filter, |
889 | const struct file_operations *format) | 889 | const struct file_operations *format) |
890 | { | 890 | { |
891 | struct dentry *entry; | ||
892 | int ret; | 891 | int ret; |
893 | 892 | ||
894 | /* | 893 | /* |
@@ -906,12 +905,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
906 | } | 905 | } |
907 | 906 | ||
908 | if (call->regfunc) | 907 | if (call->regfunc) |
909 | entry = trace_create_file("enable", 0644, call->dir, call, | 908 | trace_create_file("enable", 0644, call->dir, call, |
910 | enable); | 909 | enable); |
911 | 910 | ||
912 | if (call->id && call->profile_enable) | 911 | if (call->id && call->profile_enable) |
913 | entry = trace_create_file("id", 0444, call->dir, call, | 912 | trace_create_file("id", 0444, call->dir, call, |
914 | id); | 913 | id); |
915 | 914 | ||
916 | if (call->define_fields) { | 915 | if (call->define_fields) { |
917 | ret = call->define_fields(call); | 916 | ret = call->define_fields(call); |
@@ -920,16 +919,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
920 | " events/%s\n", call->name); | 919 | " events/%s\n", call->name); |
921 | return ret; | 920 | return ret; |
922 | } | 921 | } |
923 | entry = trace_create_file("filter", 0644, call->dir, call, | 922 | trace_create_file("filter", 0644, call->dir, call, |
924 | filter); | 923 | filter); |
925 | } | 924 | } |
926 | 925 | ||
927 | /* A trace may not want to export its format */ | 926 | /* A trace may not want to export its format */ |
928 | if (!call->show_format) | 927 | if (!call->show_format) |
929 | return 0; | 928 | return 0; |
930 | 929 | ||
931 | entry = trace_create_file("format", 0444, call->dir, call, | 930 | trace_create_file("format", 0444, call->dir, call, |
932 | format); | 931 | format); |
933 | 932 | ||
934 | return 0; | 933 | return 0; |
935 | } | 934 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 98a6cc5c64ed..21d34757b955 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -18,11 +18,10 @@ | |||
18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> | 18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/uaccess.h> | ||
23 | #include <linux/module.h> | 21 | #include <linux/module.h> |
24 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
25 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/perf_event.h> | ||
26 | 25 | ||
27 | #include "trace.h" | 26 | #include "trace.h" |
28 | #include "trace_output.h" | 27 | #include "trace_output.h" |
@@ -31,6 +30,7 @@ enum filter_op_ids | |||
31 | { | 30 | { |
32 | OP_OR, | 31 | OP_OR, |
33 | OP_AND, | 32 | OP_AND, |
33 | OP_GLOB, | ||
34 | OP_NE, | 34 | OP_NE, |
35 | OP_EQ, | 35 | OP_EQ, |
36 | OP_LT, | 36 | OP_LT, |
@@ -48,16 +48,17 @@ struct filter_op { | |||
48 | }; | 48 | }; |
49 | 49 | ||
50 | static struct filter_op filter_ops[] = { | 50 | static struct filter_op filter_ops[] = { |
51 | { OP_OR, "||", 1 }, | 51 | { OP_OR, "||", 1 }, |
52 | { OP_AND, "&&", 2 }, | 52 | { OP_AND, "&&", 2 }, |
53 | { OP_NE, "!=", 4 }, | 53 | { OP_GLOB, "~", 4 }, |
54 | { OP_EQ, "==", 4 }, | 54 | { OP_NE, "!=", 4 }, |
55 | { OP_LT, "<", 5 }, | 55 | { OP_EQ, "==", 4 }, |
56 | { OP_LE, "<=", 5 }, | 56 | { OP_LT, "<", 5 }, |
57 | { OP_GT, ">", 5 }, | 57 | { OP_LE, "<=", 5 }, |
58 | { OP_GE, ">=", 5 }, | 58 | { OP_GT, ">", 5 }, |
59 | { OP_NONE, "OP_NONE", 0 }, | 59 | { OP_GE, ">=", 5 }, |
60 | { OP_OPEN_PAREN, "(", 0 }, | 60 | { OP_NONE, "OP_NONE", 0 }, |
61 | { OP_OPEN_PAREN, "(", 0 }, | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | enum { | 64 | enum { |
@@ -197,9 +198,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event, | |||
197 | char *addr = (char *)(event + pred->offset); | 198 | char *addr = (char *)(event + pred->offset); |
198 | int cmp, match; | 199 | int cmp, match; |
199 | 200 | ||
200 | cmp = strncmp(addr, pred->str_val, pred->str_len); | 201 | cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len); |
201 | 202 | ||
202 | match = (!cmp) ^ pred->not; | 203 | match = cmp ^ pred->not; |
203 | 204 | ||
204 | return match; | 205 | return match; |
205 | } | 206 | } |
@@ -211,9 +212,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event, | |||
211 | char **addr = (char **)(event + pred->offset); | 212 | char **addr = (char **)(event + pred->offset); |
212 | int cmp, match; | 213 | int cmp, match; |
213 | 214 | ||
214 | cmp = strncmp(*addr, pred->str_val, pred->str_len); | 215 | cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len); |
215 | 216 | ||
216 | match = (!cmp) ^ pred->not; | 217 | match = cmp ^ pred->not; |
217 | 218 | ||
218 | return match; | 219 | return match; |
219 | } | 220 | } |
@@ -237,9 +238,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event, | |||
237 | char *addr = (char *)(event + str_loc); | 238 | char *addr = (char *)(event + str_loc); |
238 | int cmp, match; | 239 | int cmp, match; |
239 | 240 | ||
240 | cmp = strncmp(addr, pred->str_val, str_len); | 241 | cmp = pred->regex.match(addr, &pred->regex, str_len); |
241 | 242 | ||
242 | match = (!cmp) ^ pred->not; | 243 | match = cmp ^ pred->not; |
243 | 244 | ||
244 | return match; | 245 | return match; |
245 | } | 246 | } |
@@ -250,10 +251,121 @@ static int filter_pred_none(struct filter_pred *pred, void *event, | |||
250 | return 0; | 251 | return 0; |
251 | } | 252 | } |
252 | 253 | ||
254 | /* Basic regex callbacks */ | ||
255 | static int regex_match_full(char *str, struct regex *r, int len) | ||
256 | { | ||
257 | if (strncmp(str, r->pattern, len) == 0) | ||
258 | return 1; | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int regex_match_front(char *str, struct regex *r, int len) | ||
263 | { | ||
264 | if (strncmp(str, r->pattern, len) == 0) | ||
265 | return 1; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int regex_match_middle(char *str, struct regex *r, int len) | ||
270 | { | ||
271 | if (strstr(str, r->pattern)) | ||
272 | return 1; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int regex_match_end(char *str, struct regex *r, int len) | ||
277 | { | ||
278 | char *ptr = strstr(str, r->pattern); | ||
279 | |||
280 | if (ptr && (ptr[r->len] == 0)) | ||
281 | return 1; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * filter_parse_regex - parse a basic regex | ||
287 | * @buff: the raw regex | ||
288 | * @len: length of the regex | ||
289 | * @search: will point to the beginning of the string to compare | ||
290 | * @not: tell whether the match will have to be inverted | ||
291 | * | ||
292 | * This passes in a buffer containing a regex and this function will | ||
293 | * set search to point to the search part of the buffer and | ||
294 | * return the type of search it is (see enum above). | ||
295 | * This does modify buff. | ||
296 | * | ||
297 | * Returns enum type. | ||
298 | * search returns the pointer to use for comparison. | ||
299 | * not returns 1 if buff started with a '!' | ||
300 | * 0 otherwise. | ||
301 | */ | ||
302 | enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not) | ||
303 | { | ||
304 | int type = MATCH_FULL; | ||
305 | int i; | ||
306 | |||
307 | if (buff[0] == '!') { | ||
308 | *not = 1; | ||
309 | buff++; | ||
310 | len--; | ||
311 | } else | ||
312 | *not = 0; | ||
313 | |||
314 | *search = buff; | ||
315 | |||
316 | for (i = 0; i < len; i++) { | ||
317 | if (buff[i] == '*') { | ||
318 | if (!i) { | ||
319 | *search = buff + 1; | ||
320 | type = MATCH_END_ONLY; | ||
321 | } else { | ||
322 | if (type == MATCH_END_ONLY) | ||
323 | type = MATCH_MIDDLE_ONLY; | ||
324 | else | ||
325 | type = MATCH_FRONT_ONLY; | ||
326 | buff[i] = 0; | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | |||
332 | return type; | ||
333 | } | ||
334 | |||
335 | static void filter_build_regex(struct filter_pred *pred) | ||
336 | { | ||
337 | struct regex *r = &pred->regex; | ||
338 | char *search; | ||
339 | enum regex_type type = MATCH_FULL; | ||
340 | int not = 0; | ||
341 | |||
342 | if (pred->op == OP_GLOB) { | ||
343 | type = filter_parse_regex(r->pattern, r->len, &search, ¬); | ||
344 | r->len = strlen(search); | ||
345 | memmove(r->pattern, search, r->len+1); | ||
346 | } | ||
347 | |||
348 | switch (type) { | ||
349 | case MATCH_FULL: | ||
350 | r->match = regex_match_full; | ||
351 | break; | ||
352 | case MATCH_FRONT_ONLY: | ||
353 | r->match = regex_match_front; | ||
354 | break; | ||
355 | case MATCH_MIDDLE_ONLY: | ||
356 | r->match = regex_match_middle; | ||
357 | break; | ||
358 | case MATCH_END_ONLY: | ||
359 | r->match = regex_match_end; | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | pred->not ^= not; | ||
364 | } | ||
365 | |||
253 | /* return 1 if event matches, 0 otherwise (discard) */ | 366 | /* return 1 if event matches, 0 otherwise (discard) */ |
254 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 367 | int filter_match_preds(struct event_filter *filter, void *rec) |
255 | { | 368 | { |
256 | struct event_filter *filter = call->filter; | ||
257 | int match, top = 0, val1 = 0, val2 = 0; | 369 | int match, top = 0, val1 = 0, val2 = 0; |
258 | int stack[MAX_FILTER_PRED]; | 370 | int stack[MAX_FILTER_PRED]; |
259 | struct filter_pred *pred; | 371 | struct filter_pred *pred; |
@@ -396,7 +508,7 @@ static void filter_clear_pred(struct filter_pred *pred) | |||
396 | { | 508 | { |
397 | kfree(pred->field_name); | 509 | kfree(pred->field_name); |
398 | pred->field_name = NULL; | 510 | pred->field_name = NULL; |
399 | pred->str_len = 0; | 511 | pred->regex.len = 0; |
400 | } | 512 | } |
401 | 513 | ||
402 | static int filter_set_pred(struct filter_pred *dest, | 514 | static int filter_set_pred(struct filter_pred *dest, |
@@ -426,9 +538,8 @@ static void filter_disable_preds(struct ftrace_event_call *call) | |||
426 | filter->preds[i]->fn = filter_pred_none; | 538 | filter->preds[i]->fn = filter_pred_none; |
427 | } | 539 | } |
428 | 540 | ||
429 | void destroy_preds(struct ftrace_event_call *call) | 541 | static void __free_preds(struct event_filter *filter) |
430 | { | 542 | { |
431 | struct event_filter *filter = call->filter; | ||
432 | int i; | 543 | int i; |
433 | 544 | ||
434 | if (!filter) | 545 | if (!filter) |
@@ -441,21 +552,24 @@ void destroy_preds(struct ftrace_event_call *call) | |||
441 | kfree(filter->preds); | 552 | kfree(filter->preds); |
442 | kfree(filter->filter_string); | 553 | kfree(filter->filter_string); |
443 | kfree(filter); | 554 | kfree(filter); |
555 | } | ||
556 | |||
557 | void destroy_preds(struct ftrace_event_call *call) | ||
558 | { | ||
559 | __free_preds(call->filter); | ||
444 | call->filter = NULL; | 560 | call->filter = NULL; |
561 | call->filter_active = 0; | ||
445 | } | 562 | } |
446 | 563 | ||
447 | static int init_preds(struct ftrace_event_call *call) | 564 | static struct event_filter *__alloc_preds(void) |
448 | { | 565 | { |
449 | struct event_filter *filter; | 566 | struct event_filter *filter; |
450 | struct filter_pred *pred; | 567 | struct filter_pred *pred; |
451 | int i; | 568 | int i; |
452 | 569 | ||
453 | if (call->filter) | 570 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
454 | return 0; | 571 | if (!filter) |
455 | 572 | return ERR_PTR(-ENOMEM); | |
456 | filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL); | ||
457 | if (!call->filter) | ||
458 | return -ENOMEM; | ||
459 | 573 | ||
460 | filter->n_preds = 0; | 574 | filter->n_preds = 0; |
461 | 575 | ||
@@ -471,12 +585,24 @@ static int init_preds(struct ftrace_event_call *call) | |||
471 | filter->preds[i] = pred; | 585 | filter->preds[i] = pred; |
472 | } | 586 | } |
473 | 587 | ||
474 | return 0; | 588 | return filter; |
475 | 589 | ||
476 | oom: | 590 | oom: |
477 | destroy_preds(call); | 591 | __free_preds(filter); |
592 | return ERR_PTR(-ENOMEM); | ||
593 | } | ||
594 | |||
595 | static int init_preds(struct ftrace_event_call *call) | ||
596 | { | ||
597 | if (call->filter) | ||
598 | return 0; | ||
478 | 599 | ||
479 | return -ENOMEM; | 600 | call->filter_active = 0; |
601 | call->filter = __alloc_preds(); | ||
602 | if (IS_ERR(call->filter)) | ||
603 | return PTR_ERR(call->filter); | ||
604 | |||
605 | return 0; | ||
480 | } | 606 | } |
481 | 607 | ||
482 | static int init_subsystem_preds(struct event_subsystem *system) | 608 | static int init_subsystem_preds(struct event_subsystem *system) |
@@ -499,14 +625,7 @@ static int init_subsystem_preds(struct event_subsystem *system) | |||
499 | return 0; | 625 | return 0; |
500 | } | 626 | } |
501 | 627 | ||
502 | enum { | 628 | static void filter_free_subsystem_preds(struct event_subsystem *system) |
503 | FILTER_DISABLE_ALL, | ||
504 | FILTER_INIT_NO_RESET, | ||
505 | FILTER_SKIP_NO_RESET, | ||
506 | }; | ||
507 | |||
508 | static void filter_free_subsystem_preds(struct event_subsystem *system, | ||
509 | int flag) | ||
510 | { | 629 | { |
511 | struct ftrace_event_call *call; | 630 | struct ftrace_event_call *call; |
512 | 631 | ||
@@ -517,14 +636,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system, | |||
517 | if (strcmp(call->system, system->name) != 0) | 636 | if (strcmp(call->system, system->name) != 0) |
518 | continue; | 637 | continue; |
519 | 638 | ||
520 | if (flag == FILTER_INIT_NO_RESET) { | ||
521 | call->filter->no_reset = false; | ||
522 | continue; | ||
523 | } | ||
524 | |||
525 | if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset) | ||
526 | continue; | ||
527 | |||
528 | filter_disable_preds(call); | 639 | filter_disable_preds(call); |
529 | remove_filter_string(call->filter); | 640 | remove_filter_string(call->filter); |
530 | } | 641 | } |
@@ -532,10 +643,10 @@ static void filter_free_subsystem_preds(struct event_subsystem *system, | |||
532 | 643 | ||
533 | static int filter_add_pred_fn(struct filter_parse_state *ps, | 644 | static int filter_add_pred_fn(struct filter_parse_state *ps, |
534 | struct ftrace_event_call *call, | 645 | struct ftrace_event_call *call, |
646 | struct event_filter *filter, | ||
535 | struct filter_pred *pred, | 647 | struct filter_pred *pred, |
536 | filter_pred_fn_t fn) | 648 | filter_pred_fn_t fn) |
537 | { | 649 | { |
538 | struct event_filter *filter = call->filter; | ||
539 | int idx, err; | 650 | int idx, err; |
540 | 651 | ||
541 | if (filter->n_preds == MAX_FILTER_PRED) { | 652 | if (filter->n_preds == MAX_FILTER_PRED) { |
@@ -550,7 +661,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, | |||
550 | return err; | 661 | return err; |
551 | 662 | ||
552 | filter->n_preds++; | 663 | filter->n_preds++; |
553 | call->filter_active = 1; | ||
554 | 664 | ||
555 | return 0; | 665 | return 0; |
556 | } | 666 | } |
@@ -575,7 +685,10 @@ static bool is_string_field(struct ftrace_event_field *field) | |||
575 | 685 | ||
576 | static int is_legal_op(struct ftrace_event_field *field, int op) | 686 | static int is_legal_op(struct ftrace_event_field *field, int op) |
577 | { | 687 | { |
578 | if (is_string_field(field) && (op != OP_EQ && op != OP_NE)) | 688 | if (is_string_field(field) && |
689 | (op != OP_EQ && op != OP_NE && op != OP_GLOB)) | ||
690 | return 0; | ||
691 | if (!is_string_field(field) && op == OP_GLOB) | ||
579 | return 0; | 692 | return 0; |
580 | 693 | ||
581 | return 1; | 694 | return 1; |
@@ -626,6 +739,7 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size, | |||
626 | 739 | ||
627 | static int filter_add_pred(struct filter_parse_state *ps, | 740 | static int filter_add_pred(struct filter_parse_state *ps, |
628 | struct ftrace_event_call *call, | 741 | struct ftrace_event_call *call, |
742 | struct event_filter *filter, | ||
629 | struct filter_pred *pred, | 743 | struct filter_pred *pred, |
630 | bool dry_run) | 744 | bool dry_run) |
631 | { | 745 | { |
@@ -660,21 +774,22 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
660 | } | 774 | } |
661 | 775 | ||
662 | if (is_string_field(field)) { | 776 | if (is_string_field(field)) { |
663 | pred->str_len = field->size; | 777 | filter_build_regex(pred); |
664 | 778 | ||
665 | if (field->filter_type == FILTER_STATIC_STRING) | 779 | if (field->filter_type == FILTER_STATIC_STRING) { |
666 | fn = filter_pred_string; | 780 | fn = filter_pred_string; |
667 | else if (field->filter_type == FILTER_DYN_STRING) | 781 | pred->regex.field_len = field->size; |
782 | } else if (field->filter_type == FILTER_DYN_STRING) | ||
668 | fn = filter_pred_strloc; | 783 | fn = filter_pred_strloc; |
669 | else { | 784 | else { |
670 | fn = filter_pred_pchar; | 785 | fn = filter_pred_pchar; |
671 | pred->str_len = strlen(pred->str_val); | 786 | pred->regex.field_len = strlen(pred->regex.pattern); |
672 | } | 787 | } |
673 | } else { | 788 | } else { |
674 | if (field->is_signed) | 789 | if (field->is_signed) |
675 | ret = strict_strtoll(pred->str_val, 0, &val); | 790 | ret = strict_strtoll(pred->regex.pattern, 0, &val); |
676 | else | 791 | else |
677 | ret = strict_strtoull(pred->str_val, 0, &val); | 792 | ret = strict_strtoull(pred->regex.pattern, 0, &val); |
678 | if (ret) { | 793 | if (ret) { |
679 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); | 794 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); |
680 | return -EINVAL; | 795 | return -EINVAL; |
@@ -694,45 +809,7 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
694 | 809 | ||
695 | add_pred_fn: | 810 | add_pred_fn: |
696 | if (!dry_run) | 811 | if (!dry_run) |
697 | return filter_add_pred_fn(ps, call, pred, fn); | 812 | return filter_add_pred_fn(ps, call, filter, pred, fn); |
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int filter_add_subsystem_pred(struct filter_parse_state *ps, | ||
702 | struct event_subsystem *system, | ||
703 | struct filter_pred *pred, | ||
704 | char *filter_string, | ||
705 | bool dry_run) | ||
706 | { | ||
707 | struct ftrace_event_call *call; | ||
708 | int err = 0; | ||
709 | bool fail = true; | ||
710 | |||
711 | list_for_each_entry(call, &ftrace_events, list) { | ||
712 | |||
713 | if (!call->define_fields) | ||
714 | continue; | ||
715 | |||
716 | if (strcmp(call->system, system->name)) | ||
717 | continue; | ||
718 | |||
719 | if (call->filter->no_reset) | ||
720 | continue; | ||
721 | |||
722 | err = filter_add_pred(ps, call, pred, dry_run); | ||
723 | if (err) | ||
724 | call->filter->no_reset = true; | ||
725 | else | ||
726 | fail = false; | ||
727 | |||
728 | if (!dry_run) | ||
729 | replace_filter_string(call->filter, filter_string); | ||
730 | } | ||
731 | |||
732 | if (fail) { | ||
733 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); | ||
734 | return err; | ||
735 | } | ||
736 | return 0; | 813 | return 0; |
737 | } | 814 | } |
738 | 815 | ||
@@ -1045,8 +1122,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2) | |||
1045 | return NULL; | 1122 | return NULL; |
1046 | } | 1123 | } |
1047 | 1124 | ||
1048 | strcpy(pred->str_val, operand2); | 1125 | strcpy(pred->regex.pattern, operand2); |
1049 | pred->str_len = strlen(operand2); | 1126 | pred->regex.len = strlen(pred->regex.pattern); |
1050 | 1127 | ||
1051 | pred->op = op; | 1128 | pred->op = op; |
1052 | 1129 | ||
@@ -1090,8 +1167,8 @@ static int check_preds(struct filter_parse_state *ps) | |||
1090 | return 0; | 1167 | return 0; |
1091 | } | 1168 | } |
1092 | 1169 | ||
1093 | static int replace_preds(struct event_subsystem *system, | 1170 | static int replace_preds(struct ftrace_event_call *call, |
1094 | struct ftrace_event_call *call, | 1171 | struct event_filter *filter, |
1095 | struct filter_parse_state *ps, | 1172 | struct filter_parse_state *ps, |
1096 | char *filter_string, | 1173 | char *filter_string, |
1097 | bool dry_run) | 1174 | bool dry_run) |
@@ -1138,11 +1215,7 @@ static int replace_preds(struct event_subsystem *system, | |||
1138 | add_pred: | 1215 | add_pred: |
1139 | if (!pred) | 1216 | if (!pred) |
1140 | return -ENOMEM; | 1217 | return -ENOMEM; |
1141 | if (call) | 1218 | err = filter_add_pred(ps, call, filter, pred, dry_run); |
1142 | err = filter_add_pred(ps, call, pred, false); | ||
1143 | else | ||
1144 | err = filter_add_subsystem_pred(ps, system, pred, | ||
1145 | filter_string, dry_run); | ||
1146 | filter_free_pred(pred); | 1219 | filter_free_pred(pred); |
1147 | if (err) | 1220 | if (err) |
1148 | return err; | 1221 | return err; |
@@ -1153,10 +1226,50 @@ add_pred: | |||
1153 | return 0; | 1226 | return 0; |
1154 | } | 1227 | } |
1155 | 1228 | ||
1156 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | 1229 | static int replace_system_preds(struct event_subsystem *system, |
1230 | struct filter_parse_state *ps, | ||
1231 | char *filter_string) | ||
1157 | { | 1232 | { |
1233 | struct event_filter *filter = system->filter; | ||
1234 | struct ftrace_event_call *call; | ||
1235 | bool fail = true; | ||
1158 | int err; | 1236 | int err; |
1159 | 1237 | ||
1238 | list_for_each_entry(call, &ftrace_events, list) { | ||
1239 | |||
1240 | if (!call->define_fields) | ||
1241 | continue; | ||
1242 | |||
1243 | if (strcmp(call->system, system->name) != 0) | ||
1244 | continue; | ||
1245 | |||
1246 | /* try to see if the filter can be applied */ | ||
1247 | err = replace_preds(call, filter, ps, filter_string, true); | ||
1248 | if (err) | ||
1249 | continue; | ||
1250 | |||
1251 | /* really apply the filter */ | ||
1252 | filter_disable_preds(call); | ||
1253 | err = replace_preds(call, filter, ps, filter_string, false); | ||
1254 | if (err) | ||
1255 | filter_disable_preds(call); | ||
1256 | else { | ||
1257 | call->filter_active = 1; | ||
1258 | replace_filter_string(filter, filter_string); | ||
1259 | } | ||
1260 | fail = false; | ||
1261 | } | ||
1262 | |||
1263 | if (fail) { | ||
1264 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); | ||
1265 | return -EINVAL; | ||
1266 | } | ||
1267 | return 0; | ||
1268 | } | ||
1269 | |||
1270 | int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | ||
1271 | { | ||
1272 | int err; | ||
1160 | struct filter_parse_state *ps; | 1273 | struct filter_parse_state *ps; |
1161 | 1274 | ||
1162 | mutex_lock(&event_mutex); | 1275 | mutex_lock(&event_mutex); |
@@ -1168,8 +1281,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
1168 | if (!strcmp(strstrip(filter_string), "0")) { | 1281 | if (!strcmp(strstrip(filter_string), "0")) { |
1169 | filter_disable_preds(call); | 1282 | filter_disable_preds(call); |
1170 | remove_filter_string(call->filter); | 1283 | remove_filter_string(call->filter); |
1171 | mutex_unlock(&event_mutex); | 1284 | goto out_unlock; |
1172 | return 0; | ||
1173 | } | 1285 | } |
1174 | 1286 | ||
1175 | err = -ENOMEM; | 1287 | err = -ENOMEM; |
@@ -1187,10 +1299,11 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
1187 | goto out; | 1299 | goto out; |
1188 | } | 1300 | } |
1189 | 1301 | ||
1190 | err = replace_preds(NULL, call, ps, filter_string, false); | 1302 | err = replace_preds(call, call->filter, ps, filter_string, false); |
1191 | if (err) | 1303 | if (err) |
1192 | append_filter_err(ps, call->filter); | 1304 | append_filter_err(ps, call->filter); |
1193 | 1305 | else | |
1306 | call->filter_active = 1; | ||
1194 | out: | 1307 | out: |
1195 | filter_opstack_clear(ps); | 1308 | filter_opstack_clear(ps); |
1196 | postfix_clear(ps); | 1309 | postfix_clear(ps); |
@@ -1205,7 +1318,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
1205 | char *filter_string) | 1318 | char *filter_string) |
1206 | { | 1319 | { |
1207 | int err; | 1320 | int err; |
1208 | |||
1209 | struct filter_parse_state *ps; | 1321 | struct filter_parse_state *ps; |
1210 | 1322 | ||
1211 | mutex_lock(&event_mutex); | 1323 | mutex_lock(&event_mutex); |
@@ -1215,10 +1327,9 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
1215 | goto out_unlock; | 1327 | goto out_unlock; |
1216 | 1328 | ||
1217 | if (!strcmp(strstrip(filter_string), "0")) { | 1329 | if (!strcmp(strstrip(filter_string), "0")) { |
1218 | filter_free_subsystem_preds(system, FILTER_DISABLE_ALL); | 1330 | filter_free_subsystem_preds(system); |
1219 | remove_filter_string(system->filter); | 1331 | remove_filter_string(system->filter); |
1220 | mutex_unlock(&event_mutex); | 1332 | goto out_unlock; |
1221 | return 0; | ||
1222 | } | 1333 | } |
1223 | 1334 | ||
1224 | err = -ENOMEM; | 1335 | err = -ENOMEM; |
@@ -1235,31 +1346,87 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
1235 | goto out; | 1346 | goto out; |
1236 | } | 1347 | } |
1237 | 1348 | ||
1238 | filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET); | 1349 | err = replace_system_preds(system, ps, filter_string); |
1239 | 1350 | if (err) | |
1240 | /* try to see the filter can be applied to which events */ | ||
1241 | err = replace_preds(system, NULL, ps, filter_string, true); | ||
1242 | if (err) { | ||
1243 | append_filter_err(ps, system->filter); | 1351 | append_filter_err(ps, system->filter); |
1244 | goto out; | 1352 | |
1353 | out: | ||
1354 | filter_opstack_clear(ps); | ||
1355 | postfix_clear(ps); | ||
1356 | kfree(ps); | ||
1357 | out_unlock: | ||
1358 | mutex_unlock(&event_mutex); | ||
1359 | |||
1360 | return err; | ||
1361 | } | ||
1362 | |||
1363 | #ifdef CONFIG_EVENT_PROFILE | ||
1364 | |||
1365 | void ftrace_profile_free_filter(struct perf_event *event) | ||
1366 | { | ||
1367 | struct event_filter *filter = event->filter; | ||
1368 | |||
1369 | event->filter = NULL; | ||
1370 | __free_preds(filter); | ||
1371 | } | ||
1372 | |||
1373 | int ftrace_profile_set_filter(struct perf_event *event, int event_id, | ||
1374 | char *filter_str) | ||
1375 | { | ||
1376 | int err; | ||
1377 | struct event_filter *filter; | ||
1378 | struct filter_parse_state *ps; | ||
1379 | struct ftrace_event_call *call = NULL; | ||
1380 | |||
1381 | mutex_lock(&event_mutex); | ||
1382 | |||
1383 | list_for_each_entry(call, &ftrace_events, list) { | ||
1384 | if (call->id == event_id) | ||
1385 | break; | ||
1245 | } | 1386 | } |
1246 | 1387 | ||
1247 | filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET); | 1388 | err = -EINVAL; |
1389 | if (!call) | ||
1390 | goto out_unlock; | ||
1248 | 1391 | ||
1249 | /* really apply the filter to the events */ | 1392 | err = -EEXIST; |
1250 | err = replace_preds(system, NULL, ps, filter_string, false); | 1393 | if (event->filter) |
1251 | if (err) { | 1394 | goto out_unlock; |
1252 | append_filter_err(ps, system->filter); | 1395 | |
1253 | filter_free_subsystem_preds(system, 2); | 1396 | filter = __alloc_preds(); |
1397 | if (IS_ERR(filter)) { | ||
1398 | err = PTR_ERR(filter); | ||
1399 | goto out_unlock; | ||
1254 | } | 1400 | } |
1255 | 1401 | ||
1256 | out: | 1402 | err = -ENOMEM; |
1403 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); | ||
1404 | if (!ps) | ||
1405 | goto free_preds; | ||
1406 | |||
1407 | parse_init(ps, filter_ops, filter_str); | ||
1408 | err = filter_parse(ps); | ||
1409 | if (err) | ||
1410 | goto free_ps; | ||
1411 | |||
1412 | err = replace_preds(call, filter, ps, filter_str, false); | ||
1413 | if (!err) | ||
1414 | event->filter = filter; | ||
1415 | |||
1416 | free_ps: | ||
1257 | filter_opstack_clear(ps); | 1417 | filter_opstack_clear(ps); |
1258 | postfix_clear(ps); | 1418 | postfix_clear(ps); |
1259 | kfree(ps); | 1419 | kfree(ps); |
1420 | |||
1421 | free_preds: | ||
1422 | if (err) | ||
1423 | __free_preds(filter); | ||
1424 | |||
1260 | out_unlock: | 1425 | out_unlock: |
1261 | mutex_unlock(&event_mutex); | 1426 | mutex_unlock(&event_mutex); |
1262 | 1427 | ||
1263 | return err; | 1428 | return err; |
1264 | } | 1429 | } |
1265 | 1430 | ||
1431 | #endif /* CONFIG_EVENT_PROFILE */ | ||
1432 | |||
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c index ed7d48083520..934d81fb4ca4 100644 --- a/kernel/trace/trace_export.c +++ b/kernel/trace/trace_export.c | |||
@@ -66,44 +66,47 @@ static void __used ____ftrace_check_##name(void) \ | |||
66 | #undef __field | 66 | #undef __field |
67 | #define __field(type, item) \ | 67 | #define __field(type, item) \ |
68 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | 68 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ |
69 | "offset:%zu;\tsize:%zu;\n", \ | 69 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ |
70 | offsetof(typeof(field), item), \ | 70 | offsetof(typeof(field), item), \ |
71 | sizeof(field.item)); \ | 71 | sizeof(field.item), is_signed_type(type)); \ |
72 | if (!ret) \ | 72 | if (!ret) \ |
73 | return 0; | 73 | return 0; |
74 | 74 | ||
75 | #undef __field_desc | 75 | #undef __field_desc |
76 | #define __field_desc(type, container, item) \ | 76 | #define __field_desc(type, container, item) \ |
77 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | 77 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ |
78 | "offset:%zu;\tsize:%zu;\n", \ | 78 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ |
79 | offsetof(typeof(field), container.item), \ | 79 | offsetof(typeof(field), container.item), \ |
80 | sizeof(field.container.item)); \ | 80 | sizeof(field.container.item), \ |
81 | is_signed_type(type)); \ | ||
81 | if (!ret) \ | 82 | if (!ret) \ |
82 | return 0; | 83 | return 0; |
83 | 84 | ||
84 | #undef __array | 85 | #undef __array |
85 | #define __array(type, item, len) \ | 86 | #define __array(type, item, len) \ |
86 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ | 87 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ |
87 | "offset:%zu;\tsize:%zu;\n", \ | 88 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ |
88 | offsetof(typeof(field), item), \ | 89 | offsetof(typeof(field), item), \ |
89 | sizeof(field.item)); \ | 90 | sizeof(field.item), is_signed_type(type)); \ |
90 | if (!ret) \ | 91 | if (!ret) \ |
91 | return 0; | 92 | return 0; |
92 | 93 | ||
93 | #undef __array_desc | 94 | #undef __array_desc |
94 | #define __array_desc(type, container, item, len) \ | 95 | #define __array_desc(type, container, item, len) \ |
95 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ | 96 | ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \ |
96 | "offset:%zu;\tsize:%zu;\n", \ | 97 | "offset:%zu;\tsize:%zu;\tsigned:%u;\n", \ |
97 | offsetof(typeof(field), container.item), \ | 98 | offsetof(typeof(field), container.item), \ |
98 | sizeof(field.container.item)); \ | 99 | sizeof(field.container.item), \ |
100 | is_signed_type(type)); \ | ||
99 | if (!ret) \ | 101 | if (!ret) \ |
100 | return 0; | 102 | return 0; |
101 | 103 | ||
102 | #undef __dynamic_array | 104 | #undef __dynamic_array |
103 | #define __dynamic_array(type, item) \ | 105 | #define __dynamic_array(type, item) \ |
104 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | 106 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ |
105 | "offset:%zu;\tsize:0;\n", \ | 107 | "offset:%zu;\tsize:0;\tsigned:%u;\n", \ |
106 | offsetof(typeof(field), item)); \ | 108 | offsetof(typeof(field), item), \ |
109 | is_signed_type(type)); \ | ||
107 | if (!ret) \ | 110 | if (!ret) \ |
108 | return 0; | 111 | return 0; |
109 | 112 | ||
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 9ade66389d5a..58b8e5370767 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -14,6 +14,69 @@ static int sys_refcount_exit; | |||
14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); | 14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); |
15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); | 15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
16 | 16 | ||
17 | extern unsigned long __start_syscalls_metadata[]; | ||
18 | extern unsigned long __stop_syscalls_metadata[]; | ||
19 | |||
20 | static struct syscall_metadata **syscalls_metadata; | ||
21 | |||
22 | static struct syscall_metadata *find_syscall_meta(unsigned long syscall) | ||
23 | { | ||
24 | struct syscall_metadata *start; | ||
25 | struct syscall_metadata *stop; | ||
26 | char str[KSYM_SYMBOL_LEN]; | ||
27 | |||
28 | |||
29 | start = (struct syscall_metadata *)__start_syscalls_metadata; | ||
30 | stop = (struct syscall_metadata *)__stop_syscalls_metadata; | ||
31 | kallsyms_lookup(syscall, NULL, NULL, NULL, str); | ||
32 | |||
33 | for ( ; start < stop; start++) { | ||
34 | /* | ||
35 | * Only compare after the "sys" prefix. Archs that use | ||
36 | * syscall wrappers may have syscalls symbols aliases prefixed | ||
37 | * with "SyS" instead of "sys", leading to an unwanted | ||
38 | * mismatch. | ||
39 | */ | ||
40 | if (start->name && !strcmp(start->name + 3, str + 3)) | ||
41 | return start; | ||
42 | } | ||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | static struct syscall_metadata *syscall_nr_to_meta(int nr) | ||
47 | { | ||
48 | if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | ||
49 | return NULL; | ||
50 | |||
51 | return syscalls_metadata[nr]; | ||
52 | } | ||
53 | |||
54 | int syscall_name_to_nr(char *name) | ||
55 | { | ||
56 | int i; | ||
57 | |||
58 | if (!syscalls_metadata) | ||
59 | return -1; | ||
60 | |||
61 | for (i = 0; i < NR_syscalls; i++) { | ||
62 | if (syscalls_metadata[i]) { | ||
63 | if (!strcmp(syscalls_metadata[i]->name, name)) | ||
64 | return i; | ||
65 | } | ||
66 | } | ||
67 | return -1; | ||
68 | } | ||
69 | |||
70 | void set_syscall_enter_id(int num, int id) | ||
71 | { | ||
72 | syscalls_metadata[num]->enter_id = id; | ||
73 | } | ||
74 | |||
75 | void set_syscall_exit_id(int num, int id) | ||
76 | { | ||
77 | syscalls_metadata[num]->exit_id = id; | ||
78 | } | ||
79 | |||
17 | enum print_line_t | 80 | enum print_line_t |
18 | print_syscall_enter(struct trace_iterator *iter, int flags) | 81 | print_syscall_enter(struct trace_iterator *iter, int flags) |
19 | { | 82 | { |
@@ -103,7 +166,8 @@ extern char *__bad_type_size(void); | |||
103 | #define SYSCALL_FIELD(type, name) \ | 166 | #define SYSCALL_FIELD(type, name) \ |
104 | sizeof(type) != sizeof(trace.name) ? \ | 167 | sizeof(type) != sizeof(trace.name) ? \ |
105 | __bad_type_size() : \ | 168 | __bad_type_size() : \ |
106 | #type, #name, offsetof(typeof(trace), name), sizeof(trace.name) | 169 | #type, #name, offsetof(typeof(trace), name), \ |
170 | sizeof(trace.name), is_signed_type(type) | ||
107 | 171 | ||
108 | int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | 172 | int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) |
109 | { | 173 | { |
@@ -120,7 +184,8 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | |||
120 | if (!entry) | 184 | if (!entry) |
121 | return 0; | 185 | return 0; |
122 | 186 | ||
123 | ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", | 187 | ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" |
188 | "\tsigned:%u;\n", | ||
124 | SYSCALL_FIELD(int, nr)); | 189 | SYSCALL_FIELD(int, nr)); |
125 | if (!ret) | 190 | if (!ret) |
126 | return 0; | 191 | return 0; |
@@ -130,8 +195,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | |||
130 | entry->args[i]); | 195 | entry->args[i]); |
131 | if (!ret) | 196 | if (!ret) |
132 | return 0; | 197 | return 0; |
133 | ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, | 198 | ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;" |
134 | sizeof(unsigned long)); | 199 | "\tsigned:%u;\n", offset, |
200 | sizeof(unsigned long), | ||
201 | is_signed_type(unsigned long)); | ||
135 | if (!ret) | 202 | if (!ret) |
136 | return 0; | 203 | return 0; |
137 | offset += sizeof(unsigned long); | 204 | offset += sizeof(unsigned long); |
@@ -163,8 +230,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) | |||
163 | struct syscall_trace_exit trace; | 230 | struct syscall_trace_exit trace; |
164 | 231 | ||
165 | ret = trace_seq_printf(s, | 232 | ret = trace_seq_printf(s, |
166 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 233 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" |
167 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", | 234 | "\tsigned:%u;\n" |
235 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | ||
236 | "\tsigned:%u;\n", | ||
168 | SYSCALL_FIELD(int, nr), | 237 | SYSCALL_FIELD(int, nr), |
169 | SYSCALL_FIELD(long, ret)); | 238 | SYSCALL_FIELD(long, ret)); |
170 | if (!ret) | 239 | if (!ret) |
@@ -212,7 +281,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call) | |||
212 | if (ret) | 281 | if (ret) |
213 | return ret; | 282 | return ret; |
214 | 283 | ||
215 | ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0, | 284 | ret = trace_define_field(call, SYSCALL_FIELD(long, ret), |
216 | FILTER_OTHER); | 285 | FILTER_OTHER); |
217 | 286 | ||
218 | return ret; | 287 | return ret; |
@@ -375,6 +444,29 @@ struct trace_event event_syscall_exit = { | |||
375 | .trace = print_syscall_exit, | 444 | .trace = print_syscall_exit, |
376 | }; | 445 | }; |
377 | 446 | ||
447 | int __init init_ftrace_syscalls(void) | ||
448 | { | ||
449 | struct syscall_metadata *meta; | ||
450 | unsigned long addr; | ||
451 | int i; | ||
452 | |||
453 | syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | ||
454 | NR_syscalls, GFP_KERNEL); | ||
455 | if (!syscalls_metadata) { | ||
456 | WARN_ON(1); | ||
457 | return -ENOMEM; | ||
458 | } | ||
459 | |||
460 | for (i = 0; i < NR_syscalls; i++) { | ||
461 | addr = arch_syscall_addr(i); | ||
462 | meta = find_syscall_meta(addr); | ||
463 | syscalls_metadata[i] = meta; | ||
464 | } | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | core_initcall(init_ftrace_syscalls); | ||
469 | |||
378 | #ifdef CONFIG_EVENT_PROFILE | 470 | #ifdef CONFIG_EVENT_PROFILE |
379 | 471 | ||
380 | static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); | 472 | static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); |