lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 28 Mar 2014 10:45:10 -0400
From:	Jovi Zhangwei <jovi.zhangwei@...il.com>
To:	Ingo Molnar <mingo@...hat.com>,
	Steven Rostedt <rostedt@...dmis.org>
Cc:	linux-kernel@...r.kernel.org,
	Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	Frederic Weisbecker <fweisbec@...il.com>,
	Andi Kleen <andi@...stfloor.org>,
	Jovi Zhangwei <jovi.zhangwei@...il.com>
Subject: [PATCH v2 15/29] ktap: add built-in functions and library(kernel/trace/ktap/lib_*.c)

ktap register built-in functions and library into table.

1). Built-in functions(lib_base,c):

print, printf, print_hist, pairs, len, delete, stack,
print_trace_clock, num_cpus, arch, kernel_v, kernel_string,
user_string, stringof, ipof, gettimeofday_ns, gettimeofday_us,
gettimeofday_ms, gettimeofday_s, curr_taskinfo, in_iowait,
in_interrupt, exit.

2). Ansi library(lib_ansi.c):

ansi.clear_screen
ansi.set_color
ansi.set_color2
ansi.set_color3
ansi.reset_color
ansi.new_line

3). kdebug library(lib_kdebug.c):

kdebug.trace_by_id
kdebug.trace_end
kdebug.tracepoint
kdebug.kprobe

4). net library(lib_net.c):

net.ip_sock_saddr
net.ip_sock_daddr
net.format_ip_addr

5). table library(lib_table.c):

table.new

6). timer library(lib_timer.c):

timer.profile
timer.tick

Signed-off-by: Jovi Zhangwei <jovi.zhangwei@...il.com>
---
 kernel/trace/ktap/lib_ansi.c   | 142 ++++++++++++++
 kernel/trace/ktap/lib_base.c   | 407 +++++++++++++++++++++++++++++++++++++++++
 kernel/trace/ktap/lib_kdebug.c | 195 ++++++++++++++++++++
 kernel/trace/ktap/lib_net.c    | 107 +++++++++++
 kernel/trace/ktap/lib_table.c  |  58 ++++++
 kernel/trace/ktap/lib_timer.c  | 210 +++++++++++++++++++++
 6 files changed, 1119 insertions(+)
 create mode 100644 kernel/trace/ktap/lib_ansi.c
 create mode 100644 kernel/trace/ktap/lib_base.c
 create mode 100644 kernel/trace/ktap/lib_kdebug.c
 create mode 100644 kernel/trace/ktap/lib_net.c
 create mode 100644 kernel/trace/ktap/lib_table.c
 create mode 100644 kernel/trace/ktap/lib_timer.c

