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.zhang...@gmail.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.zhang...@gmail.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.zhang...@gmail.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.zhang...@gmail.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.zhang...@gmail.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.zhang...@gmail.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.zhang...@gmail.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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to