return 0;
}
-static int __probe_event_show_format(struct trace_seq *s,
- struct trace_probe *tp, const char *fmt,
- const char *arg)
+static int __set_print_fmt(struct trace_probe *tp, char *buf, int len)
{
int i;
+ int pos = 0;
- /* Show format */
- if (!trace_seq_printf(s, "\nprint fmt: \"%s", fmt))
- return 0;
+ const char *fmt, *arg;
- for (i = 0; i < tp->nr_args; i++)
- if (!trace_seq_printf(s, " %s=%%lx", tp->args[i].name))
- return 0;
+ if (!probe_is_return(tp)) {
+ fmt = "(%lx)";
+ arg = "REC->" FIELD_STRING_IP;
+ } else {
+ fmt = "(%lx <- %lx)";
+ arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
+ }
- if (!trace_seq_printf(s, "\", %s", arg))
- return 0;
+ /* When len=0, we just calculate the needed length */
+#define LEN_OR_ZERO (len ? len - pos : 0)
- for (i = 0; i < tp->nr_args; i++)
- if (!trace_seq_printf(s, ", REC->%s", tp->args[i].name))
- return 0;
+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
- return trace_seq_puts(s, "\n");
-}
+ for (i = 0; i < tp->nr_args; i++) {
+ pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%%lx",
+ tp->args[i].name);
+ }
-#undef SHOW_FIELD
-#define SHOW_FIELD(type, item, name) \
- do { \
- ret = trace_seq_printf(s, "\tfield:" #type " %s;\t" \
- "offset:%u;\tsize:%u;\tsigned:%d;\n", name,\
- (unsigned int)offsetof(typeof(field), item),\
- (unsigned int)sizeof(type), \
- is_signed_type(type)); \
- if (!ret) \
- return 0; \
- } while (0)
+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
-static int kprobe_event_show_format(struct ftrace_event_call *call,
- struct trace_seq *s)
-{
- struct kprobe_trace_entry field __attribute__((unused));
- int ret, i;
- struct trace_probe *tp = (struct trace_probe *)call->data;
-
- SHOW_FIELD(unsigned long, ip, FIELD_STRING_IP);
- SHOW_FIELD(int, nargs, FIELD_STRING_NARGS);
+ for (i = 0; i < tp->nr_args; i++) {
+ pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
+ tp->args[i].name);
+ }
- /* Show fields */
- for (i = 0; i < tp->nr_args; i++)
- SHOW_FIELD(unsigned long, args[i], tp->args[i].name);
- trace_seq_puts(s, "\n");
+#undef LEN_OR_ZERO
- return __probe_event_show_format(s, tp, "(%lx)",
- "REC->" FIELD_STRING_IP);
+ /* return the length of print_fmt */
+ return pos;
}
-static int kretprobe_event_show_format(struct ftrace_event_call *call,
- struct trace_seq *s)
+static int set_print_fmt(struct trace_probe *tp)
{
- struct kretprobe_trace_entry field __attribute__((unused));
- int ret, i;
- struct trace_probe *tp = (struct trace_probe *)call->data;
+ int len;
+ char *print_fmt;
- SHOW_FIELD(unsigned long, func, FIELD_STRING_FUNC);
- SHOW_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP);
- SHOW_FIELD(int, nargs, FIELD_STRING_NARGS);
+ /* First: called with 0 length to calculate the needed length */
+ len = __set_print_fmt(tp, NULL, 0);
+ print_fmt = kmalloc(len + 1, GFP_KERNEL);
+ if (!print_fmt)
+ return -ENOMEM;
- /* Show fields */
- for (i = 0; i < tp->nr_args; i++)
- SHOW_FIELD(unsigned long, args[i], tp->args[i].name);
- trace_seq_puts(s, "\n");
+ /* Second: actually write the @print_fmt */
+ __set_print_fmt(tp, print_fmt, len + 1);
+ tp->call.print_fmt = print_fmt;
- return __probe_event_show_format(s, tp, "(%lx <- %lx)",
- "REC->" FIELD_STRING_FUNC
- ", REC->" FIELD_STRING_RETIP);
+ return 0;
}
- #ifdef CONFIG_EVENT_PROFILE
+ #ifdef CONFIG_PERF_EVENTS
/* Kprobe profile handler */
- static __kprobes int kprobe_profile_func(struct kprobe *kp,
+ static __kprobes void kprobe_profile_func(struct kprobe *kp,
struct pt_regs *regs)
{
struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);