From: Greg Kroah-Hartman Date: Sun, 27 Oct 2013 21:05:02 +0000 (-0700) Subject: staging: ktap: remove code from tree X-Git-Tag: upstream/snapshot3+hdmi~4059^2~90 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=365aa51e11cc537ac39a96f765ad8e7511aa93ff;p=platform%2Fadaptation%2Frenesas_rcar%2Frenesas_kernel.git staging: ktap: remove code from tree ktap should be merged through the "proper" place in the kernel tree, in the perf tool, not as a stand-alone kernel module in staging. So remove it from here for now so that it can be merged correctly later. Reported-by: Ingo Molnar Cc: Jovi Zhangwei Cc: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 3b1501b..3bfdaa8 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -150,6 +150,4 @@ source "drivers/staging/dgnc/Kconfig" source "drivers/staging/dgap/Kconfig" -source "drivers/staging/ktap/Kconfig" - endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2270ed0..b0d3303 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -67,4 +67,3 @@ obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_DGNC) += dgnc/ obj-$(CONFIG_DGAP) += dgap/ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ -obj-$(CONFIG_KTAP) += ktap/ diff --git a/drivers/staging/ktap/Kconfig b/drivers/staging/ktap/Kconfig deleted file mode 100644 index 21f8d2e..0000000 --- a/drivers/staging/ktap/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -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 - diff --git a/drivers/staging/ktap/Makefile b/drivers/staging/ktap/Makefile deleted file mode 100644 index e2e54ba..0000000 --- a/drivers/staging/ktap/Makefile +++ /dev/null @@ -1,101 +0,0 @@ - -# Do not instrument the tracer itself: -ifdef CONFIG_FUNCTION_TRACER -ORIG_CFLAGS := $(KBUILD_CFLAGS) -KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS)) -endif - -all: mod ktap - -INTP = interpreter - -LIBDIR = $(INTP)/library - -LIB_OBJS += $(LIBDIR)/baselib.o $(LIBDIR)/kdebug.o $(LIBDIR)/timer.o \ - $(LIBDIR)/ansilib.o - -INTP_OBJS += $(INTP)/ktap.o $(INTP)/loader.o $(INTP)/object.o \ - $(INTP)/tstring.o $(INTP)/table.o $(INTP)/vm.o \ - $(INTP)/opcode.o $(INTP)/strfmt.o $(INTP)/transport.o \ - $(LIB_OBJS) - -obj-m += ktapvm.o -ktapvm-y := $(INTP_OBJS) - -KVERSION ?= $(shell uname -r) -KERNEL_SRC ?= /lib/modules/$(KVERSION)/build -mod: - $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules_install - -KTAPC_CFLAGS = -Wall -O2 - -UDIR = userspace - -$(UDIR)/lex.o: $(UDIR)/lex.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/parser.o: $(UDIR)/parser.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/code.o: $(UDIR)/code.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/dump.o: $(UDIR)/dump.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/main.o: $(UDIR)/main.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/util.o: $(UDIR)/util.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/ktapio.o: $(UDIR)/ktapio.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/eventdef.o: $(UDIR)/eventdef.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/opcode.o: $(INTP)/opcode.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/table.o: $(INTP)/table.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/tstring.o: $(INTP)/tstring.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< -$(UDIR)/object.o: $(INTP)/object.c - $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $< - -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)/opcode.o -KTAPOBJS += $(UDIR)/table.o -KTAPOBJS += $(UDIR)/tstring.o -KTAPOBJS += $(UDIR)/object.o - -ktap: $(KTAPOBJS) - $(QUIET_LINK)$(CC) $(KTAPC_CFLAGS) -o $@ $(KTAPOBJS) -lpthread - -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: - diff --git a/drivers/staging/ktap/README.md b/drivers/staging/ktap/README.md deleted file mode 100644 index c8ddd5f..0000000 --- a/drivers/staging/ktap/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# 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 scripts/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. function tracing - - 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:0x000773c0 { - print("entry:", execname(), argevent) - } - - trace probe:/lib/libc.so.6:0x000773c0%return { - print("exit:", execname(), argevent) - } - -8. timer - - tick-1ms { - printf("time fired on one cpu\n"); - } - - profile-2s { - printf("time fired on every cpu\n"); - } - -More sample scripts can be found at scripts/ directory. - -## 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 . -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 - diff --git a/drivers/staging/ktap/doc/tutorial.md b/drivers/staging/ktap/doc/tutorial.md deleted file mode 100644 index 3c32ce7..0000000 --- a/drivers/staging/ktap/doc/tutorial.md +++ /dev/null @@ -1,552 +0,0 @@ -% The ktap Tutorial - -# Introduction - -ktap is a new scripting dynamic tracing tool for linux - -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. - -Highlights features: - -* 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 - - -# 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/) - -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 - -**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 (event_ids, eventfun)** - -This function is underly representation of high level tracing primitive. -event_ids is the id of all events, it's read from -/sys/kernel/debug/tracing/events/$SYS/$EVENT/id - -for multi-events tracing, the event_ids is concatenation of all id, for example: - "2 3 4", seperated by blank space. - -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. - - -### 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. - -EVENTDEF is compatible with perf(see perf-list), with glob match, for example: - - 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 - *:* trace all tracepoints in system. - -All events are based on: /sys/kernel/debug/tracing/events/$SYS/$EVENT - -**trace_end { ACTION }** - -This is based on kdebug.probe_end function. - -## Tracing built-in variable - -**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. - - -## 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 then 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][lwn] -* [ktap introduction in LinuxCon Japan 2013][lcj] - -[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 -[lwn]: http://lwn.net/Articles/551314/ -[lcj]: http://events.linuxfoundation.org/sites/events/files/lcjpcojp13_zhangwei.pdf - - -# 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 - -For more release info, please look at RELEASES.txt in project root directory. - -# Sample scripts - -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. function tracing - - 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:0x000773c0 { - print("entry:", execname(), argevent) - } - - trace probe:/lib/libc.so.6:0x000773c0%return { - print("exit:", execname(), argevent) - } - -8. timer - - tick-1ms { - printf("time fired on one cpu\n"); - } - - profile-2s { - printf("time fired on every cpu\n"); - } - -More sample scripts can be found at scripts/ directory. - - -# 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 ::= '-' - diff --git a/drivers/staging/ktap/include/ktap.h b/drivers/staging/ktap/include/ktap.h deleted file mode 100644 index 076dd4a..0000000 --- a/drivers/staging/ktap/include/ktap.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef __KTAP_H__ -#define __KTAP_H__ - -#include "ktap_types.h" -#include "ktap_opcodes.h" - -#include -#include -#include -#include - -typedef struct ktap_Reg { - const char *name; - ktap_cfunction func; -} ktap_Reg; - -struct ktap_probe_event { - struct list_head list; - struct perf_event *perf; - ktap_state *ks; - ktap_closure *cl; -}; - -/* this structure allocate on stack */ -struct ktap_event { - struct ktap_probe_event *pevent; - struct ftrace_event_call *call; - struct trace_entry *entry; - int entry_size; - struct pt_regs *regs; -}; - -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 -}; - -#define KTAP_PERCPU_BUFFER_SIZE (3 * PAGE_SIZE) - -int gettimeofday_us(void); -ktap_state *kp_newstate(struct ktap_parm *parm, struct dentry *dir); -void kp_exit(ktap_state *ks); -void kp_final_exit(ktap_state *ks); -ktap_state *kp_newthread(ktap_state *mainthread); -void kp_exitthread(ktap_state *ks); -ktap_closure *kp_load(ktap_state *ks, unsigned char *buff); -void kp_call(ktap_state *ks, StkId func, int nresults); -void kp_optimize_code(ktap_state *ks, int level, ktap_proto *f); -void kp_register_lib(ktap_state *ks, const char *libname, const ktap_Reg *funcs); -void *kp_percpu_data(int type); - -void kp_init_baselib(ktap_state *ks); -void kp_init_oslib(ktap_state *ks); -void kp_init_kdebuglib(ktap_state *ks); -void kp_init_timerlib(ktap_state *ks); -void kp_init_ansilib(ktap_state *ks); - -int kp_probe_init(ktap_state *ks); -void kp_probe_exit(ktap_state *ks); - -void kp_perf_event_register(ktap_state *ks, struct perf_event_attr *attr, - struct task_struct *task, char *filter, - ktap_closure *cl); - -void kp_event_getarg(ktap_state *ks, ktap_value *ra, int n); -void kp_event_tostring(ktap_state *ks, struct trace_seq *seq); - -int kp_strfmt(ktap_state *ks, struct trace_seq *seq); - -void kp_transport_write(ktap_state *ks, const void *data, size_t length); -void kp_transport_event_write(ktap_state *ks, struct ktap_event *e); -void kp_transport_print_backtrace(ktap_state *ks); -void *kp_transport_reserve(ktap_state *ks, size_t length); -void kp_transport_exit(ktap_state *ks); -int kp_transport_init(ktap_state *ks, struct dentry *dir); - -void kp_exit_timers(ktap_state *ks); - -extern int kp_max_exec_count; - -/* get from kernel/trace/trace.h */ -static __always_inline int trace_get_context_bit(void) -{ - int bit; - - if (in_interrupt()) { - if (in_nmi()) - bit = 0; - else if (in_irq()) - bit = 1; - else - bit = 2; - } else - bit = 3; - - return bit; -} - -/* use a special timer context kp_state instead use this recursion approach? */ -DECLARE_PER_CPU(int, kp_recursion_context[PERF_NR_CONTEXTS]); - -static __always_inline int get_recursion_context(void) -{ - int rctx = trace_get_context_bit(); - - if (__this_cpu_read(kp_recursion_context[rctx])) - return -1; - - __this_cpu_write(kp_recursion_context[rctx], true); - barrier(); - - return rctx; -} - -static inline void put_recursion_context(int rctx) -{ - barrier(); - __this_cpu_write(kp_recursion_context[rctx], false); -} - - -extern unsigned int kp_stub_exit_instr; - -static inline void set_next_as_exit(ktap_state *ks) -{ - ktap_callinfo *ci; - - ci = ks->ci; - if (!ci) - return; - - ci->u.l.savedpc = &kp_stub_exit_instr; - - /* See precall, ci changed to ci->prev after invoke C function */ - if (ci->prev) { - ci = ci->prev; - ci->u.l.savedpc = &kp_stub_exit_instr; - } -} - -#define kp_verbose_printf(ks, ...) \ - if (G(ks)->parm->verbose) \ - kp_printf(ks, "[verbose] "__VA_ARGS__); - -/* get argument operation macro */ -#define kp_arg(ks, n) ((ks)->ci->func + (n)) -#define kp_arg_nr(ks) ((int)(ks->top - (ks->ci->func + 1))) - -#define kp_arg_check(ks, narg, type) \ - do { \ - if (unlikely(ttypenv(kp_arg(ks, narg)) != type)) { \ - kp_error(ks, "wrong type of argument %d\n", narg);\ - return -1; \ - } \ - } while (0) - - -#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 5, 0) -#define SPRINT_SYMBOL sprint_symbol_no_offset -#else -#define SPRINT_SYMBOL sprint_symbol -#endif - -#endif /* __KTAP_H__ */ diff --git a/drivers/staging/ktap/include/ktap_opcodes.h b/drivers/staging/ktap/include/ktap_opcodes.h deleted file mode 100644 index 31c558b..0000000 --- a/drivers/staging/ktap/include/ktap_opcodes.h +++ /dev/null @@ -1,240 +0,0 @@ -#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_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_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) >1) /* `sBx' is signed */ - -#define MAXARG_Ax ((1<>POS_OP) & MASK1(SIZE_OP,0)) -#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ - ((((ktap_instruction)o)<>pos) & MASK1(size,0)) -#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ - ((((ktap_instruction)v)<> 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__ */ diff --git a/drivers/staging/ktap/include/ktap_types.h b/drivers/staging/ktap/include/ktap_types.h deleted file mode 100644 index cf1cef4..0000000 --- a/drivers/staging/ktap/include/ktap_types.h +++ /dev/null @@ -1,674 +0,0 @@ -#ifndef __KTAP_TYPES_H__ -#define __KTAP_TYPES_H__ - -/* opcode is copied from lua initially */ - -#ifdef __KERNEL__ -#include -#include -#include -#include -#else -typedef char u8; -#include -#include -#include -#endif - -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; -} 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 "2" - -#define KTAP_VERSION "ktap " KTAP_VERSION_MAJOR "." KTAP_VERSION_MINOR -#define KTAP_AUTHOR "Jovi Zhangwei " -#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 int ktap_instruction; - -typedef union ktap_gcobject ktap_gcobject; - -#define CommonHeader ktap_gcobject *next; u8 tt; - -struct ktap_state; -typedef int (*ktap_cfunction) (struct ktap_state *ks); - -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; -} ktap_string; - -#define getstr(ts) (const char *)((ts) + 1) -#define eqshrstr(a,b) ((a) == (b)) - -#define svalue(o) getstr(rawtsvalue(o)) - - -union _ktap_value { - ktap_gcobject *gc; /* collectable objects */ - void *p; /* light userdata */ - int b; /* booleans */ - ktap_cfunction f; /* light C functions */ - long n; /* numbers */ -}; - - -typedef struct ktap_value { - union _ktap_value val; - int type; -} ktap_value; - -typedef ktap_value * StkId; - - - -typedef union ktap_udata { - struct { - CommonHeader; - size_t len; /* number of bytes */ - } uv; -} ktap_udata; - -/* - * 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_STACK_MAX_ENTRIES 10 - -typedef struct ktap_btrace { - CommonHeader; - unsigned int nr_entries; - unsigned long entries[KTAP_STACK_MAX_ENTRIES]; -} ktap_btrace; - -#define ktap_closure_header \ - CommonHeader; u8 nupvalues; ktap_gcobject *gclist - -typedef struct ktap_cclosure { - ktap_closure_header; - ktap_cfunction f; - ktap_value upvalue[1]; /* list of upvalues */ -} ktap_cclosure; - - -typedef struct ktap_lclosure { - ktap_closure_header; - struct ktap_proto *p; - struct ktap_upval *upvals[1]; /* list of upvalues */ -} ktap_lclosure; - - -typedef struct ktap_closure { - struct ktap_cclosure c; - struct ktap_lclosure l; -} 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 Lua 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_tables - */ -typedef union ktap_tkey { - struct { - union _ktap_value value_; - int tt_; - struct ktap_tnode *next; /* for chaining */ - } nk; - ktap_value tvk; -} ktap_tkey; - - -typedef struct ktap_tnode { - ktap_value i_val; - ktap_tkey i_key; -} ktap_tnode; - - -typedef struct ktap_table { - CommonHeader; -#ifdef __KERNEL__ - arch_spinlock_t lock; -#endif - u8 flags; /* 1<

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)) - - -#ifdef __KERNEL__ -#define ktap_assert(s) -#else -#define ktap_assert(s) -#if 0 -#define ktap_assert(s) \ - do { \ - if (!s) { \ - printf("assert failed %s, %d\n", __func__, __LINE__);\ - exit(0); \ - } \ - } while(0) -#endif -#endif - -#define check_exp(c,e) (e) - - -typedef int ktap_number; - - -#define ktap_number2int(i,n) ((i)=(int)(n)) - - -/* 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_TLCL (KTAP_TFUNCTION | (0 << 4)) /* closure */ -#define KTAP_TLCF (KTAP_TFUNCTION | (1 << 4)) /* light C function */ -#define KTAP_TCCL (KTAP_TFUNCTION | (2 << 4)) /* C closure */ -#define KTAP_TUSERDATA 7 -#define KTAP_TTHREAD 8 - -#define KTAP_NUMTAGS 9 - -#define KTAP_TPROTO 11 -#define KTAP_TUPVAL 12 - -#define KTAP_TEVENT 13 - -#define KTAP_TBTRACE 14 - -#define KTAP_TAGGRTABLE 15 -#define KTAP_TAGGRACCVAL 16 -#define KTAP_TAGGRVAL 17 - -#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 bvalue(o) (val_(o).b) -#define nvalue(o) (val_(o).n) -#define hvalue(o) (&val_(o).gc->h) -#define ahvalue(o) (&val_(o).gc->ah) -#define aggraccvalue(o) (&val_(o).gc->acc) -#define CLVALUE(o) (&val_(o).gc->cl.l) -#define clcvalue(o) (&val_(o).gc->cl.c) -#define clvalue(o) (&val_(o).gc->cl) -#define rawtsvalue(o) (&val_(o).gc->ts) -#define pvalue(o) (&val_(o).p) -#define fvalue(o) (val_(o).f) -#define rawuvalue(o) (&val_(o).gc->u) -#define uvalue(o) (&rawuvalue(o)->uv) -#define evalue(o) (val_(o).p) -#define btvalue(o) (&val_(o).gc->bt) - -#define gcvalue(o) (val_(o).gc) - -#define isnil(o) (o->type == KTAP_TNIL) -#define isboolean(o) (o->type == KTAP_TBOOLEAN) -#define isfalse(o) (isnil(o) || (isboolean(o) && bvalue(o) == 0)) - -#define ttisshrstring(o) ((o)->type == KTAP_TSHRSTR) -#define ttisstring(o) (((o)->type & 0x0F) == KTAP_TSTRING) -#define ttisnumber(o) ((o)->type == KTAP_TNUMBER) -#define ttisfunc(o) ((o)->type == KTAP_TFUNCTION) -#define ttistable(o) ((o)->type == KTAP_TTABLE) -#define ttisaggrtable(o) ((o)->type == KTAP_TAGGRTABLE) -#define ttisaggrval(o) ((o)->type == KTAP_TAGGRVAL) -#define ttisaggracc(o) ((o)->type == KTAP_TAGGRACCVAL) -#define ttisnil(o) ((o)->type == KTAP_TNIL) -#define ttisboolean(o) ((o)->type == KTAP_TBOOLEAN) -#define ttisequal(o1,o2) ((o1)->type == (o2)->type) -#define ttisevent(o) ((o)->type == KTAP_TEVENT) -#define ttisbtrace(o) ((o)->type == KTAP_TBTRACE) - -#define ttisclone(o) ttisbtrace(o) - - -#define setnilvalue(obj) \ - { ktap_value *io = (obj); io->val.n = 0; settype(io, KTAP_TNIL); } - -#define setbvalue(obj, x) \ - { ktap_value *io = (obj); io->val.b = (x); settype(io, KTAP_TBOOLEAN); } - -#define setnvalue(obj, x) \ - { ktap_value *io = (obj); io->val.n = (x); settype(io, KTAP_TNUMBER); } - -#define setaggrvalue(obj, x) \ - { ktap_value *io = (obj); io->val.n = (x); settype(io, KTAP_TAGGRVAL); } - -#define setaggraccvalue(obj,x) \ - { ktap_value *io=(obj); \ - val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TAGGRACCVAL); } - -#define setsvalue(obj, x) \ - { ktap_value *io = (obj); \ - ktap_string *x_ = (x); \ - io->val.gc = (ktap_gcobject *)x_; settype(io, x_->tsv.tt); } - -#define setcllvalue(obj, x) \ - { ktap_value *io = (obj); \ - io->val.gc = (ktap_gcobject *)x; settype(io, KTAP_TLCL); } - -#define sethvalue(obj,x) \ - { ktap_value *io=(obj); \ - val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TTABLE); } - -#define setahvalue(obj,x) \ - { ktap_value *io=(obj); \ - val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TAGGRTABLE); } - -#define setfvalue(obj,x) \ - { ktap_value *io=(obj); val_(io).f=(x); settype(io, KTAP_TLCF); } - -#define setthvalue(L,obj,x) \ - { ktap_value *io=(obj); \ - val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TTHREAD); } - -#define setevalue(obj, x) \ - { ktap_value *io=(obj); val_(io).p = (x); settype(io, KTAP_TEVENT); } - -#define setbtvalue(obj,x) \ - { ktap_value *io=(obj); \ - val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TBTRACE); } - -#define setobj(obj1,obj2) \ - { const ktap_value *io2=(obj2); ktap_value *io1=(obj1); \ - io1->val = io2->val; io1->type = io2->type; } - -#define rawequalobj(t1, t2) \ - (ttisequal(t1, t2) && kp_equalobjv(NULL, t1, t2)) - -#define equalobj(ks, t1, t2) rawequalobj(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)) - - -ktap_string *kp_tstring_newlstr(ktap_state *ks, const char *str, size_t l); -ktap_string *kp_tstring_newlstr_local(ktap_state *ks, const char *str, size_t l); -ktap_string *kp_tstring_new(ktap_state *ks, const char *str); -ktap_string *kp_tstring_new_local(ktap_state *ks, const char *str); -int kp_tstring_eqstr(ktap_string *a, ktap_string *b); -unsigned int kp_string_hash(const char *str, size_t l, unsigned int seed); -int kp_tstring_eqlngstr(ktap_string *a, ktap_string *b); -int kp_tstring_cmp(const ktap_string *ls, const ktap_string *rs); -void kp_tstring_resize(ktap_state *ks, int newsize); -void kp_tstring_freeall(ktap_state *ks); - -ktap_value *kp_table_set(ktap_state *ks, ktap_table *t, const ktap_value *key); -ktap_table *kp_table_new(ktap_state *ks); -const ktap_value *kp_table_getint(ktap_table *t, int key); -void kp_table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *v); -const ktap_value *kp_table_get(ktap_table *t, const ktap_value *key); -void kp_table_setvalue(ktap_state *ks, ktap_table *t, const ktap_value *key, ktap_value *val); -void kp_table_resize(ktap_state *ks, ktap_table *t, int nasize, int nhsize); -void kp_table_resizearray(ktap_state *ks, ktap_table *t, int nasize); -void kp_table_free(ktap_state *ks, ktap_table *t); -int kp_table_length(ktap_state *ks, ktap_table *t); -void kp_table_dump(ktap_state *ks, ktap_table *t); -void kp_table_clear(ktap_state *ks, ktap_table *t); -void kp_table_histogram(ktap_state *ks, ktap_table *t); -int kp_table_next(ktap_state *ks, ktap_table *t, StkId key); -void kp_table_atomic_inc(ktap_state *ks, ktap_table *t, ktap_value *key, int n); -void kp_aggraccval_dump(ktap_state *ks, ktap_aggraccval *acc); -ktap_aggrtable *kp_aggrtable_new(ktap_state *ks); -ktap_table *kp_aggrtable_synthesis(ktap_state *ks, ktap_aggrtable *ah); -void kp_aggrtable_dump(ktap_state *ks, ktap_aggrtable *ah); -void kp_aggrtable_free(ktap_state *ks, ktap_aggrtable *ah); -void kp_aggrtable_set(ktap_state *ks, ktap_aggrtable *ah, - ktap_value *key, ktap_value *val); -void kp_aggrtable_get(ktap_state *ks, ktap_aggrtable *ah, - ktap_value *key, ktap_value *val); -void kp_aggrtable_histogram(ktap_state *ks, ktap_aggrtable *ah); -void kp_obj_dump(ktap_state *ks, const ktap_value *v); -void kp_showobj(ktap_state *ks, const ktap_value *v); -int kp_objlen(ktap_state *ks, const ktap_value *rb); -void kp_objclone(ktap_state *ks, const ktap_value *o, ktap_value *newo, - ktap_gcobject **list); -ktap_gcobject *kp_newobject(ktap_state *ks, int type, size_t size, ktap_gcobject **list); -int kp_equalobjv(ktap_state *ks, const ktap_value *t1, const ktap_value *t2); -ktap_closure *kp_newlclosure(ktap_state *ks, int n); -ktap_proto *kp_newproto(ktap_state *ks); -ktap_upval *kp_newupval(ktap_state *ks); -void kp_free_gclist(ktap_state *ks, ktap_gcobject *o); -void kp_free_all_gcobject(ktap_state *ks); -void kp_header(u8 *h); - -int kp_str2d(const char *s, size_t len, ktap_number *result); - -#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_malloc(ktap_state *ks, int size); -void kp_free(ktap_state *ks, void *addr); -void *kp_reallocv(ktap_state *ks, void *addr, int oldsize, int newsize); -void *kp_zalloc(ktap_state *ks, int size); - -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_malloc(ks, size) malloc(size) -#define kp_free(ks, block) free(block) -#define kp_reallocv(ks, block, osize, nsize) realloc(block, nsize) -#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") - -#endif /* __KTAP_TYPES_H__ */ - diff --git a/drivers/staging/ktap/interpreter/ktap.c b/drivers/staging/ktap/interpreter/ktap.c deleted file mode 100644 index 18d8fc8..0000000 --- a/drivers/staging/ktap/interpreter/ktap.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * ktap.c - ktapvm kernel module main entry - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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. - */ - -/* - * this file is the first file to be compile, add CONFIG_ checking in here. - * See Requirements in doc/introduction.txt - */ - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) -#error "Currently ktap don't support kernel older than 3.1" -#endif - -#if !CONFIG_EVENT_TRACING -#error "Please enable CONFIG_EVENT_TRACING before compile ktap" -#endif - -#if !CONFIG_PERF_EVENTS -#error "Please enable CONFIG_PERF_EVENTS before compile ktap" -#endif - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/ktap.h" - -static int load_trunk(struct ktap_parm *parm, unsigned long **buff) -{ - int ret; - unsigned long *vmstart; - - vmstart = vmalloc(parm->trunk_len); - if (!vmstart) - return -ENOMEM; - - ret = copy_from_user(vmstart, (void __user *)parm->trunk, - parm->trunk_len); - if (ret < 0) { - vfree(vmstart); - return -EFAULT; - } - - *buff = vmstart; - return 0; -} - -int gettimeofday_us(void) -{ - struct timeval tv; - - do_gettimeofday(&tv); - return tv.tv_sec * USEC_PER_SEC + tv.tv_usec; -} - -struct dentry *kp_dir_dentry; -static atomic_t kp_is_running = ATOMIC_INIT(0); - -/* Ktap Main Entry */ -static int ktap_main(struct file *file, ktap_parm *parm) -{ - unsigned long *buff = NULL; - ktap_state *ks; - ktap_closure *cl; - int start_time, delta_time; - int ret; - - if (atomic_inc_return(&kp_is_running) != 1) { - atomic_dec(&kp_is_running); - pr_info("only one ktap thread allow to run\n"); - return -EBUSY; - } - - start_time = gettimeofday_us(); - - ks = kp_newstate(parm, kp_dir_dentry); - if (unlikely(!ks)) { - ret = -ENOEXEC; - goto out; - } - - file->private_data = ks; - - ret = load_trunk(parm, &buff); - if (ret) { - pr_err("cannot load file\n"); - goto out; - } - - cl = kp_load(ks, (unsigned char *)buff); - - vfree(buff); - - if (cl) { - /* optimize bytecode before excuting */ - kp_optimize_code(ks, 0, cl->l.p); - - delta_time = gettimeofday_us() - start_time; - kp_verbose_printf(ks, "booting time: %d (us)\n", delta_time); - kp_call(ks, ks->top - 1, 0); - } - - kp_final_exit(ks); - - out: - atomic_dec(&kp_is_running); - return ret; -} - - -static void print_version(void) -{ -} - -static long ktap_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - ktap_parm parm; - int ret; - - switch (cmd) { - case KTAP_CMD_IOC_VERSION: - print_version(); - return 0; - case KTAP_CMD_IOC_RUN: - ret = copy_from_user(&parm, (void __user *)arg, - sizeof(ktap_parm)); - if (ret < 0) - return -EFAULT; - - return ktap_main(file, &parm); - default: - return -EINVAL; - }; - - return 0; -} - -static const struct file_operations ktap_fops = { - .llseek = no_llseek, - .unlocked_ioctl = ktap_ioctl, -}; - -static long ktapvm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int new_fd, err; - struct file *new_file; - - new_fd = get_unused_fd(); - if (new_fd < 0) - return new_fd; - - new_file = anon_inode_getfile("[ktap]", &ktap_fops, NULL, O_RDWR); - if (IS_ERR(new_file)) { - err = PTR_ERR(new_file); - put_unused_fd(new_fd); - return err; - } - - file->private_data = NULL; - fd_install(new_fd, new_file); - return new_fd; -} - -static const struct file_operations ktapvm_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = ktapvm_ioctl, -}; - -unsigned int kp_stub_exit_instr; - -static int __init init_ktap(void) -{ - struct dentry *ktapvm_dentry; - - kp_dir_dentry = debugfs_create_dir("ktap", NULL); - if (!kp_dir_dentry) { - pr_err("ktap: debugfs_create_dir failed\n"); - return -1; - } - - ktapvm_dentry = debugfs_create_file("ktapvm", 0444, kp_dir_dentry, NULL, - &ktapvm_fops); - - if (!ktapvm_dentry) { - pr_err("ktapvm: cannot create ktapvm file\n"); - debugfs_remove_recursive(kp_dir_dentry); - return -1; - } - - SET_OPCODE(kp_stub_exit_instr, OP_EXIT); - - return 0; -} - -static void __exit exit_ktap(void) -{ - debugfs_remove_recursive(kp_dir_dentry); -} - -module_init(init_ktap); -module_exit(exit_ktap); - -MODULE_AUTHOR("Jovi Zhangwei "); -MODULE_DESCRIPTION("ktap"); -MODULE_LICENSE("GPL"); - -int kp_max_exec_count = 10000; -module_param_named(max_exec_count, kp_max_exec_count, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_exec_count, "non-mainthread max instruction execution count"); - diff --git a/drivers/staging/ktap/interpreter/library/ansilib.c b/drivers/staging/ktap/interpreter/library/ansilib.c deleted file mode 100644 index d058373..0000000 --- a/drivers/staging/ktap/interpreter/library/ansilib.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * ansilib.c - ANSI escape sequences library - * - * http://en.wikipedia.org/wiki/ANSI_escape_code - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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.h" - -/** - * function ansi.clear_screen - Move cursor to top left and clear screen. - * - * Description: Sends ansi code for moving cursor to top left and then the - * ansi code for clearing the screen from the cursor position to the end. - */ - -static int ktap_lib_clear_screen(ktap_state *ks) -{ - kp_printf(ks, "\033[1;1H\033[J"); - return 0; -} - -/** - * function ansi.set_color - Set the ansi Select Graphic Rendition mode. - * @fg: Foreground color to set. - * - * Description: Sends ansi code for Select Graphic Rendition mode for the - * given forground color. Black (30), Blue (34), Green (32), Cyan (36), - * Red (31), Purple (35), Brown (33), Light Gray (37). - */ - -static int ktap_lib_set_color(ktap_state *ks) -{ - int fg; - - kp_arg_check(ks, 1, KTAP_TNUMBER); - - fg = nvalue(kp_arg(ks, 1)); - kp_printf(ks, "\033[%dm", fg); - return 0; -} - -/** - * function ansi.set_color2 - Set the ansi Select Graphic Rendition mode. - * @fg: Foreground color to set. - * @bg: Background color to set. - * - * Description: Sends ansi code for Select Graphic Rendition mode for the - * given forground color, Black (30), Blue (34), Green (32), Cyan (36), - * Red (31), Purple (35), Brown (33), Light Gray (37) and the given - * background color, Black (40), Red (41), Green (42), Yellow (43), - * Blue (44), Magenta (45), Cyan (46), White (47). - */ -static int ktap_lib_set_color2(ktap_state *ks) -{ - int fg, bg; - - kp_arg_check(ks, 1, KTAP_TNUMBER); - kp_arg_check(ks, 2, KTAP_TNUMBER); - - fg = nvalue(kp_arg(ks, 1)); - bg = nvalue(kp_arg(ks, 2)); - kp_printf(ks, "\033[%d;%dm", fg, bg); - return 0; -} - -/** - * function ansi.set_color3 - Set the ansi Select Graphic Rendition mode. - * @fg: Foreground color to set. - * @bg: Background color to set. - * @attr: Color attribute to set. - * - * Description: Sends ansi code for Select Graphic Rendition mode for the - * given forground color, Black (30), Blue (34), Green (32), Cyan (36), - * Red (31), Purple (35), Brown (33), Light Gray (37), the given - * background color, Black (40), Red (41), Green (42), Yellow (43), - * Blue (44), Magenta (45), Cyan (46), White (47) and the color attribute - * All attributes off (0), Intensity Bold (1), Underline Single (4), - * Blink Slow (5), Blink Rapid (6), Image Negative (7). - */ -static int ktap_lib_set_color3(ktap_state *ks) -{ - int fg, bg, attr; - - kp_arg_check(ks, 1, KTAP_TNUMBER); - kp_arg_check(ks, 2, KTAP_TNUMBER); - kp_arg_check(ks, 3, KTAP_TNUMBER); - - fg = nvalue(kp_arg(ks, 1)); - bg = nvalue(kp_arg(ks, 2)); - attr = nvalue(kp_arg(ks, 3)); - - if (attr) - kp_printf(ks, "\033[%d;%d;%dm", fg, bg, attr); - else - kp_printf(ks, "\033[%d;%dm", fg, bg); - - return 0; -} - -/** - * function ansi.reset_color - Resets Select Graphic Rendition mode. - * - * Description: Sends ansi code to reset foreground, background and color - * attribute to default values. - */ -static int ktap_lib_reset_color(ktap_state *ks) -{ - kp_printf(ks, "\033[0;0m"); - return 0; -} - -/** - * function ansi.new_line - Move cursor to new line. - * - * Description: Sends ansi code new line. - */ -static int ktap_lib_new_line (ktap_state *ks) -{ - kp_printf(ks, "\12"); - return 0; -} - -static const ktap_Reg ansi_funcs[] = { - {"clear_screen", ktap_lib_clear_screen}, - {"set_color", ktap_lib_set_color}, - {"set_color2", ktap_lib_set_color2}, - {"set_color3", ktap_lib_set_color3}, - {"reset_color", ktap_lib_reset_color}, - {"new_line", ktap_lib_new_line}, - {NULL} -}; - -void kp_init_ansilib(ktap_state *ks) -{ - kp_register_lib(ks, "ansi", ansi_funcs); -} diff --git a/drivers/staging/ktap/interpreter/library/baselib.c b/drivers/staging/ktap/interpreter/library/baselib.c deleted file mode 100644 index 4bcdc62..0000000 --- a/drivers/staging/ktap/interpreter/library/baselib.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * baselib.c - ktapvm kernel module base library - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include "../../include/ktap.h" - -static int ktap_lib_next(ktap_state *ks) -{ - ktap_table *t = hvalue(ks->top - 2); - - if (kp_table_next(ks, t, ks->top-1)) { - ks->top += 1; - return 2; - } else { - ks->top -= 1; - setnilvalue(ks->top++); - return 1; - } -} - -static int ktap_lib_pairs(ktap_state *ks) -{ - ktap_value *v = kp_arg(ks, 1); - ktap_table *t; - - if (G(ks)->mainthread != ks) { - kp_error(ks, "only mainthread can call table pairs\n"); - return -1; - } - - if (ttistable(v)) { - t = hvalue(v); - } else if (ttisaggrtable(v)) { - t = kp_aggrtable_synthesis(ks, ahvalue(v)); - } else if (isnil(v)) { - kp_error(ks, "table is nil in pairs\n"); - return 0; - } else { - kp_error(ks, "wrong argument for pairs\n"); - return 0; - } - - setfvalue(ks->top++, ktap_lib_next); - sethvalue(ks->top++, t); - setnilvalue(ks->top++); - return 3; -} - -static int ktap_lib_len(ktap_state *ks) -{ - int len = kp_objlen(ks, kp_arg(ks, 1)); - - if (len < 0) - return -1; - - setnvalue(ks->top, len); - incr_top(ks); - return 1; -} - -static int ktap_lib_print(ktap_state *ks) -{ - int i; - int n = kp_arg_nr(ks); - - for (i = 1; i <= n; i++) { - ktap_value *arg = kp_arg(ks, i); - if (i > 1) - kp_puts(ks, "\t"); - kp_showobj(ks, arg); - } - - kp_puts(ks, "\n"); - - return 0; -} - -/* don't engage with tstring when printf, use buffer directly */ -static int ktap_lib_printf(ktap_state *ks) -{ - struct trace_seq *seq; - - preempt_disable_notrace(); - - seq = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER); - trace_seq_init(seq); - - if (kp_strfmt(ks, seq)) - return 0; - - seq->buffer[seq->len] = '\0'; - kp_transport_write(ks, seq->buffer, seq->len + 1); - - preempt_enable_notrace(); - return 0; -} - -#ifdef CONFIG_STACKTRACE -static int ktap_lib_print_backtrace(ktap_state *ks) -{ - kp_transport_print_backtrace(ks); - return 0; -} -#else -static int ktap_lib_print_backtrace(ktap_state *ks) -{ - kp_error(ks, "Please enable CONFIG_STACKTRACE before use " - "ktap print_backtrace\n"); - return 0; -} -#endif - -static int ktap_lib_backtrace(ktap_state *ks) -{ - struct stack_trace trace; - ktap_btrace *bt; - - bt = kp_percpu_data(KTAP_PERCPU_DATA_BTRACE); - - trace.nr_entries = 0; - trace.skip = 10; - trace.max_entries = KTAP_STACK_MAX_ENTRIES; - trace.entries = &bt->entries[0]; - save_stack_trace(&trace); - - bt->nr_entries = trace.nr_entries; - setbtvalue(ks->top, bt); - incr_top(ks); - return 1; -} - -extern unsigned long long ns2usecs(cycle_t nsec); -static int ktap_lib_print_trace_clock(ktap_state *ks) -{ - unsigned long long t; - unsigned long secs, usec_rem; - u64 timestamp; - - /* use ring buffer's timestamp */ - timestamp = ring_buffer_time_stamp(G(ks)->buffer, smp_processor_id()); - - t = ns2usecs(timestamp); - usec_rem = do_div(t, USEC_PER_SEC); - secs = (unsigned long)t; - - kp_printf(ks, "%5lu.%06lu\n", secs, usec_rem); - - return 0; -} - -static int ktap_lib_exit(ktap_state *ks) -{ - kp_exit(ks); - - /* do not execute bytecode any more in this thread */ - return -1; -} - -static int ktap_lib_pid(ktap_state *ks) -{ - pid_t pid = task_tgid_vnr(current); - - setnvalue(ks->top, (int)pid); - incr_top(ks); - return 1; -} - -static int ktap_lib_tid(ktap_state *ks) -{ - pid_t pid = task_pid_vnr(current); - - setnvalue(ks->top, (int)pid); - incr_top(ks); - return 1; -} - -static int ktap_lib_execname(ktap_state *ks) -{ - ktap_string *ts = kp_tstring_new(ks, current->comm); - setsvalue(ks->top, ts); - incr_top(ks); - return 1; -} - -static int ktap_lib_cpu(ktap_state *ks) -{ - setnvalue(ks->top, smp_processor_id()); - incr_top(ks); - return 1; -} - -static int ktap_lib_num_cpus(ktap_state *ks) -{ - setnvalue(ks->top, num_online_cpus()); - incr_top(ks); - return 1; -} - -static int ktap_lib_in_interrupt(ktap_state *ks) -{ - int ret = in_interrupt(); - - setnvalue(ks->top, ret); - incr_top(ks); - return 1; -} - -static int ktap_lib_arch(ktap_state *ks) -{ - setsvalue(ks->top, kp_tstring_new(ks, utsname()->machine)); - incr_top(ks); - return 1; -} - -static int ktap_lib_kernel_v(ktap_state *ks) -{ - setsvalue(ks->top, kp_tstring_new(ks, utsname()->release)); - incr_top(ks); - return 1; -} - -static int ktap_lib_user_string(ktap_state *ks) -{ - unsigned long addr; - char str[256] = {0}; - int ret; - - kp_arg_check(ks, 1, KTAP_TNUMBER); - - addr = nvalue(kp_arg(ks, 1)); - - pagefault_disable(); - ret = __copy_from_user_inatomic((void *)str, (const void *)addr, 256); - (void) &ret; /* Silence compiler warning. */ - pagefault_enable(); - str[255] = '\0'; - setsvalue(ks->top, kp_tstring_new(ks, str)); - - incr_top(ks); - return 1; -} - -static int ktap_lib_histogram(ktap_state *ks) -{ - ktap_value *v = kp_arg(ks, 1); - - if (G(ks)->mainthread != ks) { - kp_error(ks, "only mainthread can call table historgram\n"); - return -1; - } - - if (ttistable(v)) - kp_table_histogram(ks, hvalue(v)); - else if (ttisaggrtable(v)) - kp_aggrtable_histogram(ks, ahvalue(v)); - - return 0; -} - -static int ktap_lib_aggr_table(ktap_state *ks) -{ - ktap_aggrtable *ah; - - ah = kp_aggrtable_new(ks); - setahvalue(ks->top, ah); - incr_top(ks); - return 1; -} - -static int ktap_lib_aggr_count(ktap_state *ks) -{ - setaggrvalue(ks->top, AGGREGATION_TYPE_COUNT); - incr_top(ks); - return 1; -} - -static int ktap_lib_aggr_max(ktap_state *ks) -{ - kp_arg_check(ks, 1, KTAP_TNUMBER); - - ks->aggr_accval = nvalue(kp_arg(ks, 1)); - setaggrvalue(ks->top, AGGREGATION_TYPE_MAX); - incr_top(ks); - return 1; -} - -static int ktap_lib_aggr_min(ktap_state *ks) -{ - kp_arg_check(ks, 1, KTAP_TNUMBER); - - ks->aggr_accval = nvalue(kp_arg(ks, 1)); - setaggrvalue(ks->top, AGGREGATION_TYPE_MIN); - incr_top(ks); - return 1; -} - -static int ktap_lib_aggr_sum(ktap_state *ks) -{ - kp_arg_check(ks, 1, KTAP_TNUMBER); - - ks->aggr_accval = nvalue(kp_arg(ks, 1)); - setaggrvalue(ks->top, AGGREGATION_TYPE_SUM); - incr_top(ks); - return 1; -} - -static int ktap_lib_aggr_avg(ktap_state *ks) -{ - kp_arg_check(ks, 1, KTAP_TNUMBER); - - ks->aggr_accval = nvalue(kp_arg(ks, 1)); - setaggrvalue(ks->top, AGGREGATION_TYPE_AVG); - incr_top(ks); - return 1; -} - -static int ktap_lib_delete(ktap_state *ks) -{ - kp_arg_check(ks, 1, KTAP_TTABLE); - - kp_table_clear(ks, hvalue(kp_arg(ks, 1))); - return 0; -} - -static int ktap_lib_gettimeofday_us(ktap_state *ks) -{ - setnvalue(ks->top, gettimeofday_us()); - incr_top(ks); - - return 1; -} - -/* - * use gdb to get field offset of struct task_struct, for example: - * - * gdb vmlinux - * (gdb)p &(((struct task_struct *)0).prio) - */ -static int ktap_lib_curr_task_info(ktap_state *ks) -{ - int offset; - int fetch_bytes; - - kp_arg_check(ks, 1, KTAP_TNUMBER); - - offset = nvalue(kp_arg(ks, 1)); - - if (kp_arg_nr(ks) == 1) - fetch_bytes = 4; /* default fetch 4 bytes*/ - else { - kp_arg_check(ks, 2, KTAP_TNUMBER); - fetch_bytes = nvalue(kp_arg(ks, 2)); - } - - if (offset >= sizeof(struct task_struct)) { - setnilvalue(ks->top++); - kp_error(ks, "access out of bound value of task_struct\n"); - return 1; - } - -#define RET_VALUE ((unsigned long)current + offset) - - switch (fetch_bytes) { - case 4: - setnvalue(ks->top, *(unsigned int *)RET_VALUE); - break; - case 8: - setnvalue(ks->top, *(unsigned long *)RET_VALUE); - break; - default: - kp_error(ks, "unsupported fetch bytes in curr_task_info\n"); - setnilvalue(ks->top); - break; - } - -#undef RET_VALUE - - incr_top(ks); - return 1; -} - -/* - * This built-in function mainly purpose scripts/schedule/schedtimes.kp - */ -static int ktap_lib_in_iowait(ktap_state *ks) -{ - setnvalue(ks->top, current->in_iowait); - incr_top(ks); - - return 1; -} - -static const ktap_Reg base_funcs[] = { - {"pairs", ktap_lib_pairs}, - {"len", ktap_lib_len}, - {"print", ktap_lib_print}, - {"printf", ktap_lib_printf}, - {"print_backtrace", ktap_lib_print_backtrace}, - {"backtrace", ktap_lib_backtrace}, - {"print_trace_clock", ktap_lib_print_trace_clock}, - {"in_interrupt", ktap_lib_in_interrupt}, - {"exit", ktap_lib_exit}, - {"pid", ktap_lib_pid}, - {"tid", ktap_lib_tid}, - {"execname", ktap_lib_execname}, - {"cpu", ktap_lib_cpu}, - {"num_cpus", ktap_lib_num_cpus}, - {"arch", ktap_lib_arch}, - {"kernel_v", ktap_lib_kernel_v}, - {"user_string", ktap_lib_user_string}, - {"histogram", ktap_lib_histogram}, - {"aggr_table", ktap_lib_aggr_table}, - {"count", ktap_lib_aggr_count}, - {"max", ktap_lib_aggr_max}, - {"min", ktap_lib_aggr_min}, - {"sum", ktap_lib_aggr_sum}, - {"avg", ktap_lib_aggr_avg}, - - {"delete", ktap_lib_delete}, - {"gettimeofday_us", ktap_lib_gettimeofday_us}, - {"curr_taskinfo", ktap_lib_curr_task_info}, - {"in_iowait", ktap_lib_in_iowait}, - {NULL} -}; - -void kp_init_baselib(ktap_state *ks) -{ - kp_register_lib(ks, NULL, base_funcs); -} diff --git a/drivers/staging/ktap/interpreter/library/kdebug.c b/drivers/staging/ktap/interpreter/library/kdebug.c deleted file mode 100644 index a9477be..0000000 --- a/drivers/staging/ktap/interpreter/library/kdebug.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * kdebug.c - ktap probing core implementation - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include "../../include/ktap.h" - -static void ktap_call_probe_closure(ktap_state *mainthread, ktap_closure *cl, - struct ktap_event *e) -{ - ktap_state *ks; - ktap_value *func; - - ks = kp_newthread(mainthread); - setcllvalue(ks->top, cl); - func = ks->top; - incr_top(ks); - - ks->current_event = e; - - kp_call(ks, func, 0); - - ks->current_event = NULL; - kp_exitthread(ks); -} - -void kp_event_tostring(ktap_state *ks, struct trace_seq *seq) -{ - struct ktap_event *e = ks->current_event; - struct trace_iterator *iter; - struct trace_event *ev; - enum print_line_t ret = TRACE_TYPE_NO_CONSUME; - - /* Simulate the iterator */ - - /* - * use temp percpu buffer as trace_iterator - * we cannot use same temp buffer as printf. - */ - iter = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER2); - - trace_seq_init(&iter->seq); - iter->ent = e->entry; - - ev = &(e->call->event); - if (ev) - ret = ev->funcs->trace(iter, 0, ev); - - if (ret != TRACE_TYPE_NO_CONSUME) { - struct trace_seq *s = &iter->seq; - int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; - - s->buffer[len] = '\0'; - trace_seq_puts(seq, s->buffer); - } -} - -#if 0 -/* check pt_regs defintion in linux/arch/x86/include/asm/ptrace.h */ -/* support other architecture pt_regs showing */ -static void event_regstr(ktap_state *ks, struct ktap_event *e, StkId ra) -{ - struct pt_regs *regs = e->regs; - char str[256] = {0}; - -#if defined(CONFIG_X86_32) - snprintf(str, sizeof(str), - "{ax: 0x%lx, orig_ax: 0x%lx, bx: 0x%lx, cx: 0x%lx, dx: 0x%lx, " - "si: 0x%lx, di: 0x%lx, bp: 0x%lx, ds: 0x%lx, es: 0x%lx, fs: 0x%lx, " - "gs: 0x%lx, ip: 0x%lx, cs: 0x%lx, flags: 0x%lx, sp: 0x%lx, ss: 0x%lx}\n", - regs->ax, regs->orig_ax, regs->bx, regs->cx, regs->dx, - regs->si, regs->di, regs->bp, regs->ds, regs->es, regs->fs, - regs->gs, regs->ip, regs->cs, regs->flags, regs->sp, regs->ss); -#elif defined(CONFIG_X86_64) - /* x86_64 pt_regs doesn't have ds, es, fs or gs. */ - snprintf(str, sizeof(str), - "{ax: 0x%lx, orig_ax: 0x%lx, bx: 0x%lx, cx: 0x%lx, dx: 0x%lx, " - "si: 0x%lx, di: 0x%lx, r8: 0x%lx, r9: 0x%lx, r10: 0x%lx, r11: 0x%lx, " - "r12: 0x%lx, r13: 0x%lx, r14: 0x%lx, r15: 0x%lx, bp: 0x%lx, ip: 0x%lx, " - "cs: 0x%lx, flags: 0x%lx, sp: 0x%lx, ss: 0x%lx}\n", - regs->ax, regs->orig_ax, regs->bx, regs->cx, regs->dx, - regs->si, regs->di, regs->r8, regs->r9, regs->r10, regs->r11, - regs->r12, regs->r13, regs->r14, regs->r15, regs->bp, regs->ip, - regs->cs, regs->flags, regs->sp, regs->ss); -#endif - setsvalue(ra, kp_tstring_new_local(ks, str)); -} -#endif - -/***************************/ -/* This definition should keep update with kernel/trace/trace.h */ -struct ftrace_event_field { - struct list_head link; - const char *name; - const char *type; - int filter_type; - int offset; - int size; - int is_signed; -}; - -static struct list_head *ktap_get_fields(struct ftrace_event_call *event_call) -{ - if (!event_call->class->get_fields) - return &event_call->class->fields; - return event_call->class->get_fields(event_call); -} - -static void get_field_value(ktap_state *ks, struct ktap_event *e, - struct ftrace_event_field *field, ktap_value *ra) -{ - void *value = (unsigned char *)e->entry + field->offset; - - if (field->size == 4) { - int n = *(int *)value; - setnvalue(ra, n); - return; - } else if (field->size == 8) { - long n = *(long *)value; - setnvalue(ra, n); - return; - } - - if (!strncmp(field->type, "char", 4)) { - setsvalue(ra, kp_tstring_new(ks, (char *)value)); - return; - } -} - -void kp_event_getarg(ktap_state *ks, ktap_value *ra, int n) -{ - struct ktap_event *e = ks->current_event; - int index = n; - struct ftrace_event_field *field; - struct list_head *head; - - /* this is very slow and not safe, fix it in future */ - head = ktap_get_fields(e->call); - list_for_each_entry_reverse(field, head, link) { - if (--index == 0) { - get_field_value(ks, e, field, ra); - return; - } - } - - setnilvalue(ra); - return; -} - -/* Callback function for perf event subsystem - * make ktap reentrant, don't disable irq in callback function, - * same as perf and ftrace. to make reentrant, we need some - * percpu data to be context isolation(irq/sirq/nmi/process) - * - * perf callback already consider on the recursion issue, - * so ktap don't need to check again in here. - * - * Note tracepoint handler is calling with rcu_read_lock. - */ -static void ktap_overflow_callback(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - struct ktap_probe_event *ktap_pevent; - struct ktap_event e; - ktap_state *ks; - int rctx; - - ktap_pevent = event->overflow_handler_context; - ks = ktap_pevent->ks; - - if (unlikely(ks->stop)) - return; - - rctx = get_recursion_context(); - if (rctx < 0) - return; - - /* profile perf event don't have valid associated tp_event */ - if (event->tp_event) { - e.call = event->tp_event; - e.entry = data->raw->data; - e.entry_size = data->raw->size; - } - e.pevent = ktap_pevent; - e.regs = regs; - - ktap_call_probe_closure(ks, ktap_pevent->cl, &e); - - put_recursion_context(rctx); -} - -static void perf_destructor(struct ktap_probe_event *ktap_pevent) -{ - perf_event_release_kernel(ktap_pevent->perf); -} - -static int (*kp_ftrace_profile_set_filter)(struct perf_event *event, - int event_id, char *filter_str); - -/* - * Generic perf event register function - * used by tracepoints/kprobe/uprobe/profile-timer/hw_breakpoint. - */ -void kp_perf_event_register(ktap_state *ks, struct perf_event_attr *attr, - struct task_struct *task, char *filter, - ktap_closure *cl) -{ - struct ktap_probe_event *ktap_pevent; - struct perf_event *event; - int cpu, ret; - - kp_verbose_printf(ks, "enable perf event id: %d, filter: %s " - "pid: %d\n", attr->config, filter, - task ? task_tgid_vnr(task) : -1); - - /* - * don't tracing until ktap_wait, the reason is: - * 1). some event may hit before apply filter - * 2). more simple to manage tracing thread - * 3). avoid race with mainthread. - * - * Another way to do this is make attr.disabled as 1, then use - * perf_event_enable after filter apply, however, perf_event_enable - * was not exported in kernel older than 3.3, so we drop this method. - */ - ks->stop = 1; - - for_each_cpu(cpu, G(ks)->cpumask) { - ktap_pevent = kp_zalloc(ks, sizeof(*ktap_pevent)); - ktap_pevent->ks = ks; - ktap_pevent->cl = cl; - event = perf_event_create_kernel_counter(attr, cpu, task, - ktap_overflow_callback, - ktap_pevent); - if (IS_ERR(event)) { - int err = PTR_ERR(event); - kp_error(ks, "unable register perf event %d on cpu %d, " - "err: %d\n", attr->config, cpu, err); - kp_free(ks, ktap_pevent); - return; - } - - ktap_pevent->perf = event; - INIT_LIST_HEAD(&ktap_pevent->list); - list_add_tail(&ktap_pevent->list, &G(ks)->probe_events_head); - - if (!filter) - continue; - - ret = kp_ftrace_profile_set_filter(event, attr->config, filter); - if (ret) { - kp_error(ks, "unable set filter %s for event id %d, " - "ret: %d\n", filter, attr->config, ret); - perf_destructor(ktap_pevent); - list_del(&ktap_pevent->list); - kp_free(ks, ktap_pevent); - return; - } - } -} - -static void end_probes(struct ktap_state *ks) -{ - struct ktap_probe_event *ktap_pevent; - struct list_head *tmp, *pos; - struct list_head *head = &G(ks)->probe_events_head; - - list_for_each(pos, head) { - ktap_pevent = container_of(pos, struct ktap_probe_event, - list); - perf_destructor(ktap_pevent); - } - /* - * Ensure our callback won't be called anymore. The buffers - * will be freed after that. - */ - tracepoint_synchronize_unregister(); - - list_for_each_safe(pos, tmp, head) { - ktap_pevent = container_of(pos, struct ktap_probe_event, - list); - list_del(&ktap_pevent->list); - kp_free(ks, ktap_pevent); - } -} - -static int ktap_lib_probe_by_id(ktap_state *ks) -{ - const char *ids_str; - char *start; - ktap_closure *cl; - struct task_struct *task = G(ks)->trace_task; - char filter_str[128] = {0}; - char *filter, *ptr1, *sep, *ptr; - - kp_arg_check(ks, 1, KTAP_TSTRING); - kp_arg_check(ks, 2, KTAP_TFUNCTION); - - ids_str = svalue(kp_arg(ks, 1)); - cl = clvalue(kp_arg(ks, 2)); - - start = (char *)ids_str; - - again: - filter = NULL; - - sep = strchr(start, ','); - if (!sep) - ptr1 = strchr(start, '/'); - else - ptr1 = strnchr(start, sep - start, '/'); - - if (ptr1) { - char *ptr2 = strrchr(ptr1 + 1, '/'); - - if (ptr2) { - memset(filter_str, 0, sizeof(filter_str)); - strncpy(filter_str, ptr1 + 1, ptr2 - ptr1 - 1); - filter = &filter_str[0]; - } else { - kp_printf(ks, "cannot parse ids_str: %s\n", ids_str); - return -1; - } - } - - for (ptr = start; *ptr != ',' && *ptr != '\0' && *ptr != '/'; ptr++) { - char token[32] = {0}; - int id; - int i = 0; - - if (*ptr == ' ') - continue; - - while (isdigit(*ptr)) { - token[i++] = *ptr++; - } - - if (!kstrtoint(token, 10, &id)) { - struct perf_event_attr attr; - - memset(&attr, 0, sizeof(attr)); - attr.type = PERF_TYPE_TRACEPOINT; - attr.config = id; - attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | - PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD; - attr.sample_period = 1; - attr.size = sizeof(attr); - attr.disabled = 0; - - kp_perf_event_register(ks, &attr, task, filter, cl); - } - } - - if (sep && (*(sep + 1) != '\0')) { - start = sep + 1; - goto again; - } - - return 0; -} - -static int ktap_lib_probe_end(ktap_state *ks) -{ - kp_arg_check(ks, 1, KTAP_TFUNCTION); - - G(ks)->trace_end_closure = clvalue(kp_arg(ks, 1)); - return 0; -} - -static int ktap_lib_traceoff(ktap_state *ks) -{ - end_probes(ks); - - /* call trace_end_closure after probed end */ - if (G(ks)->trace_end_closure) { - setcllvalue(ks->top, G(ks)->trace_end_closure); - incr_top(ks); - kp_call(ks, ks->top - 1, 0); - G(ks)->trace_end_closure = NULL; - } - - return 0; -} - -void kp_probe_exit(ktap_state *ks) -{ - if (!G(ks)->trace_enabled) - return; - - end_probes(ks); - - /* call trace_end_closure after probed end */ - if (!G(ks)->error && G(ks)->trace_end_closure) { - setcllvalue(ks->top, G(ks)->trace_end_closure); - incr_top(ks); - kp_call(ks, ks->top - 1, 0); - G(ks)->trace_end_closure = NULL; - } - - G(ks)->trace_enabled = 0; -} - -int kp_probe_init(ktap_state *ks) -{ - G(ks)->trace_enabled = 1; - return 0; -} - -static const ktap_Reg kdebuglib_funcs[] = { - {"probe_by_id", ktap_lib_probe_by_id}, - {"probe_end", ktap_lib_probe_end}, - {"traceoff", ktap_lib_traceoff}, - {NULL} -}; - -void kp_init_kdebuglib(ktap_state *ks) -{ - kp_ftrace_profile_set_filter = - (void *)kallsyms_lookup_name("ftrace_profile_set_filter"); - if (!kp_ftrace_profile_set_filter) { - printk("ktap: cannot lookup ftrace_profile_set_filter " - "in kallsyms\n"); - return; - } - - kp_register_lib(ks, "kdebug", kdebuglib_funcs); -} - diff --git a/drivers/staging/ktap/interpreter/library/timer.c b/drivers/staging/ktap/interpreter/library/timer.c deleted file mode 100644 index 759f917..0000000 --- a/drivers/staging/ktap/interpreter/library/timer.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * timer.c - timer library support for ktap - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include "../../include/ktap.h" - -struct hrtimer_ktap { - struct hrtimer timer; - ktap_state *ks; - ktap_closure *cl; - u64 ns; - struct list_head list; -}; - -/* - * Currently ktap disallow tracing event in timer callback closure, - * that will corrupt ktap_state and ktap stack, because timer closure - * and event closure use same irq percpu ktap_state and stack. - * We can use a different percpu ktap_state and stack for timer purpuse, - * but that's don't bring any big value with cost on memory consuming. - * - * So just simply disable tracing in timer closure, - * get_recursion_context()/put_recursion_context() is used for this purpose. - * - * option: export perf_swevent_put_recursion_context to slove this issue. - */ -static enum hrtimer_restart hrtimer_ktap_fn(struct hrtimer *timer) -{ - struct hrtimer_ktap *t; - ktap_state *ks; - int rctx; - - rcu_read_lock_sched_notrace(); - rctx = get_recursion_context(); - - t = container_of(timer, struct hrtimer_ktap, timer); - - ks = kp_newthread(t->ks); - setcllvalue(ks->top, t->cl); - incr_top(ks); - kp_call(ks, ks->top - 1, 0); - kp_exitthread(ks); - - hrtimer_add_expires_ns(timer, t->ns); - - put_recursion_context(rctx); - rcu_read_unlock_sched_notrace(); - - return HRTIMER_RESTART; -} - -static void set_tick_timer(ktap_state *ks, u64 period, ktap_closure *cl) -{ - struct hrtimer_ktap *t; - - t = kp_malloc(ks, sizeof(*t)); - t->ks = ks; - t->cl = cl; - t->ns = period; - - INIT_LIST_HEAD(&t->list); - list_add(&t->list, &(G(ks)->timers)); - - hrtimer_init(&t->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - t->timer.function = hrtimer_ktap_fn; - hrtimer_start(&t->timer, ns_to_ktime(period), HRTIMER_MODE_REL); -} - -static void set_profile_timer(ktap_state *ks, u64 period, ktap_closure *cl) -{ - struct perf_event_attr attr; - - memset(&attr, 0, sizeof(attr)); - attr.type = PERF_TYPE_SOFTWARE; - attr.config = PERF_COUNT_SW_CPU_CLOCK; - attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | - PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD; - attr.sample_period = period; - attr.size = sizeof(attr); - attr.disabled = 0; - - kp_perf_event_register(ks, &attr, NULL, NULL, cl); -} - -static int do_tick_profile(ktap_state *ks, int is_tick) -{ - const char *str, *tmp; - char interval_str[32] = {0}; - char suffix[10] = {0}; - int n, i = 0; - int factor; - - kp_arg_check(ks, 1, KTAP_TSTRING); - kp_arg_check(ks, 2, KTAP_TFUNCTION); - - str = svalue(kp_arg(ks, 1)); - tmp = str; - while (isdigit(*tmp)) - tmp++; - - strncpy(interval_str, str, tmp - str); - if (kstrtoint(interval_str, 10, &n)) - goto error; - - strncpy(suffix, tmp, 9); - while (suffix[i] != ' ' && suffix[i] != '\0') - i++; - - suffix[i] = '\0'; - - if (!strcmp(suffix, "s") || !strcmp(suffix, "sec")) - factor = NSEC_PER_SEC; - else if (!strcmp(suffix, "ms") || !strcmp(suffix, "msec")) - factor = NSEC_PER_MSEC; - else if (!strcmp(suffix, "us") || !strcmp(suffix, "usec")) - factor = NSEC_PER_USEC; - else - goto error; - - if (is_tick) - set_tick_timer(ks, (u64)factor * n, clvalue(kp_arg(ks, 2))); - else - set_profile_timer(ks, (u64)factor * n, clvalue(kp_arg(ks, 2))); - - return 0; - - error: - kp_error(ks, "cannot parse timer interval: %s\n", str); - return -1; -} - -/* - * tick-n probes fire on only one CPU per interval. - * valid time suffixes: sec/s, msec/ms, usec/us - */ -static int ktap_lib_tick(ktap_state *ks) -{ - return do_tick_profile(ks, 1); -} - -/* - * A profile-n probe fires every fixed interval on every CPU - * valid time suffixes: sec/s, msec/ms, usec/us - */ -static int ktap_lib_profile(ktap_state *ks) -{ - return do_tick_profile(ks, 0); -} - -void kp_exit_timers(ktap_state *ks) -{ - struct hrtimer_ktap *t, *tmp; - struct list_head *timers_list = &(G(ks)->timers); - - list_for_each_entry_safe(t, tmp, timers_list, list) { - hrtimer_cancel(&t->timer); - kp_free(ks, t); - } -} - -static const ktap_Reg timerlib_funcs[] = { - {"profile", ktap_lib_profile}, - {"tick", ktap_lib_tick}, - {NULL} -}; - -void kp_init_timerlib(ktap_state *ks) -{ - kp_register_lib(ks, "timer", timerlib_funcs); -} - diff --git a/drivers/staging/ktap/interpreter/loader.c b/drivers/staging/ktap/interpreter/loader.c deleted file mode 100644 index 0da54d7..0000000 --- a/drivers/staging/ktap/interpreter/loader.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * loader.c - loader for ktap bytecode chunk file - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 "../include/ktap.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 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 int load_number(struct load_state *S) -{ - int 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++) - setnilvalue(&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: - setnilvalue(o); - break; - case KTAP_TBOOLEAN: - setbvalue(o, READ_CHAR(S)); - break; - case KTAP_TNUMBER: - /* - * todo: kernel not support fp, check double when - * loading - */ - setnvalue(o, READ_NUMBER(S)); - break; - case KTAP_TSTRING: - setsvalue(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; -} - - -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; - ktap_lclosure *f; - int ret, i; - - S.ks = ks; - S.buff = buff; - S.pos = 0; - - ret = load_header(&S); - if (ret) - return NULL; - - cl = kp_newlclosure(ks, 1); - if (!cl) - return cl; - - /* put closure on the top, prepare to run with this closure */ - setcllvalue(ks->top, cl); - incr_top(ks); - - cl->l.p = kp_newproto(ks); - if (load_function(&S, cl->l.p)) - return NULL; - - if (cl->l.p->sizeupvalues != 1) { - ktap_proto *p = cl->l.p; - cl = kp_newlclosure(ks, cl->l.p->sizeupvalues); - cl->l.p = p; - setcllvalue(ks->top - 1, cl); - } - - f = &cl->l; - for (i = 0; i < f->nupvalues; i++) { /* initialize upvalues */ - ktap_upval *up = kp_newupval(ks); - f->upvals[i] = up; - } - - /* set global table as 1st upvalue of 'f' */ - if (f->nupvalues == 1) { - ktap_table *reg = hvalue(&G(ks)->registry); - const ktap_value *gt = kp_table_getint(reg, KTAP_RIDX_GLOBALS); - setobj(f->upvals[0]->v, gt); - } - - verify_code(&S, cl->l.p); - return cl; -} - diff --git a/drivers/staging/ktap/interpreter/object.c b/drivers/staging/ktap/interpreter/object.c deleted file mode 100644 index 6538167..0000000 --- a/drivers/staging/ktap/interpreter/object.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * object.c - ktap object generic operation - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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. - */ - -#ifdef __KERNEL__ -#include "../include/ktap.h" -#else -#include "../include/ktap_types.h" -#endif - -#ifdef __KERNEL__ - -#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"); - } - - return addr; -} - -void kp_free(ktap_state *ks, void *addr) -{ - 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"); - } - - 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"); - } - - 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_TLCF: - 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_TUSERDATA: - kp_printf(ks, "USERDATA 0x%lx", (unsigned long)uvalue(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 -#include - -static void kp_btrace_dump(ktap_state *ks, ktap_btrace *bt) -{ - char str[KSYM_SYMBOL_LEN]; - int i; - - for (i = 0; i < bt->nr_entries; i++) { - unsigned long p = bt->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) -{ - int i; - - if (bt1->nr_entries != bt2->nr_entries) - return 0; - - for (i = 0; i < bt1->nr_entries; i++) { - if (bt1->entries[i] != bt2->entries[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_TLCF: - kp_printf(ks, "0x%lx", (unsigned long)fvalue(v)); - break; - case KTAP_TSHRSTR: - case KTAP_TLNGSTR: - kp_puts(ks, svalue(v)); - break; - case KTAP_TUSERDATA: - kp_printf(ks, "0x%lx", (unsigned long)uvalue(v)); - break; - case KTAP_TTABLE: - kp_table_dump(ks, hvalue(v)); - break; -#ifdef __KERNEL__ - case KTAP_TEVENT: - kp_transport_event_write(ks, evalue(v)); - break; - case KTAP_TBTRACE: - kp_btrace_dump(ks, btvalue(v)); - break; - case KTAP_TAGGRTABLE: - kp_aggrtable_dump(ks, ahvalue(v)); - break; - case KTAP_TAGGRACCVAL: - kp_aggraccval_dump(ks, aggraccvalue(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_TLCF: - 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_TUSERDATA: - if (uvalue(t1) == uvalue(t2)) - return 1; - else if (ks == NULL) - return 0; - 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; -} - -/* - * ktap will not use lua's length operator on table meaning, - * also # is not for length operator any more in ktap. - * - * Quote from lua mannal: - * 2.5.5 - The Length Operator - * - * The length operator is denoted by the unary operator #. - * The length of a string is its number of bytes(that is, - * the usual meaning of string length when each character is one byte). - * - * The length of a table t is defined to be any integer index n - * such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, - * n can be zero. For a regular array, with non-nil values from 1 to a given n, - * its length is exactly that n, the index of its last value. If the array has - * "holes" (that is, nil values between other non-nil values), then #t can be - * any of the indices that directly precedes a nil value - * (that is, it may consider any such nil value as the end of the array). - */ -int kp_objlen(ktap_state *ks, const ktap_value *v) -{ - switch(v->type) { - case KTAP_TTABLE: - return kp_table_length(ks, hvalue(v)); - case KTAP_TSTRING: - return rawtsvalue(v)->tsv.len; - default: - kp_printf(ks, "cannot get length of type %d\n", v->type); - return -1; - } - return 0; -} - -/* need to protect allgc field? */ -ktap_gcobject *kp_newobject(ktap_state *ks, int type, size_t size, - ktap_gcobject **list) -{ - ktap_gcobject *o; - - o = kp_malloc(ks, size); - if (list == NULL) - list = &G(ks)->allgc; - - gch(o)->tt = type; - gch(o)->next = *list; - *list = o; - - return o; -} - -ktap_upval *kp_newupval(ktap_state *ks) -{ - ktap_upval *uv; - - uv = &kp_newobject(ks, KTAP_TUPVAL, sizeof(ktap_upval), NULL)->uv; - uv->v = &uv->u.value; - setnilvalue(uv->v); - return uv; -} - -static ktap_btrace *kp_newbacktrace(ktap_state *ks, ktap_gcobject **list) -{ - ktap_btrace *bt; - - bt = &kp_newobject(ks, KTAP_TBTRACE, sizeof(ktap_btrace), list)->bt; - return bt; -} - -void kp_objclone(ktap_state *ks, const ktap_value *o, ktap_value *newo, - ktap_gcobject **list) -{ - if (ttisbtrace(o)) { - ktap_btrace *bt; - bt = kp_newbacktrace(ks, list); - bt->nr_entries = btvalue(o)->nr_entries; - memcpy(&bt->entries[0], &btvalue(o)->entries[0], - sizeof(bt->entries)); - setbtvalue(newo, bt); - } else { - kp_error(ks, "cannot clone ktap value type %d\n", ttype(o)); - setnilvalue(newo); - } -} - -ktap_closure *kp_newlclosure(ktap_state *ks, int n) -{ - ktap_closure *cl; - - cl = (ktap_closure *)kp_newobject(ks, KTAP_TLCL, sizeof(*cl), NULL); - cl->l.p = NULL; - cl->l.nupvalues = n; - while (n--) - cl->l.upvals[n] = NULL; - - return cl; -} - -static void free_proto(ktap_state *ks, ktap_proto *f) -{ - kp_free(ks, f->code); - kp_free(ks, f->p); - kp_free(ks, f->k); - kp_free(ks, f->lineinfo); - kp_free(ks, f->locvars); - kp_free(ks, f->upvalues); - kp_free(ks, f); -} - -ktap_proto *kp_newproto(ktap_state *ks) -{ - ktap_proto *f; - f = (ktap_proto *)kp_newobject(ks, KTAP_TPROTO, sizeof(*f), NULL); - f->k = NULL; - f->sizek = 0; - f->p = NULL; - f->sizep = 0; - f->code = NULL; - f->cache = NULL; - f->sizecode = 0; - f->lineinfo = NULL; - f->sizelineinfo = 0; - f->upvalues = NULL; - f->sizeupvalues = 0; - f->numparams = 0; - f->is_vararg = 0; - f->maxstacksize = 0; - f->locvars = NULL; - f->sizelocvars = 0; - f->linedefined = 0; - f->lastlinedefined = 0; - f->source = NULL; - return f; -} - -static ktap_udata *newudata(ktap_state *ks, size_t s) -{ - ktap_udata *u; - - u = &kp_newobject(ks, KTAP_TUSERDATA, sizeof(ktap_udata) + s, NULL)->u; - u->uv.len = s; - return u; -} - -void *kp_newuserdata(ktap_state *ks, size_t size) -{ - ktap_udata *u; - - u = newudata(ks, size); - return u + 1; -} - -void kp_free_gclist(ktap_state *ks, ktap_gcobject *o) -{ - while (o) { - ktap_gcobject *next; - - next = gch(o)->next; - switch (gch(o)->tt) { - case KTAP_TTABLE: - kp_table_free(ks, (ktap_table *)o); - break; - case KTAP_TPROTO: - free_proto(ks, (ktap_proto *)o); - break; -#ifdef __KERNEL__ - case KTAP_TAGGRTABLE: - kp_aggrtable_free(ks, (ktap_aggrtable *)o); - break; -#endif - default: - kp_free(ks, o); - } - o = next; - } -} - -void kp_free_all_gcobject(ktap_state *ks) -{ - kp_free_gclist(ks, G(ks)->allgc); - G(ks)->allgc = NULL; -} - -/******************************************************************************/ - -/* - * make header for precompiled chunks - * if you change the code below be sure to update load_header and FORMAT above - * and KTAPC_HEADERSIZE in ktap_types.h - */ -void kp_header(u8 *h) -{ - int x = 1; - - memcpy(h, KTAP_SIGNATURE, sizeof(KTAP_SIGNATURE) - sizeof(char)); - h += sizeof(KTAP_SIGNATURE) - sizeof(char); - *h++ = (u8)VERSION; - *h++ = (u8)FORMAT; - *h++ = (u8)(*(char*)&x); /* endianness */ - *h++ = (u8)(sizeof(int)); - *h++ = (u8)(sizeof(size_t)); - *h++ = (u8)(sizeof(ktap_instruction)); - *h++ = (u8)(sizeof(ktap_number)); - *h++ = (u8)(((ktap_number)0.5) == 0); /* is ktap_number integral? */ - memcpy(h, KTAPC_TAIL, sizeof(KTAPC_TAIL) - sizeof(char)); -} - - diff --git a/drivers/staging/ktap/interpreter/opcode.c b/drivers/staging/ktap/interpreter/opcode.c deleted file mode 100644 index 2f44855..0000000 --- a/drivers/staging/ktap/interpreter/opcode.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * opcode.c - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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_opcodes.h" - -const char *const ktap_opnames[NUM_OPCODES + 1] = { - "MOVE", - "LOADK", - "LOADKX", - "LOADBOOL", - "LOADNIL", - "GETUPVAL", - "GETTABUP", - "GETTABLE", - "SETTABUP", - "SETTABUP_INCR", - "SETUPVAL", - "SETTABLE", - "SETTABLE_INCR", - "NEWTABLE", - "SELF", - "ADD", - "SUB", - "MUL", - "DIV", - "MOD", - "POW", - "UNM", - "NOT", - "LEN", - "CONCAT", - "JMP", - "EQ", - "LT", - "LE", - "TEST", - "TESTSET", - "CALL", - "TAILCALL", - "RETURN", - "FORLOOP", - "FORPREP", - "TFORCALL", - "TFORLOOP", - "SETLIST", - "CLOSURE", - "VARARG", - "EXTRAARG", - - "EVENT", - "EVENT_NAME", - "EVENT_ARG", /* arg1, arg2 .. arg9 */ - NULL -}; - - -#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) - -const u8 ktap_opmodes[NUM_OPCODES] = { -/* T A B C mode opcode */ - opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ - ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ - ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ - ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ - ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ - ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ - ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ - ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ - ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ - ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ - ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ - ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ - ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ - ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ - ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ - ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ - ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ - ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ - ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ - ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ - ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ - ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ - ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ - ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ - ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ - ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_EVENT */ -}; - - diff --git a/drivers/staging/ktap/interpreter/strfmt.c b/drivers/staging/ktap/interpreter/strfmt.c deleted file mode 100644 index 2c1e761..0000000 --- a/drivers/staging/ktap/interpreter/strfmt.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * strfmt.c - printf implementation - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include "../include/ktap.h" - -/* macro to `unsign' a character */ -#define uchar(c) ((unsigned char)(c)) - -#define L_ESC '%' - -/* valid flags in a format specification */ -#define FLAGS "-+ #0" - -#define INTFRMLEN "ll" -#define INTFRM_T long long - -/* - * maximum size of each format specification (such as '%-099.99d') - * (+10 accounts for %99.99x plus margin of error) - */ -#define MAX_FORMAT (sizeof(FLAGS) + sizeof(INTFRMLEN) + 10) - -static const char *scanformat(ktap_state *ks, const char *strfrmt, char *form) -{ - const char *p = strfrmt; - while (*p != '\0' && strchr(FLAGS, *p) != NULL) - p++; /* skip flags */ - - if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) { - kp_error(ks, "invalid format (repeated flags)\n"); - return NULL; - } - - if (isdigit(uchar(*p))) - p++; /* skip width */ - - if (isdigit(uchar(*p))) - p++; /* (2 digits at most) */ - - if (*p == '.') { - p++; - if (isdigit(uchar(*p))) - p++; /* skip precision */ - if (isdigit(uchar(*p))) - p++; /* (2 digits at most) */ - } - - if (isdigit(uchar(*p))) { - kp_error(ks, "invalid format (width or precision too long)\n"); - return NULL; - } - - *(form++) = '%'; - memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); - form += p - strfrmt + 1; - *form = '\0'; - return p; -} - - -/* - * add length modifier into formats - */ -static void addlenmod(char *form, const char *lenmod) -{ - size_t l = strlen(form); - size_t lm = strlen(lenmod); - char spec = form[l - 1]; - - strcpy(form + l - 1, lenmod); - form[l + lm - 1] = spec; - form[l + lm] = '\0'; -} - - -static void ktap_argerror(ktap_state *ks, int narg, const char *extramsg) -{ - kp_error(ks, "bad argument #%d: (%s)\n", narg, extramsg); -} - -int kp_strfmt(ktap_state *ks, struct trace_seq *seq) -{ - int arg = 1; - size_t sfl; - ktap_value *arg_fmt = kp_arg(ks, 1); - int argnum = kp_arg_nr(ks); - const char *strfrmt, *strfrmt_end; - - strfrmt = svalue(arg_fmt); - sfl = rawtsvalue(arg_fmt)->tsv.len; - strfrmt_end = strfrmt + sfl; - - while (strfrmt < strfrmt_end) { - if (*strfrmt != L_ESC) - trace_seq_putc(seq, *strfrmt++); - else if (*++strfrmt == L_ESC) - trace_seq_putc(seq, *strfrmt++); - else { /* format item */ - char form[MAX_FORMAT]; - - if (++arg > argnum) { - ktap_argerror(ks, arg, "no value"); - return -1; - } - - strfrmt = scanformat(ks, strfrmt, form); - switch (*strfrmt++) { - case 'c': - trace_seq_printf(seq, form, - nvalue(kp_arg(ks, arg))); - break; - case 'd': case 'i': { - ktap_number n = nvalue(kp_arg(ks, arg)); - INTFRM_T ni = (INTFRM_T)n; - addlenmod(form, INTFRMLEN); - trace_seq_printf(seq, form, ni); - break; - } - case 'p': { - char str[KSYM_SYMBOL_LEN]; - SPRINT_SYMBOL(str, nvalue(kp_arg(ks, arg))); - trace_seq_puts(seq, str); - break; - } - case 'o': case 'u': case 'x': case 'X': { - ktap_number n = nvalue(kp_arg(ks, arg)); - unsigned INTFRM_T ni = (unsigned INTFRM_T)n; - addlenmod(form, INTFRMLEN); - trace_seq_printf(seq, form, ni); - break; - } - case 's': { - ktap_value *v = kp_arg(ks, arg); - const char *s; - size_t l; - - if (isnil(v)) { - trace_seq_puts(seq, "nil"); - return 0; - } - - if (ttisevent(v)) { - kp_event_tostring(ks, seq); - return 0; - } - - s = svalue(v); - l = rawtsvalue(v)->tsv.len; - if (!strchr(form, '.') && l >= 100) { - /* - * no precision and string is too long - * to be formatted; - * keep original string - */ - trace_seq_puts(seq, s); - break; - } else { - trace_seq_printf(seq, form, s); - break; - } - } - default: /* also treat cases `pnLlh' */ - kp_error(ks, "invalid option " KTAP_QL("%%%c") - " to " KTAP_QL("format"), - *(strfrmt - 1)); - } - } - } - - return 0; -} - diff --git a/drivers/staging/ktap/interpreter/table.c b/drivers/staging/ktap/interpreter/table.c deleted file mode 100644 index 4e83947..0000000 --- a/drivers/staging/ktap/interpreter/table.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* - * table.c - ktap table data structure manipulation function - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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. - */ - -#ifdef __KERNEL__ -#include "../include/ktap.h" -#include -#include -#include -#else -#include "../include/ktap_types.h" - -static inline void sort(void *base, size_t num, size_t size, - int (*cmp_func)(const void *, const void *), - void (*swap_func)(void *, void *, int size)) -{} -#endif - - -#ifdef __KERNEL__ -#define kp_table_lock_init(t) \ - do { \ - t->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \ - } while (0) -#define kp_table_lock(t) \ - do { \ - local_irq_save(flags); \ - arch_spin_lock(&t->lock); \ - } while (0) -#define kp_table_unlock(t) \ - do { \ - arch_spin_unlock(&t->lock); \ - local_irq_restore(flags); \ - } while (0) - -#else -#define kp_table_lock_init(t) -#define kp_table_lock(t) -#define kp_table_unlock(t) -#endif - -#define MAXBITS 30 -#define MAXASIZE (1 << MAXBITS) - - -#define NILCONSTANT {NULL}, KTAP_TNIL -const struct ktap_value ktap_nilobjectv = {NILCONSTANT}; -#define ktap_nilobject (&ktap_nilobjectv) - -static const ktap_tnode dummynode_ = { - {NILCONSTANT}, /* value */ - {{NILCONSTANT, NULL}}, /* key */ -}; - -#define gnode(t,i) (&(t)->node[i]) -#define gkey(n) (&(n)->i_key.tvk) -#define gval(n) (&(n)->i_val) -#define gnext(n) ((n)->i_key.nk.next) - -#define twoto(x) (1<<(x)) -#define sizenode(t) (twoto((t)->lsizenode)) - -#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) - -#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) - -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) -#define hashboolean(t,p) hashpow2(t, p) -#define hashnum(t, n) hashmod(t, (unsigned int)n) -#define hashpointer(t,p) hashmod(t, (unsigned long)(p)) - -#define dummynode (&dummynode_) -#define isdummy(n) ((n) == dummynode) - -static void table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *v); -static ktap_value *table_set(ktap_state *ks, ktap_table *t, - const ktap_value *key); -static void setnodevector(ktap_state *ks, ktap_table *t, int size); - -static int ceillog2(unsigned int x) -{ - static const u8 log_2[256] = { - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - }; - - int l = 0; - - x--; - while (x >= 256) { l += 8; x >>= 8; } - return l + log_2[x]; -} - - -ktap_table *kp_table_new(ktap_state *ks) -{ - ktap_table *t = &kp_newobject(ks, KTAP_TTABLE, sizeof(ktap_table), - NULL)->h; - t->flags = (u8)(~0); - t->array = NULL; - t->sizearray = 0; - t->node = (ktap_tnode *)dummynode; - t->gclist = NULL; - setnodevector(ks, t, 0); - - kp_table_lock_init(t); - return t; -} - -static const ktap_value *table_getint(ktap_table *t, int key) -{ - ktap_tnode *n; - - if ((unsigned int)(key - 1) < (unsigned int)t->sizearray) - return &t->array[key - 1]; - - n = hashnum(t, key); - do { - if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == key) - return gval(n); - else - n = gnext(n); - } while (n); - - return ktap_nilobject; -} - -const ktap_value *kp_table_getint(ktap_table *t, int key) -{ - const ktap_value *val; - unsigned long __maybe_unused flags; - - kp_table_lock(t); - val = table_getint(t, key); - kp_table_unlock(t); - - return val; -} - -static ktap_tnode *mainposition (const ktap_table *t, const ktap_value *key) -{ - switch (ttype(key)) { - case KTAP_TNUMBER: - return hashnum(t, nvalue(key)); - case KTAP_TLNGSTR: { - ktap_string *s = rawtsvalue(key); - if (s->tsv.extra == 0) { /* no hash? */ - s->tsv.hash = kp_string_hash(getstr(s), s->tsv.len, - s->tsv.hash); - s->tsv.extra = 1; /* now it has its hash */ - } - return hashstr(t, rawtsvalue(key)); - } - case KTAP_TSHRSTR: - return hashstr(t, rawtsvalue(key)); - case KTAP_TBOOLEAN: - return hashboolean(t, bvalue(key)); - case KTAP_TLIGHTUSERDATA: - return hashpointer(t, pvalue(key)); - case KTAP_TLCF: - return hashpointer(t, fvalue(key)); - case KTAP_TBTRACE: - /* use first entry as hash key, cannot use gcvalue as key */ - return hashpointer(t, btvalue(key)->entries[0]); - default: - return hashpointer(t, gcvalue(key)); - } -} - -static int arrayindex(const ktap_value *key) -{ - if (ttisnumber(key)) { - ktap_number n = nvalue(key); - int k = (int)n; - if ((ktap_number)k == n) - return k; - } - - /* `key' did not match some condition */ - return -1; -} - -/* - * returns the index of a `key' for table traversals. First goes all - * elements in the array part, then elements in the hash part. The - * beginning of a traversal is signaled by -1. - */ -static int findindex(ktap_state *ks, ktap_table *t, StkId key) -{ - int i; - - if (ttisnil(key)) - return -1; /* first iteration */ - - i = arrayindex(key); - if (i > 0 && i <= t->sizearray) /* is `key' inside array part? */ - return i - 1; /* yes; that's the index (corrected to C) */ - else { - ktap_tnode *n = mainposition(t, key); - for (;;) { /* check whether `key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in `next' */ - if (kp_equalobjv(ks, gkey(n), key)) { - i = n - gnode(t, 0); /* key index in hash table */ - /* hash elements are numbered after array ones */ - return i + t->sizearray; - } else - n = gnext(n); - - if (n == NULL) - /* key not found */ - kp_error(ks, "invalid table key to next"); - } - } -} - -int kp_table_next(ktap_state *ks, ktap_table *t, StkId key) -{ - unsigned long __maybe_unused flags; - int i; - - kp_table_lock(t); - - i = findindex(ks, t, key); /* find original element */ - - for (i++; i < t->sizearray; i++) { /* try first array part */ - if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setnvalue(key, i+1); - setobj(key+1, &t->array[i]); - kp_table_unlock(t); - return 1; - } - } - - for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj(key, gkey(gnode(t, i))); - setobj(key+1, gval(gnode(t, i))); - kp_table_unlock(t); - return 1; - } - } - - kp_table_unlock(t); - return 0; /* no more elements */ -} - - - -static int computesizes (int nums[], int *narray) -{ - int i; - int twotoi; /* 2^i */ - int a = 0; /* number of elements smaller than 2^i */ - int na = 0; /* number of elements to go to array part */ - int n = 0; /* optimal size for array part */ - - for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { - if (nums[i] > 0) { - a += nums[i]; - /* more than half elements present? */ - if (a > twotoi/2) { - /* optimal size (till now) */ - n = twotoi; - /* - * all elements smaller than n will go to - * array part - */ - na = a; - } - } - if (a == *narray) - break; /* all elements already counted */ - } - *narray = n; - return na; -} - - -static int countint(const ktap_value *key, int *nums) -{ - int k = arrayindex(key); - - /* is `key' an appropriate array index? */ - if (0 < k && k <= MAXASIZE) { - nums[ceillog2(k)]++; /* count as such */ - return 1; - } else - return 0; -} - - -static int numusearray(const ktap_table *t, int *nums) -{ - int lg; - int ttlg; /* 2^lg */ - int ause = 0; /* summation of `nums' */ - int i = 1; /* count to traverse all array keys */ - - /* for each slice */ - for (lg=0, ttlg=1; lg <= MAXBITS; lg++, ttlg *= 2) { - int lc = 0; /* counter */ - int lim = ttlg; - - if (lim > t->sizearray) { - lim = t->sizearray; /* adjust upper limit */ - if (i > lim) - break; /* no more elements to count */ - } - - /* count elements in range (2^(lg-1), 2^lg] */ - for (; i <= lim; i++) { - if (!ttisnil(&t->array[i-1])) - lc++; - } - nums[lg] += lc; - ause += lc; - } - return ause; -} - -static int numusehash(const ktap_table *t, int *nums, int *pnasize) -{ - int totaluse = 0; /* total number of elements */ - int ause = 0; /* summation of `nums' */ - int i = sizenode(t); - - while (i--) { - ktap_tnode *n = &t->node[i]; - if (!isnil(gval(n))) { - ause += countint(gkey(n), nums); - totaluse++; - } - } - - *pnasize += ause; - return totaluse; -} - - -static void setarrayvector(ktap_state *ks, ktap_table *t, int size) -{ - int i; - - kp_realloc(ks, t->array, t->sizearray, size, ktap_value); - for (i = t->sizearray; i < size; i++) - setnilvalue(&t->array[i]); - - t->sizearray = size; -} - -static void setnodevector(ktap_state *ks, ktap_table *t, int size) -{ - int lsize; - - if (size == 0) { /* no elements to hash part? */ - t->node = (ktap_tnode *)dummynode; /* use common `dummynode' */ - lsize = 0; - } else { - int i; - lsize = ceillog2(size); - if (lsize > MAXBITS) { - kp_error(ks, "table overflow\n"); - return; - } - - size = twoto(lsize); - t->node = kp_malloc(ks, size * sizeof(ktap_tnode)); - for (i = 0; i < size; i++) { - ktap_tnode *n = gnode(t, i); - gnext(n) = NULL; - setnilvalue(gkey(n)); - setnilvalue(gval(n)); - } - } - - t->lsizenode = (u8)lsize; - t->lastfree = gnode(t, size); /* all positions are free */ -} - -static void table_resize(ktap_state *ks, ktap_table *t, int nasize, int nhsize) -{ - int i; - int oldasize = t->sizearray; - int oldhsize = t->lsizenode; - ktap_tnode *nold = t->node; /* save old hash ... */ - -#ifdef __KERNEL__ - kp_verbose_printf(ks, "table resize, nasize: %d, nhsize: %d\n", - nasize, nhsize); -#endif - - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(ks, t, nasize); - - /* create new hash part with appropriate size */ - setnodevector(ks, t, nhsize); - - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; iarray[i])) - table_setint(ks, t, i + 1, &t->array[i]); - } - - /* shrink array */ - kp_realloc(ks, t->array, oldasize, nasize, ktap_value); - } - - /* re-insert elements from hash part */ - for (i = twoto(oldhsize) - 1; i >= 0; i--) { - ktap_tnode *old = nold+i; - if (!ttisnil(gval(old))) { - /* - * doesn't need barrier/invalidate cache, as entry was - * already present in the table - */ - setobj(table_set(ks, t, gkey(old)), gval(old)); - } - } - - if (!isdummy(nold)) - kp_free(ks, nold); /* free old array */ -} - -void kp_table_resize(ktap_state *ks, ktap_table *t, int nasize, int nhsize) -{ - unsigned long __maybe_unused flags; - - kp_table_lock(t); - table_resize(ks, t, nasize, nhsize); - kp_table_unlock(t); -} - -void kp_table_resizearray(ktap_state *ks, ktap_table *t, int nasize) -{ - unsigned long __maybe_unused flags; - int nsize; - - kp_table_lock(t); - - nsize = isdummy(t->node) ? 0 : sizenode(t); - table_resize(ks, t, nasize, nsize); - - kp_table_unlock(t); -} - -static void rehash(ktap_state *ks, ktap_table *t, const ktap_value *ek) -{ - int nasize, na; - /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */ - int nums[MAXBITS+1]; - int i; - int totaluse; - - for (i = 0; i <= MAXBITS; i++) - nums[i] = 0; /* reset counts */ - - nasize = numusearray(t, nums); /* count keys in array part */ - totaluse = nasize; /* all those keys are integer keys */ - totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ - /* count extra key */ - nasize += countint(ek, nums); - totaluse++; - /* compute new size for array part */ - na = computesizes(nums, &nasize); - /* resize the table to new computed sizes */ - table_resize(ks, t, nasize, totaluse - na); -} - - -static ktap_tnode *getfreepos(ktap_table *t) -{ - while (t->lastfree > t->node) { - t->lastfree--; - if (isnil(gkey(t->lastfree))) - return t->lastfree; - } - return NULL; /* could not find a free place */ -} - - -static ktap_value *table_newkey(ktap_state *ks, ktap_table *t, - const ktap_value *key) -{ - ktap_tnode *mp; - ktap_value newkey; - - mp = mainposition(t, key); - if (!isnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ - ktap_tnode *othern; - ktap_tnode *n = getfreepos(t); /* get a free place */ - if (n == NULL) { /* cannot find a free place? */ - rehash(ks, t, key); /* grow table */ - /* whatever called 'newkey' take care of TM cache and GC barrier */ - return table_set(ks, t, key); /* insert key into grown table */ - } - - othern = mainposition(t, gkey(mp)); - if (othern != mp) { /* is colliding node out of its main position? */ - /* yes; move colliding node into free position */ - while (gnext(othern) != mp) - othern = gnext(othern); /* find previous */ - gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ - *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - gnext(mp) = NULL; /* now `mp' is free */ - setnilvalue(gval(mp)); - } else { /* colliding node is in its own main position */ - /* new node will go into free position */ - gnext(n) = gnext(mp); /* chain new position */ - gnext(mp) = n; - mp = n; - } - } - - /* special handling for cloneable object, maily for btrace object */ - if (ttisclone(key)) - kp_objclone(ks, key, &newkey, &t->gclist); - else - newkey = *key; - - setobj(gkey(mp), &newkey); - return gval(mp); -} - - -/* - * search function for short strings - */ -static const ktap_value *table_getstr(ktap_table *t, ktap_string *key) -{ - ktap_tnode *n = hashstr(t, key); - - do { /* check whether `key' is somewhere in the chain */ - if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), - key)) - return gval(n); /* that's it */ - else - n = gnext(n); - } while (n); - - return ktap_nilobject; -} - - -/* - * main search function - */ -static const ktap_value *table_get(ktap_table *t, const ktap_value *key) -{ - switch (ttype(key)) { - case KTAP_TNIL: - return ktap_nilobject; - case KTAP_TSHRSTR: - return table_getstr(t, rawtsvalue(key)); - case KTAP_TNUMBER: { - ktap_number n = nvalue(key); - int k = (int)n; - if ((ktap_number)k == nvalue(key)) /* index is int? */ - return table_getint(t, k); /* use specialized version */ - /* else go through */ - } - default: { - ktap_tnode *n = mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (rawequalobj(gkey(n), key)) - return gval(n); /* that's it */ - else - n = gnext(n); - } while (n); - - return ktap_nilobject; - } - } -} - -const ktap_value *kp_table_get(ktap_table *t, const ktap_value *key) -{ - const ktap_value *val; - unsigned long __maybe_unused flags; - - kp_table_lock(t); - val = table_get(t, key); - kp_table_unlock(t); - - return val; -} - -static ktap_value *table_set(ktap_state *ks, ktap_table *t, - const ktap_value *key) -{ - const ktap_value *p = table_get(t, key); - - if (p != ktap_nilobject) - return (ktap_value *)p; - else - return table_newkey(ks, t, key); -} - -void kp_table_setvalue(ktap_state *ks, ktap_table *t, - const ktap_value *key, ktap_value *val) -{ - unsigned long __maybe_unused flags; - - if (isnil(key)) { - kp_printf(ks, "table index is nil\n"); - kp_exit(ks); - return; - } - - kp_table_lock(t); - setobj(table_set(ks, t, key), val); - kp_table_unlock(t); -} - -static void table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *v) -{ - const ktap_value *p; - ktap_value *cell; - - p = table_getint(t, key); - - if (p != ktap_nilobject) - cell = (ktap_value *)p; - else { - ktap_value k; - setnvalue(&k, key); - cell = table_newkey(ks, t, &k); - } - - setobj(cell, v); -} - -void kp_table_setint(ktap_state *ks, ktap_table *t, int key, ktap_value *val) -{ - unsigned long __maybe_unused flags; - - kp_table_lock(t); - table_setint(ks, t, key, val); - kp_table_unlock(t); -} - -void kp_table_atomic_inc(ktap_state *ks, ktap_table *t, ktap_value *key, int n) -{ - unsigned long __maybe_unused flags; - ktap_value *v; - - if (isnil(key)) { - kp_printf(ks, "table index is nil\n"); - kp_exit(ks); - return; - } - - kp_table_lock(t); - - v = table_set(ks, t, key); - if (isnil(v)) { - setnvalue(v, n); - } else - setnvalue(v, nvalue(v) + n); - - kp_table_unlock(t); -} - -int kp_table_length(ktap_state *ks, ktap_table *t) -{ - unsigned long __maybe_unused flags; - int i, len = 0; - - kp_table_lock(t); - - for (i = 0; i < t->sizearray; i++) { - ktap_value *v = &t->array[i]; - - if (isnil(v)) - continue; - len++; - } - - for (i = 0; i < sizenode(t); i++) { - ktap_tnode *n = &t->node[i]; - - if (isnil(gkey(n))) - continue; - - len++; - } - - kp_table_unlock(t); - return len; -} - -void kp_table_free(ktap_state *ks, ktap_table *t) -{ - if (t->sizearray > 0) - kp_free(ks, t->array); - if (!isdummy(t->node)) - kp_free(ks, t->node); - - kp_free_gclist(ks, t->gclist); - kp_free(ks, t); -} - -void kp_table_dump(ktap_state *ks, ktap_table *t) -{ - int i, count = 0; - - kp_puts(ks, "{"); - for (i = 0; i < t->sizearray; i++) { - ktap_value *v = &t->array[i]; - - if (isnil(v)) - continue; - - if (count) - kp_puts(ks, ", "); - - kp_printf(ks, "(%d: ", i + 1); - kp_showobj(ks, v); - kp_puts(ks, ")"); - count++; - } - - for (i = 0; i < sizenode(t); i++) { - ktap_tnode *n = &t->node[i]; - - if (isnil(gkey(n))) - continue; - - if (count) - kp_puts(ks, ", "); - - kp_puts(ks, "("); - kp_showobj(ks, gkey(n)); - kp_puts(ks, ": "); - kp_showobj(ks, gval(n)); - kp_puts(ks, ")"); - count++; - } - kp_puts(ks, "}"); -} - -/* - * table-clear only set nil of all elements, not free t->array and nodes. - * we assume user will reuse table soon after clear table, so reserve array - * and nodes will avoid memory allocation when insert key-value again. - */ -void kp_table_clear(ktap_state *ks, ktap_table *t) -{ - unsigned long __maybe_unused flags; - int i; - - kp_table_lock(t); - - for (i = 0; i < t->sizearray; i++) { - ktap_value *v = &t->array[i]; - - if (isnil(v)) - continue; - - setnilvalue(v); - } - - for (i = 0; i < sizenode(t); i++) { - ktap_tnode *n = &t->node[i]; - - if (isnil(gkey(n))) - continue; - - setnilvalue(gkey(n)); - setnilvalue(gval(n)); - } - - kp_table_unlock(t); -} - -#ifdef __KERNEL__ -static void string_convert(char *output, const char *input) -{ - if (strlen(input) > 32) { - strncpy(output, input, 32-4); - memset(output + 32-4, '.', 3); - } else - memcpy(output, input, strlen(input)); -} - -struct table_hist_record { - ktap_value key; - ktap_value val; -}; - -static int hist_record_cmp(const void *r1, const void *r2) -{ - const struct table_hist_record *i = r1; - const struct table_hist_record *j = r2; - - if ((nvalue(&i->val) == nvalue(&j->val))) { - return 0; - } else if ((nvalue(&i->val) < nvalue(&j->val))) { - return 1; - } else - return -1; -} - -static int kp_aggracc_read(ktap_aggraccval *acc); - -/* histogram: key should be number or string, value must be number */ -static void table_histdump(ktap_state *ks, ktap_table *t, int shownums) -{ - struct table_hist_record *thr; - unsigned long __maybe_unused flags; - char dist_str[40]; - int i, ratio, total = 0, count = 0, top_num, is_kernel_address = 0; - int size, num; - - size = sizeof(*thr) * (t->sizearray + sizenode(t)); - thr = kp_malloc(ks, size); - if (!thr) { - kp_error(ks, "Cannot allocate %d of histogram memory", size); - return; - } - - kp_table_lock(t); - - for (i = 0; i < t->sizearray; i++) { - ktap_value *v = &t->array[i]; - - if (isnil(v)) - continue; - - if (ttisnumber(v)) - num = nvalue(v); - else if (ttisaggracc(v)) - num = kp_aggracc_read(aggraccvalue(v)); - else { - kp_table_unlock(t); - goto error; - } - - setnvalue(&thr[count].key, i + 1); - setnvalue(&thr[count].val, num); - count++; - total += num; - } - - for (i = 0; i < sizenode(t); i++) { - ktap_tnode *n = &t->node[i]; - ktap_value *v = gval(n); - - if (isnil(gkey(n))) - continue; - - if (ttisnumber(v)) - num = nvalue(v); - else if (ttisaggracc(v)) - num = kp_aggracc_read(aggraccvalue(v)); - else { - kp_table_unlock(t); - goto error; - } - - setobj(&thr[count].key, gkey(n)); - setnvalue(&thr[count].val, num); - count++; - total += num; - } - - kp_table_unlock(t); - - sort(thr, count, sizeof(struct table_hist_record), - hist_record_cmp, NULL); - - dist_str[sizeof(dist_str) - 1] = '\0'; - - /* check the first key is a kernel text symbol or not */ - if (ttisnumber(&thr[0].key)) { - char str[KSYM_SYMBOL_LEN]; - - SPRINT_SYMBOL(str, nvalue(&thr[0].key)); - if (str[0] != '0' || str[1] != 'x') - is_kernel_address = 1; - } - - top_num = min(shownums, count); - for (i = 0; i < top_num; i++) { - ktap_value *key = &thr[i].key; - ktap_value *val = &thr[i].val; - - memset(dist_str, ' ', sizeof(dist_str) - 1); - ratio = (nvalue(val) * (sizeof(dist_str) - 1)) / total; - memset(dist_str, '@', ratio); - - if (ttisstring(key)) { - char buf[32 + 1] = {0}; - - string_convert(buf, svalue(key)); - kp_printf(ks, "%32s |%s%-7d\n", buf, dist_str, - nvalue(val)); - } else if (ttisnumber(key)) { - char str[KSYM_SYMBOL_LEN]; - char buf[32 + 1] = {0}; - - if (is_kernel_address) { - /* suppose it's a symbol, fix it in future */ - SPRINT_SYMBOL(str, nvalue(key)); - string_convert(buf, str); - kp_printf(ks, "%32s |%s%-7d\n", buf, dist_str, - nvalue(val)); - } else { - kp_printf(ks, "%32d |%s%-7d\n", nvalue(key), - dist_str, nvalue(val)); - } - } - } - - if (count > shownums) - kp_printf(ks, "%32s |\n", "..."); - - goto out; - - error: - kp_puts(ks, "error: table histogram only handle " - " (key: string/number val: number)\n"); - out: - kp_free(ks, thr); -} - -#define HISTOGRAM_DEFAULT_TOP_NUM 20 - -#define DISTRIBUTION_STR "------------- Distribution -------------" -void kp_table_histogram(ktap_state *ks, ktap_table *t) -{ - kp_printf(ks, "%32s%s%s\n", "value ", DISTRIBUTION_STR, " count"); - table_histdump(ks, t, HISTOGRAM_DEFAULT_TOP_NUM); -} - -/* - * Aggregation Table - */ - -static ktap_table *table_new2(ktap_state *ks, ktap_gcobject **list) -{ - ktap_table *t = &kp_newobject(ks, KTAP_TTABLE, sizeof(ktap_table), - list)->h; - t->flags = (u8)(~0); - t->array = NULL; - t->sizearray = 0; - t->node = (ktap_tnode *)dummynode; - t->gclist = NULL; - setnodevector(ks, t, 0); - - kp_table_lock_init(t); - return t; -} - -static int kp_aggracc_read(ktap_aggraccval *acc) -{ - switch (acc->type) { - case AGGREGATION_TYPE_COUNT: - case AGGREGATION_TYPE_MAX: - case AGGREGATION_TYPE_MIN: - case AGGREGATION_TYPE_SUM: - return acc->val; - case AGGREGATION_TYPE_AVG: - return acc->val / acc->more; - default: - return 0; - } - -} - -void kp_aggraccval_dump(ktap_state *ks, ktap_aggraccval *acc) -{ - switch (acc->type) { - case AGGREGATION_TYPE_COUNT: - case AGGREGATION_TYPE_MAX: - case AGGREGATION_TYPE_MIN: - case AGGREGATION_TYPE_SUM: - kp_printf(ks, "%d", acc->val); - break; - case AGGREGATION_TYPE_AVG: - kp_printf(ks, "%d", acc->val / acc->more); - break; - default: - break; - } -} - -static void synth_acc(ktap_aggraccval *acc1, ktap_aggraccval *acc2) -{ - switch (acc1->type) { - case AGGREGATION_TYPE_COUNT: - acc2->val += acc1->val; - break; - case AGGREGATION_TYPE_MAX: - acc2->val = max(acc1->val, acc2->val); - break; - case AGGREGATION_TYPE_MIN: - acc2->val = min(acc1->val, acc2->val); - break; - case AGGREGATION_TYPE_SUM: - acc2->val += acc1->val; - break; - case AGGREGATION_TYPE_AVG: - acc2->val += acc1->val; - acc2->more += acc1->more; - break; - default: - break; - } -} - -static ktap_aggraccval *get_accval(ktap_state *ks, int type, - ktap_gcobject **list) -{ - ktap_aggraccval *acc; - - acc = &kp_newobject(ks, KTAP_TAGGRACCVAL, sizeof(ktap_aggraccval), - list)->acc; - acc->type = type; - acc->val = 0; - acc->more = 0; - return acc; -} - -static void synth_accval(ktap_state *ks, ktap_value *o1, ktap_value *o2, - ktap_gcobject **list) -{ - ktap_aggraccval *acc; - - if (isnil(o2)) { - acc = get_accval(ks, aggraccvalue(o1)->type, list); - acc->val = aggraccvalue(o1)->val; - acc->more = aggraccvalue(o1)->more; - setaggraccvalue(o2, acc); - return; - } - - synth_acc(aggraccvalue(o1), aggraccvalue(o2)); -} - -static void move_table(ktap_state *ks, ktap_table *t1, ktap_table *t2) -{ - ktap_value *newv; - ktap_value n; - int i; - - for (i = 0; i < t1->sizearray; i++) { - ktap_value *v = &t1->array[i]; - - if (isnil(v)) - continue; - - setnvalue(&n, i); - - newv = table_set(ks, t2, &n); - synth_accval(ks, v, newv, &t2->gclist); - } - - for (i = 0; i < sizenode(t1); i++) { - ktap_tnode *node = &t1->node[i]; - - if (isnil(gkey(node))) - continue; - - newv = table_set(ks, t2, gkey(node)); - synth_accval(ks, gval(node), newv, &t2->gclist); - } -} - -ktap_table *kp_aggrtable_synthesis(ktap_state *ks, ktap_aggrtable *ah) -{ - ktap_table *synth_tbl; - int cpu; - - synth_tbl = table_new2(ks, &ah->gclist); - - for_each_possible_cpu(cpu) { - ktap_table **t = per_cpu_ptr(ah->pcpu_tbl, cpu); - move_table(ks, *t, synth_tbl); - } - - return synth_tbl; -} - -void kp_aggrtable_dump(ktap_state *ks, ktap_aggrtable *ah) -{ - kp_table_dump(ks, kp_aggrtable_synthesis(ks, ah)); -} - -ktap_aggrtable *kp_aggrtable_new(ktap_state *ks) -{ - ktap_aggrtable *ah; - int cpu; - - ah = &kp_newobject(ks, KTAP_TAGGRTABLE, sizeof(ktap_aggrtable), - NULL)->ah; - ah->pcpu_tbl = alloc_percpu(ktap_table *); - ah->gclist = NULL; - - for_each_possible_cpu(cpu) { - ktap_table **t = per_cpu_ptr(ah->pcpu_tbl, cpu); - *t = table_new2(ks, &ah->gclist); - } - - return ah; -} - -void kp_aggrtable_free(ktap_state *ks, ktap_aggrtable *ah) -{ - free_percpu(ah->pcpu_tbl); - kp_free_gclist(ks, ah->gclist); - kp_free(ks, ah); -} - -static -void handle_aggr_count(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) -{ - ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); - ktap_value *v = table_set(ks, t, key); - ktap_aggraccval *acc; - - if (isnil(v)) { - acc = get_accval(ks, AGGREGATION_TYPE_COUNT, &t->gclist); - acc->val = 1; - setaggraccvalue(v, acc); - return; - } - - acc = aggraccvalue(v); - acc->val += 1; -} - -static -void handle_aggr_max(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) -{ - ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); - ktap_value *v = table_set(ks, t, key); - ktap_aggraccval *acc; - - if (isnil(v)) { - acc = get_accval(ks, AGGREGATION_TYPE_MAX, &t->gclist); - acc->val = ks->aggr_accval; - setaggraccvalue(v, acc); - return; - } - - acc = aggraccvalue(v); - acc->val = max(acc->val, ks->aggr_accval); -} - -static -void handle_aggr_min(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) -{ - ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); - ktap_value *v = table_set(ks, t, key); - ktap_aggraccval *acc; - - if (isnil(v)) { - acc = get_accval(ks, AGGREGATION_TYPE_MIN, &t->gclist); - acc->val = ks->aggr_accval; - setaggraccvalue(v, acc); - return; - } - - acc = aggraccvalue(v); - acc->val = min(acc->val, ks->aggr_accval); -} - -static -void handle_aggr_sum(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) -{ - ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); - ktap_value *v = table_set(ks, t, key); - ktap_aggraccval *acc; - - if (isnil(v)) { - acc = get_accval(ks, AGGREGATION_TYPE_SUM, &t->gclist); - acc->val = ks->aggr_accval; - setaggraccvalue(v, acc); - return; - } - - acc = aggraccvalue(v); - acc->val += ks->aggr_accval; -} - -static -void handle_aggr_avg(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key) -{ - ktap_table *t = *__this_cpu_ptr(ah->pcpu_tbl); - ktap_value *v = table_set(ks, t, key); - ktap_aggraccval *acc; - - if (isnil(v)) { - acc = get_accval(ks, AGGREGATION_TYPE_AVG, &t->gclist); - acc->val = ks->aggr_accval; - acc->more = 1; - setaggraccvalue(v, acc); - return; - } - - acc = aggraccvalue(v); - acc->val += ks->aggr_accval; - acc->more++; -} - -typedef void (*aggr_func_t)(ktap_state *ks, ktap_aggrtable *ah, ktap_value *k); -static aggr_func_t kp_aggregation_handler[] = { - handle_aggr_count, - handle_aggr_max, - handle_aggr_min, - handle_aggr_sum, - handle_aggr_avg -}; - -void kp_aggrtable_set(ktap_state *ks, ktap_aggrtable *ah, - ktap_value *key, ktap_value *val) -{ - if (unlikely(!ttisaggrval(val))) { - kp_error(ks, "set invalid value to aggregation table\n"); - return; - } - - kp_aggregation_handler[nvalue(val)](ks, ah, key); -} - - -void kp_aggrtable_get(ktap_state *ks, ktap_aggrtable *ah, ktap_value *key, - ktap_value *val) -{ - ktap_aggraccval acc; /* in stack */ - const ktap_value *v; - int cpu; - - acc.val = -1; - acc.more = -1; - - for_each_possible_cpu(cpu) { - ktap_table **t = per_cpu_ptr(ah->pcpu_tbl, cpu); - - v = table_get(*t, key); - if (isnil(v)) - continue; - - if (acc.more == -1) { - acc = *aggraccvalue(v); - continue; - } - - synth_acc(aggraccvalue(v), &acc); - } - - if (acc.more == -1) { - setnilvalue(val); - } else { - setnvalue(val, kp_aggracc_read(&acc)); - } -} - -void kp_aggrtable_histogram(ktap_state *ks, ktap_aggrtable *ah) -{ - kp_table_histogram(ks, kp_aggrtable_synthesis(ks, ah)); -} -#endif diff --git a/drivers/staging/ktap/interpreter/transport.c b/drivers/staging/ktap/interpreter/transport.c deleted file mode 100644 index 4cd3662..0000000 --- a/drivers/staging/ktap/interpreter/transport.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * transport.c - ktap transport functionality - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include -#include "../include/ktap.h" - -struct ktap_trace_iterator { - struct ring_buffer *buffer; - int print_timestamp; - void *private; - - struct trace_iterator iter; -}; - -enum ktap_trace_type { - __TRACE_FIRST_TYPE = 0, - - TRACE_FN = 1, /* must be same as ftrace definition in kernel */ - TRACE_PRINT, - TRACE_BPUTS, - TRACE_STACK, - TRACE_USER_STACK, - - __TRACE_LAST_TYPE, -}; - -#define KTAP_TRACE_ITER(iter) \ - container_of(iter, struct ktap_trace_iterator, iter) - -ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) -{ - int len; - int ret; - - if (!cnt) - return 0; - - if (s->len <= s->readpos) - return -EBUSY; - - len = s->len - s->readpos; - if (cnt > len) - cnt = len; - ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); - if (ret == cnt) - return -EFAULT; - - cnt -= ret; - - s->readpos += cnt; - return cnt; -} - -int trace_seq_puts(struct trace_seq *s, const char *str) -{ - int len = strlen(str); - - if (s->full) - return 0; - - if (len > ((PAGE_SIZE - 1) - s->len)) { - s->full = 1; - return 0; - } - - memcpy(s->buffer + s->len, str, len); - s->len += len; - - return len; -} - -static int trace_empty(struct trace_iterator *iter) -{ - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - int cpu; - - for_each_online_cpu(cpu) { - if (!ring_buffer_empty_cpu(ktap_iter->buffer, cpu)) - return 0; - } - - return 1; -} - -static void trace_consume(struct trace_iterator *iter) -{ - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - - ring_buffer_consume(ktap_iter->buffer, iter->cpu, &iter->ts, - &iter->lost_events); -} - -unsigned long long ns2usecs(cycle_t nsec) -{ - nsec += 500; - do_div(nsec, 1000); - return nsec; -} - -static int trace_print_timestamp(struct trace_iterator *iter) -{ - struct trace_seq *s = &iter->seq; - unsigned long long t; - unsigned long secs, usec_rem; - - t = ns2usecs(iter->ts); - usec_rem = do_div(t, USEC_PER_SEC); - secs = (unsigned long)t; - - return trace_seq_printf(s, "%5lu.%06lu: ", secs, usec_rem); -} - -/* todo: export kernel function ftrace_find_event in future, and make faster */ -static struct trace_event *(*ftrace_find_event)(int type); - -static enum print_line_t print_trace_fmt(struct trace_iterator *iter) -{ - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - struct trace_entry *entry = iter->ent; - struct trace_event *ev; - - ev = ftrace_find_event(entry->type); - - if (ktap_iter->print_timestamp && !trace_print_timestamp(iter)) - return TRACE_TYPE_PARTIAL_LINE; - - if (ev) { - int ret = ev->funcs->trace(iter, 0, ev); - - /* overwrite '\n' at the ending */ - iter->seq.buffer[iter->seq.len - 1] = '\0'; - iter->seq.len--; - return ret; - } - - return TRACE_TYPE_PARTIAL_LINE; -} - -static enum print_line_t print_trace_stack(struct trace_iterator *iter) -{ - struct trace_entry *entry = iter->ent; - struct stack_trace trace; - char str[KSYM_SYMBOL_LEN]; - int i; - - trace.entries = (unsigned long *)(entry + 1); - trace.nr_entries = (iter->ent_size - sizeof(*entry)) / - sizeof(unsigned long); - - if (!trace_seq_puts(&iter->seq, "\n")) - return TRACE_TYPE_PARTIAL_LINE; - - for (i = 0; i < trace.nr_entries; i++) { - unsigned long p = trace.entries[i]; - - if (p == ULONG_MAX) - break; - - sprint_symbol(str, p); - if (!trace_seq_printf(&iter->seq, " => %s\n", str)) - return TRACE_TYPE_PARTIAL_LINE; - } - - return TRACE_TYPE_HANDLED; -} - -struct ktap_ftrace_entry { - struct trace_entry entry; - unsigned long ip; - unsigned long parent_ip; -}; - -static enum print_line_t print_trace_fn(struct trace_iterator *iter) -{ - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - struct ktap_ftrace_entry *field = (struct ktap_ftrace_entry *)iter->ent; - char str[KSYM_SYMBOL_LEN]; - - if (ktap_iter->print_timestamp && !trace_print_timestamp(iter)) - return TRACE_TYPE_PARTIAL_LINE; - - sprint_symbol(str, field->ip); - if (!trace_seq_puts(&iter->seq, str)) - return TRACE_TYPE_PARTIAL_LINE; - - if (!trace_seq_puts(&iter->seq, " <- ")) - return TRACE_TYPE_PARTIAL_LINE; - - sprint_symbol(str, field->parent_ip); - if (!trace_seq_puts(&iter->seq, str)) - return TRACE_TYPE_PARTIAL_LINE; - - return TRACE_TYPE_HANDLED; -} - -static enum print_line_t print_trace_bputs(struct trace_iterator *iter) -{ - if (!trace_seq_puts(&iter->seq, - (const char *)(*(unsigned long *)(iter->ent + 1)))) - return TRACE_TYPE_PARTIAL_LINE; - - return TRACE_TYPE_HANDLED; -} - -static enum print_line_t print_trace_line(struct trace_iterator *iter) -{ - struct trace_entry *entry = iter->ent; - char *str = (char *)(entry + 1); - - if (entry->type == TRACE_PRINT) { - if (!trace_seq_printf(&iter->seq, "%s", str)) - return TRACE_TYPE_PARTIAL_LINE; - - return TRACE_TYPE_HANDLED; - } - - if (entry->type == TRACE_BPUTS) - return print_trace_bputs(iter); - - if (entry->type == TRACE_STACK) - return print_trace_stack(iter); - - if (entry->type == TRACE_FN) - return print_trace_fn(iter); - - return print_trace_fmt(iter); -} - -static struct trace_entry * -peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts, - unsigned long *lost_events) -{ - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - struct ring_buffer_event *event; - - event = ring_buffer_peek(ktap_iter->buffer, cpu, ts, lost_events); - if (event) { - iter->ent_size = ring_buffer_event_length(event); - return ring_buffer_event_data(event); - } - - return NULL; -} - -static struct trace_entry * -__find_next_entry(struct trace_iterator *iter, int *ent_cpu, - unsigned long *missing_events, u64 *ent_ts) -{ - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - struct ring_buffer *buffer = ktap_iter->buffer; - struct trace_entry *ent, *next = NULL; - unsigned long lost_events = 0, next_lost = 0; - u64 next_ts = 0, ts; - int next_cpu = -1; - int next_size = 0; - int cpu; - - for_each_online_cpu(cpu) { - if (ring_buffer_empty_cpu(buffer, cpu)) - continue; - - ent = peek_next_entry(iter, cpu, &ts, &lost_events); - /* - * Pick the entry with the smallest timestamp: - */ - if (ent && (!next || ts < next_ts)) { - next = ent; - next_cpu = cpu; - next_ts = ts; - next_lost = lost_events; - next_size = iter->ent_size; - } - } - - iter->ent_size = next_size; - - if (ent_cpu) - *ent_cpu = next_cpu; - - if (ent_ts) - *ent_ts = next_ts; - - if (missing_events) - *missing_events = next_lost; - - return next; -} - -/* Find the next real entry, and increment the iterator to the next entry */ -static void *trace_find_next_entry_inc(struct trace_iterator *iter) -{ - iter->ent = __find_next_entry(iter, &iter->cpu, - &iter->lost_events, &iter->ts); - if (iter->ent) - iter->idx++; - - return iter->ent ? iter : NULL; -} - -static void poll_wait_pipe(void) -{ - set_current_state(TASK_INTERRUPTIBLE); - /* sleep for 100 msecs, and try again. */ - schedule_timeout(HZ / 10); -} - -static int tracing_wait_pipe(struct file *filp) -{ - struct trace_iterator *iter = filp->private_data; - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - ktap_state *ks = ktap_iter->private; - - while (trace_empty(iter)) { - - if ((filp->f_flags & O_NONBLOCK)) { - return -EAGAIN; - } - - mutex_unlock(&iter->mutex); - - poll_wait_pipe(); - - mutex_lock(&iter->mutex); - - if (G(ks)->wait_user && trace_empty(iter)) - return -EINTR; - } - - return 1; -} - -static ssize_t -tracing_read_pipe(struct file *filp, char __user *ubuf, size_t cnt, - loff_t *ppos) -{ - struct trace_iterator *iter = filp->private_data; - ssize_t sret; - - /* return any leftover data */ - sret = trace_seq_to_user(&iter->seq, ubuf, cnt); - if (sret != -EBUSY) - return sret; - /* - * Avoid more than one consumer on a single file descriptor - * This is just a matter of traces coherency, the ring buffer itself - * is protected. - */ - mutex_lock(&iter->mutex); - -waitagain: - sret = tracing_wait_pipe(filp); - if (sret <= 0) - goto out; - - /* stop when tracing is finished */ - if (trace_empty(iter)) { - sret = 0; - goto out; - } - - if (cnt >= PAGE_SIZE) - cnt = PAGE_SIZE - 1; - - /* reset all but tr, trace, and overruns */ - memset(&iter->seq, 0, - sizeof(struct trace_iterator) - - offsetof(struct trace_iterator, seq)); - iter->pos = -1; - - while (trace_find_next_entry_inc(iter) != NULL) { - enum print_line_t ret; - int len = iter->seq.len; - - ret = print_trace_line(iter); - if (ret == TRACE_TYPE_PARTIAL_LINE) { - /* don't print partial lines */ - iter->seq.len = len; - break; - } - if (ret != TRACE_TYPE_NO_CONSUME) - trace_consume(iter); - - if (iter->seq.len >= cnt) - break; - - /* - * Setting the full flag means we reached the trace_seq buffer - * size and we should leave by partial output condition above. - * One of the trace_seq_* functions is not used properly. - */ - WARN_ONCE(iter->seq.full, "full flag set for trace type %d", - iter->ent->type); - } - - /* Now copy what we have to the user */ - sret = trace_seq_to_user(&iter->seq, ubuf, cnt); - if (iter->seq.readpos >= iter->seq.len) - trace_seq_init(&iter->seq); - - /* - * If there was nothing to send to user, in spite of consuming trace - * entries, go back to wait for more entries. - */ - if (sret == -EBUSY) - goto waitagain; - -out: - mutex_unlock(&iter->mutex); - - return sret; -} - -static int tracing_open_pipe(struct inode *inode, struct file *filp) -{ - struct ktap_trace_iterator *ktap_iter; - ktap_state *ks = inode->i_private; - - /* create a buffer to store the information to pass to userspace */ - ktap_iter = kzalloc(sizeof(*ktap_iter), GFP_KERNEL); - if (!ktap_iter) - return -ENOMEM; - - ktap_iter->private = ks; - ktap_iter->buffer = G(ks)->buffer; - ktap_iter->print_timestamp = G(ks)->parm->print_timestamp; - mutex_init(&ktap_iter->iter.mutex); - filp->private_data = &ktap_iter->iter; - - nonseekable_open(inode, filp); - - return 0; -} - -static int tracing_release_pipe(struct inode *inode, struct file *file) -{ - struct trace_iterator *iter = file->private_data; - struct ktap_trace_iterator *ktap_iter = KTAP_TRACE_ITER(iter); - - mutex_destroy(&iter->mutex); - kfree(ktap_iter); - return 0; -} - -static const struct file_operations tracing_pipe_fops = { - .open = tracing_open_pipe, - .read = tracing_read_pipe, - .splice_read = NULL, - .release = tracing_release_pipe, - .llseek = no_llseek, -}; - -/* - * print_backtrace maybe called from ktap mainthread, so be - * care on race with event closure thread. - * - * preempt disabled in ring_buffer_lock_reserve - * - * The implementation is similar with funtion __ftrace_trace_stack. - */ -void kp_transport_print_backtrace(ktap_state *ks) -{ - struct ring_buffer *buffer = G(ks)->buffer; - struct ring_buffer_event *event; - struct trace_entry *entry; - int size; - - size = KTAP_STACK_MAX_ENTRIES * sizeof(unsigned long); - event = ring_buffer_lock_reserve(buffer, sizeof(*entry) + size); - if (!event) { - return; - } else { - struct stack_trace trace; - - entry = ring_buffer_event_data(event); - tracing_generic_entry_update(entry, 0, 0); - entry->type = TRACE_STACK; - - trace.nr_entries = 0; - trace.skip = 10; - trace.max_entries = KTAP_STACK_MAX_ENTRIES; - trace.entries = (unsigned long *)(entry + 1); - save_stack_trace(&trace); - - ring_buffer_unlock_commit(buffer, event); - } - - return; -} - -void kp_transport_event_write(ktap_state *ks, struct ktap_event *e) -{ - struct ring_buffer *buffer = G(ks)->buffer; - struct ring_buffer_event *event; - struct trace_entry *entry; - - event = ring_buffer_lock_reserve(buffer, e->entry_size + - sizeof(struct ftrace_event_call *)); - if (!event) { - return; - } else { - entry = ring_buffer_event_data(event); - - memcpy(entry, e->entry, e->entry_size); - - ring_buffer_unlock_commit(buffer, event); - } -} - -void kp_transport_write(ktap_state *ks, const void *data, size_t length) -{ - struct ring_buffer *buffer = G(ks)->buffer; - struct ring_buffer_event *event; - struct trace_entry *entry; - int size; - - size = sizeof(struct trace_entry) + length; - - event = ring_buffer_lock_reserve(buffer, size); - if (!event) { - return; - } else { - entry = ring_buffer_event_data(event); - - tracing_generic_entry_update(entry, 0, 0); - entry->type = TRACE_PRINT; - memcpy(entry + 1, data, length); - - ring_buffer_unlock_commit(buffer, event); - } -} - -/* general print function */ -void kp_printf(ktap_state *ks, const char *fmt, ...) -{ - char buff[1024]; - va_list args; - int len; - - va_start(args, fmt); - len = vscnprintf(buff, 1024, fmt, args); - va_end(args); - - buff[len] = '\0'; - kp_transport_write(ks, buff, len + 1); -} - -void __kp_puts(ktap_state *ks, const char *str) -{ - kp_transport_write(ks, str, strlen(str) + 1); -} - -void __kp_bputs(ktap_state *ks, const char *str) -{ - struct ring_buffer *buffer = G(ks)->buffer; - struct ring_buffer_event *event; - struct trace_entry *entry; - int size; - - size = sizeof(struct trace_entry) + sizeof(unsigned long *); - - event = ring_buffer_lock_reserve(buffer, size); - if (!event) { - return; - } else { - entry = ring_buffer_event_data(event); - - tracing_generic_entry_update(entry, 0, 0); - entry->type = TRACE_BPUTS; - *(unsigned long *)(entry + 1) = (unsigned long)str; - - ring_buffer_unlock_commit(buffer, event); - } -} - -void kp_transport_exit(ktap_state *ks) -{ - ring_buffer_free(G(ks)->buffer); - debugfs_remove(G(ks)->trace_pipe_dentry); -} - -#define TRACE_BUF_SIZE_DEFAULT 1441792UL /* 16384 * 88 (sizeof(entry)) */ - -int kp_transport_init(ktap_state *ks, struct dentry *dir) -{ - struct ring_buffer *buffer; - struct dentry *dentry; - char filename[32] = {0}; - - ftrace_find_event = (void *)kallsyms_lookup_name("ftrace_find_event"); - if (!ftrace_find_event) { - printk("ktap: cannot lookup ftrace_find_event in kallsyms\n"); - return -EINVAL; - } - - buffer = ring_buffer_alloc(TRACE_BUF_SIZE_DEFAULT, RB_FL_OVERWRITE); - if (!buffer) - return -ENOMEM; - - sprintf(filename, "trace_pipe_%d", (int)task_tgid_vnr(current)); - - dentry = debugfs_create_file(filename, 0444, dir, - ks, &tracing_pipe_fops); - if (!dentry) { - pr_err("ktapvm: cannot create trace_pipe file in debugfs\n"); - ring_buffer_free(buffer); - return -1; - } - - G(ks)->buffer = buffer; - G(ks)->trace_pipe_dentry = dentry; - - return 0; -} - diff --git a/drivers/staging/ktap/interpreter/tstring.c b/drivers/staging/ktap/interpreter/tstring.c deleted file mode 100644 index ce4c88d..0000000 --- a/drivers/staging/ktap/interpreter/tstring.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * tstring.c - ktap tstring data struction manipulation function - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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. - */ - -#ifdef __KERNEL__ -#include "../include/ktap.h" -#else -#include "../include/ktap_types.h" -#endif - -#define STRING_MAXSHORTLEN 40 - -int kp_tstring_cmp(const ktap_string *ls, const ktap_string *rs) -{ - const char *l = getstr(ls); - size_t ll = ls->tsv.len; - const char *r = getstr(rs); - size_t lr = rs->tsv.len; - - for (;;) { - int temp = strcmp(l, r); - if (temp != 0) - return temp; - else { - /* strings are equal up to a `\0' */ - - /* index of first `\0' in both strings */ - size_t len = strlen(l); - - /* r is finished? */ - if (len == lr) - return (len == ll) ? 0 : 1; - else if (len == ll) /* l is finished? */ - return -1; - - /* - * both strings longer than `len'; - * go on comparing (after the `\0') - */ - len++; - l += len; ll -= len; r += len; lr -= len; - } - } -} - -/* - * equality for long strings - */ -int kp_tstring_eqlngstr(ktap_string *a, ktap_string *b) -{ - size_t len = a->tsv.len; - - return (a == b) || ((len == b->tsv.len) && - (memcmp(getstr(a), getstr(b), len) == 0)); -} - -/* - * equality for strings - */ -int kp_tstring_eqstr(ktap_string *a, ktap_string *b) -{ - return (a->tsv.tt == b->tsv.tt) && - (a->tsv.tt == KTAP_TSHRSTR ? eqshrstr(a, b) : - kp_tstring_eqlngstr(a, b)); -} - -#define STRING_HASHLIMIT 5 -unsigned int kp_string_hash(const char *str, size_t l, unsigned int seed) -{ - unsigned int h = seed ^ l; - size_t l1; - size_t step = (l >> STRING_HASHLIMIT) + 1; - - for (l1 = l; l1 >= step; l1 -= step) - h = h ^ ((h<<5) + (h>>2) + (u8)(str[l1 - 1])); - - return h; -} - - -/* - * resizes the string table - */ -void kp_tstring_resize(ktap_state *ks, int newsize) -{ - int i; - ktap_stringtable *tb = &G(ks)->strt; - - if (newsize > tb->size) { - kp_realloc(ks, tb->hash, tb->size, newsize, ktap_gcobject *); - - for (i = tb->size; i < newsize; i++) - tb->hash[i] = NULL; - } - - /* rehash */ - for (i = 0; i < tb->size; i++) { - ktap_gcobject *p = tb->hash[i]; - tb->hash[i] = NULL; - - while (p) { - ktap_gcobject *next = gch(p)->next; - unsigned int h = lmod(gco2ts(p)->hash, newsize); - - gch(p)->next = tb->hash[h]; - tb->hash[h] = p; - p = next; - } - } - - if (newsize < tb->size) { - /* shrinking slice must be empty */ - kp_realloc(ks, tb->hash, tb->size, newsize, ktap_gcobject *); - } - - tb->size = newsize; -} - -/* - * creates a new string object - */ -static ktap_string *createstrobj(ktap_state *ks, const char *str, size_t l, - int tag, unsigned int h, ktap_gcobject **list) -{ - ktap_string *ts; - size_t totalsize; /* total size of TString object */ - - totalsize = sizeof(ktap_string) + ((l + 1) * sizeof(char)); - ts = &kp_newobject(ks, tag, totalsize, list)->ts; - ts->tsv.len = l; - ts->tsv.hash = h; - ts->tsv.extra = 0; - memcpy(ts + 1, str, l * sizeof(char)); - ((char *)(ts + 1))[l] = '\0'; /* ending 0 */ - return ts; -} - -/* - * creates a new short string, inserting it into string table - */ -static ktap_string *newshrstr(ktap_state *ks, const char *str, size_t l, - unsigned int h) -{ - ktap_gcobject **list; - ktap_stringtable *tb = &G(ks)->strt; - ktap_string *s; - - if (tb->nuse >= (int)tb->size) - kp_tstring_resize(ks, tb->size * 2); /* too crowded */ - - list = &tb->hash[lmod(h, tb->size)]; - s = createstrobj(ks, str, l, KTAP_TSHRSTR, h, list); - tb->nuse++; - return s; -} - -#ifdef __KERNEL__ -static arch_spinlock_t tstring_lock = - (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; -#endif - -/* - * checks whether short string exists and reuses it or creates a new one - */ -static ktap_string *internshrstr(ktap_state *ks, const char *str, size_t l) -{ - ktap_gcobject *o; - ktap_global_state *g = G(ks); - ktap_string *ts; - unsigned int h = kp_string_hash(str, l, g->seed); - unsigned long __maybe_unused flags; - -#ifdef __KERNEL__ - local_irq_save(flags); - arch_spin_lock(&tstring_lock); -#endif - - for (o = g->strt.hash[lmod(h, g->strt.size)]; o != NULL; - o = gch(o)->next) { - ts = rawgco2ts(o); - - if (h == ts->tsv.hash && ts->tsv.len == l && - (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) - goto out; - } - - ts = newshrstr(ks, str, l, h); /* not found; create a new string */ - - out: -#ifdef __KERNEL__ - arch_spin_unlock(&tstring_lock); - local_irq_restore(flags); -#endif - return ts; -} - - -/* - * new string (with explicit length) - */ -ktap_string *kp_tstring_newlstr(ktap_state *ks, const char *str, size_t l) -{ - /* short string? */ - if (l <= STRING_MAXSHORTLEN) - return internshrstr(ks, str, l); - else - return createstrobj(ks, str, l, KTAP_TLNGSTR, G(ks)->seed, - NULL); -} - -ktap_string *kp_tstring_newlstr_local(ktap_state *ks, const char *str, size_t l) -{ - return createstrobj(ks, str, l, KTAP_TLNGSTR, G(ks)->seed, - &ks->gclist); -} - -/* - * new zero-terminated string - */ -ktap_string *kp_tstring_new(ktap_state *ks, const char *str) -{ - return kp_tstring_newlstr(ks, str, strlen(str)); -} - -ktap_string *kp_tstring_new_local(ktap_state *ks, const char *str) -{ - return createstrobj(ks, str, strlen(str), KTAP_TLNGSTR, G(ks)->seed, - &ks->gclist); -} - -void kp_tstring_freeall(ktap_state *ks) -{ - ktap_global_state *g = G(ks); - int h; - - for (h = 0; h < g->strt.size; h++) { - ktap_gcobject *o, *next; - o = g->strt.hash[h]; - while (o) { - next = gch(o)->next; - kp_free(ks, o); - o = next; - } - g->strt.hash[h] = NULL; - } - - kp_free(ks, g->strt.hash); -} - -/* todo: dump long string, strt table only contain short string */ -void kp_tstring_dump(ktap_state *ks) -{ - ktap_gcobject *o; - ktap_global_state *g = G(ks); - int h; - - kp_printf(ks, "tstring dump: strt size: %d, nuse: %d\n", g->strt.size, - g->strt.nuse); - for (h = 0; h < g->strt.size; h++) { - for (o = g->strt.hash[h]; o != NULL; o = gch(o)->next) { - ktap_string *ts = rawgco2ts(o); - kp_printf(ks, "%s [%d]\n", getstr(ts), (int)ts->tsv.len); - } - } -} - diff --git a/drivers/staging/ktap/interpreter/vm.c b/drivers/staging/ktap/interpreter/vm.c deleted file mode 100644 index bc7b951..0000000 --- a/drivers/staging/ktap/interpreter/vm.c +++ /dev/null @@ -1,1369 +0,0 @@ -/* - * vm.c - ktap script virtual machine in Linux kernel - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include "../include/ktap.h" - -#define KTAP_MINSTACK 20 - -/* todo: enlarge maxstack for big system like 64-bit */ -#define KTAP_MAXSTACK 15000 - -#define KTAP_STACK_SIZE (BASIC_STACK_SIZE * sizeof(ktap_value)) - -#define CIST_KTAP (1 << 0) /* call is running a ktap function */ -#define CIST_REENTRY (1 << 2) - -#define isktapfunc(ci) ((ci)->callstatus & CIST_KTAP) - -static void ktap_concat(ktap_state *ks, int start, int end) -{ - int i, len = 0; - StkId top = ks->ci->u.l.base; - ktap_string *ts; - char *ptr, *buffer; - - for (i = start; i <= end; i++) { - if (!ttisstring(top + i)) { - kp_error(ks, "cannot concat non-string\n"); - setnilvalue(top + start); - return; - } - - len += rawtsvalue(top + i)->tsv.len; - } - - if (len >= KTAP_PERCPU_BUFFER_SIZE) { - kp_error(ks, "Error: too long string concatenation\n"); - return; - } - - preempt_disable_notrace(); - - buffer = kp_percpu_data(KTAP_PERCPU_DATA_BUFFER); - ptr = buffer; - - for (i = start; i <= end; i++) { - int len = rawtsvalue(top + i)->tsv.len; - strncpy(ptr, svalue(top + i), len); - ptr += len; - } - ts = kp_tstring_newlstr(ks, buffer, len); - setsvalue(top + start, ts); - - preempt_enable_notrace(); -} - -/* todo: compare l == r if both is tstring type? */ -static int lessthan(ktap_state *ks, const ktap_value *l, const ktap_value *r) -{ - if (ttisnumber(l) && ttisnumber(r)) - return NUMLT(nvalue(l), nvalue(r)); - else if (ttisstring(l) && ttisstring(r)) - return kp_tstring_cmp(rawtsvalue(l), rawtsvalue(r)) < 0; - - return 0; -} - -static int lessequal(ktap_state *ks, const ktap_value *l, const ktap_value *r) -{ - if (ttisnumber(l) && ttisnumber(r)) - return NUMLE(nvalue(l), nvalue(r)); - else if (ttisstring(l) && ttisstring(r)) - return kp_tstring_cmp(rawtsvalue(l), rawtsvalue(r)) <= 0; - - return 0; -} - -static int fb2int (int x) -{ - int e = (x >> 3) & 0x1f; - if (e == 0) - return x; - else - return ((x & 7) + 8) << (e - 1); -} - -static const ktap_value *ktap_tonumber(const ktap_value *obj, ktap_value *n) -{ - if (ttisnumber(obj)) - return obj; - - return NULL; -} - -static ktap_upval *findupval(ktap_state *ks, StkId level) -{ - ktap_global_state *g = G(ks); - ktap_gcobject **pp = &ks->openupval; - ktap_upval *p; - ktap_upval *uv; - - while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { - if (p->v == level) { /* found a corresponding upvalue? */ - return p; - } - pp = &p->next; - } - - /* not found: create a new one */ - uv = &kp_newobject(ks, KTAP_TUPVAL, sizeof(ktap_upval), pp)->uv; - uv->v = level; /* current value lives in the stack */ - uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ - uv->u.l.next = g->uvhead.u.l.next; - uv->u.l.next->u.l.prev = uv; - g->uvhead.u.l.next = uv; - return uv; -} - -/* todo: implement this*/ -static void function_close (ktap_state *ks, StkId level) -{ -} - -/* create a new closure */ -static void pushclosure(ktap_state *ks, ktap_proto *p, ktap_upval **encup, - StkId base, StkId ra) -{ - int nup = p->sizeupvalues; - ktap_upvaldesc *uv = p->upvalues; - int i; - ktap_closure *ncl = kp_newlclosure(ks, nup); - - ncl->l.p = p; - setcllvalue(ra, ncl); /* anchor new closure in stack */ - - /* fill in its upvalues */ - for (i = 0; i < nup; i++) { - if (uv[i].instack) { - /* upvalue refers to local variable? */ - ncl->l.upvals[i] = findupval(ks, base + uv[i].idx); - } else { - /* get upvalue from enclosing function */ - ncl->l.upvals[i] = encup[uv[i].idx]; - } - } - //p->cache = ncl; /* save it on cache for reuse */ -} - -static void gettable(ktap_state *ks, const ktap_value *t, ktap_value *key, - StkId val) -{ - if (ttistable(t)) { - setobj(val, kp_table_get(hvalue(t), key)); - } else if (ttisaggrtable(t)) { - kp_aggrtable_get(ks, ahvalue(t), key, val); - } else { - kp_error(ks, "get key from non-table\n"); - } -} - -static void settable(ktap_state *ks, const ktap_value *t, ktap_value *key, - StkId val) -{ - if (ttistable(t)) { - kp_table_setvalue(ks, hvalue(t), key, val); - } else if (ttisaggrtable(t)) { - kp_aggrtable_set(ks, ahvalue(t), key, val); - } else { - kp_error(ks, "set key to non-table\n"); - } -} - -static void settable_incr(ktap_state *ks, const ktap_value *t, ktap_value *key, - StkId val) -{ - if (unlikely(!ttistable(t))) { - kp_error(ks, "use += operator for non-table\n"); - return; - } - - if (unlikely(!ttisnumber(val))) { - kp_error(ks, "use non-number to += operator\n"); - return; - } - - kp_table_atomic_inc(ks, hvalue(t), key, nvalue(val)); -} - - -static void growstack(ktap_state *ks, int n) -{ - ktap_value *oldstack; - int lim; - ktap_callinfo *ci; - ktap_gcobject *up; - int size = ks->stacksize; - int needed = (int)(ks->top - ks->stack) + n; - int newsize = 2 * size; - - if (newsize > KTAP_MAXSTACK) - newsize = KTAP_MAXSTACK; - - if (newsize < needed) - newsize = needed; - - if (newsize > KTAP_MAXSTACK) { /* stack overflow? */ - kp_error(ks, "stack overflow\n"); - return; - } - - /* realloc stack */ - oldstack = ks->stack; - lim = ks->stacksize; - kp_realloc(ks, ks->stack, ks->stacksize, newsize, ktap_value); - - for (; lim < newsize; lim++) - setnilvalue(ks->stack + lim); - ks->stacksize = newsize; - ks->stack_last = ks->stack + newsize; - - /* correct stack */ - ks->top = (ks->top - oldstack) + ks->stack; - for (up = ks->openupval; up != NULL; up = up->gch.next) - gco2uv(up)->v = (gco2uv(up)->v - oldstack) + ks->stack; - - for (ci = ks->ci; ci != NULL; ci = ci->prev) { - ci->top = (ci->top - oldstack) + ks->stack; - ci->func = (ci->func - oldstack) + ks->stack; - if (isktapfunc(ci)) - ci->u.l.base = (ci->u.l.base - oldstack) + ks->stack; - } - -} - -static inline void checkstack(ktap_state *ks, int n) -{ - if (ks->stack_last - ks->top <= n) - growstack(ks, n); -} - -static StkId adjust_varargs(ktap_state *ks, ktap_proto *p, int actual) -{ - int i; - int nfixargs = p->numparams; - StkId base, fixed; - - /* move fixed parameters to final position */ - fixed = ks->top - actual; /* first fixed argument */ - base = ks->top; /* final position of first argument */ - - for (i=0; i < nfixargs; i++) { - setobj(ks->top++, fixed + i); - setnilvalue(fixed + i); - } - - return base; -} - -static int poscall(ktap_state *ks, StkId first_result) -{ - ktap_callinfo *ci; - StkId res; - int wanted, i; - - ci = ks->ci; - - res = ci->func; - wanted = ci->nresults; - - ks->ci = ci = ci->prev; - - for (i = wanted; i != 0 && first_result < ks->top; i--) - setobj(res++, first_result++); - - while(i-- > 0) - setnilvalue(res++); - - ks->top = res; - - return (wanted - (-1)); -} - -static ktap_callinfo *extend_ci(ktap_state *ks) -{ - ktap_callinfo *ci; - - ci = kp_malloc(ks, sizeof(ktap_callinfo)); - ks->ci->next = ci; - ci->prev = ks->ci; - ci->next = NULL; - - return ci; -} - -static void free_ci(ktap_state *ks) -{ - ktap_callinfo *ci = ks->ci; - ktap_callinfo *next; - - if (!ci) - return; - - next = ci->next; - ci->next = NULL; - while ((ci = next) != NULL) { - next = ci->next; - kp_free(ks, ci); - } -} - -#define next_ci(ks) (ks->ci = ks->ci->next ? ks->ci->next : extend_ci(ks)) -#define savestack(ks, p) ((char *)(p) - (char *)ks->stack) -#define restorestack(ks, n) ((ktap_value *)((char *)ks->stack + (n))) - -static int precall(ktap_state *ks, StkId func, int nresults) -{ - ktap_cfunction f; - ktap_callinfo *ci; - ktap_proto *p; - StkId base; - ptrdiff_t funcr = savestack(ks, func); - int n; - - switch (ttype(func)) { - case KTAP_TLCF: /* light C function */ - f = fvalue(func); - goto CFUNC; - case KTAP_TCCL: /* C closure */ - f = clcvalue(func)->f; - CFUNC: - checkstack(ks, KTAP_MINSTACK); - ci = next_ci(ks); - ci->nresults = nresults; - ci->func = restorestack(ks, funcr); - ci->top = ks->top + KTAP_MINSTACK; - ci->callstatus = 0; - n = (*f)(ks); - poscall(ks, ks->top - n); - return 1; - case KTAP_TLCL: - p = CLVALUE(func)->p; - checkstack(ks, p->maxstacksize); - func = restorestack(ks, funcr); - n = (int)(ks->top - func) - 1; /* number of real arguments */ - - /* complete missing arguments */ - for (; n < p->numparams; n++) - setnilvalue(ks->top++); - - base = (!p->is_vararg) ? func + 1 : adjust_varargs(ks, p, n); - ci = next_ci(ks); - ci->nresults = nresults; - ci->func = func; - ci->u.l.base = base; - ci->top = base + p->maxstacksize; - ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus = CIST_KTAP; - ks->top = ci->top; - return 0; - default: - kp_error(ks, "attempt to call nil function\n"); - } - - return 0; -} - -#define RA(i) (base+GETARG_A(i)) -#define RB(i) (base+GETARG_B(i)) -#define ISK(x) ((x) & BITRK) -#define RC(i) base+GETARG_C(i) -#define RKB(i) \ - ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i) -#define RKC(i) \ - ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i) - -#define dojump(ci,i,e) { \ - ci->u.l.savedpc += GETARG_sBx(i) + e; } -#define donextjump(ci) { instr = *ci->u.l.savedpc; dojump(ci, instr, 1); } - -#define arith_op(ks, op) { \ - ktap_value *rb = RKB(instr); \ - ktap_value *rc = RKC(instr); \ - if (ttisnumber(rb) && ttisnumber(rc)) { \ - ktap_number nb = nvalue(rb), nc = nvalue(rc); \ - setnvalue(ra, op(nb, nc)); \ - } else { \ - kp_puts(ks, "Error: Cannot make arith operation\n"); \ - return; \ - } } - -static ktap_value *cfunction_cache_get(ktap_state *ks, int index); - -static void ktap_execute(ktap_state *ks) -{ - int exec_count = 0; - ktap_callinfo *ci; - ktap_lclosure *cl; - ktap_value *k; - unsigned int instr, opcode; - StkId base; /* stack pointer */ - StkId ra; /* register pointer */ - int res, nresults; /* temp varible */ - - ci = ks->ci; - - newframe: - cl = CLVALUE(ci->func); - k = cl->p->k; - base = ci->u.l.base; - - mainloop: - /* main loop of interpreter */ - - /* dead loop detaction */ - if (exec_count++ == kp_max_exec_count) { - if (G(ks)->mainthread != ks) { - kp_error(ks, "non-mainthread executed instructions " - "exceed max limit(%d)\n", - kp_max_exec_count); - return; - } - - cond_resched(); - if (signal_pending(current)) { - flush_signals(current); - return; - } - exec_count = 0; - } - - instr = *(ci->u.l.savedpc++); - opcode = GET_OPCODE(instr); - - /* ra is target register */ - ra = RA(instr); - - switch (opcode) { - case OP_MOVE: - setobj(ra, base + GETARG_B(instr)); - break; - case OP_LOADK: - setobj(ra, k + GETARG_Bx(instr)); - break; - case OP_LOADKX: - setobj(ra, k + GETARG_Ax(*ci->u.l.savedpc++)); - break; - case OP_LOADBOOL: - setbvalue(ra, GETARG_B(instr)); - if (GETARG_C(instr)) - ci->u.l.savedpc++; - break; - case OP_LOADNIL: { - int b = GETARG_B(instr); - do { - setnilvalue(ra++); - } while (b--); - break; - } - case OP_GETUPVAL: { - int b = GETARG_B(instr); - setobj(ra, cl->upvals[b]->v); - break; - } - case OP_GETTABUP: { - int b = GETARG_B(instr); - gettable(ks, cl->upvals[b]->v, RKC(instr), ra); - base = ci->u.l.base; - break; - } - case OP_GETTABLE: - gettable(ks, RB(instr), RKC(instr), ra); - base = ci->u.l.base; - break; - case OP_SETTABUP: { - int a = GETARG_A(instr); - settable(ks, cl->upvals[a]->v, RKB(instr), RKC(instr)); - base = ci->u.l.base; - break; - } - case OP_SETTABUP_INCR: { - int a = GETARG_A(instr); - settable_incr(ks, cl->upvals[a]->v, RKB(instr), RKC(instr)); - base = ci->u.l.base; - break; - } - case OP_SETUPVAL: { - ktap_upval *uv = cl->upvals[GETARG_B(instr)]; - setobj(uv->v, ra); - break; - } - case OP_SETTABLE: - settable(ks, ra, RKB(instr), RKC(instr)); - base = ci->u.l.base; - break; - case OP_SETTABLE_INCR: - settable_incr(ks, ra, RKB(instr), RKC(instr)); - base = ci->u.l.base; - break; - case OP_NEWTABLE: { - int b = GETARG_B(instr); - int c = GETARG_C(instr); - ktap_table *t = kp_table_new(ks); - sethvalue(ra, t); - if (b != 0 || c != 0) - kp_table_resize(ks, t, fb2int(b), fb2int(c)); - break; - } - case OP_SELF: { - StkId rb = RB(instr); - setobj(ra+1, rb); - gettable(ks, rb, RKC(instr), ra); - base = ci->u.l.base; - break; - } - case OP_ADD: - arith_op(ks, NUMADD); - break; - case OP_SUB: - arith_op(ks, NUMSUB); - break; - case OP_MUL: - arith_op(ks, NUMMUL); - break; - case OP_DIV: - /* divide 0 checking */ - if (!nvalue(RKC(instr))) { - kp_error(ks, "divide 0 arith operation\n"); - return; - } - arith_op(ks, NUMDIV); - break; - case OP_MOD: - /* divide 0 checking */ - if (!nvalue(RKC(instr))) { - kp_error(ks, "mod 0 arith operation\n"); - return; - } - arith_op(ks, NUMMOD); - break; - case OP_POW: - kp_error(ks, "ktap don't support pow arith in kernel\n"); - return; - case OP_UNM: { - ktap_value *rb = RB(instr); - if (ttisnumber(rb)) { - ktap_number nb = nvalue(rb); - setnvalue(ra, NUMUNM(nb)); - } - break; - } - case OP_NOT: - res = isfalse(RB(instr)); - setbvalue(ra, res); - break; - case OP_LEN: { - int len = kp_objlen(ks, RB(instr)); - if (len < 0) - return; - setnvalue(ra, len); - break; - } - case OP_CONCAT: { - int b = GETARG_B(instr); - int c = GETARG_C(instr); - ktap_concat(ks, b, c); - break; - } - case OP_JMP: - dojump(ci, instr, 0); - break; - case OP_EQ: { - ktap_value *rb = RKB(instr); - ktap_value *rc = RKC(instr); - if ((int)equalobj(ks, rb, rc) != GETARG_A(instr)) - ci->u.l.savedpc++; - else - donextjump(ci); - - base = ci->u.l.base; - break; - } - case OP_LT: - if (lessthan(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) - ci->u.l.savedpc++; - else - donextjump(ci); - base = ci->u.l.base; - break; - case OP_LE: - if (lessequal(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) - ci->u.l.savedpc++; - else - donextjump(ci); - base = ci->u.l.base; - break; - case OP_TEST: - if (GETARG_C(instr) ? isfalse(ra) : !isfalse(ra)) - ci->u.l.savedpc++; - else - donextjump(ci); - break; - case OP_TESTSET: { - ktap_value *rb = RB(instr); - if (GETARG_C(instr) ? isfalse(rb) : !isfalse(rb)) - ci->u.l.savedpc++; - else { - setobj(ra, rb); - donextjump(ci); - } - break; - } - case OP_CALL: { - int b = GETARG_B(instr); - int ret; - - nresults = GETARG_C(instr) - 1; - - if (b != 0) - ks->top = ra + b; - - ret = precall(ks, ra, nresults); - if (ret) { /* C function */ - if (nresults >= 0) - ks->top = ci->top; - base = ci->u.l.base; - break; - } else { /* ktap function */ - ci = ks->ci; - /* this flag is used for return time, see OP_RETURN */ - ci->callstatus |= CIST_REENTRY; - goto newframe; - } - break; - } - case OP_TAILCALL: { - int b = GETARG_B(instr); - - if (b != 0) - ks->top = ra+b; - if (precall(ks, ra, -1)) /* C function? */ - base = ci->u.l.base; - else { - int aux; - - /* - * tail call: put called frame (n) in place of - * caller one (o) - */ - ktap_callinfo *nci = ks->ci; /* called frame */ - ktap_callinfo *oci = nci->prev; /* caller frame */ - StkId nfunc = nci->func; /* called function */ - StkId ofunc = oci->func; /* caller function */ - /* last stack slot filled by 'precall' */ - StkId lim = nci->u.l.base + - CLVALUE(nfunc)->p->numparams; - - /* close all upvalues from previous call */ - if (cl->p->sizep > 0) - function_close(ks, oci->u.l.base); - - /* move new frame into old one */ - for (aux = 0; nfunc + aux < lim; aux++) - setobj(ofunc + aux, nfunc + aux); - /* correct base */ - oci->u.l.base = ofunc + (nci->u.l.base - nfunc); - /* correct top */ - oci->top = ks->top = ofunc + (ks->top - nfunc); - oci->u.l.savedpc = nci->u.l.savedpc; - /* remove new frame */ - ci = ks->ci = oci; - /* restart ktap_execute over new ktap function */ - goto newframe; - } - break; - } - case OP_RETURN: { - int b = GETARG_B(instr); - if (b != 0) - ks->top = ra+b-1; - if (cl->p->sizep > 0) - function_close(ks, base); - b = poscall(ks, ra); - - /* if it's called from external invocation, just return */ - if (!(ci->callstatus & CIST_REENTRY)) - return; - - ci = ks->ci; - if (b) - ks->top = ci->top; - goto newframe; - } - case OP_FORLOOP: { - ktap_number step = nvalue(ra+2); - /* increment index */ - ktap_number idx = NUMADD(nvalue(ra), step); - ktap_number limit = nvalue(ra+1); - if (NUMLT(0, step) ? NUMLE(idx, limit) : NUMLE(limit, idx)) { - ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ - setnvalue(ra, idx); /* update internal index... */ - setnvalue(ra+3, idx); /* ...and external index */ - } - break; - } - case OP_FORPREP: { - const ktap_value *init = ra; - const ktap_value *plimit = ra + 1; - const ktap_value *pstep = ra + 2; - - if (!ktap_tonumber(init, ra)) { - kp_error(ks, KTAP_QL("for") - " initial value must be a number\n"); - return; - } else if (!ktap_tonumber(plimit, ra + 1)) { - kp_error(ks, KTAP_QL("for") - " limit must be a number\n"); - return; - } else if (!ktap_tonumber(pstep, ra + 2)) { - kp_error(ks, KTAP_QL("for") " step must be a number\n"); - return; - } - - setnvalue(ra, NUMSUB(nvalue(ra), nvalue(pstep))); - ci->u.l.savedpc += GETARG_sBx(instr); - break; - } - case OP_TFORCALL: { - StkId cb = ra + 3; /* call base */ - setobj(cb + 2, ra + 2); - setobj(cb + 1, ra + 1); - setobj(cb, ra); - ks->top = cb + 3; /* func. + 2 args (state and index) */ - kp_call(ks, cb, GETARG_C(instr)); - base = ci->u.l.base; - ks->top = ci->top; - instr = *(ci->u.l.savedpc++); /* go to next instruction */ - ra = RA(instr); - } - /*go through */ - case OP_TFORLOOP: - if (!ttisnil(ra + 1)) { /* continue loop? */ - setobj(ra, ra + 1); /* save control variable */ - ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ - } - break; - case OP_SETLIST: { - int n = GETARG_B(instr); - int c = GETARG_C(instr); - int last; - ktap_table *h; - - if (n == 0) - n = (int)(ks->top - ra) - 1; - if (c == 0) - c = GETARG_Ax(*ci->u.l.savedpc++); - - h = hvalue(ra); - last = ((c - 1) * LFIELDS_PER_FLUSH) + n; - if (last > h->sizearray) /* needs more space? */ - kp_table_resizearray(ks, h, last); - - for (; n > 0; n--) { - ktap_value *val = ra+n; - kp_table_setint(ks, h, last--, val); - } - /* correct top (in case of previous open call) */ - ks->top = ci->top; - break; - } - case OP_CLOSURE: { - /* need to use closure cache? (multithread contention issue)*/ - ktap_proto *p = cl->p->p[GETARG_Bx(instr)]; - pushclosure(ks, p, cl->upvals, base, ra); - break; - } - case OP_VARARG: { - int b = GETARG_B(instr) - 1; - int j; - int n = (int)(base - ci->func) - cl->p->numparams - 1; - if (b < 0) { /* B == 0? */ - b = n; /* get all var. arguments */ - checkstack(ks, n); - /* previous call may change the stack */ - ra = RA(instr); - ks->top = ra + n; - } - for (j = 0; j < b; j++) { - if (j < n) { - setobj(ra + j, base - n + j); - } else - setnilvalue(ra + j); - } - break; - } - case OP_EXTRAARG: - return; - - case OP_EVENT: { - struct ktap_event *e = ks->current_event; - - if (unlikely(!e)) { - kp_error(ks, "invalid event context\n"); - return; - } - setevalue(ra, e); - break; - } - - case OP_EVENTNAME: { - struct ktap_event *e = ks->current_event; - - if (unlikely(!e)) { - kp_error(ks, "invalid event context\n"); - return; - } - setsvalue(ra, kp_tstring_new(ks, e->call->name)); - break; - } - case OP_EVENTARG: - if (unlikely(!ks->current_event)) { - kp_error(ks, "invalid event context\n"); - return; - } - - kp_event_getarg(ks, ra, GETARG_B(instr)); - break; - case OP_LOAD_GLOBAL: { - ktap_value *cfunc = cfunction_cache_get(ks, GETARG_C(instr)); - setobj(ra, cfunc); - } - break; - - case OP_EXIT: - return; - } - - goto mainloop; -} - -void kp_call(ktap_state *ks, StkId func, int nresults) -{ - if (!precall(ks, func, nresults)) - ktap_execute(ks); -} - -static int cfunction_cache_getindex(ktap_state *ks, ktap_value *fname); - -/* - * This function must be called before all code loaded. - */ -void kp_optimize_code(ktap_state *ks, int level, ktap_proto *f) -{ - int i; - - for (i = 0; i < f->sizecode; i++) { - int instr = f->code[i]; - ktap_value *k = f->k; - - if (GET_OPCODE(instr) == OP_GETTABUP) { - if ((GETARG_B(instr) == 0) && ISK(GETARG_C(instr))) { - ktap_value *field = k + INDEXK(GETARG_C(instr)); - if (ttype(field) == KTAP_TSTRING) { - int index = cfunction_cache_getindex(ks, - field); - if (index == -1) - break; - - SET_OPCODE(instr, OP_LOAD_GLOBAL); - SETARG_C(instr, index); - f->code[i] = instr; - break; - } - } - } - } - - /* continue optimize sub functions */ - for (i = 0; i < f->sizep; i++) - kp_optimize_code(ks, level + 1, f->p[i]); -} - -static ktap_value *cfunction_cache_get(ktap_state *ks, int index) -{ - return &G(ks)->cfunction_tbl[index]; -} - -static int cfunction_cache_getindex(ktap_state *ks, ktap_value *fname) -{ - const ktap_value *gt = kp_table_getint(hvalue(&G(ks)->registry), - KTAP_RIDX_GLOBALS); - const ktap_value *cfunc; - int nr, i; - - nr = G(ks)->nr_builtin_cfunction; - cfunc = kp_table_get(hvalue(gt), fname); - - for (i = 0; i < nr; i++) { - if (rawequalobj(&G(ks)->cfunction_tbl[i], cfunc)) - return i; - } - - return -1; -} - -static void cfunction_cache_add(ktap_state *ks, ktap_value *func) -{ - int nr = G(ks)->nr_builtin_cfunction; - setobj(&G(ks)->cfunction_tbl[nr], func); - G(ks)->nr_builtin_cfunction++; -} - -static void cfunction_cache_exit(ktap_state *ks) -{ - kp_free(ks, G(ks)->cfunction_tbl); -} - -static int cfunction_cache_init(ktap_state *ks) -{ - G(ks)->cfunction_tbl = kp_zalloc(ks, sizeof(ktap_value) * 128); - if (!G(ks)->cfunction_tbl) - return -ENOMEM; - - return 0; -} - -/* function for register library */ -void kp_register_lib(ktap_state *ks, const char *libname, const ktap_Reg *funcs) -{ - int i; - ktap_table *target_tbl; - const ktap_value *gt = kp_table_getint(hvalue(&G(ks)->registry), - KTAP_RIDX_GLOBALS); - - /* lib is null when register baselib function */ - if (libname == NULL) - target_tbl = hvalue(gt); - else { - ktap_value key, val; - - target_tbl = kp_table_new(ks); - kp_table_resize(ks, target_tbl, 0, - sizeof(*funcs) / sizeof(ktap_Reg)); - - setsvalue(&key, kp_tstring_new(ks, libname)); - sethvalue(&val, target_tbl); - kp_table_setvalue(ks, hvalue(gt), &key, &val); - } - - for (i = 0; funcs[i].name != NULL; i++) { - ktap_value func_name, cl; - - setsvalue(&func_name, kp_tstring_new(ks, funcs[i].name)); - setfvalue(&cl, funcs[i].func); - kp_table_setvalue(ks, target_tbl, &func_name, &cl); - - cfunction_cache_add(ks, &cl); - } -} - -#define BASIC_STACK_SIZE (2 * KTAP_MINSTACK) - -static void kp_init_registry(ktap_state *ks) -{ - ktap_value mt; - ktap_table *registry = kp_table_new(ks); - - sethvalue(&G(ks)->registry, registry); - kp_table_resize(ks, registry, KTAP_RIDX_LAST, 0); - setthvalue(ks, &mt, ks); - kp_table_setint(ks, registry, KTAP_RIDX_MAINTHREAD, &mt); - sethvalue(&mt, kp_table_new(ks)); - kp_table_setint(ks, registry, KTAP_RIDX_GLOBALS, &mt); -} - -static int kp_init_arguments(ktap_state *ks, int argc, char __user **user_argv) -{ - const ktap_value *gt = kp_table_getint(hvalue(&G(ks)->registry), - KTAP_RIDX_GLOBALS); - ktap_table *global_tbl = hvalue(gt); - ktap_table *arg_tbl = kp_table_new(ks); - ktap_value arg_tblval; - ktap_value arg_tsval; - char **argv; - int i, ret; - - setsvalue(&arg_tsval, kp_tstring_new(ks, "arg")); - sethvalue(&arg_tblval, arg_tbl); - kp_table_setvalue(ks, global_tbl, &arg_tsval, &arg_tblval); - - if (!argc) - return 0; - - if (argc > 1024) - return -EINVAL; - - argv = kzalloc(argc * sizeof(char *), GFP_KERNEL); - if (!argv) - return -ENOMEM; - - ret = copy_from_user(argv, user_argv, argc * sizeof(char *)); - if (ret < 0) { - kfree(argv); - return -EFAULT; - } - - kp_table_resize(ks, arg_tbl, argc, 1); - - ret = 0; - for (i = 0; i < argc; i++) { - ktap_value val; - char __user *ustr = argv[i]; - char * kstr; - int len; - int res; - - len = strlen_user(ustr); - if (len > 0x1000) { - ret = -EINVAL; - break; - } - - kstr = kmalloc(len + 1, GFP_KERNEL); - if (!kstr) { - ret = -ENOMEM; - break; - } - - if (strncpy_from_user(kstr, ustr, len) < 0) { - ret = -EFAULT; - break; - } - - kstr[len] = '\0'; - - if (!kstrtoint(kstr, 10, &res)) { - setnvalue(&val, res); - } else - setsvalue(&val, kp_tstring_new(ks, kstr)); - - kp_table_setint(ks, arg_tbl, i, &val); - - kfree(kstr); - } - - kfree(argv); - return ret; -} - -DEFINE_PER_CPU(int, kp_recursion_context[PERF_NR_CONTEXTS]); - -/* todo: make this per-session aware */ -static void __percpu *kp_pcpu_data[KTAP_PERCPU_DATA_MAX][PERF_NR_CONTEXTS]; - -void *kp_percpu_data(int type) -{ - return this_cpu_ptr(kp_pcpu_data[type][trace_get_context_bit()]); -} - -static void free_kp_percpu_data(void) -{ - int i, j; - - for (i = 0; i < KTAP_PERCPU_DATA_MAX; i++) { - for (j = 0; j < PERF_NR_CONTEXTS; j++) { - free_percpu(kp_pcpu_data[i][j]); - kp_pcpu_data[i][j] = NULL; - } - } -} - -static int alloc_kp_percpu_data(void) -{ - int data_size[KTAP_PERCPU_DATA_MAX] = { - sizeof(ktap_state), KTAP_STACK_SIZE, KTAP_PERCPU_BUFFER_SIZE, - KTAP_PERCPU_BUFFER_SIZE, sizeof(ktap_btrace)}; - int i, j; - - for (i = 0; i < KTAP_PERCPU_DATA_MAX; i++) { - for (j = 0; j < PERF_NR_CONTEXTS; j++) { - void __percpu *data = __alloc_percpu(data_size[i], - __alignof__(char)); - if (!data) - goto fail; - kp_pcpu_data[i][j] = data; - } - } - - return 0; - - fail: - free_kp_percpu_data(); - return -ENOMEM; -} - -static void kp_init_state(ktap_state *ks) -{ - ktap_callinfo *ci; - int i; - - ks->stacksize = BASIC_STACK_SIZE; - - for (i = 0; i < BASIC_STACK_SIZE; i++) - setnilvalue(ks->stack + i); - - ks->top = ks->stack; - ks->stack_last = ks->stack + ks->stacksize; - - ci = &ks->baseci; - ci->callstatus = 0; - ci->func = ks->top; - setnilvalue(ks->top++); - ci->top = ks->top + KTAP_MINSTACK; - ks->ci = ci; -} - -static void free_all_ci(ktap_state *ks) -{ - int cpu; - - for_each_possible_cpu(cpu) { - ktap_state *ks; - int j; - - for (j = 0; j < PERF_NR_CONTEXTS; j++) { - if (!kp_pcpu_data[KTAP_PERCPU_DATA_STATE][j]) - break; - - ks = per_cpu_ptr(kp_pcpu_data[KTAP_PERCPU_DATA_STATE][j], cpu); - if (!ks) - break; - - free_ci(ks); - } - } - - free_ci(ks); -} - -void kp_exitthread(ktap_state *ks) -{ - /* free local allocation objects, like annotate strings */ - kp_free_gclist(ks, ks->gclist); -} - -ktap_state *kp_newthread(ktap_state *mainthread) -{ - ktap_state *ks; - - ks = kp_percpu_data(KTAP_PERCPU_DATA_STATE); - ks->stack = kp_percpu_data(KTAP_PERCPU_DATA_STACK); - G(ks) = G(mainthread); - ks->gclist = NULL; - kp_init_state(ks); - return ks; -} - -/* - * wait ktapio thread read all content in ring buffer. - * - * Here we use stupid approach to sync with ktapio thread, - * note that we cannot use semaphore/completion/other sync method, - * because ktapio thread could be killed by SIG_KILL in anytime, there - * have no safe way to up semaphore or wake waitqueue before thread exit. - * - * we also cannot use waitqueue of current->signal->wait_chldexit to sync - * exit, becasue mainthread and ktapio thread are in same thread group. - * - * Also ktap mainthread must wait ktapio thread exit, otherwise ktapio - * thread will oops when access ktap structure. - */ -static void wait_user_completion(ktap_state *ks) -{ - struct task_struct *tsk = G(ks)->task; - G(ks)->wait_user = 1; - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - /* sleep for 100 msecs, and try again. */ - schedule_timeout(HZ / 10); - - if (get_nr_threads(tsk) == 1) - break; - } -} - -/* kp_wait: used for mainthread waiting for exit */ -static void kp_wait(ktap_state *ks) -{ - struct task_struct *task = G(ks)->trace_task; - - if (G(ks)->exit) - return; - - ks->stop = 0; - - /* tell workload process to start executing */ - if (G(ks)->parm->workload) - send_sig(SIGINT, G(ks)->trace_task, 0); - - while (!ks->stop) { - set_current_state(TASK_INTERRUPTIBLE); - /* sleep for 100 msecs, and try again. */ - schedule_timeout(HZ / 10); - - if (signal_pending(current)) { - flush_signals(current); - - /* newline for handle CTRL+C display as ^C */ - kp_puts(ks, "\n"); - break; - } - - /* stop waiting if target pid is exited */ - if (task && task->state == TASK_DEAD) - break; - } - -} - -void kp_exit(ktap_state *ks) -{ - set_next_as_exit(ks); - - G(ks)->mainthread->stop = 1; - G(ks)->exit = 1; -} - -void kp_final_exit(ktap_state *ks) -{ - if (!list_empty(&G(ks)->probe_events_head) || - !list_empty(&G(ks)->timers)) - kp_wait(ks); - - if (G(ks)->trace_task) - put_task_struct(G(ks)->trace_task); - - kp_exit_timers(ks); - kp_probe_exit(ks); - - /* free all resources got by ktap */ - kp_tstring_freeall(ks); - kp_free_all_gcobject(ks); - cfunction_cache_exit(ks); - - wait_user_completion(ks); - - kp_transport_exit(ks); - - kp_exitthread(ks); - kp_free(ks, ks->stack); - free_all_ci(ks); - - free_kp_percpu_data(); - - free_cpumask_var(G(ks)->cpumask); - kp_free(ks, ks); -} - -/* ktap mainthread initization, main entry for ktap */ -ktap_state *kp_newstate(ktap_parm *parm, struct dentry *dir) -{ - ktap_state *ks; - pid_t pid; - int cpu; - - ks = kzalloc(sizeof(ktap_state) + sizeof(ktap_global_state), - GFP_KERNEL); - if (!ks) - return NULL; - - ks->stack = kp_malloc(ks, KTAP_STACK_SIZE); - G(ks) = (ktap_global_state *)(ks + 1); - G(ks)->mainthread = ks; - G(ks)->seed = 201236; /* todo: make more random in future */ - G(ks)->task = current; - G(ks)->parm = parm; - INIT_LIST_HEAD(&(G(ks)->timers)); - INIT_LIST_HEAD(&(G(ks)->probe_events_head)); - G(ks)->exit = 0; - - if (kp_transport_init(ks, dir)) - goto out; - - pid = (pid_t)parm->trace_pid; - if (pid != -1) { - struct task_struct *task; - - rcu_read_lock(); - task = pid_task(find_vpid(pid), PIDTYPE_PID); - if (!task) { - kp_error(ks, "cannot find pid %d\n", pid); - rcu_read_unlock(); - goto out; - } - G(ks)->trace_task = task; - get_task_struct(task); - rcu_read_unlock(); - } - - if( !alloc_cpumask_var(&G(ks)->cpumask, GFP_KERNEL)) - goto out; - - cpumask_copy(G(ks)->cpumask, cpu_online_mask); - - cpu = parm->trace_cpu; - if (cpu != -1) { - if (!cpu_online(cpu)) { - printk(KERN_INFO "ktap: cpu %d is not online\n", cpu); - goto out; - } - - cpumask_clear(G(ks)->cpumask); - cpumask_set_cpu(cpu, G(ks)->cpumask); - } - - if (cfunction_cache_init(ks)) - goto out; - - kp_tstring_resize(ks, 512); /* set inital string hashtable size */ - - kp_init_state(ks); - kp_init_registry(ks); - kp_init_arguments(ks, parm->argc, parm->argv); - - /* init library */ - kp_init_baselib(ks); - kp_init_kdebuglib(ks); - kp_init_timerlib(ks); - kp_init_ansilib(ks); - - if (alloc_kp_percpu_data()) - goto out; - - if (kp_probe_init(ks)) - goto out; - - return ks; - - out: - G(ks)->exit = 1; - kp_final_exit(ks); - return NULL; -} - diff --git a/drivers/staging/ktap/scripts/basic/backtrace.kp b/drivers/staging/ktap/scripts/basic/backtrace.kp deleted file mode 100644 index 39b8c39..0000000 --- a/drivers/staging/ktap/scripts/basic/backtrace.kp +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ktap - -trace sched:sched_switch { - print_backtrace() -} - diff --git a/drivers/staging/ktap/scripts/basic/event_trigger.kp b/drivers/staging/ktap/scripts/basic/event_trigger.kp deleted file mode 100644 index 3cc8b04..0000000 --- a/drivers/staging/ktap/scripts/basic/event_trigger.kp +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env ktap - -soft_disabled = 1 -this_cpu = 0 - -trace syscalls:sys_enter_open { - print(argevent) - soft_disabled = 0 - this_cpu = cpu() -} - -trace *:* { - if (soft_disabled == 0 && cpu() == this_cpu) { - print(argevent) - } -} - -trace syscalls:sys_exit_open { - print(argevent) - if (cpu() == this_cpu) { - exit() - } -} - diff --git a/drivers/staging/ktap/scripts/basic/event_trigger_ftrace.kp b/drivers/staging/ktap/scripts/basic/event_trigger_ftrace.kp deleted file mode 100644 index 7e0d7d3..0000000 --- a/drivers/staging/ktap/scripts/basic/event_trigger_ftrace.kp +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env ktap - - -#This ktap script will output all function calling between -#sys_enter_open and sys_exit_open, in one cpu. - -soft_disabled = 1 -this_cpu = 0 - -trace syscalls:sys_enter_open { - print(argevent) - soft_disabled = 0 - this_cpu = cpu() -} - -trace ftrace:function { - if (soft_disabled == 0 && cpu() == this_cpu) { - print(argevent) - } -} - -trace syscalls:sys_exit_open { - print(argevent) - if (cpu() == this_cpu) { - exit() - } -} - diff --git a/drivers/staging/ktap/scripts/basic/ftrace.kp b/drivers/staging/ktap/scripts/basic/ftrace.kp deleted file mode 100644 index 9feca2b..0000000 --- a/drivers/staging/ktap/scripts/basic/ftrace.kp +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ktap - -trace ftrace:function /ip==mutex*/ { - print(cpu(), pid(), execname(), argevent) -} - diff --git a/drivers/staging/ktap/scripts/basic/function_time.kp b/drivers/staging/ktap/scripts/basic/function_time.kp deleted file mode 100644 index e7859a3..0000000 --- a/drivers/staging/ktap/scripts/basic/function_time.kp +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env ktap - -#Demo for thread-local variable -# -#Note this kind of function time tracing already handled concurrent issue, -#but not aware on the recursion problem, user need to aware this limitation, -#so don't use this script to trace function which could be called recursive. - -self = {} -count_max = 0 -count_min = 0 -count_num = 0 -total_time = 0 - -printf("measure time(us) of function vfs_read\n"); - -trace probe:vfs_read { - if (execname() == "ktap") { - return - } - - self[tid()] = gettimeofday_us() -} - -trace probe:vfs_read%return { - if (execname() == "ktap") { - return - } - - if (self[tid()] == nil) { - return - } - - local durtion = gettimeofday_us() - self[tid()] - if (durtion > count_max) { - count_max = durtion - } - local min = count_min - if (min == 0 || durtion < min) { - count_min = durtion - } - - count_num = count_num + 1 - total_time = total_time + durtion - - self[tid()] = nil -} - -trace_end { - printf("avg\tmax\tmin\n"); - printf("-------------------\n") - - printf("%d\t%d\t%d\n", total_time/count_num, - count_max, count_min) -} - - diff --git a/drivers/staging/ktap/scripts/basic/kretprobe.kp b/drivers/staging/ktap/scripts/basic/kretprobe.kp deleted file mode 100644 index 82de3cf..0000000 --- a/drivers/staging/ktap/scripts/basic/kretprobe.kp +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ktap - -trace probe:vfs_read%return fd=$retval { - print(execname(), argevent); -} - diff --git a/drivers/staging/ktap/scripts/game/tetris.kp b/drivers/staging/ktap/scripts/game/tetris.kp deleted file mode 100644 index 7125cd4..0000000 --- a/drivers/staging/ktap/scripts/game/tetris.kp +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/env ktap - -# -# Tetris KTAP Script -# -# Copyright (C) 2013/OCT/05 Tadaki SAKAI -# -# based on stapgames (Systemtap Game Collection) -# https://github.com/mhiramat/stapgames/blob/master/games/tetris.stp -# -# - Requirements -# Kernel Configuration: CONFIG_KPROBE_EVENT=y -# CONFIG_EVENT_TRACING=y -# CONFIG_PERF_EVENTS=y -# CONFIG_DEBUG_FS=y -# CPU Architecture : x86_64 -# -# - Setup -# $ sudo mount -t debugfs none /sys/kernel/debug/ -# -# $ git clone https://github.com/ktap/ktap -# $ cd ktap -# $ make 2>&1 | tee ../make.log -# $ sudo make load -# $ sudo sh -c 'echo 50000 > /sys/module/ktapvm/parameters/max_exec_count' -# -# - Run Tetris -# $ sudo ./ktap scripts/game/tetris.kp -# - - -# -# utils -# - -function rand(max) { - r = gettimeofday_us() - if (r < 0) { - r = r * -1 - } - return r % max -} - -color_table = {} -color_table["Black"] = 40 -color_table["Red"] = 41 -color_table["Green"] = 42 -color_table["Yellow"] = 43 -color_table["Blue"] = 44 -color_table["Purple"] = 45 -color_table["Cyan"] = 46 -color_table["White"] = 47 - -function get_color_number(txt) { - return color_table[txt] -} - -color_table_text = {} -color_table_text[40] = "Black" -color_table_text[41] = "Red" -color_table_text[42] = "Green" -color_table_text[43] = "Yellow" -color_table_text[44] = "Blue" -color_table_text[45] = "Purple" -color_table_text[46] = "Cyan" -color_table_text[47] = "White" - -function get_color_text(num) { - return color_table_text[num] -} - -function update_display() { - for (i = 0, 239, 1) { - if ((i % 12 - 11) != 0) { - tmp = "" - } else { - tmp = "\n" - } - - if (display_buffer[240 + i] == back_text) { - printf("%s%s", back_text, tmp) - } else { - ctext = display_buffer[240 + i] - ansi.set_color2(get_color_number(ctext), - get_color_number(ctext)) - printf(" %s", tmp) - ansi.reset_color() - } - - # clear the display buffer - display_buffer[240 + i] = display_buffer[i] - } - - printf("%d\n",point) -} - - -# -# global value -# - -key_code = 0 -point = 0 -block_number = 0 -height = 0 -height_update = 0 - -destination_position = {} -back_text = {} -block_color = {} -display_buffer = {} - -block_data0 = {} -block_data1 = {} -block_data2 = {} -block_data3 = {} -block_data4 = {} -block_data5 = {} -block_data6 = {} -block_table = {} - -# -# Initialize -# - -# Create blocks -# block is represented by the position from the center. -# Every block has "L" part in the center except for a bar. -block_data0[0] = -11 # non-"L" part for each block -block_data1[0] = -24 -block_data2[0] = 2 -block_data3[0] = 13 -block_data4[0] = -13 -block_data5[0] = -1 -block_data6[0] = 2 - -block_table[0] = block_data0 -block_table[1] = block_data1 -block_table[2] = block_data2 -block_table[3] = block_data3 -block_table[4] = block_data4 -block_table[5] = block_data5 -block_table[6] = block_data6 - -for (i = 0, len(block_table) - 1, 1) { - # common "L" part - block_table[i][1] = 0 - block_table[i][2] = 1 - block_table[i][3] = -12 -} - -block_table[6][3] = -1 # bar is not common -# Position: 1 row has 12 columns, -# and (x, y) is represented by h = x + y * 12.p -height = 17 # First block position (center) - -for (i = 0, 240, 1) { - # Wall and Floor (sentinel) - if (((i % 12) < 2) || (i > 228)) { - block_color = "White" - tmp = block_color - } else { - back_text = " " - tmp = back_text - } - display_buffer[i - 1] = tmp - display_buffer[240 + i - 1] = tmp -} - -block_number = rand(len(color_table) - 1) -block_color = get_color_text(block_number + 40) - -ansi.clear_screen() - - -# -# Key Input -# - -trace probe:kbd_event handle=%di event_type=%si event_code=%dx value=%cx { - # Only can run it in x86_64 - # - # Register follow x86_64 call conversion: - # - # x86_64: - # %rcx 4 argument - # %rdx 3 argument - # %rsi 2 argument - # %rdi 1 argument - - local event_code = arg4 - local value = arg5 - - if (value != 0) { - if ((event_code - 4) != 0) { - key_code = event_code - } - } -} - - -# -# timer -# - -tick-200ms { - ansi.clear_screen() - - f = 0 # move/rotate flag - - if (key_code != 0) { # if key is pressed - if(key_code != 103) { #move left or right - # d: movement direction - if ((key_code - 105) != 0) { - if ((key_code - 106) != 0) { - d = 0 - } else { - d = 1 - } - } else { - d = -1 - } - - for (i = 0, 3, 1) { # check if the block can be moved - # destination is free - if (display_buffer[height + - block_table[block_number][i] + d] - != back_text) { - f = 1 - } - } - # move if destinations of every block are free - if (f == 0) { - height = height + d - } - } else { # rotate - for (i = 0, 3, 1) { # check if block can be rotated - # each block position - p = block_table[block_number][i] - - # destination x pos(p/12 rounded) - v = (p * 2 + 252) / 24 - 10 - w = p - v * 12 # destination y pos - - # destination position - destination_position[i] = w * 12 - v - - # check if desetination is free - if (display_buffer[height + - destination_position[i]] != back_text) { - f = 1 - } - } - - if (f == 0) { - # rotate if destinations of every block - # are free - for (i = 0, 3, 1) { - block_table[block_number][i] = - destination_position[i] - } - } - } - } - key_code = 0 # clear the input key - - f = 0 - for (i = 0, 3, 1) { # drop 1 row - # check if destination is free - p = height + block_table[block_number][i] - if (display_buffer[12 + p] != back_text) { - f = 1 - } - - # copy the moving block to display buffer - display_buffer[240 + p] = block_color - } - - if ((f == 1) && (height == 17)) { - update_display() - exit() # exit if there are block at initial position - } - - height_update = !height_update - if (height_update != 0) { - if(f != 0) { # the block can't drop anymore - for (i = 0, 3, 1) { - # fix the block - display_buffer[height + - block_table[block_number][i]] = block_color - } - # determin the next block - block_number = rand(len(color_table) - 1) - - block_color = get_color_text(block_number + 40) - - height = 17 # make the block to initial position - } else { - height = height + 12 # drop the block 1 row - } - } - - k = 1 - for (i = 18, 0, -1) { #check if line is filled - # search for filled line - j = 10 - while ((j > 0) && - (display_buffer[i * 12 + j] != back_text)) { - j = j - 1 - } - - if (j == 0) { # filled! - # add a point: 1 line - 1 point, ..., tetris - 10points - point = point + k - k = k + 1 - - # drop every upper block - j = (i + 1) * 12 - i = i + 1 - while (j > 2 * 12) { - j = j - 1 - display_buffer[j] = display_buffer[j - 12] - } - } - } - - update_display() -} diff --git a/drivers/staging/ktap/scripts/helloworld.kp b/drivers/staging/ktap/scripts/helloworld.kp deleted file mode 100644 index 5673c15..0000000 --- a/drivers/staging/ktap/scripts/helloworld.kp +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env ktap - -print("Hello World! I am ktap") diff --git a/drivers/staging/ktap/scripts/interrupt/hardirq_time.kp b/drivers/staging/ktap/scripts/interrupt/hardirq_time.kp deleted file mode 100644 index 1d3c33e..0000000 --- a/drivers/staging/ktap/scripts/interrupt/hardirq_time.kp +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env ktap - -#this script output each average consumimg time of each hardirq -s = aggr_table() -map = {} - -trace irq:irq_handler_entry { - map[cpu()] = gettimeofday_us() -} - -trace irq:irq_handler_exit { - local entry_time = map[cpu()] - if (entry_time == nil) { - return; - } - - s[arg1] = avg(gettimeofday_us() - entry_time) - map[cpu()] = nil -} - -trace_end { - print("hardirq average executing time (us)") - histogram(s) -} - diff --git a/drivers/staging/ktap/scripts/interrupt/softirq_time.kp b/drivers/staging/ktap/scripts/interrupt/softirq_time.kp deleted file mode 100644 index 7e1a9d8..0000000 --- a/drivers/staging/ktap/scripts/interrupt/softirq_time.kp +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env ktap - -#this script output each average consumimg time of each softirq line -s = aggr_table() -map = {} - -trace irq:softirq_entry { - map[cpu()] = gettimeofday_us() -} - -trace irq:softirq_exit { - local entry_time = map[cpu()] - if (entry_time == nil) { - return; - } - - s[arg1] = avg(gettimeofday_us() - entry_time) - map[cpu()] = nil -} - -trace_end { - print("softirq average executing time (us)") - histogram(s) -} - diff --git a/drivers/staging/ktap/scripts/io/kprobes-do-sys-open.kp b/drivers/staging/ktap/scripts/io/kprobes-do-sys-open.kp deleted file mode 100644 index a15f911..0000000 --- a/drivers/staging/ktap/scripts/io/kprobes-do-sys-open.kp +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env ktap - -#Only can run it in x86_64 -# -#Register follow x86_64 call conversion: -# -#x86_64: -# %rcx 4 argument -# %rdx 3 argument -# %rsi 2 argument -# %rdi 1 argument - -trace probe:do_sys_open dfd=%di filename=%si flags=%dx mode=%cx { - printf("[do_sys_open entry]: (%s) open file (%s)\n", - execname(), user_string(arg3)) -} - -trace probe:do_sys_open%return fd=$retval { - printf("[do_sys_open exit]: return fd (%d)\n", arg3) -} diff --git a/drivers/staging/ktap/scripts/io/traceio.kp b/drivers/staging/ktap/scripts/io/traceio.kp deleted file mode 100644 index 8a95a25..0000000 --- a/drivers/staging/ktap/scripts/io/traceio.kp +++ /dev/null @@ -1,56 +0,0 @@ -#! /usr/bin/env ktap - -# Based on systemtap traceio.stp - -#this script is broken, fix it soon. - -reads = aggr_table() -writes = aggr_table() -total_io = aggr_table() - -trace syscalls:sys_exit_read { - reads[execname()] = sum(arg2) - total_io[execname()] = sum(arg2) -} - -trace syscalls:sys_exit_write { - writes[execname()] = sum(arg2) - total_io[execname()] = sum(arg2) -} - -function humanread_digit(bytes) { - if (bytes > 1024*1024*1024) { - return bytes/1024/1024/1024 - } elseif (bytes > 1024*1024) { - return bytes/1024/1024 - } elseif (bytes > 1024) { - return bytes/1024 - } else { - return bytes - } -} - -function humanread_x(bytes) { - if (bytes > 1024*1024*1024) { - return " GiB" - } elseif (bytes > 1024*1024) { - return " MiB" - } elseif (bytes > 1024) { - return " KiB" - } else { - return " B" - } -} - -tick-1s { - ansi.clear_screen() - for (exec, count in pairs(total_io)) { - local readnum = reads[exec] - local writenum = writes[exec] - printf("%15s r: %12d%s w: %12d%s\n", exec, - humanread_digit(readnum), humanread_x(readnum), - humanread_digit(writenum), humanread_x(writenum)) - } - printf("\n") -} - diff --git a/drivers/staging/ktap/scripts/mem/kmalloc-top.kp b/drivers/staging/ktap/scripts/mem/kmalloc-top.kp deleted file mode 100644 index f18ed9f..0000000 --- a/drivers/staging/ktap/scripts/mem/kmalloc-top.kp +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env ktap - -kmalloc_stack = {} - -trace kmem:kmalloc { - kmalloc_stack[backtrace()] += 1 -} - -tick-60s { - for (k, v in pairs(kmalloc_stack)) { - print(k) - printf("%d\n\n", v) - } - - exit() -} - diff --git a/drivers/staging/ktap/scripts/mem/kmem.kp b/drivers/staging/ktap/scripts/mem/kmem.kp deleted file mode 100644 index c6f2c99..0000000 --- a/drivers/staging/ktap/scripts/mem/kmem.kp +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env ktap - -count1 = 0 -trace kmem:kmalloc { - count1 = count1 + 1 -} - -count2 = 0 -trace kmem:kfree { - count2 = count2 + 1 -} - -count3 = 0 -trace kmem:mm_page_alloc { - count3 = count3 + 1 -} - -count4 = 0 -trace kmem:mm_page_free { - count4 = count4 + 1 -} - -trace_end { - print("\n") - print("kmem:kmalloc:\t", count1) - print("kmem:kfree:\t", count2) - print("kmem:mm_page_alloc:", count3) - print("kmem:mm_page_free:", count4) - print("trace ending\n") -} diff --git a/drivers/staging/ktap/scripts/profiling/function_profiler.kp b/drivers/staging/ktap/scripts/profiling/function_profiler.kp deleted file mode 100644 index 589017f..0000000 --- a/drivers/staging/ktap/scripts/profiling/function_profiler.kp +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ktap - -#kernel function profile -#You can use this script to know what function is called frequently, -#without enable CONFIG_FUNCTION_PROFILER in kernel. - -s = aggr_table() - -trace ftrace:function { - s[arg1] = count() -} - -trace_end { - histogram(s) -} - -#sample output -#^C -# value ------------- Distribution ------------- count -# sub_preempt_count | @@@@@ 34904 -# add_preempt_count | @@@@@ 33435 -# nsecs_to_jiffies64 | @@@ 19919 -# irqtime_account_process_tick... | @ 9970 -# account_idle_time | @ 9880 -# _raw_spin_lock | 5100 -# _raw_spin_unlock | 5021 -# _raw_spin_unlock_irqrestore | 4235 -# _raw_spin_lock_irqsave | 4232 -# __rcu_read_lock | 3373 -# __rcu_read_unlock | 3373 -# lookup_address | 2392 -# pfn_range_is_mapped | 2384 -# update_cfs_rq_blocked_load | 1983 -# idle_cpu | 1808 -# ktime_get | 1394 -# _raw_spin_unlock_irq | 1270 -# _raw_spin_lock_irq | 1091 -# update_curr | 950 -# irqtime_account_irq | 950 -# ... | -# diff --git a/drivers/staging/ktap/scripts/profiling/stack_profile.kp b/drivers/staging/ktap/scripts/profiling/stack_profile.kp deleted file mode 100644 index 9794560..0000000 --- a/drivers/staging/ktap/scripts/profiling/stack_profile.kp +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ktap - -# This ktap script samples stacktrace of system per 10us, -# you can use generated output to make a flame graph. -# -# Flame Graphs: -# http://dtrace.org/blogs/brendan/2012/03/17/linux-kernel-performance-flame-graphs/ - -s = aggr_table() - -profile-10us { - s[backtrace()] = count() -} - -tick-60s { - exit() -} - -trace_end { - for (k, v in pairs(s)) { - print(k) - print(v) - print() - } -} - diff --git a/drivers/staging/ktap/scripts/schedule/sched_transition.kp b/drivers/staging/ktap/scripts/schedule/sched_transition.kp deleted file mode 100644 index eb54b09..0000000 --- a/drivers/staging/ktap/scripts/schedule/sched_transition.kp +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env ktap - -trace sched:sched_switch { - printf("%s ... ", arg1) -} diff --git a/drivers/staging/ktap/scripts/schedule/schedtimes.kp b/drivers/staging/ktap/scripts/schedule/schedtimes.kp deleted file mode 100644 index acef904..0000000 --- a/drivers/staging/ktap/scripts/schedule/schedtimes.kp +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/vin/env ktap - -#schedtimer.kp -#Initially inspired by Systemtap schedtimes.stp -#and more bugfree compare with Systemtap's version -# -#Note that the time value is associate with pid, not with execname strictly, -#sometime you will found there have sleep time for command "ls", the reason -#is that sleep time is belong to parent process bash, so clear on this. - -RUNNING = 0 -QUEUED = 1 -SLEEPING = 2 -DEAD = 64 - -run_time = {} -queued_time = {} -sleep_time = {} -io_wait_time = {} - -pid_state = {} -pid_names = {} -prev_timestamp = {} -io_wait = {} - -trace sched:sched_switch { - local prev_comm = arg1 - local prev_pid = arg2 - local prev_state = arg4 - local next_comm = arg5 - local next_pid = arg6 - local t = gettimeofday_us() - - if (pid_state[prev_pid] == nil) { - #do nothing - } elseif (pid_state[prev_pid] == RUNNING) { - run_time[prev_pid] += t - prev_timestamp[prev_pid] - } elseif (pid_state[prev_pid] == QUEUED) { - #found this: - #sched_wakeup comm=foo - #sched_switch prev_comm=foo - run_time[prev_pid] += t - prev_timestamp[prev_pid] - } - - pid_names[prev_pid] = prev_comm - prev_timestamp[prev_pid] = t - - if (prev_state == DEAD) { - pid_state[prev_pid] = DEAD - } elseif (prev_state > 0) { - if (in_iowait() == 1) { - io_wait[prev_pid] = 1 - } - pid_state[prev_pid] = SLEEPING - } elseif (prev_state == 0) { - pid_state[prev_pid] = QUEUED - } - - if (pid_state[next_pid] == nil) { - pid_state[next_pid] = RUNNING - } elseif (pid_state[next_pid] == QUEUED) { - queued_time[next_pid] += t - prev_timestamp[next_pid] - pid_state[next_pid] = RUNNING - } - - pid_names[next_pid] = next_comm - prev_timestamp[next_pid] = t -} - -trace sched:sched_wakeup, sched:sched_wakeup_new { - local comm = arg1 - local wakeup_pid = arg2 - local success = arg4 - local t = gettimeofday_us() - - if (pid_state[wakeup_pid] == nil) { - #do nothing - } elseif (pid_state[wakeup_pid] == SLEEPING) { - local durtion = t - prev_timestamp[wakeup_pid] - - sleep_time[wakeup_pid] += durtion - if (io_wait[wakeup_pid] == 1) { - io_wait_time[wakeup_pid] += durtion - io_wait[wakeup_pid] = 0 - } - } elseif (pid_state[wakeup_pid] == RUNNING) { - return - } - - pid_names[wakeup_pid] = comm - prev_timestamp[wakeup_pid] = t - pid_state[wakeup_pid] = QUEUED -} - -trace_end { - local t = gettimeofday_us() - - for (pid, state in pairs(pid_state)) { - local durtion = t - prev_timestamp[pid] - if (state == SLEEPING) { - sleep_time[pid] += durtion - } elseif (state == QUEUED) { - queued_time[pid] += durtion - } elseif (state == RUNNING) { - run_time[pid] += durtion - } - } - - printf ("%16s: %6s %10s %10s %10s %10s %10s\n\n", - "execname", "pid", "run(us)", "sleep(us)", "io_wait(us)", - "queued(us)", "total(us)") - - for (pid, time in pairs(run_time)) { - if (sleep_time[pid] == nil) { - sleep_time[pid] = 0 - } - if (queued_time[pid] == nil) { - queue_time[pid] = 0 - } - printf("%16s: %6d %10d %10d %10d %10d %10d\n", - pid_names[pid], pid, run_time[pid], sleep_time[pid], - io_wait_time[pid], queued_time[pid], - run_time[pid] + sleep_time[pid] + queued_time[pid]); - } -} diff --git a/drivers/staging/ktap/scripts/syscalls/errinfo.kp b/drivers/staging/ktap/scripts/syscalls/errinfo.kp deleted file mode 100644 index 049031b..0000000 --- a/drivers/staging/ktap/scripts/syscalls/errinfo.kp +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env ktap - -#errdesc get from include/uapi/asm-generic/errno*.h -errdesc = { - [1] = "Operation not permitted", #EPERM - [2] = "No such file or directory", #ENOENT - [3] = "No such process", #ESRCH - [4] = "Interrupted system call", #EINRT - [5] = "I/O error", #EIO - [6] = "No such device or address", #ENXIO - [7] = "Argument list too long", #E2BIG - [8] = "Exec format error", #ENOEXEC - [9] = "Bad file number", #EBADF - [10] = "No child processes", #ECHILD - [11] = "Try again", #EAGAIN - [12] = "Out of memory", #ENOMEM - [13] = "Permission denied", #EACCES - [14] = "Bad address", #EFAULT - [15] = "Block device required", #ENOTBLK - [16] = "Device or resource busy", #EBUSY - [17] = "File exists", #EEXIST - [18] = "Cross-device link", #EXDEV - [19] = "No such device", #ENODEV - [20] = "Not a directory", #ENOTDIR - [21] = "Is a directory", #EISDIR - [22] = "Invalid argument", #EINVAL - [23] = "File table overflow", #ENFILE - [24] = "Too many open files", #EMFILE - [25] = "Not a typewriter", #ENOTTY - [26] = "Text file busy", #ETXTBSY - [27] = "File too large", #EFBIG - [28] = "No space left on device", #ENOSPC - [29] = "Illegal seek", #ESPIPE - [30] = "Read-only file system", #EROFS - [31] = "Too many links", #EMLINK - [32] = "Broken pipe", #EPIPE - [33] = "Math argument out of domain of func", #EDOM - [34] = "Math result not representable", #ERANGE - - [35] = "Resource deadlock would occur", #EDEADLK - [36] = "File name too long", #ENAMETOOLONG - [37] = "No record locks available", #ENOLCK - [38] = "Function not implemented", #ENOSYS - [39] = "Directory not empty", #ENOTEMPTY - [40] = "Too many symbolic links encountered", #ELOOP - [42] = "No message of desired type", #ENOMSG - [43] = "Identifier removed", #EIDRM - [44] = "Channel number out of range", #ECHRNG - [45] = "Level 2 not synchronized", #EL2NSYNC - [46] = "Level 3 halted", #EL3HLT - [47] = "Level 3 reset", #EL3RST - [48] = "Link number out of range", #ELNRNG - [49] = "Protocol driver not attached", #EUNATCH - [50] = "No CSI structure available", #ENOCSI - [51] = "Level 2 halted", #EL2HLT - [52] = "Invalid exchange", #EBADE - [53] = "Invalid request descriptor", #EBADR - [54] = "Exchange full", #EXFULL - [55] = "No anode", #ENOANO - [56] = "Invalid request code", #EBADRQC - [57] = "Invalid slot", #EBADSLT - - [59] = "Bad font file format", #EBFONT - [60] = "Device not a stream", #ENOSTR - [61] = "No data available", #ENODATA - [62] = "Timer expired", #ETIME - [63] = "Out of streams resources", #ENOSR - [64] = "Machine is not on the network", #ENONET - [65] = "Package not installed", #ENOPKG - [66] = "Object is remote", #EREMOTE - [67] = "Link has been severed", #ENOLINK - [68] = "Advertise error", #EADV - [69] = "Srmount error", #ESRMNT - [70] = "Communication error on send", #ECOMM - [71] = "Protocol error", #EPROTO - [72] = "Multihop attempted", #EMULTIHOP - [73] = "RFS specific error", #EDOTDOT - [74] = "Not a data message", #EBADMSG - [75] = "Value too large for defined data type", #EOVERFLOW - [76] = "Name not unique on network", #ENOTUNIQ - [77] = "File descriptor in bad state", #EBADFD - [78] = "Remote address changed", #EREMCHG - [79] = "Can not access a needed shared library", #ELIBACC - [80] = "Accessing a corrupted shared library", #ELIBBAD - [81] = ".lib section in a.out corrupted", #ELIBSCN - [82] = "Attempting to link in too many shared libraries", #ELIBMAX - [83] = "Cannot exec a shared library directly", #ELIBEXEC - [84] = "Illegal byte sequence", #EILSEQ - [85] = "Interrupted system call should be restarted", #ERESTART - [86] = "Streams pipe error", #ESTRPIPE - [87] = "Too many users", #EUSERS - [88] = "Socket operation on non-socket", #ENOTSOCK - [89] = "Destination address required", #EDESTADDRREQ - [90] = "Message too long", #EMSGSIZE - [91] = "Protocol wrong type for socket", #EPROTOTYPE - [92] = "Protocol not available", #ENOPROTOOPT - [93] = "Protocol not supported", #EPROTONOSUPPORT - [94] = "Socket type not supported", #ESOCKTNOSUPPORT - [95] = "Operation not supported on transport endpoint", #EOPNOTSUPP - [96] = "Protocol family not supported", #EPFNOSUPPORT - [97] = "Address family not supported by protocol", #EAFNOSUPPORT - [98] = "Address already in use", #EADDRINUSE - [99] = "Cannot assign requested address", #EADDRNOTAVAIL - [100] = "Network is down", #ENETDOWN - [101] = "Network is unreachable", #ENETUNREACH - [102] = "Network dropped connection because of reset", #ENETRESET - [103] = "Software caused connection abort", #ECONNABORTED - [104] = "Connection reset by peer", #ECONNRESET - [105] = "No buffer space available", #ENOBUFS - [106] = "Transport endpoint is already connected", #EISCONN - [107] = "Transport endpoint is not connected", #ENOTCONN - [108] = " Cannot send after transport endpoint shutdown", #ESHUTDOWN - [109] = "Too many references: cannot splice", #ETOOMANYREFS - [110] = "Connection timed out", #ETIMEDOUT - [111] = "Connection refused", #ECONNREFUSED - [112] = "Host is down", #EHOSTDOWN - [113] = "No route to host", #EHOSTUNREACH - [114] = "Operation already in progress", #EALREADY - [115] = "Operation now in progress", #EINPROGRESS - [116] = "Stale NFS file handle", #ESTALE - [117] = "Structure needs cleaning", #EUCLEAN - [118] = "Not a XENIX named type file", #ENOTNAM - [119] = "No XENIX semaphores available", #ENAVAIL - [120] = "Is a named type file", #EISNAM - [121] = "Remote I/O error", #EREMOTEIO - [122] = "Quota exceeded", #EDQUOT - [123] = "No medium found", #ENOMEDIUM - [124] = "Wrong medium type", #EMEDIUMTYPE - [125] = "Operation Canceled", #ECANCELED - [126] = "Required key not available", #ENOKEY - [127] = "Key has expired", #EKEYEXPIRED - [128] = "Key has been revoked", #EKEYREVOKED - [129] = "Key was rejected by service", #EKEYREJECTED - [130] = "Owner died", #EOWNERDEAD - [131] = "State not recoverable", #ENOTRECOVERABLE - -} - -trace syscalls:sys_exit_* { - if (arg2 < 0) { - local errno = -arg2 - printf("%-15s%-20s\t%d\t%-30s\n", - execname(), argname, errno, errdesc[errno]) - } -} diff --git a/drivers/staging/ktap/scripts/syscalls/sctop.kp b/drivers/staging/ktap/scripts/syscalls/sctop.kp deleted file mode 100644 index 6df45cb..0000000 --- a/drivers/staging/ktap/scripts/syscalls/sctop.kp +++ /dev/null @@ -1,14 +0,0 @@ -#! /usr/bin/env ktap - -#this script is broken, fix it soon. -s = {} - -trace syscalls:sys_enter_* { - s[argname] += 1 -} - -tick-5s { - ansi.clear_screen() - histogram(s) - delete(s) -} diff --git a/drivers/staging/ktap/scripts/syscalls/syscalls.kp b/drivers/staging/ktap/scripts/syscalls/syscalls.kp deleted file mode 100644 index 8bbaaca..0000000 --- a/drivers/staging/ktap/scripts/syscalls/syscalls.kp +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ktap - -trace syscalls:* { - print(cpu(), pid(), execname(), argevent) -} - diff --git a/drivers/staging/ktap/scripts/syscalls/syscalls_count.kp b/drivers/staging/ktap/scripts/syscalls/syscalls_count.kp deleted file mode 100644 index 363c622..0000000 --- a/drivers/staging/ktap/scripts/syscalls/syscalls_count.kp +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env ktap - -s = aggr_table() - -trace syscalls:sys_enter_* { - s[argname] = count() -} - -trace_end { - histogram(s) -} - -print("Press Control-C to stop.") - -#Result: -# -#[root@jovi ktap]# ./ktap scripts/syscalls_histogram.kp -#^C -# value ------------- Distribution ------------- count -# sys_enter_rt_sigprocmask |@@@@@@ 326 -# sys_enter_read |@@@@@ 287 -# sys_enter_close |@@@@ 236 -# sys_enter_open |@@@@ 222 -# sys_enter_stat64 |@@ 132 -# sys_enter_select |@@ 123 -# sys_enter_rt_sigaction |@@ 107 -# sys_enter_poll |@ 72 -# sys_enter_write |@ 70 -# sys_enter_mmap_pgoff |@ 58 -# sys_enter_fstat64 | 41 -# sys_enter_nanosleep | 23 -# sys_enter_access | 20 -# sys_enter_mprotect | 18 -# sys_enter_geteuid | 17 -# sys_enter_getegid | 16 -# sys_enter_getuid | 16 -# sys_enter_getgid | 16 -# sys_enter_brk | 15 -# sys_enter_waitpid | 11 -# sys_enter_time | 10 -# sys_enter_ioctl | 9 -# sys_enter_munmap | 9 -# sys_enter_fcntl64 | 7 -# sys_enter_dup2 | 7 -# sys_enter_clone | 6 -# sys_enter_exit_group | 6 -# sys_enter_execve | 4 -# sys_enter_pipe | 3 -# sys_enter_gettimeofday | 3 -# sys_enter_getdents | 2 -# sys_enter_getgroups | 2 -# sys_enter_statfs64 | 2 -# sys_enter_lseek | 2 -# sys_enter_openat | 1 -# sys_enter_newuname | 1 - diff --git a/drivers/staging/ktap/scripts/syscalls/syscalls_count_by_proc.kp b/drivers/staging/ktap/scripts/syscalls/syscalls_count_by_proc.kp deleted file mode 100644 index 7b7d722..0000000 --- a/drivers/staging/ktap/scripts/syscalls/syscalls_count_by_proc.kp +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env ktap - -s = aggr_table() - -trace syscalls:sys_enter_* { - s[execname()] = count() -} - -trace_end { - histogram(s) -} - -print("Press Control-C to stop.") - -#Result: -# -#[root@jovi ktap]# ./ktap scripts/syscalls_histogram2.kp -#^C -# value ------------- Distribution ------------- count -# sshd |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 196 -# iscsid |@@@@ 24 -# sendmail |@ 9 - - diff --git a/drivers/staging/ktap/scripts/tracepoints/eventcount.kp b/drivers/staging/ktap/scripts/tracepoints/eventcount.kp deleted file mode 100644 index 9bc357f..0000000 --- a/drivers/staging/ktap/scripts/tracepoints/eventcount.kp +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env ktap - -# showing all tracepoints in histogram style - -s = {} - -trace *:* { - s[argname] += 1 -} - -trace_end { - histogram(s) -} - -print("Press Control-C to stop.") - -#Results: -#^C -# -# value ------------- Distribution ------------- count -# rcu_utilization |@@@@@ 225289 -# cpu_idle |@@@ 120168 -# sched_wakeup |@@ 91950 -# timer_cancel |@@ 91232 -# timer_start |@@ 91201 -# sched_stat_sleep |@@ 90981 -# timer_expire_exit |@@ 90634 -# timer_expire_entry |@@ 90625 -# hrtimer_cancel |@ 75411 -# hrtimer_start |@ 74946 -# softirq_raise |@ 63117 -# softirq_exit |@ 63109 -# softirq_entry |@ 63094 -# sched_switch |@ 62331 -# sched_stat_wait |@ 60491 -# hrtimer_expire_exit |@ 47538 -# hrtimer_expire_entry |@ 47530 -# sched_stat_runtime | 2780 -# kmem_cache_free | 2684 -# kmem_cache_alloc | 2415 -# kfree | 2288 -# sys_exit | 2145 -# sys_enter | 2145 -# sys_exit_rt_sigprocmask | 1000 -# sys_enter_rt_sigprocmask | 1000 -# timer_init | 912 -# sched_stat_blocked | 685 -# kmalloc | 667 -# workqueue_execute_end | 621 -# workqueue_execute_start | 621 -# sys_enter_select | 566 -# sys_exit_select | 566 -# sys_enter_read | 526 -# sys_exit_read | 526 -# mm_page_free | 478 -# mm_page_alloc | 427 -# mm_page_free_batched | 382 -# net_dev_queue | 296 -# net_dev_xmit | 296 -# consume_skb | 296 -# sys_exit_write | 290 -# sys_enter_write | 290 -# kfree_skb | 289 -# kmem_cache_alloc_node | 269 -# kmalloc_node | 263 -# sys_enter_close | 249 -# sys_exit_close | 249 -# hrtimer_init | 248 -# netif_receive_skb | 242 -# sys_enter_open | 237 -# sys_exit_open | 237 -# napi_poll | 226 -# sched_migrate_task | 207 -# sys_exit_poll | 173 -# sys_enter_poll | 173 -# workqueue_queue_work | 152 -# workqueue_activate_work | 152 -# sys_enter_stat64 | 133 -# sys_exit_stat64 | 133 -# sys_exit_rt_sigaction | 133 -# sys_enter_rt_sigaction | 133 -# irq_handler_entry | 125 -# irq_handler_exit | 125 -# mm_page_alloc_zone_locked | 99 -# sys_exit_mmap_pgoff | 66 -# sys_enter_mmap_pgoff | 66 -# sys_exit_fstat64 | 54 -# sys_enter_fstat64 | 54 -# sys_enter_nanosleep | 51 -# sys_exit_nanosleep | 51 -# block_bio_queue | 46 -# block_bio_remap | 46 -# block_bio_complete | 46 -# mix_pool_bytes | 44 -# mm_page_pcpu_drain | 31 -# sys_exit_time | 23 -# sys_enter_time | 23 -# sys_exit_access | 20 -# sys_enter_access | 20 -# mix_pool_bytes_nolock | 18 -# sys_enter_mprotect | 18 -# sys_exit_mprotect | 18 -# sys_enter_geteuid | 17 -# sys_exit_geteuid | 17 -# sys_enter_munmap | 17 -# sys_exit_munmap | 17 -# block_getrq | 16 -# sys_enter_getuid | 16 -# sys_enter_getgid | 16 -# sys_exit_getgid | 16 -# sys_exit_getuid | 16 -# block_rq_issue | 16 -# scsi_dispatch_cmd_start | 16 -# block_rq_complete | 16 -# scsi_dispatch_cmd_done | 16 -# sys_enter_getegid | 16 -# sys_exit_getegid | 16 -# block_rq_insert | 16 -# skb_copy_datagram_iovec | 15 -# sys_enter_brk | 15 -# sys_exit_brk | 15 -# credit_entropy_bits | 14 -# wbc_writepage | 14 -# sys_exit_clone | 12 -# block_touch_buffer | 12 -# sched_process_wait | 11 -# sys_enter_waitpid | 11 -# sys_exit_waitpid | 11 -# writeback_written | 10 -# writeback_start | 10 -# writeback_queue_io | 10 -# ext4_es_lookup_extent_enter | 9 -# sys_enter_ioctl | 9 -# sys_exit_ioctl | 9 -# ext4_ext_map_blocks_enter | 9 -# ext4_ext_map_blocks_exit | 9 -# ext4_es_lookup_extent_exit | 9 -# ext4_es_insert_extent | 9 -# ext4_ext_show_extent | 8 -# extract_entropy | 8 -#ext4_es_find_delayed_extent_exit | 8 -# ext4_es_find_delayed_extent_... | 8 -# writeback_pages_written | 7 -# sys_exit_dup2 | 7 -# sys_enter_dup2 | 7 -# signal_generate | 7 -# sys_enter_fcntl64 | 7 -# sys_exit_fcntl64 | 7 -# global_dirty_state | 7 -# writeback_dirty_inode_start | 7 -# block_bio_backmerge | 7 -# writeback_dirty_inode | 7 -# sched_wakeup_new | 6 -# sched_process_free | 6 -# sys_enter_exit_group | 6 -# task_newtask | 6 -# sys_enter_clone | 6 -# sched_process_fork | 6 -# sched_process_exit | 6 -# sys_exit_gettimeofday | 5 -# signal_deliver | 5 -# sys_enter_gettimeofday | 5 -# writeback_single_inode | 4 -# sys_enter_execve | 4 -# task_rename | 4 -# sched_process_exec | 4 -# block_dirty_buffer | 4 -# sys_exit_execve | 4 -# block_unplug | 4 -# sched_stat_iowait | 4 -# writeback_single_inode_start | 4 -# block_plug | 4 -# writeback_write_inode | 3 -# sys_enter_pipe | 3 -# writeback_dirty_page | 3 -# writeback_write_inode_start | 3 -# ext4_mark_inode_dirty | 3 -# ext4_journal_start | 3 -# sys_exit_pipe | 3 -# jbd2_drop_transaction | 2 -# jbd2_commit_locking | 2 -# jbd2_commit_flushing | 2 -# jbd2_handle_start | 2 -# jbd2_run_stats | 2 -# sys_exit_getdents | 2 -# jbd2_checkpoint_stats | 2 -# sys_enter_getgroups | 2 -# jbd2_start_commit | 2 -# jbd2_end_commit | 2 -# ext4_da_writepages | 2 -# jbd2_handle_stats | 2 -# sys_enter_statfs64 | 2 -# sys_exit_statfs64 | 2 -# sys_exit_getgroups | 2 -# sys_exit_lseek | 2 -# sys_enter_lseek | 2 -# sys_enter_getdents | 2 -# ext4_da_write_pages | 2 -# jbd2_commit_logging | 2 -# ext4_request_blocks | 1 -# sys_exit_openat | 1 -# ext4_discard_preallocations | 1 -# ext4_mballoc_alloc | 1 -# sys_enter_openat | 1 -# ext4_da_writepages_result | 1 -# ext4_allocate_blocks | 1 -# sys_enter_newuname | 1 -# ext4_da_update_reserve_space | 1 -# ext4_get_reserved_cluster_alloc | 1 -# sys_exit_newuname | 1 -# writeback_wake_thread | 1 - diff --git a/drivers/staging/ktap/scripts/tracepoints/eventcount_by_proc.kp b/drivers/staging/ktap/scripts/tracepoints/eventcount_by_proc.kp deleted file mode 100644 index 8706f73..0000000 --- a/drivers/staging/ktap/scripts/tracepoints/eventcount_by_proc.kp +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env ktap - -# showing all tracepoints in histogram style - -s = aggr_table() - -trace *:* { - s[execname()] = count() -} - -trace_end { - histogram(s) -} - -print("Press Control-C to stop.") - -#Results: -#^C -# value ------------- Distribution ------------- count -# swapper/0 |@@@@@@@@@@@@ 354378 -# swapper/1 |@@@@@@@@@@ 284984 -# ps |@@@@ 115697 -# ksmtuned |@@@ 95857 -# iscsid |@@ 80008 -# awk |@ 30354 -# irqbalance | 16530 -# rcu_sched | 15892 -# sendmail | 14463 -# kworker/0:1 | 10540 -# kworker/u4:2 | 9250 -# kworker/1:2 | 7943 -# sleep | 7555 -# crond | 3911 -# ksoftirqd/0 | 3817 -# sshd | 2849 -# systemd-journal | 2209 -# migration/1 | 1601 -# migration/0 | 1350 -# dhclient | 1343 -# nm-dhcp-client. | 1208 -# ksoftirqd/1 | 1064 -# watchdog/1 | 966 -# watchdog/0 | 964 -# khugepaged | 776 -# dbus-daemon | 611 -# rpcbind | 607 -# gdbus | 529 -# NetworkManager | 399 -# jbd2/dm-1-8 | 378 -# modem-manager | 184 -# abrt-watch-log | 157 -# polkitd | 156 -# rs:main Q:Reg | 153 -# avahi-daemon | 151 -# rsyslogd | 102 -# systemd | 96 -# kworker/0:1H | 45 -# smartd | 30 - diff --git a/drivers/staging/ktap/scripts/tracepoints/tracepoints.kp b/drivers/staging/ktap/scripts/tracepoints/tracepoints.kp deleted file mode 100644 index 5d08869..0000000 --- a/drivers/staging/ktap/scripts/tracepoints/tracepoints.kp +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ktap - -trace *:* { - print(cpu(), pid(), execname(), argevent) -} - diff --git a/drivers/staging/ktap/scripts/userspace/uprobes-malloc.kp b/drivers/staging/ktap/scripts/userspace/uprobes-malloc.kp deleted file mode 100644 index 14c172f..0000000 --- a/drivers/staging/ktap/scripts/userspace/uprobes-malloc.kp +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env ktap - -trace probe:/lib/libc.so.6:0x000773c0 { - print("entry:", execname(), argevent) -} - -trace probe:/lib/libc.so.6:0x000773c0%return { - print("exit:", execname(), argevent) -} diff --git a/drivers/staging/ktap/test/aggr_table.kp b/drivers/staging/ktap/test/aggr_table.kp deleted file mode 100644 index 985b634..0000000 --- a/drivers/staging/ktap/test/aggr_table.kp +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#---------------------------------# - -s = aggr_table() - -s["count"] = count() -s["count"] = count() -s["count"] = count() - -s["max"] = max(1) -s["max"] = max(0) -s["max"] = max(100) - -s["min"] = min(50) -s["min"] = min(2) -s["min"] = min(100) - -s["sum"] = sum(10) -s["sum"] = sum(20) -s["sum"] = sum(30) - -s["avg"] = avg(10) -s["avg"] = avg(20) -s["avg"] = avg(30) - -if (s["count"] != 3) { - failed() -} - -if (s["max"] != 100) { - failed() -} - -if (s["min"] != 2) { - failed() -} - -if (s["sum"] != 60) { - failed() -} - -if (s["avg"] != 20) { - failed() -} diff --git a/drivers/staging/ktap/test/ansi.kp b/drivers/staging/ktap/test/ansi.kp deleted file mode 100644 index e8a2783..0000000 --- a/drivers/staging/ktap/test/ansi.kp +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env ktap - -ansi.clear_screen() - -ansi.set_color(32) -printf("this line should be Green color\n") - -ansi.set_color(31) -printf("this line should be Red color\n") - -ansi.set_color2(34, 43) -printf("this line should be Blue color, with Yellow background\n") - -ansi.reset_color() -ansi.set_color3(34, 46, 4) -printf("this line should be Blue color, with Cyan background, underline single attribute\n") - -ansi.reset_color() -ansi.new_line() - diff --git a/drivers/staging/ktap/test/arg.kp b/drivers/staging/ktap/test/arg.kp deleted file mode 100644 index 0cf16eb..0000000 --- a/drivers/staging/ktap/test/arg.kp +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#-----------------------------------------# - -if (!arg[0]) { - failed() -} - -if (arg[1] != 1) { - failed() -} - -if (arg[2] != "testing") { - failed() -} - -if (arg[3] != "2 3 4") { - failed() -} diff --git a/drivers/staging/ktap/test/arith.kp b/drivers/staging/ktap/test/arith.kp deleted file mode 100644 index 32880a1..0000000 --- a/drivers/staging/ktap/test/arith.kp +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#-----------------------------------------# - -a = 4 -b = 5 - -if ((a + b) != 9) { - failed() -} - -if ((a - b) != -1) { - failed() -} - -if ((a % b) != 4) { - failed() -} - -if ((a / b) != 0) { - failed() -} diff --git a/drivers/staging/ktap/test/bench/sembench.c b/drivers/staging/ktap/test/bench/sembench.c deleted file mode 100644 index 0811934..0000000 --- a/drivers/staging/ktap/test/bench/sembench.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * copyright Oracle 2007. Licensed under GPLv2 - * To compile: gcc -Wall -o sembench sembench.c -lpthread - * - * usage: sembench -t thread count -w wakenum -r runtime -o op - * op can be: 0 (ipc sem) 1 (nanosleep) 2 (futexes) - * - * example: - * sembench -t 1024 -w 512 -r 60 -o 2 - * runs 1024 threads, waking up 512 at a time, running for 60 seconds using - * futex locking. - * - */ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 199309 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VERSION "0.2" - -/* futexes have been around since 2.5.something, but it still seems I - * need to make my own syscall. Sigh. - */ -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 -#define FUTEX_FD 2 -#define FUTEX_REQUEUE 3 -#define FUTEX_CMP_REQUEUE 4 -#define FUTEX_WAKE_OP 5 -static inline int futex (int *uaddr, int op, int val, - const struct timespec *timeout, - int *uaddr2, int val3) -{ - return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3); -} - -static void smp_mb(void) -{ - __sync_synchronize(); -} - -static int all_done = 0; -static int timeout_test = 0; - -#define SEMS_PERID 250 - -struct sem_operations; - -struct lockinfo { - unsigned long id; - unsigned long index; - int data; - pthread_t tid; - struct lockinfo *next; - struct sem_operations *ops; - unsigned long ready; -}; - -struct sem_wakeup_info { - int wakeup_count; - struct sembuf sb[SEMS_PERID]; -}; - -struct sem_operations { - void (*wait)(struct lockinfo *l); - int (*wake)(struct sem_wakeup_info *wi, int num_semids, int num); - void (*setup)(struct sem_wakeup_info **wi, int num_semids); - void (*cleanup)(int num_semids); - char *name; -}; - -int *semid_lookup = NULL; - -pthread_mutex_t worklist_mutex = PTHREAD_MUTEX_INITIALIZER; -static unsigned long total_burns = 0; -static unsigned long min_burns = ~0UL; -static unsigned long max_burns = 0; - -/* currently running threads */ -static int thread_count = 0; - -struct lockinfo *worklist = NULL; -static int workers_started = 0; - -/* total threads started */ -static int num_threads = 2048; - -static void worklist_add(struct lockinfo *l) -{ - smp_mb(); - l->ready = 1; -} - -static struct lockinfo *worklist_rm(void) -{ - static int last_index = 0; - int i; - struct lockinfo *l; - - for (i = 0; i < num_threads; i++) { - int test = (last_index + i) % num_threads; - - l = worklist + test; - smp_mb(); - if (l->ready) { - l->ready = 0; - last_index = test; - return l; - } - } - return NULL; -} - -/* ipc semaphore post& wait */ -void wait_ipc_sem(struct lockinfo *l) -{ - struct sembuf sb; - int ret; - struct timespec *tvp = NULL; - struct timespec tv = { 0, 1 }; - - sb.sem_num = l->index; - sb.sem_flg = 0; - - sb.sem_op = -1; - l->data = 1; - - if (timeout_test && (l->id % 5) == 0) - tvp = &tv; - - worklist_add(l); - ret = semtimedop(semid_lookup[l->id], &sb, 1, tvp); - - while(l->data != 0 && tvp) { - struct timespec tv2 = { 0, 500 }; - nanosleep(&tv2, NULL); - } - - if (l->data != 0) { - if (tvp) - return; - fprintf(stderr, "wakeup without data update\n"); - exit(1); - } - if (ret) { - if (errno == EAGAIN && tvp) - return; - perror("semtimed op"); - exit(1); - } -} - -int ipc_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) -{ - int i; - int ret; - struct lockinfo *l; - int found = 0; - - for (i = 0; i < num_semids; i++) { - wi[i].wakeup_count = 0; - } - while(num > 0) { - struct sembuf *sb; - l = worklist_rm(); - if (!l) - break; - if (l->data != 1) - fprintf(stderr, "warning, lockinfo data was %d\n", - l->data); - l->data = 0; - sb = wi[l->id].sb + wi[l->id].wakeup_count; - sb->sem_num = l->index; - sb->sem_op = 1; - sb->sem_flg = IPC_NOWAIT; - wi[l->id].wakeup_count++; - found++; - num--; - } - if (!found) - return 0; - for (i = 0; i < num_semids; i++) { - int wakeup_total; - int cur; - int offset = 0; - if (!wi[i].wakeup_count) - continue; - wakeup_total = wi[i].wakeup_count; - while(wakeup_total > 0) { - cur = wakeup_total > 64 ? 64 : wakeup_total; - ret = semtimedop(semid_lookup[i], wi[i].sb + offset, - cur, NULL); - if (ret) { - perror("semtimedop"); - exit(1); - } - offset += cur; - wakeup_total -= cur; - } - } - return found; -} - -void setup_ipc_sems(struct sem_wakeup_info **wi, int num_semids) -{ - int i; - *wi = malloc(sizeof(**wi) * num_semids); - semid_lookup = malloc(num_semids * sizeof(int)); - for(i = 0; i < num_semids; i++) { - semid_lookup[i] = semget(IPC_PRIVATE, SEMS_PERID, - IPC_CREAT | 0777); - if (semid_lookup[i] < 0) { - perror("semget"); - exit(1); - } - } - sleep(10); -} - -void cleanup_ipc_sems(int num) -{ - int i; - for (i = 0; i < num; i++) { - semctl(semid_lookup[i], 0, IPC_RMID); - } -} - -struct sem_operations ipc_sem_ops = { - .wait = wait_ipc_sem, - .wake = ipc_wake_some, - .setup = setup_ipc_sems, - .cleanup = cleanup_ipc_sems, - .name = "ipc sem operations", -}; - -/* futex post & wait */ -void wait_futex_sem(struct lockinfo *l) -{ - int ret; - l->data = 1; - worklist_add(l); - while(l->data == 1) { - ret = futex(&l->data, FUTEX_WAIT, 1, NULL, NULL, 0); - /* - if (ret && ret != EWOULDBLOCK) { - perror("futex wait"); - exit(1); - }*/ - } -} - -int futex_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) -{ - int i; - int ret; - struct lockinfo *l; - int found = 0; - - for (i = 0; i < num; i++) { - l = worklist_rm(); - if (!l) - break; - if (l->data != 1) - fprintf(stderr, "warning, lockinfo data was %d\n", - l->data); - l->data = 0; - ret = futex(&l->data, FUTEX_WAKE, 1, NULL, NULL, 0); - if (ret < 0) { - perror("futex wake"); - exit(1); - } - found++; - } - return found; -} - -void setup_futex_sems(struct sem_wakeup_info **wi, int num_semids) -{ - return; -} - -void cleanup_futex_sems(int num) -{ - return; -} - -struct sem_operations futex_sem_ops = { - .wait = wait_futex_sem, - .wake = futex_wake_some, - .setup = setup_futex_sems, - .cleanup = cleanup_futex_sems, - .name = "futex sem operations", -}; - -/* nanosleep sems here */ -void wait_nanosleep_sem(struct lockinfo *l) -{ - int ret; - struct timespec tv = { 0, 1000000 }; - int count = 0; - - l->data = 1; - worklist_add(l); - while(l->data) { - ret = nanosleep(&tv, NULL); - if (ret) { - perror("nanosleep"); - exit(1); - } - count++; - } -} - -int nanosleep_wake_some(struct sem_wakeup_info *wi, int num_semids, int num) -{ - int i; - struct lockinfo *l; - - for (i = 0; i < num; i++) { - l = worklist_rm(); - if (!l) - break; - if (l->data != 1) - fprintf(stderr, "warning, lockinfo data was %d\n", - l->data); - l->data = 0; - } - return i; -} - -void setup_nanosleep_sems(struct sem_wakeup_info **wi, int num_semids) -{ - return; -} - -void cleanup_nanosleep_sems(int num) -{ - return; -} - -struct sem_operations nanosleep_sem_ops = { - .wait = wait_nanosleep_sem, - .wake = nanosleep_wake_some, - .setup = setup_nanosleep_sems, - .cleanup = cleanup_nanosleep_sems, - .name = "nano sleep sem operations", -}; - -void *worker(void *arg) -{ - struct lockinfo *l = (struct lockinfo *)arg; - int burn_count = 0; - pthread_t tid = pthread_self(); - size_t pagesize = getpagesize(); - char *buf = malloc(pagesize); - - if (!buf) { - perror("malloc"); - exit(1); - } - - l->tid = tid; - workers_started = 1; - smp_mb(); - - while(!all_done) { - l->ops->wait(l); - if (all_done) - break; - burn_count++; - } - pthread_mutex_lock(&worklist_mutex); - total_burns += burn_count; - if (burn_count < min_burns) - min_burns = burn_count; - if (burn_count > max_burns) - max_burns = burn_count; - thread_count--; - pthread_mutex_unlock(&worklist_mutex); - return (void *)0; -} - -void print_usage(void) -{ - printf("usage: sembench [-t threads] [-w wake incr] [-r runtime]"); - printf(" [-o num] (0=ipc, 1=nanosleep, 2=futex)\n"); - exit(1); -} - -#define NUM_OPERATIONS 3 -struct sem_operations *allops[NUM_OPERATIONS] = { &ipc_sem_ops, - &nanosleep_sem_ops, - &futex_sem_ops}; - -int main(int ac, char **av) { - int ret; - int i; - int semid = 0; - int sem_num = 0; - int burn_count = 0; - struct sem_wakeup_info *wi = NULL; - struct timeval start; - struct timeval now; - int num_semids = 0; - int wake_num = 256; - int run_secs = 30; - int pagesize = getpagesize(); - char *buf = malloc(pagesize); - struct sem_operations *ops = allops[0]; - cpu_set_t cpu_mask; - cpu_set_t target_mask; - int target_cpu = 0; - int max_cpu = -1; - - if (!buf) { - perror("malloc"); - exit(1); - } - for (i = 1; i < ac; i++) { - if (strcmp(av[i], "-t") == 0) { - if (i == ac -1) - print_usage(); - num_threads = atoi(av[i+1]); - i++; - } else if (strcmp(av[i], "-w") == 0) { - if (i == ac -1) - print_usage(); - wake_num = atoi(av[i+1]); - i++; - } else if (strcmp(av[i], "-r") == 0) { - if (i == ac -1) - print_usage(); - run_secs = atoi(av[i+1]); - i++; - } else if (strcmp(av[i], "-o") == 0) { - int index; - if (i == ac -1) - print_usage(); - index = atoi(av[i+1]); - if (index >= NUM_OPERATIONS) { - fprintf(stderr, "invalid operations %d\n", - index); - exit(1); - } - ops = allops[index]; - i++; - } else if (strcmp(av[i], "-T") == 0) { - timeout_test = 1; - } else if (strcmp(av[i], "-h") == 0) { - print_usage(); - } - } - num_semids = (num_threads + SEMS_PERID - 1) / SEMS_PERID; - ops->setup(&wi, num_semids); - - ret = sched_getaffinity(0, sizeof(cpu_set_t), &cpu_mask); - if (ret) { - perror("sched_getaffinity"); - exit(1); - } - for (i = 0; i < CPU_SETSIZE; i++) - if (CPU_ISSET(i, &cpu_mask)) - max_cpu = i; - if (max_cpu == -1) { - fprintf(stderr, "sched_getaffinity returned empty mask\n"); - exit(1); - } - - CPU_ZERO(&target_mask); - - worklist = malloc(sizeof(*worklist) * num_threads); - memset(worklist, 0, sizeof(*worklist) * num_threads); - - for (i = 0; i < num_threads; i++) { - struct lockinfo *l; - pthread_t tid; - thread_count++; - l = worklist + i; - if (!l) { - perror("malloc"); - exit(1); - } - l->id = semid; - l->index = sem_num++; - l->ops = ops; - if (sem_num >= SEMS_PERID) { - semid++; - sem_num = 0; - } - ret = pthread_create(&tid, NULL, worker, (void *)l); - if (ret) { - perror("pthread_create"); - exit(1); - } - - while (!CPU_ISSET(target_cpu, &cpu_mask)) { - target_cpu++; - if (target_cpu > max_cpu) - target_cpu = 0; - } - CPU_SET(target_cpu, &target_mask); - ret = pthread_setaffinity_np(tid, sizeof(cpu_set_t), - &target_mask); - CPU_CLR(target_cpu, &target_mask); - target_cpu++; - - ret = pthread_detach(tid); - if (ret) { - perror("pthread_detach"); - exit(1); - } - } - while(!workers_started) { - smp_mb(); - usleep(200); - } - gettimeofday(&start, NULL); - fprintf(stderr, "main loop going\n"); - while(1) { - ops->wake(wi, num_semids, wake_num); - burn_count++; - gettimeofday(&now, NULL); - if (now.tv_sec - start.tv_sec >= run_secs) - break; - } - fprintf(stderr, "all done\n"); - all_done = 1; - while(thread_count > 0) { - ops->wake(wi, num_semids, wake_num); - usleep(200); - } - printf("%d threads, waking %d at a time\n", num_threads, wake_num); - printf("using %s\n", ops->name); - printf("main thread burns: %d\n", burn_count); - printf("worker burn count total %lu min %lu max %lu avg %lu\n", - total_burns, min_burns, max_burns, total_burns / num_threads); - printf("run time %d seconds %lu worker burns per second\n", - (int)(now.tv_sec - start.tv_sec), - total_burns / (now.tv_sec - start.tv_sec)); - ops->cleanup(num_semids); - return 0; -} - diff --git a/drivers/staging/ktap/test/bench/test.sh b/drivers/staging/ktap/test/bench/test.sh deleted file mode 100644 index 9f77969..0000000 --- a/drivers/staging/ktap/test/bench/test.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -gcc -o sembench sembench.c -O2 -lpthread - -COMMAND="./sembench -t 200 -w 20 -r 30 -o 2" - -echo -e "\n\t\tPass 1 without tracing" -$COMMAND -echo -e "\n\t\tPass 2 without tracing" -$COMMAND -echo -e "\n\t\tPass 3 without tracing" -$COMMAND - -echo "" - -KTAP_ONE_LINER="trace syscalls:sys_*_futex {}" - -echo -e "\n\t\tPass 1 with tracing" -../../ktap -e "$KTAP_ONE_LINER" -- $COMMAND -echo -e "\n\t\tPass 2 with tracing" -../../ktap -e "$KTAP_ONE_LINER" -- $COMMAND -echo -e "\n\t\tPass 3 with tracing" -../../ktap -e "$KTAP_ONE_LINER" -- $COMMAND - -rm -rf ./sembench diff --git a/drivers/staging/ktap/test/concat.kp b/drivers/staging/ktap/test/concat.kp deleted file mode 100644 index be77bb7..0000000 --- a/drivers/staging/ktap/test/concat.kp +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#----------------------------------------# - -a = "123" -b = "456" - -if (a..b != "123456") { - failed() -} diff --git a/drivers/staging/ktap/test/count.kp b/drivers/staging/ktap/test/count.kp deleted file mode 100644 index 26f962c..0000000 --- a/drivers/staging/ktap/test/count.kp +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#---------------------------------------# - -t = {} - -t["key"] += 1 -if (t["key"] != 1) { - failed() -} - -t["key"] += 1 -if (t["key"] != 2) { - failed() -} diff --git a/drivers/staging/ktap/test/fibonacci.kp b/drivers/staging/ktap/test/fibonacci.kp deleted file mode 100644 index 7e141da0..0000000 --- a/drivers/staging/ktap/test/fibonacci.kp +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#---------------fibonacci---------------- - - -#regular recursive fibonacci -function fib(n) { - if (n < 2) { - return n - } - return fib(n-1) + fib(n-2) -} - -if (fib(20) != 6765) { - failed() -} - -#tail recursive fibonacci -function fib(n) { - f = function (iter, res, next) { - if (iter == 0) { - return res; - } - return f(iter-1, next, res+next) - } - return f(n, 0, 1) -} - -if (fib(20) != 6765) { - failed() -} diff --git a/drivers/staging/ktap/test/function.kp b/drivers/staging/ktap/test/function.kp deleted file mode 100644 index bfbff26..0000000 --- a/drivers/staging/ktap/test/function.kp +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -### basic function call ### -function f1(a, b) { - return a + b -} - -if (f1(2, 3) != 5) { - failed(); -} - -### return string ### -function f2() { - return "function return" -} - -if (f2() != "function return") { - failed(); -} - -### mutli-value return ### -function f3(a, b) { - return a+b, a-b; -} - -c, d = f3(2, 3); -if(c != 5 || d != -1) { - failed(); -} - - -### closure testing ### -function f4() { - f5 = function(a, b) { - return a * b - } - return f5 -} - -local f = f4() -if (f(9, 9) != 81) { - failed(); -} - -### closure with lexcial variable ### -# issue: variable cannot be local -i = 1 -function f6() { - i = 5 - f7 = function(a, b) { - return a * b + i - } - return f7 -} - -f = f6() -if (f(9, 9) != 81 + i) { - failed(); -} - -i = 6 -if (f(9, 9) != 81 + i) { - failed(); -} - -### tail call -### stack should not overflow in tail call mechanism -a = 0 -function f8(i) { - if (i == 1000000) { - a = 1000000 - return - } - # must add return here, otherwise stack overflow - return f8(i+1) -} - -f8(0) -if (a != 1000000) { - failed(); -} - - diff --git a/drivers/staging/ktap/test/if.kp b/drivers/staging/ktap/test/if.kp deleted file mode 100644 index 3122084..0000000 --- a/drivers/staging/ktap/test/if.kp +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#-----------------------------------------# - -if (false) { - failed() -} - -if (nil) { - failed() -} - -# ktap only think false and nil is "real false", number 0 is true -# it's same as lua -# Might change it in future, to make similar with C -if (0) { - #failed() -} - diff --git a/drivers/staging/ktap/test/kprobe.kp b/drivers/staging/ktap/test/kprobe.kp deleted file mode 100644 index 022d4a7..0000000 --- a/drivers/staging/ktap/test/kprobe.kp +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ktap - -n = 0 -trace probe:schedule { - n = n + 1 -} - -tick-1s { - if (n == 0) { - printf("failed\n"); - } - exit() -} - diff --git a/drivers/staging/ktap/test/kretprobe.kp b/drivers/staging/ktap/test/kretprobe.kp deleted file mode 100644 index e311e84..0000000 --- a/drivers/staging/ktap/test/kretprobe.kp +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ktap - -n = 0 -trace probe:__schedule%return { - n = n + 1 -} - -tick-1s { - if (n == 0) { - printf("failed\n"); - } - exit() -} - diff --git a/drivers/staging/ktap/test/len.kp b/drivers/staging/ktap/test/len.kp deleted file mode 100644 index 697d915..0000000 --- a/drivers/staging/ktap/test/len.kp +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#-----------------------------------------# - -a = "123456789" - -if (len(a) != 9) { - failed() -} - -b = {} -b[0] = 0 -b[1] = 1 -b["keys"] = "values" - -if (len(b) != 3) { - failed() -} - - diff --git a/drivers/staging/ktap/test/looping.kp b/drivers/staging/ktap/test/looping.kp deleted file mode 100644 index fe48051..0000000 --- a/drivers/staging/ktap/test/looping.kp +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -### basic while-loop testing -a = 1 -while (a < 1000) { - a = a + 1 -} - -if (a != 1000) { - failed() -} - -### break testing -### Note that ktap don't have continue keyword -a = 1 -while (a < 1000) { - if (a == 10) { - break - } - a = a + 1 -} - -if (a != 10) { - failed() -} - -### for-loop testing -b=0 -for (c = 0, 1000, 1) { - b = b + 1 -} - -if (b != 1001) { - failed() -} diff --git a/drivers/staging/ktap/test/pairs.kp b/drivers/staging/ktap/test/pairs.kp deleted file mode 100644 index cdf3825..0000000 --- a/drivers/staging/ktap/test/pairs.kp +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#-----------------------------------------# - -t = {} -t[1] = 101 -t[2] = 102 -t[3] = 103 -t["key_1"] = "value_1" -t["key_2"] = "value_2" -t["key_3"] = "value_3" - -local n = 0 - -for (k, v in pairs(t)) { - n = n + 1 - - if (k == 1 && v != 101) { - failed() - } - if (k == 2 && v != 102) { - failed() - } - if (k == 3 && v != 103) { - failed() - } - if (k == "key_1" && v != "value_1") { - failed() - } - if (k == "key_2" && v != "value_2") { - failed() - } - if (k == "key_3" && v != "value_3") { - failed() - } -} - -if (n != len(t)) { - failed() -} diff --git a/drivers/staging/ktap/test/run_test.sh b/drivers/staging/ktap/test/run_test.sh deleted file mode 100644 index b98af26..0000000 --- a/drivers/staging/ktap/test/run_test.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh - -rmmod ktapvm > /dev/null 2>&1 -insmod ../ktapvm.ko -if test $? -ne 0; then - echo "Cannot insmod ../ktapvm.ko" - exit -1 -fi - -KTAP=../ktap -function ktaprun { - echo "$KTAP $@" - $KTAP $@ -} - - - -####################################################### -# Use $ktap directly if the arguments contains strings -$KTAP arg.kp 1 testing "2 3 4" -$KTAP -e 'print("one-liner testing")' -$KTAP -e 'exit()' -$KTAP -o /dev/null -e 'trace syscalls:* { print(argevent) }' \ - -- ls > /devnull - -$KTAP -o /dev/null -e 'trace syscalls:* { print(argevent) }' \ - -- $KTAP -e 'while (1) {}' - -ktaprun arith.kp -ktaprun concat.kp -ktaprun count.kp -ktaprun fibonacci.kp -ktaprun function.kp -ktaprun if.kp -ktaprun kprobe.kp -ktaprun kretprobe.kp -ktaprun len.kp -ktaprun looping.kp -ktaprun pairs.kp -ktaprun table.kp -ktaprun aggr_table.kp -ktaprun timer.kp -ktaprun tracepoint.kp -ktaprun -o /dev/null zerodivide.kp -ktaprun ansi.kp - -echo "testing kill deadloop ktap script" -$KTAP -e 'while (1) {}' & -pkill ktap -sleep 1 - -##################################################### -rmmod ktapvm -if test $? -ne 0; then - echo "Error in rmmod ../ktapvm.ko, leak module refcount?" - exit -1 -fi - diff --git a/drivers/staging/ktap/test/table.kp b/drivers/staging/ktap/test/table.kp deleted file mode 100644 index 1f6d6e4..0000000 --- a/drivers/staging/ktap/test/table.kp +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -### table testing ### -x = {} -x[1] = "1" -if (x[1] != "1") { - failed() -} - -x[1] = 22222222222222222222222222222222222222222 -if (x[1] != 22222222222222222222222222222222222222222) { - failed() -} - -x[1] = "jovi" -if (x[1] != "jovi") { - failed() -} - -x[11111111111111111111111111111111] = "jovi" -if (x[11111111111111111111111111111111] != "jovi") { - failed() -} - -x["jovi"] = 1 -if (x["jovi"] != 1) { - failed() -} - -x["long string....................................."] = 1 -if (x["long string....................................."] != 1) { - failed() -} - -# issue: subx must declare firstly, otherwise kernel will oops -subx = {} -subx["test"] = "this is test" -x["test"] = subx -if (x["test"]["test"] != "this is test") { - failed() -} - -tbl = {} -i = 1 -while (i < 100000) { - tbl[i] = i - i = i + 1 -} - -i = 1 -while (i < 100000) { - if (tbl[i] != i) { - failed() - } - i = i + 1 -} - -#### table initization -days = {"Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday"} - -if (days[2] != "Monday") { - failed() -} - - diff --git a/drivers/staging/ktap/test/timer.kp b/drivers/staging/ktap/test/timer.kp deleted file mode 100644 index 02e8a61..0000000 --- a/drivers/staging/ktap/test/timer.kp +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#---------------------------------------# - -n1 = 0 -n2 = 0 - -tick-1s { - n1 = n1 + 1 -} - -tick-1s { - n2 = n2 + 1 -} - -tick-4s { - if (n1 == 0 || n2 == 0) { - failed() - } - exit() -} - - diff --git a/drivers/staging/ktap/test/tracepoint.kp b/drivers/staging/ktap/test/tracepoint.kp deleted file mode 100644 index fb036e6..0000000 --- a/drivers/staging/ktap/test/tracepoint.kp +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env ktap - -function failed() { - printf("failed\n"); - exit(-1); -} - -#----------------------------------------# - -n = 0 - -trace sched:* { - n = n + 1 -} - -tick-1s { - if (n == 0) { - failed() - } - exit() -} - diff --git a/drivers/staging/ktap/test/zerodivide.kp b/drivers/staging/ktap/test/zerodivide.kp deleted file mode 100644 index abb1eae..0000000 --- a/drivers/staging/ktap/test/zerodivide.kp +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env ktap - -a = 1/0 -#should not go here -printf("Failed\n") diff --git a/drivers/staging/ktap/userspace/code.c b/drivers/staging/ktap/userspace/code.c deleted file mode 100644 index 1427fd5..0000000 --- a/drivers/staging/ktap/userspace/code.c +++ /dev/null @@ -1,968 +0,0 @@ -/* - * code.c - Code generator for ktap - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include - -#include "../include/ktap_types.h" -#include "../include/ktap_opcodes.h" -#include "ktapc.h" - - -#define hasjumps(e) ((e)->t != (e)->f) - -void codegen_patchtohere (ktap_funcstate *fs, int list); - -static int isnumeral(ktap_expdesc *e) -{ - return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); -} - -void codegen_nil(ktap_funcstate *fs, int from, int n) -{ - ktap_instruction *previous; - int l = from + n - 1; /* last register to set nil */ - - if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ - previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); - int pl = pfrom + GETARG_B(*previous); - - if ((pfrom <= from && from <= pl + 1) || - (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ - if (pfrom < from) - from = pfrom; /* from = min(from, pfrom) */ - if (pl > l) - l = pl; /* l = max(l, pl) */ - SETARG_A(*previous, from); - SETARG_B(*previous, l - from); - return; - } - } /* else go through */ - } - codegen_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ -} - -int codegen_jump(ktap_funcstate *fs) -{ - int jpc = fs->jpc; /* save list of jumps to here */ - int j; - - fs->jpc = NO_JUMP; - j = codegen_codeAsBx(fs, OP_JMP, 0, NO_JUMP); - codegen_concat(fs, &j, jpc); /* keep them on hold */ - return j; -} - -void codegen_ret(ktap_funcstate *fs, int first, int nret) -{ - codegen_codeABC(fs, OP_RETURN, first, nret+1, 0); -} - -static int condjump(ktap_funcstate *fs, OpCode op, int A, int B, int C) -{ - codegen_codeABC(fs, op, A, B, C); - return codegen_jump(fs); -} - -static void fixjump(ktap_funcstate *fs, int pc, int dest) -{ - ktap_instruction *jmp = &fs->f->code[pc]; - int offset = dest-(pc+1); - - ktap_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sBx) - lex_syntaxerror(fs->ls, "control structure too long"); - SETARG_sBx(*jmp, offset); -} - -/* - * returns current `pc' and marks it as a jump target (to avoid wrong - * optimizations with consecutive instructions not in the same basic block). - */ -int codegen_getlabel(ktap_funcstate *fs) -{ - fs->lasttarget = fs->pc; - return fs->pc; -} - -static int getjump(ktap_funcstate *fs, int pc) -{ - int offset = GETARG_sBx(fs->f->code[pc]); - - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ -} - -static ktap_instruction *getjumpcontrol(ktap_funcstate *fs, int pc) -{ - ktap_instruction *pi = &fs->f->code[pc]; - if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) - return pi-1; - else - return pi; -} - -/* - * check whether list has any jump that do not produce a value - * (or produce an inverted value) - */ -static int need_value(ktap_funcstate *fs, int list) -{ - for (; list != NO_JUMP; list = getjump(fs, list)) { - ktap_instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TESTSET) - return 1; - } - return 0; /* not found */ -} - -static int patchtestreg(ktap_funcstate *fs, int node, int reg) -{ - ktap_instruction *i = getjumpcontrol(fs, node); - if (GET_OPCODE(*i) != OP_TESTSET) - return 0; /* cannot patch other instructions */ - if (reg != NO_REG && reg != GETARG_B(*i)) - SETARG_A(*i, reg); - else /* no register to put value or register already has the value */ - *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); - - return 1; -} - -static void removevalues(ktap_funcstate *fs, int list) -{ - for (; list != NO_JUMP; list = getjump(fs, list)) - patchtestreg(fs, list, NO_REG); -} - -static void patchlistaux(ktap_funcstate *fs, int list, int vtarget, int reg, - int dtarget) -{ - while (list != NO_JUMP) { - int next = getjump(fs, list); - if (patchtestreg(fs, list, reg)) - fixjump(fs, list, vtarget); - else - fixjump(fs, list, dtarget); /* jump to default target */ - list = next; - } -} - -static void dischargejpc(ktap_funcstate *fs) -{ - patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); - fs->jpc = NO_JUMP; -} - -void codegen_patchlist(ktap_funcstate *fs, int list, int target) -{ - if (target == fs->pc) - codegen_patchtohere(fs, list); - else { - ktap_assert(target < fs->pc); - patchlistaux(fs, list, target, NO_REG, target); - } -} - -void codegen_patchclose(ktap_funcstate *fs, int list, int level) -{ - level++; /* argument is +1 to reserve 0 as non-op */ - while (list != NO_JUMP) { - int next = getjump(fs, list); - ktap_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && - (GETARG_A(fs->f->code[list]) == 0 || - GETARG_A(fs->f->code[list]) >= level)); - SETARG_A(fs->f->code[list], level); - list = next; - } -} - -void codegen_patchtohere(ktap_funcstate *fs, int list) -{ - codegen_getlabel(fs); - codegen_concat(fs, &fs->jpc, list); -} - -void codegen_concat(ktap_funcstate *fs, int *l1, int l2) -{ - if (l2 == NO_JUMP) - return; - else if (*l1 == NO_JUMP) - *l1 = l2; - else { - int list = *l1; - int next; - while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, l2); - } -} - -static int codegen_code(ktap_funcstate *fs, ktap_instruction i) -{ - ktap_proto *f = fs->f; - - dischargejpc(fs); /* `pc' will change */ - - /* put new instruction in code array */ - ktapc_growvector(f->code, fs->pc, f->sizecode, ktap_instruction, - MAX_INT, "opcodes"); - f->code[fs->pc] = i; - - /* save corresponding line information */ - ktapc_growvector(f->lineinfo, fs->pc, f->sizelineinfo, int, - MAX_INT, "opcodes"); - f->lineinfo[fs->pc] = fs->ls->lastline; - return fs->pc++; -} - -int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c) -{ - ktap_assert(getOpMode(o) == iABC); - //ktap_assert(getBMode(o) != OpArgN || b == 0); - //ktap_assert(getCMode(o) != OpArgN || c == 0); - //ktap_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); - return codegen_code(fs, CREATE_ABC(o, a, b, c)); -} - -int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc) -{ - ktap_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); - ktap_assert(getCMode(o) == OpArgN); - ktap_assert(a <= MAXARG_A && bc <= MAXARG_Bx); - return codegen_code(fs, CREATE_ABx(o, a, bc)); -} - -static int codeextraarg(ktap_funcstate *fs, int a) -{ - ktap_assert(a <= MAXARG_Ax); - return codegen_code(fs, CREATE_Ax(OP_EXTRAARG, a)); -} - -int codegen_codek(ktap_funcstate *fs, int reg, int k) -{ - if (k <= MAXARG_Bx) - return codegen_codeABx(fs, OP_LOADK, reg, k); - else { - int p = codegen_codeABx(fs, OP_LOADKX, reg, 0); - codeextraarg(fs, k); - return p; - } -} - -void codegen_checkstack(ktap_funcstate *fs, int n) -{ - int newstack = fs->freereg + n; - - if (newstack > fs->f->maxstacksize) { - if (newstack >= MAXSTACK) - lex_syntaxerror(fs->ls, "function or expression too complex"); - fs->f->maxstacksize = (u8)(newstack); - } -} - -void codegen_reserveregs(ktap_funcstate *fs, int n) -{ - codegen_checkstack(fs, n); - fs->freereg += n; -} - -static void freereg(ktap_funcstate *fs, int reg) -{ - if (!ISK(reg) && reg >= fs->nactvar) { - fs->freereg--; - ktap_assert(reg == fs->freereg); - } -} - -static void freeexp(ktap_funcstate *fs, ktap_expdesc *e) -{ - if (e->k == VNONRELOC) - freereg(fs, e->u.info); -} - -static int addk(ktap_funcstate *fs, ktap_value *key, ktap_value *v) -{ - const ktap_value *idx = ktapc_table_get(fs->h, key); - ktap_proto *f = fs->f; - ktap_value kn; - int k, oldsize; - - if (ttisnumber(idx)) { - ktap_number n = nvalue(idx); - ktap_number2int(k, n); - if (ktapc_equalobj(&f->k[k], v)) - return k; - /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); - go through and create a new entry for this value */ - } - /* constant not found; create a new entry */ - oldsize = f->sizek; - k = fs->nk; - - /* numerical value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setnvalue(&kn, (ktap_number)k); - ktapc_table_setvalue(fs->h, key, &kn); - ktapc_growvector(f->k, k, f->sizek, ktap_value, MAXARG_Ax, "constants"); - while (oldsize < f->sizek) - setnilvalue(&f->k[oldsize++]); - setobj(&f->k[k], v); - fs->nk++; - return k; -} - -int codegen_stringK(ktap_funcstate *fs, ktap_string *s) -{ - ktap_value o; - - setsvalue(&o, s); - return addk(fs, &o, &o); -} - -int codegen_numberK(ktap_funcstate *fs, ktap_number r) -{ - int n; - ktap_value o, s; - - setnvalue(&o, r); - if (r == 0 || ktap_numisnan(NULL, r)) { /* handle -0 and NaN */ - /* use raw representation as key to avoid numeric problems */ - setsvalue(&s, ktapc_ts_newlstr((char *)&r, sizeof(r))); - // incr_top(L); - n = addk(fs, &s, &o); - // L->top--; - } else - n = addk(fs, &o, &o); /* regular case */ - return n; -} - -static int boolK(ktap_funcstate *fs, int b) -{ - ktap_value o; - setbvalue(&o, b); - return addk(fs, &o, &o); -} - -static int nilK(ktap_funcstate *fs) -{ - ktap_value k, v; - setnilvalue(&v); - /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(&k, fs->h); - return addk(fs, &k, &v); -} - -void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults) -{ - if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getcode(fs, e), nresults+1); - } - else if (e->k == VVARARG) { - SETARG_B(getcode(fs, e), nresults+1); - SETARG_A(getcode(fs, e), fs->freereg); - codegen_reserveregs(fs, 1); - } -} - -void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e) -{ - if (e->k == VCALL) { /* expression is an open function call? */ - e->k = VNONRELOC; - e->u.info = GETARG_A(getcode(fs, e)); - } else if (e->k == VVARARG) { - SETARG_B(getcode(fs, e), 2); - e->k = VRELOCABLE; /* can relocate its simple result */ - } -} - -void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e) -{ - switch (e->k) { - case VLOCAL: { - e->k = VNONRELOC; - break; - } - case VUPVAL: { - e->u.info = codegen_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - case VINDEXED: { - OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ - freereg(fs, e->u.ind.idx); - if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ - freereg(fs, e->u.ind.t); - op = OP_GETTABLE; - } - e->u.info = codegen_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; - break; - } - case VVARARG: - case VCALL: { - codegen_setoneret(fs, e); - break; - } - default: - break; /* there is one value available (somewhere) */ - } -} - -static int code_label(ktap_funcstate *fs, int A, int b, int jump) -{ - codegen_getlabel(fs); /* those instructions may be jump targets */ - return codegen_codeABC(fs, OP_LOADBOOL, A, b, jump); -} - -static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg) -{ - codegen_dischargevars(fs, e); - switch (e->k) { - case VNIL: { - codegen_nil(fs, reg, 1); - break; - } - case VFALSE: case VTRUE: { - codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); - break; - } - case VEVENT: - codegen_codeABC(fs, OP_EVENT, reg, 0, 0); - break; - case VEVENTNAME: - codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0); - break; - case VEVENTARG: - codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0); - break; - case VK: { - codegen_codek(fs, reg, e->u.info); - break; - } - case VKNUM: { - codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval)); - break; - } - case VRELOCABLE: { - ktap_instruction *pc = &getcode(fs, e); - SETARG_A(*pc, reg); - break; - } - case VNONRELOC: { - if (reg != e->u.info) - codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0); - break; - } - default: - ktap_assert(e->k == VVOID || e->k == VJMP); - return; /* nothing to do... */ - } - - e->u.info = reg; - e->k = VNONRELOC; -} - -static void discharge2anyreg(ktap_funcstate *fs, ktap_expdesc *e) -{ - if (e->k != VNONRELOC) { - codegen_reserveregs(fs, 1); - discharge2reg(fs, e, fs->freereg-1); - } -} - -static void exp2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg) -{ - discharge2reg(fs, e, reg); - if (e->k == VJMP) - codegen_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ - if (hasjumps(e)) { - int final; /* position after whole expression */ - int p_f = NO_JUMP; /* position of an eventual LOAD false */ - int p_t = NO_JUMP; /* position of an eventual LOAD true */ - - if (need_value(fs, e->t) || need_value(fs, e->f)) { - int fj = (e->k == VJMP) ? NO_JUMP : codegen_jump(fs); - - p_f = code_label(fs, reg, 0, 1); - p_t = code_label(fs, reg, 1, 0); - codegen_patchtohere(fs, fj); - } - final = codegen_getlabel(fs); - patchlistaux(fs, e->f, final, reg, p_f); - patchlistaux(fs, e->t, final, reg, p_t); - } - e->f = e->t = NO_JUMP; - e->u.info = reg; - e->k = VNONRELOC; -} - -void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e) -{ - codegen_dischargevars(fs, e); - freeexp(fs, e); - codegen_reserveregs(fs, 1); - exp2reg(fs, e, fs->freereg - 1); -} - -int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e) -{ - codegen_dischargevars(fs, e); - if (e->k == VNONRELOC) { - if (!hasjumps(e)) - return e->u.info; /* exp is already in a register */ - if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->u.info); /* put value on it */ - return e->u.info; - } - } - codegen_exp2nextreg(fs, e); /* default */ - return e->u.info; -} - -void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e) -{ - if (e->k != VUPVAL || hasjumps(e)) - codegen_exp2anyreg(fs, e); -} - -void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e) -{ - if (hasjumps(e)) - codegen_exp2anyreg(fs, e); - else - codegen_dischargevars(fs, e); -} - -int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e) -{ - codegen_exp2val(fs, e); - switch (e->k) { - case VTRUE: - case VFALSE: - case VNIL: { - if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ - e->u.info = (e->k == VNIL) ? nilK(fs) : - boolK(fs, (e->k == VTRUE)); - e->k = VK; - return RKASK(e->u.info); - } - else - break; - } - case VKNUM: { - e->u.info = codegen_numberK(fs, e->u.nval); - e->k = VK; - /* go through */ - } - case VK: { - if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ - return RKASK(e->u.info); - else - break; - } - default: - break; - } - /* not a constant in the right range: put it in a register */ - return codegen_exp2anyreg(fs, e); -} - -void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex) -{ - switch (var->k) { - case VLOCAL: { - freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); - return; - } - case VUPVAL: { - int e = codegen_exp2anyreg(fs, ex); - codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); - break; - } - case VINDEXED: { - OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; - int e = codegen_exp2RK(fs, ex); - codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); - break; - } - default: - ktap_assert(0); /* invalid var kind to store */ - break; - } - - freeexp(fs, ex); -} - -void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex) -{ - switch (var->k) { -#if 0 /*current not supported */ - case VLOCAL: { - freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); - return; - } - case VUPVAL: { - int e = codegen_exp2anyreg(fs, ex); - codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); - break; - } -#endif - case VINDEXED: { - OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE_INCR : - OP_SETTABUP_INCR; - int e = codegen_exp2RK(fs, ex); - codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); - break; - } - default: - ktap_assert(0); /* invalid var kind to store */ - break; - } - - freeexp(fs, ex); -} - - -void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key) -{ - int ereg; - - codegen_exp2anyreg(fs, e); - ereg = e->u.info; /* register where 'e' was placed */ - freeexp(fs, e); - e->u.info = fs->freereg; /* base register for op_self */ - e->k = VNONRELOC; - codegen_reserveregs(fs, 2); /* function and 'self' produced by op_self */ - codegen_codeABC(fs, OP_SELF, e->u.info, ereg, codegen_exp2RK(fs, key)); - freeexp(fs, key); -} - -static void invertjump(ktap_funcstate *fs, ktap_expdesc *e) -{ - ktap_instruction *pc = getjumpcontrol(fs, e->u.info); - ktap_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && - GET_OPCODE(*pc) != OP_TEST); - SETARG_A(*pc, !(GETARG_A(*pc))); -} - -static int jumponcond(ktap_funcstate *fs, ktap_expdesc *e, int cond) -{ - if (e->k == VRELOCABLE) { - ktap_instruction ie = getcode(fs, e); - if (GET_OPCODE(ie) == OP_NOT) { - fs->pc--; /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); - } - /* else go through */ - } - discharge2anyreg(fs, e); - freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); -} - -void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e) -{ - int pc; /* pc of last jump */ - - codegen_dischargevars(fs, e); - switch (e->k) { - case VJMP: { - invertjump(fs, e); - pc = e->u.info; - break; - } - case VK: case VKNUM: case VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } - default: - pc = jumponcond(fs, e, 0); - break; - } - - codegen_concat(fs, &e->f, pc); /* insert last jump in `f' list */ - codegen_patchtohere(fs, e->t); - e->t = NO_JUMP; -} - -void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e) -{ - int pc; /* pc of last jump */ - codegen_dischargevars(fs, e); - - switch (e->k) { - case VJMP: { - pc = e->u.info; - break; - } - case VNIL: case VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } - default: - pc = jumponcond(fs, e, 1); - break; - } - codegen_concat(fs, &e->t, pc); /* insert last jump in `t' list */ - codegen_patchtohere(fs, e->f); - e->f = NO_JUMP; -} - -static void codenot(ktap_funcstate *fs, ktap_expdesc *e) -{ - codegen_dischargevars(fs, e); - switch (e->k) { - case VNIL: case VFALSE: { - e->k = VTRUE; - break; - } - case VK: case VKNUM: case VTRUE: { - e->k = VFALSE; - break; - } - case VJMP: { - invertjump(fs, e); - break; - } - case VRELOCABLE: - case VNONRELOC: { - discharge2anyreg(fs, e); - freeexp(fs, e); - e->u.info = codegen_codeABC(fs, OP_NOT, 0, e->u.info, 0); - e->k = VRELOCABLE; - break; - } - default: - ktap_assert(0); /* cannot happen */ - break; - } - - /* interchange true and false lists */ - { int temp = e->f; e->f = e->t; e->t = temp; } - removevalues(fs, e->f); - removevalues(fs, e->t); -} - -void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k) -{ - ktap_assert(!hasjumps(t)); - t->u.ind.t = t->u.info; - t->u.ind.idx = codegen_exp2RK(fs, k); - t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL - : check_exp(vkisinreg(t->k), VLOCAL); - t->k = VINDEXED; -} - -static int constfolding(OpCode op, ktap_expdesc *e1, ktap_expdesc *e2) -{ - ktap_number r; - - if (!isnumeral(e1) || !isnumeral(e2)) - return 0; - - if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) - return 0; /* do not attempt to divide by 0 */ - - if (op == OP_POW) - return 0; /* ktap current do not suppor pow arith */ - - r = ktapc_arith(op - OP_ADD + KTAP_OPADD, e1->u.nval, e2->u.nval); - e1->u.nval = r; - return 1; -} - -static void codearith(ktap_funcstate *fs, OpCode op, - ktap_expdesc *e1, ktap_expdesc *e2, int line) -{ - if (constfolding(op, e1, e2)) - return; - else { - int o2 = (op != OP_UNM && op != OP_LEN) ? codegen_exp2RK(fs, e2) : 0; - int o1 = codegen_exp2RK(fs, e1); - - if (o1 > o2) { - freeexp(fs, e1); - freeexp(fs, e2); - } else { - freeexp(fs, e2); - freeexp(fs, e1); - } - e1->u.info = codegen_codeABC(fs, op, 0, o1, o2); - e1->k = VRELOCABLE; - codegen_fixline(fs, line); - } -} - -static void codecomp(ktap_funcstate *fs, OpCode op, int cond, ktap_expdesc *e1, - ktap_expdesc *e2) -{ - int o1 = codegen_exp2RK(fs, e1); - int o2 = codegen_exp2RK(fs, e2); - - freeexp(fs, e2); - freeexp(fs, e1); - if (cond == 0 && op != OP_EQ) { - int temp; /* exchange args to replace by `<' or `<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - cond = 1; - } - e1->u.info = condjump(fs, op, cond, o1, o2); - e1->k = VJMP; -} - -void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line) -{ - ktap_expdesc e2; - - e2.t = e2.f = NO_JUMP; - e2.k = VKNUM; - e2.u.nval = 0; - - switch (op) { - case OPR_MINUS: { - if (isnumeral(e)) /* minus constant? */ - e->u.nval = ktap_numunm(e->u.nval); /* fold it */ - else { - codegen_exp2anyreg(fs, e); - codearith(fs, OP_UNM, e, &e2, line); - } - break; - } - case OPR_NOT: - codenot(fs, e); - break; - case OPR_LEN: { - codegen_exp2anyreg(fs, e); /* cannot operate on constants */ - codearith(fs, OP_LEN, e, &e2, line); - break; - } - default: - ktap_assert(0); - } -} - -void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v) -{ - switch (op) { - case OPR_AND: { - codegen_goiftrue(fs, v); - break; - } - case OPR_OR: { - codegen_goiffalse(fs, v); - break; - } - case OPR_CONCAT: { - codegen_exp2nextreg(fs, v); /* operand must be on the `stack' */ - break; - } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { - if (!isnumeral(v)) codegen_exp2RK(fs, v); - break; - } - default: - codegen_exp2RK(fs, v); - break; - } -} - -void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line) -{ - switch (op) { - case OPR_AND: { - ktap_assert(e1->t == NO_JUMP); /* list must be closed */ - codegen_dischargevars(fs, e2); - codegen_concat(fs, &e2->f, e1->f); - *e1 = *e2; - break; - } - case OPR_OR: { - ktap_assert(e1->f == NO_JUMP); /* list must be closed */ - codegen_dischargevars(fs, e2); - codegen_concat(fs, &e2->t, e1->t); - *e1 = *e2; - break; - } - case OPR_CONCAT: { - codegen_exp2val(fs, e2); - if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - ktap_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); - freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->u.info); - e1->k = VRELOCABLE; e1->u.info = e2->u.info; - } else { - codegen_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codearith(fs, OP_CONCAT, e1, e2, line); - } - break; - } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { - codearith(fs, (OpCode)(op - OPR_ADD + OP_ADD), e1, e2, line); - break; - } - case OPR_EQ: case OPR_LT: case OPR_LE: { - codecomp(fs, (OpCode)(op - OPR_EQ + OP_EQ), 1, e1, e2); - break; - } - case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, (OpCode)(op - OPR_NE + OP_EQ), 0, e1, e2); - break; - } - default: - ktap_assert(0); - } -} - -void codegen_fixline(ktap_funcstate *fs, int line) -{ - fs->f->lineinfo[fs->pc - 1] = line; -} - -void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore) -{ - int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; - int b = (tostore == KTAP_MULTRET) ? 0 : tostore; - - ktap_assert(tostore != 0); - if (c <= MAXARG_C) - codegen_codeABC(fs, OP_SETLIST, base, b, c); - else if (c <= MAXARG_Ax) { - codegen_codeABC(fs, OP_SETLIST, base, b, 0); - codeextraarg(fs, c); - } else - lex_syntaxerror(fs->ls, "constructor too long"); - fs->freereg = base + 1; /* free registers with list values */ -} - diff --git a/drivers/staging/ktap/userspace/dump.c b/drivers/staging/ktap/userspace/dump.c deleted file mode 100644 index 088b08d..0000000 --- a/drivers/staging/ktap/userspace/dump.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * dump.c - save precompiled ktap chunks - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include - -#include "../include/ktap_types.h" -#include "../include/ktap_opcodes.h" -#include "ktapc.h" - - -typedef struct { - ktap_writer writer; - void *data; - int strip; - int status; -} DumpState; - -#define DumpMem(b, n, size, D) DumpBlock(b, (n)*(size), D) -#define DumpVar(x, D) DumpMem(&x, 1, sizeof(x), D) - -static void DumpBlock(const void *b, size_t size, DumpState *D) -{ - if (D->status == 0) - D->status = ((D->writer))(b, size, D->data); -} - -static void DumpChar(int y, DumpState *D) -{ - char x = (char)y; - DumpVar(x, D); -} - -static void DumpInt(int x, DumpState *D) -{ - DumpVar(x, D); -} - -static void DumpNumber(ktap_number x, DumpState *D) -{ - DumpVar(x,D); -} - -static void DumpVector(const void *b, int n, size_t size, DumpState *D) -{ - DumpInt(n, D); - DumpMem(b, n, size, D); -} - -static void DumpString(const ktap_string *s, DumpState *D) -{ - if (s == NULL) { - int size = 0; - DumpVar(size, D); - } else { - int size = s->tsv.len + 1; /* include trailing '\0' */ - DumpVar(size, D); - DumpBlock(getstr(s), size * sizeof(char), D); - } -} - -#define DumpCode(f, D) DumpVector(f->code, f->sizecode, sizeof(ktap_instruction), D) - -static void DumpFunction(const ktap_proto *f, DumpState *D); - -static void DumpConstants(const ktap_proto *f, DumpState *D) -{ - int i, n = f->sizek; - - DumpInt(n, D); - for (i = 0; i < n; i++) { - const ktap_value* o=&f->k[i]; - DumpChar(ttypenv(o), D); - switch (ttypenv(o)) { - case KTAP_TNIL: - break; - case KTAP_TBOOLEAN: - DumpChar(bvalue(o), D); - break; - case KTAP_TNUMBER: - DumpNumber(nvalue(o), D); - break; - case KTAP_TSTRING: - DumpString(rawtsvalue(o), D); - break; - default: - printf("ktap: DumpConstants with unknown vaule type %d\n", ttypenv(o)); - ktap_assert(0); - } - } - n = f->sizep; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpFunction(f->p[i], D); -} - -static void DumpUpvalues(const ktap_proto *f, DumpState *D) -{ - int i, n = f->sizeupvalues; - - DumpInt(n, D); - for (i = 0; i < n; i++) { - DumpChar(f->upvalues[i].instack, D); - DumpChar(f->upvalues[i].idx, D); - } -} - -static void DumpDebug(const ktap_proto *f, DumpState *D) -{ - int i,n; - - DumpString((D->strip) ? NULL : f->source, D); - n= (D->strip) ? 0 : f->sizelineinfo; - DumpVector(f->lineinfo, n, sizeof(int), D); - n = (D->strip) ? 0 : f->sizelocvars; - DumpInt(n, D); - - for (i = 0; i < n; i++) { - DumpString(f->locvars[i].varname, D); - DumpInt(f->locvars[i].startpc, D); - DumpInt(f->locvars[i].endpc, D); - } - n = (D->strip) ? 0 : f->sizeupvalues; - DumpInt(n, D); - for (i = 0; i < n; i++) - DumpString(f->upvalues[i].name, D); -} - -static void DumpFunction(const ktap_proto *f, DumpState *D) -{ - DumpInt(f->linedefined, D); - DumpInt(f->lastlinedefined, D); - DumpChar(f->numparams, D); - DumpChar(f->is_vararg, D); - DumpChar(f->maxstacksize, D); - DumpCode(f, D); - DumpConstants(f, D); - DumpUpvalues(f, D); - DumpDebug(f, D); -} - -static void DumpHeader(DumpState *D) -{ - u8 h[KTAPC_HEADERSIZE]; - - kp_header(h); - DumpBlock(h, KTAPC_HEADERSIZE, D); -} - -/* - * dump ktap function as precompiled chunk - */ -int ktapc_dump(const ktap_proto *f, ktap_writer w, void *data, int strip) -{ - DumpState D; - - D.writer = w; - D.data = data; - D.strip = strip; - D.status = 0; - DumpHeader(&D); - DumpFunction(f, &D); - return D.status; -} diff --git a/drivers/staging/ktap/userspace/eventdef.c b/drivers/staging/ktap/userspace/eventdef.c deleted file mode 100644 index 76a68ac..0000000 --- a/drivers/staging/ktap/userspace/eventdef.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * eventdef.c - ktap eventdef parser - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include -#include - -#include "../include/ktap_types.h" -#include "../include/ktap_opcodes.h" -#include "ktapc.h" - -static char tracing_events_path[] = "/sys/kernel/debug/tracing/events"; - -#define IDS_ARRAY_SIZE 4096 -static u8 *ids_array; - -#define set_id(id) \ - do { \ - ids_array[id/8] = ids_array[id/8] | (1 << (id%8)); \ - } while(0) - -#define clear_id(id) \ - do { \ - ids_array[id/8] = ids_array[id/8] & ~ (1 << (id%8)); \ - } while(0) - - -static int get_digit_len(int id) -{ - int len = -1; - - if (id < 10) - len = 1; - else if (id < 100) - len = 2; - else if (id < 1000) - len = 3; - else if (id < 10000) - len = 4; - else if (id < 100000) - len = 5; - - return len; -} - -static char *get_idstr(char *filter) -{ - char *idstr, *ptr; - int total_len = 0; - int filter_len; - int i; - - filter_len = filter ? strlen(filter) : 0; - - for (i = 0; i < IDS_ARRAY_SIZE*8; i++) { - if (ids_array[i/8] & (1 << (i%8))) - total_len += get_digit_len(i) + 1; - } - - if (!total_len) - return NULL; - - idstr = malloc(total_len + filter_len + 1); - if (!idstr) - return NULL; - - memset(idstr, 0, total_len + filter_len + 1); - ptr = idstr; - for (i = 0; i < IDS_ARRAY_SIZE*8; i++) { - if (ids_array[i/8] & (1 << (i%8))) { - char digits[32] = {0}; - int len; - - sprintf(digits, "%d ", i); - len = strlen(digits); - strncpy(ptr, digits, len); - ptr += len; - } - } - - if (filter) - memcpy(ptr, filter, strlen(filter)); - - return idstr; -} - -static int add_event(char *evtid_path) -{ - char id_buf[24]; - int id, fd; - - fd = open(evtid_path, O_RDONLY); - if (fd < 0) { - /* - * some tracepoint doesn't have id file, like ftrace, - * return success in here, and don't print error. - */ - verbose_printf("warning: cannot open file %s\n", evtid_path); - return 0; - } - - if (read(fd, id_buf, sizeof(id_buf)) < 0) { - fprintf(stderr, "read file error %s\n", evtid_path); - close(fd); - return -1; - } - - id = atoll(id_buf); - - if (id >= IDS_ARRAY_SIZE * 8) { - fprintf(stderr, "tracepoint id(%d) is bigger than %d\n", id, - IDS_ARRAY_SIZE * 8); - close(fd); - return -1; - } - - set_id(id); - - close(fd); - return 0; -} - -static int add_tracepoint(char *sys_name, char *evt_name) -{ - char evtid_path[PATH_MAX] = {0}; - - - snprintf(evtid_path, PATH_MAX, "%s/%s/%s/id", tracing_events_path, - sys_name, evt_name); - return add_event(evtid_path); -} - -static int add_tracepoint_multi_event(char *sys_name, char *evt_name) -{ - char evt_path[PATH_MAX]; - struct dirent *evt_ent; - DIR *evt_dir; - int ret = 0; - - snprintf(evt_path, PATH_MAX, "%s/%s", tracing_events_path, sys_name); - evt_dir = opendir(evt_path); - if (!evt_dir) { - perror("Can't open event dir"); - return -1; - } - - while (!ret && (evt_ent = readdir(evt_dir))) { - if (!strcmp(evt_ent->d_name, ".") - || !strcmp(evt_ent->d_name, "..") - || !strcmp(evt_ent->d_name, "enable") - || !strcmp(evt_ent->d_name, "filter")) - continue; - - if (!strglobmatch(evt_ent->d_name, evt_name)) - continue; - - ret = add_tracepoint(sys_name, evt_ent->d_name); - } - - closedir(evt_dir); - return ret; -} - -static int add_tracepoint_event(char *sys_name, char *evt_name) -{ - return strpbrk(evt_name, "*?") ? - add_tracepoint_multi_event(sys_name, evt_name) : - add_tracepoint(sys_name, evt_name); -} - -static int add_tracepoint_multi_sys(char *sys_name, char *evt_name) -{ - struct dirent *events_ent; - DIR *events_dir; - int ret = 0; - - events_dir = opendir(tracing_events_path); - if (!events_dir) { - perror("Can't open event dir"); - return -1; - } - - while (!ret && (events_ent = readdir(events_dir))) { - if (!strcmp(events_ent->d_name, ".") - || !strcmp(events_ent->d_name, "..") - || !strcmp(events_ent->d_name, "enable") - || !strcmp(events_ent->d_name, "header_event") - || !strcmp(events_ent->d_name, "header_page")) - continue; - - if (!strglobmatch(events_ent->d_name, sys_name)) - continue; - - ret = add_tracepoint_event(events_ent->d_name, - evt_name); - } - - closedir(events_dir); - return ret; -} - -static int parse_events_add_tracepoint(char *sys, char *event) -{ - if (strpbrk(sys, "*?")) - return add_tracepoint_multi_sys(sys, event); - else - return add_tracepoint_event(sys, event); -} - -enum { - KPROBE_EVENT, - UPROBE_EVENT, -}; - -struct probe_list { - struct probe_list *next; - int type; - int kp_seq; - char *probe_event; -}; - -static struct probe_list *probe_list_head; - -#define KPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/kprobe_events" - -static int parse_events_add_kprobe(char *old_event) -{ - static int event_seq = 0; - struct probe_list *pl; - char probe_event[128] = {0}; - char event_id_path[128] = {0}; - char *event; - char *r; - int fd; - int ret; - - fd = open(KPROBE_EVENTS_PATH, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open %s\n", KPROBE_EVENTS_PATH); - return -1; - } - - event = strdup(old_event); - r = strstr(event, "%return"); - if (r) { - memset(r, ' ', 7); - snprintf(probe_event, 128, "r:kprobes/kp%d %s", - event_seq, event); - } else - snprintf(probe_event, 128, "p:kprobes/kp%d %s", - event_seq, event); - - free(event); - - verbose_printf("kprobe event %s\n", probe_event); - ret = write(fd, probe_event, strlen(probe_event)); - if (ret <= 0) { - fprintf(stderr, "Cannot write %s to %s\n", probe_event, - KPROBE_EVENTS_PATH); - close(fd); - return -1; - } - - close(fd); - - pl = malloc(sizeof(struct probe_list)); - if (!pl) - return -1; - - pl->type = KPROBE_EVENT; - pl->kp_seq = event_seq; - pl->next = probe_list_head; - probe_list_head = pl; - - sprintf(event_id_path, "/sys/kernel/debug/tracing/events/kprobes/kp%d/id", - event_seq); - ret = add_event(event_id_path); - if (ret < 0) - return -1; - - event_seq++; - return 0; -} - -#define UPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/uprobe_events" - -static int parse_events_add_uprobe(char *old_event) -{ - static int event_seq = 0; - struct probe_list *pl; - char probe_event[128] = {0}; - char event_id_path[128] = {0}; - char *event; - char *r; - int fd; - int ret; - - fd = open(UPROBE_EVENTS_PATH, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH); - return -1; - } - - event = strdup(old_event); - r = strstr(event, "%return"); - if (r) { - memset(r, ' ', 7); - snprintf(probe_event, 128, "r:uprobes/kp%d %s", - event_seq, event); - } else - snprintf(probe_event, 128, "p:uprobes/kp%d %s", - event_seq, event); - - free(event); - - verbose_printf("uprobe event %s\n", probe_event); - ret = write(fd, probe_event, strlen(probe_event)); - if (ret <= 0) { - fprintf(stderr, "Cannot write %s to %s\n", probe_event, - UPROBE_EVENTS_PATH); - close(fd); - return -1; - } - - close(fd); - - pl = malloc(sizeof(struct probe_list)); - if (!pl) - return -1; - - pl->type = UPROBE_EVENT; - pl->kp_seq = event_seq; - pl->next = probe_list_head; - probe_list_head = pl; - - sprintf(event_id_path, "/sys/kernel/debug/tracing/events/uprobes/kp%d/id", - event_seq); - ret = add_event(event_id_path); - if (ret < 0) - return -1; - - event_seq++; - return 0; -} - -static int parse_events_add_probe(char *old_event) -{ - char *separator; - - separator = strchr(old_event, ':'); - if (!separator || (separator == old_event)) - return parse_events_add_kprobe(old_event); - else - return parse_events_add_uprobe(old_event); -} - -static int parse_events_add_stapsdt(char *old_event) -{ - printf("Currently ktap don't support stapsdt, please waiting\n"); - - return -1; -} - -static void strim(char *s) -{ - size_t size; - char *end; - - size = strlen(s); - if (!size) - return; - - end = s + size -1; - while (end >= s && isspace(*end)) - end--; - - *(end + 1) = '\0'; -} - -static int get_sys_event_filter_str(char *start, - char **sys, char **event, char **filter) -{ - char *separator, *separator2, *ptr, *end; - - while (*start == ' ') - start++; - - /* find sys */ - separator = strchr(start, ':'); - if (!separator || (separator == start)) { - return -1; - } - - ptr = malloc(separator - start + 1); - if (!ptr) - return -1; - - strncpy(ptr, start, separator - start); - ptr[separator - start] = '\0'; - - strim(ptr); - *sys = ptr; - - if (!strcmp(*sys, "probe") && (*(separator + 1) == '/')) { - /* it's uprobe event */ - separator2 = strchr(separator + 1, ':'); - if (!separator2) - return -1; - } else - separator2 = separator; - - /* find filter */ - end = start + strlen(start); - while (*--end == ' ') { - } - - if (*end == '/') { - char *filter_start; - - filter_start = strchr(separator2, '/'); - if (filter_start == end) - return -1; - - ptr = malloc(end - filter_start + 2); - if (!ptr) - return -1; - - memcpy(ptr, filter_start, end - filter_start + 1); - ptr[end - filter_start + 1] = '\0'; - - *filter = ptr; - - end = filter_start; - } else { - *filter = NULL; - end++; - } - - /* find event */ - ptr = malloc(end - separator); - if (!ptr) - return -1; - - memcpy(ptr, separator + 1, end - separator - 1); - ptr[end - separator - 1] = '\0'; - - strim(ptr); - *event = ptr; - - return 0; -} - -static char *get_next_eventdef(char *str) -{ - char *separator; - - separator = strchr(str, ','); - if (!separator) - return str + strlen(str); - - *separator = '\0'; - return separator + 1; -} - -ktap_string *ktapc_parse_eventdef(ktap_string *eventdef) -{ - const char *def_str = getstr(eventdef); - char *str = strdup(def_str); - char *sys, *event, *filter, *idstr, *g_idstr, *next; - ktap_string *ts; - int ret; - - if (!ids_array) { - ids_array = malloc(IDS_ARRAY_SIZE); - if (!ids_array) - return NULL; - } - - g_idstr = malloc(4096); - if (!g_idstr) - return NULL; - - memset(g_idstr, 0, 4096); - - parse_next_eventdef: - memset(ids_array, 0, IDS_ARRAY_SIZE); - - next = get_next_eventdef(str); - - if (get_sys_event_filter_str(str, &sys, &event, &filter)) - goto error; - - verbose_printf("parse_eventdef: sys[%s], event[%s], filter[%s]\n", - sys, event, filter); - - if (!strcmp(sys, "probe")) - ret = parse_events_add_probe(event); - else if (!strcmp(sys, "stapsdt")) - ret = parse_events_add_stapsdt(event); - else - ret = parse_events_add_tracepoint(sys, event); - - if (ret) - goto error; - - /* don't trace ftrace:function when all tracepoints enabled */ - if (!strcmp(sys, "*")) - clear_id(1); - - idstr = get_idstr(filter); - if (!idstr) - goto error; - - str = next; - - g_idstr = strcat(g_idstr, idstr); - g_idstr = strcat(g_idstr, ","); - - if (*next != '\0') - goto parse_next_eventdef; - - ts = ktapc_ts_new(g_idstr); - free(g_idstr); - - return ts; - error: - cleanup_event_resources(); - return NULL; -} - -void cleanup_event_resources(void) -{ - struct probe_list *pl; - const char *path; - char probe_event[32] = {0}; - int fd, ret; - - for (pl = probe_list_head; pl; pl = pl->next) { - if (pl->type == KPROBE_EVENT) { - path = KPROBE_EVENTS_PATH; - snprintf(probe_event, 32, "-:kprobes/kp%d", pl->kp_seq); - } else if (pl->type == UPROBE_EVENT) { - path = UPROBE_EVENTS_PATH; - snprintf(probe_event, 32, "-:uprobes/kp%d", pl->kp_seq); - } else { - fprintf(stderr, "Cannot cleanup event type %d\n", pl->type); - continue; - } - - fd = open(path, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open %s\n", UPROBE_EVENTS_PATH); - continue; - } - - ret = write(fd, probe_event, strlen(probe_event)); - if (ret <= 0) { - fprintf(stderr, "Cannot write %s to %s\n", probe_event, - path); - close(fd); - continue; - } - - close(fd); - } -} - diff --git a/drivers/staging/ktap/userspace/ktapc.h b/drivers/staging/ktap/userspace/ktapc.h deleted file mode 100644 index 879cd29..0000000 --- a/drivers/staging/ktap/userspace/ktapc.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * ktapc.h - * only can be included by userspace compiler - */ - -#include - -typedef int bool; -#define false 0 -#define true 1 - -#define MAX_INT ((int)(~0U>>1)) -#define UCHAR_MAX 255 - -#define MAX_SIZET ((size_t)(~(size_t)0)-2) - -#define KTAP_ERRSYNTAX 3 - -/* - * KTAP_IDSIZE gives the maximum size for the description of the source - * of a function in debug information. - * CHANGE it if you want a different size. - */ -#define KTAP_IDSIZE 60 - - -#define FIRST_RESERVED 257 - -/* - * maximum depth for nested C calls and syntactical nested non-terminals - * in a program. (Value must fit in an unsigned short int.) - */ -#define KTAP_MAXCCALLS 200 - -#define KTAP_MULTRET (-1) - - -#define SHRT_MAX UCHAR_MAX - -#define MAXUPVAL UCHAR_MAX - - -/* maximum stack for a ktap function */ -#define MAXSTACK 250 - -#define islalpha(c) (isalpha(c) || (c) == '_') -#define islalnum(c) (isalnum(c) || (c) == '_') - -#define isreserved(s) ((s)->tsv.tt == KTAP_TSHRSTR && (s)->tsv.extra > 0) - -#define ktap_numeq(a,b) ((a)==(b)) -#define ktap_numisnan(L,a) (!ktap_numeq((a), (a))) - -#define ktap_numunm(a) (-(a)) - -/* - * ** Comparison and arithmetic functions - * */ - -#define KTAP_OPADD 0 /* ORDER TM */ -#define KTAP_OPSUB 1 -#define KTAP_OPMUL 2 -#define KTAP_OPDIV 3 -#define KTAP_OPMOD 4 -#define KTAP_OPPOW 5 -#define KTAP_OPUNM 6 - -#define KTAP_OPEQ 0 -#define KTAP_OPLT 1 -#define KTAP_OPLE 2 - - -/* - * WARNING: if you change the order of this enumeration, - * grep "ORDER RESERVED" - */ -enum RESERVED { - /* terminal symbols denoted by reserved words */ - TK_TRACE = FIRST_RESERVED, TK_TRACE_END, - TK_ARGEVENT, TK_ARGNAME, - TK_ARG1, TK_ARG2, TK_ARG3, TK_ARG4, TK_ARG5, TK_ARG6, TK_ARG7, TK_ARG8, - TK_ARG9, TK_PROFILE, TK_TICK, - TK_AND, TK_BREAK, - TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, - TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, - TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, - /* other terminal symbols */ - TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_INCR, TK_DBCOLON, - TK_EOS, TK_NUMBER, TK_NAME, TK_STRING -}; - -/* number of reserved words */ -#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED + 1)) - -#define EOZ (0) /* end of stream */ - -typedef union { - ktap_number r; - ktap_string *ts; -} ktap_seminfo; /* semantics information */ - - -typedef struct ktap_token { - int token; - ktap_seminfo seminfo; -} ktap_token; - -typedef struct ktap_mbuffer { - char *buffer; - size_t n; - size_t buffsize; -} ktap_mbuffer; - -#define mbuff_init(buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) -#define mbuff(buff) ((buff)->buffer) -#define mbuff_reset(buff) ((buff)->n = 0, memset((buff)->buffer, 0, (buff)->buffsize)) -#define mbuff_len(buff) ((buff)->n) -#define mbuff_size(buff) ((buff)->buffsize) - -#define mbuff_resize(buff, size) \ - (ktapc_realloc((buff)->buffer, (buff)->buffsize, size, char), \ - (buff)->buffsize = size) - -#define mbuff_free(buff) mbuff_resize(buff, 0) - - -/* - * state of the lexer plus state of the parser when shared by all - * functions - */ -typedef struct ktap_lexstate { - char *ptr; /* source file reading position */ - int current; /* current character (charint) */ - int linenumber; /* input line counter */ - int lastline; /* line of last token `consumed' */ - ktap_token t; /* current token */ - ktap_token lookahead; /* look ahead token */ - struct ktap_funcstate *fs; /* current function (parser) */ - ktap_mbuffer *buff; /* buffer for tokens */ - struct ktap_dyndata *dyd; /* dynamic structures used by the parser */ - ktap_string *source; /* current source name */ - ktap_string *envn; /* environment variable name */ - char decpoint; /* locale decimal point */ - int nCcalls; -} ktap_lexstate; - - -/* - * Expression descriptor - */ -typedef enum { - VVOID, /* no value */ - VNIL, - VTRUE, - VFALSE, - VK, /* info = index of constant in `k' */ - VKNUM, /* nval = numerical value */ - VNONRELOC, /* info = result register */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in 'upvalues' */ - VINDEXED, /* t = table register/upvalue; idx = index R/K */ - VJMP, /* info = instruction pc */ - VRELOCABLE, /* info = instruction pc */ - VCALL, /* info = instruction pc */ - VVARARG, /* info = instruction pc */ - VEVENT, - VEVENTNAME, - VEVENTARG, -} expkind; - - -#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) -#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) - -typedef struct ktap_expdesc { - expkind k; - union { - struct { /* for indexed variables (VINDEXED) */ - short idx; /* index (R/K) */ - u8 t; /* table (register or upvalue) */ - u8 vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ - } ind; - int info; /* for generic use */ - ktap_number nval; /* for VKNUM */ - } u; - int t; /* patch list of `exit when true' */ - int f; /* patch list of `exit when false' */ -} ktap_expdesc; - - -typedef struct ktap_vardesc { - short idx; /* variable index in stack */ -} ktap_vardesc; - - -/* description of pending goto statements and label statements */ -typedef struct ktap_labeldesc { - ktap_string *name; /* label identifier */ - int pc; /* position in code */ - int line; /* line where it appeared */ - u8 nactvar; /* local level where it appears in current block */ -} ktap_labeldesc; - - -/* list of labels or gotos */ -typedef struct ktap_labellist { - ktap_labeldesc *arr; /* array */ - int n; /* number of entries in use */ - int size; /* array size */ -} ktap_labellist; - - -/* dynamic structures used by the parser */ -typedef struct ktap_dyndata { - struct { /* list of active local variables */ - ktap_vardesc *arr; - int n; - int size; - } actvar; - ktap_labellist gt; /* list of pending gotos */ - ktap_labellist label; /* list of active labels */ -} ktap_dyndata; - - -/* control of blocks */ -struct ktap_blockcnt; /* defined in lparser.c */ - - -/* state needed to generate code for a given function */ -typedef struct ktap_funcstate { - ktap_proto *f; /* current function header */ - ktap_table *h; /* table to find (and reuse) elements in `k' */ - struct ktap_funcstate *prev; /* enclosing function */ - struct ktap_lexstate *ls; /* lexical state */ - struct ktap_blockcnt *bl; /* chain of current blocks */ - int pc; /* next position to code (equivalent to `ncode') */ - int lasttarget; /* 'label' of last 'jump label' */ - int jpc; /* list of pending jumps to `pc' */ - int nk; /* number of elements in `k' */ - int np; /* number of elements in `p' */ - int firstlocal; /* index of first local var (in ktap_dyndata array) */ - short nlocvars; /* number of elements in 'f->locvars' */ - u8 nactvar; /* number of active local variables */ - u8 nups; /* number of upvalues */ - u8 freereg; /* first free register */ -} ktap_funcstate; - - -/* - * Marks the end of a patch list. It is an invalid value both as an absolute - * address, and as a list link (would link an element to itself). - */ -#define NO_JUMP (-1) - - -/* - * grep "ORDER OPR" if you change these enums (ORDER OP) - */ -typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, - OPR_CONCAT, - OPR_EQ, OPR_LT, OPR_LE, - OPR_NE, OPR_GT, OPR_GE, - OPR_AND, OPR_OR, - OPR_NOBINOPR -} BinOpr; - - -typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; - - -#define getcode(fs,e) ((fs)->f->code[(e)->u.info]) - -#define codegen_codeAsBx(fs,o,A,sBx) codegen_codeABx(fs,o,A,(sBx)+MAXARG_sBx) - -#define codegen_setmultret(fs,e) codegen_setreturns(fs, e, KTAP_MULTRET) - -#define codegen_jumpto(fs,t) codegen_patchlist(fs, codegen_jump(fs), t) - - -#define ktapc_realloc(v, osize, nsize, t) \ - ((v) = (t *)ktapc_reallocv(v, osize * sizeof(t), nsize * sizeof(t))) - -#define ktapc_reallocvector(v,oldn,n,t) ktapc_realloc(v,oldn,n,t) - - -#define ktapc_growvector(v,nelems,size,t,limit,e) \ - if ((nelems)+1 > (size)) \ - ((v)=(t *)ktapc_growaux(v,&(size),sizeof(t),limit,e)) - - -void lex_init(); -ktap_string *lex_newstring(ktap_lexstate *ls, const char *str, size_t l); -const char *lex_token2str(ktap_lexstate *ls, int token); -void lex_syntaxerror(ktap_lexstate *ls, const char *msg); -void lex_setinput(ktap_lexstate *ls, char *ptr, ktap_string *source, int firstchar); -void lex_next(ktap_lexstate *ls); -int lex_lookahead(ktap_lexstate *ls); -void lex_read_string_until(ktap_lexstate *ls, int c); -ktap_closure *ktapc_parser(char *pos, const char *name); -ktap_string *ktapc_ts_new(const char *str); -int ktapc_ts_eqstr(ktap_string *a, ktap_string *b); -ktap_string *ktapc_ts_newlstr(const char *str, size_t l); -ktap_proto *ktapc_newproto(); -ktap_table *ktapc_table_new(); -const ktap_value *ktapc_table_get(ktap_table *t, const ktap_value *key); -void ktapc_table_setvalue(ktap_table *t, const ktap_value *key, ktap_value *val); -ktap_closure *ktapc_newlclosure(int n); -char *ktapc_sprintf(const char *fmt, ...); - -void *ktapc_reallocv(void *block, size_t osize, size_t nsize); -void *ktapc_growaux(void *block, int *size, size_t size_elems, int limit, - const char *what); - -void ktapio_exit(void); -int ktapio_create(const char *output_filename); - -ktap_string *ktapc_parse_eventdef(ktap_string *eventdef); -void cleanup_event_resources(void); - -extern int verbose; -#define verbose_printf(...) \ - if (verbose) \ - printf("[verbose] " __VA_ARGS__); - -#define ktapc_equalobj(t1, t2) kp_equalobjv(NULL, t1, t2) - - -#include "../include/ktap_opcodes.h" - -int codegen_stringK(ktap_funcstate *fs, ktap_string *s); -void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k); -void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults); -void codegen_reserveregs(ktap_funcstate *fs, int n); -void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e); -void codegen_nil(ktap_funcstate *fs, int from, int n); -void codegen_patchlist(ktap_funcstate *fs, int list, int target); -void codegen_patchclose(ktap_funcstate *fs, int list, int level); -int codegen_jump(ktap_funcstate *fs); -void codegen_patchtohere(ktap_funcstate *fs, int list); -int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc); -void codegen_ret(ktap_funcstate *fs, int first, int nret); -void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e); -void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e); -int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e); -int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c); -void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore); -void codegen_fixline (ktap_funcstate *fs, int line); -void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e); -void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key); -void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line); -void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v); -void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line); -void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e); -void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex); -void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex); -void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e); -int codegen_getlabel(ktap_funcstate *fs); -int codegen_codek(ktap_funcstate *fs, int reg, int k); -int codegen_numberK(ktap_funcstate *fs, ktap_number r); -void codegen_checkstack(ktap_funcstate *fs, int n); -void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e); -void codegen_concat(ktap_funcstate *fs, int *l1, int l2); -int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e); - -typedef int (*ktap_writer)(const void* p, size_t sz, void* ud); -int ktapc_dump(const ktap_proto *f, ktap_writer w, void *data, int strip); - -void ktapc_chunkid(char *out, const char *source, size_t bufflen); -int ktapc_str2d(const char *s, size_t len, ktap_number *result); -int ktapc_hexavalue(int c); -ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2); -int ktapc_int2fb(unsigned int x); - -bool strglobmatch(const char *str, const char *pat); - diff --git a/drivers/staging/ktap/userspace/ktapio.c b/drivers/staging/ktap/userspace/ktapio.c deleted file mode 100644 index f9bcab4..0000000 --- a/drivers/staging/ktap/userspace/ktapio.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * ktapio.c - ring buffer transport in userspace - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_BUFLEN 131072 -#define PATH_MAX 128 - -#define handle_error(str) do { perror(str); exit(-1); } while(0) - -extern pid_t ktap_pid; - -void sigfunc(int signo) -{ - /* should not not reach here */ -} - -static void block_sigint() -{ - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, SIGINT); - - pthread_sigmask(SIG_BLOCK, &mask, NULL); -} - -static void *reader_thread(void *data) -{ - char buf[MAX_BUFLEN]; - char filename[PATH_MAX]; - const char *output = data; - int failed = 0, fd, out_fd, len; - - block_sigint(); - - if (output) { - out_fd = open(output, O_CREAT | O_WRONLY | O_TRUNC, - S_IRUSR|S_IWUSR); - if (out_fd < 0) { - fprintf(stderr, "Cannot open output file %s\n", output); - return NULL; - } - } else - out_fd = 2; - - sprintf(filename, "/sys/kernel/debug/ktap/trace_pipe_%d", ktap_pid); - - open_again: - fd = open(filename, O_RDONLY); - if (fd < 0) { - usleep(10000); - - if (failed++ == 10) { - fprintf(stderr, "Cannot open file %s\n", filename); - return NULL; - } - goto open_again; - } - - while ((len = read(fd, buf, sizeof(buf))) > 0) - write(out_fd, buf, len); - - close(fd); - close(out_fd); - - return NULL; -} - -int ktapio_create(const char *output) -{ - pthread_t reader; - - signal(SIGINT, sigfunc); - - if (pthread_create(&reader, NULL, reader_thread, (void *)output) < 0) - handle_error("pthread_create reader_thread failed\n"); - - return 0; -} - diff --git a/drivers/staging/ktap/userspace/lex.c b/drivers/staging/ktap/userspace/lex.c deleted file mode 100644 index 484dd7f..0000000 --- a/drivers/staging/ktap/userspace/lex.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * lex.c - ktap lexical analyzer - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include "../include/ktap_types.h" -#include "ktapc.h" - -#define next(ls) (ls->current = *ls->ptr++) - -#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') - -#define KTAP_MINBUFFER 32 - -/* ORDER RESERVED */ -static const char *const ktap_tokens [] = { - "trace", "trace_end", "argevent", "argname", - "arg1", "arg2", "arg3", "arg4", "arg5", "arg6", "arg7", "arg9", "arg9", - "profile", "tick", - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "goto", "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", - "..", "...", "==", ">=", "<=", "!=", "+=", "::", "", - "", "", "" -}; - -#define save_and_next(ls) (save(ls, ls->current), next(ls)) - -static void lexerror(ktap_lexstate *ls, const char *msg, int token); - -static void save(ktap_lexstate *ls, int c) -{ - ktap_mbuffer *b = ls->buff; - if (mbuff_len(b) + 1 > mbuff_size(b)) { - size_t newsize; - if (mbuff_size(b) >= MAX_SIZET / 2) - lexerror(ls, "lexical element too long", 0); - newsize = mbuff_size(b) * 2; - mbuff_resize(b, newsize); - } - b->buffer[mbuff_len(b)++] = (char)c; -} - -void lex_init() -{ - int i; - for (i = 0; i < NUM_RESERVED; i++) { - ktap_string *ts = ktapc_ts_new(ktap_tokens[i]); - ts->tsv.extra = (u8)(i+1); /* reserved word */ - } -} - -const char *lex_token2str(ktap_lexstate *ls, int token) -{ - if (token < FIRST_RESERVED) { - ktap_assert(token == (unsigned char)token); - return (isprint(token)) ? ktapc_sprintf(KTAP_QL("%c"), token) : - ktapc_sprintf("char(%d)", token); - } else { - const char *s = ktap_tokens[token - FIRST_RESERVED]; - if (token < TK_EOS) - return ktapc_sprintf(KTAP_QS, s); - else - return s; - } -} - -static const char *txtToken(ktap_lexstate *ls, int token) -{ - switch (token) { - case TK_NAME: - case TK_STRING: - case TK_NUMBER: - save(ls, '\0'); - return ktapc_sprintf(KTAP_QS, mbuff(ls->buff)); - default: - return lex_token2str(ls, token); - } -} - -static void lexerror(ktap_lexstate *ls, const char *msg, int token) -{ - char buff[KTAP_IDSIZE]; - char *newmsg; - - ktapc_chunkid(buff, getstr(ls->source), KTAP_IDSIZE); - newmsg = ktapc_sprintf("%s:%d: %s", buff, ls->linenumber, msg); - if (token) - newmsg = ktapc_sprintf("%s near %s", newmsg, txtToken(ls, token)); - printf("lexerror: %s\n", newmsg); - exit(EXIT_FAILURE); -} - -void lex_syntaxerror(ktap_lexstate *ls, const char *msg) -{ - lexerror(ls, msg, ls->t.token); -} - -/* - * creates a new string and anchors it in function's table so that - * it will not be collected until the end of the function's compilation - * (by that time it should be anchored in function's prototype) - */ -ktap_string *lex_newstring(ktap_lexstate *ls, const char *str, size_t l) -{ - const ktap_value *o; /* entry for `str' */ - ktap_value val; /* entry for `str' */ - ktap_value tsv; - ktap_string *ts = ktapc_ts_newlstr(str, l); /* create new string */ - setsvalue(&tsv, ts); - o = ktapc_table_get(ls->fs->h, &tsv); - if (ttisnil(o)) { /* not in use yet? (see 'addK') */ - /* boolean value does not need GC barrier; - table has no metatable, so it does not need to invalidate cache */ - setbvalue(&val, 1); /* t[string] = true */ - ktapc_table_setvalue(ls->fs->h, &tsv, &val); - } - return ts; -} - -/* - * increment line number and skips newline sequence (any of - * \n, \r, \n\r, or \r\n) - */ -static void inclinenumber(ktap_lexstate *ls) -{ - int old = ls->current; - ktap_assert(currIsNewline(ls)); - next(ls); /* skip `\n' or `\r' */ - if (currIsNewline(ls) && ls->current != old) - next(ls); /* skip `\n\r' or `\r\n' */ - if (++ls->linenumber >= MAX_INT) - lex_syntaxerror(ls, "chunk has too many lines"); -} - -void lex_setinput(ktap_lexstate *ls, char *ptr, ktap_string *source, int firstchar) -{ - ls->decpoint = '.'; - ls->current = firstchar; - ls->lookahead.token = TK_EOS; /* no look-ahead token */ - ls->ptr = ptr; - ls->fs = NULL; - ls->linenumber = 1; - ls->lastline = 1; - ls->source = source; - ls->envn = ktapc_ts_new(KTAP_ENV); /* create env name */ - mbuff_resize(ls->buff, KTAP_MINBUFFER); /* initialize buffer */ -} - -/* - * ======================================================= - * LEXICAL ANALYZER - * ======================================================= - */ -static int check_next(ktap_lexstate *ls, const char *set) -{ - if (ls->current == '\0' || !strchr(set, ls->current)) - return 0; - save_and_next(ls); - return 1; -} - -/* - * change all characters 'from' in buffer to 'to' - */ -static void buffreplace(ktap_lexstate *ls, char from, char to) -{ - size_t n = mbuff_len(ls->buff); - char *p = mbuff(ls->buff); - while (n--) - if (p[n] == from) p[n] = to; -} - -#if !defined(getlocaledecpoint) -#define getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - -#define mbuff2d(b,e) ktapc_str2d(mbuff(b), mbuff_len(b) - 1, e) - -/* - * in case of format error, try to change decimal point separator to - * the one defined in the current locale and check again - */ -static void trydecpoint(ktap_lexstate *ls, ktap_seminfo *seminfo) -{ - char old = ls->decpoint; - ls->decpoint = getlocaledecpoint(); - buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ - if (!mbuff2d(ls->buff, &seminfo->r)) { - /* format error with correct decimal point: no more options */ - buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ - lexerror(ls, "malformed number", TK_NUMBER); - } -} - -/* - * this function is quite liberal in what it accepts, as 'ktapc_str2d' - * will reject ill-formed numerals. - */ -static void read_numeral(ktap_lexstate *ls, ktap_seminfo *seminfo) -{ - const char *expo = "Ee"; - int first = ls->current; - - ktap_assert(isdigit(ls->current)); - save_and_next(ls); - if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ - expo = "Pp"; - for (;;) { - if (check_next(ls, expo)) /* exponent part? */ - check_next(ls, "+-"); /* optional exponent sign */ - if (isxdigit(ls->current) || ls->current == '.') - save_and_next(ls); - else - break; - } - save(ls, '\0'); - buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ - if (!mbuff2d(ls->buff, &seminfo->r)) /* format error? */ - trydecpoint(ls, seminfo); /* try to update decimal point separator */ -} - -/* - * skip a sequence '[=*[' or ']=*]' and return its number of '='s or - * -1 if sequence is malformed - */ -static int skip_sep(ktap_lexstate *ls) -{ - int count = 0; - int s = ls->current; - - ktap_assert(s == '[' || s == ']'); - save_and_next(ls); - while (ls->current == '=') { - save_and_next(ls); - count++; - } - return (ls->current == s) ? count : (-count) - 1; -} - -static void read_long_string(ktap_lexstate *ls, ktap_seminfo *seminfo, int sep) -{ - save_and_next(ls); /* skip 2nd `[' */ - if (currIsNewline(ls)) /* string starts with a newline? */ - inclinenumber(ls); /* skip it */ - for (;;) { - switch (ls->current) { - case EOZ: - lexerror(ls, (seminfo) ? "unfinished long string" : - "unfinished long comment", TK_EOS); - break; /* to avoid warnings */ - case ']': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd `]' */ - goto endloop; - } - break; - } - case '\n': - case '\r': { - save(ls, '\n'); - inclinenumber(ls); - /* avoid wasting space */ - if (!seminfo) - mbuff_reset(ls->buff); - break; - } - default: { - if (seminfo) - save_and_next(ls); - else - next(ls); - } - } - } - - endloop: - if (seminfo) - seminfo->ts = lex_newstring(ls, mbuff(ls->buff) + (2 + sep), - mbuff_len(ls->buff) - 2*(2 + sep)); -} - -static void escerror(ktap_lexstate *ls, int *c, int n, const char *msg) -{ - int i; - mbuff_reset(ls->buff); /* prepare error message */ - save(ls, '\\'); - for (i = 0; i < n && c[i] != EOZ; i++) - save(ls, c[i]); - lexerror(ls, msg, TK_STRING); -} - -static int readhexaesc(ktap_lexstate *ls) -{ - int c[3], i; /* keep input for error message */ - int r = 0; /* result accumulator */ - c[0] = 'x'; /* for error message */ - for (i = 1; i < 3; i++) { /* read two hexa digits */ - c[i] = next(ls); - if (!isxdigit(c[i])) - escerror(ls, c, i + 1, "hexadecimal digit expected"); - r = (r << 4) + ktapc_hexavalue(c[i]); - } - return r; -} - -static int readdecesc(ktap_lexstate *ls) -{ - int c[3], i; - int r = 0; /* result accumulator */ - for (i = 0; i < 3 && isdigit(ls->current); i++) { /* read up to 3 digits */ - c[i] = ls->current; - r = 10*r + c[i] - '0'; - next(ls); - } - if (r > UCHAR_MAX) - escerror(ls, c, i, "decimal escape too large"); - return r; -} - -static void read_string(ktap_lexstate *ls, int del, ktap_seminfo *seminfo) -{ - save_and_next(ls); /* keep delimiter (for error messages) */ - while (ls->current != del) { - switch (ls->current) { - case EOZ: - lexerror(ls, "unfinished string", TK_EOS); - break; /* to avoid warnings */ - case '\n': - case '\r': - lexerror(ls, "unfinished string", TK_STRING); - break; /* to avoid warnings */ - case '\\': { /* escape sequences */ - int c; /* final character to be saved */ - next(ls); /* do not save the `\' */ - switch (ls->current) { - case 'a': c = '\a'; goto read_save; - case 'b': c = '\b'; goto read_save; - case 'f': c = '\f'; goto read_save; - case 'n': c = '\n'; goto read_save; - case 'r': c = '\r'; goto read_save; - case 't': c = '\t'; goto read_save; - case 'v': c = '\v'; goto read_save; - case 'x': c = readhexaesc(ls); goto read_save; - case '\n': case '\r': - inclinenumber(ls); c = '\n'; goto only_save; - case '\\': case '\"': case '\'': - c = ls->current; goto read_save; - case EOZ: goto no_save; /* will raise an error next loop */ - case 'z': { /* zap following span of spaces */ - next(ls); /* skip the 'z' */ - while (isspace(ls->current)) { - if (currIsNewline(ls)) - inclinenumber(ls); - else - next(ls); - } - goto no_save; - } - default: { - if (!isdigit(ls->current)) - escerror(ls, &ls->current, 1, "invalid escape sequence"); - /* digital escape \ddd */ - c = readdecesc(ls); - goto only_save; - } - } - read_save: - next(ls); /* read next character */ - only_save: - save(ls, c); /* save 'c' */ - no_save: - break; - } - default: - save_and_next(ls); - } - } - save_and_next(ls); /* skip delimiter */ - seminfo->ts = lex_newstring(ls, mbuff(ls->buff) + 1, mbuff_len(ls->buff) - 2); -} - -static int llex(ktap_lexstate *ls, ktap_seminfo *seminfo) -{ - mbuff_reset(ls->buff); - - for (;;) { - switch (ls->current) { - case '\n': case '\r': { /* line breaks */ - inclinenumber(ls); - break; - } - case ' ': case '\f': case '\t': case '\v': { /* spaces */ - next(ls); - break; - } - case '#': { - while (!currIsNewline(ls) && ls->current != EOZ) - next(ls); /* skip until end of line (or end of file) */ - break; - } - #if 0 - case '-': { /* '-' or '--' (comment) */ - next(ls); - if (ls->current != '-') - return '-'; - /* else is a comment */ - next(ls); - if (ls->current == '[') { /* long comment? */ - int sep = skip_sep(ls); - mbuff_reset(ls->buff); /* `skip_sep' may dirty the buffer */ - if (sep >= 0) { - read_long_string(ls, NULL, sep); /* skip long comment */ - mbuff_reset(ls->buff); /* previous call may dirty the buff. */ - break; - } - } - /* else short comment */ - while (!currIsNewline(ls) && ls->current != EOZ) - next(ls); /* skip until end of line (or end of file) */ - break; - } - #endif - case '[': { /* long string or simply '[' */ - int sep = skip_sep(ls); - if (sep >= 0) { - read_long_string(ls, seminfo, sep); - return TK_STRING; - } - else if (sep == -1) - return '['; - else - lexerror(ls, "invalid long string delimiter", TK_STRING); - } - case '+': { - next(ls); - if (ls->current != '=') - return '+'; - else { - next(ls); - return TK_INCR; - } - } - case '=': { - next(ls); - if (ls->current != '=') - return '='; - else { - next(ls); - return TK_EQ; - } - } - case '<': { - next(ls); - if (ls->current != '=') - return '<'; - else { - next(ls); - return TK_LE; - } - } - case '>': { - next(ls); - if (ls->current != '=') - return '>'; - else { - next(ls); - return TK_GE; - } - } - case '!': { - next(ls); - if (ls->current != '=') - return TK_NOT; - else { - next(ls); - return TK_NE; - } - } - case ':': { - next(ls); - if (ls->current != ':') - return ':'; - else { - next(ls); - return TK_DBCOLON; - } - } - case '"': case '\'': { /* short literal strings */ - read_string(ls, ls->current, seminfo); - return TK_STRING; - } - case '.': { /* '.', '..', '...', or number */ - save_and_next(ls); - if (check_next(ls, ".")) { - if (check_next(ls, ".")) - return TK_DOTS; /* '...' */ - else - return TK_CONCAT; /* '..' */ - } - else if (!isdigit(ls->current)) - return '.'; - /* else go through */ - } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - read_numeral(ls, seminfo); - return TK_NUMBER; - } - case EOZ: { - return TK_EOS; - } - case '&': { - next(ls); - if (ls->current != '&') - return '&'; - else { - next(ls); - return TK_AND; - } - } - case '|': { - next(ls); - if (ls->current != '|') - return '|'; - else { - next(ls); - return TK_OR; - } - } - default: { - if (islalpha(ls->current)) { - /* identifier or reserved word? */ - ktap_string *ts; - do { - save_and_next(ls); - } while (islalnum(ls->current)); - ts = lex_newstring(ls, mbuff(ls->buff), - mbuff_len(ls->buff)); - seminfo->ts = ts; - if (isreserved(ts)) /* reserved word? */ - return ts->tsv.extra - 1 + - FIRST_RESERVED; - else { - return TK_NAME; - } - } else { /* single-char tokens (+ - / ...) */ - int c = ls->current; - next(ls); - return c; - } - } - } - } -} - -void lex_read_string_until(ktap_lexstate *ls, int c) -{ - ktap_string *ts; - char errmsg[32]; - - mbuff_reset(ls->buff); - - while (ls->current == ' ') - next(ls); - - do { - save_and_next(ls); - } while (ls->current != c && ls->current != EOZ); - - if (ls->current != c) { - sprintf(errmsg, "expect %c", c); - lexerror(ls, errmsg, 0); - } - - ts = lex_newstring(ls, mbuff(ls->buff), mbuff_len(ls->buff)); - ls->t.seminfo.ts = ts; - ls->t.token = TK_STRING; -} - -void lex_next(ktap_lexstate *ls) -{ - ls->lastline = ls->linenumber; - if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ - ls->t = ls->lookahead; /* use this one */ - ls->lookahead.token = TK_EOS; /* and discharge it */ - } else - ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ -} - -int lex_lookahead(ktap_lexstate *ls) -{ - ktap_assert(ls->lookahead.token == TK_EOS); - ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); - return ls->lookahead.token; -} - diff --git a/drivers/staging/ktap/userspace/main.c b/drivers/staging/ktap/userspace/main.c deleted file mode 100644 index 2aa686a..0000000 --- a/drivers/staging/ktap/userspace/main.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * main.c - ktap compiler and loader entry - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../include/ktap_types.h" -#include "../include/ktap_opcodes.h" -#include "ktapc.h" - - -/*******************************************************************/ - -void *ktapc_reallocv(void *block, size_t osize, size_t nsize) -{ - return kp_reallocv(NULL, block, osize, nsize); -} - -ktap_closure *ktapc_newlclosure(int n) -{ - return kp_newlclosure(NULL, n); -} - -ktap_proto *ktapc_newproto() -{ - return kp_newproto(NULL); -} - -const ktap_value *ktapc_table_get(ktap_table *t, const ktap_value *key) -{ - return kp_table_get(t, key); -} - -void ktapc_table_setvalue(ktap_table *t, const ktap_value *key, ktap_value *val) -{ - kp_table_setvalue(NULL, t, key, val); -} - -ktap_table *ktapc_table_new() -{ - return kp_table_new(NULL); -} - -ktap_string *ktapc_ts_newlstr(const char *str, size_t l) -{ - return kp_tstring_newlstr(NULL, str, l); -} - -ktap_string *ktapc_ts_new(const char *str) -{ - return kp_tstring_new(NULL, str); -} - -int ktapc_ts_eqstr(ktap_string *a, ktap_string *b) -{ - return kp_tstring_eqstr(a, b); -} - -static void ktapc_runerror(const char *err_msg_fmt, ...) -{ - va_list ap; - - fprintf(stderr, "ktapc_runerror\n"); - - va_start(ap, err_msg_fmt); - vfprintf(stderr, err_msg_fmt, ap); - va_end(ap); - - exit(EXIT_FAILURE); -} - -/* - * todo: memory leak here - */ -char *ktapc_sprintf(const char *fmt, ...) -{ - char *msg = malloc(128); - - va_list argp; - va_start(argp, fmt); - vsprintf(msg, fmt, argp); - va_end(argp); - return msg; -} - - -#define MINSIZEARRAY 4 - -void *ktapc_growaux(void *block, int *size, size_t size_elems, int limit, - const char *what) -{ - void *newblock; - int newsize; - - if (*size >= limit/2) { /* cannot double it? */ - if (*size >= limit) /* cannot grow even a little? */ - ktapc_runerror("too many %s (limit is %d)\n", - what, limit); - newsize = limit; /* still have at least one free place */ - } else { - newsize = (*size) * 2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - } - - newblock = ktapc_reallocv(block, (*size) * size_elems, newsize * size_elems); - *size = newsize; /* update only when everything else is OK */ - return newblock; -} - -/*************************************************************************/ - -#define print_base(i) \ - do { \ - if (i < f->sizelocvars) /* it's a localvars */ \ - printf("%s", getstr(f->locvars[i].varname)); \ - else \ - printf("base + %d", i); \ - } while (0) - -#define print_RKC(instr) \ - do { \ - if (ISK(GETARG_C(instr))) \ - kp_showobj(NULL, k + INDEXK(GETARG_C(instr))); \ - else \ - print_base(GETARG_C(instr)); \ - } while (0) - -static void decode_instruction(ktap_proto *f, int instr) -{ - int opcode = GET_OPCODE(instr); - ktap_value *k; - - k = f->k; - - printf("%.8x\t", instr); - printf("%s\t", ktap_opnames[opcode]); - - switch (opcode) { - case OP_GETTABUP: - print_base(GETARG_A(instr)); - printf(" <- "); - - if (GETARG_B(instr) == 0) - printf("global"); - else - printf("upvalues[%d]", GETARG_B(instr)); - - printf("{"); print_RKC(instr); printf("}"); - - break; - case OP_GETTABLE: - print_base(GETARG_A(instr)); - printf(" <- "); - - print_base(GETARG_B(instr)); - - printf("{"); - print_RKC(instr); - printf("}"); - break; - case OP_LOADK: - printf("\t"); - print_base(GETARG_A(instr)); - printf(" <- "); - - kp_showobj(NULL, k + GETARG_Bx(instr)); - break; - case OP_CALL: - printf("\t"); - print_base(GETARG_A(instr)); - break; - case OP_JMP: - printf("\t%d", GETARG_sBx(instr)); - break; - default: - break; - } - - printf("\n"); -} - -static int function_nr = 0; - -/* this is a debug function used for check bytecode chunk file */ -static void dump_function(int level, ktap_proto *f) -{ - int i; - - printf("\n----------------------------------------------------\n"); - printf("function %d [level %d]:\n", function_nr++, level); - printf("linedefined: %d\n", f->linedefined); - printf("lastlinedefined: %d\n", f->lastlinedefined); - printf("numparams: %d\n", f->numparams); - printf("is_vararg: %d\n", f->is_vararg); - printf("maxstacksize: %d\n", f->maxstacksize); - printf("source: %s\n", getstr(f->source)); - printf("sizelineinfo: %d \t", f->sizelineinfo); - for (i = 0; i < f->sizelineinfo; i++) - printf("%d ", f->lineinfo[i]); - printf("\n"); - - printf("sizek: %d\n", f->sizek); - for (i = 0; i < f->sizek; i++) { - switch(f->k[i].type) { - case KTAP_TNIL: - printf("\tNIL\n"); - break; - case KTAP_TBOOLEAN: - printf("\tBOOLEAN: "); - printf("%d\n", f->k[i].val.b); - break; - case KTAP_TNUMBER: - printf("\tTNUMBER: "); - printf("%ld\n", f->k[i].val.n); - break; - case KTAP_TSTRING: - printf("\tTSTRING: "); - printf("%s\n", svalue(&(f->k[i]))); - - break; - default: - printf("\terror: unknow constant type\n"); - } - } - - printf("sizelocvars: %d\n", f->sizelocvars); - for (i = 0; i < f->sizelocvars; i++) { - printf("\tlocvars: %s startpc: %d endpc: %d\n", - getstr(f->locvars[i].varname), f->locvars[i].startpc, - f->locvars[i].endpc); - } - - printf("sizeupvalues: %d\n", f->sizeupvalues); - for (i = 0; i < f->sizeupvalues; i++) { - printf("\tname: %s instack: %d idx: %d\n", - getstr(f->upvalues[i].name), f->upvalues[i].instack, - f->upvalues[i].idx); - } - - printf("\n"); - printf("sizecode: %d\n", f->sizecode); - for (i = 0; i < f->sizecode; i++) - decode_instruction(f, f->code[i]); - - printf("sizep: %d\n", f->sizep); - for (i = 0; i < f->sizep; i++) - dump_function(level + 1, f->p[i]); - -} - -static void usage(const char *msg_fmt, ...) -{ - va_list ap; - - va_start(ap, msg_fmt); - fprintf(stderr, msg_fmt, ap); - va_end(ap); - - fprintf(stderr, -"Usage: ktap [options] file [script args] -- cmd [args]\n" -" or: ktap [options] -e one-liner -- cmd [args]\n" -"\n" -"Options and arguments:\n" -" -o file : send script output to file, instead of stderr\n" -" -p pid : specific tracing pid\n" -" -C cpu : cpu to monitor in system-wide\n" -" -T : show timestamp for event\n" -" -V : show version\n" -" -v : enable verbose mode\n" -" -s : simple event tracing\n" -" -b : list byte codes\n" -" file : program read from script file\n" -" -- cmd [args] : workload to tracing\n"); - - exit(EXIT_FAILURE); -} - -ktap_global_state dummy_global_state; - -static void init_dummy_global_state() -{ - memset(&dummy_global_state, 0, sizeof(ktap_global_state)); - dummy_global_state.seed = 201236; - - kp_tstring_resize(NULL, 32); /* set inital string hashtable size */ -} - -#define handle_error(str) do { perror(str); exit(-1); } while(0) - -static struct ktap_parm uparm; -static int ktap_trunk_mem_size = 1024; - -static int ktapc_writer(const void* p, size_t sz, void* ud) -{ - if (uparm.trunk_len + sz > ktap_trunk_mem_size) { - int new_size = (uparm.trunk_len + sz) * 2; - uparm.trunk = realloc(uparm.trunk, new_size); - ktap_trunk_mem_size = new_size; - } - - memcpy(uparm.trunk + uparm.trunk_len, p, sz); - uparm.trunk_len += sz; - - return 0; -} - - -static int forks; -static char **workload_argv; - -static int fork_workload(int ktap_fd) -{ - int pid; - - pid = fork(); - if (pid < 0) - handle_error("failed to fork"); - - if (pid > 0) - return pid; - - signal(SIGTERM, SIG_DFL); - - execvp("", workload_argv); - - /* - * waiting ktapvm prepare all tracing event - * make it more robust in future. - */ - pause(); - - execvp(workload_argv[0], workload_argv); - - perror(workload_argv[0]); - exit(-1); - - return -1; -} - -#define KTAPVM_PATH "/sys/kernel/debug/ktap/ktapvm" - -static char *output_filename; -pid_t ktap_pid; - -static int run_ktapvm() -{ - int ktapvm_fd, ktap_fd; - int ret; - - ktap_pid = getpid(); - - ktapvm_fd = open(KTAPVM_PATH, O_RDONLY); - if (ktapvm_fd < 0) - handle_error("open " KTAPVM_PATH " failed"); - - ktap_fd = ioctl(ktapvm_fd, 0, NULL); - if (ktap_fd < 0) - handle_error("ioctl ktapvm failed"); - - ktapio_create(output_filename); - - if (forks) { - uparm.trace_pid = fork_workload(ktap_fd); - uparm.workload = 1; - } - - ret = ioctl(ktap_fd, KTAP_CMD_IOC_RUN, &uparm); - - close(ktap_fd); - close(ktapvm_fd); - - return ret; -} - -int verbose; -static int dump_bytecode; -static char oneline_src[1024]; -static int trace_pid = -1; -static int trace_cpu = -1; -static int print_timestamp; - -#define SIMPLE_ONE_LINER_FMT \ - "trace %s { print(cpu(), tid(), execname(), argevent) }" - -static const char *script_file; -static int script_args_start; -static int script_args_end; - -static void parse_option(int argc, char **argv) -{ - char pid[32] = {0}; - char cpu_str[32] = {0}; - char *next_arg; - int i, j; - - for (i = 1; i < argc; i++) { - if (argv[i][0] != '-') { - script_file = argv[i]; - if (!script_file) - usage(""); - - script_args_start = i + 1; - script_args_end = argc; - - for (j = i + 1; j < argc; j++) { - if (argv[j][0] == '-' && argv[j][1] == '-') - goto found_cmd; - } - - return; - } - - if (argv[i][0] == '-' && argv[i][1] == '-') { - j = i; - goto found_cmd; - } - - next_arg = argv[i + 1]; - - switch (argv[i][1]) { - case 'o': - output_filename = malloc(strlen(next_arg) + 1); - if (!output_filename) - return; - - strncpy(output_filename, next_arg, strlen(next_arg)); - i++; - break; - case 'e': - strncpy(oneline_src, next_arg, strlen(next_arg)); - i++; - break; - case 'p': - strncpy(pid, next_arg, strlen(next_arg)); - trace_pid = atoi(pid); - i++; - break; - case 'C': - strncpy(cpu_str, next_arg, strlen(next_arg)); - trace_cpu = atoi(cpu_str); - i++; - break; - case 'T': - print_timestamp = 1; - break; - case 'v': - verbose = 1; - break; - case 's': - sprintf(oneline_src, SIMPLE_ONE_LINER_FMT, next_arg); - i++; - break; - case 'b': - dump_bytecode = 1; - break; - case 'V': - case '?': - case 'h': - usage(""); - break; - default: - usage("wrong argument\n"); - break; - } - } - - return; - - found_cmd: - script_args_end = j; - forks = 1; - workload_argv = &argv[j + 1]; -} - -static void compile(const char *input) -{ - ktap_closure *cl; - char *buff; - struct stat sb; - int fdin; - - if (oneline_src[0] != '\0') { - init_dummy_global_state(); - cl = ktapc_parser(oneline_src, input); - goto dump; - } - - fdin = open(input, O_RDONLY); - if (fdin < 0) { - fprintf(stderr, "open file %s failed\n", input); - exit(-1); - } - - if (fstat(fdin, &sb) == -1) - handle_error("fstat failed"); - - buff = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); - if (buff == MAP_FAILED) - handle_error("mmap failed"); - - init_dummy_global_state(); - cl = ktapc_parser(buff, input); - - munmap(buff, sb.st_size); - close(fdin); - - dump: - if (dump_bytecode) { - dump_function(1, cl->l.p); - exit(0); - } - - /* ktapc output */ - uparm.trunk = malloc(ktap_trunk_mem_size); - if (!uparm.trunk) - handle_error("malloc failed"); - - ktapc_dump(cl->l.p, ktapc_writer, NULL, 0); -} - -int main(int argc, char **argv) -{ - char **ktapvm_argv; - int new_index, i; - int ret; - - if (argc == 1) - usage(""); - - parse_option(argc, argv); - - if (oneline_src[0] != '\0') - script_file = "one-liner"; - - compile(script_file); - - ktapvm_argv = (char **)malloc(sizeof(char *)*(script_args_end - - script_args_start + 1)); - if (!ktapvm_argv) { - fprintf(stderr, "canno allocate ktapvm_argv\n"); - return -1; - } - - ktapvm_argv[0] = malloc(strlen(script_file) + 1); - if (!ktapvm_argv[0]) { - fprintf(stderr, "canno allocate memory\n"); - return -1; - } - strcpy(ktapvm_argv[0], script_file); - ktapvm_argv[0][strlen(script_file)] = '\0'; - - /* pass rest argv into ktapvm */ - new_index = 1; - for (i = script_args_start; i < script_args_end; i++) { - ktapvm_argv[new_index] = malloc(strlen(argv[i]) + 1); - if (!ktapvm_argv[new_index]) { - fprintf(stderr, "canno allocate memory\n"); - return -1; - } - strcpy(ktapvm_argv[new_index], argv[i]); - ktapvm_argv[new_index][strlen(argv[i])] = '\0'; - new_index++; - } - - uparm.argv = ktapvm_argv; - uparm.argc = new_index; - uparm.verbose = verbose; - uparm.trace_pid = trace_pid; - uparm.trace_cpu = trace_cpu; - uparm.print_timestamp = print_timestamp; - - /* start running into kernel ktapvm */ - ret = run_ktapvm(); - - cleanup_event_resources(); - return ret; -} - - diff --git a/drivers/staging/ktap/userspace/parser.c b/drivers/staging/ktap/userspace/parser.c deleted file mode 100644 index dd9e2de..0000000 --- a/drivers/staging/ktap/userspace/parser.c +++ /dev/null @@ -1,1910 +0,0 @@ -/* - * parser.c - ktap parser - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include - -#include "../include/ktap_types.h" -#include "../include/ktap_opcodes.h" -#include "ktapc.h" - -/* maximum number of local variables per function (must be smaller - than 250, due to the bytecode format) */ -#define MAXVARS 200 - -#define hasmultret(k) ((k) == VCALL || (k) == VVARARG) - - -/* - * nodes for block list (list of active blocks) - */ -typedef struct ktap_blockcnt { - struct ktap_blockcnt *previous; /* chain */ - short firstlabel; /* index of first label in this block */ - short firstgoto; /* index of first pending goto in this block */ - u8 nactvar; /* # active locals outside the block */ - u8 upval; /* true if some variable in the block is an upvalue */ - u8 isloop; /* true if `block' is a loop */ -} ktap_blockcnt; - -/* - * prototypes for recursive non-terminal functions - */ -static void statement (ktap_lexstate *ls); -static void expr (ktap_lexstate *ls, ktap_expdesc *v); - -static void anchor_token(ktap_lexstate *ls) -{ - /* last token from outer function must be EOS */ - ktap_assert((int)(ls->fs != NULL) || ls->t.token == TK_EOS); - if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { - ktap_string *ts = ls->t.seminfo.ts; - lex_newstring(ls, getstr(ts), ts->tsv.len); - } -} - -/* semantic error */ -static void semerror(ktap_lexstate *ls, const char *msg) -{ - ls->t.token = 0; /* remove 'near to' from final message */ - lex_syntaxerror(ls, msg); -} - -static void error_expected(ktap_lexstate *ls, int token) -{ - lex_syntaxerror(ls, - ktapc_sprintf("%s expected", lex_token2str(ls, token))); -} - -static void errorlimit(ktap_funcstate *fs, int limit, const char *what) -{ - const char *msg; - int line = fs->f->linedefined; - const char *where = (line == 0) ? "main function" - : ktapc_sprintf("function at line %d", line); - - msg = ktapc_sprintf("too many %s (limit is %d) in %s", - what, limit, where); - lex_syntaxerror(fs->ls, msg); -} - -static void checklimit(ktap_funcstate *fs, int v, int l, const char *what) -{ - if (v > l) - errorlimit(fs, l, what); -} - -static int testnext(ktap_lexstate *ls, int c) -{ - if (ls->t.token == c) { - lex_next(ls); - return 1; - } - else - return 0; -} - -static void check(ktap_lexstate *ls, int c) -{ - if (ls->t.token != c) - error_expected(ls, c); -} - -static void checknext(ktap_lexstate *ls, int c) -{ - check(ls, c); - lex_next(ls); -} - -#define check_condition(ls,c,msg) { if (!(c)) lex_syntaxerror(ls, msg); } - -static void check_match(ktap_lexstate *ls, int what, int who, int where) -{ - if (!testnext(ls, what)) { - if (where == ls->linenumber) - error_expected(ls, what); - else { - lex_syntaxerror(ls, ktapc_sprintf( - "%s expected (to close %s at line %d)", - lex_token2str(ls, what), - lex_token2str(ls, who), where)); - } - } -} - -static ktap_string *str_checkname(ktap_lexstate *ls) -{ - ktap_string *ts; - - check(ls, TK_NAME); - ts = ls->t.seminfo.ts; - lex_next(ls); - return ts; -} - -static void init_exp(ktap_expdesc *e, expkind k, int i) -{ - e->f = e->t = NO_JUMP; - e->k = k; - e->u.info = i; -} - -static void codestring(ktap_lexstate *ls, ktap_expdesc *e, ktap_string *s) -{ - init_exp(e, VK, codegen_stringK(ls->fs, s)); -} - -static void checkname(ktap_lexstate *ls, ktap_expdesc *e) -{ - codestring(ls, e, str_checkname(ls)); -} - -static int registerlocalvar(ktap_lexstate *ls, ktap_string *varname) -{ - ktap_funcstate *fs = ls->fs; - ktap_proto *f = fs->f; - int oldsize = f->sizelocvars; - - ktapc_growvector(f->locvars, fs->nlocvars, f->sizelocvars, - ktap_locvar, SHRT_MAX, "local variables"); - - while (oldsize < f->sizelocvars) - f->locvars[oldsize++].varname = NULL; - - f->locvars[fs->nlocvars].varname = varname; - return fs->nlocvars++; -} - -static void new_localvar(ktap_lexstate *ls, ktap_string *name) -{ - ktap_funcstate *fs = ls->fs; - ktap_dyndata *dyd = ls->dyd; - int reg = registerlocalvar(ls, name); - - checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, - MAXVARS, "local variables"); - ktapc_growvector(dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, ktap_vardesc, MAX_INT, "local variables"); - dyd->actvar.arr[dyd->actvar.n++].idx = (short)reg; -} - -static void new_localvarliteral_(ktap_lexstate *ls, const char *name, size_t sz) -{ - new_localvar(ls, lex_newstring(ls, name, sz)); -} - -#define new_localvarliteral(ls,v) \ - new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) - -static ktap_locvar *getlocvar(ktap_funcstate *fs, int i) -{ - int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; - - ktap_assert(idx < fs->nlocvars); - return &fs->f->locvars[idx]; -} - -static void adjustlocalvars(ktap_lexstate *ls, int nvars) -{ - ktap_funcstate *fs = ls->fs; - - fs->nactvar = (u8)(fs->nactvar + nvars); - for (; nvars; nvars--) { - getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; - } -} - -static void removevars(ktap_funcstate *fs, int tolevel) -{ - fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); - - while (fs->nactvar > tolevel) - getlocvar(fs, --fs->nactvar)->endpc = fs->pc; -} - -static int searchupvalue(ktap_funcstate *fs, ktap_string *name) -{ - int i; - ktap_upvaldesc *up = fs->f->upvalues; - - for (i = 0; i < fs->nups; i++) { - if (ktapc_ts_eqstr(up[i].name, name)) - return i; - } - return -1; /* not found */ -} - -static int newupvalue(ktap_funcstate *fs, ktap_string *name, ktap_expdesc *v) -{ - ktap_proto *f = fs->f; - int oldsize = f->sizeupvalues; - - checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); - ktapc_growvector(f->upvalues, fs->nups, f->sizeupvalues, - ktap_upvaldesc, MAXUPVAL, "upvalues"); - - while (oldsize < f->sizeupvalues) - f->upvalues[oldsize++].name = NULL; - f->upvalues[(int)fs->nups].instack = (v->k == VLOCAL); - f->upvalues[(int)fs->nups].idx = (u8)(v->u.info); - f->upvalues[(int)fs->nups].name = name; - return fs->nups++; -} - -static int searchvar(ktap_funcstate *fs, ktap_string *n) -{ - int i; - - for (i = fs->nactvar-1; i >= 0; i--) { - if (ktapc_ts_eqstr(n, getlocvar(fs, i)->varname)) - return i; - } - return -1; /* not found */ -} - -/* - * Mark block where variable at given level was defined - * (to emit close instructions later). - */ -static void markupval(ktap_funcstate *fs, int level) -{ - ktap_blockcnt *bl = fs->bl; - - while (bl->nactvar > level) - bl = bl->previous; - bl->upval = 1; -} - -/* - * Find variable with given name 'n'. If it is an upvalue, add this - * upvalue into all intermediate functions. - */ -static int singlevaraux(ktap_funcstate *fs, ktap_string *n, ktap_expdesc *var, int base) -{ - if (fs == NULL) /* no more levels? */ - return VVOID; /* default is global */ - else { - int v = searchvar(fs, n); /* look up locals at current level */ - if (v >= 0) { /* found? */ - init_exp(var, VLOCAL, v); /* variable is local */ - if (!base) - markupval(fs, v); /* local will be used as an upval */ - return VLOCAL; - } else { /* not found as local at current level; try upvalues */ - int idx = searchupvalue(fs, n); /* try existing upvalues */ - if (idx < 0) { /* not found? */ - if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ - return VVOID; /* not found; is a global */ - /* else was LOCAL or UPVAL */ - idx = newupvalue(fs, n, var); /* will be a new upvalue */ - } - init_exp(var, VUPVAL, idx); - return VUPVAL; - } - } -} - -static void singlevar(ktap_lexstate *ls, ktap_expdesc *var) -{ - ktap_string *varname = str_checkname(ls); - ktap_funcstate *fs = ls->fs; - - if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ - ktap_expdesc key; - singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ - ktap_assert(var->k == VLOCAL || var->k == VUPVAL); - codestring(ls, &key, varname); /* key is variable name */ - codegen_indexed(fs, var, &key); /* env[varname] */ - } -} - -static void adjust_assign(ktap_lexstate *ls, int nvars, int nexps, ktap_expdesc *e) -{ - ktap_funcstate *fs = ls->fs; - int extra = nvars - nexps; - - if (hasmultret(e->k)) { - extra++; /* includes call itself */ - if (extra < 0) - extra = 0; - codegen_setreturns(fs, e, extra); /* last exp. provides the difference */ - if (extra > 1) - codegen_reserveregs(fs, extra-1); - } else { - if (e->k != VVOID) - codegen_exp2nextreg(fs, e); /* close last expression */ - if (extra > 0) { - int reg = fs->freereg; - - codegen_reserveregs(fs, extra); - codegen_nil(fs, reg, extra); - } - } -} - -static void enterlevel(ktap_lexstate *ls) -{ - ++ls->nCcalls; - checklimit(ls->fs, ls->nCcalls, KTAP_MAXCCALLS, "C levels"); -} - -static void closegoto(ktap_lexstate *ls, int g, ktap_labeldesc *label) -{ - int i; - ktap_funcstate *fs = ls->fs; - ktap_labellist *gl = &ls->dyd->gt; - ktap_labeldesc *gt = &gl->arr[g]; - - ktap_assert(ktapc_ts_eqstr(gt->name, label->name)); - if (gt->nactvar < label->nactvar) { - ktap_string *vname = getlocvar(fs, gt->nactvar)->varname; - const char *msg = ktapc_sprintf( - " at line %d jumps into the scope of local " KTAP_QS, - getstr(gt->name), gt->line, getstr(vname)); - semerror(ls, msg); - } - - codegen_patchlist(fs, gt->pc, label->pc); - /* remove goto from pending list */ - for (i = g; i < gl->n - 1; i++) - gl->arr[i] = gl->arr[i + 1]; - gl->n--; -} - -/* - * try to close a goto with existing labels; this solves backward jumps - */ -static int findlabel(ktap_lexstate *ls, int g) -{ - int i; - ktap_blockcnt *bl = ls->fs->bl; - ktap_dyndata *dyd = ls->dyd; - ktap_labeldesc *gt = &dyd->gt.arr[g]; - - /* check labels in current block for a match */ - for (i = bl->firstlabel; i < dyd->label.n; i++) { - ktap_labeldesc *lb = &dyd->label.arr[i]; - if (ktapc_ts_eqstr(lb->name, gt->name)) { /* correct label? */ - if (gt->nactvar > lb->nactvar && - (bl->upval || dyd->label.n > bl->firstlabel)) - codegen_patchclose(ls->fs, gt->pc, lb->nactvar); - closegoto(ls, g, lb); /* close it */ - return 1; - } - } - return 0; /* label not found; cannot close goto */ -} - -static int newlabelentry(ktap_lexstate *ls, ktap_labellist *l, ktap_string *name, - int line, int pc) -{ - int n = l->n; - - ktapc_growvector(l->arr, n, l->size, - ktap_labeldesc, SHRT_MAX, "labels/gotos"); - l->arr[n].name = name; - l->arr[n].line = line; - l->arr[n].nactvar = ls->fs->nactvar; - l->arr[n].pc = pc; - l->n++; - return n; -} - - -/* - * check whether new label 'lb' matches any pending gotos in current - * block; solves forward jumps - */ -static void findgotos(ktap_lexstate *ls, ktap_labeldesc *lb) -{ - ktap_labellist *gl = &ls->dyd->gt; - int i = ls->fs->bl->firstgoto; - - while (i < gl->n) { - if (ktapc_ts_eqstr(gl->arr[i].name, lb->name)) - closegoto(ls, i, lb); - else - i++; - } -} - -/* - * "export" pending gotos to outer level, to check them against - * outer labels; if the block being exited has upvalues, and - * the goto exits the scope of any variable (which can be the - * upvalue), close those variables being exited. - */ -static void movegotosout(ktap_funcstate *fs, ktap_blockcnt *bl) -{ - int i = bl->firstgoto; - ktap_labellist *gl = &fs->ls->dyd->gt; - - /* correct pending gotos to current block and try to close it - with visible labels */ - while (i < gl->n) { - ktap_labeldesc *gt = &gl->arr[i]; - - if (gt->nactvar > bl->nactvar) { - if (bl->upval) - codegen_patchclose(fs, gt->pc, bl->nactvar); - gt->nactvar = bl->nactvar; - } - if (!findlabel(fs->ls, i)) - i++; /* move to next one */ - } -} - -static void enterblock(ktap_funcstate *fs, ktap_blockcnt *bl, u8 isloop) -{ - bl->isloop = isloop; - bl->nactvar = fs->nactvar; - bl->firstlabel = fs->ls->dyd->label.n; - bl->firstgoto = fs->ls->dyd->gt.n; - bl->upval = 0; - bl->previous = fs->bl; - fs->bl = bl; - ktap_assert(fs->freereg == fs->nactvar); -} - - -/* - * create a label named "break" to resolve break statements - */ -static void breaklabel(ktap_lexstate *ls) -{ - ktap_string *n = ktapc_ts_new("break"); - int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); - - findgotos(ls, &ls->dyd->label.arr[l]); -} - -/* - * generates an error for an undefined 'goto'; choose appropriate - * message when label name is a reserved word (which can only be 'break') - */ -static void undefgoto(ktap_lexstate *ls, ktap_labeldesc *gt) -{ - const char *msg = isreserved(gt->name) - ? "<%s> at line %d not inside a loop" - : "no visible label " KTAP_QS " for at line %d"; - - msg = ktapc_sprintf(msg, getstr(gt->name), gt->line); - semerror(ls, msg); -} - -static void leaveblock(ktap_funcstate *fs) -{ - ktap_blockcnt *bl = fs->bl; - ktap_lexstate *ls = fs->ls; - if (bl->previous && bl->upval) { - /* create a 'jump to here' to close upvalues */ - int j = codegen_jump(fs); - - codegen_patchclose(fs, j, bl->nactvar); - codegen_patchtohere(fs, j); - } - - if (bl->isloop) - breaklabel(ls); /* close pending breaks */ - - fs->bl = bl->previous; - removevars(fs, bl->nactvar); - ktap_assert(bl->nactvar == fs->nactvar); - fs->freereg = fs->nactvar; /* free registers */ - ls->dyd->label.n = bl->firstlabel; /* remove local labels */ - if (bl->previous) /* inner block? */ - movegotosout(fs, bl); /* update pending gotos to outer block */ - else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ - undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ -} - -/* - * adds a new prototype into list of prototypes - */ -static ktap_proto *addprototype(ktap_lexstate *ls) -{ - ktap_proto *clp; - ktap_funcstate *fs = ls->fs; - ktap_proto *f = fs->f; /* prototype of current function */ - - if (fs->np >= f->sizep) { - int oldsize = f->sizep; - ktapc_growvector(f->p, fs->np, f->sizep, ktap_proto *, MAXARG_Bx, "functions"); - while (oldsize < f->sizep) - f->p[oldsize++] = NULL; - } - f->p[fs->np++] = clp = ktapc_newproto(); - return clp; -} - -/* - * codes instruction to create new closure in parent function - */ -static void codeclosure(ktap_lexstate *ls, ktap_expdesc *v) -{ - ktap_funcstate *fs = ls->fs->prev; - init_exp(v, VRELOCABLE, codegen_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); - codegen_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ -} - -static void open_func(ktap_lexstate *ls, ktap_funcstate *fs, ktap_blockcnt *bl) -{ - ktap_proto *f; - - fs->prev = ls->fs; /* linked list of funcstates */ - fs->ls = ls; - ls->fs = fs; - fs->pc = 0; - fs->lasttarget = 0; - fs->jpc = NO_JUMP; - fs->freereg = 0; - fs->nk = 0; - fs->np = 0; - fs->nups = 0; - fs->nlocvars = 0; - fs->nactvar = 0; - fs->firstlocal = ls->dyd->actvar.n; - fs->bl = NULL; - f = fs->f; - f->source = ls->source; - f->maxstacksize = 2; /* registers 0/1 are always valid */ - fs->h = ktapc_table_new(); - //table_resize(NULL, fs->h, 32, 32); - enterblock(fs, bl, 0); -} - -static void close_func(ktap_lexstate *ls) -{ - ktap_funcstate *fs = ls->fs; - ktap_proto *f = fs->f; - - codegen_ret(fs, 0, 0); /* final return */ - leaveblock(fs); - ktapc_reallocvector(f->code, f->sizecode, fs->pc, ktap_instruction); - f->sizecode = fs->pc; - ktapc_reallocvector(f->lineinfo, f->sizelineinfo, fs->pc, int); - f->sizelineinfo = fs->pc; - ktapc_reallocvector(f->k, f->sizek, fs->nk, ktap_value); - f->sizek = fs->nk; - ktapc_reallocvector(f->p, f->sizep, fs->np, ktap_proto *); - f->sizep = fs->np; - ktapc_reallocvector(f->locvars, f->sizelocvars, fs->nlocvars, ktap_locvar); - f->sizelocvars = fs->nlocvars; - ktapc_reallocvector(f->upvalues, f->sizeupvalues, fs->nups, ktap_upvaldesc); - f->sizeupvalues = fs->nups; - ktap_assert((int)(fs->bl == NULL)); - ls->fs = fs->prev; - /* last token read was anchored in defunct function; must re-anchor it */ - anchor_token(ls); -} - -/*============================================================*/ -/* GRAMMAR RULES */ -/*============================================================*/ - -/* - * check whether current token is in the follow set of a block. - * 'until' closes syntactical blocks, but do not close scope, - * so it handled in separate. - */ -static int block_follow(ktap_lexstate *ls, int withuntil) -{ - switch (ls->t.token) { - case TK_ELSE: case TK_ELSEIF: - case TK_END: case TK_EOS: - return 1; - case TK_UNTIL: - return withuntil; - case '}': - return 1; - default: - return 0; - } -} - -static void statlist(ktap_lexstate *ls) -{ - /* statlist -> { stat [`;'] } */ - while (!block_follow(ls, 1)) { - if (ls->t.token == TK_RETURN) { - statement(ls); - return; /* 'return' must be last statement */ - } - statement(ls); - } -} - -static void fieldsel(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* fieldsel -> ['.' | ':'] NAME */ - ktap_funcstate *fs = ls->fs; - ktap_expdesc key; - - codegen_exp2anyregup(fs, v); - lex_next(ls); /* skip the dot or colon */ - checkname(ls, &key); - codegen_indexed(fs, v, &key); -} - -static void yindex(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* index -> '[' expr ']' */ - lex_next(ls); /* skip the '[' */ - expr(ls, v); - codegen_exp2val(ls->fs, v); - checknext(ls, ']'); -} - -/* - * {====================================================================== - * Rules for Constructors - * ======================================================================= - */ -struct ConsControl { - ktap_expdesc v; /* last list item read */ - ktap_expdesc *t; /* table descriptor */ - int nh; /* total number of `record' elements */ - int na; /* total number of array elements */ - int tostore; /* number of array elements pending to be stored */ -}; - -static void recfield(ktap_lexstate *ls, struct ConsControl *cc) -{ - /* recfield -> (NAME | `['exp1`]') = exp1 */ - ktap_funcstate *fs = ls->fs; - int reg = ls->fs->freereg; - ktap_expdesc key, val; - int rkkey; - - if (ls->t.token == TK_NAME) { - checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); - checkname(ls, &key); - } else /* ls->t.token == '[' */ - yindex(ls, &key); - - cc->nh++; - checknext(ls, '='); - rkkey = codegen_exp2RK(fs, &key); - expr(ls, &val); - codegen_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, codegen_exp2RK(fs, &val)); - fs->freereg = reg; /* free registers */ -} - -static void closelistfield(ktap_funcstate *fs, struct ConsControl *cc) -{ - if (cc->v.k == VVOID) - return; /* there is no list item */ - codegen_exp2nextreg(fs, &cc->v); - cc->v.k = VVOID; - if (cc->tostore == LFIELDS_PER_FLUSH) { - codegen_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ - cc->tostore = 0; /* no more items pending */ - } -} - -static void lastlistfield(ktap_funcstate *fs, struct ConsControl *cc) -{ - if (cc->tostore == 0) - return; - - if (hasmultret(cc->v.k)) { - codegen_setmultret(fs, &cc->v); - codegen_setlist(fs, cc->t->u.info, cc->na, KTAP_MULTRET); - cc->na--; /* do not count last expression (unknown number of elements) */ - } else { - if (cc->v.k != VVOID) - codegen_exp2nextreg(fs, &cc->v); - codegen_setlist(fs, cc->t->u.info, cc->na, cc->tostore); - } -} - -static void listfield(ktap_lexstate *ls, struct ConsControl *cc) -{ - /* listfield -> exp */ - expr(ls, &cc->v); - checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); - cc->na++; - cc->tostore++; -} - -static void field(ktap_lexstate *ls, struct ConsControl *cc) -{ - /* field -> listfield | recfield */ - switch(ls->t.token) { - case TK_NAME: { /* may be 'listfield' or 'recfield' */ - if (lex_lookahead(ls) != '=') /* expression? */ - listfield(ls, cc); - else - recfield(ls, cc); - break; - } - case '[': { - recfield(ls, cc); - break; - } - default: - listfield(ls, cc); - break; - } -} - -static void constructor(ktap_lexstate *ls, ktap_expdesc *t) -{ - /* constructor -> '{' [ field { sep field } [sep] ] '}' - sep -> ',' | ';' */ - ktap_funcstate *fs = ls->fs; - int line = ls->linenumber; - int pc = codegen_codeABC(fs, OP_NEWTABLE, 0, 0, 0); - struct ConsControl cc; - - cc.na = cc.nh = cc.tostore = 0; - cc.t = t; - init_exp(t, VRELOCABLE, pc); - init_exp(&cc.v, VVOID, 0); /* no value (yet) */ - codegen_exp2nextreg(ls->fs, t); /* fix it at stack top */ - checknext(ls, '{'); - do { - ktap_assert(cc.v.k == VVOID || cc.tostore > 0); - if (ls->t.token == '}') - break; - closelistfield(fs, &cc); - field(ls, &cc); - } while (testnext(ls, ',') || testnext(ls, ';')); - check_match(ls, '}', '{', line); - lastlistfield(fs, &cc); - SETARG_B(fs->f->code[pc], ktapc_int2fb(cc.na)); /* set initial array size */ - SETARG_C(fs->f->code[pc], ktapc_int2fb(cc.nh)); /* set initial table size */ -} - -/* }====================================================================== */ - -static void parlist(ktap_lexstate *ls) -{ - /* parlist -> [ param { `,' param } ] */ - ktap_funcstate *fs = ls->fs; - ktap_proto *f = fs->f; - int nparams = 0; - f->is_vararg = 0; - - if (ls->t.token != ')') { /* is `parlist' not empty? */ - do { - switch (ls->t.token) { - case TK_NAME: { /* param -> NAME */ - new_localvar(ls, str_checkname(ls)); - nparams++; - break; - } - case TK_DOTS: { /* param -> `...' */ - lex_next(ls); - f->is_vararg = 1; - break; - } - default: - lex_syntaxerror(ls, " or " KTAP_QL("...") " expected"); - } - } while (!f->is_vararg && testnext(ls, ',')); - } - adjustlocalvars(ls, nparams); - f->numparams = (u8)(fs->nactvar); - codegen_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ -} - -static void body(ktap_lexstate *ls, ktap_expdesc *e, int ismethod, int line) -{ - /* body -> `(' parlist `)' block END */ - ktap_funcstate new_fs; - ktap_blockcnt bl; - - new_fs.f = addprototype(ls); - new_fs.f->linedefined = line; - open_func(ls, &new_fs, &bl); - checknext(ls, '('); - if (ismethod) { - new_localvarliteral(ls, "self"); /* create 'self' parameter */ - adjustlocalvars(ls, 1); - } - parlist(ls); - checknext(ls, ')'); - checknext(ls, '{'); - statlist(ls); - new_fs.f->lastlinedefined = ls->linenumber; - checknext(ls, '}'); - //check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, e); - close_func(ls); -} - -static void func_body_no_args(ktap_lexstate *ls, ktap_expdesc *e, int line) -{ - /* body -> `(' parlist `)' block END */ - ktap_funcstate new_fs; - ktap_blockcnt bl; - - new_fs.f = addprototype(ls); - new_fs.f->linedefined = line; - open_func(ls, &new_fs, &bl); - checknext(ls, '{'); - statlist(ls); - new_fs.f->lastlinedefined = ls->linenumber; - checknext(ls, '}'); - //check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, e); - close_func(ls); -} - -static int explist(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* explist -> expr { `,' expr } */ - int n = 1; /* at least one expression */ - - expr(ls, v); - while (testnext(ls, ',')) { - codegen_exp2nextreg(ls->fs, v); - expr(ls, v); - n++; - } - return n; -} - -static void funcargs(ktap_lexstate *ls, ktap_expdesc *f, int line) -{ - ktap_funcstate *fs = ls->fs; - ktap_expdesc args; - int base, nparams; - - switch (ls->t.token) { - case '(': { /* funcargs -> `(' [ explist ] `)' */ - lex_next(ls); - if (ls->t.token == ')') /* arg list is empty? */ - args.k = VVOID; - else { - explist(ls, &args); - codegen_setmultret(fs, &args); - } - check_match(ls, ')', '(', line); - break; - } - case '{': { /* funcargs -> constructor */ - constructor(ls, &args); - break; - } - case TK_STRING: { /* funcargs -> STRING */ - codestring(ls, &args, ls->t.seminfo.ts); - lex_next(ls); /* must use `seminfo' before `next' */ - break; - } - default: { - lex_syntaxerror(ls, "function arguments expected"); - } - } - ktap_assert(f->k == VNONRELOC); - base = f->u.info; /* base register for call */ - if (hasmultret(args.k)) - nparams = KTAP_MULTRET; /* open call */ - else { - if (args.k != VVOID) - codegen_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - init_exp(f, VCALL, codegen_codeABC(fs, OP_CALL, base, nparams+1, 2)); - codegen_fixline(fs, line); - fs->freereg = base+1; /* call remove function and arguments and leaves - (unless changed) one result */ -} - -/* - * {====================================================================== - * Expression parsing - * ======================================================================= - */ -static void primaryexp(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* primaryexp -> NAME | '(' expr ')' */ - switch (ls->t.token) { - case '(': { - int line = ls->linenumber; - - lex_next(ls); - expr(ls, v); - check_match(ls, ')', '(', line); - codegen_dischargevars(ls->fs, v); - return; - } - case TK_NAME: - singlevar(ls, v); - return; - default: - lex_syntaxerror(ls, "unexpected symbol"); - } -} - -static void suffixedexp(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* suffixedexp -> - primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ - ktap_funcstate *fs = ls->fs; - int line = ls->linenumber; - - primaryexp(ls, v); - for (;;) { - switch (ls->t.token) { - case '.': { /* fieldsel */ - fieldsel(ls, v); - break; - } - case '[': { /* `[' exp1 `]' */ - ktap_expdesc key; - codegen_exp2anyregup(fs, v); - yindex(ls, &key); - codegen_indexed(fs, v, &key); - break; - } - case ':': { /* `:' NAME funcargs */ - ktap_expdesc key; - lex_next(ls); - checkname(ls, &key); - codegen_self(fs, v, &key); - funcargs(ls, v, line); - break; - } - case '(': case TK_STRING: case '{': { /* funcargs */ - codegen_exp2nextreg(fs, v); - funcargs(ls, v, line); - break; - } - default: - return; - } - } -} - -static void simpleexp(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | - constructor | FUNCTION body | suffixedexp */ - switch (ls->t.token) { - case TK_NUMBER: { - init_exp(v, VKNUM, 0); - v->u.nval = ls->t.seminfo.r; - break; - } - case TK_STRING: { - codestring(ls, v, ls->t.seminfo.ts); - break; - } - case TK_NIL: { - init_exp(v, VNIL, 0); - break; - } - case TK_TRUE: { - init_exp(v, VTRUE, 0); - break; - } - case TK_FALSE: { - init_exp(v, VFALSE, 0); - break; - } - case TK_DOTS: { /* vararg */ - ktap_funcstate *fs = ls->fs; - check_condition(ls, fs->f->is_vararg, - "cannot use " KTAP_QL("...") " outside a vararg function"); - init_exp(v, VVARARG, codegen_codeABC(fs, OP_VARARG, 0, 1, 0)); - break; - } - case '{': { /* constructor */ - constructor(ls, v); - return; - } - case TK_FUNCTION: { - lex_next(ls); - body(ls, v, 0, ls->linenumber); - return; - } - case TK_ARGEVENT: - init_exp(v, VEVENT, 0); - break; - - case TK_ARGNAME: - init_exp(v, VEVENTNAME, 0); - break; - case TK_ARG1: - case TK_ARG2: - case TK_ARG3: - case TK_ARG4: - case TK_ARG5: - case TK_ARG6: - case TK_ARG7: - case TK_ARG8: - case TK_ARG9: - init_exp(v, VEVENTARG, ls->t.token - TK_ARG1 + 1); - break; - default: { - suffixedexp(ls, v); - return; - } - } - lex_next(ls); -} - -static UnOpr getunopr(int op) -{ - switch (op) { - case TK_NOT: return OPR_NOT; - case '-': return OPR_MINUS; - case '#': return OPR_LEN; - default: return OPR_NOUNOPR; - } -} - -static BinOpr getbinopr(int op) -{ - switch (op) { - case '+': return OPR_ADD; - case '-': return OPR_SUB; - case '*': return OPR_MUL; - case '/': return OPR_DIV; - case '%': return OPR_MOD; - case '^': return OPR_POW; - case TK_CONCAT: return OPR_CONCAT; - case TK_NE: return OPR_NE; - case TK_EQ: return OPR_EQ; - case '<': return OPR_LT; - case TK_LE: return OPR_LE; - case '>': return OPR_GT; - case TK_GE: return OPR_GE; - case TK_AND: return OPR_AND; - case TK_OR: return OPR_OR; - default: return OPR_NOBINOPR; - } -} - -static const struct { - u8 left; /* left priority for each binary operator */ - u8 right; /* right priority */ -} priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ - {10, 9}, {5, 4}, /* ^, .. (right associative) */ - {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ - {3, 3}, {3, 3}, {3, 3}, /* !=, >, >= */ - {2, 2}, {1, 1} /* and, or */ -}; - -#define UNARY_PRIORITY 8 /* priority for unary operators */ - -#define leavelevel(ls) (ls->nCcalls--) - -/* - * subexpr -> (simpleexp | unop subexpr) { binop subexpr } - * where `binop' is any binary operator with a priority higher than `limit' - */ -static BinOpr subexpr(ktap_lexstate *ls, ktap_expdesc *v, int limit) -{ - BinOpr op; - UnOpr uop; - - enterlevel(ls); - uop = getunopr(ls->t.token); - if (uop != OPR_NOUNOPR) { - int line = ls->linenumber; - - lex_next(ls); - subexpr(ls, v, UNARY_PRIORITY); - codegen_prefix(ls->fs, uop, v, line); - } else - simpleexp(ls, v); - - /* expand while operators have priorities higher than `limit' */ - op = getbinopr(ls->t.token); - while (op != OPR_NOBINOPR && priority[op].left > limit) { - ktap_expdesc v2; - BinOpr nextop; - int line = ls->linenumber; - - lex_next(ls); - codegen_infix(ls->fs, op, v); - /* read sub-expression with higher priority */ - nextop = subexpr(ls, &v2, priority[op].right); - codegen_posfix(ls->fs, op, v, &v2, line); - op = nextop; - } - leavelevel(ls); - return op; /* return first untreated operator */ -} - -static void expr(ktap_lexstate *ls, ktap_expdesc *v) -{ - subexpr(ls, v, 0); -} - -/* }==================================================================== */ - -/* - * {====================================================================== - * Rules for Statements - * ======================================================================= - */ -static void block(ktap_lexstate *ls) -{ - /* block -> statlist */ - ktap_funcstate *fs = ls->fs; - ktap_blockcnt bl; - - enterblock(fs, &bl, 0); - statlist(ls); - leaveblock(fs); -} - -/* - * structure to chain all variables in the left-hand side of an - * assignment - */ -struct LHS_assign { - struct LHS_assign *prev; - ktap_expdesc v; /* variable (global, local, upvalue, or indexed) */ -}; - -/* - * check whether, in an assignment to an upvalue/local variable, the - * upvalue/local variable is begin used in a previous assignment to a - * table. If so, save original upvalue/local value in a safe place and - * use this safe copy in the previous assignment. - */ -static void check_conflict(ktap_lexstate *ls, struct LHS_assign *lh, ktap_expdesc *v) -{ - ktap_funcstate *fs = ls->fs; - int extra = fs->freereg; /* eventual position to save local variable */ - int conflict = 0; - - for (; lh; lh = lh->prev) { /* check all previous assignments */ - if (lh->v.k == VINDEXED) { /* assigning to a table? */ - /* table is the upvalue/local being assigned now? */ - if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { - conflict = 1; - lh->v.u.ind.vt = VLOCAL; - lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ - } - /* index is the local being assigned? (index cannot be upvalue) */ - if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { - conflict = 1; - lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ - } - } - } - if (conflict) { - /* copy upvalue/local value to a temporary (in position 'extra') */ - OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; - codegen_codeABC(fs, op, extra, v->u.info, 0); - codegen_reserveregs(fs, 1); - } -} - -static void assignment(ktap_lexstate *ls, struct LHS_assign *lh, int nvars) -{ - ktap_expdesc e; - - check_condition(ls, vkisvar(lh->v.k), "syntax error"); - if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ - struct LHS_assign nv; - - nv.prev = lh; - suffixedexp(ls, &nv.v); - if (nv.v.k != VINDEXED) - check_conflict(ls, lh, &nv.v); - checklimit(ls->fs, nvars + ls->nCcalls, KTAP_MAXCCALLS, - "C levels"); - assignment(ls, &nv, nvars+1); - } else if (testnext(ls, '=')) { /* assignment -> '=' explist */ - int nexps; - - nexps = explist(ls, &e); - if (nexps != nvars) { - adjust_assign(ls, nvars, nexps, &e); - /* remove extra values */ - if (nexps > nvars) - ls->fs->freereg -= nexps - nvars; - } else { - /* close last expression */ - codegen_setoneret(ls->fs, &e); - codegen_storevar(ls->fs, &lh->v, &e); - return; /* avoid default */ - } - } else if (testnext(ls, TK_INCR)) { /* assignment -> '+=' explist */ - int nexps; - - nexps = explist(ls, &e); - if (nexps != nvars) { - lex_syntaxerror(ls, "don't allow multi-assign for +="); - } else { - /* close last expression */ - codegen_setoneret(ls->fs, &e); - codegen_storeincr(ls->fs, &lh->v, &e); - return; /* avoid default */ - } - } - - init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ - codegen_storevar(ls->fs, &lh->v, &e); -} - -static int cond(ktap_lexstate *ls) -{ - /* cond -> exp */ - ktap_expdesc v; - expr(ls, &v); /* read condition */ - if (v.k == VNIL) - v.k = VFALSE; /* `falses' are all equal here */ - codegen_goiftrue(ls->fs, &v); - return v.f; -} - -static void gotostat(ktap_lexstate *ls, int pc) -{ - int line = ls->linenumber; - ktap_string *label; - int g; - - if (testnext(ls, TK_GOTO)) - label = str_checkname(ls); - else { - lex_next(ls); /* skip break */ - label = ktapc_ts_new("break"); - } - g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); - findlabel(ls, g); /* close it if label already defined */ -} - -/* check for repeated labels on the same block */ -static void checkrepeated(ktap_funcstate *fs, ktap_labellist *ll, ktap_string *label) -{ - int i; - for (i = fs->bl->firstlabel; i < ll->n; i++) { - if (ktapc_ts_eqstr(label, ll->arr[i].name)) { - const char *msg = ktapc_sprintf( - "label " KTAP_QS " already defined on line %d", - getstr(label), ll->arr[i].line); - semerror(fs->ls, msg); - } - } -} - -/* skip no-op statements */ -static void skipnoopstat(ktap_lexstate *ls) -{ - while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) - statement(ls); -} - -static void labelstat (ktap_lexstate *ls, ktap_string *label, int line) -{ - /* label -> '::' NAME '::' */ - ktap_funcstate *fs = ls->fs; - ktap_labellist *ll = &ls->dyd->label; - int l; /* index of new label being created */ - - checkrepeated(fs, ll, label); /* check for repeated labels */ - checknext(ls, TK_DBCOLON); /* skip double colon */ - /* create new entry for this label */ - l = newlabelentry(ls, ll, label, line, fs->pc); - skipnoopstat(ls); /* skip other no-op statements */ - if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ - /* assume that locals are already out of scope */ - ll->arr[l].nactvar = fs->bl->nactvar; - } - findgotos(ls, &ll->arr[l]); -} - -static void whilestat(ktap_lexstate *ls, int line) -{ - /* whilestat -> WHILE cond DO block END */ - ktap_funcstate *fs = ls->fs; - int whileinit; - int condexit; - ktap_blockcnt bl; - - lex_next(ls); /* skip WHILE */ - whileinit = codegen_getlabel(fs); - checknext(ls, '('); - condexit = cond(ls); - checknext(ls, ')'); - - enterblock(fs, &bl, 1); - //checknext(ls, TK_DO); - checknext(ls, '{'); - block(ls); - codegen_jumpto(fs, whileinit); - checknext(ls, '}'); - //check_match(ls, TK_END, TK_WHILE, line); - leaveblock(fs); - codegen_patchtohere(fs, condexit); /* false conditions finish the loop */ -} - -static void repeatstat(ktap_lexstate *ls, int line) -{ - /* repeatstat -> REPEAT block UNTIL cond */ - int condexit; - ktap_funcstate *fs = ls->fs; - int repeat_init = codegen_getlabel(fs); - ktap_blockcnt bl1, bl2; - - enterblock(fs, &bl1, 1); /* loop block */ - enterblock(fs, &bl2, 0); /* scope block */ - lex_next(ls); /* skip REPEAT */ - statlist(ls); - check_match(ls, TK_UNTIL, TK_REPEAT, line); - condexit = cond(ls); /* read condition (inside scope block) */ - if (bl2.upval) /* upvalues? */ - codegen_patchclose(fs, condexit, bl2.nactvar); - leaveblock(fs); /* finish scope */ - codegen_patchlist(fs, condexit, repeat_init); /* close the loop */ - leaveblock(fs); /* finish loop */ -} - -static int exp1(ktap_lexstate *ls) -{ - ktap_expdesc e; - int reg; - - expr(ls, &e); - codegen_exp2nextreg(ls->fs, &e); - ktap_assert(e.k == VNONRELOC); - reg = e.u.info; - return reg; -} - -static void forbody(ktap_lexstate *ls, int base, int line, int nvars, int isnum) -{ - /* forbody -> DO block */ - ktap_blockcnt bl; - ktap_funcstate *fs = ls->fs; - int prep, endfor; - - checknext(ls, ')'); - - adjustlocalvars(ls, 3); /* control variables */ - //checknext(ls, TK_DO); - checknext(ls, '{'); - prep = isnum ? codegen_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : codegen_jump(fs); - enterblock(fs, &bl, 0); /* scope for declared variables */ - adjustlocalvars(ls, nvars); - codegen_reserveregs(fs, nvars); - block(ls); - leaveblock(fs); /* end of scope for declared variables */ - codegen_patchtohere(fs, prep); - if (isnum) /* numeric for? */ - endfor = codegen_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); - else { /* generic for */ - codegen_codeABC(fs, OP_TFORCALL, base, 0, nvars); - codegen_fixline(fs, line); - endfor = codegen_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); - } - codegen_patchlist(fs, endfor, prep + 1); - codegen_fixline(fs, line); -} - -static void fornum(ktap_lexstate *ls, ktap_string *varname, int line) -{ - /* fornum -> NAME = exp1,exp1[,exp1] forbody */ - ktap_funcstate *fs = ls->fs; - int base = fs->freereg; - - new_localvarliteral(ls, "(for index)"); - new_localvarliteral(ls, "(for limit)"); - new_localvarliteral(ls, "(for step)"); - new_localvar(ls, varname); - checknext(ls, '='); - exp1(ls); /* initial value */ - checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ - else { /* default step = 1 */ - codegen_codek(fs, fs->freereg, codegen_numberK(fs, 1)); - codegen_reserveregs(fs, 1); - } - forbody(ls, base, line, 1, 1); -} - -static void forlist(ktap_lexstate *ls, ktap_string *indexname) -{ - /* forlist -> NAME {,NAME} IN explist forbody */ - ktap_funcstate *fs = ls->fs; - ktap_expdesc e; - int nvars = 4; /* gen, state, control, plus at least one declared var */ - int line; - int base = fs->freereg; - - /* create control variables */ - new_localvarliteral(ls, "(for generator)"); - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for control)"); - /* create declared variables */ - new_localvar(ls, indexname); - while (testnext(ls, ',')) { - new_localvar(ls, str_checkname(ls)); - nvars++; - } - checknext(ls, TK_IN); - line = ls->linenumber; - adjust_assign(ls, 3, explist(ls, &e), &e); - codegen_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 3, 0); -} - -static void forstat(ktap_lexstate *ls, int line) -{ - /* forstat -> FOR (fornum | forlist) END */ - ktap_funcstate *fs = ls->fs; - ktap_string *varname; - ktap_blockcnt bl; - - enterblock(fs, &bl, 1); /* scope for loop and control variables */ - lex_next(ls); /* skip `for' */ - - checknext(ls, '('); - varname = str_checkname(ls); /* first variable name */ - switch (ls->t.token) { - case '=': - fornum(ls, varname, line); - break; - case ',': case TK_IN: - forlist(ls, varname); - break; - default: - lex_syntaxerror(ls, KTAP_QL("=") " or " KTAP_QL("in") " expected"); - } - //check_match(ls, TK_END, TK_FOR, line); - checknext(ls, '}'); - leaveblock(fs); /* loop scope (`break' jumps to this point) */ -} - -static void test_then_block(ktap_lexstate *ls, int *escapelist) -{ - /* test_then_block -> [IF | ELSEIF] cond THEN block */ - ktap_blockcnt bl; - ktap_funcstate *fs = ls->fs; - ktap_expdesc v; - int jf; /* instruction to skip 'then' code (if condition is false) */ - - lex_next(ls); /* skip IF or ELSEIF */ - checknext(ls, '('); - expr(ls, &v); /* read condition */ - checknext(ls, ')'); - //checknext(ls, TK_THEN); - checknext(ls, '{'); - if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { - codegen_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ - enterblock(fs, &bl, 0); /* must enter block before 'goto' */ - gotostat(ls, v.t); /* handle goto/break */ - skipnoopstat(ls); /* skip other no-op statements */ - if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ - leaveblock(fs); - checknext(ls, '}'); - return; /* and that is it */ - } else /* must skip over 'then' part if condition is false */ - jf = codegen_jump(fs); - } else { /* regular case (not goto/break) */ - codegen_goiftrue(ls->fs, &v); /* skip over block if condition is false */ - enterblock(fs, &bl, 0); - jf = v.f; - } - statlist(ls); /* `then' part */ - checknext(ls, '}'); - leaveblock(fs); - if (ls->t.token == TK_ELSE || ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ - codegen_concat(fs, escapelist, codegen_jump(fs)); /* must jump over it */ - codegen_patchtohere(fs, jf); -} - -static void ifstat(ktap_lexstate *ls, int line) -{ - /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ - ktap_funcstate *fs = ls->fs; - int escapelist = NO_JUMP; /* exit list for finished parts */ - - test_then_block(ls, &escapelist); /* IF cond THEN block */ - while (ls->t.token == TK_ELSEIF) - test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ - if (testnext(ls, TK_ELSE)) { - checknext(ls, '{'); - block(ls); /* `else' part */ - checknext(ls, '}'); - } - //check_match(ls, TK_END, TK_IF, line); - codegen_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ -} - -static void localfunc(ktap_lexstate *ls) -{ - ktap_expdesc b; - ktap_funcstate *fs = ls->fs; - - new_localvar(ls, str_checkname(ls)); /* new local variable */ - adjustlocalvars(ls, 1); /* enter its scope */ - body(ls, &b, 0, ls->linenumber); /* function created in next register */ - /* debug information will only see the variable after this point! */ - getlocvar(fs, b.u.info)->startpc = fs->pc; -} - -static void localstat(ktap_lexstate *ls) -{ - /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ - int nvars = 0; - int nexps; - ktap_expdesc e; - - do { - new_localvar(ls, str_checkname(ls)); - nvars++; - } while (testnext(ls, ',')); - if (testnext(ls, '=')) - nexps = explist(ls, &e); - else { - e.k = VVOID; - nexps = 0; - } - adjust_assign(ls, nvars, nexps, &e); - adjustlocalvars(ls, nvars); -} - -static int funcname(ktap_lexstate *ls, ktap_expdesc *v) -{ - /* funcname -> NAME {fieldsel} [`:' NAME] */ - int ismethod = 0; - - singlevar(ls, v); - while (ls->t.token == '.') - fieldsel(ls, v); - if (ls->t.token == ':') { - ismethod = 1; - fieldsel(ls, v); - } - return ismethod; -} - -static void funcstat(ktap_lexstate *ls, int line) -{ - /* funcstat -> FUNCTION funcname body */ - int ismethod; - ktap_expdesc v, b; - - lex_next(ls); /* skip FUNCTION */ - ismethod = funcname(ls, &v); - body(ls, &b, ismethod, line); - codegen_storevar(ls->fs, &v, &b); - codegen_fixline(ls->fs, line); /* definition `happens' in the first line */ -} - -static void exprstat(ktap_lexstate *ls) -{ - /* stat -> func | assignment */ - ktap_funcstate *fs = ls->fs; - struct LHS_assign v; - - suffixedexp(ls, &v.v); - /* stat -> assignment ? */ - if (ls->t.token == '=' || ls->t.token == ',' || - ls->t.token == TK_INCR) { - v.prev = NULL; - assignment(ls, &v, 1); - } else { /* stat -> func */ - check_condition(ls, v.v.k == VCALL, "syntax error"); - SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ - } -} - -static void retstat(ktap_lexstate *ls) -{ - /* stat -> RETURN [explist] [';'] */ - ktap_funcstate *fs = ls->fs; - ktap_expdesc e; - int first, nret; /* registers with returned values */ - - if (block_follow(ls, 1) || ls->t.token == ';') - first = nret = 0; /* return no values */ - else { - nret = explist(ls, &e); /* optional return values */ - if (hasmultret(e.k)) { - codegen_setmultret(fs, &e); - if (e.k == VCALL && nret == 1) { /* tail call? */ - SET_OPCODE(getcode(fs,&e), OP_TAILCALL); - ktap_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); - } - first = fs->nactvar; - nret = KTAP_MULTRET; /* return all values */ - } else { - if (nret == 1) /* only one single value? */ - first = codegen_exp2anyreg(fs, &e); - else { - codegen_exp2nextreg(fs, &e); /* values must go to the `stack' */ - first = fs->nactvar; /* return all `active' values */ - ktap_assert(nret == fs->freereg - first); - } - } - } - codegen_ret(fs, first, nret); - testnext(ls, ';'); /* skip optional semicolon */ -} - -static void tracestat(ktap_lexstate *ls) -{ - ktap_expdesc v0, key, args; - ktap_expdesc *v = &v0; - ktap_string *kdebug_str = ktapc_ts_new("kdebug"); - ktap_string *probe_str = ktapc_ts_new("probe_by_id"); - ktap_string *probe_end_str = ktapc_ts_new("probe_end"); - ktap_funcstate *fs = ls->fs; - int token = ls->t.token; - int line = ls->linenumber; - int base, nparams; - - if (token == TK_TRACE) - lex_read_string_until(ls, '{'); - else - lex_next(ls); /* skip "trace_end" keyword */ - - /* kdebug */ - singlevaraux(fs, ls->envn, v, 1); /* get environment variable */ - codestring(ls, &key, kdebug_str); /* key is variable name */ - codegen_indexed(fs, v, &key); /* env[varname] */ - - /* fieldsel: kdebug.probe */ - codegen_exp2anyregup(fs, v); - if (token == TK_TRACE) - codestring(ls, &key, probe_str); - else if (token == TK_TRACE_END) - codestring(ls, &key, probe_end_str); - codegen_indexed(fs, v, &key); - - /* funcargs*/ - codegen_exp2nextreg(fs, v); - - if (token == TK_TRACE) { - /* argument: EVENTDEF string */ - check(ls, TK_STRING); - enterlevel(ls); - ktap_string *ts = ktapc_parse_eventdef(ls->t.seminfo.ts); - check_condition(ls, ts != NULL, "Cannot parse eventdef"); - codestring(ls, &args, ts); - lex_next(ls); /* skip EVENTDEF string */ - leavelevel(ls); - - codegen_exp2nextreg(fs, &args); /* for next argument */ - } - - /* argument: callback function */ - enterlevel(ls); - func_body_no_args(ls, &args, ls->linenumber); - leavelevel(ls); - - codegen_setmultret(fs, &args); - - base = v->u.info; /* base register for call */ - if (hasmultret(args.k)) - nparams = KTAP_MULTRET; /* open call */ - else { - codegen_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - init_exp(v, VCALL, codegen_codeABC(fs, OP_CALL, base, nparams+1, 2)); - codegen_fixline(fs, line); - fs->freereg = base+1; - - check_condition(ls, v->k == VCALL, "syntax error"); - SETARG_C(getcode(fs, v), 1); /* call statement uses no results */ -} - -static void timerstat(ktap_lexstate *ls) -{ - ktap_expdesc v0, key, args; - ktap_expdesc *v = &v0; - ktap_funcstate *fs = ls->fs; - ktap_string *token_str = ls->t.seminfo.ts; - ktap_string *interval_str; - int line = ls->linenumber; - int base, nparams; - - lex_next(ls); /* skip profile/tick keyword */ - check(ls, '-'); - - lex_read_string_until(ls, '{'); - interval_str = ls->t.seminfo.ts; - - //printf("timerstat str: %s\n", getstr(interval_str)); - //exit(0); - - /* timer */ - singlevaraux(fs, ls->envn, v, 1); /* get environment variable */ - codestring(ls, &key, ktapc_ts_new("timer")); /* key is variable name */ - codegen_indexed(fs, v, &key); /* env[varname] */ - - /* fieldsel: timer.profile, timer.tick */ - codegen_exp2anyregup(fs, v); - codestring(ls, &key, token_str); - codegen_indexed(fs, v, &key); - - /* funcargs*/ - codegen_exp2nextreg(fs, v); - - /* argument: interval string */ - check(ls, TK_STRING); - enterlevel(ls); - codestring(ls, &args, interval_str); - lex_next(ls); /* skip interval string */ - leavelevel(ls); - - codegen_exp2nextreg(fs, &args); /* for next argument */ - - /* argument: callback function */ - enterlevel(ls); - func_body_no_args(ls, &args, ls->linenumber); - leavelevel(ls); - - codegen_setmultret(fs, &args); - - base = v->u.info; /* base register for call */ - if (hasmultret(args.k)) - nparams = KTAP_MULTRET; /* open call */ - else { - codegen_exp2nextreg(fs, &args); /* close last argument */ - nparams = fs->freereg - (base+1); - } - init_exp(v, VCALL, codegen_codeABC(fs, OP_CALL, base, nparams+1, 2)); - codegen_fixline(fs, line); - fs->freereg = base+1; - - check_condition(ls, v->k == VCALL, "syntax error"); - SETARG_C(getcode(fs, v), 1); /* call statement uses no results */ -} - -static void statement(ktap_lexstate *ls) -{ - int line = ls->linenumber; /* may be needed for error messages */ - - enterlevel(ls); - switch (ls->t.token) { - case ';': { /* stat -> ';' (empty statement) */ - lex_next(ls); /* skip ';' */ - break; - } - case TK_IF: { /* stat -> ifstat */ - ifstat(ls, line); - break; - } - case TK_WHILE: { /* stat -> whilestat */ - whilestat(ls, line); - break; - } - case TK_DO: { /* stat -> DO block END */ - lex_next(ls); /* skip DO */ - block(ls); - check_match(ls, TK_END, TK_DO, line); - break; - } - case TK_FOR: { /* stat -> forstat */ - forstat(ls, line); - break; - } - case TK_REPEAT: { /* stat -> repeatstat */ - repeatstat(ls, line); - break; - } - case TK_FUNCTION: { /* stat -> funcstat */ - funcstat(ls, line); - break; - } - case TK_LOCAL: { /* stat -> localstat */ - lex_next(ls); /* skip LOCAL */ - if (testnext(ls, TK_FUNCTION)) /* local function? */ - localfunc(ls); - else - localstat(ls); - break; - } - case TK_DBCOLON: { /* stat -> label */ - lex_next(ls); /* skip double colon */ - labelstat(ls, str_checkname(ls), line); - break; - } - case TK_RETURN: { /* stat -> retstat */ - lex_next(ls); /* skip RETURN */ - retstat(ls); - break; - } - case TK_BREAK: /* stat -> breakstat */ - case TK_GOTO: { /* stat -> 'goto' NAME */ - gotostat(ls, codegen_jump(ls->fs)); - break; - } - - case TK_TRACE: - case TK_TRACE_END: - tracestat(ls); - break; - case TK_PROFILE: - case TK_TICK: - timerstat(ls); - break; - default: { /* stat -> func | assignment */ - exprstat(ls); - break; - } - } - //ktap_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && - // ls->fs->freereg >= ls->fs->nactvar); - ls->fs->freereg = ls->fs->nactvar; /* free registers */ - leavelevel(ls); -} -/* }====================================================================== */ - -/* - * compiles the main function, which is a regular vararg function with an upvalue - */ -static void mainfunc(ktap_lexstate *ls, ktap_funcstate *fs) -{ - ktap_blockcnt bl; - ktap_expdesc v; - - open_func(ls, fs, &bl); - fs->f->is_vararg = 1; /* main function is always vararg */ - init_exp(&v, VLOCAL, 0); /* create and... */ - newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ - lex_next(ls); /* read first token */ - statlist(ls); /* parse main body */ - check(ls, TK_EOS); - close_func(ls); -} - -ktap_closure *ktapc_parser(char *ptr, const char *name) -{ - ktap_lexstate lexstate; - ktap_funcstate funcstate; - ktap_dyndata dyd; - ktap_mbuffer buff; - int firstchar = *ptr++; - ktap_closure *cl = ktapc_newlclosure(1); /* create main closure */ - - memset(&lexstate, 0, sizeof(ktap_lexstate)); - memset(&funcstate, 0, sizeof(ktap_funcstate)); - funcstate.f = cl->l.p = ktapc_newproto(); - funcstate.f->source = ktapc_ts_new(name); /* create and anchor ktap_string */ - - lex_init(); - - mbuff_init(&buff); - memset(&dyd, 0, sizeof(ktap_dyndata)); - lexstate.buff = &buff; - lexstate.dyd = &dyd; - lex_setinput(&lexstate, ptr, funcstate.f->source, firstchar); - - mainfunc(&lexstate, &funcstate); - - ktap_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); - - /* all scopes should be correctly finished */ - ktap_assert(dyd.actvar.n == 0 && dyd.gt.n == 0 && dyd.label.n == 0); - return cl; -} - diff --git a/drivers/staging/ktap/userspace/util.c b/drivers/staging/ktap/userspace/util.c deleted file mode 100644 index 8124de9..0000000 --- a/drivers/staging/ktap/userspace/util.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * util.c - * - * This file is part of ktap by Jovi Zhangwei. - * - * Copyright (C) 2012-2013 Jovi Zhangwei . - * - * 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 -#include -#include -#include -#include "../include/ktap_types.h" -#include "ktapc.h" - -/* - * converts an integer to a "floating point byte", represented as - * (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if - * eeeee != 0 and (xxx) otherwise. - */ -int ktapc_int2fb(unsigned int x) -{ - int e = 0; /* exponent */ - - if (x < 8) - return x; - while (x >= 0x10) { - x = (x+1) >> 1; - e++; - } - return ((e+1) << 3) | ((int)x - 8); -} - -/* converts back */ -int ktapc_fb2int(int x) -{ - int e = (x >> 3) & 0x1f; - - if (e == 0) - return x; - else - return ((x & 7) + 8) << (e - 1); -} - -int ktapc_ceillog2(unsigned int x) -{ - static const u8 log_2[256] = { - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - }; - int l = 0; - - x--; - while (x >= 256) { - l += 8; - x >>= 8; - } - return l + log_2[x]; -} - -ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2) -{ - switch (op) { - case KTAP_OPADD: return NUMADD(v1, v2); - case KTAP_OPSUB: return NUMSUB(v1, v2); - case KTAP_OPMUL: return NUMMUL(v1, v2); - case KTAP_OPDIV: return NUMDIV(v1, v2); - case KTAP_OPMOD: return NUMMOD(v1, v2); - //case KTAP_OPPOW: return NUMPOW(v1, v2); - case KTAP_OPUNM: return NUMUNM(v1); - default: ktap_assert(0); return 0; - } -} - -int ktapc_hexavalue(int c) -{ - if (isdigit(c)) - return c - '0'; - else - return tolower(c) - 'a' + 10; -} - -static int isneg(const char **s) -{ - if (**s == '-') { - (*s)++; - return 1; - } else if (**s == '+') - (*s)++; - - return 0; -} - -static ktap_number readhexa(const char **s, ktap_number r, int *count) -{ - for (; isxdigit((unsigned char)(**s)); (*s)++) { /* read integer part */ - r = (r * 16.0) + (ktap_number)(ktapc_hexavalue((unsigned char)(**s))); - (*count)++; - } - - return r; -} - -/* - * convert an hexadecimal numeric string to a number, following - * C99 specification for 'strtod' - */ -static ktap_number strx2number(const char *s, char **endptr) -{ - ktap_number r = 0.0; - int e = 0, i = 0; - int neg = 0; /* 1 if number is negative */ - - *endptr = (char *)s; /* nothing is valid yet */ - while (isspace((unsigned char)(*s))) - s++; /* skip initial spaces */ - - neg = isneg(&s); /* check signal */ - if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ - return 0.0; /* invalid format (no '0x') */ - - s += 2; /* skip '0x' */ - r = readhexa(&s, r, &i); /* read integer part */ - if (*s == '.') { - s++; /* skip dot */ - r = readhexa(&s, r, &e); /* read fractional part */ - } - - if (i == 0 && e == 0) - return 0.0; /* invalid format (no digit) */ - e *= -4; /* each fractional digit divides value by 2^-4 */ - *endptr = (char *)s; /* valid up to here */ - - if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; - int neg1; - - s++; /* skip 'p' */ - neg1 = isneg(&s); /* signal */ - if (!isdigit((unsigned char)(*s))) - goto ret; /* must have at least one digit */ - while (isdigit((unsigned char)(*s))) /* read exponent */ - exp1 = exp1 * 10 + *(s++) - '0'; - if (neg1) exp1 = -exp1; - e += exp1; - } - - *endptr = (char *)s; /* valid up to here */ - ret: - if (neg) - r = -r; - - return ldexp(r, e); -} - -int ktapc_str2d(const char *s, size_t len, ktap_number *result) -{ - char *endptr; - - if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ - return 0; - else if (strpbrk(s, "xX")) /* hexa? */ - *result = strx2number(s, &endptr); - else - *result = strtod(s, &endptr); - - if (endptr == s) - return 0; /* nothing recognized */ - while (isspace((unsigned char)(*endptr))) - endptr++; - return (endptr == s + len); /* OK if no trailing characters */ -} - -/* number of chars of a literal string without the ending \0 */ -#define LL(x) (sizeof(x)/sizeof(char) - 1) - -#define RETS "..." -#define PRE "[string \"" -#define POS "\"]" - -#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) - -void ktapc_chunkid(char *out, const char *source, size_t bufflen) -{ - size_t l = strlen(source); - - if (*source == '=') { /* 'literal' source */ - if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l * sizeof(char)); - else { /* truncate it */ - addstr(out, source + 1, bufflen - 1); - *out = '\0'; - } - } else if (*source == '@') { /* file name */ - if (l <= bufflen) /* small enough? */ - memcpy(out, source + 1, l * sizeof(char)); - else { /* add '...' before rest of name */ - addstr(out, RETS, LL(RETS)); - bufflen -= LL(RETS); - memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); - } - } else { /* string; format as [string "source"] */ - const char *nl = strchr(source, '\n'); /* find first new line (if any) */ - addstr(out, PRE, LL(PRE)); /* add prefix */ - bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ - if (l < bufflen && nl == NULL) { /* small one-line source? */ - addstr(out, source, l); /* keep it */ - } else { - if (nl != NULL) - l = nl - source; /* stop at first newline */ - if (l > bufflen) - l = bufflen; - addstr(out, source, l); - addstr(out, RETS, LL(RETS)); - } - memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); - } -} - - -/* - * strglobmatch is copyed from perf(linux/tools/perf/util/string.c) - */ - -/* Character class matching */ -static bool __match_charclass(const char *pat, char c, const char **npat) -{ - bool complement = false, ret = true; - - if (*pat == '!') { - complement = true; - pat++; - } - if (*pat++ == c) /* First character is special */ - goto end; - - while (*pat && *pat != ']') { /* Matching */ - if (*pat == '-' && *(pat + 1) != ']') { /* Range */ - if (*(pat - 1) <= c && c <= *(pat + 1)) - goto end; - if (*(pat - 1) > *(pat + 1)) - goto error; - pat += 2; - } else if (*pat++ == c) - goto end; - } - if (!*pat) - goto error; - ret = false; - -end: - while (*pat && *pat != ']') /* Searching closing */ - pat++; - if (!*pat) - goto error; - *npat = pat + 1; - return complement ? !ret : ret; - -error: - return false; -} - -/* Glob/lazy pattern matching */ -static bool __match_glob(const char *str, const char *pat, bool ignore_space) -{ - while (*str && *pat && *pat != '*') { - if (ignore_space) { - /* Ignore spaces for lazy matching */ - if (isspace(*str)) { - str++; - continue; - } - if (isspace(*pat)) { - pat++; - continue; - } - } - if (*pat == '?') { /* Matches any single character */ - str++; - pat++; - continue; - } else if (*pat == '[') /* Character classes/Ranges */ - if (__match_charclass(pat + 1, *str, &pat)) { - str++; - continue; - } else - return false; - else if (*pat == '\\') /* Escaped char match as normal char */ - pat++; - if (*str++ != *pat++) - return false; - } - /* Check wild card */ - if (*pat == '*') { - while (*pat == '*') - pat++; - if (!*pat) /* Tail wild card matches all */ - return true; - while (*str) - if (__match_glob(str++, pat, ignore_space)) - return true; - } - return !*str && !*pat; -} - -/** - * strglobmatch - glob expression pattern matching - * @str: the target string to match - * @pat: the pattern string to match - * - * This returns true if the @str matches @pat. @pat can includes wildcards - * ('*','?') and character classes ([CHARS], complementation and ranges are - * also supported). Also, this supports escape character ('\') to use special - * characters as normal character. - * - * Note: if @pat syntax is broken, this always returns false. - */ -bool strglobmatch(const char *str, const char *pat) -{ - return __match_glob(str, pat, false); -} -