diff options
-rw-r--r-- | Documentation/trace/kprobetrace.txt | 4 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 110 |
2 files changed, 111 insertions, 3 deletions
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index db5531865648..8f882ebd1368 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt | |||
@@ -62,13 +62,15 @@ enabled: | |||
62 | You can enable/disable the probe by writing 1 or 0 on it. | 62 | You can enable/disable the probe by writing 1 or 0 on it. |
63 | 63 | ||
64 | format: | 64 | format: |
65 | It shows the format of this probe event. It also shows aliases of arguments | 65 | This shows the format of this probe event. It also shows aliases of arguments |
66 | which you specified to kprobe_events. | 66 | which you specified to kprobe_events. |
67 | 67 | ||
68 | filter: | 68 | filter: |
69 | You can write filtering rules of this event. And you can use both of aliase | 69 | You can write filtering rules of this event. And you can use both of aliase |
70 | names and field names for describing filters. | 70 | names and field names for describing filters. |
71 | 71 | ||
72 | id: | ||
73 | This shows the id of this probe event. | ||
72 | 74 | ||
73 | Event Profiling | 75 | Event Profiling |
74 | --------------- | 76 | --------------- |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 4ce728ca1b18..730e992d28da 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/string.h> | 28 | #include <linux/string.h> |
29 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
31 | #include <linux/perf_counter.h> | ||
31 | 32 | ||
32 | #include "trace.h" | 33 | #include "trace.h" |
33 | #include "trace_output.h" | 34 | #include "trace_output.h" |
@@ -280,6 +281,7 @@ static struct trace_probe *alloc_trace_probe(const char *event, | |||
280 | } else | 281 | } else |
281 | tp->rp.kp.addr = addr; | 282 | tp->rp.kp.addr = addr; |
282 | 283 | ||
284 | /* Set handler here for checking whether this probe is return or not. */ | ||
283 | if (is_return) | 285 | if (is_return) |
284 | tp->rp.handler = kretprobe_trace_func; | 286 | tp->rp.handler = kretprobe_trace_func; |
285 | else | 287 | else |
@@ -929,10 +931,13 @@ static int probe_event_enable(struct ftrace_event_call *call) | |||
929 | { | 931 | { |
930 | struct trace_probe *tp = (struct trace_probe *)call->data; | 932 | struct trace_probe *tp = (struct trace_probe *)call->data; |
931 | 933 | ||
932 | if (probe_is_return(tp)) | 934 | if (probe_is_return(tp)) { |
935 | tp->rp.handler = kretprobe_trace_func; | ||
933 | return enable_kretprobe(&tp->rp); | 936 | return enable_kretprobe(&tp->rp); |
934 | else | 937 | } else { |
938 | tp->rp.kp.pre_handler = kprobe_trace_func; | ||
935 | return enable_kprobe(&tp->rp.kp); | 939 | return enable_kprobe(&tp->rp.kp); |
940 | } | ||
936 | } | 941 | } |
937 | 942 | ||
938 | static void probe_event_disable(struct ftrace_event_call *call) | 943 | static void probe_event_disable(struct ftrace_event_call *call) |
@@ -1105,6 +1110,101 @@ static int kretprobe_event_show_format(struct ftrace_event_call *call, | |||
1105 | "func, ret_ip"); | 1110 | "func, ret_ip"); |
1106 | } | 1111 | } |
1107 | 1112 | ||
1113 | #ifdef CONFIG_EVENT_PROFILE | ||
1114 | |||
1115 | /* Kprobe profile handler */ | ||
1116 | static __kprobes int kprobe_profile_func(struct kprobe *kp, | ||
1117 | struct pt_regs *regs) | ||
1118 | { | ||
1119 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); | ||
1120 | struct ftrace_event_call *call = &tp->call; | ||
1121 | struct kprobe_trace_entry *entry; | ||
1122 | int size, i, pc; | ||
1123 | unsigned long irq_flags; | ||
1124 | |||
1125 | local_save_flags(irq_flags); | ||
1126 | pc = preempt_count(); | ||
1127 | |||
1128 | size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); | ||
1129 | |||
1130 | do { | ||
1131 | char raw_data[size]; | ||
1132 | struct trace_entry *ent; | ||
1133 | |||
1134 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
1135 | entry = (struct kprobe_trace_entry *)raw_data; | ||
1136 | ent = &entry->ent; | ||
1137 | |||
1138 | tracing_generic_entry_update(ent, irq_flags, pc); | ||
1139 | ent->type = call->id; | ||
1140 | entry->nargs = tp->nr_args; | ||
1141 | entry->ip = (unsigned long)kp->addr; | ||
1142 | for (i = 0; i < tp->nr_args; i++) | ||
1143 | entry->args[i] = call_fetch(&tp->args[i], regs); | ||
1144 | perf_tpcounter_event(call->id, entry->ip, 1, entry, size); | ||
1145 | } while (0); | ||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1149 | /* Kretprobe profile handler */ | ||
1150 | static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri, | ||
1151 | struct pt_regs *regs) | ||
1152 | { | ||
1153 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | ||
1154 | struct ftrace_event_call *call = &tp->call; | ||
1155 | struct kretprobe_trace_entry *entry; | ||
1156 | int size, i, pc; | ||
1157 | unsigned long irq_flags; | ||
1158 | |||
1159 | local_save_flags(irq_flags); | ||
1160 | pc = preempt_count(); | ||
1161 | |||
1162 | size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); | ||
1163 | |||
1164 | do { | ||
1165 | char raw_data[size]; | ||
1166 | struct trace_entry *ent; | ||
1167 | |||
1168 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
1169 | entry = (struct kretprobe_trace_entry *)raw_data; | ||
1170 | ent = &entry->ent; | ||
1171 | |||
1172 | tracing_generic_entry_update(ent, irq_flags, pc); | ||
1173 | ent->type = call->id; | ||
1174 | entry->nargs = tp->nr_args; | ||
1175 | entry->func = (unsigned long)tp->rp.kp.addr; | ||
1176 | entry->ret_ip = (unsigned long)ri->ret_addr; | ||
1177 | for (i = 0; i < tp->nr_args; i++) | ||
1178 | entry->args[i] = call_fetch(&tp->args[i], regs); | ||
1179 | perf_tpcounter_event(call->id, entry->ret_ip, 1, entry, size); | ||
1180 | } while (0); | ||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | static int probe_profile_enable(struct ftrace_event_call *call) | ||
1185 | { | ||
1186 | struct trace_probe *tp = (struct trace_probe *)call->data; | ||
1187 | |||
1188 | if (atomic_inc_return(&call->profile_count)) | ||
1189 | return 0; | ||
1190 | |||
1191 | if (probe_is_return(tp)) { | ||
1192 | tp->rp.handler = kretprobe_profile_func; | ||
1193 | return enable_kretprobe(&tp->rp); | ||
1194 | } else { | ||
1195 | tp->rp.kp.pre_handler = kprobe_profile_func; | ||
1196 | return enable_kprobe(&tp->rp.kp); | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | static void probe_profile_disable(struct ftrace_event_call *call) | ||
1201 | { | ||
1202 | if (atomic_add_negative(-1, &call->profile_count)) | ||
1203 | probe_event_disable(call); | ||
1204 | } | ||
1205 | |||
1206 | #endif /* CONFIG_EVENT_PROFILE */ | ||
1207 | |||
1108 | static int register_probe_event(struct trace_probe *tp) | 1208 | static int register_probe_event(struct trace_probe *tp) |
1109 | { | 1209 | { |
1110 | struct ftrace_event_call *call = &tp->call; | 1210 | struct ftrace_event_call *call = &tp->call; |
@@ -1130,6 +1230,12 @@ static int register_probe_event(struct trace_probe *tp) | |||
1130 | call->enabled = 1; | 1230 | call->enabled = 1; |
1131 | call->regfunc = probe_event_enable; | 1231 | call->regfunc = probe_event_enable; |
1132 | call->unregfunc = probe_event_disable; | 1232 | call->unregfunc = probe_event_disable; |
1233 | |||
1234 | #ifdef CONFIG_EVENT_PROFILE | ||
1235 | atomic_set(&call->profile_count, -1); | ||
1236 | call->profile_enable = probe_profile_enable; | ||
1237 | call->profile_disable = probe_profile_disable; | ||
1238 | #endif | ||
1133 | call->data = tp; | 1239 | call->data = tp; |
1134 | ret = trace_add_event_call(call); | 1240 | ret = trace_add_event_call(call); |
1135 | if (ret) { | 1241 | if (ret) { |