[PATCH v5 1/1] Initial support for LuaJIT scripting
Dmitry V. Levin
ldv at altlinux.org
Tue Jul 4 20:31:49 UTC 2017
On Tue, Jul 04, 2017 at 01:25:23PM +0300, Victor Krapivensky wrote:
[...]
> diff --git a/luajit_lib.h b/luajit_lib.h
> new file mode 100644
> index 00000000..16e49610
> --- /dev/null
> +++ b/luajit_lib.h
> @@ -0,0 +1,260 @@
> +"do\n\
> + local ffi = require(strace._ffilibname)\n\
> + local bit = require(strace._bitlibname)\n\
> + strace._en, strace._ex = {}, {}\n\
> + for p = 0, strace.npersonalities - 1 do\n\
> + strace._en[p] = {}\n\
> + strace._ex[p] = {}\n\
> + end\n\
> + local function chain(f, g)\n\
> + if not f then return g end\n\
> + return function(...)\n\
> + f(...)\n\
> + g(...)\n\
> + end\n\
> + end\n\
> + function strace.entering(tcp)\n\
> + return bit.band(tcp.flags, strace._tcbflg.insyscall) == 0\n\
> + end\n\
> + function strace.exiting(tcp)\n\
> + return bit.band(tcp.flags, strace._tcbflg.insyscall) ~= 0\n\
> + end\n\
> +\n\
> + -- `arg' defaults to true.\n\
> + local function alter_trace_opt(flagbit, tcp, arg)\n\
> + if strace.exiting(tcp) then\n\
> + error('altering tracing options must be done on syscall entering')\n\
> + end\n\
> + -- we want to support custom boolean-like objects, so check for nil explicitly\n\
> + if type(arg) == 'nil' or arg then\n\
> + tcp.qual_flg = bit.bor(tcp.qual_flg, flagbit)\n\
> + else\n\
> + tcp.qual_flg = bit.band(tcp.qual_flg, bit.bnot(flagbit))\n\
> + end\n\
> + end\n\
> + function strace.trace (tcp, arg) alter_trace_opt(strace._qualflg.trace, tcp, arg) end\n\
> + function strace.abbrev (tcp, arg) alter_trace_opt(strace._qualflg.abbrev, tcp, arg) end\n\
> + function strace.verbose(tcp, arg) alter_trace_opt(strace._qualflg.verbose, tcp, arg) end\n\
> + function strace.raw (tcp, arg) alter_trace_opt(strace._qualflg.raw, tcp, arg) end\n\
> +\n\
> + function strace.ptr_to_kulong(ptr)\n\
> + return ffi.cast('kernel_ulong_t', ffi.cast('unsigned long', ptr))\n\
> + end\n\
> + function strace.at_exit(f)\n\
> + strace._at_exit = chain(strace._at_exit, f)\n\
> + end\n\
> + function strace.get_err_name(err, pers)\n\
> + pers = pers or 0\n\
> + if err < 0 or err > strace.nerrnoent_vec[pers] then\n\
> + return nil\n\
> + end\n\
> + local s = strace.errnoent_vec[pers][err]\n\
> + if s ~= nil then\n\
> + return ffi.string(s)\n\
> + end\n\
> + return nil\n\
> + end\n\
> + function strace.get_sc_name(scno, pers)\n\
> + pers = pers or 0\n\
> + if scno < 0 or scno >= strace.nsysent_vec[pers] then\n\
> + return nil\n\
> + end\n\
> + local s = strace.sysent_vec[pers][scno].sys_name\n\
> + if s ~= nil then\n\
> + return ffi.string(s)\n\
> + end\n\
> + return nil\n\
> + end\n\
> + function strace.get_ioctl_name(code, pers)\n\
> + pers = pers or 0\n\
> + -- we could have provided a definition for stdlib's bsearch() and used it, but LuaJIT's FFI manual\n\
> + -- says generated callbacks are a limited resource and also slow. So implement binary search ourselves.\n\
> + local lb, rb = ffi.cast('unsigned int', 0), strace.nioctlent_vec[pers]\n\
> + if rb == 0 then\n\
> + return nil\n\
> + end\n\
> + local arr = strace.ioctlent_vec[pers]\n\
> + while rb - lb > 1 do\n\
> + local mid = lb + (rb - lb) / 2\n\
> + if arr[mid].code <= code then\n\
> + lb = mid\n\
> + else\n\
> + rb = mid\n\
> + end\n\
> + end\n\
> + if arr[lb].code == code then\n\
> + return ffi.string(arr[lb].symbol)\n\
> + end\n\
> + return nil\n\
> + end\n\
> + function strace.get_scno(scname, pers)\n\
> + pers = pers or 0\n\
> + for i = 0, tonumber(strace.nsysent_vec[pers]) - 1 do\n\
> + local s = strace.sysent_vec[pers][i].sys_name\n\
> + if s ~= nil and ffi.string(s) == scname then\n\
> + return i\n\
> + end\n\
> + end\n\
> + return nil\n\
> + end\n\
> + function strace.get_signo(signame, pers)\n\
> + pers = pers or 0\n\
> + for i = 0, tonumber(strace.nsignalent_vec[pers]) - 1 do\n\
> + local s = strace.signalent_vec[pers][i]\n\
> + if s ~= nil and ffi.string(s) == signame then\n\
> + return i\n\
> + end\n\
> + end\n\
> + return nil\n\
> + end\n\
> + function strace.get_errno(errname, pers)\n\
> + pers = pers or 0\n\
> + for i = 0, tonumber(strace.nerrnoent_vec[pers]) - 1 do\n\
> + local s = strace.errnoent_vec[pers][i]\n\
> + if s ~= nil and ffi.string(s) == errname then\n\
> + return i\n\
> + end\n\
> + end\n\
> + return nil\n\
> + end\n\
> + function strace.inject_signal(tcp, sig)\n\
> + if type(sig) == 'string' then\n\
> + sig = strace.get_signo(sig, tcp.currpers)\n\
> + if not sig then\n\
> + error('signal not found')\n\
> + end\n\
> + end\n\
> + if not strace.inject_signo(tcp, sig) then\n\
> + error('cannot inject signal')\n\
> + end\n\
> + end\n\
> + function strace.inject_error(tcp, err)\n\
> + if type(err) == 'string' then\n\
> + err = strace.get_errno(err, tcp.currpers)\n\
> + if not err then\n\
> + error('error not found')\n\
> + end\n\
> + end\n\
> + if err <= 0 then\n\
> + error('err must be positive')\n\
> + end\n\
> + if not strace.inject_retval(tcp, -err) then\n\
> + error('cannot inject error')\n\
> + end\n\
> + end\n\
> + function strace.read_obj(tcp, addr, ct, ...)\n\
> + local obj = ffi.new(ct, ...)\n\
> + return strace.umoven(tcp, addr, ffi.sizeof(obj, ...), obj) == 0 and obj or nil\n\
> + end\n\
> + function strace.read_str(tcp, addr, maxsz, bufsz)\n\
> + maxsz = maxsz or 4 * 1024 * 1024\n\
> + bufsz = bufsz or 1024\n\
> + local t = {}\n\
> + local buf = ffi.new('char[?]', bufsz)\n\
> + while true do\n\
> + local r = strace.umovestr(tcp, addr, bufsz, buf)\n\
> + if r < 0 then\n\
> + return nil\n\
> + elseif r == 0 then\n\
> + maxsz = maxsz - bufsz\n\
> + if maxsz < 0 then return nil end\n\
> + t[#t + 1] = ffi.string(buf, bufsz)\n\
> + addr = addr + bufsz\n\
> + else\n\
> + local s = ffi.string(buf)\n\
> + if #s > maxsz then return nil end\n\
> + return table.concat(t) .. s\n\
> + end\n\
> + end\n\
> + end\n\
> + function strace.read_path(tcp, addr)\n\
> + return strace.read_str(tcp, addr, strace.path_max, strace.path_max)\n\
> + end\n\
> + local function register_hook(scno, pers, en, ex, cb)\n\
> + assert(not not strace.monitor(scno, pers, en, ex))\n\
> + pers = tonumber(pers)\n\
> + scno = tonumber(scno)\n\
> + if en then\n\
> + strace._en[pers][scno] = chain(strace._en[pers][scno], cb)\n\
> + end\n\
> + if ex then\n\
> + strace._ex[pers][scno] = chain(strace._ex[pers][scno], cb)\n\
> + end\n\
> + end\n\
> + local function parse_when(when)\n\
> + if when == 'entering' then\n\
> + return true, false\n\
> + elseif when == 'exiting' then\n\
> + return false, true\n\
> + elseif when == 'both' then\n\
> + return true, true\n\
> + else\n\
> + error('unknown \"when\" value')\n\
> + end\n\
> + end\n\
> + function strace.monitor_all()\n\
> + for p = 0, strace.npersonalities - 1 do\n\
> + for i = 0, tonumber(strace.nsysent_vec[p]) - 1 do\n\
> + strace.monitor(i, p, true, true)\n\
> + end\n\
> + end\n\
> + end\n\
> + function strace.hook(scname, when, cb)\n\
> + local en, ex = parse_when(when)\n\
> + local found = false\n\
> + for p = 0, strace.npersonalities - 1 do\n\
> + local scno = strace.get_scno(scname, p)\n\
> + if scno then\n\
> + register_hook(scno, p, en, ex, cb)\n\
> + found = true\n\
> + end\n\
> + end\n\
> + if not found then\n\
> + error('syscall not found')\n\
> + end\n\
> + end\n\
> + function strace.hook_class(clsname, when, cb)\n\
> + local en, ex = parse_when(when)\n\
> + local flag = nil\n\
> + local ptr = strace.syscall_classes\n\
> + while ptr.name ~= nil do\n\
> + if ffi.string(ptr.name) == clsname then\n\
> + flag = ptr.value\n\
> + break\n\
> + end\n\
> + ptr = ptr + 1\n\
> + end\n\
> + if not flag then\n\
> + error('syscall class not found')\n\
> + end\n\
> + for p = 0, strace.npersonalities - 1 do\n\
> + for i = 0, tonumber(strace.nsysent_vec[p]) - 1 do\n\
> + if bit.band(strace.sysent_vec[p][i].sys_flags, flag) ~= 0 then\n\
> + register_hook(i, p, en, ex, cb)\n\
> + end\n\
> + end\n\
> + end\n\
> + end\n\
> + function strace.hook_scno(scno, when, cb, pers)\n\
> + pers = pers or 0\n\
> + local en, ex = parse_when(when)\n\
> + reigster_hook(scno, pers, en, ex, cb)\n\
> + end\n\
> + function strace._run()\n\
> + while true do\n\
> + local tcp = strace.next_sc()\n\
> + if tcp == nil then break end\n\
> + local cb = (strace.entering(tcp) and strace._en or strace._ex)[tonumber(tcp.currpers)][tonumber(tcp.scno)]\n\
> + if cb then cb(tcp) end\n\
> + end\n\
> + if strace._at_exit then strace._at_exit() end\n\
> + end\n\
> + function print(...)\n\
> + local sep = ''\n\
> + for i = 1, select('#', ...) do\n\
> + io.stderr:write(sep .. tostring(select(i, ...)))\n\
> + sep = '\\t'\n\
> + end\n\
> + io.stderr:write('\\n')\n\
> + end\n\
> +end"
This longish C string is actually a lua script, and it doesn't look nice
in this form. Wouldn't it be better if this script was translated into
a C string automatically by some Makefile rule?
--
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20170704/f9c5d88d/attachment.bin>
More information about the Strace-devel
mailing list