In newer kernel, the event call's "double linked list head of field" is
stored in struct ftrace_event_class, and some of them are special defined.
To implement them, we have to emulate them, so this patch emulates
the kernel functions:
syscall_get_enter_fields()
syscall_get_exit_fields()
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
diff --git a/extensions/trace.c b/extensions/trace.c
index a54e4fa..484c872 100755
--- a/extensions/trace.c
+++ b/extensions/trace.c
@@ -662,23 +662,127 @@ static void event_generic_print_fmt_print(struct event_type *t,
static void event_default_print(struct event_type *t,
struct format_context *fc);
+static int syscall_get_enter_fields(ulong call, ulong *fields)
+{
+ static int inited;
+ static int data_offset;
+ static int enter_fields_offset;
+
+ ulong metadata;
+
+ if (inited)
+ goto work;
+
+ inited = 1;
+ data_offset = MEMBER_OFFSET("ftrace_event_call", "data");
+ if (data_offset < 0)
+ return -1;
+
+ enter_fields_offset = MEMBER_OFFSET("syscall_metadata",
"enter_fields");
+ if (enter_fields_offset < 0)
+ return -1;
+
+work:
+ if (data_offset < 0 || enter_fields_offset < 0)
+ return -1;
+
+ if (!readmem(call + data_offset, KVADDR, &metadata, sizeof(metadata),
+ "read ftrace_event_call data", RETURN_ON_ERROR))
+ return -1;
+
+ *fields = metadata + enter_fields_offset;
+ return 0;
+}
+
+static int syscall_get_exit_fields(ulong call, ulong *fields)
+{
+ static int inited;
+ static ulong syscall_exit_fields_value;
+
+ if (!inited) {
+ struct syment *sp;
+
+ if (!(sp = symbol_search("syscall_exit_fields"))) {
+ inited = -1;
+ } else {
+ syscall_exit_fields_value = sp->value;
+ inited = 1;
+ }
+ }
+
+ if (inited == -1)
+ return -1;
+
+ *fields = syscall_exit_fields_value;
+
+ return 0;
+}
+
static
int ftrace_get_event_type_fields(ulong call, ulong *fields)
{
static int inited;
static int fields_offset;
+ static int class_offset;
+ static int get_fields_offset;
+ static ulong syscall_get_enter_fields_value;
+ static ulong syscall_get_exit_fields_value;
- if (!inited) {
- inited = 1;
- fields_offset = MEMBER_OFFSET("ftrace_event_call", "fields");
- }
+ struct syment *sp;
+ ulong class, get_fields;
+ if (inited)
+ goto work;
+
+ inited = 1;
+ fields_offset = MEMBER_OFFSET("ftrace_event_call", "fields");
+
+ class_offset = MEMBER_OFFSET("ftrace_event_call", "class");
+ if (class_offset < 0)
+ goto work;
+
+ inited = 2;
+ fields_offset = MEMBER_OFFSET("ftrace_event_class", "fields");
if (fields_offset < 0)
return -1;
- *fields = call + fields_offset;
+ get_fields_offset = MEMBER_OFFSET("ftrace_event_class",
"get_fields");
+ if ((sp = symbol_search("syscall_get_enter_fields")) != NULL)
+ syscall_get_enter_fields_value = sp->value;
+ if ((sp = symbol_search("syscall_get_exit_fields")) != NULL)
+ syscall_get_exit_fields_value = sp->value;
- return 0;
+work:
+ if (fields_offset < 0)
+ return -1;
+
+ if (inited == 1) {
+ *fields = call + fields_offset;
+ return 0;
+ }
+
+ if (!readmem(call + class_offset, KVADDR, &class, sizeof(class),
+ "read ftrace_event_call class", RETURN_ON_ERROR))
+ return -1;
+
+ if (!readmem(class + get_fields_offset, KVADDR, &get_fields,
+ sizeof(get_fields), "read ftrace_event_call get_fields",
+ RETURN_ON_ERROR))
+ return -1;
+
+ if (!get_fields) {
+ *fields = class + fields_offset;
+ return 0;
+ }
+
+ if (get_fields == syscall_get_enter_fields_value)
+ return syscall_get_enter_fields(call, fields);
+
+ if (get_fields == syscall_get_exit_fields_value)
+ return syscall_get_exit_fields(call, fields);
+
+ fprintf(fp, "Unkown get_fields function\n");
+ return -1;
}
static int ftrace_init_event_type(ulong call, struct event_type *aevent_type)