diff --git a/kernel/trace/ktap/lib_ansi.c b/kernel/trace/ktap/lib_ansi.c
new file mode 100644
index 0000000..04f0b9a
--- /dev/null
+++ b/kernel/trace/ktap/lib_ansi.c
@@ -0,0 +1,142 @@
+/*
+ * lib_ansi.c - ANSI escape sequences library
+ *
+ * http://en.wikipedia.org/wiki/ANSI_escape_code
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@...il.com>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <uapi/ktap/ktap_types.h>
+#include "ktap.h"
+#include "kp_vm.h"
+
+/**
+ * function ansi.clear_screen - Move cursor to top left and clear screen.
+ *
+ * Description: Sends ansi code for moving cursor to top left and then the
+ * ansi code for clearing the screen from the cursor position to the end.
+ */
+
+static int kplib_ansi_clear_screen(ktap_state_t *ks)
+{
+	kp_printf(ks, "\033[1;1H\033[J");
+	return 0;
+}
+
+/**
+ * function ansi.set_color - Set the ansi Select Graphic Rendition mode.
+ * @fg: Foreground color to set.
+ *
+ * Description: Sends ansi code for Select Graphic Rendition mode for the
+ * given forground color. Black (30), Blue (34), Green (32), Cyan (36),
+ * Red (31), Purple (35), Brown (33), Light Gray (37).
+ */
+
+static int kplib_ansi_set_color(ktap_state_t *ks)
+{
+	int fg = kp_arg_checknumber(ks, 1);
+
+	kp_printf(ks, "\033[%dm", fg);
+	return 0;
+}
+
+/**
+ * function ansi.set_color2 - Set the ansi Select Graphic Rendition mode.
+ * @fg: Foreground color to set.
+ * @bg: Background color to set.
+ *
+ * Description: Sends ansi code for Select Graphic Rendition mode for the
+ * given forground color, Black (30), Blue (34), Green (32), Cyan (36),
+ * Red (31), Purple (35), Brown (33), Light Gray (37) and the given
+ * background color, Black (40), Red (41), Green (42), Yellow (43),
+ * Blue (44), Magenta (45), Cyan (46), White (47).
+ */
+static int kplib_ansi_set_color2(ktap_state_t *ks)
+{
+	int fg = kp_arg_checknumber(ks, 1);
+	int bg = kp_arg_checknumber(ks, 2);
+	
+	kp_printf(ks, "\033[%d;%dm", fg, bg);
+	return 0;
+}
+
+/**
+ * function ansi.set_color3 - Set the ansi Select Graphic Rendition mode.
+ * @fg: Foreground color to set.
+ * @bg: Background color to set.
+ * @attr: Color attribute to set.
+ *
+ * Description: Sends ansi code for Select Graphic Rendition mode for the
+ * given forground color, Black (30), Blue (34), Green (32), Cyan (36),
+ * Red (31), Purple (35), Brown (33), Light Gray (37), the given
+ * background color, Black (40), Red (41), Green (42), Yellow (43),
+ * Blue (44), Magenta (45), Cyan (46), White (47) and the color attribute
+ * All attributes off (0), Intensity Bold (1), Underline Single (4),
+ * Blink Slow (5), Blink Rapid (6), Image Negative (7).
+ */
+static int kplib_ansi_set_color3(ktap_state_t *ks)
+{
+	int fg = kp_arg_checknumber(ks, 1);
+	int bg = kp_arg_checknumber(ks, 2);
+	int attr = kp_arg_checknumber(ks, 3);
+
+	if (attr)
+		kp_printf(ks, "\033[%d;%d;%dm", fg, bg, attr);
+	else
+		kp_printf(ks, "\033[%d;%dm", fg, bg);
+	
+	return 0;
+}
+
+/**
+ * function ansi.reset_color - Resets Select Graphic Rendition mode.
+ *
+ * Description: Sends ansi code to reset foreground, background and color
+ * attribute to default values.
+ */
+static int kplib_ansi_reset_color(ktap_state_t *ks)
+{
+	kp_printf(ks, "\033[0;0m");
+	return 0;
+}
+
+/**
+ * function ansi.new_line - Move cursor to new line.
+ *
+ * Description: Sends ansi code new line.
+ */
+static int kplib_ansi_new_line (ktap_state_t *ks)
+{
+	kp_printf(ks, "\12");
+	return 0;
+}
+
+static const ktap_libfunc_t ansi_lib_funcs[] = {
+	{"clear_screen", kplib_ansi_clear_screen},
+	{"set_color", kplib_ansi_set_color},
+	{"set_color2", kplib_ansi_set_color2},
+	{"set_color3", kplib_ansi_set_color3},
+	{"reset_color", kplib_ansi_reset_color},
+	{"new_line", kplib_ansi_new_line},
+	{NULL}
+};
+
+int kp_lib_init_ansi(ktap_state_t *ks)
+{
+	return kp_vm_register_lib(ks, "ansi", ansi_lib_funcs); 
+}
diff --git a/kernel/trace/ktap/lib_base.c b/kernel/trace/ktap/lib_base.c
new file mode 100644
index 0000000..1765cc3
--- /dev/null
+++ b/kernel/trace/ktap/lib_base.c
@@ -0,0 +1,407 @@
+/*
+ * lib_base.c - base library
+ *
+ * Caveat: all kernel funtion called by ktap library have to be lock free,
+ * otherwise system will deadlock.
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@...il.com>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/version.h>
+#include <linux/hardirq.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/utsname.h>
+#include <linux/time.h>
+#include <linux/clocksource.h>
+#include <linux/ring_buffer.h>
+#include <linux/stacktrace.h>
+#include <linux/cred.h>
+#include <linux/uidgid.h>
+#include <uapi/ktap/ktap_types.h>
+#include "ktap.h"
+#include "kp_obj.h"
+#include "kp_str.h"
+#include "kp_tab.h"
+#include "kp_transport.h"
+#include "kp_events.h"
+#include "kp_vm.h"
+
+static int kplib_print(ktap_state_t *ks)
+{
+	int i;
+	int n = kp_arg_nr(ks);
+
+	for (i = 1; i <= n; i++) {
+		ktap_val_t *arg = kp_arg(ks, i);
+		if (i > 1)
+			kp_puts(ks, "\t");
+		kp_obj_show(ks, arg);
+	}
+
+	kp_puts(ks, "\n");
+	return 0;
+}
+
+/* don't engage with intern string in printf, use buffer directly */
+static int kplib_printf(ktap_state_t *ks)
+{
+	struct trace_seq *seq;
+
+	preempt_disable_notrace();
+
+	seq = kp_this_cpu_print_buffer(ks);
+	trace_seq_init(seq);
+
+	if (kp_str_fmt(ks, seq))
+		goto out;
+
+	seq->buffer[seq->len] = '\0';
+	kp_transport_write(ks, seq->buffer, seq->len + 1);
+
+ out:
+	preempt_enable_notrace();
+	return 0;
+}
+
+#define HISTOGRAM_DEFAULT_TOP_NUM	20
+
+static int kplib_print_hist(ktap_state_t *ks)
+{
+	int n ;
+
+	kp_arg_check(ks, 1, KTAP_TTAB);
+	n = kp_arg_checkoptnumber(ks, 2, HISTOGRAM_DEFAULT_TOP_NUM);
+
+	n = min(n, 1000);
+	n = max(n, HISTOGRAM_DEFAULT_TOP_NUM);
+
+	kp_tab_print_hist(ks, hvalue(kp_arg(ks, 1)), n);
+
+	return 0;
+}
+
+static int kplib_pairs(ktap_state_t *ks)
+{
+	kp_arg_check(ks, 1, KTAP_TTAB);
+
+	set_cfunc(ks->top++, (ktap_cfunction)kp_tab_next);
+	set_table(ks->top++, hvalue(kp_arg(ks, 1)));
+	set_nil(ks->top++);
+	return 3;
+}
+
+static int kplib_len(ktap_state_t *ks)
+{
+	int len = kp_obj_len(ks, kp_arg(ks, 1));
+
+	if (len < 0)
+		return -1;
+
+	set_number(ks->top, len);
+	incr_top(ks);
+	return 1;
+}
+
+static int kplib_delete(ktap_state_t *ks)
+{
+	kp_arg_check(ks, 1, KTAP_TTAB);
+	kp_tab_clear(hvalue(kp_arg(ks, 1)));
+	return 0;
+}
+
+#ifdef CONFIG_STACKTRACE
+static int kplib_stack(ktap_state_t *ks)
+{
+	uint16_t skip, depth = 10;
+
+	depth = kp_arg_checkoptnumber(ks, 1, 10); /* default as 10 */
+	depth = min_t(uint16_t, depth, KP_MAX_STACK_DEPTH);
+	skip = kp_arg_checkoptnumber(ks, 2, 10); /* default as 10 */
+
+	set_kstack(ks->top, depth, skip);
+	incr_top(ks);
+	return 1;
+}
+#else
+static int kplib_stack(ktap_state_t *ks)
+{
+	kp_error(ks, "Please enable CONFIG_STACKTRACE before call stack()\n");
+	return -1;
+}
+#endif
+
+
+extern unsigned long long ns2usecs(cycle_t nsec);
+static int kplib_print_trace_clock(ktap_state_t *ks)
+{
+	unsigned long long t;
+	unsigned long secs, usec_rem;
+	u64 timestamp;
+
+	/* use ring buffer's timestamp */
+	timestamp = ring_buffer_time_stamp(G(ks)->buffer, smp_processor_id());
+
+	t = ns2usecs(timestamp);
+	usec_rem = do_div(t, USEC_PER_SEC);
+	secs = (unsigned long)t;
+
+	kp_printf(ks, "%5lu.%06lu\n", secs, usec_rem);
+	return 0;
+}
+
+static int kplib_num_cpus(ktap_state_t *ks)
+{
+	set_number(ks->top, num_online_cpus());
+	incr_top(ks);
+	return 1;
+}
+
+/* TODO: intern string firstly */
+static int kplib_arch(ktap_state_t *ks)
+{
+	ktap_str_t *ts = kp_str_newz(ks, utsname()->machine);
+	if (unlikely(!ts))
+		return -1;
+
+	set_string(ks->top, ts);
+	incr_top(ks);
+	return 1;
+}
+
+/* TODO: intern string firstly */
+static int kplib_kernel_v(ktap_state_t *ks)
+{
+	ktap_str_t *ts = kp_str_newz(ks, utsname()->release);
+	if (unlikely(!ts))
+		return -1;
+
+	set_string(ks->top, ts);
+	incr_top(ks);
+	return 1;
+}
+
+static int kplib_kernel_string(ktap_state_t *ks)
+{
+	unsigned long addr = kp_arg_checknumber(ks, 1);
+	char str[256] = {0};
+	ktap_str_t *ts;
+	char *ret;
+
+	ret = strncpy((void *)str, (const void *)addr, 256);
+	(void) &ret;  /* Silence compiler warning. */
+	str[255] = '\0';
+
+	ts = kp_str_newz(ks, str);
+	if (unlikely(!ts))
+		return -1;
+
+	set_string(ks->top, ts);
+	incr_top(ks);
+	return 1;
+}
+
+static int kplib_user_string(ktap_state_t *ks)
+{
+	unsigned long addr = kp_arg_checknumber(ks, 1);
+	char str[256] = {0};
+	ktap_str_t *ts;
+	int ret;
+
+	pagefault_disable();
+	ret = __copy_from_user_inatomic((void *)str, (const void *)addr, 256);
+	(void) &ret;  /* Silence compiler warning. */
+	pagefault_enable();
+	str[255] = '\0';
+
+	ts = kp_str_newz(ks, str);
+	if (unlikely(!ts))
+		return -1;
+
+	set_string(ks->top, ts);
+	incr_top(ks);
+	return 1;
+}
+
+static int kplib_stringof(ktap_state_t *ks)
+{
+	ktap_val_t *v = kp_arg(ks, 1);
+	const ktap_str_t *ts = NULL;
+
+	if (itype(v) == KTAP_TEVENTSTR) {
+		ts = kp_event_stringify(ks);
+	} else if (itype(v) == KTAP_TKIP) {
+		char str[KSYM_SYMBOL_LEN];
+
+		SPRINT_SYMBOL(str, nvalue(v));
+		ts = kp_str_newz(ks, str);
+	}
+
+	if (unlikely(!ts))
+		return -1;
+
+	set_string(ks->top++, ts);
+	return 1;
+}
+
+static int kplib_ipof(ktap_state_t *ks)
+{
+	unsigned long addr = kp_arg_checknumber(ks, 1);
+
+	set_ip(ks->top++, addr);
+	return 1;
+}
+
+static int kplib_gettimeofday_ns(ktap_state_t *ks)
+{
+	set_number(ks->top, gettimeofday_ns());
+	incr_top(ks);
+
+	return 1;
+}
+
+static int kplib_gettimeofday_us(ktap_state_t *ks)
+{
+	set_number(ks->top, gettimeofday_ns() / NSEC_PER_USEC);
+	incr_top(ks);
+
+	return 1;
+}
+
+static int kplib_gettimeofday_ms(ktap_state_t *ks)
+{
+	set_number(ks->top, gettimeofday_ns() / NSEC_PER_MSEC);
+	incr_top(ks);
+
+	return 1;
+}
+
+static int kplib_gettimeofday_s(ktap_state_t *ks)
+{
+	set_number(ks->top, gettimeofday_ns() / NSEC_PER_SEC);
+	incr_top(ks);
+
+	return 1;
+}
+
+/*
+ * use gdb to get field offset of struct task_struct, for example:
+ *
+ * gdb vmlinux
+ * (gdb)p &(((struct task_struct *)0).prio)
+ */
+static int kplib_curr_taskinfo(ktap_state_t *ks)
+{
+	int offset = kp_arg_checknumber(ks, 1);
+	int fetch_bytes  = kp_arg_checkoptnumber(ks, 2, 4); /* fetch 4 bytes */
+
+	if (offset >= sizeof(struct task_struct)) {
+		set_nil(ks->top++);
+		kp_error(ks, "access out of bound value of task_struct\n");
+		return 1;
+	}
+
+#define RET_VALUE ((unsigned long)current + offset)
+
+	switch (fetch_bytes) {
+	case 4:
+		set_number(ks->top, *(unsigned int *)RET_VALUE);
+		break;
+	case 8:
+		set_number(ks->top, *(unsigned long *)RET_VALUE);
+		break;
+	default:
+		kp_error(ks, "unsupported fetch bytes in curr_task_info\n");
+		set_nil(ks->top);
+		break;
+	}
+
+#undef RET_VALUE
+
+	incr_top(ks);
+	return 1;
+}
+
+/*
+ * This built-in function mainly purpose scripts/schedule/schedtimes.kp
+ */
+static int kplib_in_iowait(ktap_state_t *ks)
+{
+	set_number(ks->top, current->in_iowait);
+	incr_top(ks);
+
+	return 1;
+}
+
+static int kplib_in_interrupt(ktap_state_t *ks)
+{
+	int ret = in_interrupt();
+
+	set_number(ks->top, ret);
+	incr_top(ks);
+	return 1;
+}
+
+static int kplib_exit(ktap_state_t *ks)
+{
+	kp_vm_try_to_exit(ks);
+
+	/* do not execute bytecode any more in this thread */
+	return -1;
+}
+
+static const ktap_libfunc_t base_lib_funcs[] = {
+	{"print", kplib_print},
+	{"printf", kplib_printf},
+	{"print_hist", kplib_print_hist},
+
+	{"pairs", kplib_pairs},
+	{"len", kplib_len},
+	{"delete", kplib_delete},
+
+	{"stack", kplib_stack},
+	{"print_trace_clock", kplib_print_trace_clock},
+
+	{"num_cpus", kplib_num_cpus},
+	{"arch", kplib_arch},
+	{"kernel_v", kplib_kernel_v},
+	{"kernel_string", kplib_kernel_string},
+	{"user_string", kplib_user_string},
+	{"stringof", kplib_stringof},
+	{"ipof", kplib_ipof},
+
+	{"gettimeofday_ns", kplib_gettimeofday_ns},
+	{"gettimeofday_us", kplib_gettimeofday_us},
+	{"gettimeofday_ms", kplib_gettimeofday_ms},
+	{"gettimeofday_s", kplib_gettimeofday_s},
+
+	{"curr_taskinfo", kplib_curr_taskinfo},
+
+	{"in_iowait", kplib_in_iowait},
+	{"in_interrupt", kplib_in_interrupt},
+
+	{"exit", kplib_exit},
+	{NULL}
+};
+
+int kp_lib_init_base(ktap_state_t *ks)
+{
+	return kp_vm_register_lib(ks, NULL, base_lib_funcs); 
+}
diff --git a/kernel/trace/ktap/lib_kdebug.c b/kernel/trace/ktap/lib_kdebug.c
new file mode 100644
index 0000000..247fc51
--- /dev/null
+++ b/kernel/trace/ktap/lib_kdebug.c
@@ -0,0 +1,195 @@
+/*
+ * lib_kdebug.c - kdebug library support for ktap
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@...il.com>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/ftrace_event.h>
+#include <uapi/ktap/ktap_types.h>
+#include "ktap.h"
+#include "kp_obj.h"
+#include "kp_str.h"
+#include "kp_transport.h"
+#include "kp_vm.h"
+#include "kp_events.h"
+
+/**
+ * function kdebug.trace_by_id
+ *
+ * @uaddr: userspace address refer to ktap_eventdesc_t
+ * @closure
+ */
+static int kplib_kdebug_trace_by_id(ktap_state_t *ks)
+{
+	unsigned long uaddr = kp_arg_checknumber(ks, 1);
+	ktap_func_t *fn = kp_arg_checkfunction(ks, 2);
+	struct task_struct *task = G(ks)->trace_task;
+	ktap_eventdesc_t eventsdesc;
+	char *filter = NULL;
+	int *id_arr;
+	int i;
+
+	if (G(ks)->mainthread != ks) {
+		kp_error(ks,
+		    "kdebug.trace_by_id only can be called in mainthread\n");
+		return -1;
+	}
+
+	/* kdebug.trace_by_id cannot be called in trace_end state */
+	if (G(ks)->state != KTAP_RUNNING) {
+		kp_error(ks,
+		    "kdebug.trace_by_id only can be called in RUNNING state\n");
+		return -1;
+	}
+
+	/* copy ktap_eventdesc_t from userspace */
+	if (copy_from_user(&eventsdesc, (void *)uaddr,
+			     sizeof(ktap_eventdesc_t)))
+		return -1;
+
+	if (eventsdesc.filter) {
+		int len;
+
+		len = strlen_user(eventsdesc.filter);
+		if (len > 0x1000)
+			return -1;
+
+		filter = kmalloc(len + 1, GFP_KERNEL);
+		if (!filter)
+			return -1;
+
+		/* copy filter string from userspace */
+		if (strncpy_from_user(filter, eventsdesc.filter, len) < 0) {
+			kfree(filter);
+			return -1;
+		}
+	}
+
+	id_arr = kmalloc(eventsdesc.nr * sizeof(int), GFP_KERNEL);
+	if (!id_arr) {
+		kfree(filter);
+		return -1;
+	}
+
+	/* copy all event id from userspace */
+	if (copy_from_user(id_arr, eventsdesc.id_arr,
+			   eventsdesc.nr * sizeof(int))) {
+		kfree(filter);
+		kfree(id_arr);
+		return -1;
+	}
+
+	fn = clvalue(kp_arg(ks, 2));
+
+	for (i = 0; i < eventsdesc.nr; i++) {
+		struct perf_event_attr attr;
+
+		cond_resched();
+
+		if (signal_pending(current)) {
+			flush_signals(current);
+			kfree(filter);
+			kfree(id_arr);
+			return -1;
+		}
+
+		memset(&attr, 0, sizeof(attr));
+		attr.type = PERF_TYPE_TRACEPOINT;	
+		attr.config = id_arr[i];
+		attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
+				   PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD;
+		attr.sample_period = 1;
+		attr.size = sizeof(attr);
+		attr.disabled = 0;
+
+		/* register event one by one */
+		if (kp_event_create(ks, &attr, task, filter, fn))
+			break;
+	}
+
+	kfree(filter);
+	kfree(id_arr);
+	return 0;
+}
+
+static int kplib_kdebug_trace_end(ktap_state_t *ks)
+{
+	/* trace_end_closure will be called when ktap main thread exit */
+	G(ks)->trace_end_closure = kp_arg_checkfunction(ks, 1);
+	return 0;
+}
+
+static int kplib_kdebug_tracepoint(ktap_state_t *ks)
+{
+	const char *event_name = kp_arg_checkstring(ks, 1);
+	ktap_func_t *fn = kp_arg_checkfunction(ks, 2);
+
+	if (G(ks)->mainthread != ks) {
+		kp_error(ks,
+		    "kdebug.tracepoint only can be called in mainthread\n");
+		return -1;
+	}
+
+	/* kdebug.tracepoint cannot be called in trace_end state */
+	if (G(ks)->state != KTAP_RUNNING) {
+		kp_error(ks,
+		    "kdebug.tracepoint only can be called in RUNNING state\n");
+		return -1;
+	}
+
+	return kp_event_create_tracepoint(ks, event_name, fn);
+}
+
+static int kplib_kdebug_kprobe(ktap_state_t *ks)
+{
+	const char *event_name = kp_arg_checkstring(ks, 1);
+	ktap_func_t *fn = kp_arg_checkfunction(ks, 2);
+
+	if (G(ks)->mainthread != ks) {
+		kp_error(ks,
+		    "kdebug.kprobe only can be called in mainthread\n");
+		return -1;
+	}
+
+	/* kdebug.kprobe cannot be called in trace_end state */
+	if (G(ks)->state != KTAP_RUNNING) {
+		kp_error(ks,
+		    "kdebug.kprobe only can be called in RUNNING state\n");
+		return -1;
+	}
+
+	return kp_event_create_kprobe(ks, event_name, fn);
+}
+static const ktap_libfunc_t kdebug_lib_funcs[] = {
+	{"trace_by_id", kplib_kdebug_trace_by_id},
+	{"trace_end", kplib_kdebug_trace_end},
+
+	{"tracepoint", kplib_kdebug_tracepoint},
+	{"kprobe", kplib_kdebug_kprobe},
+	{NULL}
+};
+
+int kp_lib_init_kdebug(ktap_state_t *ks)
+{
+	return kp_vm_register_lib(ks, "kdebug", kdebug_lib_funcs);
+}
+
diff --git a/kernel/trace/ktap/lib_net.c b/kernel/trace/ktap/lib_net.c
new file mode 100644
index 0000000..a34f4c2
--- /dev/null
+++ b/kernel/trace/ktap/lib_net.c
@@ -0,0 +1,107 @@
+/*
+ * lib_base.c - base library
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@...il.com>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <net/inet_sock.h>
+#include <uapi/ktap/ktap_types.h>
+#include "ktap.h"
+#include "kp_obj.h"
+#include "kp_str.h"
+#include "kp_vm.h"
+
+/**
+ * Return the source IP address for a given sock
+ */
+static int kplib_net_ip_sock_saddr(ktap_state_t *ks)
+{
+	struct inet_sock *isk;
+	int family;
+
+	/* TODO: need to validate the address firstly */	
+
+	isk = (struct inet_sock *)kp_arg_checknumber(ks, 1);
+	family = isk->sk.__sk_common.skc_family;
+
+	if (family == AF_INET) {
+		set_number(ks->top, isk->inet_rcv_saddr);
+	} else {
+		kp_error(ks, "ip_sock_saddr only support ipv4 now\n");
+		set_nil(ks->top);
+	}
+
+	incr_top(ks);
+	return 1;
+}
+
+/**
+ * Return the destination IP address for a given sock
+ */
+static int kplib_net_ip_sock_daddr(ktap_state_t *ks)
+{
+	struct inet_sock *isk;
+	int family;
+
+	/* TODO: need to validate the address firstly */	
+
+	isk = (struct inet_sock *)kp_arg_checknumber(ks, 1);
+	family = isk->sk.__sk_common.skc_family;
+
+	if (family == AF_INET) {
+		set_number(ks->top, isk->inet_daddr);
+	} else {
+		kp_error(ks, "ip_sock_daddr only support ipv4 now\n");
+		set_nil(ks->top);
+	}
+
+	incr_top(ks);
+	return 1;
+
+}
+
+/**
+ * Returns a string representation for an IP address
+ */
+static int kplib_net_format_ip_addr(ktap_state_t *ks)
+{
+	__be32 ip = (__be32)kp_arg_checknumber(ks, 1);
+	ktap_str_t *ts;
+	char ipstr[32];
+
+	snprintf(ipstr, 32, "%pI4", &ip);
+	ts = kp_str_newz(ks, ipstr);
+	if (ts) {
+		set_string(ks->top, kp_str_newz(ks, ipstr));
+		incr_top(ks);
+		return 1;
+	} else
+		return -1;
+}
+
+static const ktap_libfunc_t net_lib_funcs[] = {
+	{"ip_sock_saddr", kplib_net_ip_sock_saddr},
+	{"ip_sock_daddr", kplib_net_ip_sock_daddr},
+	{"format_ip_addr", kplib_net_format_ip_addr},
+	{NULL}
+};
+
+int kp_lib_init_net(ktap_state_t *ks)
+{
+	return kp_vm_register_lib(ks, "net", net_lib_funcs); 
+}
diff --git a/kernel/trace/ktap/lib_table.c b/kernel/trace/ktap/lib_table.c
new file mode 100644
index 0000000..470461c
--- /dev/null
+++ b/kernel/trace/ktap/lib_table.c
@@ -0,0 +1,58 @@
+/*
+ * lib_table.c - Table library
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@...il.com>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <uapi/ktap/ktap_types.h>
+#include "ktap.h"
+#include "kp_obj.h"
+#include "kp_vm.h"
+#include "kp_tab.h"
+
+static int kplib_table_new(ktap_state_t *ks)
+{
+	int narr = kp_arg_checkoptnumber(ks, 1, 0);
+	int nrec = kp_arg_checkoptnumber(ks, 2, 0);
+	ktap_tab_t *h;
+
+	h = kp_tab_new_ah(ks, narr, nrec);
+	if (!h) {
+		set_nil(ks->top);
+	} else {
+		set_table(ks->top, h);
+	}
+
+	incr_top(ks);
+	return 1;
+}
+
+static const ktap_libfunc_t table_lib_funcs[] = {
+	{"new",	kplib_table_new},
+	{NULL}
+};
+
+int kp_lib_init_table(ktap_state_t *ks)
+{
+	return kp_vm_register_lib(ks, "table", table_lib_funcs);
+}
+
diff --git a/kernel/trace/ktap/lib_timer.c b/kernel/trace/ktap/lib_timer.c
new file mode 100644
index 0000000..d1b6b77
--- /dev/null
+++ b/kernel/trace/ktap/lib_timer.c
@@ -0,0 +1,210 @@
+/*
+ * lib_timer.c - timer library support for ktap
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhangwei@...il.com>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <uapi/ktap/ktap_types.h>
+#include "ktap.h"
+#include "kp_obj.h"
+#include "kp_vm.h"
+#include "kp_events.h"
+
+struct ktap_hrtimer {
+	struct hrtimer timer;
+	ktap_state_t *ks;
+	ktap_func_t *fn;
+	u64 ns;
+	struct list_head list;
+};
+
+/*
+ * Currently ktap disallow tracing event in timer callback closure,
+ * that will corrupt ktap_state_t and ktap stack, because timer closure
+ * and event closure use same irq percpu ktap_state_t and stack.
+ * We can use a different percpu ktap_state_t and stack for timer purpuse,
+ * but that's don't bring any big value with cost on memory consuming.
+ *
+ * So just simply disable tracing in timer closure,
+ * get_recursion_context()/put_recursion_context() is used for this purpose.
+ */
+static enum hrtimer_restart hrtimer_ktap_fn(struct hrtimer *timer)
+{
+	struct ktap_hrtimer *t;
+	ktap_state_t *ks;
+	int rctx;
+
+	rcu_read_lock_sched_notrace();
+
+	t = container_of(timer, struct ktap_hrtimer, timer);
+	rctx = get_recursion_context(t->ks);
+
+	ks = kp_vm_new_thread(t->ks, rctx);
+	set_func(ks->top, t->fn);
+	incr_top(ks);
+	kp_vm_call(ks, ks->top - 1, 0);
+	kp_vm_exit_thread(ks);
+
+	hrtimer_add_expires_ns(timer, t->ns);
+
+	put_recursion_context(ks, rctx);
+	rcu_read_unlock_sched_notrace();
+
+	return HRTIMER_RESTART;
+}
+
+static int set_tick_timer(ktap_state_t *ks, u64 period, ktap_func_t *fn)
+{
+	struct ktap_hrtimer *t;
+
+	t = kp_malloc(ks, sizeof(*t));
+	if (unlikely(!t))
+		return -ENOMEM;
+	t->ks = ks;
+	t->fn = fn;
+	t->ns = period;
+
+	INIT_LIST_HEAD(&t->list);
+	list_add(&t->list, &(G(ks)->timers));
+
+	hrtimer_init(&t->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	t->timer.function = hrtimer_ktap_fn;
+	hrtimer_start(&t->timer, ns_to_ktime(period), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+static int set_profile_timer(ktap_state_t *ks, u64 period, ktap_func_t *fn)
+{
+	struct perf_event_attr attr;
+
+	memset(&attr, 0, sizeof(attr));
+	attr.type = PERF_TYPE_SOFTWARE;
+	attr.config = PERF_COUNT_SW_CPU_CLOCK;
+	attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
+			   PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD;
+	attr.sample_period = period;
+	attr.size = sizeof(attr);
+	attr.disabled = 0;
+
+	return kp_event_create(ks, &attr, NULL, NULL, fn);
+}
+
+static int do_tick_profile(ktap_state_t *ks, int is_tick)
+{
+	const char *str = kp_arg_checkstring(ks, 1);
+	ktap_func_t *fn = kp_arg_checkfunction(ks, 2);
+	const char *tmp;
+	char interval_str[32] = {0};
+	char suffix[10] = {0};
+	int i = 0, ret, n;
+	int factor;
+
+	tmp = str;
+	while (isdigit(*tmp))
+		tmp++;
+
+	strncpy(interval_str, str, tmp - str);
+	if (kstrtoint(interval_str, 10, &n))
+		goto error;
+
+	strncpy(suffix, tmp, 9);
+	while (suffix[i] != ' ' && suffix[i] != '\0')
+		i++;
+
+	suffix[i] = '\0';
+
+	if (!strcmp(suffix, "s") || !strcmp(suffix, "sec"))
+		factor = NSEC_PER_SEC;
+	else if (!strcmp(suffix, "ms") || !strcmp(suffix, "msec"))
+		factor = NSEC_PER_MSEC;
+	else if (!strcmp(suffix, "us") || !strcmp(suffix, "usec"))
+		factor = NSEC_PER_USEC;
+	else
+		goto error;
+
+	if (is_tick)
+		ret = set_tick_timer(ks, (u64)factor * n, fn);
+	else
+		ret = set_profile_timer(ks, (u64)factor * n, fn);
+
+	return ret;
+
+ error:
+	kp_error(ks, "cannot parse timer interval: %s\n", str);
+	return -1;
+}
+
+/*
+ * tick-n probes fire on only one CPU per interval.
+ * valid time suffixes: sec/s, msec/ms, usec/us
+ */
+static int kplib_timer_tick(ktap_state_t *ks)
+{
+	/* timer.tick cannot be called in trace_end state */
+	if (G(ks)->state != KTAP_RUNNING) {
+		kp_error(ks,
+			 "timer.tick only can be called in RUNNING state\n");
+		return -1;
+	}
+
+	return do_tick_profile(ks, 1);
+}
+
+/*
+ * A profile-n probe fires every fixed interval on every CPU
+ * valid time suffixes: sec/s, msec/ms, usec/us
+ */
+static int kplib_timer_profile(ktap_state_t *ks)
+{
+	/* timer.profile cannot be called in trace_end state */
+	if (G(ks)->state != KTAP_RUNNING) {
+		kp_error(ks,
+			 "timer.profile only can be called in RUNNING state\n");
+		return -1;
+	}
+
+	return do_tick_profile(ks, 0);
+}
+
+void kp_exit_timers(ktap_state_t *ks)
+{
+	struct ktap_hrtimer *t, *tmp;
+	struct list_head *timers_list = &(G(ks)->timers);
+
+	list_for_each_entry_safe(t, tmp, timers_list, list) {
+		hrtimer_cancel(&t->timer);
+		kp_free(ks, t);
+	}
+}
+
+static const ktap_libfunc_t timer_lib_funcs[] = {
+	{"profile",	kplib_timer_profile},
+	{"tick",	kplib_timer_tick},
+	{NULL}
+};
+
+int kp_lib_init_timer(ktap_state_t *ks)
+{
+	return kp_vm_register_lib(ks, "timer", timer_lib_funcs);
+}
+
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists