diff options
-rw-r--r-- | Documentation/trace/kprobetrace.txt | 4 | ||||
-rw-r--r-- | kernel/trace/trace.h | 16 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 535 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 11 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 78 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 28 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 898 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 33 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 753 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 1 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 42 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 12 |
12 files changed, 1634 insertions, 777 deletions
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt index a9100b28eb84..ec94748ae65b 100644 --- a/Documentation/trace/kprobetrace.txt +++ b/Documentation/trace/kprobetrace.txt | |||
@@ -40,7 +40,9 @@ Synopsis of kprobe_events | |||
40 | $stack : Fetch stack address. | 40 | $stack : Fetch stack address. |
41 | $retval : Fetch return value.(*) | 41 | $retval : Fetch return value.(*) |
42 | +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) | 42 | +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) |
43 | NAME=FETCHARG: Set NAME as the argument name of FETCHARG. | 43 | NAME=FETCHARG : Set NAME as the argument name of FETCHARG. |
44 | FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types | ||
45 | (u8/u16/u32/u64/s8/s16/s32/s64) are supported. | ||
44 | 46 | ||
45 | (*) only for return probe. | 47 | (*) only for return probe. |
46 | (**) this is useful for fetching a field of data structures. | 48 | (**) this is useful for fetching a field of data structures. |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index bec2c973ff0c..3ebdb6bd2362 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -102,29 +102,17 @@ struct syscall_trace_exit { | |||
102 | long ret; | 102 | long ret; |
103 | }; | 103 | }; |
104 | 104 | ||
105 | struct kprobe_trace_entry { | 105 | struct kprobe_trace_entry_head { |
106 | struct trace_entry ent; | 106 | struct trace_entry ent; |
107 | unsigned long ip; | 107 | unsigned long ip; |
108 | int nargs; | ||
109 | unsigned long args[]; | ||
110 | }; | 108 | }; |
111 | 109 | ||
112 | #define SIZEOF_KPROBE_TRACE_ENTRY(n) \ | 110 | struct kretprobe_trace_entry_head { |
113 | (offsetof(struct kprobe_trace_entry, args) + \ | ||
114 | (sizeof(unsigned long) * (n))) | ||
115 | |||
116 | struct kretprobe_trace_entry { | ||
117 | struct trace_entry ent; | 111 | struct trace_entry ent; |
118 | unsigned long func; | 112 | unsigned long func; |
119 | unsigned long ret_ip; | 113 | unsigned long ret_ip; |
120 | int nargs; | ||
121 | unsigned long args[]; | ||
122 | }; | 114 | }; |
123 | 115 | ||
124 | #define SIZEOF_KRETPROBE_TRACE_ENTRY(n) \ | ||
125 | (offsetof(struct kretprobe_trace_entry, args) + \ | ||
126 | (sizeof(unsigned long) * (n))) | ||
127 | |||
128 | /* | 116 | /* |
129 | * trace_flag_type is an enumeration that holds different | 117 | * trace_flag_type is an enumeration that holds different |
130 | * states when a trace occurs. These are: | 118 | * states when a trace occurs. These are: |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 1251e367bae9..a7514326052b 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
30 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
31 | #include <linux/perf_event.h> | 31 | #include <linux/perf_event.h> |
32 | #include <linux/stringify.h> | ||
33 | #include <asm/bitsperlong.h> | ||
32 | 34 | ||
33 | #include "trace.h" | 35 | #include "trace.h" |
34 | #include "trace_output.h" | 36 | #include "trace_output.h" |
@@ -40,7 +42,6 @@ | |||
40 | 42 | ||
41 | /* Reserved field names */ | 43 | /* Reserved field names */ |
42 | #define FIELD_STRING_IP "__probe_ip" | 44 | #define FIELD_STRING_IP "__probe_ip" |
43 | #define FIELD_STRING_NARGS "__probe_nargs" | ||
44 | #define FIELD_STRING_RETIP "__probe_ret_ip" | 45 | #define FIELD_STRING_RETIP "__probe_ret_ip" |
45 | #define FIELD_STRING_FUNC "__probe_func" | 46 | #define FIELD_STRING_FUNC "__probe_func" |
46 | 47 | ||
@@ -52,56 +53,102 @@ const char *reserved_field_names[] = { | |||
52 | "common_tgid", | 53 | "common_tgid", |
53 | "common_lock_depth", | 54 | "common_lock_depth", |
54 | FIELD_STRING_IP, | 55 | FIELD_STRING_IP, |
55 | FIELD_STRING_NARGS, | ||
56 | FIELD_STRING_RETIP, | 56 | FIELD_STRING_RETIP, |
57 | FIELD_STRING_FUNC, | 57 | FIELD_STRING_FUNC, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct fetch_func { | 60 | /* Printing function type */ |
61 | unsigned long (*func)(struct pt_regs *, void *); | 61 | typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *); |
62 | #define PRINT_TYPE_FUNC_NAME(type) print_type_##type | ||
63 | #define PRINT_TYPE_FMT_NAME(type) print_type_format_##type | ||
64 | |||
65 | /* Printing in basic type function template */ | ||
66 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \ | ||
67 | static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ | ||
68 | const char *name, void *data)\ | ||
69 | { \ | ||
70 | return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\ | ||
71 | } \ | ||
72 | static const char PRINT_TYPE_FMT_NAME(type)[] = fmt; | ||
73 | |||
74 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int) | ||
75 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int) | ||
76 | DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long) | ||
77 | DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long) | ||
78 | DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int) | ||
79 | DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int) | ||
80 | DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long) | ||
81 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long) | ||
82 | |||
83 | /* Data fetch function type */ | ||
84 | typedef void (*fetch_func_t)(struct pt_regs *, void *, void *); | ||
85 | |||
86 | struct fetch_param { | ||
87 | fetch_func_t fn; | ||
62 | void *data; | 88 | void *data; |
63 | }; | 89 | }; |
64 | 90 | ||
65 | static __kprobes unsigned long call_fetch(struct fetch_func *f, | 91 | static __kprobes void call_fetch(struct fetch_param *fprm, |
66 | struct pt_regs *regs) | 92 | struct pt_regs *regs, void *dest) |
67 | { | 93 | { |
68 | return f->func(regs, f->data); | 94 | return fprm->fn(regs, fprm->data, dest); |
69 | } | 95 | } |
70 | 96 | ||
71 | /* fetch handlers */ | 97 | #define FETCH_FUNC_NAME(kind, type) fetch_##kind##_##type |
72 | static __kprobes unsigned long fetch_register(struct pt_regs *regs, | 98 | /* |
73 | void *offset) | 99 | * Define macro for basic types - we don't need to define s* types, because |
74 | { | 100 | * we have to care only about bitwidth at recording time. |
75 | return regs_get_register(regs, (unsigned int)((unsigned long)offset)); | 101 | */ |
102 | #define DEFINE_BASIC_FETCH_FUNCS(kind) \ | ||
103 | DEFINE_FETCH_##kind(u8) \ | ||
104 | DEFINE_FETCH_##kind(u16) \ | ||
105 | DEFINE_FETCH_##kind(u32) \ | ||
106 | DEFINE_FETCH_##kind(u64) | ||
107 | |||
108 | #define CHECK_BASIC_FETCH_FUNCS(kind, fn) \ | ||
109 | ((FETCH_FUNC_NAME(kind, u8) == fn) || \ | ||
110 | (FETCH_FUNC_NAME(kind, u16) == fn) || \ | ||
111 | (FETCH_FUNC_NAME(kind, u32) == fn) || \ | ||
112 | (FETCH_FUNC_NAME(kind, u64) == fn)) | ||
113 | |||
114 | /* Data fetch function templates */ | ||
115 | #define DEFINE_FETCH_reg(type) \ | ||
116 | static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ | ||
117 | void *offset, void *dest) \ | ||
118 | { \ | ||
119 | *(type *)dest = (type)regs_get_register(regs, \ | ||
120 | (unsigned int)((unsigned long)offset)); \ | ||
76 | } | 121 | } |
77 | 122 | DEFINE_BASIC_FETCH_FUNCS(reg) | |
78 | static __kprobes unsigned long fetch_stack(struct pt_regs *regs, | 123 | |
79 | void *num) | 124 | #define DEFINE_FETCH_stack(type) \ |
80 | { | 125 | static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ |
81 | return regs_get_kernel_stack_nth(regs, | 126 | void *offset, void *dest) \ |
82 | (unsigned int)((unsigned long)num)); | 127 | { \ |
128 | *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ | ||
129 | (unsigned int)((unsigned long)offset)); \ | ||
83 | } | 130 | } |
131 | DEFINE_BASIC_FETCH_FUNCS(stack) | ||
84 | 132 | ||
85 | static __kprobes unsigned long fetch_memory(struct pt_regs *regs, void *addr) | 133 | #define DEFINE_FETCH_retval(type) \ |
86 | { | 134 | static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\ |
87 | unsigned long retval; | 135 | void *dummy, void *dest) \ |
88 | 136 | { \ | |
89 | if (probe_kernel_address(addr, retval)) | 137 | *(type *)dest = (type)regs_return_value(regs); \ |
90 | return 0; | ||
91 | return retval; | ||
92 | } | 138 | } |
93 | 139 | DEFINE_BASIC_FETCH_FUNCS(retval) | |
94 | static __kprobes unsigned long fetch_retvalue(struct pt_regs *regs, | 140 | |
95 | void *dummy) | 141 | #define DEFINE_FETCH_memory(type) \ |
96 | { | 142 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ |
97 | return regs_return_value(regs); | 143 | void *addr, void *dest) \ |
98 | } | 144 | { \ |
99 | 145 | type retval; \ | |
100 | static __kprobes unsigned long fetch_stack_address(struct pt_regs *regs, | 146 | if (probe_kernel_address(addr, retval)) \ |
101 | void *dummy) | 147 | *(type *)dest = 0; \ |
102 | { | 148 | else \ |
103 | return kernel_stack_pointer(regs); | 149 | *(type *)dest = retval; \ |
104 | } | 150 | } |
151 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
105 | 152 | ||
106 | /* Memory fetching by symbol */ | 153 | /* Memory fetching by symbol */ |
107 | struct symbol_cache { | 154 | struct symbol_cache { |
@@ -145,51 +192,126 @@ static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) | |||
145 | return sc; | 192 | return sc; |
146 | } | 193 | } |
147 | 194 | ||
148 | static __kprobes unsigned long fetch_symbol(struct pt_regs *regs, void *data) | 195 | #define DEFINE_FETCH_symbol(type) \ |
149 | { | 196 | static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\ |
150 | struct symbol_cache *sc = data; | 197 | void *data, void *dest) \ |
151 | 198 | { \ | |
152 | if (sc->addr) | 199 | struct symbol_cache *sc = data; \ |
153 | return fetch_memory(regs, (void *)sc->addr); | 200 | if (sc->addr) \ |
154 | else | 201 | fetch_memory_##type(regs, (void *)sc->addr, dest); \ |
155 | return 0; | 202 | else \ |
203 | *(type *)dest = 0; \ | ||
156 | } | 204 | } |
205 | DEFINE_BASIC_FETCH_FUNCS(symbol) | ||
157 | 206 | ||
158 | /* Special indirect memory access interface */ | 207 | /* Dereference memory access function */ |
159 | struct indirect_fetch_data { | 208 | struct deref_fetch_param { |
160 | struct fetch_func orig; | 209 | struct fetch_param orig; |
161 | long offset; | 210 | long offset; |
162 | }; | 211 | }; |
163 | 212 | ||
164 | static __kprobes unsigned long fetch_indirect(struct pt_regs *regs, void *data) | 213 | #define DEFINE_FETCH_deref(type) \ |
165 | { | 214 | static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\ |
166 | struct indirect_fetch_data *ind = data; | 215 | void *data, void *dest) \ |
167 | unsigned long addr; | 216 | { \ |
168 | 217 | struct deref_fetch_param *dprm = data; \ | |
169 | addr = call_fetch(&ind->orig, regs); | 218 | unsigned long addr; \ |
170 | if (addr) { | 219 | call_fetch(&dprm->orig, regs, &addr); \ |
171 | addr += ind->offset; | 220 | if (addr) { \ |
172 | return fetch_memory(regs, (void *)addr); | 221 | addr += dprm->offset; \ |
173 | } else | 222 | fetch_memory_##type(regs, (void *)addr, dest); \ |
174 | return 0; | 223 | } else \ |
224 | *(type *)dest = 0; \ | ||
175 | } | 225 | } |
226 | DEFINE_BASIC_FETCH_FUNCS(deref) | ||
176 | 227 | ||
177 | static __kprobes void free_indirect_fetch_data(struct indirect_fetch_data *data) | 228 | static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) |
178 | { | 229 | { |
179 | if (data->orig.func == fetch_indirect) | 230 | if (CHECK_BASIC_FETCH_FUNCS(deref, data->orig.fn)) |
180 | free_indirect_fetch_data(data->orig.data); | 231 | free_deref_fetch_param(data->orig.data); |
181 | else if (data->orig.func == fetch_symbol) | 232 | else if (CHECK_BASIC_FETCH_FUNCS(symbol, data->orig.fn)) |
182 | free_symbol_cache(data->orig.data); | 233 | free_symbol_cache(data->orig.data); |
183 | kfree(data); | 234 | kfree(data); |
184 | } | 235 | } |
185 | 236 | ||
237 | /* Default (unsigned long) fetch type */ | ||
238 | #define __DEFAULT_FETCH_TYPE(t) u##t | ||
239 | #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) | ||
240 | #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) | ||
241 | #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) | ||
242 | |||
243 | #define ASSIGN_FETCH_FUNC(kind, type) \ | ||
244 | .kind = FETCH_FUNC_NAME(kind, type) | ||
245 | |||
246 | #define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \ | ||
247 | {.name = #ptype, \ | ||
248 | .size = sizeof(ftype), \ | ||
249 | .is_signed = sign, \ | ||
250 | .print = PRINT_TYPE_FUNC_NAME(ptype), \ | ||
251 | .fmt = PRINT_TYPE_FMT_NAME(ptype), \ | ||
252 | ASSIGN_FETCH_FUNC(reg, ftype), \ | ||
253 | ASSIGN_FETCH_FUNC(stack, ftype), \ | ||
254 | ASSIGN_FETCH_FUNC(retval, ftype), \ | ||
255 | ASSIGN_FETCH_FUNC(memory, ftype), \ | ||
256 | ASSIGN_FETCH_FUNC(symbol, ftype), \ | ||
257 | ASSIGN_FETCH_FUNC(deref, ftype), \ | ||
258 | } | ||
259 | |||
260 | /* Fetch type information table */ | ||
261 | static const struct fetch_type { | ||
262 | const char *name; /* Name of type */ | ||
263 | size_t size; /* Byte size of type */ | ||
264 | int is_signed; /* Signed flag */ | ||
265 | print_type_func_t print; /* Print functions */ | ||
266 | const char *fmt; /* Fromat string */ | ||
267 | /* Fetch functions */ | ||
268 | fetch_func_t reg; | ||
269 | fetch_func_t stack; | ||
270 | fetch_func_t retval; | ||
271 | fetch_func_t memory; | ||
272 | fetch_func_t symbol; | ||
273 | fetch_func_t deref; | ||
274 | } fetch_type_table[] = { | ||
275 | ASSIGN_FETCH_TYPE(u8, u8, 0), | ||
276 | ASSIGN_FETCH_TYPE(u16, u16, 0), | ||
277 | ASSIGN_FETCH_TYPE(u32, u32, 0), | ||
278 | ASSIGN_FETCH_TYPE(u64, u64, 0), | ||
279 | ASSIGN_FETCH_TYPE(s8, u8, 1), | ||
280 | ASSIGN_FETCH_TYPE(s16, u16, 1), | ||
281 | ASSIGN_FETCH_TYPE(s32, u32, 1), | ||
282 | ASSIGN_FETCH_TYPE(s64, u64, 1), | ||
283 | }; | ||
284 | |||
285 | static const struct fetch_type *find_fetch_type(const char *type) | ||
286 | { | ||
287 | int i; | ||
288 | |||
289 | if (!type) | ||
290 | type = DEFAULT_FETCH_TYPE_STR; | ||
291 | |||
292 | for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) | ||
293 | if (strcmp(type, fetch_type_table[i].name) == 0) | ||
294 | return &fetch_type_table[i]; | ||
295 | return NULL; | ||
296 | } | ||
297 | |||
298 | /* Special function : only accept unsigned long */ | ||
299 | static __kprobes void fetch_stack_address(struct pt_regs *regs, | ||
300 | void *dummy, void *dest) | ||
301 | { | ||
302 | *(unsigned long *)dest = kernel_stack_pointer(regs); | ||
303 | } | ||
304 | |||
186 | /** | 305 | /** |
187 | * Kprobe event core functions | 306 | * Kprobe event core functions |
188 | */ | 307 | */ |
189 | 308 | ||
190 | struct probe_arg { | 309 | struct probe_arg { |
191 | struct fetch_func fetch; | 310 | struct fetch_param fetch; |
192 | const char *name; | 311 | unsigned int offset; /* Offset from argument entry */ |
312 | const char *name; /* Name of this argument */ | ||
313 | const char *comm; /* Command of this argument */ | ||
314 | const struct fetch_type *type; /* Type of this argument */ | ||
193 | }; | 315 | }; |
194 | 316 | ||
195 | /* Flags for trace_probe */ | 317 | /* Flags for trace_probe */ |
@@ -204,6 +326,7 @@ struct trace_probe { | |||
204 | const char *symbol; /* symbol name */ | 326 | const char *symbol; /* symbol name */ |
205 | struct ftrace_event_call call; | 327 | struct ftrace_event_call call; |
206 | struct trace_event event; | 328 | struct trace_event event; |
329 | ssize_t size; /* trace entry size */ | ||
207 | unsigned int nr_args; | 330 | unsigned int nr_args; |
208 | struct probe_arg args[]; | 331 | struct probe_arg args[]; |
209 | }; | 332 | }; |
@@ -212,6 +335,7 @@ struct trace_probe { | |||
212 | (offsetof(struct trace_probe, args) + \ | 335 | (offsetof(struct trace_probe, args) + \ |
213 | (sizeof(struct probe_arg) * (n))) | 336 | (sizeof(struct probe_arg) * (n))) |
214 | 337 | ||
338 | |||
215 | static __kprobes int probe_is_return(struct trace_probe *tp) | 339 | static __kprobes int probe_is_return(struct trace_probe *tp) |
216 | { | 340 | { |
217 | return tp->rp.handler != NULL; | 341 | return tp->rp.handler != NULL; |
@@ -222,49 +346,6 @@ static __kprobes const char *probe_symbol(struct trace_probe *tp) | |||
222 | return tp->symbol ? tp->symbol : "unknown"; | 346 | return tp->symbol ? tp->symbol : "unknown"; |
223 | } | 347 | } |
224 | 348 | ||
225 | static int probe_arg_string(char *buf, size_t n, struct fetch_func *ff) | ||
226 | { | ||
227 | int ret = -EINVAL; | ||
228 | |||
229 | if (ff->func == fetch_register) { | ||
230 | const char *name; | ||
231 | name = regs_query_register_name((unsigned int)((long)ff->data)); | ||
232 | ret = snprintf(buf, n, "%%%s", name); | ||
233 | } else if (ff->func == fetch_stack) | ||
234 | ret = snprintf(buf, n, "$stack%lu", (unsigned long)ff->data); | ||
235 | else if (ff->func == fetch_memory) | ||
236 | ret = snprintf(buf, n, "@0x%p", ff->data); | ||
237 | else if (ff->func == fetch_symbol) { | ||
238 | struct symbol_cache *sc = ff->data; | ||
239 | if (sc->offset) | ||
240 | ret = snprintf(buf, n, "@%s%+ld", sc->symbol, | ||
241 | sc->offset); | ||
242 | else | ||
243 | ret = snprintf(buf, n, "@%s", sc->symbol); | ||
244 | } else if (ff->func == fetch_retvalue) | ||
245 | ret = snprintf(buf, n, "$retval"); | ||
246 | else if (ff->func == fetch_stack_address) | ||
247 | ret = snprintf(buf, n, "$stack"); | ||
248 | else if (ff->func == fetch_indirect) { | ||
249 | struct indirect_fetch_data *id = ff->data; | ||
250 | size_t l = 0; | ||
251 | ret = snprintf(buf, n, "%+ld(", id->offset); | ||
252 | if (ret >= n) | ||
253 | goto end; | ||
254 | l += ret; | ||
255 | ret = probe_arg_string(buf + l, n - l, &id->orig); | ||
256 | if (ret < 0) | ||
257 | goto end; | ||
258 | l += ret; | ||
259 | ret = snprintf(buf + l, n - l, ")"); | ||
260 | ret += l; | ||
261 | } | ||
262 | end: | ||
263 | if (ret >= n) | ||
264 | return -ENOSPC; | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | static int register_probe_event(struct trace_probe *tp); | 349 | static int register_probe_event(struct trace_probe *tp); |
269 | static void unregister_probe_event(struct trace_probe *tp); | 350 | static void unregister_probe_event(struct trace_probe *tp); |
270 | 351 | ||
@@ -347,11 +428,12 @@ error: | |||
347 | 428 | ||
348 | static void free_probe_arg(struct probe_arg *arg) | 429 | static void free_probe_arg(struct probe_arg *arg) |
349 | { | 430 | { |
350 | if (arg->fetch.func == fetch_symbol) | 431 | if (CHECK_BASIC_FETCH_FUNCS(deref, arg->fetch.fn)) |
432 | free_deref_fetch_param(arg->fetch.data); | ||
433 | else if (CHECK_BASIC_FETCH_FUNCS(symbol, arg->fetch.fn)) | ||
351 | free_symbol_cache(arg->fetch.data); | 434 | free_symbol_cache(arg->fetch.data); |
352 | else if (arg->fetch.func == fetch_indirect) | ||
353 | free_indirect_fetch_data(arg->fetch.data); | ||
354 | kfree(arg->name); | 435 | kfree(arg->name); |
436 | kfree(arg->comm); | ||
355 | } | 437 | } |
356 | 438 | ||
357 | static void free_trace_probe(struct trace_probe *tp) | 439 | static void free_trace_probe(struct trace_probe *tp) |
@@ -457,28 +539,30 @@ static int split_symbol_offset(char *symbol, unsigned long *offset) | |||
457 | #define PARAM_MAX_ARGS 16 | 539 | #define PARAM_MAX_ARGS 16 |
458 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | 540 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
459 | 541 | ||
460 | static int parse_probe_vars(char *arg, struct fetch_func *ff, int is_return) | 542 | static int parse_probe_vars(char *arg, const struct fetch_type *t, |
543 | struct fetch_param *f, int is_return) | ||
461 | { | 544 | { |
462 | int ret = 0; | 545 | int ret = 0; |
463 | unsigned long param; | 546 | unsigned long param; |
464 | 547 | ||
465 | if (strcmp(arg, "retval") == 0) { | 548 | if (strcmp(arg, "retval") == 0) { |
466 | if (is_return) { | 549 | if (is_return) |
467 | ff->func = fetch_retvalue; | 550 | f->fn = t->retval; |
468 | ff->data = NULL; | 551 | else |
469 | } else | ||
470 | ret = -EINVAL; | 552 | ret = -EINVAL; |
471 | } else if (strncmp(arg, "stack", 5) == 0) { | 553 | } else if (strncmp(arg, "stack", 5) == 0) { |
472 | if (arg[5] == '\0') { | 554 | if (arg[5] == '\0') { |
473 | ff->func = fetch_stack_address; | 555 | if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0) |
474 | ff->data = NULL; | 556 | f->fn = fetch_stack_address; |
557 | else | ||
558 | ret = -EINVAL; | ||
475 | } else if (isdigit(arg[5])) { | 559 | } else if (isdigit(arg[5])) { |
476 | ret = strict_strtoul(arg + 5, 10, ¶m); | 560 | ret = strict_strtoul(arg + 5, 10, ¶m); |
477 | if (ret || param > PARAM_MAX_STACK) | 561 | if (ret || param > PARAM_MAX_STACK) |
478 | ret = -EINVAL; | 562 | ret = -EINVAL; |
479 | else { | 563 | else { |
480 | ff->func = fetch_stack; | 564 | f->fn = t->stack; |
481 | ff->data = (void *)param; | 565 | f->data = (void *)param; |
482 | } | 566 | } |
483 | } else | 567 | } else |
484 | ret = -EINVAL; | 568 | ret = -EINVAL; |
@@ -488,7 +572,8 @@ static int parse_probe_vars(char *arg, struct fetch_func *ff, int is_return) | |||
488 | } | 572 | } |
489 | 573 | ||
490 | /* Recursive argument parser */ | 574 | /* Recursive argument parser */ |
491 | static int __parse_probe_arg(char *arg, struct fetch_func *ff, int is_return) | 575 | static int __parse_probe_arg(char *arg, const struct fetch_type *t, |
576 | struct fetch_param *f, int is_return) | ||
492 | { | 577 | { |
493 | int ret = 0; | 578 | int ret = 0; |
494 | unsigned long param; | 579 | unsigned long param; |
@@ -497,13 +582,13 @@ static int __parse_probe_arg(char *arg, struct fetch_func *ff, int is_return) | |||
497 | 582 | ||
498 | switch (arg[0]) { | 583 | switch (arg[0]) { |
499 | case '$': | 584 | case '$': |
500 | ret = parse_probe_vars(arg + 1, ff, is_return); | 585 | ret = parse_probe_vars(arg + 1, t, f, is_return); |
501 | break; | 586 | break; |
502 | case '%': /* named register */ | 587 | case '%': /* named register */ |
503 | ret = regs_query_register_offset(arg + 1); | 588 | ret = regs_query_register_offset(arg + 1); |
504 | if (ret >= 0) { | 589 | if (ret >= 0) { |
505 | ff->func = fetch_register; | 590 | f->fn = t->reg; |
506 | ff->data = (void *)(unsigned long)ret; | 591 | f->data = (void *)(unsigned long)ret; |
507 | ret = 0; | 592 | ret = 0; |
508 | } | 593 | } |
509 | break; | 594 | break; |
@@ -512,26 +597,22 @@ static int __parse_probe_arg(char *arg, struct fetch_func *ff, int is_return) | |||
512 | ret = strict_strtoul(arg + 1, 0, ¶m); | 597 | ret = strict_strtoul(arg + 1, 0, ¶m); |
513 | if (ret) | 598 | if (ret) |
514 | break; | 599 | break; |
515 | ff->func = fetch_memory; | 600 | f->fn = t->memory; |
516 | ff->data = (void *)param; | 601 | f->data = (void *)param; |
517 | } else { | 602 | } else { |
518 | ret = split_symbol_offset(arg + 1, &offset); | 603 | ret = split_symbol_offset(arg + 1, &offset); |
519 | if (ret) | 604 | if (ret) |
520 | break; | 605 | break; |
521 | ff->data = alloc_symbol_cache(arg + 1, offset); | 606 | f->data = alloc_symbol_cache(arg + 1, offset); |
522 | if (ff->data) | 607 | if (f->data) |
523 | ff->func = fetch_symbol; | 608 | f->fn = t->symbol; |
524 | else | ||
525 | ret = -EINVAL; | ||
526 | } | 609 | } |
527 | break; | 610 | break; |
528 | case '+': /* indirect memory */ | 611 | case '+': /* deref memory */ |
529 | case '-': | 612 | case '-': |
530 | tmp = strchr(arg, '('); | 613 | tmp = strchr(arg, '('); |
531 | if (!tmp) { | 614 | if (!tmp) |
532 | ret = -EINVAL; | ||
533 | break; | 615 | break; |
534 | } | ||
535 | *tmp = '\0'; | 616 | *tmp = '\0'; |
536 | ret = strict_strtol(arg + 1, 0, &offset); | 617 | ret = strict_strtol(arg + 1, 0, &offset); |
537 | if (ret) | 618 | if (ret) |
@@ -541,38 +622,58 @@ static int __parse_probe_arg(char *arg, struct fetch_func *ff, int is_return) | |||
541 | arg = tmp + 1; | 622 | arg = tmp + 1; |
542 | tmp = strrchr(arg, ')'); | 623 | tmp = strrchr(arg, ')'); |
543 | if (tmp) { | 624 | if (tmp) { |
544 | struct indirect_fetch_data *id; | 625 | struct deref_fetch_param *dprm; |
626 | const struct fetch_type *t2 = find_fetch_type(NULL); | ||
545 | *tmp = '\0'; | 627 | *tmp = '\0'; |
546 | id = kzalloc(sizeof(struct indirect_fetch_data), | 628 | dprm = kzalloc(sizeof(struct deref_fetch_param), |
547 | GFP_KERNEL); | 629 | GFP_KERNEL); |
548 | if (!id) | 630 | if (!dprm) |
549 | return -ENOMEM; | 631 | return -ENOMEM; |
550 | id->offset = offset; | 632 | dprm->offset = offset; |
551 | ret = __parse_probe_arg(arg, &id->orig, is_return); | 633 | ret = __parse_probe_arg(arg, t2, &dprm->orig, |
634 | is_return); | ||
552 | if (ret) | 635 | if (ret) |
553 | kfree(id); | 636 | kfree(dprm); |
554 | else { | 637 | else { |
555 | ff->func = fetch_indirect; | 638 | f->fn = t->deref; |
556 | ff->data = (void *)id; | 639 | f->data = (void *)dprm; |
557 | } | 640 | } |
558 | } else | 641 | } |
559 | ret = -EINVAL; | ||
560 | break; | 642 | break; |
561 | default: | ||
562 | /* TODO: support custom handler */ | ||
563 | ret = -EINVAL; | ||
564 | } | 643 | } |
644 | if (!ret && !f->fn) | ||
645 | ret = -EINVAL; | ||
565 | return ret; | 646 | return ret; |
566 | } | 647 | } |
567 | 648 | ||
568 | /* String length checking wrapper */ | 649 | /* String length checking wrapper */ |
569 | static int parse_probe_arg(char *arg, struct fetch_func *ff, int is_return) | 650 | static int parse_probe_arg(char *arg, struct trace_probe *tp, |
651 | struct probe_arg *parg, int is_return) | ||
570 | { | 652 | { |
653 | const char *t; | ||
654 | |||
571 | if (strlen(arg) > MAX_ARGSTR_LEN) { | 655 | if (strlen(arg) > MAX_ARGSTR_LEN) { |
572 | pr_info("Argument is too long.: %s\n", arg); | 656 | pr_info("Argument is too long.: %s\n", arg); |
573 | return -ENOSPC; | 657 | return -ENOSPC; |
574 | } | 658 | } |
575 | return __parse_probe_arg(arg, ff, is_return); | 659 | parg->comm = kstrdup(arg, GFP_KERNEL); |
660 | if (!parg->comm) { | ||
661 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | ||
662 | return -ENOMEM; | ||
663 | } | ||
664 | t = strchr(parg->comm, ':'); | ||
665 | if (t) { | ||
666 | arg[t - parg->comm] = '\0'; | ||
667 | t++; | ||
668 | } | ||
669 | parg->type = find_fetch_type(t); | ||
670 | if (!parg->type) { | ||
671 | pr_info("Unsupported type: %s\n", t); | ||
672 | return -EINVAL; | ||
673 | } | ||
674 | parg->offset = tp->size; | ||
675 | tp->size += parg->type->size; | ||
676 | return __parse_probe_arg(arg, parg->type, &parg->fetch, is_return); | ||
576 | } | 677 | } |
577 | 678 | ||
578 | /* Return 1 if name is reserved or already used by another argument */ | 679 | /* Return 1 if name is reserved or already used by another argument */ |
@@ -602,15 +703,18 @@ static int create_trace_probe(int argc, char **argv) | |||
602 | * @ADDR : fetch memory at ADDR (ADDR should be in kernel) | 703 | * @ADDR : fetch memory at ADDR (ADDR should be in kernel) |
603 | * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol) | 704 | * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol) |
604 | * %REG : fetch register REG | 705 | * %REG : fetch register REG |
605 | * Indirect memory fetch: | 706 | * Dereferencing memory fetch: |
606 | * +|-offs(ARG) : fetch memory at ARG +|- offs address. | 707 | * +|-offs(ARG) : fetch memory at ARG +|- offs address. |
607 | * Alias name of args: | 708 | * Alias name of args: |
608 | * NAME=FETCHARG : set NAME as alias of FETCHARG. | 709 | * NAME=FETCHARG : set NAME as alias of FETCHARG. |
710 | * Type of args: | ||
711 | * FETCHARG:TYPE : use TYPE instead of unsigned long. | ||
609 | */ | 712 | */ |
610 | struct trace_probe *tp; | 713 | struct trace_probe *tp; |
611 | int i, ret = 0; | 714 | int i, ret = 0; |
612 | int is_return = 0, is_delete = 0; | 715 | int is_return = 0, is_delete = 0; |
613 | char *symbol = NULL, *event = NULL, *arg = NULL, *group = NULL; | 716 | char *symbol = NULL, *event = NULL, *group = NULL; |
717 | char *arg, *tmp; | ||
614 | unsigned long offset = 0; | 718 | unsigned long offset = 0; |
615 | void *addr = NULL; | 719 | void *addr = NULL; |
616 | char buf[MAX_EVENT_NAME_LEN]; | 720 | char buf[MAX_EVENT_NAME_LEN]; |
@@ -723,13 +827,6 @@ static int create_trace_probe(int argc, char **argv) | |||
723 | else | 827 | else |
724 | arg = argv[i]; | 828 | arg = argv[i]; |
725 | 829 | ||
726 | if (conflict_field_name(argv[i], tp->args, i)) { | ||
727 | pr_info("Argument%d name '%s' conflicts with " | ||
728 | "another field.\n", i, argv[i]); | ||
729 | ret = -EINVAL; | ||
730 | goto error; | ||
731 | } | ||
732 | |||
733 | tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); | 830 | tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); |
734 | if (!tp->args[i].name) { | 831 | if (!tp->args[i].name) { |
735 | pr_info("Failed to allocate argument%d name '%s'.\n", | 832 | pr_info("Failed to allocate argument%d name '%s'.\n", |
@@ -737,9 +834,19 @@ static int create_trace_probe(int argc, char **argv) | |||
737 | ret = -ENOMEM; | 834 | ret = -ENOMEM; |
738 | goto error; | 835 | goto error; |
739 | } | 836 | } |
837 | tmp = strchr(tp->args[i].name, ':'); | ||
838 | if (tmp) | ||
839 | *tmp = '_'; /* convert : to _ */ | ||
840 | |||
841 | if (conflict_field_name(tp->args[i].name, tp->args, i)) { | ||
842 | pr_info("Argument%d name '%s' conflicts with " | ||
843 | "another field.\n", i, argv[i]); | ||
844 | ret = -EINVAL; | ||
845 | goto error; | ||
846 | } | ||
740 | 847 | ||
741 | /* Parse fetch argument */ | 848 | /* Parse fetch argument */ |
742 | ret = parse_probe_arg(arg, &tp->args[i].fetch, is_return); | 849 | ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); |
743 | if (ret) { | 850 | if (ret) { |
744 | pr_info("Parse error at argument%d. (%d)\n", i, ret); | 851 | pr_info("Parse error at argument%d. (%d)\n", i, ret); |
745 | kfree(tp->args[i].name); | 852 | kfree(tp->args[i].name); |
@@ -794,8 +901,7 @@ static void probes_seq_stop(struct seq_file *m, void *v) | |||
794 | static int probes_seq_show(struct seq_file *m, void *v) | 901 | static int probes_seq_show(struct seq_file *m, void *v) |
795 | { | 902 | { |
796 | struct trace_probe *tp = v; | 903 | struct trace_probe *tp = v; |
797 | int i, ret; | 904 | int i; |
798 | char buf[MAX_ARGSTR_LEN + 1]; | ||
799 | 905 | ||
800 | seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p'); | 906 | seq_printf(m, "%c", probe_is_return(tp) ? 'r' : 'p'); |
801 | seq_printf(m, ":%s/%s", tp->call.system, tp->call.name); | 907 | seq_printf(m, ":%s/%s", tp->call.system, tp->call.name); |
@@ -807,15 +913,10 @@ static int probes_seq_show(struct seq_file *m, void *v) | |||
807 | else | 913 | else |
808 | seq_printf(m, " %s", probe_symbol(tp)); | 914 | seq_printf(m, " %s", probe_symbol(tp)); |
809 | 915 | ||
810 | for (i = 0; i < tp->nr_args; i++) { | 916 | for (i = 0; i < tp->nr_args; i++) |
811 | ret = probe_arg_string(buf, MAX_ARGSTR_LEN, &tp->args[i].fetch); | 917 | seq_printf(m, " %s=%s", tp->args[i].name, tp->args[i].comm); |
812 | if (ret < 0) { | ||
813 | pr_warning("Argument%d decoding error(%d).\n", i, ret); | ||
814 | return ret; | ||
815 | } | ||
816 | seq_printf(m, " %s=%s", tp->args[i].name, buf); | ||
817 | } | ||
818 | seq_printf(m, "\n"); | 918 | seq_printf(m, "\n"); |
919 | |||
819 | return 0; | 920 | return 0; |
820 | } | 921 | } |
821 | 922 | ||
@@ -945,9 +1046,10 @@ static const struct file_operations kprobe_profile_ops = { | |||
945 | static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) | 1046 | static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) |
946 | { | 1047 | { |
947 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); | 1048 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); |
948 | struct kprobe_trace_entry *entry; | 1049 | struct kprobe_trace_entry_head *entry; |
949 | struct ring_buffer_event *event; | 1050 | struct ring_buffer_event *event; |
950 | struct ring_buffer *buffer; | 1051 | struct ring_buffer *buffer; |
1052 | u8 *data; | ||
951 | int size, i, pc; | 1053 | int size, i, pc; |
952 | unsigned long irq_flags; | 1054 | unsigned long irq_flags; |
953 | struct ftrace_event_call *call = &tp->call; | 1055 | struct ftrace_event_call *call = &tp->call; |
@@ -957,7 +1059,7 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) | |||
957 | local_save_flags(irq_flags); | 1059 | local_save_flags(irq_flags); |
958 | pc = preempt_count(); | 1060 | pc = preempt_count(); |
959 | 1061 | ||
960 | size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); | 1062 | size = sizeof(*entry) + tp->size; |
961 | 1063 | ||
962 | event = trace_current_buffer_lock_reserve(&buffer, call->id, size, | 1064 | event = trace_current_buffer_lock_reserve(&buffer, call->id, size, |
963 | irq_flags, pc); | 1065 | irq_flags, pc); |
@@ -965,10 +1067,10 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs) | |||
965 | return; | 1067 | return; |
966 | 1068 | ||
967 | entry = ring_buffer_event_data(event); | 1069 | entry = ring_buffer_event_data(event); |
968 | entry->nargs = tp->nr_args; | ||
969 | entry->ip = (unsigned long)kp->addr; | 1070 | entry->ip = (unsigned long)kp->addr; |
1071 | data = (u8 *)&entry[1]; | ||
970 | for (i = 0; i < tp->nr_args; i++) | 1072 | for (i = 0; i < tp->nr_args; i++) |
971 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1073 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
972 | 1074 | ||
973 | if (!filter_current_check_discard(buffer, call, entry, event)) | 1075 | if (!filter_current_check_discard(buffer, call, entry, event)) |
974 | trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); | 1076 | trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); |
@@ -979,9 +1081,10 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, | |||
979 | struct pt_regs *regs) | 1081 | struct pt_regs *regs) |
980 | { | 1082 | { |
981 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | 1083 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); |
982 | struct kretprobe_trace_entry *entry; | 1084 | struct kretprobe_trace_entry_head *entry; |
983 | struct ring_buffer_event *event; | 1085 | struct ring_buffer_event *event; |
984 | struct ring_buffer *buffer; | 1086 | struct ring_buffer *buffer; |
1087 | u8 *data; | ||
985 | int size, i, pc; | 1088 | int size, i, pc; |
986 | unsigned long irq_flags; | 1089 | unsigned long irq_flags; |
987 | struct ftrace_event_call *call = &tp->call; | 1090 | struct ftrace_event_call *call = &tp->call; |
@@ -989,7 +1092,7 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, | |||
989 | local_save_flags(irq_flags); | 1092 | local_save_flags(irq_flags); |
990 | pc = preempt_count(); | 1093 | pc = preempt_count(); |
991 | 1094 | ||
992 | size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); | 1095 | size = sizeof(*entry) + tp->size; |
993 | 1096 | ||
994 | event = trace_current_buffer_lock_reserve(&buffer, call->id, size, | 1097 | event = trace_current_buffer_lock_reserve(&buffer, call->id, size, |
995 | irq_flags, pc); | 1098 | irq_flags, pc); |
@@ -997,11 +1100,11 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, | |||
997 | return; | 1100 | return; |
998 | 1101 | ||
999 | entry = ring_buffer_event_data(event); | 1102 | entry = ring_buffer_event_data(event); |
1000 | entry->nargs = tp->nr_args; | ||
1001 | entry->func = (unsigned long)tp->rp.kp.addr; | 1103 | entry->func = (unsigned long)tp->rp.kp.addr; |
1002 | entry->ret_ip = (unsigned long)ri->ret_addr; | 1104 | entry->ret_ip = (unsigned long)ri->ret_addr; |
1105 | data = (u8 *)&entry[1]; | ||
1003 | for (i = 0; i < tp->nr_args; i++) | 1106 | for (i = 0; i < tp->nr_args; i++) |
1004 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1107 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
1005 | 1108 | ||
1006 | if (!filter_current_check_discard(buffer, call, entry, event)) | 1109 | if (!filter_current_check_discard(buffer, call, entry, event)) |
1007 | trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); | 1110 | trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); |
@@ -1011,13 +1114,14 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, | |||
1011 | enum print_line_t | 1114 | enum print_line_t |
1012 | print_kprobe_event(struct trace_iterator *iter, int flags) | 1115 | print_kprobe_event(struct trace_iterator *iter, int flags) |
1013 | { | 1116 | { |
1014 | struct kprobe_trace_entry *field; | 1117 | struct kprobe_trace_entry_head *field; |
1015 | struct trace_seq *s = &iter->seq; | 1118 | struct trace_seq *s = &iter->seq; |
1016 | struct trace_event *event; | 1119 | struct trace_event *event; |
1017 | struct trace_probe *tp; | 1120 | struct trace_probe *tp; |
1121 | u8 *data; | ||
1018 | int i; | 1122 | int i; |
1019 | 1123 | ||
1020 | field = (struct kprobe_trace_entry *)iter->ent; | 1124 | field = (struct kprobe_trace_entry_head *)iter->ent; |
1021 | event = ftrace_find_event(field->ent.type); | 1125 | event = ftrace_find_event(field->ent.type); |
1022 | tp = container_of(event, struct trace_probe, event); | 1126 | tp = container_of(event, struct trace_probe, event); |
1023 | 1127 | ||
@@ -1030,9 +1134,10 @@ print_kprobe_event(struct trace_iterator *iter, int flags) | |||
1030 | if (!trace_seq_puts(s, ")")) | 1134 | if (!trace_seq_puts(s, ")")) |
1031 | goto partial; | 1135 | goto partial; |
1032 | 1136 | ||
1033 | for (i = 0; i < field->nargs; i++) | 1137 | data = (u8 *)&field[1]; |
1034 | if (!trace_seq_printf(s, " %s=%lx", | 1138 | for (i = 0; i < tp->nr_args; i++) |
1035 | tp->args[i].name, field->args[i])) | 1139 | if (!tp->args[i].type->print(s, tp->args[i].name, |
1140 | data + tp->args[i].offset)) | ||
1036 | goto partial; | 1141 | goto partial; |
1037 | 1142 | ||
1038 | if (!trace_seq_puts(s, "\n")) | 1143 | if (!trace_seq_puts(s, "\n")) |
@@ -1046,13 +1151,14 @@ partial: | |||
1046 | enum print_line_t | 1151 | enum print_line_t |
1047 | print_kretprobe_event(struct trace_iterator *iter, int flags) | 1152 | print_kretprobe_event(struct trace_iterator *iter, int flags) |
1048 | { | 1153 | { |
1049 | struct kretprobe_trace_entry *field; | 1154 | struct kretprobe_trace_entry_head *field; |
1050 | struct trace_seq *s = &iter->seq; | 1155 | struct trace_seq *s = &iter->seq; |
1051 | struct trace_event *event; | 1156 | struct trace_event *event; |
1052 | struct trace_probe *tp; | 1157 | struct trace_probe *tp; |
1158 | u8 *data; | ||
1053 | int i; | 1159 | int i; |
1054 | 1160 | ||
1055 | field = (struct kretprobe_trace_entry *)iter->ent; | 1161 | field = (struct kretprobe_trace_entry_head *)iter->ent; |
1056 | event = ftrace_find_event(field->ent.type); | 1162 | event = ftrace_find_event(field->ent.type); |
1057 | tp = container_of(event, struct trace_probe, event); | 1163 | tp = container_of(event, struct trace_probe, event); |
1058 | 1164 | ||
@@ -1071,9 +1177,10 @@ print_kretprobe_event(struct trace_iterator *iter, int flags) | |||
1071 | if (!trace_seq_puts(s, ")")) | 1177 | if (!trace_seq_puts(s, ")")) |
1072 | goto partial; | 1178 | goto partial; |
1073 | 1179 | ||
1074 | for (i = 0; i < field->nargs; i++) | 1180 | data = (u8 *)&field[1]; |
1075 | if (!trace_seq_printf(s, " %s=%lx", | 1181 | for (i = 0; i < tp->nr_args; i++) |
1076 | tp->args[i].name, field->args[i])) | 1182 | if (!tp->args[i].type->print(s, tp->args[i].name, |
1183 | data + tp->args[i].offset)) | ||
1077 | goto partial; | 1184 | goto partial; |
1078 | 1185 | ||
1079 | if (!trace_seq_puts(s, "\n")) | 1186 | if (!trace_seq_puts(s, "\n")) |
@@ -1129,29 +1236,43 @@ static int probe_event_raw_init(struct ftrace_event_call *event_call) | |||
1129 | static int kprobe_event_define_fields(struct ftrace_event_call *event_call) | 1236 | static int kprobe_event_define_fields(struct ftrace_event_call *event_call) |
1130 | { | 1237 | { |
1131 | int ret, i; | 1238 | int ret, i; |
1132 | struct kprobe_trace_entry field; | 1239 | struct kprobe_trace_entry_head field; |
1133 | struct trace_probe *tp = (struct trace_probe *)event_call->data; | 1240 | struct trace_probe *tp = (struct trace_probe *)event_call->data; |
1134 | 1241 | ||
1135 | DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); | 1242 | DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); |
1136 | DEFINE_FIELD(int, nargs, FIELD_STRING_NARGS, 1); | ||
1137 | /* Set argument names as fields */ | 1243 | /* Set argument names as fields */ |
1138 | for (i = 0; i < tp->nr_args; i++) | 1244 | for (i = 0; i < tp->nr_args; i++) { |
1139 | DEFINE_FIELD(unsigned long, args[i], tp->args[i].name, 0); | 1245 | ret = trace_define_field(event_call, tp->args[i].type->name, |
1246 | tp->args[i].name, | ||
1247 | sizeof(field) + tp->args[i].offset, | ||
1248 | tp->args[i].type->size, | ||
1249 | tp->args[i].type->is_signed, | ||
1250 | FILTER_OTHER); | ||
1251 | if (ret) | ||
1252 | return ret; | ||
1253 | } | ||
1140 | return 0; | 1254 | return 0; |
1141 | } | 1255 | } |
1142 | 1256 | ||
1143 | static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) | 1257 | static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) |
1144 | { | 1258 | { |
1145 | int ret, i; | 1259 | int ret, i; |
1146 | struct kretprobe_trace_entry field; | 1260 | struct kretprobe_trace_entry_head field; |
1147 | struct trace_probe *tp = (struct trace_probe *)event_call->data; | 1261 | struct trace_probe *tp = (struct trace_probe *)event_call->data; |
1148 | 1262 | ||
1149 | DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); | 1263 | DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); |
1150 | DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0); | 1264 | DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0); |
1151 | DEFINE_FIELD(int, nargs, FIELD_STRING_NARGS, 1); | ||
1152 | /* Set argument names as fields */ | 1265 | /* Set argument names as fields */ |
1153 | for (i = 0; i < tp->nr_args; i++) | 1266 | for (i = 0; i < tp->nr_args; i++) { |
1154 | DEFINE_FIELD(unsigned long, args[i], tp->args[i].name, 0); | 1267 | ret = trace_define_field(event_call, tp->args[i].type->name, |
1268 | tp->args[i].name, | ||
1269 | sizeof(field) + tp->args[i].offset, | ||
1270 | tp->args[i].type->size, | ||
1271 | tp->args[i].type->is_signed, | ||
1272 | FILTER_OTHER); | ||
1273 | if (ret) | ||
1274 | return ret; | ||
1275 | } | ||
1155 | return 0; | 1276 | return 0; |
1156 | } | 1277 | } |
1157 | 1278 | ||
@@ -1176,8 +1297,8 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len) | |||
1176 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); | 1297 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
1177 | 1298 | ||
1178 | for (i = 0; i < tp->nr_args; i++) { | 1299 | for (i = 0; i < tp->nr_args; i++) { |
1179 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%%lx", | 1300 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", |
1180 | tp->args[i].name); | 1301 | tp->args[i].name, tp->args[i].type->fmt); |
1181 | } | 1302 | } |
1182 | 1303 | ||
1183 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | 1304 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); |
@@ -1219,12 +1340,13 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, | |||
1219 | { | 1340 | { |
1220 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); | 1341 | struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp); |
1221 | struct ftrace_event_call *call = &tp->call; | 1342 | struct ftrace_event_call *call = &tp->call; |
1222 | struct kprobe_trace_entry *entry; | 1343 | struct kprobe_trace_entry_head *entry; |
1344 | u8 *data; | ||
1223 | int size, __size, i; | 1345 | int size, __size, i; |
1224 | unsigned long irq_flags; | 1346 | unsigned long irq_flags; |
1225 | int rctx; | 1347 | int rctx; |
1226 | 1348 | ||
1227 | __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args); | 1349 | __size = sizeof(*entry) + tp->size; |
1228 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 1350 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
1229 | size -= sizeof(u32); | 1351 | size -= sizeof(u32); |
1230 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, | 1352 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, |
@@ -1235,10 +1357,10 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp, | |||
1235 | if (!entry) | 1357 | if (!entry) |
1236 | return; | 1358 | return; |
1237 | 1359 | ||
1238 | entry->nargs = tp->nr_args; | ||
1239 | entry->ip = (unsigned long)kp->addr; | 1360 | entry->ip = (unsigned long)kp->addr; |
1361 | data = (u8 *)&entry[1]; | ||
1240 | for (i = 0; i < tp->nr_args; i++) | 1362 | for (i = 0; i < tp->nr_args; i++) |
1241 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1363 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
1242 | 1364 | ||
1243 | perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs); | 1365 | perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags, regs); |
1244 | } | 1366 | } |
@@ -1249,12 +1371,13 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, | |||
1249 | { | 1371 | { |
1250 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); | 1372 | struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); |
1251 | struct ftrace_event_call *call = &tp->call; | 1373 | struct ftrace_event_call *call = &tp->call; |
1252 | struct kretprobe_trace_entry *entry; | 1374 | struct kretprobe_trace_entry_head *entry; |
1375 | u8 *data; | ||
1253 | int size, __size, i; | 1376 | int size, __size, i; |
1254 | unsigned long irq_flags; | 1377 | unsigned long irq_flags; |
1255 | int rctx; | 1378 | int rctx; |
1256 | 1379 | ||
1257 | __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); | 1380 | __size = sizeof(*entry) + tp->size; |
1258 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 1381 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
1259 | size -= sizeof(u32); | 1382 | size -= sizeof(u32); |
1260 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, | 1383 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, |
@@ -1265,11 +1388,11 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri, | |||
1265 | if (!entry) | 1388 | if (!entry) |
1266 | return; | 1389 | return; |
1267 | 1390 | ||
1268 | entry->nargs = tp->nr_args; | ||
1269 | entry->func = (unsigned long)tp->rp.kp.addr; | 1391 | entry->func = (unsigned long)tp->rp.kp.addr; |
1270 | entry->ret_ip = (unsigned long)ri->ret_addr; | 1392 | entry->ret_ip = (unsigned long)ri->ret_addr; |
1393 | data = (u8 *)&entry[1]; | ||
1271 | for (i = 0; i < tp->nr_args; i++) | 1394 | for (i = 0; i < tp->nr_args; i++) |
1272 | entry->args[i] = call_fetch(&tp->args[i].fetch, regs); | 1395 | call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset); |
1273 | 1396 | ||
1274 | perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, | 1397 | perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, |
1275 | irq_flags, regs); | 1398 | irq_flags, regs); |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index bb671b346774..63c25d304880 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -79,7 +79,16 @@ Probe points are defined by following syntax. | |||
79 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. | 79 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. |
80 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. | 80 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. |
81 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. | 81 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. |
82 | 'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). | 82 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). |
83 | |||
84 | PROBE ARGUMENT | ||
85 | -------------- | ||
86 | Each probe argument follows below syntax. | ||
87 | |||
88 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] | ||
89 | |||
90 | 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) | ||
91 | 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. | ||
83 | 92 | ||
84 | LINE SYNTAX | 93 | LINE SYNTAX |
85 | ----------- | 94 | ----------- |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index bfc47fff9c59..c1e54035e8cf 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include "util/debug.h" | 40 | #include "util/debug.h" |
41 | #include "util/debugfs.h" | 41 | #include "util/debugfs.h" |
42 | #include "util/parse-options.h" | 42 | #include "util/parse-options.h" |
43 | #include "util/parse-events.h" /* For debugfs_path */ | ||
44 | #include "util/probe-finder.h" | 43 | #include "util/probe-finder.h" |
45 | #include "util/probe-event.h" | 44 | #include "util/probe-event.h" |
46 | 45 | ||
@@ -59,23 +58,25 @@ static struct { | |||
59 | 58 | ||
60 | 59 | ||
61 | /* Parse an event definition. Note that any error must die. */ | 60 | /* Parse an event definition. Note that any error must die. */ |
62 | static void parse_probe_event(const char *str) | 61 | static int parse_probe_event(const char *str) |
63 | { | 62 | { |
64 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; | 63 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; |
64 | int ret; | ||
65 | 65 | ||
66 | pr_debug("probe-definition(%d): %s\n", params.nevents, str); | 66 | pr_debug("probe-definition(%d): %s\n", params.nevents, str); |
67 | if (++params.nevents == MAX_PROBES) | 67 | if (++params.nevents == MAX_PROBES) |
68 | die("Too many probes (> %d) are specified.", MAX_PROBES); | 68 | die("Too many probes (> %d) are specified.", MAX_PROBES); |
69 | 69 | ||
70 | /* Parse a perf-probe command into event */ | 70 | /* Parse a perf-probe command into event */ |
71 | parse_perf_probe_command(str, pev); | 71 | ret = parse_perf_probe_command(str, pev); |
72 | |||
73 | pr_debug("%d arguments\n", pev->nargs); | 72 | pr_debug("%d arguments\n", pev->nargs); |
73 | |||
74 | return ret; | ||
74 | } | 75 | } |
75 | 76 | ||
76 | static void parse_probe_event_argv(int argc, const char **argv) | 77 | static int parse_probe_event_argv(int argc, const char **argv) |
77 | { | 78 | { |
78 | int i, len; | 79 | int i, len, ret; |
79 | char *buf; | 80 | char *buf; |
80 | 81 | ||
81 | /* Bind up rest arguments */ | 82 | /* Bind up rest arguments */ |
@@ -86,16 +87,18 @@ static void parse_probe_event_argv(int argc, const char **argv) | |||
86 | len = 0; | 87 | len = 0; |
87 | for (i = 0; i < argc; i++) | 88 | for (i = 0; i < argc; i++) |
88 | len += sprintf(&buf[len], "%s ", argv[i]); | 89 | len += sprintf(&buf[len], "%s ", argv[i]); |
89 | parse_probe_event(buf); | 90 | ret = parse_probe_event(buf); |
90 | free(buf); | 91 | free(buf); |
92 | return ret; | ||
91 | } | 93 | } |
92 | 94 | ||
93 | static int opt_add_probe_event(const struct option *opt __used, | 95 | static int opt_add_probe_event(const struct option *opt __used, |
94 | const char *str, int unset __used) | 96 | const char *str, int unset __used) |
95 | { | 97 | { |
96 | if (str) | 98 | if (str) |
97 | parse_probe_event(str); | 99 | return parse_probe_event(str); |
98 | return 0; | 100 | else |
101 | return 0; | ||
99 | } | 102 | } |
100 | 103 | ||
101 | static int opt_del_probe_event(const struct option *opt __used, | 104 | static int opt_del_probe_event(const struct option *opt __used, |
@@ -113,11 +116,14 @@ static int opt_del_probe_event(const struct option *opt __used, | |||
113 | static int opt_show_lines(const struct option *opt __used, | 116 | static int opt_show_lines(const struct option *opt __used, |
114 | const char *str, int unset __used) | 117 | const char *str, int unset __used) |
115 | { | 118 | { |
119 | int ret = 0; | ||
120 | |||
116 | if (str) | 121 | if (str) |
117 | parse_line_range_desc(str, ¶ms.line_range); | 122 | ret = parse_line_range_desc(str, ¶ms.line_range); |
118 | INIT_LIST_HEAD(¶ms.line_range.line_list); | 123 | INIT_LIST_HEAD(¶ms.line_range.line_list); |
119 | params.show_lines = true; | 124 | params.show_lines = true; |
120 | return 0; | 125 | |
126 | return ret; | ||
121 | } | 127 | } |
122 | #endif | 128 | #endif |
123 | 129 | ||
@@ -142,9 +148,9 @@ static const struct option options[] = { | |||
142 | OPT_CALLBACK('a', "add", NULL, | 148 | OPT_CALLBACK('a', "add", NULL, |
143 | #ifdef DWARF_SUPPORT | 149 | #ifdef DWARF_SUPPORT |
144 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" | 150 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" |
145 | " [ARG ...]", | 151 | " [[NAME=]ARG ...]", |
146 | #else | 152 | #else |
147 | "[EVENT=]FUNC[+OFF|%return] [ARG ...]", | 153 | "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", |
148 | #endif | 154 | #endif |
149 | "probe point definition, where\n" | 155 | "probe point definition, where\n" |
150 | "\t\tGROUP:\tGroup name (optional)\n" | 156 | "\t\tGROUP:\tGroup name (optional)\n" |
@@ -178,6 +184,8 @@ static const struct option options[] = { | |||
178 | 184 | ||
179 | int cmd_probe(int argc, const char **argv, const char *prefix __used) | 185 | int cmd_probe(int argc, const char **argv, const char *prefix __used) |
180 | { | 186 | { |
187 | int ret; | ||
188 | |||
181 | argc = parse_options(argc, argv, options, probe_usage, | 189 | argc = parse_options(argc, argv, options, probe_usage, |
182 | PARSE_OPT_STOP_AT_NON_OPTION); | 190 | PARSE_OPT_STOP_AT_NON_OPTION); |
183 | if (argc > 0) { | 191 | if (argc > 0) { |
@@ -185,28 +193,31 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
185 | pr_warning(" Error: '-' is not supported.\n"); | 193 | pr_warning(" Error: '-' is not supported.\n"); |
186 | usage_with_options(probe_usage, options); | 194 | usage_with_options(probe_usage, options); |
187 | } | 195 | } |
188 | parse_probe_event_argv(argc, argv); | 196 | ret = parse_probe_event_argv(argc, argv); |
197 | if (ret < 0) { | ||
198 | pr_err(" Error: Parse Error. (%d)\n", ret); | ||
199 | return ret; | ||
200 | } | ||
189 | } | 201 | } |
190 | 202 | ||
191 | if ((!params.nevents && !params.dellist && !params.list_events && | 203 | if ((!params.nevents && !params.dellist && !params.list_events && |
192 | !params.show_lines)) | 204 | !params.show_lines)) |
193 | usage_with_options(probe_usage, options); | 205 | usage_with_options(probe_usage, options); |
194 | 206 | ||
195 | if (debugfs_valid_mountpoint(debugfs_path) < 0) | ||
196 | die("Failed to find debugfs path."); | ||
197 | |||
198 | if (params.list_events) { | 207 | if (params.list_events) { |
199 | if (params.nevents != 0 || params.dellist) { | 208 | if (params.nevents != 0 || params.dellist) { |
200 | pr_warning(" Error: Don't use --list with" | 209 | pr_err(" Error: Don't use --list with --add/--del.\n"); |
201 | " --add/--del.\n"); | ||
202 | usage_with_options(probe_usage, options); | 210 | usage_with_options(probe_usage, options); |
203 | } | 211 | } |
204 | if (params.show_lines) { | 212 | if (params.show_lines) { |
205 | pr_warning(" Error: Don't use --list with --line.\n"); | 213 | pr_err(" Error: Don't use --list with --line.\n"); |
206 | usage_with_options(probe_usage, options); | 214 | usage_with_options(probe_usage, options); |
207 | } | 215 | } |
208 | show_perf_probe_events(); | 216 | ret = show_perf_probe_events(); |
209 | return 0; | 217 | if (ret < 0) |
218 | pr_err(" Error: Failed to show event list. (%d)\n", | ||
219 | ret); | ||
220 | return ret; | ||
210 | } | 221 | } |
211 | 222 | ||
212 | #ifdef DWARF_SUPPORT | 223 | #ifdef DWARF_SUPPORT |
@@ -217,19 +228,30 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
217 | usage_with_options(probe_usage, options); | 228 | usage_with_options(probe_usage, options); |
218 | } | 229 | } |
219 | 230 | ||
220 | show_line_range(¶ms.line_range); | 231 | ret = show_line_range(¶ms.line_range); |
221 | return 0; | 232 | if (ret < 0) |
233 | pr_err(" Error: Failed to show lines. (%d)\n", ret); | ||
234 | return ret; | ||
222 | } | 235 | } |
223 | #endif | 236 | #endif |
224 | 237 | ||
225 | if (params.dellist) { | 238 | if (params.dellist) { |
226 | del_perf_probe_events(params.dellist); | 239 | ret = del_perf_probe_events(params.dellist); |
227 | strlist__delete(params.dellist); | 240 | strlist__delete(params.dellist); |
228 | if (params.nevents == 0) | 241 | if (ret < 0) { |
229 | return 0; | 242 | pr_err(" Error: Failed to delete events. (%d)\n", ret); |
243 | return ret; | ||
244 | } | ||
230 | } | 245 | } |
231 | 246 | ||
232 | add_perf_probe_events(params.events, params.nevents, params.force_add); | 247 | if (params.nevents) { |
248 | ret = add_perf_probe_events(params.events, params.nevents, | ||
249 | params.force_add); | ||
250 | if (ret < 0) { | ||
251 | pr_err(" Error: Failed to add events. (%d)\n", ret); | ||
252 | return ret; | ||
253 | } | ||
254 | } | ||
233 | return 0; | 255 | return 0; |
234 | } | 256 | } |
235 | 257 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 18cf8b321608..9c2b8743cef6 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -68,7 +68,7 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) | |||
68 | int64_t cmp = 0; | 68 | int64_t cmp = 0; |
69 | 69 | ||
70 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 70 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
71 | cmp = se->cmp(left, right); | 71 | cmp = se->se_cmp(left, right); |
72 | if (cmp) | 72 | if (cmp) |
73 | break; | 73 | break; |
74 | } | 74 | } |
@@ -85,7 +85,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
85 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 85 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
86 | int64_t (*f)(struct hist_entry *, struct hist_entry *); | 86 | int64_t (*f)(struct hist_entry *, struct hist_entry *); |
87 | 87 | ||
88 | f = se->collapse ?: se->cmp; | 88 | f = se->se_collapse ?: se->se_cmp; |
89 | 89 | ||
90 | cmp = f(left, right); | 90 | cmp = f(left, right); |
91 | if (cmp) | 91 | if (cmp) |
@@ -536,8 +536,8 @@ int hist_entry__snprintf(struct hist_entry *self, | |||
536 | continue; | 536 | continue; |
537 | 537 | ||
538 | ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); | 538 | ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); |
539 | ret += se->snprintf(self, s + ret, size - ret, | 539 | ret += se->se_snprintf(self, s + ret, size - ret, |
540 | se->width ? *se->width : 0); | 540 | se->se_width ? *se->se_width : 0); |
541 | } | 541 | } |
542 | 542 | ||
543 | return ret; | 543 | return ret; |
@@ -564,7 +564,7 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, | |||
564 | if (sort__first_dimension == SORT_COMM) { | 564 | if (sort__first_dimension == SORT_COMM) { |
565 | struct sort_entry *se = list_first_entry(&hist_entry__sort_list, | 565 | struct sort_entry *se = list_first_entry(&hist_entry__sort_list, |
566 | typeof(*se), list); | 566 | typeof(*se), list); |
567 | left_margin = se->width ? *se->width : 0; | 567 | left_margin = se->se_width ? *se->se_width : 0; |
568 | left_margin -= thread__comm_len(self->thread); | 568 | left_margin -= thread__comm_len(self->thread); |
569 | } | 569 | } |
570 | 570 | ||
@@ -615,22 +615,22 @@ size_t perf_session__fprintf_hists(struct rb_root *hists, | |||
615 | if (se->elide) | 615 | if (se->elide) |
616 | continue; | 616 | continue; |
617 | if (sep) { | 617 | if (sep) { |
618 | fprintf(fp, "%c%s", *sep, se->header); | 618 | fprintf(fp, "%c%s", *sep, se->se_header); |
619 | continue; | 619 | continue; |
620 | } | 620 | } |
621 | width = strlen(se->header); | 621 | width = strlen(se->se_header); |
622 | if (se->width) { | 622 | if (se->se_width) { |
623 | if (symbol_conf.col_width_list_str) { | 623 | if (symbol_conf.col_width_list_str) { |
624 | if (col_width) { | 624 | if (col_width) { |
625 | *se->width = atoi(col_width); | 625 | *se->se_width = atoi(col_width); |
626 | col_width = strchr(col_width, ','); | 626 | col_width = strchr(col_width, ','); |
627 | if (col_width) | 627 | if (col_width) |
628 | ++col_width; | 628 | ++col_width; |
629 | } | 629 | } |
630 | } | 630 | } |
631 | width = *se->width = max(*se->width, width); | 631 | width = *se->se_width = max(*se->se_width, width); |
632 | } | 632 | } |
633 | fprintf(fp, " %*s", width, se->header); | 633 | fprintf(fp, " %*s", width, se->se_header); |
634 | } | 634 | } |
635 | fprintf(fp, "\n"); | 635 | fprintf(fp, "\n"); |
636 | 636 | ||
@@ -652,10 +652,10 @@ size_t perf_session__fprintf_hists(struct rb_root *hists, | |||
652 | continue; | 652 | continue; |
653 | 653 | ||
654 | fprintf(fp, " "); | 654 | fprintf(fp, " "); |
655 | if (se->width) | 655 | if (se->se_width) |
656 | width = *se->width; | 656 | width = *se->se_width; |
657 | else | 657 | else |
658 | width = strlen(se->header); | 658 | width = strlen(se->se_header); |
659 | for (i = 0; i < width; i++) | 659 | for (i = 0; i < width; i++) |
660 | fprintf(fp, "."); | 660 | fprintf(fp, "."); |
661 | } | 661 | } |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3fc0be741b8e..5bf8ab034466 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -42,8 +42,8 @@ | |||
42 | #include "color.h" | 42 | #include "color.h" |
43 | #include "symbol.h" | 43 | #include "symbol.h" |
44 | #include "thread.h" | 44 | #include "thread.h" |
45 | #include "debugfs.h" | ||
45 | #include "trace-event.h" /* For __unused */ | 46 | #include "trace-event.h" /* For __unused */ |
46 | #include "parse-events.h" /* For debugfs_path */ | ||
47 | #include "probe-event.h" | 47 | #include "probe-event.h" |
48 | #include "probe-finder.h" | 48 | #include "probe-finder.h" |
49 | 49 | ||
@@ -53,7 +53,7 @@ | |||
53 | 53 | ||
54 | bool probe_event_dry_run; /* Dry run flag */ | 54 | bool probe_event_dry_run; /* Dry run flag */ |
55 | 55 | ||
56 | #define semantic_error(msg ...) die("Semantic error :" msg) | 56 | #define semantic_error(msg ...) pr_err("Semantic error :" msg) |
57 | 57 | ||
58 | /* If there is no space to write, returns -E2BIG. */ | 58 | /* If there is no space to write, returns -E2BIG. */ |
59 | static int e_snprintf(char *str, size_t size, const char *format, ...) | 59 | static int e_snprintf(char *str, size_t size, const char *format, ...) |
@@ -76,19 +76,30 @@ static struct map_groups kmap_groups; | |||
76 | static struct map *kmaps[MAP__NR_TYPES]; | 76 | static struct map *kmaps[MAP__NR_TYPES]; |
77 | 77 | ||
78 | /* Initialize symbol maps and path of vmlinux */ | 78 | /* Initialize symbol maps and path of vmlinux */ |
79 | static void init_vmlinux(void) | 79 | static int init_vmlinux(void) |
80 | { | 80 | { |
81 | int ret; | ||
82 | |||
81 | symbol_conf.sort_by_name = true; | 83 | symbol_conf.sort_by_name = true; |
82 | if (symbol_conf.vmlinux_name == NULL) | 84 | if (symbol_conf.vmlinux_name == NULL) |
83 | symbol_conf.try_vmlinux_path = true; | 85 | symbol_conf.try_vmlinux_path = true; |
84 | else | 86 | else |
85 | pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); | 87 | pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); |
86 | if (symbol__init() < 0) | 88 | ret = symbol__init(); |
87 | die("Failed to init symbol map."); | 89 | if (ret < 0) { |
90 | pr_debug("Failed to init symbol map.\n"); | ||
91 | goto out; | ||
92 | } | ||
88 | 93 | ||
89 | map_groups__init(&kmap_groups); | 94 | map_groups__init(&kmap_groups); |
90 | if (map_groups__create_kernel_maps(&kmap_groups, kmaps) < 0) | 95 | ret = map_groups__create_kernel_maps(&kmap_groups, kmaps); |
91 | die("Failed to create kernel maps."); | 96 | if (ret < 0) |
97 | pr_debug("Failed to create kernel maps.\n"); | ||
98 | |||
99 | out: | ||
100 | if (ret < 0) | ||
101 | pr_warning("Failed to init vmlinux path.\n"); | ||
102 | return ret; | ||
92 | } | 103 | } |
93 | 104 | ||
94 | #ifdef DWARF_SUPPORT | 105 | #ifdef DWARF_SUPPORT |
@@ -102,24 +113,34 @@ static int open_vmlinux(void) | |||
102 | return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY); | 113 | return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY); |
103 | } | 114 | } |
104 | 115 | ||
105 | static void convert_to_perf_probe_point(struct kprobe_trace_point *tp, | 116 | /* Convert trace point to probe point with debuginfo */ |
106 | struct perf_probe_point *pp) | 117 | static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, |
118 | struct perf_probe_point *pp) | ||
107 | { | 119 | { |
108 | struct symbol *sym; | 120 | struct symbol *sym; |
109 | int fd, ret = 0; | 121 | int fd, ret = -ENOENT; |
110 | 122 | ||
111 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], | 123 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], |
112 | tp->symbol, NULL); | 124 | tp->symbol, NULL); |
113 | if (sym) { | 125 | if (sym) { |
114 | fd = open_vmlinux(); | 126 | fd = open_vmlinux(); |
115 | ret = find_perf_probe_point(fd, sym->start + tp->offset, pp); | 127 | if (fd >= 0) { |
116 | close(fd); | 128 | ret = find_perf_probe_point(fd, |
129 | sym->start + tp->offset, pp); | ||
130 | close(fd); | ||
131 | } | ||
117 | } | 132 | } |
118 | if (ret <= 0) { | 133 | if (ret <= 0) { |
119 | pp->function = xstrdup(tp->symbol); | 134 | pr_debug("Failed to find corresponding probes from " |
135 | "debuginfo. Use kprobe event information.\n"); | ||
136 | pp->function = strdup(tp->symbol); | ||
137 | if (pp->function == NULL) | ||
138 | return -ENOMEM; | ||
120 | pp->offset = tp->offset; | 139 | pp->offset = tp->offset; |
121 | } | 140 | } |
122 | pp->retprobe = tp->retprobe; | 141 | pp->retprobe = tp->retprobe; |
142 | |||
143 | return 0; | ||
123 | } | 144 | } |
124 | 145 | ||
125 | /* Try to find perf_probe_event with debuginfo */ | 146 | /* Try to find perf_probe_event with debuginfo */ |
@@ -131,9 +152,10 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, | |||
131 | 152 | ||
132 | fd = open_vmlinux(); | 153 | fd = open_vmlinux(); |
133 | if (fd < 0) { | 154 | if (fd < 0) { |
134 | if (need_dwarf) | 155 | if (need_dwarf) { |
135 | die("Could not open debuginfo file."); | 156 | pr_warning("Failed to open debuginfo file.\n"); |
136 | 157 | return fd; | |
158 | } | ||
137 | pr_debug("Could not open vmlinux. Try to use symbols.\n"); | 159 | pr_debug("Could not open vmlinux. Try to use symbols.\n"); |
138 | return 0; | 160 | return 0; |
139 | } | 161 | } |
@@ -142,30 +164,32 @@ static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, | |||
142 | ntevs = find_kprobe_trace_events(fd, pev, tevs); | 164 | ntevs = find_kprobe_trace_events(fd, pev, tevs); |
143 | close(fd); | 165 | close(fd); |
144 | 166 | ||
145 | if (ntevs > 0) /* Succeeded to find trace events */ | 167 | if (ntevs > 0) { /* Succeeded to find trace events */ |
168 | pr_debug("find %d kprobe_trace_events.\n", ntevs); | ||
146 | return ntevs; | 169 | return ntevs; |
170 | } | ||
147 | 171 | ||
148 | if (ntevs == 0) /* No error but failed to find probe point. */ | 172 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
149 | die("Probe point '%s' not found. - probe not added.", | 173 | pr_warning("Probe point '%s' not found.\n", |
150 | synthesize_perf_probe_point(&pev->point)); | 174 | synthesize_perf_probe_point(&pev->point)); |
151 | 175 | return -ENOENT; | |
152 | /* Error path */ | 176 | } |
177 | /* Error path : ntevs < 0 */ | ||
153 | if (need_dwarf) { | 178 | if (need_dwarf) { |
154 | if (ntevs == -ENOENT) | 179 | if (ntevs == -EBADF) |
155 | pr_warning("No dwarf info found in the vmlinux - " | 180 | pr_warning("No dwarf info found in the vmlinux - " |
156 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | 181 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
157 | die("Could not analyze debuginfo."); | 182 | return ntevs; |
158 | } | 183 | } |
159 | pr_debug("An error occurred in debuginfo analysis." | 184 | pr_debug("An error occurred in debuginfo analysis." |
160 | " Try to use symbols.\n"); | 185 | " Try to use symbols.\n"); |
161 | return 0; | 186 | return 0; |
162 | |||
163 | } | 187 | } |
164 | 188 | ||
165 | #define LINEBUF_SIZE 256 | 189 | #define LINEBUF_SIZE 256 |
166 | #define NR_ADDITIONAL_LINES 2 | 190 | #define NR_ADDITIONAL_LINES 2 |
167 | 191 | ||
168 | static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) | 192 | static int show_one_line(FILE *fp, int l, bool skip, bool show_num) |
169 | { | 193 | { |
170 | char buf[LINEBUF_SIZE]; | 194 | char buf[LINEBUF_SIZE]; |
171 | const char *color = PERF_COLOR_BLUE; | 195 | const char *color = PERF_COLOR_BLUE; |
@@ -174,7 +198,7 @@ static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) | |||
174 | goto error; | 198 | goto error; |
175 | if (!skip) { | 199 | if (!skip) { |
176 | if (show_num) | 200 | if (show_num) |
177 | fprintf(stdout, "%7u %s", l, buf); | 201 | fprintf(stdout, "%7d %s", l, buf); |
178 | else | 202 | else |
179 | color_fprintf(stdout, color, " %s", buf); | 203 | color_fprintf(stdout, color, " %s", buf); |
180 | } | 204 | } |
@@ -190,34 +214,48 @@ static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) | |||
190 | color_fprintf(stdout, color, "%s", buf); | 214 | color_fprintf(stdout, color, "%s", buf); |
191 | } | 215 | } |
192 | } | 216 | } |
193 | return; | 217 | |
218 | return 0; | ||
194 | error: | 219 | error: |
195 | if (feof(fp)) | 220 | if (feof(fp)) |
196 | die("Source file is shorter than expected."); | 221 | pr_warning("Source file is shorter than expected.\n"); |
197 | else | 222 | else |
198 | die("File read error: %s", strerror(errno)); | 223 | pr_warning("File read error: %s\n", strerror(errno)); |
224 | |||
225 | return -1; | ||
199 | } | 226 | } |
200 | 227 | ||
201 | /* | 228 | /* |
202 | * Show line-range always requires debuginfo to find source file and | 229 | * Show line-range always requires debuginfo to find source file and |
203 | * line number. | 230 | * line number. |
204 | */ | 231 | */ |
205 | void show_line_range(struct line_range *lr) | 232 | int show_line_range(struct line_range *lr) |
206 | { | 233 | { |
207 | unsigned int l = 1; | 234 | int l = 1; |
208 | struct line_node *ln; | 235 | struct line_node *ln; |
209 | FILE *fp; | 236 | FILE *fp; |
210 | int fd, ret; | 237 | int fd, ret; |
211 | 238 | ||
212 | /* Search a line range */ | 239 | /* Search a line range */ |
213 | init_vmlinux(); | 240 | ret = init_vmlinux(); |
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | |||
214 | fd = open_vmlinux(); | 244 | fd = open_vmlinux(); |
215 | if (fd < 0) | 245 | if (fd < 0) { |
216 | die("Could not open debuginfo file."); | 246 | pr_warning("Failed to open debuginfo file.\n"); |
247 | return fd; | ||
248 | } | ||
249 | |||
217 | ret = find_line_range(fd, lr); | 250 | ret = find_line_range(fd, lr); |
218 | if (ret <= 0) | ||
219 | die("Source line is not found.\n"); | ||
220 | close(fd); | 251 | close(fd); |
252 | if (ret == 0) { | ||
253 | pr_warning("Specified source line is not found.\n"); | ||
254 | return -ENOENT; | ||
255 | } else if (ret < 0) { | ||
256 | pr_warning("Debuginfo analysis failed. (%d)\n", ret); | ||
257 | return ret; | ||
258 | } | ||
221 | 259 | ||
222 | setup_pager(); | 260 | setup_pager(); |
223 | 261 | ||
@@ -228,52 +266,70 @@ void show_line_range(struct line_range *lr) | |||
228 | fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); | 266 | fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); |
229 | 267 | ||
230 | fp = fopen(lr->path, "r"); | 268 | fp = fopen(lr->path, "r"); |
231 | if (fp == NULL) | 269 | if (fp == NULL) { |
232 | die("Failed to open %s: %s", lr->path, strerror(errno)); | 270 | pr_warning("Failed to open %s: %s\n", lr->path, |
271 | strerror(errno)); | ||
272 | return -errno; | ||
273 | } | ||
233 | /* Skip to starting line number */ | 274 | /* Skip to starting line number */ |
234 | while (l < lr->start) | 275 | while (l < lr->start && ret >= 0) |
235 | show_one_line(fp, l++, true, false); | 276 | ret = show_one_line(fp, l++, true, false); |
277 | if (ret < 0) | ||
278 | goto end; | ||
236 | 279 | ||
237 | list_for_each_entry(ln, &lr->line_list, list) { | 280 | list_for_each_entry(ln, &lr->line_list, list) { |
238 | while (ln->line > l) | 281 | while (ln->line > l && ret >= 0) |
239 | show_one_line(fp, (l++) - lr->offset, false, false); | 282 | ret = show_one_line(fp, (l++) - lr->offset, |
240 | show_one_line(fp, (l++) - lr->offset, false, true); | 283 | false, false); |
284 | if (ret >= 0) | ||
285 | ret = show_one_line(fp, (l++) - lr->offset, | ||
286 | false, true); | ||
287 | if (ret < 0) | ||
288 | goto end; | ||
241 | } | 289 | } |
242 | 290 | ||
243 | if (lr->end == INT_MAX) | 291 | if (lr->end == INT_MAX) |
244 | lr->end = l + NR_ADDITIONAL_LINES; | 292 | lr->end = l + NR_ADDITIONAL_LINES; |
245 | while (l < lr->end && !feof(fp)) | 293 | while (l <= lr->end && !feof(fp) && ret >= 0) |
246 | show_one_line(fp, (l++) - lr->offset, false, false); | 294 | ret = show_one_line(fp, (l++) - lr->offset, false, false); |
247 | 295 | end: | |
248 | fclose(fp); | 296 | fclose(fp); |
297 | return ret; | ||
249 | } | 298 | } |
250 | 299 | ||
251 | #else /* !DWARF_SUPPORT */ | 300 | #else /* !DWARF_SUPPORT */ |
252 | 301 | ||
253 | static void convert_to_perf_probe_point(struct kprobe_trace_point *tp, | 302 | static int convert_to_perf_probe_point(struct kprobe_trace_point *tp, |
254 | struct perf_probe_point *pp) | 303 | struct perf_probe_point *pp) |
255 | { | 304 | { |
256 | pp->function = xstrdup(tp->symbol); | 305 | pp->function = strdup(tp->symbol); |
306 | if (pp->function == NULL) | ||
307 | return -ENOMEM; | ||
257 | pp->offset = tp->offset; | 308 | pp->offset = tp->offset; |
258 | pp->retprobe = tp->retprobe; | 309 | pp->retprobe = tp->retprobe; |
310 | |||
311 | return 0; | ||
259 | } | 312 | } |
260 | 313 | ||
261 | static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, | 314 | static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev, |
262 | struct kprobe_trace_event **tevs __unused) | 315 | struct kprobe_trace_event **tevs __unused) |
263 | { | 316 | { |
264 | if (perf_probe_event_need_dwarf(pev)) | 317 | if (perf_probe_event_need_dwarf(pev)) { |
265 | die("Debuginfo-analysis is not supported"); | 318 | pr_warning("Debuginfo-analysis is not supported.\n"); |
319 | return -ENOSYS; | ||
320 | } | ||
266 | return 0; | 321 | return 0; |
267 | } | 322 | } |
268 | 323 | ||
269 | void show_line_range(struct line_range *lr __unused) | 324 | int show_line_range(struct line_range *lr __unused) |
270 | { | 325 | { |
271 | die("Debuginfo-analysis is not supported"); | 326 | pr_warning("Debuginfo-analysis is not supported.\n"); |
327 | return -ENOSYS; | ||
272 | } | 328 | } |
273 | 329 | ||
274 | #endif | 330 | #endif |
275 | 331 | ||
276 | void parse_line_range_desc(const char *arg, struct line_range *lr) | 332 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
277 | { | 333 | { |
278 | const char *ptr; | 334 | const char *ptr; |
279 | char *tmp; | 335 | char *tmp; |
@@ -284,29 +340,45 @@ void parse_line_range_desc(const char *arg, struct line_range *lr) | |||
284 | */ | 340 | */ |
285 | ptr = strchr(arg, ':'); | 341 | ptr = strchr(arg, ':'); |
286 | if (ptr) { | 342 | if (ptr) { |
287 | lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); | 343 | lr->start = (int)strtoul(ptr + 1, &tmp, 0); |
288 | if (*tmp == '+') | 344 | if (*tmp == '+') { |
289 | lr->end = lr->start + (unsigned int)strtoul(tmp + 1, | 345 | lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); |
290 | &tmp, 0); | 346 | lr->end--; /* |
291 | else if (*tmp == '-') | 347 | * Adjust the number of lines here. |
292 | lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); | 348 | * If the number of lines == 1, the |
349 | * the end of line should be equal to | ||
350 | * the start of line. | ||
351 | */ | ||
352 | } else if (*tmp == '-') | ||
353 | lr->end = (int)strtoul(tmp + 1, &tmp, 0); | ||
293 | else | 354 | else |
294 | lr->end = 0; | 355 | lr->end = INT_MAX; |
295 | pr_debug("Line range is %u to %u\n", lr->start, lr->end); | 356 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); |
296 | if (lr->end && lr->start > lr->end) | 357 | if (lr->start > lr->end) { |
297 | semantic_error("Start line must be smaller" | 358 | semantic_error("Start line must be smaller" |
298 | " than end line."); | 359 | " than end line.\n"); |
299 | if (*tmp != '\0') | 360 | return -EINVAL; |
300 | semantic_error("Tailing with invalid character '%d'.", | 361 | } |
362 | if (*tmp != '\0') { | ||
363 | semantic_error("Tailing with invalid character '%d'.\n", | ||
301 | *tmp); | 364 | *tmp); |
302 | tmp = xstrndup(arg, (ptr - arg)); | 365 | return -EINVAL; |
303 | } else | 366 | } |
304 | tmp = xstrdup(arg); | 367 | tmp = strndup(arg, (ptr - arg)); |
368 | } else { | ||
369 | tmp = strdup(arg); | ||
370 | lr->end = INT_MAX; | ||
371 | } | ||
372 | |||
373 | if (tmp == NULL) | ||
374 | return -ENOMEM; | ||
305 | 375 | ||
306 | if (strchr(tmp, '.')) | 376 | if (strchr(tmp, '.')) |
307 | lr->file = tmp; | 377 | lr->file = tmp; |
308 | else | 378 | else |
309 | lr->function = tmp; | 379 | lr->function = tmp; |
380 | |||
381 | return 0; | ||
310 | } | 382 | } |
311 | 383 | ||
312 | /* Check the name is good for event/group */ | 384 | /* Check the name is good for event/group */ |
@@ -322,7 +394,7 @@ static bool check_event_name(const char *name) | |||
322 | } | 394 | } |
323 | 395 | ||
324 | /* Parse probepoint definition. */ | 396 | /* Parse probepoint definition. */ |
325 | static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | 397 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) |
326 | { | 398 | { |
327 | struct perf_probe_point *pp = &pev->point; | 399 | struct perf_probe_point *pp = &pev->point; |
328 | char *ptr, *tmp; | 400 | char *ptr, *tmp; |
@@ -339,13 +411,18 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
339 | if (ptr && *ptr == '=') { /* Event name */ | 411 | if (ptr && *ptr == '=') { /* Event name */ |
340 | *ptr = '\0'; | 412 | *ptr = '\0'; |
341 | tmp = ptr + 1; | 413 | tmp = ptr + 1; |
342 | ptr = strchr(arg, ':'); | 414 | if (strchr(arg, ':')) { |
343 | if (ptr) /* Group name is not supported yet. */ | 415 | semantic_error("Group name is not supported yet.\n"); |
344 | semantic_error("Group name is not supported yet."); | 416 | return -ENOTSUP; |
345 | if (!check_event_name(arg)) | 417 | } |
418 | if (!check_event_name(arg)) { | ||
346 | semantic_error("%s is bad for event name -it must " | 419 | semantic_error("%s is bad for event name -it must " |
347 | "follow C symbol-naming rule.", arg); | 420 | "follow C symbol-naming rule.\n", arg); |
348 | pev->event = xstrdup(arg); | 421 | return -EINVAL; |
422 | } | ||
423 | pev->event = strdup(arg); | ||
424 | if (pev->event == NULL) | ||
425 | return -ENOMEM; | ||
349 | pev->group = NULL; | 426 | pev->group = NULL; |
350 | arg = tmp; | 427 | arg = tmp; |
351 | } | 428 | } |
@@ -356,18 +433,24 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
356 | *ptr++ = '\0'; | 433 | *ptr++ = '\0'; |
357 | } | 434 | } |
358 | 435 | ||
436 | tmp = strdup(arg); | ||
437 | if (tmp == NULL) | ||
438 | return -ENOMEM; | ||
439 | |||
359 | /* Check arg is function or file and copy it */ | 440 | /* Check arg is function or file and copy it */ |
360 | if (strchr(arg, '.')) /* File */ | 441 | if (strchr(tmp, '.')) /* File */ |
361 | pp->file = xstrdup(arg); | 442 | pp->file = tmp; |
362 | else /* Function */ | 443 | else /* Function */ |
363 | pp->function = xstrdup(arg); | 444 | pp->function = tmp; |
364 | 445 | ||
365 | /* Parse other options */ | 446 | /* Parse other options */ |
366 | while (ptr) { | 447 | while (ptr) { |
367 | arg = ptr; | 448 | arg = ptr; |
368 | c = nc; | 449 | c = nc; |
369 | if (c == ';') { /* Lazy pattern must be the last part */ | 450 | if (c == ';') { /* Lazy pattern must be the last part */ |
370 | pp->lazy_line = xstrdup(arg); | 451 | pp->lazy_line = strdup(arg); |
452 | if (pp->lazy_line == NULL) | ||
453 | return -ENOMEM; | ||
371 | break; | 454 | break; |
372 | } | 455 | } |
373 | ptr = strpbrk(arg, ";:+@%"); | 456 | ptr = strpbrk(arg, ";:+@%"); |
@@ -378,131 +461,211 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
378 | switch (c) { | 461 | switch (c) { |
379 | case ':': /* Line number */ | 462 | case ':': /* Line number */ |
380 | pp->line = strtoul(arg, &tmp, 0); | 463 | pp->line = strtoul(arg, &tmp, 0); |
381 | if (*tmp != '\0') | 464 | if (*tmp != '\0') { |
382 | semantic_error("There is non-digit char" | 465 | semantic_error("There is non-digit char" |
383 | " in line number."); | 466 | " in line number.\n"); |
467 | return -EINVAL; | ||
468 | } | ||
384 | break; | 469 | break; |
385 | case '+': /* Byte offset from a symbol */ | 470 | case '+': /* Byte offset from a symbol */ |
386 | pp->offset = strtoul(arg, &tmp, 0); | 471 | pp->offset = strtoul(arg, &tmp, 0); |
387 | if (*tmp != '\0') | 472 | if (*tmp != '\0') { |
388 | semantic_error("There is non-digit character" | 473 | semantic_error("There is non-digit character" |
389 | " in offset."); | 474 | " in offset.\n"); |
475 | return -EINVAL; | ||
476 | } | ||
390 | break; | 477 | break; |
391 | case '@': /* File name */ | 478 | case '@': /* File name */ |
392 | if (pp->file) | 479 | if (pp->file) { |
393 | semantic_error("SRC@SRC is not allowed."); | 480 | semantic_error("SRC@SRC is not allowed.\n"); |
394 | pp->file = xstrdup(arg); | 481 | return -EINVAL; |
482 | } | ||
483 | pp->file = strdup(arg); | ||
484 | if (pp->file == NULL) | ||
485 | return -ENOMEM; | ||
395 | break; | 486 | break; |
396 | case '%': /* Probe places */ | 487 | case '%': /* Probe places */ |
397 | if (strcmp(arg, "return") == 0) { | 488 | if (strcmp(arg, "return") == 0) { |
398 | pp->retprobe = 1; | 489 | pp->retprobe = 1; |
399 | } else /* Others not supported yet */ | 490 | } else { /* Others not supported yet */ |
400 | semantic_error("%%%s is not supported.", arg); | 491 | semantic_error("%%%s is not supported.\n", arg); |
492 | return -ENOTSUP; | ||
493 | } | ||
401 | break; | 494 | break; |
402 | default: | 495 | default: /* Buggy case */ |
403 | DIE_IF("Program has a bug."); | 496 | pr_err("This program has a bug at %s:%d.\n", |
497 | __FILE__, __LINE__); | ||
498 | return -ENOTSUP; | ||
404 | break; | 499 | break; |
405 | } | 500 | } |
406 | } | 501 | } |
407 | 502 | ||
408 | /* Exclusion check */ | 503 | /* Exclusion check */ |
409 | if (pp->lazy_line && pp->line) | 504 | if (pp->lazy_line && pp->line) { |
410 | semantic_error("Lazy pattern can't be used with line number."); | 505 | semantic_error("Lazy pattern can't be used with line number."); |
506 | return -EINVAL; | ||
507 | } | ||
411 | 508 | ||
412 | if (pp->lazy_line && pp->offset) | 509 | if (pp->lazy_line && pp->offset) { |
413 | semantic_error("Lazy pattern can't be used with offset."); | 510 | semantic_error("Lazy pattern can't be used with offset."); |
511 | return -EINVAL; | ||
512 | } | ||
414 | 513 | ||
415 | if (pp->line && pp->offset) | 514 | if (pp->line && pp->offset) { |
416 | semantic_error("Offset can't be used with line number."); | 515 | semantic_error("Offset can't be used with line number."); |
516 | return -EINVAL; | ||
517 | } | ||
417 | 518 | ||
418 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) | 519 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { |
419 | semantic_error("File always requires line number or " | 520 | semantic_error("File always requires line number or " |
420 | "lazy pattern."); | 521 | "lazy pattern."); |
522 | return -EINVAL; | ||
523 | } | ||
421 | 524 | ||
422 | if (pp->offset && !pp->function) | 525 | if (pp->offset && !pp->function) { |
423 | semantic_error("Offset requires an entry function."); | 526 | semantic_error("Offset requires an entry function."); |
527 | return -EINVAL; | ||
528 | } | ||
424 | 529 | ||
425 | if (pp->retprobe && !pp->function) | 530 | if (pp->retprobe && !pp->function) { |
426 | semantic_error("Return probe requires an entry function."); | 531 | semantic_error("Return probe requires an entry function."); |
532 | return -EINVAL; | ||
533 | } | ||
427 | 534 | ||
428 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) | 535 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { |
429 | semantic_error("Offset/Line/Lazy pattern can't be used with " | 536 | semantic_error("Offset/Line/Lazy pattern can't be used with " |
430 | "return probe."); | 537 | "return probe."); |
538 | return -EINVAL; | ||
539 | } | ||
431 | 540 | ||
432 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", | 541 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", |
433 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, | 542 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, |
434 | pp->lazy_line); | 543 | pp->lazy_line); |
544 | return 0; | ||
435 | } | 545 | } |
436 | 546 | ||
437 | /* Parse perf-probe event argument */ | 547 | /* Parse perf-probe event argument */ |
438 | static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg) | 548 | static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) |
439 | { | 549 | { |
440 | const char *tmp; | 550 | char *tmp; |
441 | struct perf_probe_arg_field **fieldp; | 551 | struct perf_probe_arg_field **fieldp; |
442 | 552 | ||
443 | pr_debug("parsing arg: %s into ", str); | 553 | pr_debug("parsing arg: %s into ", str); |
444 | 554 | ||
555 | tmp = strchr(str, '='); | ||
556 | if (tmp) { | ||
557 | arg->name = strndup(str, tmp - str); | ||
558 | if (arg->name == NULL) | ||
559 | return -ENOMEM; | ||
560 | pr_debug("name:%s ", arg->name); | ||
561 | str = tmp + 1; | ||
562 | } | ||
563 | |||
564 | tmp = strchr(str, ':'); | ||
565 | if (tmp) { /* Type setting */ | ||
566 | *tmp = '\0'; | ||
567 | arg->type = strdup(tmp + 1); | ||
568 | if (arg->type == NULL) | ||
569 | return -ENOMEM; | ||
570 | pr_debug("type:%s ", arg->type); | ||
571 | } | ||
572 | |||
445 | tmp = strpbrk(str, "-."); | 573 | tmp = strpbrk(str, "-."); |
446 | if (!is_c_varname(str) || !tmp) { | 574 | if (!is_c_varname(str) || !tmp) { |
447 | /* A variable, register, symbol or special value */ | 575 | /* A variable, register, symbol or special value */ |
448 | arg->name = xstrdup(str); | 576 | arg->var = strdup(str); |
449 | pr_debug("%s\n", arg->name); | 577 | if (arg->var == NULL) |
450 | return; | 578 | return -ENOMEM; |
579 | pr_debug("%s\n", arg->var); | ||
580 | return 0; | ||
451 | } | 581 | } |
452 | 582 | ||
453 | /* Structure fields */ | 583 | /* Structure fields */ |
454 | arg->name = xstrndup(str, tmp - str); | 584 | arg->var = strndup(str, tmp - str); |
455 | pr_debug("%s, ", arg->name); | 585 | if (arg->var == NULL) |
586 | return -ENOMEM; | ||
587 | pr_debug("%s, ", arg->var); | ||
456 | fieldp = &arg->field; | 588 | fieldp = &arg->field; |
457 | 589 | ||
458 | do { | 590 | do { |
459 | *fieldp = xzalloc(sizeof(struct perf_probe_arg_field)); | 591 | *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); |
592 | if (*fieldp == NULL) | ||
593 | return -ENOMEM; | ||
460 | if (*tmp == '.') { | 594 | if (*tmp == '.') { |
461 | str = tmp + 1; | 595 | str = tmp + 1; |
462 | (*fieldp)->ref = false; | 596 | (*fieldp)->ref = false; |
463 | } else if (tmp[1] == '>') { | 597 | } else if (tmp[1] == '>') { |
464 | str = tmp + 2; | 598 | str = tmp + 2; |
465 | (*fieldp)->ref = true; | 599 | (*fieldp)->ref = true; |
466 | } else | 600 | } else { |
467 | semantic_error("Argument parse error: %s", str); | 601 | semantic_error("Argument parse error: %s\n", str); |
602 | return -EINVAL; | ||
603 | } | ||
468 | 604 | ||
469 | tmp = strpbrk(str, "-."); | 605 | tmp = strpbrk(str, "-."); |
470 | if (tmp) { | 606 | if (tmp) { |
471 | (*fieldp)->name = xstrndup(str, tmp - str); | 607 | (*fieldp)->name = strndup(str, tmp - str); |
608 | if ((*fieldp)->name == NULL) | ||
609 | return -ENOMEM; | ||
472 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); | 610 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); |
473 | fieldp = &(*fieldp)->next; | 611 | fieldp = &(*fieldp)->next; |
474 | } | 612 | } |
475 | } while (tmp); | 613 | } while (tmp); |
476 | (*fieldp)->name = xstrdup(str); | 614 | (*fieldp)->name = strdup(str); |
615 | if ((*fieldp)->name == NULL) | ||
616 | return -ENOMEM; | ||
477 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); | 617 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); |
618 | |||
619 | /* If no name is specified, set the last field name */ | ||
620 | if (!arg->name) { | ||
621 | arg->name = strdup((*fieldp)->name); | ||
622 | if (arg->name == NULL) | ||
623 | return -ENOMEM; | ||
624 | } | ||
625 | return 0; | ||
478 | } | 626 | } |
479 | 627 | ||
480 | /* Parse perf-probe event command */ | 628 | /* Parse perf-probe event command */ |
481 | void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | 629 | int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) |
482 | { | 630 | { |
483 | char **argv; | 631 | char **argv; |
484 | int argc, i; | 632 | int argc, i, ret = 0; |
485 | 633 | ||
486 | argv = argv_split(cmd, &argc); | 634 | argv = argv_split(cmd, &argc); |
487 | if (!argv) | 635 | if (!argv) { |
488 | die("argv_split failed."); | 636 | pr_debug("Failed to split arguments.\n"); |
489 | if (argc > MAX_PROBE_ARGS + 1) | 637 | return -ENOMEM; |
490 | semantic_error("Too many arguments"); | 638 | } |
491 | 639 | if (argc - 1 > MAX_PROBE_ARGS) { | |
640 | semantic_error("Too many probe arguments (%d).\n", argc - 1); | ||
641 | ret = -ERANGE; | ||
642 | goto out; | ||
643 | } | ||
492 | /* Parse probe point */ | 644 | /* Parse probe point */ |
493 | parse_perf_probe_point(argv[0], pev); | 645 | ret = parse_perf_probe_point(argv[0], pev); |
646 | if (ret < 0) | ||
647 | goto out; | ||
494 | 648 | ||
495 | /* Copy arguments and ensure return probe has no C argument */ | 649 | /* Copy arguments and ensure return probe has no C argument */ |
496 | pev->nargs = argc - 1; | 650 | pev->nargs = argc - 1; |
497 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 651 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
498 | for (i = 0; i < pev->nargs; i++) { | 652 | if (pev->args == NULL) { |
499 | parse_perf_probe_arg(argv[i + 1], &pev->args[i]); | 653 | ret = -ENOMEM; |
500 | if (is_c_varname(pev->args[i].name) && pev->point.retprobe) | 654 | goto out; |
655 | } | ||
656 | for (i = 0; i < pev->nargs && ret >= 0; i++) { | ||
657 | ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); | ||
658 | if (ret >= 0 && | ||
659 | is_c_varname(pev->args[i].var) && pev->point.retprobe) { | ||
501 | semantic_error("You can't specify local variable for" | 660 | semantic_error("You can't specify local variable for" |
502 | " kretprobe"); | 661 | " kretprobe.\n"); |
662 | ret = -EINVAL; | ||
663 | } | ||
503 | } | 664 | } |
504 | 665 | out: | |
505 | argv_free(argv); | 666 | argv_free(argv); |
667 | |||
668 | return ret; | ||
506 | } | 669 | } |
507 | 670 | ||
508 | /* Return true if this perf_probe_event requires debuginfo */ | 671 | /* Return true if this perf_probe_event requires debuginfo */ |
@@ -514,14 +677,14 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | |||
514 | return true; | 677 | return true; |
515 | 678 | ||
516 | for (i = 0; i < pev->nargs; i++) | 679 | for (i = 0; i < pev->nargs; i++) |
517 | if (is_c_varname(pev->args[i].name)) | 680 | if (is_c_varname(pev->args[i].var)) |
518 | return true; | 681 | return true; |
519 | 682 | ||
520 | return false; | 683 | return false; |
521 | } | 684 | } |
522 | 685 | ||
523 | /* Parse kprobe_events event into struct probe_point */ | 686 | /* Parse kprobe_events event into struct probe_point */ |
524 | void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) | 687 | int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) |
525 | { | 688 | { |
526 | struct kprobe_trace_point *tp = &tev->point; | 689 | struct kprobe_trace_point *tp = &tev->point; |
527 | char pr; | 690 | char pr; |
@@ -531,17 +694,25 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) | |||
531 | 694 | ||
532 | pr_debug("Parsing kprobe_events: %s\n", cmd); | 695 | pr_debug("Parsing kprobe_events: %s\n", cmd); |
533 | argv = argv_split(cmd, &argc); | 696 | argv = argv_split(cmd, &argc); |
534 | if (!argv) | 697 | if (!argv) { |
535 | die("argv_split failed."); | 698 | pr_debug("Failed to split arguments.\n"); |
536 | if (argc < 2) | 699 | return -ENOMEM; |
537 | semantic_error("Too less arguments."); | 700 | } |
701 | if (argc < 2) { | ||
702 | semantic_error("Too few probe arguments.\n"); | ||
703 | ret = -ERANGE; | ||
704 | goto out; | ||
705 | } | ||
538 | 706 | ||
539 | /* Scan event and group name. */ | 707 | /* Scan event and group name. */ |
540 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", | 708 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", |
541 | &pr, (float *)(void *)&tev->group, | 709 | &pr, (float *)(void *)&tev->group, |
542 | (float *)(void *)&tev->event); | 710 | (float *)(void *)&tev->event); |
543 | if (ret != 3) | 711 | if (ret != 3) { |
544 | semantic_error("Failed to parse event name: %s", argv[0]); | 712 | semantic_error("Failed to parse event name: %s\n", argv[0]); |
713 | ret = -EINVAL; | ||
714 | goto out; | ||
715 | } | ||
545 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); | 716 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); |
546 | 717 | ||
547 | tp->retprobe = (pr == 'r'); | 718 | tp->retprobe = (pr == 'r'); |
@@ -553,19 +724,29 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) | |||
553 | tp->offset = 0; | 724 | tp->offset = 0; |
554 | 725 | ||
555 | tev->nargs = argc - 2; | 726 | tev->nargs = argc - 2; |
556 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); | 727 | tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); |
728 | if (tev->args == NULL) { | ||
729 | ret = -ENOMEM; | ||
730 | goto out; | ||
731 | } | ||
557 | for (i = 0; i < tev->nargs; i++) { | 732 | for (i = 0; i < tev->nargs; i++) { |
558 | p = strchr(argv[i + 2], '='); | 733 | p = strchr(argv[i + 2], '='); |
559 | if (p) /* We don't need which register is assigned. */ | 734 | if (p) /* We don't need which register is assigned. */ |
560 | *p++ = '\0'; | 735 | *p++ = '\0'; |
561 | else | 736 | else |
562 | p = argv[i + 2]; | 737 | p = argv[i + 2]; |
563 | tev->args[i].name = xstrdup(argv[i + 2]); | 738 | tev->args[i].name = strdup(argv[i + 2]); |
564 | /* TODO: parse regs and offset */ | 739 | /* TODO: parse regs and offset */ |
565 | tev->args[i].value = xstrdup(p); | 740 | tev->args[i].value = strdup(p); |
741 | if (tev->args[i].name == NULL || tev->args[i].value == NULL) { | ||
742 | ret = -ENOMEM; | ||
743 | goto out; | ||
744 | } | ||
566 | } | 745 | } |
567 | 746 | ret = 0; | |
747 | out: | ||
568 | argv_free(argv); | 748 | argv_free(argv); |
749 | return ret; | ||
569 | } | 750 | } |
570 | 751 | ||
571 | /* Compose only probe arg */ | 752 | /* Compose only probe arg */ |
@@ -575,7 +756,10 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | |||
575 | int ret; | 756 | int ret; |
576 | char *tmp = buf; | 757 | char *tmp = buf; |
577 | 758 | ||
578 | ret = e_snprintf(tmp, len, "%s", pa->name); | 759 | if (pa->name && pa->var) |
760 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | ||
761 | else | ||
762 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | ||
579 | if (ret <= 0) | 763 | if (ret <= 0) |
580 | goto error; | 764 | goto error; |
581 | tmp += ret; | 765 | tmp += ret; |
@@ -590,9 +774,20 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | |||
590 | len -= ret; | 774 | len -= ret; |
591 | field = field->next; | 775 | field = field->next; |
592 | } | 776 | } |
777 | |||
778 | if (pa->type) { | ||
779 | ret = e_snprintf(tmp, len, ":%s", pa->type); | ||
780 | if (ret <= 0) | ||
781 | goto error; | ||
782 | tmp += ret; | ||
783 | len -= ret; | ||
784 | } | ||
785 | |||
593 | return tmp - buf; | 786 | return tmp - buf; |
594 | error: | 787 | error: |
595 | die("Failed to synthesize perf probe argument: %s", strerror(-ret)); | 788 | pr_debug("Failed to synthesize perf probe argument: %s", |
789 | strerror(-ret)); | ||
790 | return ret; | ||
596 | } | 791 | } |
597 | 792 | ||
598 | /* Compose only probe point (not argument) */ | 793 | /* Compose only probe point (not argument) */ |
@@ -602,7 +797,11 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
602 | char offs[32] = "", line[32] = "", file[32] = ""; | 797 | char offs[32] = "", line[32] = "", file[32] = ""; |
603 | int ret, len; | 798 | int ret, len; |
604 | 799 | ||
605 | buf = xzalloc(MAX_CMDLEN); | 800 | buf = zalloc(MAX_CMDLEN); |
801 | if (buf == NULL) { | ||
802 | ret = -ENOMEM; | ||
803 | goto error; | ||
804 | } | ||
606 | if (pp->offset) { | 805 | if (pp->offset) { |
607 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); | 806 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); |
608 | if (ret <= 0) | 807 | if (ret <= 0) |
@@ -614,12 +813,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
614 | goto error; | 813 | goto error; |
615 | } | 814 | } |
616 | if (pp->file) { | 815 | if (pp->file) { |
617 | len = strlen(pp->file) - 32; | 816 | len = strlen(pp->file) - 31; |
618 | if (len < 0) | 817 | if (len < 0) |
619 | len = 0; | 818 | len = 0; |
620 | tmp = strchr(pp->file + len, '/'); | 819 | tmp = strchr(pp->file + len, '/'); |
621 | if (!tmp) | 820 | if (!tmp) |
622 | tmp = pp->file + len - 1; | 821 | tmp = pp->file + len; |
623 | ret = e_snprintf(file, 32, "@%s", tmp + 1); | 822 | ret = e_snprintf(file, 32, "@%s", tmp + 1); |
624 | if (ret <= 0) | 823 | if (ret <= 0) |
625 | goto error; | 824 | goto error; |
@@ -636,7 +835,11 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
636 | 835 | ||
637 | return buf; | 836 | return buf; |
638 | error: | 837 | error: |
639 | die("Failed to synthesize perf probe point: %s", strerror(-ret)); | 838 | pr_debug("Failed to synthesize perf probe point: %s", |
839 | strerror(-ret)); | ||
840 | if (buf) | ||
841 | free(buf); | ||
842 | return NULL; | ||
640 | } | 843 | } |
641 | 844 | ||
642 | #if 0 | 845 | #if 0 |
@@ -727,6 +930,13 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, | |||
727 | buf += ret; | 930 | buf += ret; |
728 | buflen -= ret; | 931 | buflen -= ret; |
729 | } | 932 | } |
933 | /* Print argument type */ | ||
934 | if (arg->type) { | ||
935 | ret = e_snprintf(buf, buflen, ":%s", arg->type); | ||
936 | if (ret <= 0) | ||
937 | return ret; | ||
938 | buf += ret; | ||
939 | } | ||
730 | 940 | ||
731 | return buf - tmp; | 941 | return buf - tmp; |
732 | } | 942 | } |
@@ -737,7 +947,10 @@ char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) | |||
737 | char *buf; | 947 | char *buf; |
738 | int i, len, ret; | 948 | int i, len, ret; |
739 | 949 | ||
740 | buf = xzalloc(MAX_CMDLEN); | 950 | buf = zalloc(MAX_CMDLEN); |
951 | if (buf == NULL) | ||
952 | return NULL; | ||
953 | |||
741 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", | 954 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", |
742 | tp->retprobe ? 'r' : 'p', | 955 | tp->retprobe ? 'r' : 'p', |
743 | tev->group, tev->event, | 956 | tev->group, tev->event, |
@@ -759,29 +972,44 @@ error: | |||
759 | return NULL; | 972 | return NULL; |
760 | } | 973 | } |
761 | 974 | ||
762 | void convert_to_perf_probe_event(struct kprobe_trace_event *tev, | 975 | int convert_to_perf_probe_event(struct kprobe_trace_event *tev, |
763 | struct perf_probe_event *pev) | 976 | struct perf_probe_event *pev) |
764 | { | 977 | { |
765 | char buf[64]; | 978 | char buf[64] = ""; |
766 | int i; | 979 | int i, ret; |
767 | 980 | ||
768 | /* Convert event/group name */ | 981 | /* Convert event/group name */ |
769 | pev->event = xstrdup(tev->event); | 982 | pev->event = strdup(tev->event); |
770 | pev->group = xstrdup(tev->group); | 983 | pev->group = strdup(tev->group); |
984 | if (pev->event == NULL || pev->group == NULL) | ||
985 | return -ENOMEM; | ||
771 | 986 | ||
772 | /* Convert trace_point to probe_point */ | 987 | /* Convert trace_point to probe_point */ |
773 | convert_to_perf_probe_point(&tev->point, &pev->point); | 988 | ret = convert_to_perf_probe_point(&tev->point, &pev->point); |
989 | if (ret < 0) | ||
990 | return ret; | ||
774 | 991 | ||
775 | /* Convert trace_arg to probe_arg */ | 992 | /* Convert trace_arg to probe_arg */ |
776 | pev->nargs = tev->nargs; | 993 | pev->nargs = tev->nargs; |
777 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 994 | pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
778 | for (i = 0; i < tev->nargs; i++) | 995 | if (pev->args == NULL) |
996 | return -ENOMEM; | ||
997 | for (i = 0; i < tev->nargs && ret >= 0; i++) { | ||
779 | if (tev->args[i].name) | 998 | if (tev->args[i].name) |
780 | pev->args[i].name = xstrdup(tev->args[i].name); | 999 | pev->args[i].name = strdup(tev->args[i].name); |
781 | else { | 1000 | else { |
782 | synthesize_kprobe_trace_arg(&tev->args[i], buf, 64); | 1001 | ret = synthesize_kprobe_trace_arg(&tev->args[i], |
783 | pev->args[i].name = xstrdup(buf); | 1002 | buf, 64); |
1003 | pev->args[i].name = strdup(buf); | ||
784 | } | 1004 | } |
1005 | if (pev->args[i].name == NULL && ret >= 0) | ||
1006 | ret = -ENOMEM; | ||
1007 | } | ||
1008 | |||
1009 | if (ret < 0) | ||
1010 | clear_perf_probe_event(pev); | ||
1011 | |||
1012 | return ret; | ||
785 | } | 1013 | } |
786 | 1014 | ||
787 | void clear_perf_probe_event(struct perf_probe_event *pev) | 1015 | void clear_perf_probe_event(struct perf_probe_event *pev) |
@@ -803,6 +1031,10 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
803 | for (i = 0; i < pev->nargs; i++) { | 1031 | for (i = 0; i < pev->nargs; i++) { |
804 | if (pev->args[i].name) | 1032 | if (pev->args[i].name) |
805 | free(pev->args[i].name); | 1033 | free(pev->args[i].name); |
1034 | if (pev->args[i].var) | ||
1035 | free(pev->args[i].var); | ||
1036 | if (pev->args[i].type) | ||
1037 | free(pev->args[i].type); | ||
806 | field = pev->args[i].field; | 1038 | field = pev->args[i].field; |
807 | while (field) { | 1039 | while (field) { |
808 | next = field->next; | 1040 | next = field->next; |
@@ -833,6 +1065,8 @@ void clear_kprobe_trace_event(struct kprobe_trace_event *tev) | |||
833 | free(tev->args[i].name); | 1065 | free(tev->args[i].name); |
834 | if (tev->args[i].value) | 1066 | if (tev->args[i].value) |
835 | free(tev->args[i].value); | 1067 | free(tev->args[i].value); |
1068 | if (tev->args[i].type) | ||
1069 | free(tev->args[i].type); | ||
836 | ref = tev->args[i].ref; | 1070 | ref = tev->args[i].ref; |
837 | while (ref) { | 1071 | while (ref) { |
838 | next = ref->next; | 1072 | next = ref->next; |
@@ -848,24 +1082,31 @@ void clear_kprobe_trace_event(struct kprobe_trace_event *tev) | |||
848 | static int open_kprobe_events(bool readwrite) | 1082 | static int open_kprobe_events(bool readwrite) |
849 | { | 1083 | { |
850 | char buf[PATH_MAX]; | 1084 | char buf[PATH_MAX]; |
1085 | const char *__debugfs; | ||
851 | int ret; | 1086 | int ret; |
852 | 1087 | ||
853 | ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); | 1088 | __debugfs = debugfs_find_mountpoint(); |
854 | if (ret < 0) | 1089 | if (__debugfs == NULL) { |
855 | die("Failed to make kprobe_events path."); | 1090 | pr_warning("Debugfs is not mounted.\n"); |
1091 | return -ENOENT; | ||
1092 | } | ||
856 | 1093 | ||
857 | if (readwrite && !probe_event_dry_run) | 1094 | ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); |
858 | ret = open(buf, O_RDWR, O_APPEND); | 1095 | if (ret >= 0) { |
859 | else | 1096 | pr_debug("Opening %s write=%d\n", buf, readwrite); |
860 | ret = open(buf, O_RDONLY, 0); | 1097 | if (readwrite && !probe_event_dry_run) |
1098 | ret = open(buf, O_RDWR, O_APPEND); | ||
1099 | else | ||
1100 | ret = open(buf, O_RDONLY, 0); | ||
1101 | } | ||
861 | 1102 | ||
862 | if (ret < 0) { | 1103 | if (ret < 0) { |
863 | if (errno == ENOENT) | 1104 | if (errno == ENOENT) |
864 | die("kprobe_events file does not exist -" | 1105 | pr_warning("kprobe_events file does not exist - please" |
865 | " please rebuild with CONFIG_KPROBE_EVENT."); | 1106 | " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); |
866 | else | 1107 | else |
867 | die("Could not open kprobe_events file: %s", | 1108 | pr_warning("Failed to open kprobe_events file: %s\n", |
868 | strerror(errno)); | 1109 | strerror(errno)); |
869 | } | 1110 | } |
870 | return ret; | 1111 | return ret; |
871 | } | 1112 | } |
@@ -891,8 +1132,11 @@ static struct strlist *get_kprobe_trace_command_rawlist(int fd) | |||
891 | if (p[idx] == '\n') | 1132 | if (p[idx] == '\n') |
892 | p[idx] = '\0'; | 1133 | p[idx] = '\0'; |
893 | ret = strlist__add(sl, buf); | 1134 | ret = strlist__add(sl, buf); |
894 | if (ret < 0) | 1135 | if (ret < 0) { |
895 | die("strlist__add failed: %s", strerror(-ret)); | 1136 | pr_debug("strlist__add failed: %s\n", strerror(-ret)); |
1137 | strlist__delete(sl); | ||
1138 | return NULL; | ||
1139 | } | ||
896 | } | 1140 | } |
897 | fclose(fp); | 1141 | fclose(fp); |
898 | 1142 | ||
@@ -900,7 +1144,7 @@ static struct strlist *get_kprobe_trace_command_rawlist(int fd) | |||
900 | } | 1144 | } |
901 | 1145 | ||
902 | /* Show an event */ | 1146 | /* Show an event */ |
903 | static void show_perf_probe_event(struct perf_probe_event *pev) | 1147 | static int show_perf_probe_event(struct perf_probe_event *pev) |
904 | { | 1148 | { |
905 | int i, ret; | 1149 | int i, ret; |
906 | char buf[128]; | 1150 | char buf[128]; |
@@ -908,52 +1152,71 @@ static void show_perf_probe_event(struct perf_probe_event *pev) | |||
908 | 1152 | ||
909 | /* Synthesize only event probe point */ | 1153 | /* Synthesize only event probe point */ |
910 | place = synthesize_perf_probe_point(&pev->point); | 1154 | place = synthesize_perf_probe_point(&pev->point); |
1155 | if (!place) | ||
1156 | return -EINVAL; | ||
911 | 1157 | ||
912 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); | 1158 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); |
913 | if (ret < 0) | 1159 | if (ret < 0) |
914 | die("Failed to copy event: %s", strerror(-ret)); | 1160 | return ret; |
1161 | |||
915 | printf(" %-20s (on %s", buf, place); | 1162 | printf(" %-20s (on %s", buf, place); |
916 | 1163 | ||
917 | if (pev->nargs > 0) { | 1164 | if (pev->nargs > 0) { |
918 | printf(" with"); | 1165 | printf(" with"); |
919 | for (i = 0; i < pev->nargs; i++) { | 1166 | for (i = 0; i < pev->nargs; i++) { |
920 | synthesize_perf_probe_arg(&pev->args[i], buf, 128); | 1167 | ret = synthesize_perf_probe_arg(&pev->args[i], |
1168 | buf, 128); | ||
1169 | if (ret < 0) | ||
1170 | break; | ||
921 | printf(" %s", buf); | 1171 | printf(" %s", buf); |
922 | } | 1172 | } |
923 | } | 1173 | } |
924 | printf(")\n"); | 1174 | printf(")\n"); |
925 | free(place); | 1175 | free(place); |
1176 | return ret; | ||
926 | } | 1177 | } |
927 | 1178 | ||
928 | /* List up current perf-probe events */ | 1179 | /* List up current perf-probe events */ |
929 | void show_perf_probe_events(void) | 1180 | int show_perf_probe_events(void) |
930 | { | 1181 | { |
931 | int fd; | 1182 | int fd, ret; |
932 | struct kprobe_trace_event tev; | 1183 | struct kprobe_trace_event tev; |
933 | struct perf_probe_event pev; | 1184 | struct perf_probe_event pev; |
934 | struct strlist *rawlist; | 1185 | struct strlist *rawlist; |
935 | struct str_node *ent; | 1186 | struct str_node *ent; |
936 | 1187 | ||
937 | setup_pager(); | 1188 | setup_pager(); |
938 | init_vmlinux(); | 1189 | ret = init_vmlinux(); |
1190 | if (ret < 0) | ||
1191 | return ret; | ||
939 | 1192 | ||
940 | memset(&tev, 0, sizeof(tev)); | 1193 | memset(&tev, 0, sizeof(tev)); |
941 | memset(&pev, 0, sizeof(pev)); | 1194 | memset(&pev, 0, sizeof(pev)); |
942 | 1195 | ||
943 | fd = open_kprobe_events(false); | 1196 | fd = open_kprobe_events(false); |
1197 | if (fd < 0) | ||
1198 | return fd; | ||
1199 | |||
944 | rawlist = get_kprobe_trace_command_rawlist(fd); | 1200 | rawlist = get_kprobe_trace_command_rawlist(fd); |
945 | close(fd); | 1201 | close(fd); |
1202 | if (!rawlist) | ||
1203 | return -ENOENT; | ||
946 | 1204 | ||
947 | strlist__for_each(ent, rawlist) { | 1205 | strlist__for_each(ent, rawlist) { |
948 | parse_kprobe_trace_command(ent->s, &tev); | 1206 | ret = parse_kprobe_trace_command(ent->s, &tev); |
949 | convert_to_perf_probe_event(&tev, &pev); | 1207 | if (ret >= 0) { |
950 | /* Show an event */ | 1208 | ret = convert_to_perf_probe_event(&tev, &pev); |
951 | show_perf_probe_event(&pev); | 1209 | if (ret >= 0) |
1210 | ret = show_perf_probe_event(&pev); | ||
1211 | } | ||
952 | clear_perf_probe_event(&pev); | 1212 | clear_perf_probe_event(&pev); |
953 | clear_kprobe_trace_event(&tev); | 1213 | clear_kprobe_trace_event(&tev); |
1214 | if (ret < 0) | ||
1215 | break; | ||
954 | } | 1216 | } |
955 | |||
956 | strlist__delete(rawlist); | 1217 | strlist__delete(rawlist); |
1218 | |||
1219 | return ret; | ||
957 | } | 1220 | } |
958 | 1221 | ||
959 | /* Get current perf-probe event names */ | 1222 | /* Get current perf-probe event names */ |
@@ -963,86 +1226,116 @@ static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) | |||
963 | struct strlist *sl, *rawlist; | 1226 | struct strlist *sl, *rawlist; |
964 | struct str_node *ent; | 1227 | struct str_node *ent; |
965 | struct kprobe_trace_event tev; | 1228 | struct kprobe_trace_event tev; |
1229 | int ret = 0; | ||
966 | 1230 | ||
967 | memset(&tev, 0, sizeof(tev)); | 1231 | memset(&tev, 0, sizeof(tev)); |
968 | 1232 | ||
969 | rawlist = get_kprobe_trace_command_rawlist(fd); | 1233 | rawlist = get_kprobe_trace_command_rawlist(fd); |
970 | sl = strlist__new(true, NULL); | 1234 | sl = strlist__new(true, NULL); |
971 | strlist__for_each(ent, rawlist) { | 1235 | strlist__for_each(ent, rawlist) { |
972 | parse_kprobe_trace_command(ent->s, &tev); | 1236 | ret = parse_kprobe_trace_command(ent->s, &tev); |
1237 | if (ret < 0) | ||
1238 | break; | ||
973 | if (include_group) { | 1239 | if (include_group) { |
974 | if (e_snprintf(buf, 128, "%s:%s", tev.group, | 1240 | ret = e_snprintf(buf, 128, "%s:%s", tev.group, |
975 | tev.event) < 0) | 1241 | tev.event); |
976 | die("Failed to copy group:event name."); | 1242 | if (ret >= 0) |
977 | strlist__add(sl, buf); | 1243 | ret = strlist__add(sl, buf); |
978 | } else | 1244 | } else |
979 | strlist__add(sl, tev.event); | 1245 | ret = strlist__add(sl, tev.event); |
980 | clear_kprobe_trace_event(&tev); | 1246 | clear_kprobe_trace_event(&tev); |
1247 | if (ret < 0) | ||
1248 | break; | ||
981 | } | 1249 | } |
982 | |||
983 | strlist__delete(rawlist); | 1250 | strlist__delete(rawlist); |
984 | 1251 | ||
1252 | if (ret < 0) { | ||
1253 | strlist__delete(sl); | ||
1254 | return NULL; | ||
1255 | } | ||
985 | return sl; | 1256 | return sl; |
986 | } | 1257 | } |
987 | 1258 | ||
988 | static void write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) | 1259 | static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) |
989 | { | 1260 | { |
990 | int ret; | 1261 | int ret; |
991 | char *buf = synthesize_kprobe_trace_command(tev); | 1262 | char *buf = synthesize_kprobe_trace_command(tev); |
992 | 1263 | ||
1264 | if (!buf) { | ||
1265 | pr_debug("Failed to synthesize kprobe trace event.\n"); | ||
1266 | return -EINVAL; | ||
1267 | } | ||
1268 | |||
993 | pr_debug("Writing event: %s\n", buf); | 1269 | pr_debug("Writing event: %s\n", buf); |
994 | if (!probe_event_dry_run) { | 1270 | if (!probe_event_dry_run) { |
995 | ret = write(fd, buf, strlen(buf)); | 1271 | ret = write(fd, buf, strlen(buf)); |
996 | if (ret <= 0) | 1272 | if (ret <= 0) |
997 | die("Failed to write event: %s", strerror(errno)); | 1273 | pr_warning("Failed to write event: %s\n", |
1274 | strerror(errno)); | ||
998 | } | 1275 | } |
999 | free(buf); | 1276 | free(buf); |
1277 | return ret; | ||
1000 | } | 1278 | } |
1001 | 1279 | ||
1002 | static void get_new_event_name(char *buf, size_t len, const char *base, | 1280 | static int get_new_event_name(char *buf, size_t len, const char *base, |
1003 | struct strlist *namelist, bool allow_suffix) | 1281 | struct strlist *namelist, bool allow_suffix) |
1004 | { | 1282 | { |
1005 | int i, ret; | 1283 | int i, ret; |
1006 | 1284 | ||
1007 | /* Try no suffix */ | 1285 | /* Try no suffix */ |
1008 | ret = e_snprintf(buf, len, "%s", base); | 1286 | ret = e_snprintf(buf, len, "%s", base); |
1009 | if (ret < 0) | 1287 | if (ret < 0) { |
1010 | die("snprintf() failed: %s", strerror(-ret)); | 1288 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); |
1289 | return ret; | ||
1290 | } | ||
1011 | if (!strlist__has_entry(namelist, buf)) | 1291 | if (!strlist__has_entry(namelist, buf)) |
1012 | return; | 1292 | return 0; |
1013 | 1293 | ||
1014 | if (!allow_suffix) { | 1294 | if (!allow_suffix) { |
1015 | pr_warning("Error: event \"%s\" already exists. " | 1295 | pr_warning("Error: event \"%s\" already exists. " |
1016 | "(Use -f to force duplicates.)\n", base); | 1296 | "(Use -f to force duplicates.)\n", base); |
1017 | die("Can't add new event."); | 1297 | return -EEXIST; |
1018 | } | 1298 | } |
1019 | 1299 | ||
1020 | /* Try to add suffix */ | 1300 | /* Try to add suffix */ |
1021 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | 1301 | for (i = 1; i < MAX_EVENT_INDEX; i++) { |
1022 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 1302 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
1023 | if (ret < 0) | 1303 | if (ret < 0) { |
1024 | die("snprintf() failed: %s", strerror(-ret)); | 1304 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); |
1305 | return ret; | ||
1306 | } | ||
1025 | if (!strlist__has_entry(namelist, buf)) | 1307 | if (!strlist__has_entry(namelist, buf)) |
1026 | break; | 1308 | break; |
1027 | } | 1309 | } |
1028 | if (i == MAX_EVENT_INDEX) | 1310 | if (i == MAX_EVENT_INDEX) { |
1029 | die("Too many events are on the same function."); | 1311 | pr_warning("Too many events are on the same function.\n"); |
1312 | ret = -ERANGE; | ||
1313 | } | ||
1314 | |||
1315 | return ret; | ||
1030 | } | 1316 | } |
1031 | 1317 | ||
1032 | static void __add_kprobe_trace_events(struct perf_probe_event *pev, | 1318 | static int __add_kprobe_trace_events(struct perf_probe_event *pev, |
1033 | struct kprobe_trace_event *tevs, | 1319 | struct kprobe_trace_event *tevs, |
1034 | int ntevs, bool allow_suffix) | 1320 | int ntevs, bool allow_suffix) |
1035 | { | 1321 | { |
1036 | int i, fd; | 1322 | int i, fd, ret; |
1037 | struct kprobe_trace_event *tev = NULL; | 1323 | struct kprobe_trace_event *tev = NULL; |
1038 | char buf[64]; | 1324 | char buf[64]; |
1039 | const char *event, *group; | 1325 | const char *event, *group; |
1040 | struct strlist *namelist; | 1326 | struct strlist *namelist; |
1041 | 1327 | ||
1042 | fd = open_kprobe_events(true); | 1328 | fd = open_kprobe_events(true); |
1329 | if (fd < 0) | ||
1330 | return fd; | ||
1043 | /* Get current event names */ | 1331 | /* Get current event names */ |
1044 | namelist = get_kprobe_trace_event_names(fd, false); | 1332 | namelist = get_kprobe_trace_event_names(fd, false); |
1333 | if (!namelist) { | ||
1334 | pr_debug("Failed to get current event list.\n"); | ||
1335 | return -EIO; | ||
1336 | } | ||
1045 | 1337 | ||
1338 | ret = 0; | ||
1046 | printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); | 1339 | printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); |
1047 | for (i = 0; i < ntevs; i++) { | 1340 | for (i = 0; i < ntevs; i++) { |
1048 | tev = &tevs[i]; | 1341 | tev = &tevs[i]; |
@@ -1059,12 +1352,21 @@ static void __add_kprobe_trace_events(struct perf_probe_event *pev, | |||
1059 | group = PERFPROBE_GROUP; | 1352 | group = PERFPROBE_GROUP; |
1060 | 1353 | ||
1061 | /* Get an unused new event name */ | 1354 | /* Get an unused new event name */ |
1062 | get_new_event_name(buf, 64, event, namelist, allow_suffix); | 1355 | ret = get_new_event_name(buf, 64, event, |
1356 | namelist, allow_suffix); | ||
1357 | if (ret < 0) | ||
1358 | break; | ||
1063 | event = buf; | 1359 | event = buf; |
1064 | 1360 | ||
1065 | tev->event = xstrdup(event); | 1361 | tev->event = strdup(event); |
1066 | tev->group = xstrdup(group); | 1362 | tev->group = strdup(group); |
1067 | write_kprobe_trace_event(fd, tev); | 1363 | if (tev->event == NULL || tev->group == NULL) { |
1364 | ret = -ENOMEM; | ||
1365 | break; | ||
1366 | } | ||
1367 | ret = write_kprobe_trace_event(fd, tev); | ||
1368 | if (ret < 0) | ||
1369 | break; | ||
1068 | /* Add added event name to namelist */ | 1370 | /* Add added event name to namelist */ |
1069 | strlist__add(namelist, event); | 1371 | strlist__add(namelist, event); |
1070 | 1372 | ||
@@ -1086,49 +1388,90 @@ static void __add_kprobe_trace_events(struct perf_probe_event *pev, | |||
1086 | */ | 1388 | */ |
1087 | allow_suffix = true; | 1389 | allow_suffix = true; |
1088 | } | 1390 | } |
1089 | /* Show how to use the event. */ | 1391 | |
1090 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | 1392 | if (ret >= 0) { |
1091 | printf("\tperf record -e %s:%s -a sleep 1\n\n", tev->group, tev->event); | 1393 | /* Show how to use the event. */ |
1394 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | ||
1395 | printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, | ||
1396 | tev->event); | ||
1397 | } | ||
1092 | 1398 | ||
1093 | strlist__delete(namelist); | 1399 | strlist__delete(namelist); |
1094 | close(fd); | 1400 | close(fd); |
1401 | return ret; | ||
1095 | } | 1402 | } |
1096 | 1403 | ||
1097 | static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, | 1404 | static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, |
1098 | struct kprobe_trace_event **tevs) | 1405 | struct kprobe_trace_event **tevs) |
1099 | { | 1406 | { |
1100 | struct symbol *sym; | 1407 | struct symbol *sym; |
1101 | int ntevs = 0, i; | 1408 | int ret = 0, i; |
1102 | struct kprobe_trace_event *tev; | 1409 | struct kprobe_trace_event *tev; |
1103 | 1410 | ||
1104 | /* Convert perf_probe_event with debuginfo */ | 1411 | /* Convert perf_probe_event with debuginfo */ |
1105 | ntevs = try_to_find_kprobe_trace_events(pev, tevs); | 1412 | ret = try_to_find_kprobe_trace_events(pev, tevs); |
1106 | if (ntevs > 0) | 1413 | if (ret != 0) |
1107 | return ntevs; | 1414 | return ret; |
1108 | 1415 | ||
1109 | /* Allocate trace event buffer */ | 1416 | /* Allocate trace event buffer */ |
1110 | ntevs = 1; | 1417 | tev = *tevs = zalloc(sizeof(struct kprobe_trace_event)); |
1111 | tev = *tevs = xzalloc(sizeof(struct kprobe_trace_event)); | 1418 | if (tev == NULL) |
1419 | return -ENOMEM; | ||
1112 | 1420 | ||
1113 | /* Copy parameters */ | 1421 | /* Copy parameters */ |
1114 | tev->point.symbol = xstrdup(pev->point.function); | 1422 | tev->point.symbol = strdup(pev->point.function); |
1423 | if (tev->point.symbol == NULL) { | ||
1424 | ret = -ENOMEM; | ||
1425 | goto error; | ||
1426 | } | ||
1115 | tev->point.offset = pev->point.offset; | 1427 | tev->point.offset = pev->point.offset; |
1116 | tev->nargs = pev->nargs; | 1428 | tev->nargs = pev->nargs; |
1117 | if (tev->nargs) { | 1429 | if (tev->nargs) { |
1118 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) | 1430 | tev->args = zalloc(sizeof(struct kprobe_trace_arg) |
1119 | * tev->nargs); | 1431 | * tev->nargs); |
1120 | for (i = 0; i < tev->nargs; i++) | 1432 | if (tev->args == NULL) { |
1121 | tev->args[i].value = xstrdup(pev->args[i].name); | 1433 | ret = -ENOMEM; |
1434 | goto error; | ||
1435 | } | ||
1436 | for (i = 0; i < tev->nargs; i++) { | ||
1437 | if (pev->args[i].name) { | ||
1438 | tev->args[i].name = strdup(pev->args[i].name); | ||
1439 | if (tev->args[i].name == NULL) { | ||
1440 | ret = -ENOMEM; | ||
1441 | goto error; | ||
1442 | } | ||
1443 | } | ||
1444 | tev->args[i].value = strdup(pev->args[i].var); | ||
1445 | if (tev->args[i].value == NULL) { | ||
1446 | ret = -ENOMEM; | ||
1447 | goto error; | ||
1448 | } | ||
1449 | if (pev->args[i].type) { | ||
1450 | tev->args[i].type = strdup(pev->args[i].type); | ||
1451 | if (tev->args[i].type == NULL) { | ||
1452 | ret = -ENOMEM; | ||
1453 | goto error; | ||
1454 | } | ||
1455 | } | ||
1456 | } | ||
1122 | } | 1457 | } |
1123 | 1458 | ||
1124 | /* Currently just checking function name from symbol map */ | 1459 | /* Currently just checking function name from symbol map */ |
1125 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], | 1460 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], |
1126 | tev->point.symbol, NULL); | 1461 | tev->point.symbol, NULL); |
1127 | if (!sym) | 1462 | if (!sym) { |
1128 | die("Kernel symbol \'%s\' not found - probe not added.", | 1463 | pr_warning("Kernel symbol \'%s\' not found.\n", |
1129 | tev->point.symbol); | 1464 | tev->point.symbol); |
1465 | ret = -ENOENT; | ||
1466 | goto error; | ||
1467 | } | ||
1130 | 1468 | ||
1131 | return ntevs; | 1469 | return 1; |
1470 | error: | ||
1471 | clear_kprobe_trace_event(tev); | ||
1472 | free(tev); | ||
1473 | *tevs = NULL; | ||
1474 | return ret; | ||
1132 | } | 1475 | } |
1133 | 1476 | ||
1134 | struct __event_package { | 1477 | struct __event_package { |
@@ -1137,96 +1480,137 @@ struct __event_package { | |||
1137 | int ntevs; | 1480 | int ntevs; |
1138 | }; | 1481 | }; |
1139 | 1482 | ||
1140 | void add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | 1483 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, |
1141 | bool force_add) | 1484 | bool force_add) |
1142 | { | 1485 | { |
1143 | int i; | 1486 | int i, j, ret; |
1144 | struct __event_package *pkgs; | 1487 | struct __event_package *pkgs; |
1145 | 1488 | ||
1146 | pkgs = xzalloc(sizeof(struct __event_package) * npevs); | 1489 | pkgs = zalloc(sizeof(struct __event_package) * npevs); |
1490 | if (pkgs == NULL) | ||
1491 | return -ENOMEM; | ||
1147 | 1492 | ||
1148 | /* Init vmlinux path */ | 1493 | /* Init vmlinux path */ |
1149 | init_vmlinux(); | 1494 | ret = init_vmlinux(); |
1495 | if (ret < 0) | ||
1496 | return ret; | ||
1150 | 1497 | ||
1151 | /* Loop 1: convert all events */ | 1498 | /* Loop 1: convert all events */ |
1152 | for (i = 0; i < npevs; i++) { | 1499 | for (i = 0; i < npevs; i++) { |
1153 | pkgs[i].pev = &pevs[i]; | 1500 | pkgs[i].pev = &pevs[i]; |
1154 | /* Convert with or without debuginfo */ | 1501 | /* Convert with or without debuginfo */ |
1155 | pkgs[i].ntevs = convert_to_kprobe_trace_events(pkgs[i].pev, | 1502 | ret = convert_to_kprobe_trace_events(pkgs[i].pev, |
1156 | &pkgs[i].tevs); | 1503 | &pkgs[i].tevs); |
1504 | if (ret < 0) | ||
1505 | goto end; | ||
1506 | pkgs[i].ntevs = ret; | ||
1157 | } | 1507 | } |
1158 | 1508 | ||
1159 | /* Loop 2: add all events */ | 1509 | /* Loop 2: add all events */ |
1510 | for (i = 0; i < npevs && ret >= 0; i++) | ||
1511 | ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, | ||
1512 | pkgs[i].ntevs, force_add); | ||
1513 | end: | ||
1514 | /* Loop 3: cleanup trace events */ | ||
1160 | for (i = 0; i < npevs; i++) | 1515 | for (i = 0; i < npevs; i++) |
1161 | __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, | 1516 | for (j = 0; j < pkgs[i].ntevs; j++) |
1162 | pkgs[i].ntevs, force_add); | 1517 | clear_kprobe_trace_event(&pkgs[i].tevs[j]); |
1163 | /* TODO: cleanup all trace events? */ | 1518 | |
1519 | return ret; | ||
1164 | } | 1520 | } |
1165 | 1521 | ||
1166 | static void __del_trace_kprobe_event(int fd, struct str_node *ent) | 1522 | static int __del_trace_kprobe_event(int fd, struct str_node *ent) |
1167 | { | 1523 | { |
1168 | char *p; | 1524 | char *p; |
1169 | char buf[128]; | 1525 | char buf[128]; |
1170 | int ret; | 1526 | int ret; |
1171 | 1527 | ||
1172 | /* Convert from perf-probe event to trace-kprobe event */ | 1528 | /* Convert from perf-probe event to trace-kprobe event */ |
1173 | if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) | 1529 | ret = e_snprintf(buf, 128, "-:%s", ent->s); |
1174 | die("Failed to copy event."); | 1530 | if (ret < 0) |
1531 | goto error; | ||
1532 | |||
1175 | p = strchr(buf + 2, ':'); | 1533 | p = strchr(buf + 2, ':'); |
1176 | if (!p) | 1534 | if (!p) { |
1177 | die("Internal error: %s should have ':' but not.", ent->s); | 1535 | pr_debug("Internal error: %s should have ':' but not.\n", |
1536 | ent->s); | ||
1537 | ret = -ENOTSUP; | ||
1538 | goto error; | ||
1539 | } | ||
1178 | *p = '/'; | 1540 | *p = '/'; |
1179 | 1541 | ||
1180 | pr_debug("Writing event: %s\n", buf); | 1542 | pr_debug("Writing event: %s\n", buf); |
1181 | ret = write(fd, buf, strlen(buf)); | 1543 | ret = write(fd, buf, strlen(buf)); |
1182 | if (ret <= 0) | 1544 | if (ret < 0) |
1183 | die("Failed to write event: %s", strerror(errno)); | 1545 | goto error; |
1546 | |||
1184 | printf("Remove event: %s\n", ent->s); | 1547 | printf("Remove event: %s\n", ent->s); |
1548 | return 0; | ||
1549 | error: | ||
1550 | pr_warning("Failed to delete event: %s\n", strerror(-ret)); | ||
1551 | return ret; | ||
1185 | } | 1552 | } |
1186 | 1553 | ||
1187 | static void del_trace_kprobe_event(int fd, const char *group, | 1554 | static int del_trace_kprobe_event(int fd, const char *group, |
1188 | const char *event, struct strlist *namelist) | 1555 | const char *event, struct strlist *namelist) |
1189 | { | 1556 | { |
1190 | char buf[128]; | 1557 | char buf[128]; |
1191 | struct str_node *ent, *n; | 1558 | struct str_node *ent, *n; |
1192 | int found = 0; | 1559 | int found = 0, ret = 0; |
1193 | 1560 | ||
1194 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | 1561 | ret = e_snprintf(buf, 128, "%s:%s", group, event); |
1195 | die("Failed to copy event."); | 1562 | if (ret < 0) { |
1563 | pr_err("Failed to copy event."); | ||
1564 | return ret; | ||
1565 | } | ||
1196 | 1566 | ||
1197 | if (strpbrk(buf, "*?")) { /* Glob-exp */ | 1567 | if (strpbrk(buf, "*?")) { /* Glob-exp */ |
1198 | strlist__for_each_safe(ent, n, namelist) | 1568 | strlist__for_each_safe(ent, n, namelist) |
1199 | if (strglobmatch(ent->s, buf)) { | 1569 | if (strglobmatch(ent->s, buf)) { |
1200 | found++; | 1570 | found++; |
1201 | __del_trace_kprobe_event(fd, ent); | 1571 | ret = __del_trace_kprobe_event(fd, ent); |
1572 | if (ret < 0) | ||
1573 | break; | ||
1202 | strlist__remove(namelist, ent); | 1574 | strlist__remove(namelist, ent); |
1203 | } | 1575 | } |
1204 | } else { | 1576 | } else { |
1205 | ent = strlist__find(namelist, buf); | 1577 | ent = strlist__find(namelist, buf); |
1206 | if (ent) { | 1578 | if (ent) { |
1207 | found++; | 1579 | found++; |
1208 | __del_trace_kprobe_event(fd, ent); | 1580 | ret = __del_trace_kprobe_event(fd, ent); |
1209 | strlist__remove(namelist, ent); | 1581 | if (ret >= 0) |
1582 | strlist__remove(namelist, ent); | ||
1210 | } | 1583 | } |
1211 | } | 1584 | } |
1212 | if (found == 0) | 1585 | if (found == 0 && ret >= 0) |
1213 | pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); | 1586 | pr_info("Info: Event \"%s\" does not exist.\n", buf); |
1587 | |||
1588 | return ret; | ||
1214 | } | 1589 | } |
1215 | 1590 | ||
1216 | void del_perf_probe_events(struct strlist *dellist) | 1591 | int del_perf_probe_events(struct strlist *dellist) |
1217 | { | 1592 | { |
1218 | int fd; | 1593 | int fd, ret = 0; |
1219 | const char *group, *event; | 1594 | const char *group, *event; |
1220 | char *p, *str; | 1595 | char *p, *str; |
1221 | struct str_node *ent; | 1596 | struct str_node *ent; |
1222 | struct strlist *namelist; | 1597 | struct strlist *namelist; |
1223 | 1598 | ||
1224 | fd = open_kprobe_events(true); | 1599 | fd = open_kprobe_events(true); |
1600 | if (fd < 0) | ||
1601 | return fd; | ||
1602 | |||
1225 | /* Get current event names */ | 1603 | /* Get current event names */ |
1226 | namelist = get_kprobe_trace_event_names(fd, true); | 1604 | namelist = get_kprobe_trace_event_names(fd, true); |
1605 | if (namelist == NULL) | ||
1606 | return -EINVAL; | ||
1227 | 1607 | ||
1228 | strlist__for_each(ent, dellist) { | 1608 | strlist__for_each(ent, dellist) { |
1229 | str = xstrdup(ent->s); | 1609 | str = strdup(ent->s); |
1610 | if (str == NULL) { | ||
1611 | ret = -ENOMEM; | ||
1612 | break; | ||
1613 | } | ||
1230 | pr_debug("Parsing: %s\n", str); | 1614 | pr_debug("Parsing: %s\n", str); |
1231 | p = strchr(str, ':'); | 1615 | p = strchr(str, ':'); |
1232 | if (p) { | 1616 | if (p) { |
@@ -1238,10 +1622,14 @@ void del_perf_probe_events(struct strlist *dellist) | |||
1238 | event = str; | 1622 | event = str; |
1239 | } | 1623 | } |
1240 | pr_debug("Group: %s, Event: %s\n", group, event); | 1624 | pr_debug("Group: %s, Event: %s\n", group, event); |
1241 | del_trace_kprobe_event(fd, group, event, namelist); | 1625 | ret = del_trace_kprobe_event(fd, group, event, namelist); |
1242 | free(str); | 1626 | free(str); |
1627 | if (ret < 0) | ||
1628 | break; | ||
1243 | } | 1629 | } |
1244 | strlist__delete(namelist); | 1630 | strlist__delete(namelist); |
1245 | close(fd); | 1631 | close(fd); |
1632 | |||
1633 | return ret; | ||
1246 | } | 1634 | } |
1247 | 1635 | ||
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 9d99fc24c4fc..e7ff0d02c0d4 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -23,6 +23,7 @@ struct kprobe_trace_arg_ref { | |||
23 | struct kprobe_trace_arg { | 23 | struct kprobe_trace_arg { |
24 | char *name; /* Argument name */ | 24 | char *name; /* Argument name */ |
25 | char *value; /* Base value */ | 25 | char *value; /* Base value */ |
26 | char *type; /* Type name */ | ||
26 | struct kprobe_trace_arg_ref *ref; /* Referencing offset */ | 27 | struct kprobe_trace_arg_ref *ref; /* Referencing offset */ |
27 | }; | 28 | }; |
28 | 29 | ||
@@ -55,6 +56,8 @@ struct perf_probe_arg_field { | |||
55 | /* Perf probe probing argument */ | 56 | /* Perf probe probing argument */ |
56 | struct perf_probe_arg { | 57 | struct perf_probe_arg { |
57 | char *name; /* Argument name */ | 58 | char *name; /* Argument name */ |
59 | char *var; /* Variable name */ | ||
60 | char *type; /* Type name */ | ||
58 | struct perf_probe_arg_field *field; /* Structure fields */ | 61 | struct perf_probe_arg_field *field; /* Structure fields */ |
59 | }; | 62 | }; |
60 | 63 | ||
@@ -71,25 +74,25 @@ struct perf_probe_event { | |||
71 | /* Line number container */ | 74 | /* Line number container */ |
72 | struct line_node { | 75 | struct line_node { |
73 | struct list_head list; | 76 | struct list_head list; |
74 | unsigned int line; | 77 | int line; |
75 | }; | 78 | }; |
76 | 79 | ||
77 | /* Line range */ | 80 | /* Line range */ |
78 | struct line_range { | 81 | struct line_range { |
79 | char *file; /* File name */ | 82 | char *file; /* File name */ |
80 | char *function; /* Function name */ | 83 | char *function; /* Function name */ |
81 | unsigned int start; /* Start line number */ | 84 | int start; /* Start line number */ |
82 | unsigned int end; /* End line number */ | 85 | int end; /* End line number */ |
83 | int offset; /* Start line offset */ | 86 | int offset; /* Start line offset */ |
84 | char *path; /* Real path name */ | 87 | char *path; /* Real path name */ |
85 | struct list_head line_list; /* Visible lines */ | 88 | struct list_head line_list; /* Visible lines */ |
86 | }; | 89 | }; |
87 | 90 | ||
88 | /* Command string to events */ | 91 | /* Command string to events */ |
89 | extern void parse_perf_probe_command(const char *cmd, | 92 | extern int parse_perf_probe_command(const char *cmd, |
90 | struct perf_probe_event *pev); | 93 | struct perf_probe_event *pev); |
91 | extern void parse_kprobe_trace_command(const char *cmd, | 94 | extern int parse_kprobe_trace_command(const char *cmd, |
92 | struct kprobe_trace_event *tev); | 95 | struct kprobe_trace_event *tev); |
93 | 96 | ||
94 | /* Events to command string */ | 97 | /* Events to command string */ |
95 | extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); | 98 | extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); |
@@ -101,22 +104,22 @@ extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, | |||
101 | extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | 104 | extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); |
102 | 105 | ||
103 | /* Convert from kprobe_trace_event to perf_probe_event */ | 106 | /* Convert from kprobe_trace_event to perf_probe_event */ |
104 | extern void convert_to_perf_probe_event(struct kprobe_trace_event *tev, | 107 | extern int convert_to_perf_probe_event(struct kprobe_trace_event *tev, |
105 | struct perf_probe_event *pev); | 108 | struct perf_probe_event *pev); |
106 | 109 | ||
107 | /* Release event contents */ | 110 | /* Release event contents */ |
108 | extern void clear_perf_probe_event(struct perf_probe_event *pev); | 111 | extern void clear_perf_probe_event(struct perf_probe_event *pev); |
109 | extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev); | 112 | extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev); |
110 | 113 | ||
111 | /* Command string to line-range */ | 114 | /* Command string to line-range */ |
112 | extern void parse_line_range_desc(const char *cmd, struct line_range *lr); | 115 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); |
113 | 116 | ||
114 | 117 | ||
115 | extern void add_perf_probe_events(struct perf_probe_event *pevs, int ntevs, | 118 | extern int add_perf_probe_events(struct perf_probe_event *pevs, int ntevs, |
116 | bool force_add); | 119 | bool force_add); |
117 | extern void del_perf_probe_events(struct strlist *dellist); | 120 | extern int del_perf_probe_events(struct strlist *dellist); |
118 | extern void show_perf_probe_events(void); | 121 | extern int show_perf_probe_events(void); |
119 | extern void show_line_range(struct line_range *lr); | 122 | extern int show_line_range(struct line_range *lr); |
120 | 123 | ||
121 | 124 | ||
122 | /* Maximum index number of event-name postfix */ | 125 | /* Maximum index number of event-name postfix */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index a8513772df08..3e7977560be5 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -84,6 +84,9 @@ const char *x86_64_regs_table[X86_64_MAX_REGS] = { | |||
84 | #define arch_regs_table x86_32_regs_table | 84 | #define arch_regs_table x86_32_regs_table |
85 | #endif | 85 | #endif |
86 | 86 | ||
87 | /* Kprobe tracer basic type is up to u64 */ | ||
88 | #define MAX_BASIC_TYPE_BITS 64 | ||
89 | |||
87 | /* Return architecture dependent register string (for kprobe-tracer) */ | 90 | /* Return architecture dependent register string (for kprobe-tracer) */ |
88 | static const char *get_arch_regstr(unsigned int n) | 91 | static const char *get_arch_regstr(unsigned int n) |
89 | { | 92 | { |
@@ -108,7 +111,7 @@ static int strtailcmp(const char *s1, const char *s2) | |||
108 | /* Line number list operations */ | 111 | /* Line number list operations */ |
109 | 112 | ||
110 | /* Add a line to line number list */ | 113 | /* Add a line to line number list */ |
111 | static void line_list__add_line(struct list_head *head, unsigned int line) | 114 | static int line_list__add_line(struct list_head *head, int line) |
112 | { | 115 | { |
113 | struct line_node *ln; | 116 | struct line_node *ln; |
114 | struct list_head *p; | 117 | struct list_head *p; |
@@ -119,20 +122,23 @@ static void line_list__add_line(struct list_head *head, unsigned int line) | |||
119 | p = &ln->list; | 122 | p = &ln->list; |
120 | goto found; | 123 | goto found; |
121 | } else if (ln->line == line) /* Already exist */ | 124 | } else if (ln->line == line) /* Already exist */ |
122 | return ; | 125 | return 1; |
123 | } | 126 | } |
124 | /* List is empty, or the smallest entry */ | 127 | /* List is empty, or the smallest entry */ |
125 | p = head; | 128 | p = head; |
126 | found: | 129 | found: |
127 | pr_debug("line list: add a line %u\n", line); | 130 | pr_debug("line list: add a line %u\n", line); |
128 | ln = xzalloc(sizeof(struct line_node)); | 131 | ln = zalloc(sizeof(struct line_node)); |
132 | if (ln == NULL) | ||
133 | return -ENOMEM; | ||
129 | ln->line = line; | 134 | ln->line = line; |
130 | INIT_LIST_HEAD(&ln->list); | 135 | INIT_LIST_HEAD(&ln->list); |
131 | list_add(&ln->list, p); | 136 | list_add(&ln->list, p); |
137 | return 0; | ||
132 | } | 138 | } |
133 | 139 | ||
134 | /* Check if the line in line number list */ | 140 | /* Check if the line in line number list */ |
135 | static int line_list__has_line(struct list_head *head, unsigned int line) | 141 | static int line_list__has_line(struct list_head *head, int line) |
136 | { | 142 | { |
137 | struct line_node *ln; | 143 | struct line_node *ln; |
138 | 144 | ||
@@ -193,19 +199,7 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | |||
193 | { | 199 | { |
194 | const char *name; | 200 | const char *name; |
195 | name = dwarf_diename(dw_die); | 201 | name = dwarf_diename(dw_die); |
196 | DIE_IF(name == NULL); | 202 | return name ? strcmp(tname, name) : -1; |
197 | return strcmp(tname, name); | ||
198 | } | ||
199 | |||
200 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | ||
201 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | ||
202 | { | ||
203 | Dwarf_Addr epc; | ||
204 | int ret; | ||
205 | |||
206 | ret = dwarf_entrypc(dw_die, &epc); | ||
207 | DIE_IF(ret == -1); | ||
208 | return epc; | ||
209 | } | 203 | } |
210 | 204 | ||
211 | /* Get type die, but skip qualifiers and typedef */ | 205 | /* Get type die, but skip qualifiers and typedef */ |
@@ -230,6 +224,58 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | |||
230 | return die_mem; | 224 | return die_mem; |
231 | } | 225 | } |
232 | 226 | ||
227 | static bool die_is_signed_type(Dwarf_Die *tp_die) | ||
228 | { | ||
229 | Dwarf_Attribute attr; | ||
230 | Dwarf_Word ret; | ||
231 | |||
232 | if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || | ||
233 | dwarf_formudata(&attr, &ret) != 0) | ||
234 | return false; | ||
235 | |||
236 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || | ||
237 | ret == DW_ATE_signed_fixed); | ||
238 | } | ||
239 | |||
240 | static int die_get_byte_size(Dwarf_Die *tp_die) | ||
241 | { | ||
242 | Dwarf_Attribute attr; | ||
243 | Dwarf_Word ret; | ||
244 | |||
245 | if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || | ||
246 | dwarf_formudata(&attr, &ret) != 0) | ||
247 | return 0; | ||
248 | |||
249 | return (int)ret; | ||
250 | } | ||
251 | |||
252 | /* Get data_member_location offset */ | ||
253 | static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | ||
254 | { | ||
255 | Dwarf_Attribute attr; | ||
256 | Dwarf_Op *expr; | ||
257 | size_t nexpr; | ||
258 | int ret; | ||
259 | |||
260 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) | ||
261 | return -ENOENT; | ||
262 | |||
263 | if (dwarf_formudata(&attr, offs) != 0) { | ||
264 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ | ||
265 | ret = dwarf_getlocation(&attr, &expr, &nexpr); | ||
266 | if (ret < 0 || nexpr == 0) | ||
267 | return -ENOENT; | ||
268 | |||
269 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { | ||
270 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", | ||
271 | expr[0].atom, nexpr); | ||
272 | return -ENOTSUP; | ||
273 | } | ||
274 | *offs = (Dwarf_Word)expr[0].number; | ||
275 | } | ||
276 | return 0; | ||
277 | } | ||
278 | |||
233 | /* Return values for die_find callbacks */ | 279 | /* Return values for die_find callbacks */ |
234 | enum { | 280 | enum { |
235 | DIE_FIND_CB_FOUND = 0, /* End of Search */ | 281 | DIE_FIND_CB_FOUND = 0, /* End of Search */ |
@@ -362,7 +408,7 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | |||
362 | */ | 408 | */ |
363 | 409 | ||
364 | /* Show a location */ | 410 | /* Show a location */ |
365 | static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | 411 | static int convert_location(Dwarf_Op *op, struct probe_finder *pf) |
366 | { | 412 | { |
367 | unsigned int regn; | 413 | unsigned int regn; |
368 | Dwarf_Word offs = 0; | 414 | Dwarf_Word offs = 0; |
@@ -370,11 +416,13 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | |||
370 | const char *regs; | 416 | const char *regs; |
371 | struct kprobe_trace_arg *tvar = pf->tvar; | 417 | struct kprobe_trace_arg *tvar = pf->tvar; |
372 | 418 | ||
373 | /* TODO: support CFA */ | ||
374 | /* If this is based on frame buffer, set the offset */ | 419 | /* If this is based on frame buffer, set the offset */ |
375 | if (op->atom == DW_OP_fbreg) { | 420 | if (op->atom == DW_OP_fbreg) { |
376 | if (pf->fb_ops == NULL) | 421 | if (pf->fb_ops == NULL) { |
377 | die("The attribute of frame base is not supported.\n"); | 422 | pr_warning("The attribute of frame base is not " |
423 | "supported.\n"); | ||
424 | return -ENOTSUP; | ||
425 | } | ||
378 | ref = true; | 426 | ref = true; |
379 | offs = op->number; | 427 | offs = op->number; |
380 | op = &pf->fb_ops[0]; | 428 | op = &pf->fb_ops[0]; |
@@ -392,84 +440,155 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | |||
392 | ref = true; | 440 | ref = true; |
393 | } else if (op->atom == DW_OP_regx) { | 441 | } else if (op->atom == DW_OP_regx) { |
394 | regn = op->number; | 442 | regn = op->number; |
395 | } else | 443 | } else { |
396 | die("DW_OP %d is not supported.", op->atom); | 444 | pr_warning("DW_OP %x is not supported.\n", op->atom); |
445 | return -ENOTSUP; | ||
446 | } | ||
397 | 447 | ||
398 | regs = get_arch_regstr(regn); | 448 | regs = get_arch_regstr(regn); |
399 | if (!regs) | 449 | if (!regs) { |
400 | die("%u exceeds max register number.", regn); | 450 | pr_warning("%u exceeds max register number.\n", regn); |
451 | return -ERANGE; | ||
452 | } | ||
453 | |||
454 | tvar->value = strdup(regs); | ||
455 | if (tvar->value == NULL) | ||
456 | return -ENOMEM; | ||
401 | 457 | ||
402 | tvar->value = xstrdup(regs); | ||
403 | if (ref) { | 458 | if (ref) { |
404 | tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); | 459 | tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); |
460 | if (tvar->ref == NULL) | ||
461 | return -ENOMEM; | ||
405 | tvar->ref->offset = (long)offs; | 462 | tvar->ref->offset = (long)offs; |
406 | } | 463 | } |
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int convert_variable_type(Dwarf_Die *vr_die, | ||
468 | struct kprobe_trace_arg *targ) | ||
469 | { | ||
470 | Dwarf_Die type; | ||
471 | char buf[16]; | ||
472 | int ret; | ||
473 | |||
474 | if (die_get_real_type(vr_die, &type) == NULL) { | ||
475 | pr_warning("Failed to get a type information of %s.\n", | ||
476 | dwarf_diename(vr_die)); | ||
477 | return -ENOENT; | ||
478 | } | ||
479 | |||
480 | ret = die_get_byte_size(&type) * 8; | ||
481 | if (ret) { | ||
482 | /* Check the bitwidth */ | ||
483 | if (ret > MAX_BASIC_TYPE_BITS) { | ||
484 | pr_info("%s exceeds max-bitwidth." | ||
485 | " Cut down to %d bits.\n", | ||
486 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); | ||
487 | ret = MAX_BASIC_TYPE_BITS; | ||
488 | } | ||
489 | |||
490 | ret = snprintf(buf, 16, "%c%d", | ||
491 | die_is_signed_type(&type) ? 's' : 'u', ret); | ||
492 | if (ret < 0 || ret >= 16) { | ||
493 | if (ret >= 16) | ||
494 | ret = -E2BIG; | ||
495 | pr_warning("Failed to convert variable type: %s\n", | ||
496 | strerror(-ret)); | ||
497 | return ret; | ||
498 | } | ||
499 | targ->type = strdup(buf); | ||
500 | if (targ->type == NULL) | ||
501 | return -ENOMEM; | ||
502 | } | ||
503 | return 0; | ||
407 | } | 504 | } |
408 | 505 | ||
409 | static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | 506 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, |
410 | struct perf_probe_arg_field *field, | 507 | struct perf_probe_arg_field *field, |
411 | struct kprobe_trace_arg_ref **ref_ptr) | 508 | struct kprobe_trace_arg_ref **ref_ptr, |
509 | Dwarf_Die *die_mem) | ||
412 | { | 510 | { |
413 | struct kprobe_trace_arg_ref *ref = *ref_ptr; | 511 | struct kprobe_trace_arg_ref *ref = *ref_ptr; |
414 | Dwarf_Attribute attr; | ||
415 | Dwarf_Die member; | ||
416 | Dwarf_Die type; | 512 | Dwarf_Die type; |
417 | Dwarf_Word offs; | 513 | Dwarf_Word offs; |
514 | int ret; | ||
418 | 515 | ||
419 | pr_debug("converting %s in %s\n", field->name, varname); | 516 | pr_debug("converting %s in %s\n", field->name, varname); |
420 | if (die_get_real_type(vr_die, &type) == NULL) | 517 | if (die_get_real_type(vr_die, &type) == NULL) { |
421 | die("Failed to get a type information of %s.", varname); | 518 | pr_warning("Failed to get the type of %s.\n", varname); |
519 | return -ENOENT; | ||
520 | } | ||
422 | 521 | ||
423 | /* Check the pointer and dereference */ | 522 | /* Check the pointer and dereference */ |
424 | if (dwarf_tag(&type) == DW_TAG_pointer_type) { | 523 | if (dwarf_tag(&type) == DW_TAG_pointer_type) { |
425 | if (!field->ref) | 524 | if (!field->ref) { |
426 | die("Semantic error: %s must be referred by '->'", | 525 | pr_err("Semantic error: %s must be referred by '->'\n", |
427 | field->name); | 526 | field->name); |
527 | return -EINVAL; | ||
528 | } | ||
428 | /* Get the type pointed by this pointer */ | 529 | /* Get the type pointed by this pointer */ |
429 | if (die_get_real_type(&type, &type) == NULL) | 530 | if (die_get_real_type(&type, &type) == NULL) { |
430 | die("Failed to get a type information of %s.", varname); | 531 | pr_warning("Failed to get the type of %s.\n", varname); |
431 | 532 | return -ENOENT; | |
533 | } | ||
432 | /* Verify it is a data structure */ | 534 | /* Verify it is a data structure */ |
433 | if (dwarf_tag(&type) != DW_TAG_structure_type) | 535 | if (dwarf_tag(&type) != DW_TAG_structure_type) { |
434 | die("%s is not a data structure.", varname); | 536 | pr_warning("%s is not a data structure.\n", varname); |
537 | return -EINVAL; | ||
538 | } | ||
435 | 539 | ||
436 | ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); | 540 | ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); |
541 | if (ref == NULL) | ||
542 | return -ENOMEM; | ||
437 | if (*ref_ptr) | 543 | if (*ref_ptr) |
438 | (*ref_ptr)->next = ref; | 544 | (*ref_ptr)->next = ref; |
439 | else | 545 | else |
440 | *ref_ptr = ref; | 546 | *ref_ptr = ref; |
441 | } else { | 547 | } else { |
442 | /* Verify it is a data structure */ | 548 | /* Verify it is a data structure */ |
443 | if (dwarf_tag(&type) != DW_TAG_structure_type) | 549 | if (dwarf_tag(&type) != DW_TAG_structure_type) { |
444 | die("%s is not a data structure.", varname); | 550 | pr_warning("%s is not a data structure.\n", varname); |
445 | 551 | return -EINVAL; | |
446 | if (field->ref) | 552 | } |
447 | die("Semantic error: %s must be referred by '.'", | 553 | if (field->ref) { |
448 | field->name); | 554 | pr_err("Semantic error: %s must be referred by '.'\n", |
449 | if (!ref) | 555 | field->name); |
450 | die("Structure on a register is not supported yet."); | 556 | return -EINVAL; |
557 | } | ||
558 | if (!ref) { | ||
559 | pr_warning("Structure on a register is not " | ||
560 | "supported yet.\n"); | ||
561 | return -ENOTSUP; | ||
562 | } | ||
451 | } | 563 | } |
452 | 564 | ||
453 | if (die_find_member(&type, field->name, &member) == NULL) | 565 | if (die_find_member(&type, field->name, die_mem) == NULL) { |
454 | die("%s(tyep:%s) has no member %s.", varname, | 566 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, |
455 | dwarf_diename(&type), field->name); | 567 | dwarf_diename(&type), field->name); |
568 | return -EINVAL; | ||
569 | } | ||
456 | 570 | ||
457 | /* Get the offset of the field */ | 571 | /* Get the offset of the field */ |
458 | if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL || | 572 | ret = die_get_data_member_location(die_mem, &offs); |
459 | dwarf_formudata(&attr, &offs) != 0) | 573 | if (ret < 0) { |
460 | die("Failed to get the offset of %s.", field->name); | 574 | pr_warning("Failed to get the offset of %s.\n", field->name); |
575 | return ret; | ||
576 | } | ||
461 | ref->offset += (long)offs; | 577 | ref->offset += (long)offs; |
462 | 578 | ||
463 | /* Converting next field */ | 579 | /* Converting next field */ |
464 | if (field->next) | 580 | if (field->next) |
465 | convert_variable_fields(&member, field->name, field->next, | 581 | return convert_variable_fields(die_mem, field->name, |
466 | &ref); | 582 | field->next, &ref, die_mem); |
583 | else | ||
584 | return 0; | ||
467 | } | 585 | } |
468 | 586 | ||
469 | /* Show a variables in kprobe event format */ | 587 | /* Show a variables in kprobe event format */ |
470 | static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 588 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
471 | { | 589 | { |
472 | Dwarf_Attribute attr; | 590 | Dwarf_Attribute attr; |
591 | Dwarf_Die die_mem; | ||
473 | Dwarf_Op *expr; | 592 | Dwarf_Op *expr; |
474 | size_t nexpr; | 593 | size_t nexpr; |
475 | int ret; | 594 | int ret; |
@@ -481,44 +600,74 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
481 | if (ret <= 0 || nexpr == 0) | 600 | if (ret <= 0 || nexpr == 0) |
482 | goto error; | 601 | goto error; |
483 | 602 | ||
484 | convert_location(expr, pf); | 603 | ret = convert_location(expr, pf); |
485 | 604 | if (ret == 0 && pf->pvar->field) { | |
486 | if (pf->pvar->field) | 605 | ret = convert_variable_fields(vr_die, pf->pvar->var, |
487 | convert_variable_fields(vr_die, pf->pvar->name, | 606 | pf->pvar->field, &pf->tvar->ref, |
488 | pf->pvar->field, &pf->tvar->ref); | 607 | &die_mem); |
608 | vr_die = &die_mem; | ||
609 | } | ||
610 | if (ret == 0) { | ||
611 | if (pf->pvar->type) { | ||
612 | pf->tvar->type = strdup(pf->pvar->type); | ||
613 | if (pf->tvar->type == NULL) | ||
614 | ret = -ENOMEM; | ||
615 | } else | ||
616 | ret = convert_variable_type(vr_die, pf->tvar); | ||
617 | } | ||
489 | /* *expr will be cached in libdw. Don't free it. */ | 618 | /* *expr will be cached in libdw. Don't free it. */ |
490 | return ; | 619 | return ret; |
491 | error: | 620 | error: |
492 | /* TODO: Support const_value */ | 621 | /* TODO: Support const_value */ |
493 | die("Failed to find the location of %s at this address.\n" | 622 | pr_err("Failed to find the location of %s at this address.\n" |
494 | " Perhaps, it has been optimized out.", pf->pvar->name); | 623 | " Perhaps, it has been optimized out.\n", pf->pvar->var); |
624 | return -ENOENT; | ||
495 | } | 625 | } |
496 | 626 | ||
497 | /* Find a variable in a subprogram die */ | 627 | /* Find a variable in a subprogram die */ |
498 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 628 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
499 | { | 629 | { |
500 | Dwarf_Die vr_die; | 630 | Dwarf_Die vr_die; |
501 | char buf[128]; | 631 | char buf[32], *ptr; |
632 | int ret; | ||
633 | |||
634 | /* TODO: Support arrays */ | ||
635 | if (pf->pvar->name) | ||
636 | pf->tvar->name = strdup(pf->pvar->name); | ||
637 | else { | ||
638 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); | ||
639 | if (ret < 0) | ||
640 | return ret; | ||
641 | ptr = strchr(buf, ':'); /* Change type separator to _ */ | ||
642 | if (ptr) | ||
643 | *ptr = '_'; | ||
644 | pf->tvar->name = strdup(buf); | ||
645 | } | ||
646 | if (pf->tvar->name == NULL) | ||
647 | return -ENOMEM; | ||
502 | 648 | ||
503 | /* TODO: Support struct members and arrays */ | 649 | if (!is_c_varname(pf->pvar->var)) { |
504 | if (!is_c_varname(pf->pvar->name)) { | ||
505 | /* Copy raw parameters */ | 650 | /* Copy raw parameters */ |
506 | pf->tvar->value = xstrdup(pf->pvar->name); | 651 | pf->tvar->value = strdup(pf->pvar->var); |
507 | } else { | 652 | if (pf->tvar->value == NULL) |
508 | synthesize_perf_probe_arg(pf->pvar, buf, 128); | 653 | return -ENOMEM; |
509 | pf->tvar->name = xstrdup(buf); | 654 | else |
510 | pr_debug("Searching '%s' variable in context.\n", | 655 | return 0; |
511 | pf->pvar->name); | 656 | } |
512 | /* Search child die for local variables and parameters. */ | 657 | |
513 | if (!die_find_variable(sp_die, pf->pvar->name, &vr_die)) | 658 | pr_debug("Searching '%s' variable in context.\n", |
514 | die("Failed to find '%s' in this function.", | 659 | pf->pvar->var); |
515 | pf->pvar->name); | 660 | /* Search child die for local variables and parameters. */ |
516 | convert_variable(&vr_die, pf); | 661 | if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { |
662 | pr_warning("Failed to find '%s' in this function.\n", | ||
663 | pf->pvar->var); | ||
664 | return -ENOENT; | ||
517 | } | 665 | } |
666 | return convert_variable(&vr_die, pf); | ||
518 | } | 667 | } |
519 | 668 | ||
520 | /* Show a probe point to output buffer */ | 669 | /* Show a probe point to output buffer */ |
521 | static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | 670 | static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) |
522 | { | 671 | { |
523 | struct kprobe_trace_event *tev; | 672 | struct kprobe_trace_event *tev; |
524 | Dwarf_Addr eaddr; | 673 | Dwarf_Addr eaddr; |
@@ -528,23 +677,34 @@ static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
528 | Dwarf_Attribute fb_attr; | 677 | Dwarf_Attribute fb_attr; |
529 | size_t nops; | 678 | size_t nops; |
530 | 679 | ||
531 | if (pf->ntevs == MAX_PROBES) | 680 | if (pf->ntevs == MAX_PROBES) { |
532 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | 681 | pr_warning("Too many( > %d) probe point found.\n", MAX_PROBES); |
682 | return -ERANGE; | ||
683 | } | ||
533 | tev = &pf->tevs[pf->ntevs++]; | 684 | tev = &pf->tevs[pf->ntevs++]; |
534 | 685 | ||
535 | /* If no real subprogram, find a real one */ | 686 | /* If no real subprogram, find a real one */ |
536 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 687 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { |
537 | sp_die = die_find_real_subprogram(&pf->cu_die, | 688 | sp_die = die_find_real_subprogram(&pf->cu_die, |
538 | pf->addr, &die_mem); | 689 | pf->addr, &die_mem); |
539 | if (!sp_die) | 690 | if (!sp_die) { |
540 | die("Probe point is not found in subprograms."); | 691 | pr_warning("Failed to find probe point in any " |
692 | "functions.\n"); | ||
693 | return -ENOENT; | ||
694 | } | ||
541 | } | 695 | } |
542 | 696 | ||
543 | /* Copy the name of probe point */ | 697 | /* Copy the name of probe point */ |
544 | name = dwarf_diename(sp_die); | 698 | name = dwarf_diename(sp_die); |
545 | if (name) { | 699 | if (name) { |
546 | dwarf_entrypc(sp_die, &eaddr); | 700 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
547 | tev->point.symbol = xstrdup(name); | 701 | pr_warning("Failed to get entry pc of %s\n", |
702 | dwarf_diename(sp_die)); | ||
703 | return -ENOENT; | ||
704 | } | ||
705 | tev->point.symbol = strdup(name); | ||
706 | if (tev->point.symbol == NULL) | ||
707 | return -ENOMEM; | ||
548 | tev->point.offset = (unsigned long)(pf->addr - eaddr); | 708 | tev->point.offset = (unsigned long)(pf->addr - eaddr); |
549 | } else | 709 | } else |
550 | /* This function has no name. */ | 710 | /* This function has no name. */ |
@@ -556,55 +716,74 @@ static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
556 | /* Get the frame base attribute/ops */ | 716 | /* Get the frame base attribute/ops */ |
557 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 717 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); |
558 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 718 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
559 | if (ret <= 0 || nops == 0) | 719 | if (ret <= 0 || nops == 0) { |
560 | pf->fb_ops = NULL; | 720 | pf->fb_ops = NULL; |
721 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && | ||
722 | pf->cfi != NULL) { | ||
723 | Dwarf_Frame *frame; | ||
724 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || | ||
725 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { | ||
726 | pr_warning("Failed to get CFA on 0x%jx\n", | ||
727 | (uintmax_t)pf->addr); | ||
728 | return -ENOENT; | ||
729 | } | ||
730 | } | ||
561 | 731 | ||
562 | /* Find each argument */ | 732 | /* Find each argument */ |
563 | /* TODO: use dwarf_cfi_addrframe */ | ||
564 | tev->nargs = pf->pev->nargs; | 733 | tev->nargs = pf->pev->nargs; |
565 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); | 734 | tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); |
735 | if (tev->args == NULL) | ||
736 | return -ENOMEM; | ||
566 | for (i = 0; i < pf->pev->nargs; i++) { | 737 | for (i = 0; i < pf->pev->nargs; i++) { |
567 | pf->pvar = &pf->pev->args[i]; | 738 | pf->pvar = &pf->pev->args[i]; |
568 | pf->tvar = &tev->args[i]; | 739 | pf->tvar = &tev->args[i]; |
569 | find_variable(sp_die, pf); | 740 | ret = find_variable(sp_die, pf); |
741 | if (ret != 0) | ||
742 | return ret; | ||
570 | } | 743 | } |
571 | 744 | ||
572 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 745 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
573 | pf->fb_ops = NULL; | 746 | pf->fb_ops = NULL; |
747 | return 0; | ||
574 | } | 748 | } |
575 | 749 | ||
576 | /* Find probe point from its line number */ | 750 | /* Find probe point from its line number */ |
577 | static void find_probe_point_by_line(struct probe_finder *pf) | 751 | static int find_probe_point_by_line(struct probe_finder *pf) |
578 | { | 752 | { |
579 | Dwarf_Lines *lines; | 753 | Dwarf_Lines *lines; |
580 | Dwarf_Line *line; | 754 | Dwarf_Line *line; |
581 | size_t nlines, i; | 755 | size_t nlines, i; |
582 | Dwarf_Addr addr; | 756 | Dwarf_Addr addr; |
583 | int lineno; | 757 | int lineno; |
584 | int ret; | 758 | int ret = 0; |
585 | 759 | ||
586 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); | 760 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
587 | DIE_IF(ret != 0); | 761 | pr_warning("No source lines found in this CU.\n"); |
762 | return -ENOENT; | ||
763 | } | ||
588 | 764 | ||
589 | for (i = 0; i < nlines; i++) { | 765 | for (i = 0; i < nlines && ret == 0; i++) { |
590 | line = dwarf_onesrcline(lines, i); | 766 | line = dwarf_onesrcline(lines, i); |
591 | dwarf_lineno(line, &lineno); | 767 | if (dwarf_lineno(line, &lineno) != 0 || |
592 | if (lineno != pf->lno) | 768 | lineno != pf->lno) |
593 | continue; | 769 | continue; |
594 | 770 | ||
595 | /* TODO: Get fileno from line, but how? */ | 771 | /* TODO: Get fileno from line, but how? */ |
596 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 772 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
597 | continue; | 773 | continue; |
598 | 774 | ||
599 | ret = dwarf_lineaddr(line, &addr); | 775 | if (dwarf_lineaddr(line, &addr) != 0) { |
600 | DIE_IF(ret != 0); | 776 | pr_warning("Failed to get the address of the line.\n"); |
777 | return -ENOENT; | ||
778 | } | ||
601 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", | 779 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", |
602 | (int)i, lineno, (uintmax_t)addr); | 780 | (int)i, lineno, (uintmax_t)addr); |
603 | pf->addr = addr; | 781 | pf->addr = addr; |
604 | 782 | ||
605 | convert_probe_point(NULL, pf); | 783 | ret = convert_probe_point(NULL, pf); |
606 | /* Continuing, because target line might be inlined. */ | 784 | /* Continuing, because target line might be inlined. */ |
607 | } | 785 | } |
786 | return ret; | ||
608 | } | 787 | } |
609 | 788 | ||
610 | /* Find lines which match lazy pattern */ | 789 | /* Find lines which match lazy pattern */ |
@@ -612,15 +791,27 @@ static int find_lazy_match_lines(struct list_head *head, | |||
612 | const char *fname, const char *pat) | 791 | const char *fname, const char *pat) |
613 | { | 792 | { |
614 | char *fbuf, *p1, *p2; | 793 | char *fbuf, *p1, *p2; |
615 | int fd, line, nlines = 0; | 794 | int fd, ret, line, nlines = 0; |
616 | struct stat st; | 795 | struct stat st; |
617 | 796 | ||
618 | fd = open(fname, O_RDONLY); | 797 | fd = open(fname, O_RDONLY); |
619 | if (fd < 0) | 798 | if (fd < 0) { |
620 | die("failed to open %s", fname); | 799 | pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); |
621 | DIE_IF(fstat(fd, &st) < 0); | 800 | return fd; |
801 | } | ||
802 | |||
803 | ret = fstat(fd, &st); | ||
804 | if (ret < 0) { | ||
805 | pr_warning("Failed to get the size of %s: %s\n", | ||
806 | fname, strerror(errno)); | ||
807 | return ret; | ||
808 | } | ||
622 | fbuf = xmalloc(st.st_size + 2); | 809 | fbuf = xmalloc(st.st_size + 2); |
623 | DIE_IF(read(fd, fbuf, st.st_size) < 0); | 810 | ret = read(fd, fbuf, st.st_size); |
811 | if (ret < 0) { | ||
812 | pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); | ||
813 | return ret; | ||
814 | } | ||
624 | close(fd); | 815 | close(fd); |
625 | fbuf[st.st_size] = '\n'; /* Dummy line */ | 816 | fbuf[st.st_size] = '\n'; /* Dummy line */ |
626 | fbuf[st.st_size + 1] = '\0'; | 817 | fbuf[st.st_size + 1] = '\0'; |
@@ -640,7 +831,7 @@ static int find_lazy_match_lines(struct list_head *head, | |||
640 | } | 831 | } |
641 | 832 | ||
642 | /* Find probe points from lazy pattern */ | 833 | /* Find probe points from lazy pattern */ |
643 | static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 834 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
644 | { | 835 | { |
645 | Dwarf_Lines *lines; | 836 | Dwarf_Lines *lines; |
646 | Dwarf_Line *line; | 837 | Dwarf_Line *line; |
@@ -648,31 +839,40 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
648 | Dwarf_Addr addr; | 839 | Dwarf_Addr addr; |
649 | Dwarf_Die die_mem; | 840 | Dwarf_Die die_mem; |
650 | int lineno; | 841 | int lineno; |
651 | int ret; | 842 | int ret = 0; |
652 | 843 | ||
653 | if (list_empty(&pf->lcache)) { | 844 | if (list_empty(&pf->lcache)) { |
654 | /* Matching lazy line pattern */ | 845 | /* Matching lazy line pattern */ |
655 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 846 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
656 | pf->pev->point.lazy_line); | 847 | pf->pev->point.lazy_line); |
657 | if (ret <= 0) | 848 | if (ret == 0) { |
658 | die("No matched lines found in %s.", pf->fname); | 849 | pr_debug("No matched lines found in %s.\n", pf->fname); |
850 | return 0; | ||
851 | } else if (ret < 0) | ||
852 | return ret; | ||
659 | } | 853 | } |
660 | 854 | ||
661 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); | 855 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
662 | DIE_IF(ret != 0); | 856 | pr_warning("No source lines found in this CU.\n"); |
663 | for (i = 0; i < nlines; i++) { | 857 | return -ENOENT; |
858 | } | ||
859 | |||
860 | for (i = 0; i < nlines && ret >= 0; i++) { | ||
664 | line = dwarf_onesrcline(lines, i); | 861 | line = dwarf_onesrcline(lines, i); |
665 | 862 | ||
666 | dwarf_lineno(line, &lineno); | 863 | if (dwarf_lineno(line, &lineno) != 0 || |
667 | if (!line_list__has_line(&pf->lcache, lineno)) | 864 | !line_list__has_line(&pf->lcache, lineno)) |
668 | continue; | 865 | continue; |
669 | 866 | ||
670 | /* TODO: Get fileno from line, but how? */ | 867 | /* TODO: Get fileno from line, but how? */ |
671 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 868 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
672 | continue; | 869 | continue; |
673 | 870 | ||
674 | ret = dwarf_lineaddr(line, &addr); | 871 | if (dwarf_lineaddr(line, &addr) != 0) { |
675 | DIE_IF(ret != 0); | 872 | pr_debug("Failed to get the address of line %d.\n", |
873 | lineno); | ||
874 | continue; | ||
875 | } | ||
676 | if (sp_die) { | 876 | if (sp_die) { |
677 | /* Address filtering 1: does sp_die include addr? */ | 877 | /* Address filtering 1: does sp_die include addr? */ |
678 | if (!dwarf_haspc(sp_die, addr)) | 878 | if (!dwarf_haspc(sp_die, addr)) |
@@ -686,27 +886,42 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
686 | (int)i, lineno, (unsigned long long)addr); | 886 | (int)i, lineno, (unsigned long long)addr); |
687 | pf->addr = addr; | 887 | pf->addr = addr; |
688 | 888 | ||
689 | convert_probe_point(sp_die, pf); | 889 | ret = convert_probe_point(sp_die, pf); |
690 | /* Continuing, because target line might be inlined. */ | 890 | /* Continuing, because target line might be inlined. */ |
691 | } | 891 | } |
692 | /* TODO: deallocate lines, but how? */ | 892 | /* TODO: deallocate lines, but how? */ |
893 | return ret; | ||
693 | } | 894 | } |
694 | 895 | ||
896 | /* Callback parameter with return value */ | ||
897 | struct dwarf_callback_param { | ||
898 | void *data; | ||
899 | int retval; | ||
900 | }; | ||
901 | |||
695 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 902 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
696 | { | 903 | { |
697 | struct probe_finder *pf = (struct probe_finder *)data; | 904 | struct dwarf_callback_param *param = data; |
905 | struct probe_finder *pf = param->data; | ||
698 | struct perf_probe_point *pp = &pf->pev->point; | 906 | struct perf_probe_point *pp = &pf->pev->point; |
907 | Dwarf_Addr addr; | ||
699 | 908 | ||
700 | if (pp->lazy_line) | 909 | if (pp->lazy_line) |
701 | find_probe_point_lazy(in_die, pf); | 910 | param->retval = find_probe_point_lazy(in_die, pf); |
702 | else { | 911 | else { |
703 | /* Get probe address */ | 912 | /* Get probe address */ |
704 | pf->addr = die_get_entrypc(in_die); | 913 | if (dwarf_entrypc(in_die, &addr) != 0) { |
914 | pr_warning("Failed to get entry pc of %s.\n", | ||
915 | dwarf_diename(in_die)); | ||
916 | param->retval = -ENOENT; | ||
917 | return DWARF_CB_ABORT; | ||
918 | } | ||
919 | pf->addr = addr; | ||
705 | pf->addr += pp->offset; | 920 | pf->addr += pp->offset; |
706 | pr_debug("found inline addr: 0x%jx\n", | 921 | pr_debug("found inline addr: 0x%jx\n", |
707 | (uintmax_t)pf->addr); | 922 | (uintmax_t)pf->addr); |
708 | 923 | ||
709 | convert_probe_point(in_die, pf); | 924 | param->retval = convert_probe_point(in_die, pf); |
710 | } | 925 | } |
711 | 926 | ||
712 | return DWARF_CB_OK; | 927 | return DWARF_CB_OK; |
@@ -715,39 +930,53 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | |||
715 | /* Search function from function name */ | 930 | /* Search function from function name */ |
716 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 931 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
717 | { | 932 | { |
718 | struct probe_finder *pf = (struct probe_finder *)data; | 933 | struct dwarf_callback_param *param = data; |
934 | struct probe_finder *pf = param->data; | ||
719 | struct perf_probe_point *pp = &pf->pev->point; | 935 | struct perf_probe_point *pp = &pf->pev->point; |
720 | 936 | ||
721 | /* Check tag and diename */ | 937 | /* Check tag and diename */ |
722 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 938 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
723 | die_compare_name(sp_die, pp->function) != 0) | 939 | die_compare_name(sp_die, pp->function) != 0) |
724 | return 0; | 940 | return DWARF_CB_OK; |
725 | 941 | ||
726 | pf->fname = dwarf_decl_file(sp_die); | 942 | pf->fname = dwarf_decl_file(sp_die); |
727 | if (pp->line) { /* Function relative line */ | 943 | if (pp->line) { /* Function relative line */ |
728 | dwarf_decl_line(sp_die, &pf->lno); | 944 | dwarf_decl_line(sp_die, &pf->lno); |
729 | pf->lno += pp->line; | 945 | pf->lno += pp->line; |
730 | find_probe_point_by_line(pf); | 946 | param->retval = find_probe_point_by_line(pf); |
731 | } else if (!dwarf_func_inline(sp_die)) { | 947 | } else if (!dwarf_func_inline(sp_die)) { |
732 | /* Real function */ | 948 | /* Real function */ |
733 | if (pp->lazy_line) | 949 | if (pp->lazy_line) |
734 | find_probe_point_lazy(sp_die, pf); | 950 | param->retval = find_probe_point_lazy(sp_die, pf); |
735 | else { | 951 | else { |
736 | pf->addr = die_get_entrypc(sp_die); | 952 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { |
953 | pr_warning("Failed to get entry pc of %s.\n", | ||
954 | dwarf_diename(sp_die)); | ||
955 | param->retval = -ENOENT; | ||
956 | return DWARF_CB_ABORT; | ||
957 | } | ||
737 | pf->addr += pp->offset; | 958 | pf->addr += pp->offset; |
738 | /* TODO: Check the address in this function */ | 959 | /* TODO: Check the address in this function */ |
739 | convert_probe_point(sp_die, pf); | 960 | param->retval = convert_probe_point(sp_die, pf); |
740 | } | 961 | } |
741 | } else | 962 | } else { |
963 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
964 | .retval = 0}; | ||
742 | /* Inlined function: search instances */ | 965 | /* Inlined function: search instances */ |
743 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); | 966 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, |
967 | &_param); | ||
968 | param->retval = _param.retval; | ||
969 | } | ||
744 | 970 | ||
745 | return 1; /* Exit; no same symbol in this CU. */ | 971 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
746 | } | 972 | } |
747 | 973 | ||
748 | static void find_probe_point_by_func(struct probe_finder *pf) | 974 | static int find_probe_point_by_func(struct probe_finder *pf) |
749 | { | 975 | { |
750 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); | 976 | struct dwarf_callback_param _param = {.data = (void *)pf, |
977 | .retval = 0}; | ||
978 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); | ||
979 | return _param.retval; | ||
751 | } | 980 | } |
752 | 981 | ||
753 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ | 982 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ |
@@ -760,19 +989,29 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
760 | size_t cuhl; | 989 | size_t cuhl; |
761 | Dwarf_Die *diep; | 990 | Dwarf_Die *diep; |
762 | Dwarf *dbg; | 991 | Dwarf *dbg; |
992 | int ret = 0; | ||
763 | 993 | ||
764 | pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); | 994 | pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); |
995 | if (pf.tevs == NULL) | ||
996 | return -ENOMEM; | ||
765 | *tevs = pf.tevs; | 997 | *tevs = pf.tevs; |
766 | pf.ntevs = 0; | 998 | pf.ntevs = 0; |
767 | 999 | ||
768 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1000 | dbg = dwarf_begin(fd, DWARF_C_READ); |
769 | if (!dbg) | 1001 | if (!dbg) { |
770 | return -ENOENT; | 1002 | pr_warning("No dwarf info found in the vmlinux - " |
1003 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1004 | return -EBADF; | ||
1005 | } | ||
1006 | |||
1007 | /* Get the call frame information from this dwarf */ | ||
1008 | pf.cfi = dwarf_getcfi(dbg); | ||
771 | 1009 | ||
772 | off = 0; | 1010 | off = 0; |
773 | line_list__init(&pf.lcache); | 1011 | line_list__init(&pf.lcache); |
774 | /* Loop on CUs (Compilation Unit) */ | 1012 | /* Loop on CUs (Compilation Unit) */ |
775 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | 1013 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && |
1014 | ret >= 0) { | ||
776 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1015 | /* Get the DIE(Debugging Information Entry) of this CU */ |
777 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); | 1016 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); |
778 | if (!diep) | 1017 | if (!diep) |
@@ -786,12 +1025,12 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
786 | 1025 | ||
787 | if (!pp->file || pf.fname) { | 1026 | if (!pp->file || pf.fname) { |
788 | if (pp->function) | 1027 | if (pp->function) |
789 | find_probe_point_by_func(&pf); | 1028 | ret = find_probe_point_by_func(&pf); |
790 | else if (pp->lazy_line) | 1029 | else if (pp->lazy_line) |
791 | find_probe_point_lazy(NULL, &pf); | 1030 | ret = find_probe_point_lazy(NULL, &pf); |
792 | else { | 1031 | else { |
793 | pf.lno = pp->line; | 1032 | pf.lno = pp->line; |
794 | find_probe_point_by_line(&pf); | 1033 | ret = find_probe_point_by_line(&pf); |
795 | } | 1034 | } |
796 | } | 1035 | } |
797 | off = noff; | 1036 | off = noff; |
@@ -799,7 +1038,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
799 | line_list__free(&pf.lcache); | 1038 | line_list__free(&pf.lcache); |
800 | dwarf_end(dbg); | 1039 | dwarf_end(dbg); |
801 | 1040 | ||
802 | return pf.ntevs; | 1041 | return (ret < 0) ? ret : pf.ntevs; |
803 | } | 1042 | } |
804 | 1043 | ||
805 | /* Reverse search */ | 1044 | /* Reverse search */ |
@@ -812,10 +1051,11 @@ int find_perf_probe_point(int fd, unsigned long addr, | |||
812 | Dwarf_Addr laddr, eaddr; | 1051 | Dwarf_Addr laddr, eaddr; |
813 | const char *tmp; | 1052 | const char *tmp; |
814 | int lineno, ret = 0; | 1053 | int lineno, ret = 0; |
1054 | bool found = false; | ||
815 | 1055 | ||
816 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1056 | dbg = dwarf_begin(fd, DWARF_C_READ); |
817 | if (!dbg) | 1057 | if (!dbg) |
818 | return -ENOENT; | 1058 | return -EBADF; |
819 | 1059 | ||
820 | /* Find cu die */ | 1060 | /* Find cu die */ |
821 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { | 1061 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { |
@@ -826,82 +1066,135 @@ int find_perf_probe_point(int fd, unsigned long addr, | |||
826 | /* Find a corresponding line */ | 1066 | /* Find a corresponding line */ |
827 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | 1067 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); |
828 | if (line) { | 1068 | if (line) { |
829 | dwarf_lineaddr(line, &laddr); | 1069 | if (dwarf_lineaddr(line, &laddr) == 0 && |
830 | if ((Dwarf_Addr)addr == laddr) { | 1070 | (Dwarf_Addr)addr == laddr && |
831 | dwarf_lineno(line, &lineno); | 1071 | dwarf_lineno(line, &lineno) == 0) { |
832 | ppt->line = lineno; | ||
833 | |||
834 | tmp = dwarf_linesrc(line, NULL, NULL); | 1072 | tmp = dwarf_linesrc(line, NULL, NULL); |
835 | DIE_IF(!tmp); | 1073 | if (tmp) { |
836 | ppt->file = xstrdup(tmp); | 1074 | ppt->line = lineno; |
837 | ret = 1; | 1075 | ppt->file = strdup(tmp); |
1076 | if (ppt->file == NULL) { | ||
1077 | ret = -ENOMEM; | ||
1078 | goto end; | ||
1079 | } | ||
1080 | found = true; | ||
1081 | } | ||
838 | } | 1082 | } |
839 | } | 1083 | } |
840 | 1084 | ||
841 | /* Find a corresponding function */ | 1085 | /* Find a corresponding function */ |
842 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1086 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
843 | tmp = dwarf_diename(&spdie); | 1087 | tmp = dwarf_diename(&spdie); |
844 | if (!tmp) | 1088 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) |
845 | goto end; | 1089 | goto end; |
846 | 1090 | ||
847 | dwarf_entrypc(&spdie, &eaddr); | 1091 | if (ppt->line) { |
848 | if (!lineno) { | 1092 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, |
849 | /* We don't have a line number, let's use offset */ | 1093 | &indie)) { |
850 | ppt->function = xstrdup(tmp); | 1094 | /* addr in an inline function */ |
851 | ppt->offset = addr - (unsigned long)eaddr; | 1095 | tmp = dwarf_diename(&indie); |
852 | ret = 1; | 1096 | if (!tmp) |
853 | goto end; | 1097 | goto end; |
1098 | ret = dwarf_decl_line(&indie, &lineno); | ||
1099 | } else { | ||
1100 | if (eaddr == addr) { /* Function entry */ | ||
1101 | lineno = ppt->line; | ||
1102 | ret = 0; | ||
1103 | } else | ||
1104 | ret = dwarf_decl_line(&spdie, &lineno); | ||
1105 | } | ||
1106 | if (ret == 0) { | ||
1107 | /* Make a relative line number */ | ||
1108 | ppt->line -= lineno; | ||
1109 | goto found; | ||
1110 | } | ||
854 | } | 1111 | } |
855 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) { | 1112 | /* We don't have a line number, let's use offset */ |
856 | /* addr in an inline function */ | 1113 | ppt->offset = addr - (unsigned long)eaddr; |
857 | tmp = dwarf_diename(&indie); | 1114 | found: |
858 | if (!tmp) | 1115 | ppt->function = strdup(tmp); |
859 | goto end; | 1116 | if (ppt->function == NULL) { |
860 | dwarf_decl_line(&indie, &lineno); | 1117 | ret = -ENOMEM; |
861 | } else { | 1118 | goto end; |
862 | if (eaddr == addr) /* No offset: function entry */ | ||
863 | lineno = ppt->line; | ||
864 | else | ||
865 | dwarf_decl_line(&spdie, &lineno); | ||
866 | } | 1119 | } |
867 | ppt->function = xstrdup(tmp); | 1120 | found = true; |
868 | ppt->line -= lineno; /* Make a relative line number */ | ||
869 | } | 1121 | } |
870 | 1122 | ||
871 | end: | 1123 | end: |
872 | dwarf_end(dbg); | 1124 | dwarf_end(dbg); |
1125 | if (ret >= 0) | ||
1126 | ret = found ? 1 : 0; | ||
873 | return ret; | 1127 | return ret; |
874 | } | 1128 | } |
875 | 1129 | ||
1130 | /* Add a line and store the src path */ | ||
1131 | static int line_range_add_line(const char *src, unsigned int lineno, | ||
1132 | struct line_range *lr) | ||
1133 | { | ||
1134 | /* Copy real path */ | ||
1135 | if (!lr->path) { | ||
1136 | lr->path = strdup(src); | ||
1137 | if (lr->path == NULL) | ||
1138 | return -ENOMEM; | ||
1139 | } | ||
1140 | return line_list__add_line(&lr->line_list, lineno); | ||
1141 | } | ||
1142 | |||
1143 | /* Search function declaration lines */ | ||
1144 | static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) | ||
1145 | { | ||
1146 | struct dwarf_callback_param *param = data; | ||
1147 | struct line_finder *lf = param->data; | ||
1148 | const char *src; | ||
1149 | int lineno; | ||
1150 | |||
1151 | src = dwarf_decl_file(sp_die); | ||
1152 | if (src && strtailcmp(src, lf->fname) != 0) | ||
1153 | return DWARF_CB_OK; | ||
1154 | |||
1155 | if (dwarf_decl_line(sp_die, &lineno) != 0 || | ||
1156 | (lf->lno_s > lineno || lf->lno_e < lineno)) | ||
1157 | return DWARF_CB_OK; | ||
1158 | |||
1159 | param->retval = line_range_add_line(src, lineno, lf->lr); | ||
1160 | return DWARF_CB_OK; | ||
1161 | } | ||
1162 | |||
1163 | static int find_line_range_func_decl_lines(struct line_finder *lf) | ||
1164 | { | ||
1165 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | ||
1166 | dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); | ||
1167 | return param.retval; | ||
1168 | } | ||
876 | 1169 | ||
877 | /* Find line range from its line number */ | 1170 | /* Find line range from its line number */ |
878 | static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1171 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
879 | { | 1172 | { |
880 | Dwarf_Lines *lines; | 1173 | Dwarf_Lines *lines; |
881 | Dwarf_Line *line; | 1174 | Dwarf_Line *line; |
882 | size_t nlines, i; | 1175 | size_t nlines, i; |
883 | Dwarf_Addr addr; | 1176 | Dwarf_Addr addr; |
884 | int lineno; | 1177 | int lineno, ret = 0; |
885 | int ret; | ||
886 | const char *src; | 1178 | const char *src; |
887 | Dwarf_Die die_mem; | 1179 | Dwarf_Die die_mem; |
888 | 1180 | ||
889 | line_list__init(&lf->lr->line_list); | 1181 | line_list__init(&lf->lr->line_list); |
890 | ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); | 1182 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { |
891 | DIE_IF(ret != 0); | 1183 | pr_warning("No source lines found in this CU.\n"); |
1184 | return -ENOENT; | ||
1185 | } | ||
892 | 1186 | ||
1187 | /* Search probable lines on lines list */ | ||
893 | for (i = 0; i < nlines; i++) { | 1188 | for (i = 0; i < nlines; i++) { |
894 | line = dwarf_onesrcline(lines, i); | 1189 | line = dwarf_onesrcline(lines, i); |
895 | ret = dwarf_lineno(line, &lineno); | 1190 | if (dwarf_lineno(line, &lineno) != 0 || |
896 | DIE_IF(ret != 0); | 1191 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
897 | if (lf->lno_s > lineno || lf->lno_e < lineno) | ||
898 | continue; | 1192 | continue; |
899 | 1193 | ||
900 | if (sp_die) { | 1194 | if (sp_die) { |
901 | /* Address filtering 1: does sp_die include addr? */ | 1195 | /* Address filtering 1: does sp_die include addr? */ |
902 | ret = dwarf_lineaddr(line, &addr); | 1196 | if (dwarf_lineaddr(line, &addr) != 0 || |
903 | DIE_IF(ret != 0); | 1197 | !dwarf_haspc(sp_die, addr)) |
904 | if (!dwarf_haspc(sp_die, addr)) | ||
905 | continue; | 1198 | continue; |
906 | 1199 | ||
907 | /* Address filtering 2: No child include addr? */ | 1200 | /* Address filtering 2: No child include addr? */ |
@@ -914,30 +1207,49 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
914 | if (strtailcmp(src, lf->fname) != 0) | 1207 | if (strtailcmp(src, lf->fname) != 0) |
915 | continue; | 1208 | continue; |
916 | 1209 | ||
917 | /* Copy real path */ | 1210 | ret = line_range_add_line(src, lineno, lf->lr); |
918 | if (!lf->lr->path) | 1211 | if (ret < 0) |
919 | lf->lr->path = xstrdup(src); | 1212 | return ret; |
920 | line_list__add_line(&lf->lr->line_list, (unsigned int)lineno); | ||
921 | } | 1213 | } |
1214 | |||
1215 | /* | ||
1216 | * Dwarf lines doesn't include function declarations. We have to | ||
1217 | * check functions list or given function. | ||
1218 | */ | ||
1219 | if (sp_die) { | ||
1220 | src = dwarf_decl_file(sp_die); | ||
1221 | if (src && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
1222 | (lf->lno_s <= lineno && lf->lno_e >= lineno)) | ||
1223 | ret = line_range_add_line(src, lineno, lf->lr); | ||
1224 | } else | ||
1225 | ret = find_line_range_func_decl_lines(lf); | ||
1226 | |||
922 | /* Update status */ | 1227 | /* Update status */ |
923 | if (!list_empty(&lf->lr->line_list)) | 1228 | if (ret >= 0) |
924 | lf->found = 1; | 1229 | if (!list_empty(&lf->lr->line_list)) |
1230 | ret = lf->found = 1; | ||
1231 | else | ||
1232 | ret = 0; /* Lines are not found */ | ||
925 | else { | 1233 | else { |
926 | free(lf->lr->path); | 1234 | free(lf->lr->path); |
927 | lf->lr->path = NULL; | 1235 | lf->lr->path = NULL; |
928 | } | 1236 | } |
1237 | return ret; | ||
929 | } | 1238 | } |
930 | 1239 | ||
931 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1240 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
932 | { | 1241 | { |
933 | find_line_range_by_line(in_die, (struct line_finder *)data); | 1242 | struct dwarf_callback_param *param = data; |
1243 | |||
1244 | param->retval = find_line_range_by_line(in_die, param->data); | ||
934 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1245 | return DWARF_CB_ABORT; /* No need to find other instances */ |
935 | } | 1246 | } |
936 | 1247 | ||
937 | /* Search function from function name */ | 1248 | /* Search function from function name */ |
938 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1249 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
939 | { | 1250 | { |
940 | struct line_finder *lf = (struct line_finder *)data; | 1251 | struct dwarf_callback_param *param = data; |
1252 | struct line_finder *lf = param->data; | ||
941 | struct line_range *lr = lf->lr; | 1253 | struct line_range *lr = lf->lr; |
942 | 1254 | ||
943 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1255 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
@@ -946,44 +1258,55 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
946 | dwarf_decl_line(sp_die, &lr->offset); | 1258 | dwarf_decl_line(sp_die, &lr->offset); |
947 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); | 1259 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); |
948 | lf->lno_s = lr->offset + lr->start; | 1260 | lf->lno_s = lr->offset + lr->start; |
949 | if (!lr->end) | 1261 | if (lf->lno_s < 0) /* Overflow */ |
1262 | lf->lno_s = INT_MAX; | ||
1263 | lf->lno_e = lr->offset + lr->end; | ||
1264 | if (lf->lno_e < 0) /* Overflow */ | ||
950 | lf->lno_e = INT_MAX; | 1265 | lf->lno_e = INT_MAX; |
951 | else | 1266 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
952 | lf->lno_e = lr->offset + lr->end; | ||
953 | lr->start = lf->lno_s; | 1267 | lr->start = lf->lno_s; |
954 | lr->end = lf->lno_e; | 1268 | lr->end = lf->lno_e; |
955 | if (dwarf_func_inline(sp_die)) | 1269 | if (dwarf_func_inline(sp_die)) { |
1270 | struct dwarf_callback_param _param; | ||
1271 | _param.data = (void *)lf; | ||
1272 | _param.retval = 0; | ||
956 | dwarf_func_inline_instances(sp_die, | 1273 | dwarf_func_inline_instances(sp_die, |
957 | line_range_inline_cb, lf); | 1274 | line_range_inline_cb, |
958 | else | 1275 | &_param); |
959 | find_line_range_by_line(sp_die, lf); | 1276 | param->retval = _param.retval; |
960 | return 1; | 1277 | } else |
1278 | param->retval = find_line_range_by_line(sp_die, lf); | ||
1279 | return DWARF_CB_ABORT; | ||
961 | } | 1280 | } |
962 | return 0; | 1281 | return DWARF_CB_OK; |
963 | } | 1282 | } |
964 | 1283 | ||
965 | static void find_line_range_by_func(struct line_finder *lf) | 1284 | static int find_line_range_by_func(struct line_finder *lf) |
966 | { | 1285 | { |
967 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0); | 1286 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; |
1287 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); | ||
1288 | return param.retval; | ||
968 | } | 1289 | } |
969 | 1290 | ||
970 | int find_line_range(int fd, struct line_range *lr) | 1291 | int find_line_range(int fd, struct line_range *lr) |
971 | { | 1292 | { |
972 | struct line_finder lf = {.lr = lr, .found = 0}; | 1293 | struct line_finder lf = {.lr = lr, .found = 0}; |
973 | int ret; | 1294 | int ret = 0; |
974 | Dwarf_Off off = 0, noff; | 1295 | Dwarf_Off off = 0, noff; |
975 | size_t cuhl; | 1296 | size_t cuhl; |
976 | Dwarf_Die *diep; | 1297 | Dwarf_Die *diep; |
977 | Dwarf *dbg; | 1298 | Dwarf *dbg; |
978 | 1299 | ||
979 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1300 | dbg = dwarf_begin(fd, DWARF_C_READ); |
980 | if (!dbg) | 1301 | if (!dbg) { |
981 | return -ENOENT; | 1302 | pr_warning("No dwarf info found in the vmlinux - " |
1303 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1304 | return -EBADF; | ||
1305 | } | ||
982 | 1306 | ||
983 | /* Loop on CUs (Compilation Unit) */ | 1307 | /* Loop on CUs (Compilation Unit) */ |
984 | while (!lf.found) { | 1308 | while (!lf.found && ret >= 0) { |
985 | ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); | 1309 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) |
986 | if (ret != 0) | ||
987 | break; | 1310 | break; |
988 | 1311 | ||
989 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1312 | /* Get the DIE(Debugging Information Entry) of this CU */ |
@@ -999,20 +1322,18 @@ int find_line_range(int fd, struct line_range *lr) | |||
999 | 1322 | ||
1000 | if (!lr->file || lf.fname) { | 1323 | if (!lr->file || lf.fname) { |
1001 | if (lr->function) | 1324 | if (lr->function) |
1002 | find_line_range_by_func(&lf); | 1325 | ret = find_line_range_by_func(&lf); |
1003 | else { | 1326 | else { |
1004 | lf.lno_s = lr->start; | 1327 | lf.lno_s = lr->start; |
1005 | if (!lr->end) | 1328 | lf.lno_e = lr->end; |
1006 | lf.lno_e = INT_MAX; | 1329 | ret = find_line_range_by_line(NULL, &lf); |
1007 | else | ||
1008 | lf.lno_e = lr->end; | ||
1009 | find_line_range_by_line(NULL, &lf); | ||
1010 | } | 1330 | } |
1011 | } | 1331 | } |
1012 | off = noff; | 1332 | off = noff; |
1013 | } | 1333 | } |
1014 | pr_debug("path: %lx\n", (unsigned long)lr->path); | 1334 | pr_debug("path: %lx\n", (unsigned long)lr->path); |
1015 | dwarf_end(dbg); | 1335 | dwarf_end(dbg); |
1016 | return lf.found; | 1336 | |
1337 | return (ret < 0) ? ret : lf.found; | ||
1017 | } | 1338 | } |
1018 | 1339 | ||
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 2a271321944f..310ce897229c 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -42,6 +42,7 @@ struct probe_finder { | |||
42 | struct list_head lcache; /* Line cache for lazy match */ | 42 | struct list_head lcache; /* Line cache for lazy match */ |
43 | 43 | ||
44 | /* For variable searching */ | 44 | /* For variable searching */ |
45 | Dwarf_CFI *cfi; /* Call Frame Information */ | ||
45 | Dwarf_Op *fb_ops; /* Frame base attribute */ | 46 | Dwarf_Op *fb_ops; /* Frame base attribute */ |
46 | struct perf_probe_arg *pvar; /* Current target variable */ | 47 | struct perf_probe_arg *pvar; /* Current target variable */ |
47 | struct kprobe_trace_arg *tvar; /* Current result variable */ | 48 | struct kprobe_trace_arg *tvar; /* Current result variable */ |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 9d24d4b2c8fb..da30b305fba0 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -30,38 +30,38 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, | |||
30 | size_t size, unsigned int width); | 30 | size_t size, unsigned int width); |
31 | 31 | ||
32 | struct sort_entry sort_thread = { | 32 | struct sort_entry sort_thread = { |
33 | .header = "Command: Pid", | 33 | .se_header = "Command: Pid", |
34 | .cmp = sort__thread_cmp, | 34 | .se_cmp = sort__thread_cmp, |
35 | .snprintf = hist_entry__thread_snprintf, | 35 | .se_snprintf = hist_entry__thread_snprintf, |
36 | .width = &threads__col_width, | 36 | .se_width = &threads__col_width, |
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct sort_entry sort_comm = { | 39 | struct sort_entry sort_comm = { |
40 | .header = "Command", | 40 | .se_header = "Command", |
41 | .cmp = sort__comm_cmp, | 41 | .se_cmp = sort__comm_cmp, |
42 | .collapse = sort__comm_collapse, | 42 | .se_collapse = sort__comm_collapse, |
43 | .snprintf = hist_entry__comm_snprintf, | 43 | .se_snprintf = hist_entry__comm_snprintf, |
44 | .width = &comms__col_width, | 44 | .se_width = &comms__col_width, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct sort_entry sort_dso = { | 47 | struct sort_entry sort_dso = { |
48 | .header = "Shared Object", | 48 | .se_header = "Shared Object", |
49 | .cmp = sort__dso_cmp, | 49 | .se_cmp = sort__dso_cmp, |
50 | .snprintf = hist_entry__dso_snprintf, | 50 | .se_snprintf = hist_entry__dso_snprintf, |
51 | .width = &dsos__col_width, | 51 | .se_width = &dsos__col_width, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | struct sort_entry sort_sym = { | 54 | struct sort_entry sort_sym = { |
55 | .header = "Symbol", | 55 | .se_header = "Symbol", |
56 | .cmp = sort__sym_cmp, | 56 | .se_cmp = sort__sym_cmp, |
57 | .snprintf = hist_entry__sym_snprintf, | 57 | .se_snprintf = hist_entry__sym_snprintf, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct sort_entry sort_parent = { | 60 | struct sort_entry sort_parent = { |
61 | .header = "Parent symbol", | 61 | .se_header = "Parent symbol", |
62 | .cmp = sort__parent_cmp, | 62 | .se_cmp = sort__parent_cmp, |
63 | .snprintf = hist_entry__parent_snprintf, | 63 | .se_snprintf = hist_entry__parent_snprintf, |
64 | .width = &parent_symbol__col_width, | 64 | .se_width = &parent_symbol__col_width, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct sort_dimension { | 67 | struct sort_dimension { |
@@ -255,7 +255,7 @@ int sort_dimension__add(const char *tok) | |||
255 | if (strncasecmp(tok, sd->name, strlen(tok))) | 255 | if (strncasecmp(tok, sd->name, strlen(tok))) |
256 | continue; | 256 | continue; |
257 | 257 | ||
258 | if (sd->entry->collapse) | 258 | if (sd->entry->se_collapse) |
259 | sort__need_collapse = 1; | 259 | sort__need_collapse = 1; |
260 | 260 | ||
261 | if (sd->entry == &sort_parent) { | 261 | if (sd->entry == &sort_parent) { |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 6d7b4be70609..1d857aa2c01f 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -78,13 +78,13 @@ enum sort_type { | |||
78 | struct sort_entry { | 78 | struct sort_entry { |
79 | struct list_head list; | 79 | struct list_head list; |
80 | 80 | ||
81 | const char *header; | 81 | const char *se_header; |
82 | 82 | ||
83 | int64_t (*cmp)(struct hist_entry *, struct hist_entry *); | 83 | int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); |
84 | int64_t (*collapse)(struct hist_entry *, struct hist_entry *); | 84 | int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); |
85 | int (*snprintf)(struct hist_entry *self, char *bf, size_t size, | 85 | int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size, |
86 | unsigned int width); | 86 | unsigned int width); |
87 | unsigned int *width; | 87 | unsigned int *se_width; |
88 | bool elide; | 88 | bool elide; |
89 | }; | 89 | }; |
90 | 90 | ||