| From 982d59f0bfdb7a85fd64fcebf4d18b49dfdf5120 Mon Sep 17 00:00:00 2001 |
| From: Li xin <lixin.fnst@cn.fujitsu.com> |
| Date: Fri, 17 Oct 2014 15:06:28 +0300 |
| Subject: [PATCH] ktap-0.4 |
| |
| --- |
| drivers/staging/Kconfig | 2 |
| drivers/staging/Makefile | 1 |
| drivers/staging/ktap/Kconfig | 32 |
| drivers/staging/ktap/Makefile | 203 + |
| drivers/staging/ktap/README.md | 167 |
| drivers/staging/ktap/RELEASES.txt | 155 |
| drivers/staging/ktap/doc/tutorial.md | 691 +++ |
| drivers/staging/ktap/include/ktap_ffi.h | 180 |
| drivers/staging/ktap/include/ktap_opcodes.h | 239 + |
| drivers/staging/ktap/include/ktap_types.h | 609 +++ |
| drivers/staging/ktap/runtime/ffi/call_x86_64.S | 143 |
| drivers/staging/ktap/runtime/ffi/cdata.c | 67 |
| drivers/staging/ktap/runtime/ffi/ffi_call.c | 427 ++ |
| drivers/staging/ktap/runtime/ffi/ffi_symbol.c | 174 |
| drivers/staging/ktap/runtime/ffi/ffi_type.c | 51 |
| drivers/staging/ktap/runtime/ffi/ffi_util.c | 92 |
| drivers/staging/ktap/runtime/kp_amalg.c | 43 |
| drivers/staging/ktap/runtime/kp_load.c | 401 ++ |
| drivers/staging/ktap/runtime/kp_load.h | 6 |
| drivers/staging/ktap/runtime/kp_obj.c | 478 ++ |
| drivers/staging/ktap/runtime/kp_obj.h | 29 |
| drivers/staging/ktap/runtime/kp_opcode.c | 134 |
| drivers/staging/ktap/runtime/kp_str.c | 460 ++ |
| drivers/staging/ktap/runtime/kp_str.h | 20 |
| drivers/staging/ktap/runtime/kp_tab.c | 1396 +++++++ |
| drivers/staging/ktap/runtime/kp_tab.h | 32 |
| drivers/staging/ktap/runtime/kp_transport.c | 641 +++ |
| drivers/staging/ktap/runtime/kp_transport.h | 13 |
| drivers/staging/ktap/runtime/kp_vm.c | 1496 +++++++ |
| drivers/staging/ktap/runtime/kp_vm.h | 16 |
| drivers/staging/ktap/runtime/ktap.c | 217 + |
| drivers/staging/ktap/runtime/ktap.h | 130 |
| drivers/staging/ktap/runtime/lib_ansi.c | 155 |
| drivers/staging/ktap/runtime/lib_base.c | 607 +++ |
| drivers/staging/ktap/runtime/lib_ffi.c | 50 |
| drivers/staging/ktap/runtime/lib_kdebug.c | 426 ++ |
| drivers/staging/ktap/runtime/lib_timer.c | 193 |
| drivers/staging/ktap/samples/ansi/ansi_color_demo.kp | 22 |
| drivers/staging/ktap/samples/basic/backtrace.kp | 6 |
| drivers/staging/ktap/samples/basic/event_trigger.kp | 24 |
| drivers/staging/ktap/samples/basic/event_trigger_ftrace.kp | 28 |
| drivers/staging/ktap/samples/basic/ftrace.kp | 6 |
| drivers/staging/ktap/samples/basic/function_time.kp | 57 |
| drivers/staging/ktap/samples/basic/kretprobe.kp | 6 |
| drivers/staging/ktap/samples/ffi/ffi_kmalloc.kp | 19 |
| drivers/staging/ktap/samples/ffi/printk.kp | 10 |
| drivers/staging/ktap/samples/ffi/sched_clock.kp | 6 |
| drivers/staging/ktap/samples/game/tetris.kp | 293 + |
| drivers/staging/ktap/samples/helloworld.kp | 3 |
| drivers/staging/ktap/samples/interrupt/hardirq_time.kp | 24 |
| drivers/staging/ktap/samples/interrupt/softirq_time.kp | 24 |
| drivers/staging/ktap/samples/io/kprobes-do-sys-open.kp | 20 |
| drivers/staging/ktap/samples/io/traceio.kp | 54 |
| drivers/staging/ktap/samples/mem/kmalloc-top.kp | 17 |
| drivers/staging/ktap/samples/mem/kmem.kp | 30 |
| drivers/staging/ktap/samples/profiling/function_profiler.kp | 41 |
| drivers/staging/ktap/samples/profiling/stack_profile.kp | 30 |
| drivers/staging/ktap/samples/schedule/sched_transition.kp | 5 |
| drivers/staging/ktap/samples/schedule/schedtimes.kp | 125 |
| drivers/staging/ktap/samples/syscalls/errinfo.kp | 145 |
| drivers/staging/ktap/samples/syscalls/execve.kp | 8 |
| drivers/staging/ktap/samples/syscalls/opensnoop.kp | 31 |
| drivers/staging/ktap/samples/syscalls/sctop.kp | 13 |
| drivers/staging/ktap/samples/syscalls/syscalls.kp | 6 |
| drivers/staging/ktap/samples/syscalls/syscalls_count.kp | 54 |
| drivers/staging/ktap/samples/syscalls/syscalls_count_by_proc.kp | 22 |
| drivers/staging/ktap/samples/syscalls/syslatl.kp | 30 |
| drivers/staging/ktap/samples/syscalls/syslist.kp | 31 |
| drivers/staging/ktap/samples/tracepoints/eventcount.kp | 210 + |
| drivers/staging/ktap/samples/tracepoints/eventcount_by_proc.kp | 57 |
| drivers/staging/ktap/samples/tracepoints/tracepoints.kp | 6 |
| drivers/staging/ktap/samples/userspace/gcc_unwind.kp | 9 |
| drivers/staging/ktap/samples/userspace/glibc_func_hist.kp | 44 |
| drivers/staging/ktap/samples/userspace/glibc_sdt.kp | 11 |
| drivers/staging/ktap/samples/userspace/glibc_trace.kp | 11 |
| drivers/staging/ktap/samples/userspace/malloc_free.kp | 20 |
| drivers/staging/ktap/samples/userspace/malloc_size_hist.kp | 22 |
| drivers/staging/ktap/test/arg.kp | 24 |
| drivers/staging/ktap/test/arithmetic.kp | 50 |
| drivers/staging/ktap/test/benchmark/sembench.c | 556 ++ |
| drivers/staging/ktap/test/benchmark/test.sh | 26 |
| drivers/staging/ktap/test/concat.kp | 15 |
| drivers/staging/ktap/test/count.kp | 20 |
| drivers/staging/ktap/test/ffi/.gitignore | 2 |
| drivers/staging/ktap/test/ffi/Makefile | 46 |
| drivers/staging/ktap/test/ffi/cparser_test.c | 322 + |
| drivers/staging/ktap/test/ffi/ffi_test.kp | 47 |
| drivers/staging/ktap/test/ffi/ktap_ffi_test.c | 64 |
| drivers/staging/ktap/test/fibonacci.kp | 36 |
| drivers/staging/ktap/test/function.kp | 88 |
| drivers/staging/ktap/test/if.kp | 24 |
| drivers/staging/ktap/test/kprobe.kp | 19 |
| drivers/staging/ktap/test/kretprobe.kp | 14 |
| drivers/staging/ktap/test/ksym.kp | 17 |
| drivers/staging/ktap/test/len.kp | 25 |
| drivers/staging/ktap/test/looping.kp | 40 |
| drivers/staging/ktap/test/pairs.kp | 84 |
| drivers/staging/ktap/test/ptable.kp | 46 |
| drivers/staging/ktap/test/run_test.sh | 62 |
| drivers/staging/ktap/test/stack_overflow.kp | 9 |
| drivers/staging/ktap/test/table.kp | 71 |
| drivers/staging/ktap/test/timer.kp | 28 |
| drivers/staging/ktap/test/tracepoint.kp | 22 |
| drivers/staging/ktap/test/zerodivide.kp | 5 |
| drivers/staging/ktap/userspace/code.c | 998 +++++ |
| drivers/staging/ktap/userspace/cparser.h | 202 + |
| drivers/staging/ktap/userspace/dump.c | 251 + |
| drivers/staging/ktap/userspace/eventdef.c | 857 ++++ |
| drivers/staging/ktap/userspace/ffi/cparser.c | 1755 ++++++++ |
| drivers/staging/ktap/userspace/ffi/ctype.c | 551 ++ |
| drivers/staging/ktap/userspace/ktapc.h | 393 ++ |
| drivers/staging/ktap/userspace/ktapio.c | 106 |
| drivers/staging/ktap/userspace/lex.c | 632 +++ |
| drivers/staging/ktap/userspace/main.c | 727 +++ |
| drivers/staging/ktap/userspace/parser.c | 1963 ++++++++++ |
| drivers/staging/ktap/userspace/symbol.c | 291 + |
| drivers/staging/ktap/userspace/symbol.h | 50 |
| drivers/staging/ktap/userspace/util.c | 381 + |
| 118 files changed, 22675 insertions(+) |
| create mode 100644 drivers/staging/ktap/Kconfig |
| create mode 100644 drivers/staging/ktap/Makefile |
| create mode 100644 drivers/staging/ktap/README.md |
| create mode 100644 drivers/staging/ktap/RELEASES.txt |
| create mode 100644 drivers/staging/ktap/doc/tutorial.md |
| create mode 100644 drivers/staging/ktap/include/ktap_ffi.h |
| create mode 100644 drivers/staging/ktap/include/ktap_opcodes.h |
| create mode 100644 drivers/staging/ktap/include/ktap_types.h |
| create mode 100644 drivers/staging/ktap/runtime/ffi/call_x86_64.S |
| create mode 100644 drivers/staging/ktap/runtime/ffi/cdata.c |
| create mode 100644 drivers/staging/ktap/runtime/ffi/ffi_call.c |
| create mode 100644 drivers/staging/ktap/runtime/ffi/ffi_symbol.c |
| create mode 100644 drivers/staging/ktap/runtime/ffi/ffi_type.c |
| create mode 100644 drivers/staging/ktap/runtime/ffi/ffi_util.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_amalg.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_load.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_load.h |
| create mode 100644 drivers/staging/ktap/runtime/kp_obj.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_obj.h |
| create mode 100644 drivers/staging/ktap/runtime/kp_opcode.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_str.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_str.h |
| create mode 100644 drivers/staging/ktap/runtime/kp_tab.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_tab.h |
| create mode 100644 drivers/staging/ktap/runtime/kp_transport.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_transport.h |
| create mode 100644 drivers/staging/ktap/runtime/kp_vm.c |
| create mode 100644 drivers/staging/ktap/runtime/kp_vm.h |
| create mode 100644 drivers/staging/ktap/runtime/ktap.c |
| create mode 100644 drivers/staging/ktap/runtime/ktap.h |
| create mode 100644 drivers/staging/ktap/runtime/lib_ansi.c |
| create mode 100644 drivers/staging/ktap/runtime/lib_base.c |
| create mode 100644 drivers/staging/ktap/runtime/lib_ffi.c |
| create mode 100644 drivers/staging/ktap/runtime/lib_kdebug.c |
| create mode 100644 drivers/staging/ktap/runtime/lib_timer.c |
| create mode 100644 drivers/staging/ktap/samples/ansi/ansi_color_demo.kp |
| create mode 100644 drivers/staging/ktap/samples/basic/backtrace.kp |
| create mode 100644 drivers/staging/ktap/samples/basic/event_trigger.kp |
| create mode 100644 drivers/staging/ktap/samples/basic/event_trigger_ftrace.kp |
| create mode 100644 drivers/staging/ktap/samples/basic/ftrace.kp |
| create mode 100644 drivers/staging/ktap/samples/basic/function_time.kp |
| create mode 100644 drivers/staging/ktap/samples/basic/kretprobe.kp |
| create mode 100644 drivers/staging/ktap/samples/ffi/ffi_kmalloc.kp |
| create mode 100644 drivers/staging/ktap/samples/ffi/printk.kp |
| create mode 100644 drivers/staging/ktap/samples/ffi/sched_clock.kp |
| create mode 100644 drivers/staging/ktap/samples/game/tetris.kp |
| create mode 100644 drivers/staging/ktap/samples/helloworld.kp |
| create mode 100644 drivers/staging/ktap/samples/interrupt/hardirq_time.kp |
| create mode 100644 drivers/staging/ktap/samples/interrupt/softirq_time.kp |
| create mode 100644 drivers/staging/ktap/samples/io/kprobes-do-sys-open.kp |
| create mode 100644 drivers/staging/ktap/samples/io/traceio.kp |
| create mode 100644 drivers/staging/ktap/samples/mem/kmalloc-top.kp |
| create mode 100644 drivers/staging/ktap/samples/mem/kmem.kp |
| create mode 100644 drivers/staging/ktap/samples/profiling/function_profiler.kp |
| create mode 100644 drivers/staging/ktap/samples/profiling/stack_profile.kp |
| create mode 100644 drivers/staging/ktap/samples/schedule/sched_transition.kp |
| create mode 100644 drivers/staging/ktap/samples/schedule/schedtimes.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/errinfo.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/execve.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/opensnoop.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/sctop.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/syscalls.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/syscalls_count.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/syscalls_count_by_proc.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/syslatl.kp |
| create mode 100644 drivers/staging/ktap/samples/syscalls/syslist.kp |
| create mode 100644 drivers/staging/ktap/samples/tracepoints/eventcount.kp |
| create mode 100644 drivers/staging/ktap/samples/tracepoints/eventcount_by_proc.kp |
| create mode 100644 drivers/staging/ktap/samples/tracepoints/tracepoints.kp |
| create mode 100644 drivers/staging/ktap/samples/userspace/gcc_unwind.kp |
| create mode 100644 drivers/staging/ktap/samples/userspace/glibc_func_hist.kp |
| create mode 100644 drivers/staging/ktap/samples/userspace/glibc_sdt.kp |
| create mode 100644 drivers/staging/ktap/samples/userspace/glibc_trace.kp |
| create mode 100644 drivers/staging/ktap/samples/userspace/malloc_free.kp |
| create mode 100644 drivers/staging/ktap/samples/userspace/malloc_size_hist.kp |
| create mode 100644 drivers/staging/ktap/test/arg.kp |
| create mode 100644 drivers/staging/ktap/test/arithmetic.kp |
| create mode 100644 drivers/staging/ktap/test/benchmark/sembench.c |
| create mode 100644 drivers/staging/ktap/test/benchmark/test.sh |
| create mode 100644 drivers/staging/ktap/test/concat.kp |
| create mode 100644 drivers/staging/ktap/test/count.kp |
| create mode 100644 drivers/staging/ktap/test/ffi/.gitignore |
| create mode 100644 drivers/staging/ktap/test/ffi/Makefile |
| create mode 100644 drivers/staging/ktap/test/ffi/cparser_test.c |
| create mode 100644 drivers/staging/ktap/test/ffi/ffi_test.kp |
| create mode 100644 drivers/staging/ktap/test/ffi/ktap_ffi_test.c |
| create mode 100644 drivers/staging/ktap/test/fibonacci.kp |
| create mode 100644 drivers/staging/ktap/test/function.kp |
| create mode 100644 drivers/staging/ktap/test/if.kp |
| create mode 100644 drivers/staging/ktap/test/kprobe.kp |
| create mode 100644 drivers/staging/ktap/test/kretprobe.kp |
| create mode 100644 drivers/staging/ktap/test/ksym.kp |
| create mode 100644 drivers/staging/ktap/test/len.kp |
| create mode 100644 drivers/staging/ktap/test/looping.kp |
| create mode 100644 drivers/staging/ktap/test/pairs.kp |
| create mode 100644 drivers/staging/ktap/test/ptable.kp |
| create mode 100644 drivers/staging/ktap/test/run_test.sh |
| create mode 100644 drivers/staging/ktap/test/stack_overflow.kp |
| create mode 100644 drivers/staging/ktap/test/table.kp |
| create mode 100644 drivers/staging/ktap/test/timer.kp |
| create mode 100644 drivers/staging/ktap/test/tracepoint.kp |
| create mode 100644 drivers/staging/ktap/test/zerodivide.kp |
| create mode 100644 drivers/staging/ktap/userspace/code.c |
| create mode 100644 drivers/staging/ktap/userspace/cparser.h |
| create mode 100644 drivers/staging/ktap/userspace/dump.c |
| create mode 100644 drivers/staging/ktap/userspace/eventdef.c |
| create mode 100644 drivers/staging/ktap/userspace/ffi/cparser.c |
| create mode 100644 drivers/staging/ktap/userspace/ffi/ctype.c |
| create mode 100644 drivers/staging/ktap/userspace/ktapc.h |
| create mode 100644 drivers/staging/ktap/userspace/ktapio.c |
| create mode 100644 drivers/staging/ktap/userspace/lex.c |
| create mode 100644 drivers/staging/ktap/userspace/main.c |
| create mode 100644 drivers/staging/ktap/userspace/parser.c |
| create mode 100644 drivers/staging/ktap/userspace/symbol.c |
| create mode 100644 drivers/staging/ktap/userspace/symbol.h |
| create mode 100644 drivers/staging/ktap/userspace/util.c |
| |
| --- a/drivers/staging/Kconfig |
| +++ b/drivers/staging/Kconfig |
| @@ -146,4 +146,6 @@ source "drivers/staging/dgnc/Kconfig" |
| |
| source "drivers/staging/dgap/Kconfig" |
| |
| +source "drivers/staging/ktap/Kconfig" |
| + |
| endif # STAGING |
| --- a/drivers/staging/Makefile |
| +++ b/drivers/staging/Makefile |
| @@ -65,3 +65,4 @@ obj-$(CONFIG_XILLYBUS) += xillybus/ |
| obj-$(CONFIG_DGNC) += dgnc/ |
| obj-$(CONFIG_DGAP) += dgap/ |
| obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ |
| +obj-$(CONFIG_KTAP) += ktap/ |
| --- /dev/null |
| +++ b/drivers/staging/ktap/Kconfig |
| @@ -0,0 +1,32 @@ |
| +config KTAP |
| + tristate "a programable dynamic tracing tool for Linux" |
| + depends on PERF_EVENTS && EVENT_TRACING |
| + default n |
| + help |
| + ktap is a new script-based dynamic tracing tool for Linux, |
| + it uses a scripting language and lets users trace the |
| + Linux kernel dynamically. ktap is designed to give |
| + operational insights with interoperability that allow |
| + users to tune, troubleshoot and extend kernel and application. |
| + It's similar with Linux Systemtap and Solaris Dtrace. |
| + |
| + ktap have different design principles from Linux mainstream |
| + dynamic tracing language in that it's based on bytecode, |
| + so it doesn't depend upon GCC, doesn't require compiling |
| + kernel module for each script, safe to use in production |
| + environment, fulfilling the embedded ecosystem's tracing needs. |
| + |
| + See ktap tutorial for more information: |
| + http://www.ktap.org/doc/tutorial.html |
| + |
| +config KTAP_FFI |
| + tristate "FFI support for ktap" |
| + depends on KTAP |
| + depends on X86_64 |
| + default n |
| + help |
| + This option brings FFI support to ktap. With FFI enabled ktap, |
| + users can call into native kernel C function directly in ktap |
| + script. Except for a new cdef keyword, this option also adds |
| + a ffi module which exports helper functions like ffi.new and |
| + ffi.sizeof. |
| --- /dev/null |
| +++ b/drivers/staging/ktap/Makefile |
| @@ -0,0 +1,203 @@ |
| + |
| +# |
| +# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds) |
| +# (this will also disable resolve resolving symbols in DSO functionality) |
| +# |
| +# Define FFI if you want to compile ktap with FFI support. By default This |
| +# toggle is off. |
| +# |
| +# Define amalg to enable amalgamation build, This compiles the ktapvm as |
| +# one huge C file and allows GCC to generate faster and shorter code. Alas, |
| +# this requires lots of memory during the build. |
| +# Recommend to use amalgmation build as default. |
| +amalg = 1 |
| +NO_LIBELF = 1 |
| +# Do not instrument the tracer itself: |
| +ifdef CONFIG_FUNCTION_TRACER |
| +ORIG_CFLAGS := $(KBUILD_CFLAGS) |
| +KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS)) |
| +endif |
| + |
| +all: mod ktap |
| + |
| +INC = include |
| +RUNTIME = runtime |
| + |
| +FFIDIR = $(RUNTIME)/ffi |
| +KTAP_LIBS = -lpthread |
| + |
| +LIB_OBJS += $(RUNTIME)/lib_base.o $(RUNTIME)/lib_kdebug.o $(RUNTIME)/lib_timer.o \ |
| + $(RUNTIME)/lib_ansi.o |
| + |
| +ifndef amalg |
| +ifdef FFI |
| +FFI_OBJS += $(FFIDIR)/ffi_call.o $(FFIDIR)/ffi_type.o $(FFIDIR)/ffi_symbol.o \ |
| + $(FFIDIR)/cdata.o $(FFIDIR)/ffi_util.o |
| +RUNTIME_OBJS += $(FFI_OBJS) |
| +LIB_OBJS += $(RUNTIME)/lib_ffi.o |
| +endif |
| +RUNTIME_OBJS += $(RUNTIME)/ktap.o $(RUNTIME)/kp_load.o $(RUNTIME)/kp_obj.o \ |
| + $(RUNTIME)/kp_str.o $(RUNTIME)/kp_tab.o $(RUNTIME)/kp_vm.o \ |
| + $(RUNTIME)/kp_opcode.o $(RUNTIME)/kp_transport.o \ |
| + $(LIB_OBJS) |
| +else |
| +RUNTIME_OBJS += $(RUNTIME)/kp_amalg.o |
| +endif |
| + |
| +ifdef FFI |
| +ifeq ($(KBUILD_MODULES), 1) |
| +ifdef CONFIG_X86_64 |
| +# call_x86_64.o is compiled from call_x86_64.S |
| +RUNTIME_OBJS += $(FFIDIR)/call_x86_64.o |
| +else |
| +$(error ktap FFI only supports x86_64 for now!) |
| +endif |
| +endif |
| + |
| + |
| +ccflags-y += -DCONFIG_KTAP_FFI |
| +endif |
| + |
| +obj-m += ktapvm.o |
| +ktapvm-y := $(RUNTIME_OBJS) |
| + |
| +KVERSION ?= $(shell uname -r) |
| +KERNEL_SRC ?= /lib/modules/$(KVERSION)/build |
| +PWD := $(shell pwd) |
| +mod: |
| + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules |
| + |
| +modules_install: |
| + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install |
| + |
| +KTAPC_CFLAGS = -Wall -O2 |
| + |
| + |
| +# try-cc |
| +# Usage: option = $(call try-cc, source-to-build, cc-options, msg) |
| +ifneq ($(V),1) |
| +TRY_CC_OUTPUT= > /dev/null 2>&1 |
| +endif |
| +TRY_CC_MSG=echo " CHK $(3)" 1>&2; |
| + |
| +try-cc = $(shell sh -c \ |
| + 'TMP="/tmp/.$$$$"; \ |
| + $(TRY_CC_MSG) \ |
| + echo "$(1)" | \ |
| + $(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \ |
| + rm -f "$$TMP"') |
| + |
| + |
| +define SOURCE_LIBELF |
| +#include <libelf.h> |
| + |
| +int main(void) |
| +{ |
| + Elf *elf = elf_begin(0, ELF_C_READ, 0); |
| + return (long)elf; |
| +} |
| +endef |
| + |
| +FLAGS_LIBELF = -lelf |
| + |
| +ifdef NO_LIBELF |
| + KTAPC_CFLAGS += -DNO_LIBELF |
| +else |
| +ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y) |
| + $(warning No libelf found, disables symbol resolving, please install elfutils-libelf-devel/libelf-dev); |
| + NO_LIBELF := 1 |
| + KTAPC_CFLAGS += -DNO_LIBELF |
| +else |
| + KTAP_LIBS += -lelf |
| +endif |
| +endif |
| + |
| +UDIR = userspace |
| + |
| +$(UDIR)/lex.o: $(UDIR)/lex.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/parser.o: $(UDIR)/parser.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/code.o: $(UDIR)/code.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/dump.o: $(UDIR)/dump.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/main.o: $(UDIR)/main.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/util.o: $(UDIR)/util.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/ktapio.o: $(UDIR)/ktapio.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/eventdef.o: $(UDIR)/eventdef.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/kp_opcode.o: $(RUNTIME)/kp_opcode.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/kp_tab.o: $(RUNTIME)/kp_tab.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/kp_str.o: $(RUNTIME)/kp_str.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/kp_obj.o: $(RUNTIME)/kp_obj.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +ifndef NO_LIBELF |
| +$(UDIR)/symbol.o: $(UDIR)/symbol.c |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +endif |
| +ifdef FFI |
| +KTAPC_CFLAGS += -DCONFIG_KTAP_FFI |
| +$(UDIR)/ffi_type.o: $(RUNTIME)/ffi/ffi_type.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/ffi/cparser.o: $(UDIR)/ffi/cparser.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +$(UDIR)/ffi/ctype.o: $(UDIR)/ffi/ctype.c $(INC)/* |
| + $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< |
| +endif |
| + |
| + |
| +KTAPOBJS = |
| +KTAPOBJS += $(UDIR)/lex.o |
| +KTAPOBJS += $(UDIR)/parser.o |
| +KTAPOBJS += $(UDIR)/code.o |
| +KTAPOBJS += $(UDIR)/dump.o |
| +KTAPOBJS += $(UDIR)/main.o |
| +KTAPOBJS += $(UDIR)/util.o |
| +KTAPOBJS += $(UDIR)/ktapio.o |
| +KTAPOBJS += $(UDIR)/eventdef.o |
| +KTAPOBJS += $(UDIR)/kp_opcode.o |
| +KTAPOBJS += $(UDIR)/kp_tab.o |
| +KTAPOBJS += $(UDIR)/kp_str.o |
| +KTAPOBJS += $(UDIR)/kp_obj.o |
| +ifndef NO_LIBELF |
| +KTAPOBJS += $(UDIR)/symbol.o |
| +endif |
| +ifdef FFI |
| +KTAPOBJS += $(UDIR)/ffi_type.o |
| +KTAPOBJS += $(UDIR)/ffi/cparser.o |
| +KTAPOBJS += $(UDIR)/ffi/ctype.o |
| +endif |
| + |
| +ktap: $(KTAPOBJS) |
| + $(QUIET_LINK)$(CC) $(KTAPC_CFLAGS) -o $@ $(KTAPOBJS) $(KTAP_LIBS) |
| + |
| +KMISC := /lib/modules/$(KVERSION)/ktapvm/ |
| + |
| +install: mod ktap |
| + install -d $(KMISC) |
| + install -m 644 -c *.ko /lib/modules/$(KVERSION)/ktapvm/ |
| + /sbin/depmod -a |
| + |
| +load: |
| + insmod ktapvm.ko |
| + |
| +unload: |
| + rmmod ktapvm |
| + |
| +test: FORCE |
| + cd test; sh ./run_test.sh; cd - |
| + |
| +clean: |
| + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean |
| + $(RM) ktap |
| + |
| +PHONY += FORCE |
| +FORCE: |
| + |
| --- /dev/null |
| +++ b/drivers/staging/ktap/README.md |
| @@ -0,0 +1,167 @@ |
| +# ktap |
| + |
| +A New Scripting Dynamic Tracing Tool For Linux |
| +[www.ktap.org][homepage] |
| + |
| +ktap is a new scripting dynamic tracing tool for Linux, |
| +it uses a scripting language and lets users trace the Linux kernel dynamically. |
| +ktap is designed to give operational insights with interoperability |
| +that allows users to tune, troubleshoot and extend kernel and application. |
| +It's similar with Linux Systemtap and Solaris Dtrace. |
| + |
| +ktap have different design principles from Linux mainstream dynamic tracing |
| +language in that it's based on bytecode, so it doesn't depend upon GCC, |
| +doesn't require compiling kernel module for each script, safe to use in |
| +production environment, fulfilling the embedded ecosystem's tracing needs. |
| + |
| +More information can be found at [ktap homepage][homepage]. |
| + |
| +[homepage]: http://www.ktap.org |
| + |
| +## Highlights |
| + |
| + * simple but powerful scripting language |
| + * register based interpreter (heavily optimized) in Linux kernel |
| + * small and lightweight (6KLOC of interpreter) |
| + * not depend on gcc for each script running |
| + * easy to use in embedded environment without debugging info |
| + * support for tracepoint, kprobe, uprobe, function trace, timer, and more |
| + * supported in x86, arm, ppc, mips |
| + * safety in sandbox |
| + |
| +## Building & Running |
| + |
| +1. Clone ktap from github |
| + |
| + $ git clone http://github.com/ktap/ktap.git |
| + |
| +2. Compiling ktap |
| + |
| + $ cd ktap |
| + $ make #generate ktapvm kernel module and ktap binary |
| + |
| +3. Load ktapvm kernel module(make sure debugfs mounted) |
| + |
| + $ make load #need to be root or have sudo access |
| + |
| +4. Running ktap |
| + |
| + $ ./ktap samples/helloworld.kp |
| + |
| + |
| +## Examples |
| + |
| +1. simplest one-liner command to enable all tracepoints |
| + |
| + ktap -e "trace *:* { print(argevent) }" |
| + |
| +2. syscall tracing on target process |
| + |
| + ktap -e "trace syscalls:* { print(argevent) }" -- ls |
| + |
| +3. ftrace(kernel newer than 3.3, and must compiled with CONFIG_FUNCTION_TRACER) |
| + |
| + ktap -e "trace ftrace:function { print(argevent) }" |
| + |
| + ktap -e "trace ftrace:function /ip==mutex*/ { print(argevent) }" |
| + |
| +4. simple syscall tracing |
| + |
| + trace syscalls:* { |
| + print(cpu(), pid(), execname(), argevent) |
| + } |
| + |
| +5. syscall tracing in histogram style |
| + |
| + s = {} |
| + |
| + trace syscalls:sys_enter_* { |
| + s[argname] += 1 |
| + } |
| + |
| + trace_end { |
| + histogram(s) |
| + } |
| + |
| +6. kprobe tracing |
| + |
| + trace probe:do_sys_open dfd=%di fname=%dx flags=%cx mode=+4($stack) { |
| + print("entry:", execname(), argevent) |
| + } |
| + |
| + trace probe:do_sys_open%return fd=$retval { |
| + print("exit:", execname(), argevent) |
| + } |
| + |
| +7. uprobe tracing |
| + |
| + trace probe:/lib/libc.so.6:malloc { |
| + print("entry:", execname(), argevent) |
| + } |
| + |
| + trace probe:/lib/libc.so.6:malloc%return { |
| + print("exit:", execname(), argevent) |
| + } |
| + |
| +8. stapsdt tracing (userspace static marker) |
| + |
| + trace sdt:/lib64/libc.so.6:lll_futex_wake { |
| + print("lll_futex_wake", execname(), argevent) |
| + } |
| + |
| + or: |
| + |
| + #trace all static mark in libc |
| + trace sdt:/lib64/libc.so.6:* { |
| + print(execname(), argevent) |
| + } |
| + |
| +9. timer |
| + |
| + tick-1ms { |
| + printf("time fired on one cpu\n"); |
| + } |
| + |
| + profile-2s { |
| + printf("time fired on every cpu\n"); |
| + } |
| + |
| +10. FFI (Call kernel function from ktap script, need compile with FFI=1) |
| + |
| + cdef[[ |
| + int printk(char *fmt, ...); |
| + ]] |
| + |
| + C.printk("This message is called from ktap ffi\n") |
| + |
| +More examples can be found at [samples][samples_dir] directory. |
| + |
| +[samples_dir]: https://github.com/ktap/ktap/tree/master/samples |
| + |
| +## Mailing list |
| + |
| +ktap@freelists.org |
| +You can subscribe to ktap mailing list at link (subscribe before posting): |
| +http://www.freelists.org/list/ktap |
| + |
| + |
| +## Copyright and License |
| + |
| +ktap is licensed under GPL v2 |
| + |
| +Copyright (C) 2012-2013, Jovi Zhangwei <jovi.zhangwei@gmail.com>. |
| +All rights reserved. |
| + |
| + |
| +## Contribution |
| + |
| +ktap is still under active development, so contributions are welcome. |
| +You are encouraged to report bugs, provide feedback, send feature request, |
| +or hack on it. |
| + |
| + |
| +## See More |
| + |
| +More info can be found at [documentation][tutorial] |
| +[tutorial]: http://www.ktap.org/doc/tutorial.html |
| + |
| --- /dev/null |
| +++ b/drivers/staging/ktap/RELEASES.txt |
| @@ -0,0 +1,155 @@ |
| +Version 0.4 (Dec 9 2013) |
| +------------------------- |
| += Highlight changes from v0.3 |
| + |
| + * kernel symbol read (syntax: `symbol_name`) |
| + |
| + * parse symbol on uprobe (need libelf link) |
| + trace probe:/lib64/libc.so.6:malloc {} |
| + trace probe:/lib64/libc.so.6:malloc%return {} |
| + trace probe:/lib64/libc.so.6:* {} # trace all function in glibc |
| + |
| + * support static marker(SDT) |
| + trace sdt:/lib64/libc.so.6:setjmp {} |
| + trace sdt:/lib64/libc.so.6:* {} # trace all sdt in glibc |
| + |
| + * support kprobe wildcard |
| + trace probe:vfs* {} |
| + |
| + * support run multiple ktap instances concurrently |
| + |
| + * add command option for list available events and symbols |
| + -le [glob] : list pre-defined events in system |
| + -lf DSO : list available functions from DSO |
| + -lm DSO : list available sdt notes from DSO |
| + |
| + * better annotation for output of argname |
| + |
| + * basic FFI support (depend on CONFIG_KTAP_FFI) |
| + FFI will allow call kernel function from ktap script |
| + |
| + cdef [[ int printk(char *fmt, ...); ]] |
| + C.printk("this is ffi printk from ktap\n") |
| + |
| + (currently only support basic C types, structure support is ongoing) |
| + |
| + * New sample scripts |
| + userspace/malloc_size_hist.kp |
| + userspace/malloc_free.kp |
| + userspace/gcc_unwind.kp |
| + userspace/glibc_sdt.kp #trace all static marker in glibc |
| + userspace/glibc_trace.kp #trace all functions in glibc |
| + userspace/glibc_func_hist.kp #show glibc functions in histogram |
| + syscalls/syslatl.kp #syscall latency linear aggregation |
| + syscalls/syslist.kp #syscall latency as a list with counts |
| + syscalls/opensnoop.kp #trace open() syscalls and print basic details |
| + ffi/ffi_kmalloc.kp |
| + ffi/printk.kp |
| + ffi/sched_clock.kp |
| + |
| + * use amalgamation build as default |
| + x86_64 build: ktap binary size is 98K, ktapvm.ko size is 983K |
| + |
| + * Big cleanups and lots of bugfix |
| + |
| + |
| +Version 0.3 (Oct 29 2013) |
| +------------------------- |
| += Highlight changes from v0.2 |
| + |
| + * Homepage released: www.ktap.org |
| + |
| + * Tutorial: http://www.ktap.org/doc/tutorial.html |
| + |
| + * Wiki: https://github.com/ktap/ktap/wiki |
| + |
| + * simple new tracing block syntax |
| + trace EVENTDEF { action } |
| + trace_end { action } |
| + |
| + * New event tracing keywords: argevent, argname, arg1..arg9 |
| + trace "syscalls:*" function () { |
| + print(argevent) |
| + } |
| + |
| + * New timer block syntax |
| + tick-N { action } |
| + profile-N { action } |
| + |
| + * Basic aggregation support |
| + It's similar with systemtap, use "<<<" operator |
| + support aggregate function: count, sum, avg, max, min |
| + |
| + * Introduce new "+=" operator |
| + |
| + * Introduce sort_paris for table sort iteration |
| + |
| + * New sample scripts |
| + helloworld.kp |
| + syscalls/sctop.kp |
| + profiling/stack_profile.kp |
| + io/traceio.kp |
| + mem/kmalloc-top.kp |
| + syscalls/errinfo.kp |
| + schedule/schedtimes.kp |
| + game/tetris.kp |
| + |
| + * ansi library for sending ANSI escape sequences |
| + |
| + |
| + * statistics of ktapvm |
| + |
| + * Big cleanups and lots of bugfix |
| + |
| +Version 0.2 (Jul 31 2013) |
| +------------------------- |
| + |
| += Script highlight changes from v0.1 |
| + |
| + * new tracing block syntax |
| + trace EVENTDEF function (e) { BODY } |
| + trace_end function (e) { BODY } |
| + |
| + * support trace filter |
| + trace 'sched:sched_switch /prev_comm == foo || next_comm == foo/ |
| + |
| + * support kprobe/kretprobe |
| + trace "probe:do_sys_open dfd=%di filename=%dx flags=%cx mode=+4($stack)" |
| + trace "probe:do_sys_open%return fd=$retval" |
| + |
| + * support uprobe/uretprobe |
| + trace "probe:/lib/libc.so.6:0x000773c0" |
| + trace "probe:/lib/libc.so.6:0x000773c0%return" |
| + |
| + * support function tracing |
| + trace "ftrace:function /ip == mutex*/" |
| + |
| + * support oneline scripting |
| + ktap -e 'trace "syscalls:*" function (e) { print(e) }' |
| + |
| + * specific pid or cpu to tracing |
| + ktap -C cpu *.kp |
| + ktap -p pid *.kp |
| + |
| + * more sample scripts |
| + |
| + * support calling print_backtrace() in any context |
| + |
| + * support calling exit() in any context |
| + |
| += Backend highlight changes from v0.1 |
| + |
| + * unified perf callback mechanism |
| + * use ring buffer transport instead of relayfs |
| + * reentrant in ktap tracing |
| + * performance boost(use percpu data in many case) |
| + * safe table/string manipulation |
| + * safe ktap exit |
| + * big code cleanups |
| + * fixed a lot of bugs, more stable than v0.1 |
| + |
| +Version 0.1 (May 21 2013) |
| +------------------------- |
| + |
| + https://lwn.net/Articles/551253/ |
| + |
| --- /dev/null |
| +++ b/drivers/staging/ktap/doc/tutorial.md |
| @@ -0,0 +1,691 @@ |
| +% The ktap Tutorial |
| + |
| +# Introduction |
| + |
| +ktap is a new script-based dynamic tracing tool for linux |
| +http://www.ktap.org |
| + |
| +ktap is a new script-based dynamic tracing tool for Linux, |
| +it uses a scripting language and lets users trace the Linux kernel dynamically. |
| +ktap is designed to give operational insights with interoperability |
| +that allows users to tune, troubleshoot and extend kernel and application. |
| +It's similar with Linux Systemtap and Solaris Dtrace. |
| + |
| +ktap have different design principles from Linux mainstream dynamic tracing |
| +language in that it's based on bytecode, so it doesn't depend upon GCC, |
| +doesn't require compiling kernel module for each script, safe to use in |
| +production environment, fulfilling the embedded ecosystem's tracing needs. |
| + |
| +Highlights features: |
| + |
| +* simple but powerful scripting language |
| +* register based interpreter (heavily optimized) in Linux kernel |
| +* small and lightweight |
| +* not depend on gcc for each script running |
| +* easy to use in embedded environment without debugging info |
| +* support for tracepoint, kprobe, uprobe, function trace, timer, and more |
| +* supported in x86, arm, ppc, mips |
| +* safety in sandbox |
| + |
| + |
| +# Getting started |
| + |
| +Requirements |
| + |
| +* Linux 3.1 or later(Need some kernel patches for kernel earlier than 3.1) |
| +* CONFIG_EVENT_TRACING enabled |
| +* CONFIG_PERF_EVENTS enabled |
| +* CONFIG_DEBUG_FS enabled |
| + make sure debugfs mounted before insmod ktapvm |
| + mount debugfs: mount -t debugfs none /sys/kernel/debug/ |
| +* libelf (optional) |
| + Install elfutils-libelf-devel on RHEL-based distros, or libelf-dev on |
| + Debian-based distros. |
| + Use `make NO_LIBELF=1` to build without libelf support. |
| + libelf is required for resolving symbols to addresses in DSO, and for sdt. |
| + |
| +Note that those configuration is always enabled in Linux distribution, |
| +like REHL, Fedora, Ubuntu, etc. |
| + |
| +1. Clone ktap from github |
| + |
| + $ git clone http://github.com/ktap/ktap.git |
| + |
| +2. Compiling ktap |
| + |
| + $ cd ktap |
| + $ make #generate ktapvm kernel module and ktap binary |
| + |
| +3. Load ktapvm kernel module(make sure debugfs mounted) |
| + |
| + $ make load #need to be root or have sudo access |
| + |
| +4. Running ktap |
| + |
| + $ ./ktap scripts/helloworld.kp |
| + |
| + |
| +# Language basics |
| + |
| +## Syntax basics |
| + |
| +ktap's syntax is design on the mind of C language syntax friendly, |
| +to make it easy scripting by kernel developer. |
| + |
| +1. Variable declaration |
| +The biggest syntax differences with C is that ktap is a dynamic typed |
| +language, so you won't need add any variable type declaration, just |
| +use the variable. |
| + |
| +2. function |
| +All functions in ktap should use keyword "function" declaration |
| + |
| +3. comments |
| +The comments of ktap is starting from '#', long comments doesn't support now. |
| + |
| +4. others |
| +Don't need place any ';' at the ending of statement in ktap. |
| +ktap use free syntax style, so you can choose to use the ';' or not. |
| + |
| +ktap use nil as NULL, the result of any number operate on nil is nil. |
| + |
| +ktap don't have array structure, also don't have any pointer operation. |
| + |
| +## Control structures |
| + |
| +ktap if/else is same as C language. |
| + |
| +There have two method of for-loop in ktap: |
| + |
| + for (i = init, limit, step) { body } |
| + |
| +this is same as below in C: |
| + |
| + for (i = init; i < limit; i += step) { body } |
| + |
| +The next for-loop method is: |
| + |
| + for (k, v in pairs(t)) { body } # looping all elements of table |
| + |
| +Note that ktap don't have "continue" keyword, but C does. |
| + |
| +## Date structures |
| + |
| +Associative array is heavily used in ktap, it's also called by table. |
| + |
| +table declaration: |
| + |
| + t = {} |
| + |
| +how to use table: |
| + |
| + t[1] = 1 |
| + t[1] = "xxx" |
| + t["key"] = 10 |
| + t["key"] = "value" |
| + |
| + for (k, v in pairs(t)) { body } # looping all elements of table |
| + |
| + |
| +# Built in functions and librarys |
| + |
| +## Built in functions |
| + |
| +**print (...)** |
| +Receives any number of arguments, and prints their values, |
| +print is not intended for formatted output, but only as a |
| +quick way to show a value, typically for debugging. |
| +For formatted output, use printf. |
| + |
| +**printf (fmt, ...)** |
| +Similar with C printf, use for format string output. |
| + |
| +**pairs (t)** |
| +Returns three values: the next function, the table t, and nil, |
| +so that the construction |
| +for (k,v in pairs(t)) { body } |
| +will iterate over all key-value pairs of table t. |
| + |
| +**len (t) /len (s)** |
| +If the argument is string, return length of string, |
| +if the argument is table, return counts of table pairs. |
| + |
| +**in_interrupt ()** |
| +checking is context is interrupt context |
| + |
| +**exit ()** |
| +quit ktap executing, similar with exit syscall |
| + |
| +**pid ()** |
| +return current process pid |
| + |
| +**tid ()** |
| +return current thread id |
| + |
| +**uid ()** |
| +return current process uid |
| + |
| +**execname ()** |
| +return current process exec name string |
| + |
| +**cpu ()** |
| +return current cpu id |
| + |
| +**arch ()** |
| +return machine architecture, like x86, arm, etc. |
| + |
| +**kernel_v ()** |
| +return Linux kernel version string, like 3.9, etc. |
| + |
| +**user_string (addr)** |
| +Receive userspace address, read string from userspace, return string. |
| + |
| +**histogram (t)** |
| +Receive table, output table histogram to user. |
| + |
| +**curr_task_info (offset, fetch_bytes)** |
| +fetch value in field offset of task_struct structure, argument fetch_bytes |
| +could be 4 or 8, if fetch_bytes is not given, default is 4. |
| + |
| +user may need to get field offset by gdb, for example: |
| +gdb vmlinux |
| +(gdb)p &(((struct task_struct *)0).prio) |
| + |
| +**print_backtrace ()** |
| +print current task stack info |
| + |
| + |
| +## Librarys |
| + |
| +### Kdebug Library |
| + |
| +**kdebug.probe_by_id (eventdef_info, eventfun)** |
| + |
| +This function is underly representation of high level tracing primitive. |
| +Note that eventdef_info is just a userspace memory pointer refer to real |
| +eventdef_info structure, the structure defintion is: |
| + |
| + struct ktap_eventdef_info { |
| + int nr; /* the number to id */ |
| + int *id_arr; /* id array */ |
| + char *filter; |
| + }; |
| + |
| +Those id is read from /sys/kernel/debug/tracing/events/$SYS/$EVENT/id |
| + |
| +The second argument in above examples is a function: |
| +function eventfun () { action } |
| + |
| + |
| +**kdebug.probe_end (endfunc)** |
| + |
| +This function is used for invoking a function when tracing end, it will wait |
| +until user press CTRL+C to stop tracing, then ktap will call endfunc function, |
| +user could show tracing results in that function, or do other things. |
| + |
| +User don't have to use kdebug library directly, use trace/trace_end keyword. |
| + |
| +### Timer Library |
| + |
| + |
| + |
| +# Linux tracing basics |
| + |
| +tracepoints, probe, timer |
| +filters |
| +above explaintion |
| +Ring buffer |
| + |
| +# Tracing semantics in ktap |
| + |
| +## Tracing block |
| + |
| +**trace EVENTDEF /FILTER/ { ACTION }** |
| + |
| +This is the basic tracing block for ktap, you need to use a specific EVENTDEF |
| +string, and own event function. |
| + |
| +There have four type of EVENTDEF, tracepoint, kprobe, uprobe, sdt. |
| + |
| +- tracepoint: |
| + |
| + EventDef Description |
| + -------------------- ------------------------------- |
| + syscalls:* trace all syscalls events |
| + syscalls:sys_enter_* trace all syscalls entry events |
| + kmem:* trace all kmem related events |
| + sched:* trace all sched related events |
| + sched:sched_switch trace sched_switch tracepoint |
| + \*:\* trace all tracepoints in system |
| + |
| + All tracepoint events are based on: |
| + /sys/kernel/debug/tracing/events/$SYS/$EVENT |
| + |
| +- ftrace(kernel newer than 3.3, and must compiled with CONFIG_FUNCTION_TRACER) |
| + |
| + EventDef Description |
| + -------------------- ------------------------------- |
| + ftrace:function trace kernel functions based on ftrace |
| + |
| + User need to use filter (/ip==*/) to trace specfic functions. |
| + Function must be listed in /sys/kernel/debug/tracing/available_filter_functions |
| + |
| +> ***Note*** of function event |
| +> |
| +> perf support ftrace:function tracepoint since Linux 3.3(see below commit), |
| +> ktap is based on perf callback, so it means kernel must be newer than 3.3 |
| +> then can use this feature. |
| +> |
| +> commit ced39002f5ea736b716ae233fb68b26d59783912 |
| +> Author: Jiri Olsa <jolsa@redhat.com> |
| +> Date: Wed Feb 15 15:51:52 2012 +0100 |
| +> |
| +> ftrace, perf: Add support to use function tracepoint in perf |
| +> |
| + |
| +- kprobe: |
| + |
| + EventDef Description |
| + -------------------- ----------------------------------- |
| + probe:schedule trace schedule function |
| + probe:schedule%return trace schedule function return |
| + probe:SyS_write trace SyS_write function |
| + probe:vfs* trace wildcards vfs related function |
| + |
| + kprobe functions must be listed in /proc/kallsyms |
| +- uprobe: |
| + |
| + EventDef Description |
| + ------------------------------------ --------------------------- |
| + probe:/lib64/libc.so.6:malloc trace malloc function |
| + probe:/lib64/libc.so.6:malloc%return trace malloc function return |
| + probe:/lib64/libc.so.6:free trace free function |
| + probe:/lib64/libc.so.6:0x82000 trace function with file offset 0x82000 |
| + probe:/lib64/libc.so.6:* trace all libc function |
| + |
| + symbol resolving need libelf support |
| + |
| +- sdt: |
| + |
| + EventDef Description |
| + ------------------------------------ -------------------------- |
| + sdt:/libc64/libc.so.6:lll_futex_wake trace stapsdt lll_futex_wake |
| + sdt:/libc64/libc.so.6:* trace all static markers in libc |
| + |
| + sdt resolving need libelf support |
| + |
| + |
| +**trace_end { ACTION }** |
| + |
| +## Tracing built-in variables |
| + |
| +**argevent** |
| +event object, you can print it by: print(argevent), it will print events |
| +into human readable string, the result is mostly same as each entry of |
| +/sys/kernel/debug/tracing/trace |
| + |
| +**argname** |
| +event name, each event have a name associated with it. |
| + |
| +**arg1..9** |
| +get argument 1..9 of event object. |
| + |
| +> ***Note*** of arg offset |
| +> |
| +> The arg offset(1..9) is determined by event format shown in debugfs. |
| +> |
| +> #cat /sys/kernel/debug/tracing/events/sched/sched_switch/format |
| +> name: sched_switch |
| +> ID: 268 |
| +> format: |
| +> field:char prev_comm[32]; <- arg1 |
| +> field:pid_t prev_pid; <- arg2 |
| +> field:int prev_prio; <- arg3 |
| +> field:long prev_state; <- arg4 |
| +> field:char next_comm[32]; <- arg5 |
| +> field:pid_t next_pid; <- arg6 |
| +> field:int next_prio; <- arg7 |
| +> |
| +> As shown, tracepoint event sched:sched_switch have 7 arguments, from arg1 to |
| +> arg7. |
| +> |
| +> Need to note that arg1 of syscall event is syscall number, not first argument |
| +> of syscall function. Use arg2 as first argument of syscall function. |
| +> For example: |
| +> |
| +> SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) |
| +> <arg2> <arg3> <arg4> |
| +> |
| +> This is similar with kprobe and uprobe, the arg1 of kprobe/uprobe event |
| +> always is _probe_ip, not the first argument given by user, for example: |
| +> |
| +> # ktap -e 'trace probe:/lib64/libc.so.6:malloc size=%di' |
| +> |
| +> # cat /sys/kernel/debug/tracing/events/ktap_uprobes_3796/malloc/format |
| +> field:unsigned long __probe_ip; <- arg1 |
| +> field:u64 size; <- arg2 |
| + |
| + |
| +## Timer syntax |
| + |
| +**tick-Ns { ACTION }** |
| +**tick-Nsec { ACTION }** |
| +**tick-Nms { ACTION }** |
| +**tick-Nmsec { ACTION }** |
| +**tick-Nus { ACTION }** |
| +**tick-Nusec { ACTION }** |
| + |
| +**profile-Ns { ACTION }** |
| +**profile-Nsec { ACTION }** |
| +**profile-Nms { ACTION }** |
| +**profile-Nmsec { ACTION }** |
| +**profile-Nus { ACTION }** |
| +**profile-Nusec { ACTION }** |
| + |
| +architecture overview picture reference(pnp format) |
| +one-liners |
| +simple event tracing |
| + |
| +# Advanced tracing pattern |
| + |
| +Aggregation/Histogram |
| +thread local |
| +flame graph |
| + |
| +# Overhead/Performance |
| + |
| +ktap have more fast boot time thant Systemtap(try the helloword script) |
| +ktap have little memory usage than Systemtap |
| +and some scripts show that ktap have a little overhead than Systemtap |
| +(we choosed two scripts to compare, function profile, stack profile. |
| +this is not means all scripts in Systemtap have big overhead than ktap) |
| + |
| + |
| +# FAQ |
| + |
| +**Q: Why use bytecode design?** |
| +A: Using bytecode would be a clean and lightweight solution, |
| + you don't need gcc toolchain to compile every scripts, all you |
| + need is a ktapvm kernel modules and userspace tool called ktap. |
| + Since its language virtual machine design, it have great portability, |
| + suppose you are working at a multi-arch cluster, if you want to run |
| + a tracing script on each board, you won't need cross-compile tracing |
| + script onto all board, what you really need to do is use ktap tool |
| + to run script just in time. |
| + |
| + Bytecode based design also will make executing more safer, than native code |
| + generation. |
| + |
| + Reality already showing that SystemTap is not widely used in embedded Linux, |
| + caused by problem of SystemTap's architecture design choice, it's a natural |
| + design for Redhat and IBM, because Redhat/IBM is focusing on server area, |
| + not embedded area. |
| + |
| +**Q: What's the differences with SystemTap and Dtrace?** |
| +A: For SystemTap, the answer is already mentioned at above question, |
| + SystemTap use translator design, for trade-off on performance with usability, |
| + based on GCC, that's what ktap want to solve. |
| + |
| + For Dtrace, one common design with Dtrace is also use bytecode, so basically |
| + Dtrace and ktap is on the same road. There have some projects aim to porting |
| + Dtrace from Solaris to Linux, but the process is still on the road, Dtrace |
| + is rooted in Solaris, and there have many huge differences between Solaris |
| + tracing infrastructure with Linux's. |
| + |
| + Dtrace is based on D language, a language subset of C, it's a restricted |
| + language, like without for-looping, for safty use in production system. |
| + It seems that Dtrace for Linux only support x86 architecture, not work on |
| + powerpc and arm/mips, obviously it's not suit for embedded Linux currently. |
| + |
| + Dtrace use ctf as input for debuginfo handing, compare with vmlinux for |
| + SystemTap. |
| + |
| + On the license part, Dtrace is released as CDDL, which is incompatible with |
| + GPL(this is why it's impossible to upstream Dtrace into mainline). |
| + |
| +**Q: Why use dynamically typed language? but not statically typed language?** |
| +A: It's hard to say which one is more better than other, dynamically typed |
| + language bring efficiency and fast prototype production, but loosing type |
| + check at compiling phase, and easy to make mistake in runtime, also it's |
| + need many runtime checking, In contrast, statically typed language win on |
| + programing safety, and performance. Statically language would suit for |
| + interoperate with kernel, as kernel is wrote mainly in C, Need to note that |
| + SystemTap and Dtrace both is statically language. |
| + |
| + ktap choose dynamically typed language as initial implementation. |
| + |
| +**Q: Why we need ktap for event tracing? There already have a built-in ftrace** |
| +A: This also is a common question for all dynamic tracing tool, not only ktap. |
| + ktap provide more flexibility than built-in tracing infrastructure. Suppose |
| + you need print a global variable when tracepoint hit, or you want print |
| + backtrace, even more, you want to store some info into associative array, and |
| + display it in histogram style when tracing end, in these case, some of them |
| + ftrace can take it, some of them ftrace can not. |
| + Overall, ktap provide you with great flexibility to scripting your own trace |
| + need. |
| + |
| +**Q: How about the performance? Is ktap slow?** |
| +A: ktap is not slow, the bytecode is very high-level, based on lua, the language |
| + virtual machine is register-based(compare with stack-based), with little |
| + instruction, the table data structure is heavily optimized in ktapvm. |
| + ktap use per-cpu allocation in many place, without global locking scheme, |
| + it's very fast when executing tracepoint callback. |
| + Performance benchmark showing that the overhead of ktap running is nearly |
| + 10%(store event name into associative array), compare with full speed |
| + running without any tracepoint enabled. |
| + |
| + ktap will optimize overhead all the time, hopefully the overhead will |
| + decrease to little than 5%, even more. |
| + |
| +**Q: Why not porting a high level language implementation into kernel directly? |
| + Like python/JVM?** |
| +A: I take serious on the size of vm and memory footprint. Python vm is large, |
| + it's not suit to embed into kernel, and python have some functionality |
| + which we don't need. |
| + |
| + The bytecode of other high level language is also big, ktap only have 32 |
| + bytecodes, python/java/erlang have nearly two hundred bytecodes. |
| + There also have some problems when porting those language into kernel, |
| + userspace programming have many differences with kernel programming, |
| + like float numbers, handle sleeping code carefully in kernel, deadloop is |
| + not allowed in kernel, multi-thread management, etc.., so it's impossible |
| + to porting language implementation into kernel with little adaption work. |
| + |
| +**Q: What's the status of ktap now?** |
| +A: Basically it works on x86-32, x86-64, powerpc, arm, it also could work for |
| + other hardware architecture, but not proven yet(I don't have enough hardware |
| + to test) |
| + If you found some bug, fix it on you own programming skill, or report to me. |
| + |
| +**Q: How to hack ktap? I want to write some extensions onto ktap.** |
| +A: welcome hacking. |
| + You can write your own library to fulfill your specific need, |
| + you can write any script as you want. |
| + |
| +**Q: What's the plan of ktap? any roadmap?** |
| +A: the current plan is deliver stable ktapvm kernel modules, more ktap script, |
| + and bugfix. |
| + |
| + |
| +# References |
| + |
| +* [Linux Performance Analysis and Tools][LPAT] |
| +* [Dtrace Blog][dtraceblog] |
| +* [Dtrace User Guide][dug] |
| +* [LWN: ktap -- yet another kernel tracer][lwn1] |
| +* [LWN: Ktap almost gets into 3.13][lwn2] |
| +* [staging: ktap: add to the kernel tree][ktap_commit] |
| +* [ktap introduction in LinuxCon Japan 2013][lcj](content is out of date) |
| +* [ktap Examples by Brendan Gregg][KEBG] |
| + |
| +[LPAT]: http://www.brendangregg.com/Slides/SCaLE_Linux_Performance2013.pdf |
| +[dtraceblog]: http://dtrace.org/blogs/ |
| +[dug]: http://docs.huihoo.com/opensolaris/dtrace-user-guide/html/index.html |
| +[lwn1]: http://lwn.net/Articles/551314/ |
| +[lwn2]: http://lwn.net/Articles/572788/ |
| +[ktap_commit]: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c63a164271f81220ff4966d41218a9101f3d0ec4 |
| +[lcj]: http://events.linuxfoundation.org/sites/events/files/lcjpcojp13_zhangwei.pdf |
| +[KEBG]: http://www.brendangregg.com/ktap.html |
| + |
| +# History |
| + |
| +* ktap was invented at 2002 |
| +* First RFC sent to LKML at 2012.12.31 |
| +* The code was released in github at 2013.01.18 |
| +* ktap released v0.1 at 2013.05.21 |
| +* ktap released v0.2 at 2013.07.31 |
| +* ktap released v0.3 at 2013.10.29 |
| + |
| +For more release info, please look at RELEASES.txt in project root directory. |
| + |
| +# Examples |
| + |
| +1. simplest one-liner command to enable all tracepoints |
| + |
| + ktap -e "trace *:* { print(argevent) }" |
| + |
| +2. syscall tracing on target process |
| + |
| + ktap -e "trace syscalls:* { print(argevent) }" -- ls |
| + |
| +3. ftrace(kernel newer than 3.3, and must compiled with CONFIG_FUNCTION_TRACER) |
| + |
| + ktap -e "trace ftrace:function { print(argevent) }" |
| + |
| + ktap -e "trace ftrace:function /ip==mutex*/ { print(argevent) }" |
| + |
| +4. simple syscall tracing |
| + |
| + trace syscalls:* { |
| + print(cpu(), pid(), execname(), argevent) |
| + } |
| + |
| +5. syscall tracing in histogram style |
| + |
| + s = {} |
| + |
| + trace syscalls:sys_enter_* { |
| + s[argname] += 1 |
| + } |
| + |
| + trace_end { |
| + histogram(s) |
| + } |
| + |
| +6. kprobe tracing |
| + |
| + trace probe:do_sys_open dfd=%di fname=%dx flags=%cx mode=+4($stack) { |
| + print("entry:", execname(), argevent) |
| + } |
| + |
| + trace probe:do_sys_open%return fd=$retval { |
| + print("exit:", execname(), argevent) |
| + } |
| + |
| +7. uprobe tracing |
| + |
| + trace probe:/lib/libc.so.6:malloc { |
| + print("entry:", execname(), argevent) |
| + } |
| + |
| + trace probe:/lib/libc.so.6:malloc%return { |
| + print("exit:", execname(), argevent) |
| + } |
| + |
| +8. stapsdt tracing (userspace static marker) |
| + |
| + trace sdt:/lib64/libc.so.6:lll_futex_wake { |
| + print("lll_futex_wake", execname(), argevent) |
| + } |
| + |
| + or: |
| + |
| + #trace all static mark in libc |
| + trace sdt:/lib64/libc.so.6:* { |
| + print(execname(), argevent) |
| + } |
| + |
| +9. timer |
| + |
| + tick-1ms { |
| + printf("time fired on one cpu\n"); |
| + } |
| + |
| + profile-2s { |
| + printf("time fired on every cpu\n"); |
| + } |
| + |
| +10. FFI (Call kernel function from ktap script, need compile with FFI=1) |
| + |
| + cdef[[ |
| + int printk(char *fmt, ...); |
| + ]] |
| + |
| + C.printk("This message is called from ktap ffi\n") |
| + |
| +More examples can be found at [samples][samples_dir] directory. |
| + |
| +[samples_dir]: https://github.com/ktap/ktap/tree/master/samples |
| + |
| +# Appendix |
| + |
| +Here is the complete syntax of ktap in extended BNF. |
| +(based on lua syntax: http://www.lua.org/manual/5.1/manual.html#5.1) |
| + |
| + chunk ::= {stat [';']} [laststat [';'] |
| + |
| + block ::= chunk |
| + |
| + stat ::= varlist '=' explist | |
| + functioncall | |
| + { block } | |
| + while exp { block } | |
| + repeat block until exp | |
| + if exp { block {elseif exp { block }} [else block] } | |
| + for Name '=' exp ',' exp [',' exp] { block } | |
| + for namelist in explist { block } | |
| + function funcname funcbody | |
| + local function Name funcbody | |
| + local namelist ['=' explist] |
| + |
| + laststat ::= return [explist] | break |
| + |
| + funcname ::= Name {'.' Name} [':' Name] |
| + |
| + varlist ::= var {',' var} |
| + |
| + var ::= Name | prefixexp '[' exp ']'| prefixexp '.' Name |
| + |
| + namelist ::= Name {',' Name} |
| + |
| + explist ::= {exp ',' exp |
| + |
| + exp ::= nil | false | true | Number | String | '...' | function | |
| + prefixexp | tableconstructor | exp binop exp | unop exp |
| + |
| + prefixexp ::= var | functioncall | '(' exp ')' |
| + |
| + functioncall ::= prefixexp args | prefixexp ':' Name args |
| + |
| + args ::= '(' [explist] ')' | tableconstructor | String |
| + |
| + function ::= function funcbody |
| + |
| + funcbody ::= '(' [parlist] ')' { block } |
| + |
| + parlist ::= namelist [',' '...'] | '...' |
| + |
| + tableconstructor ::= '{' [fieldlist] '}' |
| + |
| + fieldlist ::= field {fieldsep field} [fieldsep] |
| + |
| + field ::= '[' exp ']' '=' exp | Name '=' exp | exp |
| + |
| + fieldsep ::= ',' | ';' |
| + |
| + binop ::= '+' | '-' | '*' | '/' | '^' | '%' | '..' | |
| + '<' | '<=' | '>' | '>=' | '==' | '!=' | |
| + and | or |
| + |
| + unop ::= '-' |
| + |
| --- /dev/null |
| +++ b/drivers/staging/ktap/include/ktap_ffi.h |
| @@ -0,0 +1,180 @@ |
| +#ifndef __KTAP_FFI_H__ |
| +#define __KTAP_FFI_H__ |
| + |
| +#ifdef CONFIG_KTAP_FFI |
| + |
| +#include "../include/ktap_types.h" |
| + |
| +/* |
| + * Types design in FFI module |
| + * |
| + * ktap_cdata is an instance of csymbol, so it's a combination of csymbol |
| + * and it's actual data in memory. |
| + * |
| + * csymbol structs are globally unique and readonly type that represent C |
| + * types. For non scalar C types like struct and function, helper structs are |
| + * used to store detailed information. See csymbol_func and csymbol_struct for |
| + * more information. |
| + */ |
| + |
| +typedef enum { |
| + /* 0 - 4 */ |
| + FFI_VOID, |
| + FFI_UINT8, |
| + FFI_INT8, |
| + FFI_UINT16, |
| + FFI_INT16, |
| + /* 5 - 9 */ |
| + FFI_UINT32, |
| + FFI_INT32, |
| + FFI_UINT64, |
| + FFI_INT64, |
| + FFI_PTR, |
| + /* 10 - 12 */ |
| + FFI_FUNC, |
| + FFI_STRUCT, |
| + FFI_UNKNOWN, |
| +} ffi_type; |
| +#define NUM_FFI_TYPE ((int)FFI_UNKNOWN) |
| + |
| + |
| +/* following struct and macros are added for C typedef |
| + * size and alignment calculation */ |
| +typedef struct { |
| + size_t size; |
| + size_t align; |
| + const char *name; |
| +} ffi_mode; |
| +extern const ffi_mode const ffi_type_modes[]; |
| + |
| +#define ffi_type_size(t) (ffi_type_modes[t].size) |
| +#define ffi_type_align(t) (ffi_type_modes[t].align) |
| +#define ffi_type_name(t) (ffi_type_modes[t].name) |
| + |
| + |
| +/* start of csymbol definition */ |
| +#define CSYM_NAME_MAX_LEN 64 |
| + |
| +typedef struct csymbol_func { |
| + void *addr; /* function address */ |
| + csymbol_id ret_id; /* function return type */ |
| + int arg_nr; /* number of arguments */ |
| + csymbol_id *arg_ids; /* function argument types */ |
| + unsigned has_var_arg; /* is this a var arg function? */ |
| +} csymbol_func; |
| + |
| +typedef struct struct_member { |
| + char name[CSYM_NAME_MAX_LEN]; /* name for this struct member */ |
| + csymbol_id id; /* type for this struct member */ |
| +} struct_member; |
| + |
| +typedef struct csymbol_struct { |
| + int memb_nr; /* number of members */ |
| + struct_member *members; /* array for each member definition */ |
| + size_t size; /* bytes used to store struct */ |
| + /* alignment of the struct, 0 indicates uninitialization */ |
| + size_t align; |
| +} csymbol_struct; |
| + |
| + |
| +/* wrapper struct for all C symbols */ |
| +typedef struct csymbol { |
| + char name[CSYM_NAME_MAX_LEN]; /* name for this symbol */ |
| + ffi_type type; /* type for this symbol */ |
| + /* following members are used only for non scalar C types */ |
| + union { |
| + csymbol_id p; /* pointer type */ |
| + csymbol_func f; /* C function type */ |
| + csymbol_struct st; /* struct type */ |
| + csymbol_id td; /* typedef type */ |
| + } u; |
| +} csymbol; |
| + |
| +/* lookup csymbol address by it's id */ |
| +inline csymbol *ffi_get_csym_by_id(ktap_state *ks, csymbol_id id); |
| +#define id_to_csym(ks, id) (ffi_get_csym_by_id(ks, id)) |
| + |
| +/* helper macros for struct csymbol */ |
| +#define csym_type(cs) ((cs)->type) |
| +#define csym_name(cs) ((cs)->name) |
| + |
| +/* |
| + * helper macros for pointer symbol |
| + */ |
| +#define csym_ptr_deref_id(cs) ((cs)->u.p) |
| +#define csym_set_ptr_deref_id(cs, id) ((cs)->u.p = (id)) |
| +/* following macro gets csymbol address */ |
| +#define csym_ptr_deref(ks, cs) (id_to_csym(ks, csym_ptr_deref_id(cs))) |
| + |
| +/* |
| + * helper macros for function symbol |
| + * csym_* accepts csymbol type |
| + * csymf_* accepts csymbol_func type |
| + */ |
| +#define csymf_addr(csf) ((csf)->addr) |
| +#define csymf_ret_id(csf) ((csf)->ret_id) |
| +#define csymf_arg_nr(csf) ((csf)->arg_nr) |
| +#define csymf_arg_ids(csf) ((csf)->arg_ids) |
| +/* get csymbol id for the nth argument */ |
| +#define csymf_arg_id(csf, n) ((csf)->arg_ids[n]) |
| +#define csym_func(cs) (&((cs)->u.f)) |
| +#define csym_func_addr(cs) (csymf_addr(csym_func(cs))) |
| +#define csym_func_arg_ids(cs) (csymf_arg_ids(csym_func(cs))) |
| +/* following macros get csymbol address */ |
| +#define csymf_ret(ks, csf) (id_to_csym(ks, csymf_ret_id(csf))) |
| +/* get csymbol address for the nth argument */ |
| +#define csymf_arg(ks, csf, n) (id_to_csym(ks, csymf_arg_id(csf, n))) |
| +#define csym_func_arg(ks, cs, n) (csymf_arg(ks, csym_func(cs), n)) |
| + |
| +/* |
| + * helper macors for struct symbol |
| + * csym_* accepts csymbol type |
| + * csymst_* accepts csymbol_struct type |
| + */ |
| +#define csymst_mb_nr(csst) ((csst)->memb_nr) |
| +#define csym_struct(cs) (&(cs)->u.st) |
| +#define csym_struct_mb(cs) (csymst_mb(ks, csym_struct(cs), n)) |
| +/* following macro gets csymbol address for the nth struct member */ |
| +#define csymst_mb(ks, csst, n) (id_to_csym(ks, (csst)->members[n].id)) |
| + |
| + |
| +/* |
| + * helper macros for ktap_cdata type |
| + */ |
| +#define cd_csym_id(cd) ((cd)->id) |
| +#define cd_set_csym_id(cd, id) (cd_csym_id(cd) = (id)) |
| +#define cd_csym(ks, cd) (id_to_csym(ks, cd_csym_id(cd))) |
| +#define cd_type(ks, cd) (cd_csym(ks, cd)->type) |
| + |
| +#define cd_int(cd) ((cd)->u.i) |
| +#define cd_ptr(cd) ((cd)->u.p) |
| +#define cd_struct(cd) ((cd)->u.st) |
| + |
| + |
| +#ifdef __KERNEL__ |
| +size_t csym_size(ktap_state *ks, csymbol *sym); |
| +size_t csym_align(ktap_state *ks, csymbol *sym); |
| +size_t csym_struct_offset(ktap_state *ks, csymbol_struct *csst, int idx); |
| +void init_csym_struct(ktap_state *ks, csymbol_struct *csst); |
| + |
| +void kp_ffi_free_symbol(ktap_state *ks); |
| +csymbol_id ffi_get_csym_id(ktap_state *ks, char *name); |
| + |
| +ktap_cdata *kp_cdata_new(ktap_state *ks); |
| +void kp_cdata_dump(ktap_state *ks, ktap_cdata *cd); |
| +ktap_cdata *kp_cdata_new_ptr(ktap_state *ks, void *addr, csymbol_id id); |
| +ktap_cdata *kp_cdata_new_struct(ktap_state *ks, void *val, csymbol_id id); |
| + |
| +int kp_ffi_call(ktap_state *ks, csymbol_func *cf); |
| +#endif /* for __KERNEL__ */ |
| + |
| +#else |
| + |
| +static void __maybe_unused kp_ffi_free_symbol(ktap_state *ks) |
| +{ |
| + return; |
| +} |
| + |
| +#endif /* CONFIG_KTAP_FFI */ |
| + |
| +#endif /* __KTAP_FFI_H__ */ |
| --- /dev/null |
| +++ b/drivers/staging/ktap/include/ktap_opcodes.h |
| @@ -0,0 +1,239 @@ |
| +#ifndef __KTAP_BYTECODE_H__ |
| +#define __KTAP_BYTECODE_H__ |
| + |
| + |
| +/* opcode is copied from lua initially */ |
| + |
| +typedef enum { |
| +/*---------------------------------------------------------------------- |
| + * name args description |
| + * ------------------------------------------------------------------------*/ |
| +OP_MOVE,/* A B R(A) := R(B) */ |
| +OP_LOADK,/* A Bx R(A) := Kst(Bx) */ |
| +OP_LOADKX,/* A R(A) := Kst(extra arg) */ |
| +OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ |
| +OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */ |
| +OP_GETUPVAL,/* A B R(A) := UpValue[B] */ |
| + |
| +OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */ |
| +OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ |
| + |
| +OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */ |
| +OP_SETTABUP_INCR,/* A B C UpValue[A][RK(B)] += RK(C) */ |
| +OP_SETTABUP_AGGR,/* A B C UpValue[A][RK(B)] <<< RK(C) */ |
| +OP_SETUPVAL,/* A B UpValue[B] := R(A) */ |
| +OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ |
| +OP_SETTABLE_INCR,/* A B C R(A)[RK(B)] += RK(C) */ |
| +OP_SETTABLE_AGGR,/* A B C R(A)[RK(B)] <<< RK(C) */ |
| + |
| +OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ |
| + |
| +OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ |
| + |
| +OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ |
| +OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ |
| +OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ |
| +OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ |
| +OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ |
| +OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ |
| +OP_UNM,/* A B R(A) := -R(B) */ |
| +OP_NOT,/* A B R(A) := not R(B) */ |
| +OP_LEN,/* A B R(A) := length of R(B) */ |
| + |
| +OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ |
| + |
| +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ |
| +OP_EQ,/* A B C if ((RK(B) == RK(C)) != A) then pc++ */ |
| +OP_LT,/* A B C if ((RK(B) < RK(C)) != A) then pc++ */ |
| +OP_LE,/* A B C if ((RK(B) <= RK(C)) != A) then pc++ */ |
| + |
| +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ |
| +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ |
| + |
| +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ |
| +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ |
| +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ |
| + |
| +OP_FORLOOP,/* A sBx R(A)+=R(A+2); |
| + if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ |
| +OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ |
| + |
| +OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ |
| +OP_TFORLOOP,/* A sBx if R(A+1) != nil then { R(A)=R(A+1); pc += sBx }*/ |
| + |
| +OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ |
| + |
| +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ |
| + |
| +OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ |
| + |
| +OP_EXTRAARG,/* Ax extra (larger) argument for previous opcode */ |
| + |
| +OP_EVENT,/* A B C R(A) := R(B)[C] */ |
| + |
| +OP_EVENTNAME, /* A R(A) = event_name() */ |
| + |
| +OP_EVENTARG,/* A B R(A) := event_arg(B)*/ |
| + |
| +OP_LOAD_GLOBAL,/* A B C R(A) := R(B)[C] */ |
| + |
| +OP_EXIT, |
| + |
| +} OpCode; |
| + |
| + |
| +#define NUM_OPCODES ((int)OP_LOAD_GLOBAL + 1) |
| + |
| + |
| +enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ |
| + |
| + |
| +/* |
| + * ** size and position of opcode arguments. |
| + * */ |
| +#define SIZE_C 9 |
| +#define SIZE_B 9 |
| +#define SIZE_Bx (SIZE_C + SIZE_B) |
| +#define SIZE_A 8 |
| +#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) |
| + |
| +#define SIZE_OP 6 |
| + |
| +#define POS_OP 0 |
| +#define POS_A (POS_OP + SIZE_OP) |
| +#define POS_C (POS_A + SIZE_A) |
| +#define POS_B (POS_C + SIZE_C) |
| +#define POS_Bx POS_C |
| +#define POS_Ax POS_A |
| + |
| + |
| + |
| +/* |
| + * ** limits for opcode arguments. |
| + * ** we use (signed) int to manipulate most arguments, |
| + * ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) |
| + * */ |
| +#define MAXARG_Bx ((1<<SIZE_Bx)-1) |
| +#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ |
| + |
| +#define MAXARG_Ax ((1<<SIZE_Ax)-1) |
| + |
| +#define MAXARG_A ((1<<SIZE_A)-1) |
| +#define MAXARG_B ((1<<SIZE_B)-1) |
| +#define MAXARG_C ((1<<SIZE_C)-1) |
| + |
| + |
| +/* creates a mask with `n' 1 bits at position `p' */ |
| +#define MASK1(n,p) ((~((~(ktap_instruction)0)<<(n)))<<(p)) |
| + |
| +/* creates a mask with `n' 0 bits at position `p' */ |
| +#define MASK0(n,p) (~MASK1(n,p)) |
| + |
| +/* |
| + * ** the following macros help to manipulate instructions |
| + * */ |
| + |
| +#define GET_OPCODE(i) ((OpCode)((i)>>POS_OP) & MASK1(SIZE_OP,0)) |
| +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ |
| + ((((ktap_instruction)o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) |
| + |
| +#define getarg(i,pos,size) ((int)((i)>>pos) & MASK1(size,0)) |
| +#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ |
| + ((((ktap_instruction)v)<<pos)&MASK1(size,pos)))) |
| + |
| +#define GETARG_A(i) getarg(i, POS_A, SIZE_A) |
| +#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) |
| + |
| +#define GETARG_B(i) getarg(i, POS_B, SIZE_B) |
| +#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) |
| + |
| +#define GETARG_C(i) getarg(i, POS_C, SIZE_C) |
| +#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) |
| + |
| +#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx) |
| +#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx) |
| + |
| +#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax) |
| +#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax) |
| + |
| +#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx) |
| +#define SETARG_sBx(i,b) SETARG_Bx((i), (unsigned int)(b)+MAXARG_sBx) |
| + |
| +#define CREATE_ABC(o,a,b,c) (((ktap_instruction)(o))<<POS_OP) \ |
| + | (((ktap_instruction)(a))<<POS_A) \ |
| + | (((ktap_instruction)(b))<<POS_B) \ |
| + | (((ktap_instruction)(c))<<POS_C) |
| + |
| +#define CREATE_ABx(o,a,bc) (((ktap_instruction)(o))<<POS_OP) \ |
| + | (((ktap_instruction)(a))<<POS_A) \ |
| + | (((ktap_instruction)(bc))<<POS_Bx) |
| + |
| +#define CREATE_Ax(o,a) (((ktap_instruction)(o))<<POS_OP) \ |
| + | (((ktap_instruction)(a))<<POS_Ax) |
| + |
| + |
| + |
| +/* |
| + * ** Macros to operate RK indices |
| + * */ |
| + |
| +/* this bit 1 means constant (0 means register) */ |
| +#define BITRK (1 << (SIZE_B - 1)) |
| + |
| +/* test whether value is a constant */ |
| +#define ISK(x) ((x) & BITRK) |
| + |
| +/* gets the index of the constant */ |
| +#define INDEXK(r) ((int)(r) & ~BITRK) |
| + |
| +#define MAXINDEXRK (BITRK - 1) |
| + |
| +/* code a constant index as a RK value */ |
| +#define RKASK(x) ((x) | BITRK) |
| + |
| + |
| +/* |
| + * ** invalid register that fits in 8 bits |
| + * */ |
| +#define NO_REG MAXARG_A |
| + |
| + |
| +/* |
| + * ** R(x) - register |
| + * ** Kst(x) - constant (in constant table) |
| + * ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) |
| + * */ |
| + |
| + |
| + |
| +/* |
| + * ** masks for instruction properties. The format is: |
| + * ** bits 0-1: op mode |
| + * ** bits 2-3: C arg mode |
| + * ** bits 4-5: B arg mode |
| + * ** bit 6: instruction set register A |
| + * ** bit 7: operator is a test (next instruction must be a jump) |
| + * */ |
| + |
| +enum OpArgMask { |
| + OpArgN, /* argument is not used */ |
| + OpArgU, /* argument is used */ |
| + OpArgR, /* argument is a register or a jump offset */ |
| + OpArgK /* argument is a constant or register/constant */ |
| +}; |
| + |
| +extern const u8 ktap_opmodes[NUM_OPCODES]; |
| + |
| +#define getOpMode(m) ((enum OpMode)ktap_opmodes[m] & 3) |
| +#define getBMode(m) ((enum OpArgMask)(ktap_opmodes[m] >> 4) & 3) |
| +#define getCMode(m) ((enum OpArgMask)(ktap_opmodes[m] >> 2) & 3) |
| +#define testAMode(m) (ktap_opmodes[m] & (1 << 6)) |
| +#define testTMode(m) (ktap_opmodes[m] & (1 << 7)) |
| + |
| + |
| +/* number of list items to accumulate before a SETLIST instruction */ |
| +#define LFIELDS_PER_FLUSH 50 |
| + |
| +extern const char *const ktap_opnames[NUM_OPCODES + 1]; |
| + |
| +#endif /* __KTAP_BYTECODE_H__ */ |
| --- /dev/null |
| +++ b/drivers/staging/ktap/include/ktap_types.h |
| @@ -0,0 +1,609 @@ |
| +#ifndef __KTAP_TYPES_H__ |
| +#define __KTAP_TYPES_H__ |
| + |
| +#ifdef __KERNEL__ |
| +#include <linux/perf_event.h> |
| +#else |
| +typedef char u8; |
| +#include <stdlib.h> |
| +#include <stdio.h> |
| +#include <string.h> |
| +#include <stdint.h> |
| +#endif |
| + |
| +/* |
| + * The first argument type of kdebug.probe_by_id() |
| + * The value is a userspace memory pointer. |
| + */ |
| +typedef struct ktap_eventdef_info { |
| + int nr; |
| + int *id_arr; |
| + char *filter; |
| +} ktap_eventdef_info; |
| + |
| +typedef struct ktap_parm { |
| + char *trunk; /* __user */ |
| + int trunk_len; |
| + int argc; |
| + char **argv; /* __user */ |
| + int verbose; |
| + int trace_pid; |
| + int workload; |
| + int trace_cpu; |
| + int print_timestamp; |
| + int quiet; |
| +} ktap_parm; |
| + |
| +/* |
| + * Ioctls that can be done on a ktap fd: |
| + * todo: use _IO macro in include/uapi/asm-generic/ioctl.h |
| + */ |
| +#define KTAP_CMD_IOC_VERSION ('$' + 0) |
| +#define KTAP_CMD_IOC_RUN ('$' + 1) |
| +#define KTAP_CMD_IOC_EXIT ('$' + 3) |
| + |
| +#define KTAP_ENV "_ENV" |
| + |
| +#define KTAP_VERSION_MAJOR "0" |
| +#define KTAP_VERSION_MINOR "4" |
| + |
| +#define KTAP_VERSION "ktap " KTAP_VERSION_MAJOR "." KTAP_VERSION_MINOR |
| +#define KTAP_AUTHOR "Jovi Zhangwei <jovi.zhangwei@gmail.com>" |
| +#define KTAP_COPYRIGHT KTAP_VERSION " Copyright (C) 2012-2013, " KTAP_AUTHOR |
| + |
| +#define MYINT(s) (s[0] - '0') |
| +#define VERSION (MYINT(KTAP_VERSION_MAJOR) * 16 + MYINT(KTAP_VERSION_MINOR)) |
| +#define FORMAT 0 /* this is the official format */ |
| + |
| +#define KTAP_SIGNATURE "\033ktap" |
| + |
| +/* data to catch conversion errors */ |
| +#define KTAPC_TAIL "\x19\x93\r\n\x1a\n" |
| + |
| +/* size in bytes of header of binary files */ |
| +#define KTAPC_HEADERSIZE (sizeof(KTAP_SIGNATURE) - sizeof(char) + 2 + \ |
| + 6 + sizeof(KTAPC_TAIL) - sizeof(char)) |
| + |
| +typedef long ktap_number; |
| +#define kp_number2int(i, n) ((i) = (int)(n)) |
| + |
| +typedef int ktap_instruction; |
| + |
| +typedef union ktap_gcobject ktap_gcobject; |
| + |
| +#define CommonHeader ktap_gcobject *next; u8 tt; |
| + |
| +typedef union ktap_string { |
| + int dummy; /* ensures maximum alignment for strings */ |
| + struct { |
| + CommonHeader; |
| + u8 extra; /* reserved words for short strings; "has hash" for longs */ |
| + unsigned int hash; |
| + size_t len; /* number of characters in string */ |
| + } tsv; |
| + /* short string is stored here, just after tsv */ |
| +} ktap_string; |
| + |
| + |
| +struct ktap_state; |
| +typedef int (*ktap_cfunction) (struct ktap_state *ks); |
| + |
| +typedef struct ktap_value { |
| + union { |
| + ktap_gcobject *gc; /* collectable objects */ |
| + void *p; /* light userdata */ |
| + int b; /* booleans */ |
| + ktap_cfunction f; /* light C functions */ |
| + ktap_number n; /* numbers */ |
| + } val; |
| + int type; |
| +} ktap_value; |
| + |
| +typedef ktap_value * StkId; |
| + |
| + |
| +/* |
| + * Description of an upvalue for function prototypes |
| + */ |
| +typedef struct ktap_upvaldesc { |
| + ktap_string *name; /* upvalue name (for debug information) */ |
| + u8 instack; /* whether it is in stack */ |
| + u8 idx; /* index of upvalue (in stack or in outer function's list) */ |
| +} ktap_upvaldesc; |
| + |
| +/* |
| + * Description of a local variable for function prototypes |
| + * (used for debug information) |
| + */ |
| +typedef struct ktap_locvar { |
| + ktap_string *varname; |
| + int startpc; /* first point where variable is active */ |
| + int endpc; /* first point where variable is dead */ |
| +} ktap_locvar; |
| + |
| + |
| +typedef struct ktap_upval { |
| + CommonHeader; |
| + ktap_value *v; /* points to stack or to its own value */ |
| + union { |
| + ktap_value value; /* the value (when closed) */ |
| + struct { /* double linked list (when open) */ |
| + struct ktap_upval *prev; |
| + struct ktap_upval *next; |
| + } l; |
| + } u; |
| +} ktap_upval; |
| + |
| + |
| +#define KTAP_MAX_STACK_ENTRIES 100 |
| + |
| +typedef struct ktap_btrace { |
| + CommonHeader; |
| + unsigned int nr_entries; |
| + /* entries stored in here, after nr_entries */ |
| +} ktap_btrace; |
| + |
| +typedef struct ktap_closure { |
| + CommonHeader; |
| + u8 nupvalues; |
| + struct ktap_proto *p; |
| + struct ktap_upval *upvals[1]; /* list of upvalues */ |
| + ktap_gcobject *gclist; |
| +} ktap_closure; |
| + |
| +typedef struct ktap_proto { |
| + CommonHeader; |
| + ktap_value *k; /* constants used by the function */ |
| + ktap_instruction *code; |
| + struct ktap_proto **p; /* functions defined inside the function */ |
| + int *lineinfo; /* map from opcodes to source lines (debug information) */ |
| + struct ktap_locvar *locvars; /* information about local variables (debug information) */ |
| + struct ktap_upvaldesc *upvalues; /* upvalue information */ |
| + ktap_closure *cache; /* last created closure with this prototype */ |
| + ktap_string *source; /* used for debug information */ |
| + int sizeupvalues; /* size of 'upvalues' */ |
| + int sizek; /* size of `k' */ |
| + int sizecode; |
| + int sizelineinfo; |
| + int sizep; /* size of `p' */ |
| + int sizelocvars; |
| + int linedefined; |
| + int lastlinedefined; |
| + u8 numparams; /* number of fixed parameters */ |
| + u8 is_vararg; |
| + u8 maxstacksize; /* maximum stack used by this function */ |
| +} ktap_proto; |
| + |
| + |
| +/* |
| + * information about a call |
| + */ |
| +typedef struct ktap_callinfo { |
| + StkId func; /* function index in the stack */ |
| + StkId top; /* top for this function */ |
| + struct ktap_callinfo *prev, *next; /* dynamic call link */ |
| + short nresults; /* expected number of results from this function */ |
| + u8 callstatus; |
| + int extra; |
| + union { |
| + struct { /* only for ktap functions */ |
| + StkId base; /* base for this function */ |
| + const unsigned int *savedpc; |
| + } l; |
| + struct { /* only for C functions */ |
| + int ctx; /* context info. in case of yields */ |
| + u8 status; |
| + } c; |
| + } u; |
| +} ktap_callinfo; |
| + |
| + |
| +/* |
| + * ktap_tab |
| + */ |
| +typedef struct ktap_tkey { |
| + struct ktap_tnode *next; /* for chaining */ |
| + ktap_value tvk; |
| +} ktap_tkey; |
| + |
| + |
| +typedef struct ktap_tnode { |
| + ktap_value i_val; |
| + ktap_tkey i_key; |
| +} ktap_tnode; |
| + |
| + |
| +typedef struct ktap_stat_data { |
| + int count; |
| + int sum; |
| + int min, max; |
| +} ktap_stat_data; |
| + |
| + |
| +typedef struct ktap_tab { |
| + CommonHeader; |
| +#ifdef __KERNEL__ |
| + arch_spinlock_t lock; |
| +#endif |
| + u8 flags; /* 1<<p means tagmethod(p) is not present */ |
| + u8 lsizenode; /* log2 of size of `node' array */ |
| + int sizearray; /* size of `array' array */ |
| + ktap_value *array; /* array part */ |
| + ktap_tnode *node; |
| + ktap_tnode *lastfree; /* any free position is before this position */ |
| + |
| + int with_stats; /* for aggregation table: ptable */ |
| + ktap_stat_data *sd_arr; |
| + ktap_stat_data *sd_rec; |
| + |
| + ktap_tnode *sorted; /* sorted table, with linked node list */ |
| + ktap_tnode *sort_head; |
| + |
| + ktap_gcobject *gclist; |
| +} ktap_tab; |
| + |
| +#define lmod(s,size) ((int)((s) & ((size)-1))) |
| + |
| +/* parallel table */ |
| +typedef struct ktap_ptab { |
| + CommonHeader; |
| + ktap_tab **tbl; /* percpu table */ |
| + ktap_tab *agg; |
| +} ktap_ptab; |
| + |
| +typedef struct ktap_stringtable { |
| + ktap_gcobject **hash; |
| + int nuse; |
| + int size; |
| +} ktap_stringtable; |
| + |
| +#ifdef CONFIG_KTAP_FFI |
| +typedef int csymbol_id; |
| +typedef struct csymbol csymbol; |
| + |
| +/* global ffi state maintained in each ktap vm instance */ |
| +typedef struct ffi_state { |
| + ktap_tab *ctable; |
| + int csym_nr; |
| + csymbol *csym_arr; |
| +} ffi_state; |
| + |
| +/* instance of csymbol */ |
| +typedef struct ktap_cdata { |
| + CommonHeader; |
| + csymbol_id id; |
| + union { |
| + uint64_t i; |
| + void *p; /* pointer address */ |
| + void *st; /* struct member data */ |
| + } u; |
| +} ktap_cdata; |
| +#endif |
| + |
| +typedef struct ktap_stats { |
| + int mem_allocated; |
| + int nr_mem_allocate; |
| + int nr_mem_free; |
| + int events_hits; |
| + int events_missed; |
| +} ktap_stats; |
| + |
| +#define KTAP_STATS(ks) this_cpu_ptr(G(ks)->stats) |
| + |
| +enum { |
| + KTAP_PERCPU_DATA_STATE, |
| + KTAP_PERCPU_DATA_STACK, |
| + KTAP_PERCPU_DATA_BUFFER, |
| + KTAP_PERCPU_DATA_BUFFER2, |
| + KTAP_PERCPU_DATA_BTRACE, |
| + |
| + KTAP_PERCPU_DATA_MAX |
| +}; |
| + |
| +typedef struct ktap_global_state { |
| + ktap_stringtable strt; /* hash table for strings */ |
| + ktap_value registry; |
| + unsigned int seed; /* randonized seed for hashes */ |
| + |
| + ktap_gcobject *allgc; /* list of all collectable objects */ |
| + |
| + ktap_upval uvhead; /* head of double-linked list of all open upvalues */ |
| + |
| + struct ktap_state *mainthread; |
| +#ifdef __KERNEL__ |
| + /* global percpu data(like stack) */ |
| + void __percpu *pcpu_data[KTAP_PERCPU_DATA_MAX][PERF_NR_CONTEXTS]; |
| + |
| + int __percpu *recursion_context[PERF_NR_CONTEXTS]; |
| + |
| + arch_spinlock_t str_lock; /* string opertion lock */ |
| + |
| + ktap_parm *parm; |
| + pid_t trace_pid; |
| + struct task_struct *trace_task; |
| + cpumask_var_t cpumask; |
| + struct ring_buffer *buffer; |
| + struct dentry *trace_pipe_dentry; |
| + int nr_builtin_cfunction; |
| + ktap_value *cfunction_tbl; |
| + struct task_struct *task; |
| + int trace_enabled; |
| + struct list_head timers; |
| + struct list_head probe_events_head; |
| + int exit; |
| + int wait_user; |
| + ktap_closure *trace_end_closure; |
| + struct ktap_stats __percpu *stats; |
| + struct kmem_cache *pevent_cache; |
| +#ifdef CONFIG_KTAP_FFI |
| + ffi_state ffis; |
| +#endif |
| +#endif |
| + int error; |
| +} ktap_global_state; |
| + |
| +typedef struct ktap_state { |
| + CommonHeader; |
| + ktap_global_state *g; |
| + int stop; |
| + StkId top; |
| + ktap_callinfo *ci; |
| + const unsigned long *oldpc; |
| + StkId stack_last; |
| + StkId stack; |
| + ktap_gcobject *openupval; |
| + ktap_callinfo baseci; |
| + |
| + /* list of temp collectable objects, free when thread exit */ |
| + ktap_gcobject *gclist; |
| + |
| +#ifdef __KERNEL__ |
| + struct ktap_event *current_event; |
| +#endif |
| +} ktap_state; |
| + |
| + |
| +typedef struct gcheader { |
| + CommonHeader; |
| +} gcheader; |
| + |
| +/* |
| + * Union of all collectable objects |
| + */ |
| +union ktap_gcobject { |
| + gcheader gch; /* common header */ |
| + union ktap_string ts; |
| + struct ktap_closure cl; |
| + struct ktap_tab h; |
| + struct ktap_ptab ph; |
| + struct ktap_proto p; |
| + struct ktap_upval uv; |
| + struct ktap_state th; /* thread */ |
| + struct ktap_btrace bt; /* backtrace object */ |
| +#ifdef CONFIG_KTAP_FFI |
| + struct ktap_cdata cd; |
| +#endif |
| +}; |
| + |
| +#define gch(o) (&(o)->gch) |
| + |
| +/* macros to convert a GCObject into a specific value */ |
| +#define rawgco2ts(o) (&((o)->ts)) |
| + |
| +#define gco2ts(o) (&rawgco2ts(o)->tsv) |
| +#define gco2uv(o) (&((o)->uv)) |
| +#define obj2gco(v) ((ktap_gcobject *)(v)) |
| +#define check_exp(c, e) (e) |
| + |
| + |
| +/* predefined values in the registry */ |
| +#define KTAP_RIDX_MAINTHREAD 1 |
| +#define KTAP_RIDX_GLOBALS 2 |
| +#define KTAP_RIDX_LAST KTAP_RIDX_GLOBALS |
| + |
| +#define KTAP_TNONE (-1) |
| + |
| +#define KTAP_TNIL 0 |
| +#define KTAP_TBOOLEAN 1 |
| +#define KTAP_TLIGHTUSERDATA 2 |
| +#define KTAP_TNUMBER 3 |
| +#define KTAP_TSTRING 4 |
| +#define KTAP_TSHRSTR (KTAP_TSTRING | (0 << 4)) /* short strings */ |
| +#define KTAP_TLNGSTR (KTAP_TSTRING | (1 << 4)) /* long strings */ |
| +#define KTAP_TTABLE 5 |
| +#define KTAP_TFUNCTION 6 |
| +#define KTAP_TCLOSURE (KTAP_TFUNCTION | (0 << 4)) /* closure */ |
| +#define KTAP_TCFUNCTION (KTAP_TFUNCTION | (1 << 4)) /* light C function */ |
| +#define KTAP_TTHREAD 7 |
| +#define KTAP_TPROTO 8 |
| +#define KTAP_TUPVAL 9 |
| +#define KTAP_TEVENT 10 |
| +#define KTAP_TBTRACE 11 |
| +#define KTAP_TPTABLE 12 |
| +#define KTAP_TSTATDATA 13 |
| +#define KTAP_TCDATA 14 |
| +/* |
| + * type number is ok so far, but it may collide later between |
| + * 16+ and | (1 << 4), so be careful on this. |
| + */ |
| + |
| +#define ttype(o) ((o->type) & 0x3F) |
| +#define settype(obj, t) ((obj)->type = (t)) |
| + |
| +/* raw type tag of a TValue */ |
| +#define rttype(o) ((o)->type) |
| + |
| +/* tag with no variants (bits 0-3) */ |
| +#define novariant(x) ((x) & 0x0F) |
| + |
| +/* type tag of a TValue with no variants (bits 0-3) */ |
| +#define ttypenv(o) (novariant(rttype(o))) |
| + |
| +#define val_(o) ((o)->val) |
| +#define gcvalue(o) (val_(o).gc) |
| + |
| +#define bvalue(o) (val_(o).b) |
| +#define nvalue(o) (val_(o).n) |
| +#define hvalue(o) (&val_(o).gc->h) |
| +#define phvalue(o) (&val_(o).gc->ph) |
| +#define clvalue(o) (&val_(o).gc->cl) |
| + |
| +#define getstr(ts) (const char *)((ts) + 1) |
| +#define eqshrstr(a, b) ((a) == (b)) |
| +#define rawtsvalue(o) (&val_(o).gc->ts) |
| +#define svalue(o) getstr(rawtsvalue(o)) |
| + |
| +#define pvalue(o) (&val_(o).p) |
| +#define sdvalue(o) ((ktap_stat_data *)val_(o).p) |
| +#define fvalue(o) (val_(o).f) |
| +#define evalue(o) (val_(o).p) |
| +#define btvalue(o) (&val_(o).gc->bt) |
| +#define cdvalue(o) (&val_(o).gc->cd) |
| + |
| +#define is_nil(o) ((o)->type == KTAP_TNIL) |
| +#define is_boolean(o) ((o)->type == KTAP_TBOOLEAN) |
| +#define is_false(o) (is_nil(o) || (is_boolean(o) && bvalue(o) == 0)) |
| +#define is_shrstring(o) ((o)->type == KTAP_TSHRSTR) |
| +#define is_string(o) (((o)->type & 0x0F) == KTAP_TSTRING) |
| +#define is_number(o) ((o)->type == KTAP_TNUMBER) |
| +#define is_table(o) ((o)->type == KTAP_TTABLE) |
| +#define is_ptable(o) ((o)->type == KTAP_TPTABLE) |
| +#define is_statdata(o) ((o)->type == KTAP_TSTATDATA) |
| +#define is_event(o) ((o)->type == KTAP_TEVENT) |
| +#define is_btrace(o) ((o)->type == KTAP_TBTRACE) |
| +#define is_needclone(o) is_btrace(o) |
| +#ifdef CONFIG_KTAP_FFI |
| +#define is_cdata(o) ((o)->type == KTAP_TCDATA) |
| +#endif |
| + |
| + |
| +#define set_nil(obj) \ |
| + { ktap_value *io = (obj); io->val.n = 0; settype(io, KTAP_TNIL); } |
| + |
| +#define set_boolean(obj, x) \ |
| + { ktap_value *io = (obj); io->val.b = (x); settype(io, KTAP_TBOOLEAN); } |
| + |
| +#define set_number(obj, x) \ |
| + { ktap_value *io = (obj); io->val.n = (x); settype(io, KTAP_TNUMBER); } |
| + |
| +#define set_statdata(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + io->val.p = (x); settype(io, KTAP_TSTATDATA); } |
| + |
| +#define set_string(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + ktap_string *x_ = (x); \ |
| + io->val.gc = (ktap_gcobject *)x_; settype(io, x_->tsv.tt); } |
| + |
| +#define set_closure(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + io->val.gc = (ktap_gcobject *)x; settype(io, KTAP_TCLOSURE); } |
| + |
| +#define set_cfunction(obj, x) \ |
| + { ktap_value *io = (obj); val_(io).f = (x); settype(io, KTAP_TCFUNCTION); } |
| + |
| +#define set_table(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TTABLE); } |
| + |
| +#define set_ptable(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TPTABLE); } |
| + |
| +#define set_thread(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TTHREAD); } |
| + |
| +#define set_event(obj, x) \ |
| + { ktap_value *io = (obj); val_(io).p = (x); settype(io, KTAP_TEVENT); } |
| + |
| +#define set_btrace(obj, x) \ |
| + { ktap_value *io = (obj); \ |
| + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TBTRACE); } |
| + |
| +#ifdef CONFIG_KTAP_FFI |
| +#define set_cdata(obj, x) \ |
| + { ktap_value *io=(obj); \ |
| + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TCDATA); } |
| +#endif |
| + |
| +#define set_obj(obj1, obj2) \ |
| + { const ktap_value *io2 = (obj2); ktap_value *io1 = (obj1); \ |
| + io1->val = io2->val; io1->type = io2->type; } |
| + |
| +#define rawequalobj(t1, t2) \ |
| + (((t1)->type == (t2)->type) && kp_equalobjv(NULL, t1, t2)) |
| + |
| +#define incr_top(ks) {ks->top++;} |
| + |
| +#define NUMADD(a, b) ((a) + (b)) |
| +#define NUMSUB(a, b) ((a) - (b)) |
| +#define NUMMUL(a, b) ((a) * (b)) |
| +#define NUMDIV(a, b) ((a) / (b)) |
| +#define NUMUNM(a) (-(a)) |
| +#define NUMEQ(a, b) ((a) == (b)) |
| +#define NUMLT(a, b) ((a) < (b)) |
| +#define NUMLE(a, b) ((a) <= (b)) |
| +#define NUMISNAN(a) (!NUMEQ((a), (a))) |
| + |
| +/* todo: floor and pow in kernel */ |
| +#define NUMMOD(a, b) ((a) % (b)) |
| +#define NUMPOW(a, b) (pow(a, b)) |
| + |
| +#define ktap_assert(s) |
| + |
| +#define kp_realloc(ks, v, osize, nsize, t) \ |
| + ((v) = (t *)kp_reallocv(ks, v, osize * sizeof(t), nsize * sizeof(t))) |
| + |
| +#define kp_error(ks, args...) \ |
| + do { \ |
| + kp_printf(ks, "error: "args); \ |
| + G(ks)->error = 1; \ |
| + kp_exit(ks); \ |
| + } while(0) |
| + |
| +#ifdef __KERNEL__ |
| +#define G(ks) (ks->g) |
| + |
| +void kp_printf(ktap_state *ks, const char *fmt, ...); |
| +extern void __kp_puts(ktap_state *ks, const char *str); |
| +extern void __kp_bputs(ktap_state *ks, const char *str); |
| + |
| +#define kp_puts(ks, str) ({ \ |
| + static const char *trace_printk_fmt \ |
| + __attribute__((section("__trace_printk_fmt"))) = \ |
| + __builtin_constant_p(str) ? str : NULL; \ |
| + \ |
| + if (__builtin_constant_p(str)) \ |
| + __kp_bputs(ks, trace_printk_fmt); \ |
| + else \ |
| + __kp_puts(ks, str); \ |
| +}) |
| + |
| +#else |
| +/* |
| + * this is used for ktapc tstring operation, tstring need G(ks)->strt |
| + * and G(ks)->seed, so ktapc need to init those field |
| + */ |
| +#define G(ks) (&dummy_global_state) |
| +extern ktap_global_state dummy_global_state; |
| + |
| +#define kp_printf(ks, args...) printf(args) |
| +#define kp_puts(ks, str) printf("%s", str) |
| +#define kp_exit(ks) exit(EXIT_FAILURE) |
| + |
| +#endif |
| + |
| +#define __maybe_unused __attribute__((unused)) |
| + |
| +/* |
| + * KTAP_QL describes how error messages quote program elements. |
| + * CHANGE it if you want a different appearance. |
| + */ |
| +#define KTAP_QL(x) "'" x "'" |
| +#define KTAP_QS KTAP_QL("%s") |
| + |
| +#define STRINGIFY(type) #type |
| + |
| +#endif /* __KTAP_TYPES_H__ */ |
| + |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/ffi/call_x86_64.S |
| @@ -0,0 +1,143 @@ |
| +/* |
| + * call_x86_64.S - assembly code to call C function and handle return value |
| + * |
| + * This file is part of ktap by Jovi Zhangwei |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@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. |
| + */ |
| + |
| + |
| +#ifdef __x86_64 |
| + |
| + .file "call_x86_64.S" |
| + .text |
| + |
| +/* ffi_call_assem_x86_64(void *stack, void *temp_stack, |
| + * void *rvalue, void *func_addr, ffi_type rftype) |
| + * @stack: base address of register values and new stack |
| + * @temp_stack: stack to store temporary values |
| + * @func_addr: Function address |
| + * @rvalue: where to put return value |
| + * @rftype: FFI type of return value |
| + */ |
| + .align 2 |
| + .globl ffi_call_assem_x86_64 |
| + .type ffi_call_assem_x86_64,@function |
| + |
| +ffi_call_assem_x86_64: |
| + movq (%rsp), %rax /* save return address */ |
| + /* move stuffs to temp memory region(void *temp_stack) */ |
| + movq %rcx, (%rsi) /* save pointer to return value */ |
| + movq %r8, 8(%rsi) /* save return_ffi_type */ |
| + movq %rbp, 16(%rsi) /* save %rbp */ |
| + movq %rax, 24(%rsi) /* save return address */ |
| + movq %rsp, 32(%rsi) /* save %rsp */ |
| + movq %rsi, %rbp /* point %rbp to temp memory region */ |
| + |
| + movq %rdx, %r11 /* move function address to %r11 */ |
| + |
| + movq %rdi, %r10 /* set %r10 point to register region */ |
| + movq (%r10), %rdi /* load registers */ |
| + movq 8(%r10), %rsi |
| + movq 16(%r10), %rdx |
| + movq 24(%r10), %rcx |
| + movq 32(%r10), %r8 |
| + movq 40(%r10), %r9 |
| + xorq %rax, %rax |
| + |
| + leaq 48(%r10), %rsp |
| + |
| + callq *%r11 |
| + |
| + movq 32(%rbp), %rsp /* restore %rsp */ |
| + movq 24(%rbp), %rcx /* restore return address */ |
| + movq %rcx, (%rsp) |
| + |
| + movq (%rbp), %rcx /* get pointer to return value */ |
| + movq 8(%rbp), %r8 /* get return_ffi_type */ |
| + movq 16(%rbp), %rbp /* restore rbp */ |
| + |
| + leaq .Lreturn_table(%rip), %r11 /* start address of return_table */ |
| + movslq (%r11, %r8, 8), %r11 /* fetch target address from table */ |
| + jmpq *%r11 /* jump according to value in table */ |
| + |
| + .align 8 |
| +.Lreturn_table: |
| + .quad .Lreturn_void /* FFI_VOID */ |
| + .quad .Lreturn_uint8 /* FFI_UINT8 */ |
| + .quad .Lreturn_int8 /* FFI_INT8 */ |
| + .quad .Lreturn_uint16 /* FFI_UINT16 */ |
| + .quad .Lreturn_int16 /* FFI_INT16 */ |
| + .quad .Lreturn_uint32 /* FFI_UINT32 */ |
| + .quad .Lreturn_int32 /* FFI_INT32 */ |
| + .quad .Lreturn_uint64 /* FFI_UINT64 */ |
| + .quad .Lreturn_int64 /* FFI_INT64 */ |
| + .quad .Lreturn_ptr /* FFI_PTR */ |
| + .quad .Lreturn_func /* FFI_FUNC */ |
| + .quad .Lreturn_struct /* FFI_STRUCT */ |
| + .quad .Lreturn_unknown /* FFI_UNKNOWN */ |
| + |
| + .align 8 |
| +.Lreturn_void: |
| +.Lreturn_func: |
| +.Lreturn_unknown: |
| + retq |
| + .align 8 |
| +.Lreturn_uint8: |
| + movzbq %al, %rax |
| + movq %rax, (%rcx) |
| + retq |
| + .align 8 |
| +.Lreturn_int8: |
| + movsbq %al, %rax |
| + movq %rax, (%rcx) |
| + retq |
| + .align 8 |
| +.Lreturn_uint16: |
| + movzwq %ax, %rax |
| + movq %rax, (%rcx) |
| + retq |
| + .align 8 |
| +.Lreturn_int16: |
| + movswq %ax, %rax |
| + movq %rax, (%rcx) |
| + retq |
| + .align 8 |
| +.Lreturn_uint32: |
| + movl %eax, %eax |
| + movq %rax, (%rcx) |
| + retq |
| + .align 8 |
| +.Lreturn_int32: |
| + movslq %eax, %rax |
| + movq %rax, (%rcx) |
| + retq |
| + .align 8 |
| +.Lreturn_uint64: |
| +.Lreturn_int64: |
| +.Lreturn_ptr: |
| + movq %rax, (%rcx) |
| + retq |
| +/* Struct type indicates that struct is put into at most two registers, |
| + * and 16 bytes space is always available |
| + */ |
| + .align 8 |
| +.Lreturn_struct: |
| + movq %rax, (%rcx) |
| + movq %rdx, 8(%rcx) |
| + retq |
| + |
| +#endif /* end for __x86_64 */ |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/ffi/cdata.c |
| @@ -0,0 +1,67 @@ |
| +/* |
| + * cdata.c - support functions for ktap_cdata |
| + * |
| + * This file is part of ktap by Jovi Zhangwei |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@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 "../../include/ktap_types.h" |
| +#include "../../include/ktap_ffi.h" |
| +#include "../kp_obj.h" |
| + |
| +ktap_cdata *kp_cdata_new(ktap_state *ks) |
| +{ |
| + ktap_cdata *cd; |
| + |
| + cd = &kp_newobject(ks, KTAP_TCDATA, sizeof(ktap_cdata), NULL)->cd; |
| + |
| + return cd; |
| +} |
| + |
| +ktap_cdata *kp_cdata_new_ptr(ktap_state *ks, void *addr, csymbol_id id) |
| +{ |
| + ktap_cdata *cd; |
| + |
| + cd = kp_cdata_new(ks); |
| + cd_set_csym_id(cd, id); |
| + cd_ptr(cd) = addr; |
| + |
| + return cd; |
| +} |
| + |
| +ktap_cdata *kp_cdata_new_struct(ktap_state *ks, void *val, csymbol_id id) |
| +{ |
| + ktap_cdata *cd; |
| + |
| + cd = kp_cdata_new(ks); |
| + cd_set_csym_id(cd, id); |
| + cd_struct(cd) = val; |
| + |
| + return cd; |
| +} |
| + |
| +void kp_cdata_dump(ktap_state *ks, ktap_cdata *cd) |
| +{ |
| + switch (cd_type(ks, cd)) { |
| + case FFI_PTR: |
| + kp_printf(ks, "pointer(%p)", cd_ptr(cd)); |
| + break; |
| + default: |
| + kp_printf(ks, "unsupported cdata type %d!\n", cd_type(ks, cd)); |
| + } |
| +} |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/ffi/ffi_call.c |
| @@ -0,0 +1,427 @@ |
| +/* |
| + * ffi_call.c - foreign function calling library support for ktap |
| + * |
| + * This file is part of ktap by Jovi Zhangwei. |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@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 "../../include/ktap_types.h" |
| +#include "../../include/ktap_ffi.h" |
| +#include "../ktap.h" |
| +#include "../kp_vm.h" |
| +#include "../kp_obj.h" |
| + |
| +static int ffi_type_check(ktap_state *ks, csymbol_func *csf, int idx) |
| +{ |
| + StkId arg; |
| + csymbol *cs; |
| + ffi_type type; |
| + |
| + if (idx >= csymf_arg_nr(csf)) |
| + return 0; |
| + arg = kp_arg(ks, idx + 1); |
| + cs = csymf_arg(ks, csf, idx); |
| + type = csym_type(cs); |
| + |
| + if (type == FFI_FUNC) |
| + goto error; |
| + |
| + switch (ttypenv(arg)) { |
| + case KTAP_TLIGHTUSERDATA: |
| + if (type != FFI_PTR) goto error; |
| + break; |
| + case KTAP_TBOOLEAN: |
| + case KTAP_TNUMBER: |
| + if (type != FFI_UINT8 && type != FFI_INT8 |
| + && type != FFI_UINT16 && type != FFI_INT16 |
| + && type != FFI_UINT32 && type != FFI_INT32 |
| + && type != FFI_UINT64 && type != FFI_INT64) |
| + goto error; |
| + break; |
| + case KTAP_TSTRING: |
| + if (type != FFI_PTR && type != FFI_UINT8 && type != FFI_INT8) |
| + goto error; |
| + break; |
| + case KTAP_TCDATA: |
| + if (cs != cd_csym(ks, cdvalue(arg))) |
| + goto error; |
| + break; |
| + default: |
| + goto error; |
| + } |
| + return 0; |
| + |
| + error: |
| + kp_error(ks, "Error: Cannot convert to csymbol %s for arg %d\n", |
| + csym_name(cs), idx); |
| + return -1; |
| +} |
| + |
| +static csymbol *ffi_get_arg_csym(ktap_state *ks, csymbol_func *csf, int idx) |
| +{ |
| + StkId arg; |
| + csymbol *cs; |
| + |
| + if (idx < csymf_arg_nr(csf)) |
| + return csymf_arg(ks, csf, idx); |
| + |
| + arg = kp_arg(ks, idx + 1); |
| + cs = id_to_csym(ks, ffi_get_csym_id(ks, "void *")); |
| + switch (ttypenv(arg)) { |
| + case KTAP_TLIGHTUSERDATA: |
| + case KTAP_TBOOLEAN: |
| + case KTAP_TNUMBER: |
| + case KTAP_TSTRING: |
| + return cs; |
| + case KTAP_TCDATA: |
| + return cd_csym(ks, cdvalue(arg)); |
| + default: |
| + kp_error(ks, "Error: Cannot get type for arg %d\n", idx); |
| + return cs; |
| + } |
| +} |
| + |
| +static void ffi_unpack(ktap_state *ks, csymbol_func *csf, int idx, |
| + char *dst, int align) |
| +{ |
| + StkId arg = kp_arg(ks, idx + 1); |
| + csymbol *cs = ffi_get_arg_csym(ks, csf, idx); |
| + ffi_type type = csym_type(cs); |
| + size_t size = csym_size(ks, cs); |
| + void *p; |
| + struct ktap_cdata *cd; |
| + |
| + /* initialize the destination section */ |
| + memset(dst, 0, ALIGN(size, align)); |
| + |
| + switch (ttypenv(arg)) { |
| + case KTAP_TBOOLEAN: |
| + memcpy(dst, &bvalue(arg), sizeof(bool)); |
| + return; |
| + case KTAP_TLIGHTUSERDATA: |
| + memcpy(dst, pvalue(arg), size); |
| + return; |
| + case KTAP_TNUMBER: |
| + memcpy(dst, &nvalue(arg), size < sizeof(ktap_number) ? |
| + size : sizeof(ktap_number)); |
| + return; |
| + case KTAP_TSTRING: |
| + p = &rawtsvalue(arg)->tsv + 1; |
| + memcpy(dst, &p, size); |
| + return; |
| + } |
| + |
| + cd = cdvalue(arg); |
| + switch (type) { |
| + case FFI_VOID: |
| + kp_error(ks, "Error: Cannot copy data from void type\n"); |
| + return; |
| + case FFI_UINT8: |
| + case FFI_INT8: |
| + case FFI_UINT16: |
| + case FFI_INT16: |
| + case FFI_UINT32: |
| + case FFI_INT32: |
| + case FFI_UINT64: |
| + case FFI_INT64: |
| + memcpy(dst, &cd_int(cd), size); |
| + return; |
| + case FFI_PTR: |
| + memcpy(dst, &cd_ptr(cd), size); |
| + return; |
| + case FFI_STRUCT: |
| + memcpy(dst, cd_struct(cd), size); |
| + return; |
| + case FFI_FUNC: |
| + case FFI_UNKNOWN: |
| + kp_error(ks, "Error: internal error for csymbol %s\n", |
| + csym_name(cs)); |
| + return; |
| + } |
| +} |
| + |
| +#ifdef __x86_64 |
| + |
| +enum arg_status { |
| + IN_REGISTER, |
| + IN_MEMORY, |
| + IN_STACK, |
| +}; |
| + |
| +#define ALIGN_STACK(v, a) ((void *)(ALIGN(((uint64_t)v), a))) |
| +#define STACK_ALIGNMENT 8 |
| +#define REDZONE_SIZE 128 |
| +#define GPR_SIZE (sizeof(void *)) |
| +#define MAX_GPR 6 |
| +#define MAX_GPR_SIZE (MAX_GPR * GPR_SIZE) |
| +#define NEWSTACK_SIZE 512 |
| + |
| +#define ffi_call(ks, cf, rvalue) ffi_call_x86_64(ks, cf, rvalue) |
| + |
| +extern void ffi_call_assem_x86_64(void *stack, void *temp_stack, |
| + void *func_addr, void *rvalue, ffi_type rtype); |
| + |
| +static void ffi_call_x86_64(ktap_state *ks, csymbol_func *csf, void *rvalue) |
| +{ |
| + int i; |
| + int gpr_nr; |
| + int arg_bytes; /* total bytes needed for exceeded args in stack */ |
| + int mem_bytes; /* total bytes needed for memory storage */ |
| + char *stack, *stack_p, *gpr_p, *arg_p, *mem_p, *tmp_p; |
| + int arg_nr; |
| + csymbol *rsym; |
| + ffi_type rtype; |
| + size_t rsize; |
| + bool ret_in_memory; |
| + /* New stack to call C function */ |
| + char space[NEWSTACK_SIZE]; |
| + |
| + arg_nr = kp_arg_nr(ks); |
| + rsym = csymf_ret(ks, csf); |
| + rtype = csym_type(rsym); |
| + rsize = csym_size(ks, rsym); |
| + ret_in_memory = false; |
| + if (rtype == FFI_STRUCT) { |
| + if (rsize > 16) { |
| + rvalue = kp_malloc(ks, rsize); |
| + rtype = FFI_VOID; |
| + ret_in_memory = true; |
| + } else { |
| + /* much easier to always copy 16 bytes from registers */ |
| + rvalue = kp_malloc(ks, 16); |
| + } |
| + } |
| + |
| + gpr_nr = 0; |
| + arg_bytes = mem_bytes = 0; |
| + if (ret_in_memory) |
| + gpr_nr++; |
| + /* calculate bytes needed for stack */ |
| + for (i = 0; i < arg_nr; i++) { |
| + csymbol *cs = ffi_get_arg_csym(ks, csf, i); |
| + size_t size = csym_size(ks, cs); |
| + size_t align = csym_align(ks, cs); |
| + enum arg_status st = IN_REGISTER; |
| + int n_gpr_nr = 0; |
| + if (size > 32) { |
| + st = IN_MEMORY; |
| + n_gpr_nr = 1; |
| + } else if (size > 16) |
| + st = IN_STACK; |
| + else |
| + n_gpr_nr = ALIGN(size, GPR_SIZE) / GPR_SIZE; |
| + |
| + if (gpr_nr + n_gpr_nr > MAX_GPR) { |
| + if (st == IN_MEMORY) |
| + arg_bytes += GPR_SIZE; |
| + else |
| + st = IN_STACK; |
| + } else |
| + gpr_nr += n_gpr_nr; |
| + if (st == IN_STACK) { |
| + arg_bytes = ALIGN(arg_bytes, align); |
| + arg_bytes += size; |
| + arg_bytes = ALIGN(arg_bytes, STACK_ALIGNMENT); |
| + } |
| + if (st == IN_MEMORY) { |
| + mem_bytes = ALIGN(mem_bytes, align); |
| + mem_bytes += size; |
| + mem_bytes = ALIGN(mem_bytes, STACK_ALIGNMENT); |
| + } |
| + } |
| + |
| + /* apply space to fake stack for C function call */ |
| + if (16 + REDZONE_SIZE + MAX_GPR_SIZE + arg_bytes + |
| + mem_bytes + 6 * 8 >= NEWSTACK_SIZE) { |
| + kp_error(ks, "Unable to handle that many arguments by now\n"); |
| + return; |
| + } |
| + stack = space; |
| + /* 128 bytes below %rsp is red zone */ |
| + /* stack should be 16-bytes aligned */ |
| + stack_p = ALIGN_STACK(stack + REDZONE_SIZE, 16); |
| + /* save general purpose registers here */ |
| + gpr_p = stack_p; |
| + memset(gpr_p, 0, MAX_GPR_SIZE); |
| + /* save arguments in stack here */ |
| + arg_p = gpr_p + MAX_GPR_SIZE; |
| + /* save arguments in memory here */ |
| + mem_p = arg_p + arg_bytes; |
| + /* set additional space as temporary space */ |
| + tmp_p = mem_p + mem_bytes; |
| + |
| + /* copy arguments here */ |
| + gpr_nr = 0; |
| + if (ret_in_memory) { |
| + memcpy(gpr_p, &rvalue, GPR_SIZE); |
| + gpr_p += GPR_SIZE; |
| + gpr_nr++; |
| + } |
| + for (i = 0; i < arg_nr; i++) { |
| + csymbol *cs = ffi_get_arg_csym(ks, csf, i); |
| + size_t size = csym_size(ks, cs); |
| + size_t align = csym_align(ks, cs); |
| + enum arg_status st = IN_REGISTER; |
| + int n_gpr_nr = 0; |
| + if (size > 32) { |
| + st = IN_MEMORY; |
| + n_gpr_nr = 1; |
| + } else if (size > 16) |
| + st = IN_STACK; |
| + else |
| + n_gpr_nr = ALIGN(size, GPR_SIZE) / GPR_SIZE; |
| + |
| + if (st == IN_MEMORY) |
| + mem_p = ALIGN_STACK(mem_p, align); |
| + /* Tricky way about storing it above mem_p. It won't overflow |
| + * because temp region can be temporarily used if necesseary. */ |
| + ffi_unpack(ks, csf, i, mem_p, GPR_SIZE); |
| + if (gpr_nr + n_gpr_nr > MAX_GPR) { |
| + if (st == IN_MEMORY) { |
| + memcpy(arg_p, &mem_p, GPR_SIZE); |
| + arg_p += GPR_SIZE; |
| + } else |
| + st = IN_STACK; |
| + } else { |
| + memcpy(gpr_p, mem_p, n_gpr_nr * GPR_SIZE); |
| + gpr_p += n_gpr_nr * GPR_SIZE; |
| + gpr_nr += n_gpr_nr; |
| + } |
| + if (st == IN_STACK) { |
| + arg_p = ALIGN_STACK(arg_p, align); |
| + memcpy(arg_p, mem_p, size); |
| + arg_p += size; |
| + arg_p = ALIGN_STACK(arg_p, STACK_ALIGNMENT); |
| + } |
| + if (st == IN_MEMORY) { |
| + mem_p += size; |
| + mem_p = ALIGN_STACK(mem_p, STACK_ALIGNMENT); |
| + } |
| + } |
| + |
| + kp_verbose_printf(ks, "Stack location: %p -redzone- %p -general purpose " |
| + "register used- %p -zero- %p -stack for argument- %p" |
| + " -memory for argument- %p -temp stack-\n", |
| + stack, stack_p, gpr_p, stack_p + MAX_GPR_SIZE, |
| + arg_p, mem_p); |
| + kp_verbose_printf(ks, "GPR number: %d; arg in stack: %d; " |
| + "arg in mem: %d\n", |
| + gpr_nr, arg_bytes, mem_bytes); |
| + kp_verbose_printf(ks, "Return: address %p type %d\n", rvalue, rtype); |
| + kp_verbose_printf(ks, "Number of register used: %d\n", gpr_nr); |
| + kp_verbose_printf(ks, "Start FFI call on %p\n", csf->addr); |
| + ffi_call_assem_x86_64(stack_p, tmp_p, csf->addr, rvalue, rtype); |
| +} |
| + |
| +#else /* non-supported platform */ |
| + |
| +#define ffi_call(ks, cf, rvalue) ffi_call_unsupported(ks, cf, rvalue) |
| + |
| +static void ffi_call_unsupported(ktap_state *ks, |
| + csymbol_func *csf, void *rvalue) |
| +{ |
| + kp_error(ks, "unsupported architecture.\n"); |
| +} |
| + |
| +#endif /* end for platform-specific setting */ |
| + |
| + |
| +static int ffi_set_return(ktap_state *ks, void *rvalue, csymbol_id ret_id) |
| +{ |
| + ktap_cdata *cd; |
| + ffi_type type = csym_type(id_to_csym(ks, ret_id)); |
| + |
| + /* push return value to ktap stack */ |
| + switch (type) { |
| + case FFI_VOID: |
| + return 0; |
| + case FFI_UINT8: |
| + case FFI_INT8: |
| + case FFI_UINT16: |
| + case FFI_INT16: |
| + case FFI_UINT32: |
| + case FFI_INT32: |
| + case FFI_UINT64: |
| + case FFI_INT64: |
| + set_number(ks->top, (ktap_number)rvalue); |
| + break; |
| + case FFI_PTR: |
| + cd = kp_cdata_new_ptr(ks, rvalue, ret_id); |
| + set_cdata(ks->top, cd); |
| + break; |
| + case FFI_STRUCT: |
| + cd = kp_cdata_new_struct(ks, rvalue, ret_id); |
| + set_cdata(ks->top, cd); |
| + break; |
| + case FFI_FUNC: |
| + case FFI_UNKNOWN: |
| + kp_error(ks, "Error: Have not support ffi_type %s\n", |
| + ffi_type_name(type)); |
| + return 0; |
| + } |
| + incr_top(ks); |
| + return 1; |
| +} |
| + |
| +/* |
| + * Call C into function |
| + * First argument should be function symbol address, argument types |
| + * and return type. |
| + * Left arguments should be arguments for calling the C function. |
| + * Types between Ktap and C are converted automatically. |
| + * Only support x86_64 function call by now |
| + */ |
| +int kp_ffi_call(ktap_state *ks, csymbol_func *csf) |
| +{ |
| + int i; |
| + int expected_arg_nr, arg_nr; |
| + ktap_closure *cl; |
| + void *rvalue; |
| + |
| + expected_arg_nr = csymf_arg_nr(csf); |
| + arg_nr = kp_arg_nr(ks); |
| + |
| + /* check stack status for C call */ |
| + if (!csf->has_var_arg && expected_arg_nr != arg_nr) { |
| + kp_error(ks, "wrong argument number %d, which should be %d\n", |
| + arg_nr, expected_arg_nr); |
| + goto out; |
| + } |
| + if (csf->has_var_arg && expected_arg_nr > arg_nr) { |
| + kp_error(ks, "argument number %d, which should be bigger than %d\n", |
| + arg_nr, expected_arg_nr); |
| + goto out; |
| + } |
| + |
| + /* maybe useful later, leave it here first */ |
| + cl = clvalue(kp_arg(ks, arg_nr + 1)); |
| + |
| + /* check the argument types */ |
| + for (i = 0; i < arg_nr; i++) { |
| + if (ffi_type_check(ks, csf, i) < 0) |
| + goto out; |
| + } |
| + |
| + /* platform-specific calling workflow */ |
| + ffi_call(ks, csf, &rvalue); |
| + kp_verbose_printf(ks, "Finish FFI call\n"); |
| + |
| +out: |
| + return ffi_set_return(ks, rvalue, csymf_ret_id(csf)); |
| +} |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/ffi/ffi_symbol.c |
| @@ -0,0 +1,174 @@ |
| +/* |
| + * ffi_symbol.c - ktapvm kernel module ffi symbol submodule |
| + * |
| + * This file is part of ktap by Jovi Zhangwei. |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@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 "../../include/ktap_types.h" |
| +#include "../../include/ktap_ffi.h" |
| +#include "../ktap.h" |
| +#include "../kp_vm.h" |
| +#include "../kp_obj.h" |
| +#include "../kp_str.h" |
| +#include "../kp_tab.h" |
| + |
| +void setup_kp_ffi_symbol_table(ktap_state *ks); |
| + |
| + |
| +static inline csymbol *get_csym_arr(ktap_state *ks) |
| +{ |
| + return G(ks)->ffis.csym_arr; |
| +} |
| + |
| +static inline int get_csym_nr(ktap_state *ks) |
| +{ |
| + return G(ks)->ffis.csym_nr; |
| +} |
| + |
| +static inline void set_csym_arr(ktap_state *ks, csymbol *csym) |
| +{ |
| + G(ks)->ffis.csym_arr = csym; |
| +} |
| + |
| +static inline void set_csym_nr(ktap_state *ks, int nr) |
| +{ |
| + G(ks)->ffis.csym_nr = nr; |
| +} |
| + |
| + |
| +static inline ktap_tab *get_ffi_ctable(ktap_state *ks) |
| +{ |
| + return G(ks)->ffis.ctable; |
| +} |
| + |
| +static void setup_ffi_ctable(ktap_state *ks) |
| +{ |
| + ktap_value ffi_lib_name, ffi_mt; |
| + ktap_tab *registry; |
| + const ktap_value *gt; |
| + |
| + gt = kp_tab_getint(hvalue(&G(ks)->registry), KTAP_RIDX_GLOBALS); |
| + |
| + G(ks)->ffis.ctable = kp_tab_new(ks); |
| + |
| + /* insert ffi C table to global table */ |
| + set_table(&ffi_mt, get_ffi_ctable(ks)); |
| + set_string(&ffi_lib_name, kp_tstring_new(ks, "C")); |
| + registry = hvalue(gt); |
| + kp_tab_setvalue(ks, registry, &ffi_lib_name, &ffi_mt); |
| +} |
| + |
| +void ffi_set_csym_arr(ktap_state *ks, int cs_nr, csymbol *new_arr) |
| +{ |
| + set_csym_nr(ks, cs_nr); |
| + set_csym_arr(ks, new_arr); |
| + |
| + if (!new_arr) |
| + return; |
| + |
| + setup_kp_ffi_symbol_table(ks); |
| +} |
| + |
| +inline csymbol *ffi_get_csym_by_id(ktap_state *ks, int id) |
| +{ |
| + return &(get_csym_arr(ks)[id]); |
| +} |
| + |
| +csymbol_id ffi_get_csym_id(ktap_state *ks, char *name) |
| +{ |
| + int i; |
| + |
| + for (i = 0; i < get_csym_nr(ks); i++) { |
| + if (!strcmp(name, csym_name(ffi_get_csym_by_id(ks, i)))) { |
| + return i; |
| + } |
| + } |
| + |
| + kp_error(ks, "Cannot find csymbol with name %s\n", name); |
| + return 0; |
| +} |
| + |
| +static void add_ffi_func_to_ctable(ktap_state *ks, csymbol_id id) |
| +{ |
| + ktap_value func_name, fv; |
| + ktap_cdata *cd; |
| + csymbol *cs; |
| + |
| + /* push cdata to ctable */ |
| + set_cdata(&fv, kp_newobject(ks, KTAP_TCDATA, sizeof(ktap_cdata), NULL)); |
| + cd = cdvalue(&fv); |
| + cd_set_csym_id(cd, id); |
| + |
| + cs = id_to_csym(ks, id); |
| + set_string(&func_name, kp_tstring_new(ks, csym_name(cs))); |
| + kp_tab_setvalue(ks, get_ffi_ctable(ks), &func_name, &fv); |
| +} |
| + |
| +void setup_kp_ffi_symbol_table(ktap_state *ks) |
| +{ |
| + int i; |
| + csymbol *cs; |
| + |
| + setup_ffi_ctable(ks); |
| + |
| + /* push all functions to ctable */ |
| + for (i = 0; i < get_csym_nr(ks); i++) { |
| + cs = &get_csym_arr(ks)[i]; |
| + switch (cs->type) { |
| + case FFI_FUNC: |
| + kp_verbose_printf(ks, "[%d] loading C function %s\n", |
| + i, csym_name(cs)); |
| + add_ffi_func_to_ctable(ks, i); |
| + kp_verbose_printf(ks, "%s loaded\n", csym_name(cs)); |
| + break; |
| + case FFI_STRUCT: |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| +} |
| + |
| +void kp_ffi_free_symbol(ktap_state *ks) |
| +{ |
| + int i; |
| + csymbol_id *arg_ids; |
| + csymbol *cs; |
| + |
| + if (!get_csym_arr(ks)) |
| + return; |
| + |
| + for (i = 0; i < get_csym_nr(ks); i++) { |
| + cs = &get_csym_arr(ks)[i]; |
| + switch (csym_type(cs)) { |
| + case FFI_FUNC: |
| + arg_ids = csym_func_arg_ids(cs); |
| + if (arg_ids) |
| + kp_free(ks, arg_ids); |
| + break; |
| + case FFI_STRUCT: |
| + /*@TODO finish this 20.11 2013 (houqp)*/ |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + kp_free(ks, get_csym_arr(ks)); |
| +} |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/ffi/ffi_type.c |
| @@ -0,0 +1,51 @@ |
| +#include "../../include/ktap_ffi.h" |
| +#ifdef __KERNEL__ |
| +#include <linux/types.h> |
| +#else |
| +#include <stdint.h> |
| +#include <stddef.h> |
| +#endif |
| + |
| +#define CTYPE_MODE_HELPER(name, type) \ |
| +struct _##name##_align { \ |
| + type t1; \ |
| + char c; \ |
| + type t2; \ |
| +}; |
| + |
| +#define CTYPE_MODE(name) \ |
| +{ \ |
| + offsetof(struct _##name##_align, c), \ |
| + offsetof(struct _##name##_align, t2) - \ |
| + offsetof(struct _##name##_align, c), \ |
| + #name \ |
| +} |
| + |
| +#define CTYPE_MODE_NAME(name) _##name##_mode |
| + |
| +/* ffi_ctype_mode should be corresponded to ffi_ctype */ |
| +CTYPE_MODE_HELPER(uint8, uint8_t); |
| +CTYPE_MODE_HELPER(int8, int8_t); |
| +CTYPE_MODE_HELPER(uint16, uint16_t); |
| +CTYPE_MODE_HELPER(int16, int16_t); |
| +CTYPE_MODE_HELPER(uint32, uint32_t); |
| +CTYPE_MODE_HELPER(int32, int32_t); |
| +CTYPE_MODE_HELPER(uint64, uint64_t); |
| +CTYPE_MODE_HELPER(int64, int64_t); |
| +CTYPE_MODE_HELPER(pointer, void*); |
| + |
| +const ffi_mode ffi_type_modes[NUM_FFI_TYPE+1] = { |
| + {0, 1, "void"}, |
| + CTYPE_MODE(uint8), |
| + CTYPE_MODE(int8), |
| + CTYPE_MODE(uint16), |
| + CTYPE_MODE(int16), |
| + CTYPE_MODE(uint32), |
| + CTYPE_MODE(int32), |
| + CTYPE_MODE(uint64), |
| + CTYPE_MODE(int64), |
| + CTYPE_MODE(pointer), |
| + {0, 1, "function"}, |
| + {0, 1, "struct"}, |
| + {0, 1, "unknown"}, |
| +}; |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/ffi/ffi_util.c |
| @@ -0,0 +1,92 @@ |
| +/* |
| + * ffi_util.c - utility function for ffi module |
| + * |
| + * This file is part of ktap by Jovi Zhangwei. |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@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 "../../include/ktap_types.h" |
| +#include "../../include/ktap_ffi.h" |
| +#include "../ktap.h" |
| + |
| +size_t csym_size(ktap_state *ks, csymbol *cs) |
| +{ |
| + ffi_type type = csym_type(cs); |
| + switch(type) { |
| + case FFI_STRUCT: |
| + if (csym_struct(cs)->align == 0) |
| + init_csym_struct(ks, csym_struct(cs)); |
| + return csym_struct(cs)->size; |
| + default: |
| + return ffi_type_size(type); |
| + } |
| +} |
| + |
| +size_t csym_align(ktap_state *ks, csymbol *cs) |
| +{ |
| + ffi_type type = csym_type(cs); |
| + switch(type) { |
| + case FFI_STRUCT: |
| + if (csym_struct(cs)->align == 0) |
| + init_csym_struct(ks, csym_struct(cs)); |
| + return csym_struct(cs)->align; |
| + default: |
| + return ffi_type_align(type); |
| + } |
| +} |
| + |
| +size_t csym_struct_offset(ktap_state *ks, csymbol_struct *csst, int idx) |
| +{ |
| + int nr = csymst_mb_nr(csst); |
| + size_t off = 0; |
| + size_t align = 1; |
| + int i; |
| + |
| + if (idx < 0 || idx > nr) |
| + return -1; |
| + for (i = 0; i < idx; i++) { |
| + csymbol *var_cs = csymst_mb(ks, csst, i); |
| + size_t var_size = csym_size(ks, var_cs); |
| + size_t var_align = csym_align(ks, var_cs); |
| + off = ALIGN(off, var_align); |
| + off += var_size; |
| + align = align > var_align ? align : var_align; |
| + } |
| + off = ALIGN(off, align); |
| + return off; |
| +} |
| + |
| +void init_csym_struct(ktap_state *ks, csymbol_struct *csst) |
| +{ |
| + int nr = csymst_mb_nr(csst); |
| + size_t size = 0; |
| + size_t align = 1; |
| + int i; |
| + |
| + for (i = 0; i < nr; i++) { |
| + csymbol *var_cs = csymst_mb(ks, csst, i); |
| + size_t var_size = csym_size(ks, var_cs); |
| + size_t var_align = csym_align(ks, var_cs); |
| + size = ALIGN(size, var_align); |
| + size += var_size; |
| + align = align > var_align ? align : var_align; |
| + } |
| + size = ALIGN(size, align); |
| + csst->size = size; |
| + csst->align = align; |
| +} |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/kp_amalg.c |
| @@ -0,0 +1,43 @@ |
| +/* |
| + * kp_amalg.c - ktapvm kernel module amalgamation. |
| + * |
| + * This file is part of ktap by Jovi Zhangwei. |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@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 "ktap.c" |
| +#include "kp_opcode.c" |
| +#include "kp_obj.c" |
| +#include "kp_load.c" |
| +#include "kp_str.c" |
| +#include "kp_tab.c" |
| +#include "kp_transport.c" |
| +#include "kp_vm.c" |
| +#include "lib_base.c" |
| +#include "lib_ansi.c" |
| +#include "lib_kdebug.c" |
| +#include "lib_timer.c" |
| + |
| +#ifdef CONFIG_KTAP_FFI |
| +#include "ffi/ffi_call.c" |
| +#include "ffi/ffi_type.c" |
| +#include "ffi/ffi_symbol.c" |
| +#include "ffi/cdata.c" |
| +#include "ffi/ffi_util.c" |
| +#include "lib_ffi.c" |
| +#endif |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/kp_load.c |
| @@ -0,0 +1,401 @@ |
| +/* |
| + * kp_load.c - loader for ktap bytecode chunk file |
| + * |
| + * This file is part of ktap by Jovi Zhangwei. |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. |
| + * |
| + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. |
| + * - The part of code in this file is copied from lua initially. |
| + * - lua's MIT license is compatible with GPL. |
| + * |
| + * 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/slab.h> |
| +#include "../include/ktap_types.h" |
| +#include "../include/ktap_ffi.h" |
| +#include "ktap.h" |
| +#include "kp_load.h" |
| +#include "kp_obj.h" |
| +#include "kp_str.h" |
| +#include "kp_tab.h" |
| +#include "kp_vm.h" |
| + |
| +#define KTAPC_TAIL "\x19\x93\r\n\x1a\n" |
| + |
| +struct load_state { |
| + unsigned char *buff; |
| + int pos; |
| + ktap_state *ks; |
| +}; |
| + |
| +#define READ_CHAR(S) (S->buff[S->pos++]) |
| +#define READ_BYTE(S) READ_CHAR(S) |
| +#define READ_INT(S) load_int(S) |
| +#define READ_NUMBER(S) load_number(S) |
| +#define READ_STRING(S) load_string(S) |
| +#define READ_VECTOR(S, dst, size) \ |
| + do { \ |
| + memcpy(dst, &S->buff[S->pos], size); \ |
| + S->pos += size; \ |
| + } while(0) |
| + |
| +#define NEW_VECTOR(S, size) kp_malloc(S->ks, size) |
| +#define FREE_VECTOR(S, v) kp_free(S->ks, v) |
| +#define GET_CURRENT(S) &S->buff[S->pos] |
| +#define ADD_POS(S, size) S->pos += size |
| + |
| + |
| +static int load_function(struct load_state *S, ktap_proto *f); |
| + |
| + |
| +static int load_int(struct load_state *S) |
| +{ |
| + int x; |
| + |
| + READ_VECTOR(S, &x, sizeof(int)); |
| + return x; |
| +} |
| + |
| +static long load_number(struct load_state *S) |
| +{ |
| + long x; |
| + |
| + READ_VECTOR(S, &x, sizeof(ktap_number)); |
| + return x; |
| +} |
| + |
| +static ktap_string *load_string(struct load_state *S) |
| +{ |
| + ktap_string *ts; |
| + size_t size; |
| + |
| + size = READ_INT(S); |
| + |
| + if (!size) |
| + return NULL; |
| + else { |
| + char *s = GET_CURRENT(S); |
| + ADD_POS(S, size); |
| + /* remove trailing '\0' */ |
| + ts = kp_tstring_newlstr(S->ks, s, size - 1); |
| + return ts; |
| + } |
| +} |
| + |
| + |
| +static int load_code(struct load_state *S, ktap_proto *f) |
| +{ |
| + int n = READ_INT(S); |
| + |
| + f->sizecode = n; |
| + f->code = NEW_VECTOR(S, n * sizeof(ktap_instruction)); |
| + READ_VECTOR(S, f->code, n * sizeof(ktap_instruction)); |
| + |
| + return 0; |
| +} |
| + |
| +static int load_constants(struct load_state *S, ktap_proto *f) |
| +{ |
| + int i,n; |
| + |
| + n = READ_INT(S); |
| + |
| + f->sizek = n; |
| + f->k = NEW_VECTOR(S, n * sizeof(ktap_value)); |
| + for (i = 0; i < n; i++) |
| + set_nil(&f->k[i]); |
| + |
| + for (i=0; i < n; i++) { |
| + ktap_value *o = &f->k[i]; |
| + |
| + int t = READ_CHAR(S); |
| + switch (t) { |
| + case KTAP_TNIL: |
| + set_nil(o); |
| + break; |
| + case KTAP_TBOOLEAN: |
| + set_boolean(o, READ_CHAR(S)); |
| + break; |
| + case KTAP_TNUMBER: |
| + /* |
| + * todo: kernel not support fp, check double when |
| + * loading |
| + */ |
| + set_number(o, READ_NUMBER(S)); |
| + break; |
| + case KTAP_TSTRING: |
| + set_string(o, READ_STRING(S)); |
| + break; |
| + default: |
| + kp_error(S->ks, "ktap: load_constants: " |
| + "unknow ktap_value\n"); |
| + return -1; |
| + |
| + } |
| + } |
| + |
| + n = READ_INT(S); |
| + f->p = NEW_VECTOR(S, n * sizeof(ktap_proto)); |
| + f->sizep = n; |
| + for (i = 0; i < n; i++) |
| + f->p[i] = NULL; |
| + for (i = 0; i < n; i++) { |
| + f->p[i] = kp_newproto(S->ks); |
| + if (load_function(S, f->p[i])) |
| + return -1; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| + |
| +static int load_upvalues(struct load_state *S, ktap_proto *f) |
| +{ |
| + int i,n; |
| + |
| + n = READ_INT(S); |
| + f->upvalues = NEW_VECTOR(S, n * sizeof(ktap_upvaldesc)); |
| + f->sizeupvalues = n; |
| + |
| + for (i = 0; i < n; i++) |
| + f->upvalues[i].name = NULL; |
| + |
| + for (i = 0; i < n; i++) { |
| + f->upvalues[i].instack = READ_BYTE(S); |
| + f->upvalues[i].idx = READ_BYTE(S); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int load_debuginfo(struct load_state *S, ktap_proto *f) |
| +{ |
| + int i,n; |
| + |
| + f->source = READ_STRING(S); |
| + n = READ_INT(S); |
| + f->sizelineinfo = n; |
| + f->lineinfo = NEW_VECTOR(S, n * sizeof(int)); |
| + READ_VECTOR(S, f->lineinfo, n * sizeof(int)); |
| + n = READ_INT(S); |
| + f->locvars = NEW_VECTOR(S, n * sizeof(struct ktap_locvar)); |
| + f->sizelocvars = n; |
| + for (i = 0; i < n; i++) |
| + f->locvars[i].varname = NULL; |
| + for (i = 0; i < n; i++) { |
| + f->locvars[i].varname = READ_STRING(S); |
| + f->locvars[i].startpc = READ_INT(S); |
| + f->locvars[i].endpc = READ_INT(S); |
| + } |
| + n = READ_INT(S); |
| + for (i = 0; i < n; i++) |
| + f->upvalues[i].name = READ_STRING(S); |
| + |
| + return 0; |
| +} |
| + |
| +static int load_function(struct load_state *S, ktap_proto *f) |
| +{ |
| + f->linedefined = READ_INT(S); |
| + f->lastlinedefined = READ_INT(S); |
| + f->numparams = READ_BYTE(S); |
| + f->is_vararg = READ_BYTE(S); |
| + f->maxstacksize = READ_BYTE(S); |
| + if (load_code(S, f)) |
| + return -1; |
| + if (load_constants(S, f)) |
| + return -1; |
| + if (load_upvalues(S, f)) |
| + return -1; |
| + if (load_debuginfo(S, f)) |
| + return -1; |
| + |
| + return 0; |
| +} |
| + |
| + |
| +#define error(S, why) \ |
| + kp_error(S->ks, "load failed: %s precompiled chunk\n", why) |
| + |
| +#define N0 KTAPC_HEADERSIZE |
| +#define N1 (sizeof(KTAP_SIGNATURE) - sizeof(char)) |
| +#define N2 N1 + 2 |
| +#define N3 N2 + 6 |
| + |
| +static int load_header(struct load_state *S) |
| +{ |
| + u8 h[KTAPC_HEADERSIZE]; |
| + u8 s[KTAPC_HEADERSIZE]; |
| + |
| + kp_header(h); |
| + READ_VECTOR(S, s, KTAPC_HEADERSIZE); |
| + |
| + if (memcmp(h, s, N0) == 0) |
| + return 0; |
| + if (memcmp(h, s, N1) != 0) |
| + error(S, "not a"); |
| + else if (memcmp(h, s, N2) != 0) |
| + error(S, "version mismatch in"); |
| + else if (memcmp(h, s, N3) != 0) |
| + error(S, "incompatible"); |
| + else |
| + error(S,"corrupted"); |
| + |
| + return -1; |
| +} |
| + |
| +#ifdef CONFIG_KTAP_FFI |
| +void ffi_set_csym_arr(ktap_state *ks, int cs_nr, csymbol *new_arr); |
| + |
| +static void load_csymbol_func(struct load_state *S, csymbol *cs) |
| +{ |
| + csymbol_func *csf = csym_func(cs); |
| + int arg_nr = csymf_arg_nr(csf); |
| + |
| + if (arg_nr > 0) { |
| + csf->arg_ids = NEW_VECTOR(S, arg_nr*sizeof(int)); |
| + READ_VECTOR(S, csf->arg_ids, arg_nr*sizeof(int)); |
| + } else { |
| + csf->arg_ids = NULL; |
| + } |
| +} |
| + |
| +static void load_csymbol_struct(struct load_state *S, csymbol *cs) |
| +{ |
| + csymbol_struct *csst = csym_struct(cs); |
| + int mb_nr = csymst_mb_nr(csst); |
| + |
| + csst->members = NEW_VECTOR(S, mb_nr*sizeof(struct_member)); |
| + READ_VECTOR(S, csst->members, mb_nr*sizeof(struct_member)); |
| +} |
| + |
| +static int load_csymbols(struct load_state *S) |
| +{ |
| + csymbol *cs_arr, *cs; |
| + int i, csym_nr; |
| + |
| + /* read number of csymbols */ |
| + csym_nr = READ_INT(S); |
| + if (csym_nr <= 0) { |
| + ffi_set_csym_arr(S->ks, 0, NULL); |
| + return 0; |
| + } |
| + |
| + /* csymbol size safty check */ |
| + if (sizeof(csymbol) != READ_INT(S)) { |
| + kp_error(S->ks, "invalid csymbol size in chunk\n"); |
| + return -1; |
| + } |
| + |
| + cs_arr = NEW_VECTOR(S, sizeof(csymbol)*csym_nr); |
| + for (i = 0; i < csym_nr; i++) { |
| + cs = &cs_arr[i]; |
| + READ_VECTOR(S, cs, sizeof(csymbol)); |
| + switch (cs->type) { |
| + case FFI_FUNC: |
| + load_csymbol_func(S, cs); |
| + break; |
| + case FFI_STRUCT: |
| + load_csymbol_struct(S, cs); |
| + break; |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + ffi_set_csym_arr(S->ks, csym_nr, cs_arr); |
| + |
| + return 0; |
| +} |
| +#else |
| +static int load_csymbols(struct load_state *S) |
| +{ |
| + int csym_nr = READ_INT(S); |
| + |
| + /* if FFI is disabled in ktapc, csym_nr should be 0 */ |
| + if (csym_nr != 0) { |
| + /* skip corrupted csymbol chunk */ |
| + int cs_size = READ_INT(S); |
| + ADD_POS(S, cs_size*csym_nr); |
| + kp_error(S->ks, "VM compiled without FFI support!\n"); |
| + return -1; |
| + } |
| + |
| + return 0; |
| +} |
| +#endif |
| + |
| +static int verify_code(struct load_state *S, ktap_proto *f) |
| +{ |
| + /* not support now */ |
| + return 0; |
| +} |
| + |
| + |
| +ktap_closure *kp_load(ktap_state *ks, unsigned char *buff) |
| +{ |
| + struct load_state S; |
| + ktap_closure *cl; |
| + int ret, i; |
| + |
| + S.ks = ks; |
| + S.buff = buff; |
| + S.pos = 0; |
| + |
| + ret = load_header(&S); |
| + if (ret) |
| + return NULL; |
| + |
| + ret = load_csymbols(&S); |
| + if (ret) |
| + return NULL; |
| + |
| + cl = kp_newclosure(ks, 1); |
| + if (!cl) |
| + return cl; |
| + |
| + /* put closure on the top, prepare to run with this closure */ |
| + set_closure(ks->top, cl); |
| + incr_top(ks); |
| + |
| + cl->p = kp_newproto(ks); |
| + if (load_function(&S, cl->p)) |
| + return NULL; |
| + |
| + if (cl->p->sizeupvalues != 1) { |
| + ktap_proto *p = cl->p; |
| + cl = kp_newclosure(ks, cl->p->sizeupvalues); |
| + cl->p = p; |
| + set_closure(ks->top - 1, cl); |
| + } |
| + |
| + for (i = 0; i < cl->nupvalues; i++) { /* initialize upvalues */ |
| + ktap_upval *up = kp_newupval(ks); |
| + cl->upvals[i] = up; |
| + } |
| + |
| + /* set global table as 1st upvalue of 'f' */ |
| + if (cl->nupvalues == 1) { |
| + ktap_tab *reg = hvalue(&G(ks)->registry); |
| + const ktap_value *gt = kp_tab_getint(reg, KTAP_RIDX_GLOBALS); |
| + set_obj(cl->upvals[0]->v, gt); |
| + } |
| + |
| + verify_code(&S, cl->p); |
| + |
| + return cl; |
| +} |
| + |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/kp_load.h |
| @@ -0,0 +1,6 @@ |
| +#ifndef __KTAP_LOAD_H__ |
| +#define __KTAP_LOAD_H__ |
| + |
| +ktap_closure *kp_load(ktap_state *ks, unsigned char *buff); |
| + |
| +#endif /* __KTAP_LOAD_H__ */ |
| --- /dev/null |
| +++ b/drivers/staging/ktap/runtime/kp_obj.c |
| @@ -0,0 +1,478 @@ |
| +/* |
| + * kp_obj.c - ktap object generic operation |
| + * |
| + * This file is part of ktap by Jovi Zhangwei. |
| + * |
| + * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>. |
| + * |
| + * Copyright (C) 1994-2013 Lua.org, PUC-Rio. |
| + * - The part of code in this file is copied from lua initially. |
| + * - lua's MIT license is compatible with GPL. |
| + * |
| + * 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 "../include/ktap_types.h" |
| +#include "../include/ktap_ffi.h" |
| +#include "kp_obj.h" |
| +#include "kp_str.h" |
| +#include "kp_tab.h" |
| + |
| +#ifdef __KERNEL__ |
| +#include <linux/slab.h> |
| +#include "ktap.h" |
| +#include "kp_vm.h" |
| +#include "kp_transport.h" |
| + |
| +#define KTAP_ALLOC_FLAGS ((GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN) \ |
| + & ~__GFP_WAIT) |
| + |
| +void *kp_malloc(ktap_state *ks, int size) |
| +{ |
| + void *addr; |
| + |
| + /* |
| + * Normally we don't want to trace under memory pressure, |
| + * so we use a simple rule to handle memory allocation failure: |
| + * |
| + * retry until allocation success, this will make caller don't need |
| + * to handle the unlikely failure case, then ktap exit. |
| + * |
| + * In this approach, if user find there have memory allocation failure, |
| + * user should re-run the ktap script, or fix the memory pressure |
| + * issue, or figure out why the script need so many memory. |
| + * |
| + * Perhaps return pre-allocated stub memory trunk when allocate failed |
| + * is a better approch? |
| + */ |
| + addr = kmalloc(size, KTAP_ALLOC_FLAGS); |
| + if (unlikely(!addr)) { |
| + kp_error(ks, "kmalloc size %d failed, retry again\n", size); |
| + printk("ktap kmalloc size %d failed, retry again\n", size); |
| + dump_stack(); |
| + while (1) { |
| + addr = kmalloc(size, KTAP_ALLOC_FLAGS); |
| + if (addr) |
| + break; |
| + } |
| + kp_printf(ks, "kmalloc retry success after failed, exit\n"); |
| + } |
| + |
| + preempt_disable(); |
| + KTAP_STATS(ks)->nr_mem_allocate += 1; |
| + KTAP_STATS(ks)->mem_allocated += size; |
| + preempt_enable(); |
| + |
| + return addr; |
| +} |
| + |
| +void kp_free(ktap_state *ks, void *addr) |
| +{ |
| + preempt_disable(); |
| + KTAP_STATS(ks)->nr_mem_free += 1; |
| + preempt_enable(); |
| + |
| + kfree(addr); |
| +} |
| + |
| +void *kp_reallocv(ktap_state *ks, void *addr, int oldsize, int newsize) |
| +{ |
| + void *new_addr; |
| + |
| + new_addr = krealloc(addr, newsize, KTAP_ALLOC_FLAGS); |
| + if (unlikely(!new_addr)) { |
| + kp_error(ks, "krealloc size %d failed, retry again\n", newsize); |
| + printk("ktap krealloc size %d failed, retry again\n", newsize); |
| + dump_stack(); |
| + while (1) { |
| + new_addr = krealloc(addr, newsize, KTAP_ALLOC_FLAGS); |
| + if (new_addr) |
| + break; |
| + } |
| + kp_printf(ks, "krealloc retry success after failed, exit\n"); |
| + } |
| + |
| + preempt_disable(); |
| + if (oldsize == 0) { |
| + KTAP_STATS(ks)->nr_mem_allocate += 1; |
| + } |
| + KTAP_STATS(ks)->mem_allocated += newsize - oldsize; |
| + preempt_enable(); |
| + |
| + return new_addr; |
| +} |
| + |
| +void *kp_zalloc(ktap_state *ks, int size) |
| +{ |
| + void *addr; |
| + |
| + addr = kzalloc(size, KTAP_ALLOC_FLAGS); |
| + if (unlikely(!addr)) { |
| + kp_error(ks, "kzalloc size %d failed, retry again\n", size); |
| + printk("ktap kzalloc size %d failed, retry again\n", size); |
| + dump_stack(); |
| + while (1) { |
| + addr = kzalloc(size, KTAP_ALLOC_FLAGS); |
| + if (addr) |
| + break; |
| + } |
| + kp_printf(ks, "kzalloc retry success after failed, exit\n"); |
| + } |
| + |
| + preempt_disable(); |
| + KTAP_STATS(ks)->nr_mem_allocate += 1; |
| + KTAP_STATS(ks)->mem_allocated += size; |
| + preempt_enable(); |
| + |
| + return addr; |
| +} |
| +#endif |
| + |
| +void kp_obj_dump(ktap_state *ks, const ktap_value *v) |
| +{ |
| + switch (ttype(v)) { |
| + case KTAP_TNIL: |
| + kp_puts(ks, "NIL"); |
| + break; |
| + case KTAP_TNUMBER: |
| + kp_printf(ks, "NUMBER %ld", nvalue(v)); |
| + break; |
| + case KTAP_TBOOLEAN: |
| + kp_printf(ks, "BOOLEAN %d", bvalue(v)); |
| + break; |
| + case KTAP_TLIGHTUSERDATA: |
| + kp_printf(ks, "LIGHTUSERDATA 0x%lx", (unsigned long)pvalue(v)); |
| + break; |
| + case KTAP_TCFUNCTION: |
| + kp_printf(ks, "LIGHTCFCUNTION 0x%lx", (unsigned long)fvalue(v)); |
| + break; |
| + case KTAP_TSHRSTR: |
| + case KTAP_TLNGSTR: |
| + kp_printf(ks, "SHRSTR #%s", svalue(v)); |
| + break; |
| + case KTAP_TTABLE: |
| + kp_printf(ks, "TABLE 0x%lx", (unsigned long)hvalue(v)); |
| + break; |
| + default: |
| + kp_printf(ks, "GCVALUE 0x%lx", (unsigned long)gcvalue(v)); |
| + break; |
| + } |
| +} |
| + |
| +#ifdef __KERNEL__ |
| +#include <linux/stacktrace.h> |
| +#include <linux/module.h> |
| +#include <linux/kallsyms.h> |
| + |
| +static void kp_btrace_dump(ktap_state *ks, ktap_btrace *bt) |
| +{ |
| + char str[KSYM_SYMBOL_LEN]; |
| + unsigned long *entries = (unsigned long *)(bt + 1); |
| + int i; |
| + |
| + for (i = 0; i < bt->nr_entries; i++) { |
| + unsigned long p = entries[i]; |
| + |
| + if (p == ULONG_MAX) |
| + break; |
| + |
| + SPRINT_SYMBOL(str, p); |
| + kp_printf(ks, "%s\n", str); |
| + } |
| +} |
| + |
| +static int kp_btrace_equal(ktap_btrace *bt1, ktap_btrace *bt2) |
| +{ |
| + unsigned long *entries1 = (unsigned long *)(bt1 + 1); |
| + unsigned long *entries2 = (unsigned long *)(bt2 + 1); |
| + int i; |
| + |
| + if (bt1->nr_entries != bt2->nr_entries) |
| + return 0; |
| + |
| + for (i = 0; i < bt1->nr_entries; i++) { |
| + if (entries1[i] != entries2[i]) |
| + return 0; |
| + } |
| + |
| + return 1; |
| +} |
| +#endif |
| + |
| +void kp_showobj(ktap_state *ks, const ktap_value *v) |
| +{ |
| + switch (ttype(v)) { |
| + case KTAP_TNIL: |
| + kp_puts(ks, "nil"); |
| + break; |
| + case KTAP_TNUMBER: |
| + kp_printf(ks, "%ld", nvalue(v)); |
| + break; |
| + case KTAP_TBOOLEAN: |
| + kp_puts(ks, (bvalue(v) == 1) ? "true" : "false"); |
| + break; |
| + case KTAP_TLIGHTUSERDATA: |
| + kp_printf(ks, "0x%lx", (unsigned long)pvalue(v)); |
| + break; |
| + case KTAP_TCFUNCTION: |
| + kp_printf(ks, "0x%lx", (unsigned long)fvalue(v)); |
| + break; |
| + case KTAP_TSHRSTR: |
| + case KTAP_TLNGSTR: |
| + kp_puts(ks, svalue(v)); |
| + break; |
| + case KTAP_TTABLE: |
| + kp_tab_dump(ks, hvalue(v)); |
| + break; |
| +#ifdef __KERNEL__ |
| +#ifdef CONFIG_KTAP_FFI |
| + case KTAP_TCDATA: |
| + kp_cdata_dump(ks, cdvalue(v)); |
| + break; |
| +#endif |
| + case KTAP_TEVENT: |
| + kp_transport_event_write(ks, evalue(v)); |
| + break; |
| + case KTAP_TBTRACE: |
| + kp_btrace_dump(ks, btvalue(v)); |
| + break; |
| + case KTAP_TPTABLE: |
| + kp_ptab_dump(ks, phvalue(v)); |
| + break; |
| + case KTAP_TSTATDATA: |
| + kp_statdata_dump(ks, sdvalue(v)); |
| + break; |
| +#endif |
| + default: |
| + kp_error(ks, "print unknown value type: %d\n", ttype(v)); |
| + break; |
| + } |
| +} |
| + |
| + |
| +/* |
| + * equality of ktap values. ks == NULL means raw equality |
| + */ |
| +int kp_equalobjv(ktap_state *ks, const ktap_value *t1, const ktap_value *t2) |
| +{ |
| + switch (ttype(t1)) { |
| + case KTAP_TNIL: |
| + return 1; |
| + case KTAP_TNUMBER: |
| + return nvalue(t1) == nvalue(t2); |
| + case KTAP_TBOOLEAN: |
| + return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ |
| + case KTAP_TLIGHTUSERDATA: |
| + return pvalue(t1) == pvalue(t2); |
| + case KTAP_TCFUNCTION: |
| + return fvalue(t1) == fvalue(t2); |
| + case KTAP_TSHRSTR: |
| + return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); |
| + case KTAP_TLNGSTR: |
| + return kp_tstring_eqlngstr(rawtsvalue(t1), rawtsvalue(t2)); |
| + case KTAP_TTABLE: |
| + if (hvalue(t1) == hvalue(t2)) |
| + return 1; |
| + else if (ks == NULL) |
| + return 0; |
| +#ifdef __KERNEL__ |
| + case KTAP_TBTRACE: |
| + return kp_btrace_equal(btvalue(t1), btvalue(t2)); |
| +#endif |
| + default: |
| + return gcvalue(t1) == gcvalue(t2); |
| + } |
| + |
| + return 0; |
<
|