* tests/.gitignore: Add lua. * tests/Makefile.am (check_PROGRAMS): Likewise. (LUAJIT_TESTS): New variable. (TESTS): Add LUAJIT_TESTS. (EXTRA_DIST): Add lua.sh, lua-basics.test, lua-qual.test, lua-tampering.test. * tests/lua-basics.test: New file. * tests/lua-qual.test: Likewise. * tests/lua-tampering.test: Likewise. * tests/lua.c: Likewise. * tests/lua.sh: Likewise. --- tests/.gitignore | 1 + tests/Makefile.am | 13 +- tests/lua-basics.test | 306 +++++++++++++++++++++++++++++++++++++++++++++++ tests/lua-qual.test | 65 ++++++++++ tests/lua-tampering.test | 199 ++++++++++++++++++++++++++++++ tests/lua.c | 115 ++++++++++++++++++ tests/lua.sh | 11 ++ 7 files changed, 709 insertions(+), 1 deletion(-) create mode 100755 tests/lua-basics.test create mode 100755 tests/lua-qual.test create mode 100755 tests/lua-tampering.test create mode 100644 tests/lua.c create mode 100644 tests/lua.sh
diff --git a/tests/.gitignore b/tests/.gitignore index 45f08fca..dceb3139 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -165,6 +165,7 @@ lookup_dcookie lseek lstat lstat64 +lua madvise mbind membarrier diff --git a/tests/Makefile.am b/tests/Makefile.am index b4ba22a6..fbd367db 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -106,6 +106,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \ ioctl_rtc-v \ is_linux_mips_n64 \ ksysent \ + lua \ mmsg-silent \ mmsg_name-v \ msg_control-v \ @@ -185,6 +186,12 @@ else LIBUNWIND_TESTS = endif +if USE_LUAJIT +LUAJIT_TESTS = lua-basics.test lua-qual.test lua-tampering.test +else +LUAJIT_TESTS = +endif + DECODER_TESTS = \ brk.test \ btrfs-v.test \ @@ -292,7 +299,7 @@ MISC_TESTS = \ threads-execve.test \ # end of MISC_TESTS -TESTS = $(GEN_TESTS) $(DECODER_TESTS) $(MISC_TESTS) $(LIBUNWIND_TESTS) +TESTS = $(GEN_TESTS) $(DECODER_TESTS) $(MISC_TESTS) $(LIBUNWIND_TESTS) $(LUAJIT_TESTS) XFAIL_TESTS_ = XFAIL_TESTS_m32 = $(LIBUNWIND_TESTS) @@ -329,6 +336,10 @@ EXTRA_DIST = \ ipc_msgbuf.expected \ ksysent.sed \ lstatx.c \ + lua.sh \ + lua-basics.test \ + lua-qual.test \ + lua-tampering.test \ match.awk \ net.expected \ netlink_sock_diag-v.sh \ diff --git a/tests/lua-basics.test b/tests/lua-basics.test new file mode 100755 index 00000000..550f6fa0 --- /dev/null +++ b/tests/lua-basics.test @@ -0,0 +1,306 @@ +#!/bin/sh + +. "${srcdir=.}/lua.sh" + +misc_decls="\ +ffi = require 'ffi' +nullptr = ffi.NULL +pcall(function() + nullptr = ffi.C.NULL +end)" + +run_with_script() +{ + run_strace_with_script -e trace=readv,writev ../lua "$@" > "$EXP" + match_diff "$LOG" "$EXP" +} + +DATA=0123abcdefghijklnmop + +run_with_script $DATA $DATA <<EOF +EOF + +run_with_script $DATA $DATA <<EOF +-- check that callbacks are run in order they were registered +ntotal = 10 +ncur = 0 +for i = 0, ntotal - 1 do + strace.at_exit(function() + assert(ncur == i) + ncur = ncur + 1 + if ncur == ntotal then + assert(io.open('at-exit-marker', 'w')) + end + end) +end +EOF +if ! [ -f at-exit-marker ]; then + fail_ "'at-exit-marker' does not exist" +fi + +run_with_script $DATA $DATA <<EOF +$misc_decls +for i = 1, 10 do assert(strace.C.next_sc() == nullptr) end +EOF + +run_with_script $DATA $DATA <<EOF +$misc_decls +function check() + assert(not strace.C.inject_signo(1)) + assert(not strace.C.inject_retval(0)) + assert(strace.C.umove(0, 1, ffi.new('char [1]')) == -1) + assert(strace.C.umove_str(0, 1, ffi.new('char [1]')) < 0) + assert(strace.C.upoke(0, 1, 'x') == -1) + assert(not strace.C.path_match(ffi.new('const char *[1]', {'aaa'}), 1)) +end + +check() +assert(strace.C.next_sc() == nullptr) +check() +EOF + +when_decls() +{ + echo "----- start of 'when_decls $*' -----" + case "$1" in + entering) + echo "\ +hooks_per_syscall = 1 +function make_state_checker() + return function(tcp) + assert(tcp ~= nullptr) + assert(strace.entering(tcp)) + assert(not strace.exiting(tcp)) + end +end" + case "$2" in + s) echo "when_obj = 'entering'" ;; + t) echo "when_obj = {true, false}" ;; + esac + ;; + exiting) + echo "\ +hooks_per_syscall = 1 +function make_state_checker() + return function(tcp) + assert(tcp ~= nullptr) + assert(strace.exiting(tcp)) + assert(not strace.entering(tcp)) + end +end" + case "$2" in + s) echo "when_obj = 'exiting'" ;; + t) echo "when_obj = {false, true}" ;; + esac + ;; + both) + echo "\ +hooks_per_syscall = 2 +function make_state_checker() + local expect_entry = true + return function(tcp) + assert(tcp ~= nullptr) + if expect_entry then + assert(strace.entering(tcp)) + assert(not strace.exiting(tcp)) + else + assert(strace.exiting(tcp)) + assert(not strace.entering(tcp)) + end + expect_entry = not expect_entry + end +end" + case "$2" in + s) echo "when_obj = 'both'" ;; + t) echo "when_obj = {true, true}" ;; + esac + ;; + esac + echo "----- end of 'when_decls $*' -----" +} + +make_hook_decl="\ +----- start of 'make_hook_decl' ----- +function make_hook(no_at_exit_hook, state_checker) + state_checker = state_checker or make_state_checker() + local nwritev, nreadv = 0, 0 + local function check_nreadv() + assert(nreadv == hooks_per_syscall) + end + local function hook(tcp, kind) + state_checker(tcp) + local name = strace.get_sc_name(tcp.scno, tcp.currpers) + if kind == 'writev' or kind == 'readv' then + assert(name == kind) + elseif kind == '|' then + assert(name == 'writev' or name == 'readv') + else + assert(kind == '*', 'unknown \"kind\" value') + end + if name == 'writev' then + assert(nreadv == 0) + nwritev = nwritev + 1 + elseif name == 'readv' then + assert(nwritev == hooks_per_syscall) + nreadv = nreadv + 1 + end + end + if no_at_exit_hook then + return hook, check_nreadv + else + strace.at_exit(check_nreadv) + return hook + end +end +----- end of 'make_hook_decl' -----" + +for when in entering exiting both; do + run_with_script $DATA $DATA <<EOF +$misc_decls +$(when_decls $when t) +$make_hook_decl +strace.C.monitor_all(when_obj[1], when_obj[2]) +check_state = make_state_checker() +tcp = strace.C.next_sc() +check_state(tcp) +assert(strace.get_sc_name(tcp.scno, tcp.currpers) == 'execve') +if strace.entering(tcp) then + assert(strace.read_path(tcp.u_arg[0]) == '../lua') + assert(strace.path_match '../lua') + assert(strace.path_match{'aaa', '../lua', 'bbb'}) + assert(not strace.path_match{'aaa', 'bbb'}) + assert(not strace.path_match 'aaa') +end +hook, final_check = make_hook(true, check_state) +while strace.C.next_sc() ~= nullptr do + hook(tcp, '*') +end +final_check() +for i = 1, 10 do assert(strace.C.next_sc() == nullptr) end +EOF + + run_with_script $DATA $DATA <<EOF +$misc_decls +$(when_decls $when t) +check_state = make_state_checker() +for _, scname in ipairs{'writev', 'readv'} do + for p = 0, strace.npersonalities - 1 do + local scno = strace.get_scno(scname, p) + if scno then + assert(not not strace.C.monitor(scno, p, when_obj[1], + when_obj[2])) + end + end + for i = 1, hooks_per_syscall do + tcp = strace.C.next_sc() + check_state(tcp) + assert(strace.get_sc_name(tcp.scno, tcp.currpers) == scname) + end +end +for i = 1, 10 do assert(strace.C.next_sc() == nullptr) end +EOF + + for objtype in s t; do + for n in 1 5; do + run_with_script $DATA $DATA <<EOF +$misc_decls +$(when_decls $when $objtype) +$make_hook_decl +for i = 1, $n do + local hook = make_hook() + strace.hook('writev', when_obj, function(tcp) hook(tcp, 'writev') end) + strace.hook('readv', when_obj, function(tcp) hook(tcp, 'readv') end) +end +EOF + done + + run_with_script $DATA $DATA <<EOF +$misc_decls +$(when_decls $when $objtype) +$make_hook_decl +hook = make_hook() +strace.hook({'readv', 'writev'}, when_obj, function(tcp) hook(tcp, '|') end) +EOF + + run_with_script $DATA $DATA <<EOF +$misc_decls +$(when_decls $when $objtype) +$make_hook_decl +hook = make_hook() +for p = 0, strace.npersonalities - 1 do + local t = {} + t[#t + 1] = strace.get_scno('writev', p) + t[#t + 1] = strace.get_scno('readv', p) + strace.hook_scno(t, p, when_obj, function(tcp) hook(tcp, '|') end) +end +EOF + + run_with_script $DATA $DATA <<EOF +$misc_decls +$(when_decls $when $objtype) +$make_hook_decl +hook = make_hook() +strace.hook_class({'%desc', '%network'}, when_obj, + function(tcp) hook(tcp, '*') end) +EOF + + done +done + +run_with_script $DATA $DATA <<EOF +$misc_decls +int = ffi.typeof('int') +cstr = ffi.typeof('const char *') +read_scno = assert(strace.get_scno('read', 0)) + +assert(strace.get_sc_name( -1 , 0) == nil) +assert(strace.get_sc_name(int(-1), 0) == nil) +assert(strace.get_sc_name( strace.C.nsysent_vec[0] , 0) == nil) +assert(strace.get_sc_name(int(strace.C.nsysent_vec[0]), 0) == nil) +assert(strace.get_sc_name(int(read_scno), 0) == 'read') + +assert(strace.get_scno('' , 0) == nil) +assert(strace.get_scno( 'some nonsense' , 0) == nil) +assert(strace.get_scno(cstr('some nonsense'), 0) == nil) +assert(strace.get_scno(cstr('read'), 0) == read_scno) + +assert(strace.get_err_name( 1 , 0) == 'EPERM') +assert(strace.get_err_name(int(1), 0) == 'EPERM') +assert(strace.get_err_name( -1 , 0) == nil) +assert(strace.get_err_name(int(-1), 0) == nil) +assert(strace.get_err_name( strace.C.nerrnoent_vec[0] , 0) == nil) +assert(strace.get_err_name(int(strace.C.nerrnoent_vec[0]), 0) == nil) + +assert(strace.get_errno( '' , 0) == nil) +assert(strace.get_errno(cstr(''), 0) == nil) +assert(strace.get_errno('some nonsense', 0) == nil) +assert(strace.get_errno( 'EPERM' , 0) == 1) +assert(strace.get_errno(cstr('EPERM'), 0) == 1) + +assert(strace.get_sig_name( -1 , 0) == nil) +assert(strace.get_sig_name(int(-1), 0) == nil) +assert(strace.get_sig_name( 9 , 0) == 'SIGKILL') +assert(strace.get_sig_name(int(9), 0) == 'SIGKILL') + +assert(strace.get_signo('', 0) == nil) +assert(strace.get_signo( 'some nonsense' , 0) == nil) +assert(strace.get_signo(cstr('some nonsense'), 0) == nil) +assert(strace.get_signo( 'SIGKILL' , 0) == 9) +assert(strace.get_signo(cstr('SIGKILL'), 0) == 9) + +function check_ioctl_for(index, pers) + local entry = strace.C.ioctlent_vec[pers][index] + local s = ffi.string(entry.symbol) + assert(strace.get_ioctl_name( entry.code , pers) == s) + assert(strace.get_ioctl_name(tonumber(entry.code), pers) == s) + assert(strace.get_ioctl_code(entry.symbol, pers) == entry.code) + assert(strace.get_ioctl_code(s, pers) == entry.code) +end +check_ioctl_for(0, 0) +n = strace.C.nioctlent_vec[0] +check_ioctl_for(n / 2, 0) +check_ioctl_for(n - 1, 0) +assert(strace.get_ioctl_name( + strace.C.ioctlent_vec[0][n - 1].code + 1, 0) == nil) +assert(strace.get_ioctl_code('some nonsense', 0) == nil) +EOF diff --git a/tests/lua-qual.test b/tests/lua-qual.test new file mode 100755 index 00000000..8d0d2647 --- /dev/null +++ b/tests/lua-qual.test @@ -0,0 +1,65 @@ +#!/bin/sh +set -e + +. "${srcdir=.}/lua.sh" + +run_prog ../umovestr +pattern_abbrev_verbose='execve("\.\./umovestr", \["\.\./umovestr"\], 0x[[:xdigit:]]* /\* [[:digit:]]* vars \*/) = 0' +pattern_nonabbrev_verbose='execve("\.\./umovestr", \["\.\./umovestr"\], \[".*\"\(\.\.\.\)\?\]) = 0' +pattern_nonverbose='execve("\.\./umovestr", 0x[[:xdigit:]]*, 0x[[:xdigit:]]*) = 0' +pattern_raw='execve(0x[[:xdigit:]]*, 0x[[:xdigit:]]*, 0x[[:xdigit:]]*) = 0' + +check_output_mismatch() +{ + local pattern + pattern="$1"; shift + run_strace_with_script "$@" ../umovestr + LC_ALL=C grep -x "$pattern" "$LOG" > /dev/null || { + printf '%s\n%s\n' \ + 'Failed patterns of expected output:' "$pattern" + dump_log_and_fail_with "output mismatch" + } +} + +gen_script() +{ + local not= + if [ "$1" = '!' ]; then + not=not + shift + fi + echo "\ +ffi = require 'ffi' +nullptr = ffi.NULL +pcall(function() + nullptr = ffi.C.NULL +end) + +strace.C.monitor_all(true, false) +while true do + tcp = strace.C.next_sc() + if tcp == nullptr then + break + end + strace.$1(tcp, + $not strace.get_sc_name(tcp.scno, tcp.currpers) == 'execve') +end" +} + +gen_script trace | check_output_mismatch "$pattern_abbrev_verbose" + +LC_ALL=C grep -v -x "$pattern_abbrev_verbose" "$LOG" | +LC_ALL=C grep '^[[:alnum:]_]*(' > /dev/null && + dump_log_and_fail_with "unexpected output" + +gen_script \! abbrev | check_output_mismatch "$pattern_nonabbrev_verbose" +gen_script \! verbose | check_output_mismatch "$pattern_nonverbose" +gen_script raw | check_output_mismatch "$pattern_raw" + +check_output_mismatch "$pattern_abbrev_verbose" -e trace=none <<EOF +strace.hook_class('%process', 'entering', strace.trace) +EOF +LC_ALL=C grep '^chdir' "$LOG" > /dev/null && + dump_log_and_fail_with "unexpected output" + +exit 0 diff --git a/tests/lua-tampering.test b/tests/lua-tampering.test new file mode 100755 index 00000000..5005fecb --- /dev/null +++ b/tests/lua-tampering.test @@ -0,0 +1,199 @@ +#!/bin/sh + +. "${srcdir=.}/lua.sh" + +run_with_script_and_opts() +{ + local opts; opts="$1" + shift + run_strace_with_script $opts -e trace=readv,writev ../lua "$@" > "$EXP" + match_diff "$LOG" "$EXP" +} + +run_with_script() +{ + run_with_script_and_opts '' "$@" +} + +DATA=0123abcdefghijklnmop + +check_prog awk + +iovec_decls="\ +----- start of 'iovec_decls' ----- +ffi.cdef[[ +struct iovec { + void *iov_base; + size_t iov_len; +}; +]] +function decode_iovec(addr, pers) + local kulong = ffi.typeof('kernel_ulong_t') + if strace.C.pers_wordsize[pers] < ffi.sizeof(kulong) then + local v = strace.read_obj(addr, 'unsigned int [2]') + return kulong(v[0]), kulong(v[1]) + else + local v = assert(strace.read_obj(addr, 'struct iovec')) + return strace.ptr_to_kulong(v.iov_base), kulong(v.iov_len) + end +end +----- end of 'iovec_decls' -----" + +run_with_script $DATA $DATA <<EOF +ffi = require 'ffi' +$iovec_decls +function check_vecs(tcp, realsz) + assert(tcp.u_arg[2] == 1) + local v_base, v_len = decode_iovec(tcp.u_arg[1], tcp.currpers) + local n = realsz or v_len + assert(n == ${#DATA}) + local buf = assert(strace.read_obj(v_base, 'char [?]', n)) + assert(ffi.string(buf, n) == '$DATA') +end +strace.hook('writev', 'entering', check_vecs) +strace.hook('readv', 'exiting', function(tcp) + assert(tcp.u_rval ~= -1) + check_vecs(tcp, tcp.u_rval) +end) +EOF + +for s in '' A AB ABC ABCD ABCDEFGH ABCDEFGHIJK; do + run_with_script $DATA "$s" <<EOF +ffi = require 'ffi' +$iovec_decls +s = '$s' +strace.hook('readv', 'entering', function(tcp) + assert(tcp.u_arg[2] == 1) + local v_base, v_len = decode_iovec(tcp.u_arg[1], tcp.currpers) + assert(v_len >= #s) + assert(strace.C.upoke(v_base, #s, s) == 0) + assert(not not strace.C.inject_retval(#s)) +end) +EOF +done + +for off in 1 2 3; do + for str in A ABC ABCD ABCDEFGH; do + expected=$(echo | awk -v d="$DATA" -v s="$str" -v off="$off" \ + "{print substr(d,1,off) s substr(d,1+off+length(s))}") + run_with_script $DATA $expected <<EOF +ffi = require 'ffi' +$iovec_decls +ins_str, ins_off = '$str', $off +strace.hook('readv', 'exiting', function(tcp) + assert(tcp.u_arg[2] == 1) + local v_base, v_len = decode_iovec(tcp.u_arg[1], tcp.currpers) + assert(v_len >= #ins_str + ins_off) + assert(strace.write_obj(v_base + ins_off, + ffi.new('char [?]', #ins_str, ins_str))) +end) +EOF + done +done + +run_with_script -EPIPE $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_error(tcp, 'EPIPE') + first = false + end +end) +EOF + +# check overwriting command-line fault injection options +run_with_script_and_opts '-e inject=writev:error=ENOSYS:when=1' -EPIPE $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_error(tcp, 'EPIPE') + first = false + end +end) +EOF + +run_with_script -SIGUSR1 $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_signal(tcp, 'SIGUSR1') + first = false + end +end) +EOF + +# check overwriting command-line signal injection options +run_with_script_and_opts '-e inject=writev:signal=SIGUSR2:when=1' -SIGUSR1 $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_signal(tcp, 'SIGUSR1') + first = false + end +end) +EOF + +run_with_script -EPIPE -SIGUSR1 $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_signal(tcp, 'SIGUSR1') + strace.inject_error(tcp, 'EPIPE') + first = false + end +end) +EOF + +run_with_script -EPIPE -SIGUSR1 $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_error(tcp, 'EPIPE') + strace.inject_signal(tcp, 'SIGUSR1') + first = false + end +end) +EOF + +# check playing nice with command-line injection options +run_with_script_and_opts '-e inject=writev:signal=SIGUSR1:when=1' -EPIPE -SIGUSR1 $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_error(tcp, 'EPIPE') + first = false + end +end) +EOF + +run_with_script_and_opts '-e inject=writev:error=EPIPE:when=1' -EPIPE -SIGUSR1 $DATA $DATA <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_signal(tcp, 'SIGUSR1') + first = false + end +end) +EOF + +expected=tESt +run_with_script -EPIPE -SIGUSR1 $DATA $expected <<EOF +first = true +strace.hook('writev', 'entering', function(tcp) + if first then + strace.inject_error(tcp, 'EPIPE') + strace.inject_signal(tcp, 'SIGUSR1') + first = false + end +end) +ffi = require 'ffi' +$iovec_decls +s = '$expected' +strace.hook('readv', 'entering', function(tcp) + assert(not not strace.C.inject_retval(#s)) + assert(tcp.u_arg[2] == 1) + local v_base, v_len = decode_iovec(tcp.u_arg[1], tcp.currpers) + assert(v_len >= #s) + assert(strace.C.upoke(v_base, #s, s) == 0) +end) +EOF diff --git a/tests/lua.c b/tests/lua.c new file mode 100644 index 00000000..96102749 --- /dev/null +++ b/tests/lua.c @@ -0,0 +1,115 @@ +#include "tests.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/uio.h> +#include <signal.h> +#include <errno.h> + +static volatile int got_sig = 0; + +static void +handler(int sig) +{ + got_sig = 1; +} + +static void +expect_sigusr1_once(void) +{ + static bool first = true; + if (first) { + assert(got_sig); + got_sig = 0; + tprintf("--- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_KERNEL} " + "---\n"); + first = false; + } else + assert(!got_sig); +} + +int +main(int argc, char **argv) +{ + tprintf("%s", ""); + + const struct sigaction act = { .sa_handler = handler }; + if (sigaction(SIGUSR1, &act, NULL)) + perror_msg_and_fail("sigaction"); + + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) + perror_msg_and_fail("sigprocmask"); + + bool expect_sigusr1 = false; + bool expect_epipe = false; + + int curarg; + for (curarg = 1; curarg < argc; ++curarg) { + if (strcmp(argv[curarg], "-EPIPE") == 0) + expect_epipe = true; + else if (strcmp(argv[curarg], "-SIGUSR1") == 0) + expect_sigusr1 = true; + else + break; + } + assert(argc - curarg == 2); + char *towrite = argv[curarg++]; + size_t ntowrite = strlen(towrite); + char *toread = argv[curarg++]; + size_t ntoread = strlen(toread); + + int fds[2]; + if (pipe(fds) < 0) + perror_msg_and_fail("pipe"); + + if (expect_epipe) { + assert(writev(fds[1], (const struct iovec [1]) {{ + .iov_base = towrite, + .iov_len = ntowrite, + }}, 1) == -1 && errno == EPIPE); + tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%zu}], 1) = " + "-1 EPIPE (%s) (INJECTED)\n", + fds[1], towrite, ntowrite, strerror(EPIPE)); + if (expect_sigusr1) + expect_sigusr1_once(); + } + + assert(writev(fds[1], (const struct iovec [1]) {{ + .iov_base = towrite, + .iov_len = ntowrite, + }}, 1) == (ssize_t) ntowrite); + tprintf("writev(%d, [{iov_base=\"%s\", iov_len=%zu}], 1) = %zu\n", + fds[1], towrite, ntowrite, ntowrite); + if (expect_sigusr1) + expect_sigusr1_once(); + + if (close(fds[1]) < 0) + perror_msg_and_fail("close"); + + char *buf = malloc(ntoread + 1); + if (!buf) + perror_msg_and_fail("malloc"); + + assert(readv(fds[0], (const struct iovec [1]) {{ + .iov_base = buf, + .iov_len = ntoread + 1, + }}, 1) == (ssize_t) ntoread); + if (ntoread && memcmp(buf, toread, ntoread) != 0) { + buf[ntoread] = '\0'; + error_msg_and_fail("expected to read '%s', got '%s'", + toread, buf); + return 1; + } + tprintf("readv(%d, [{iov_base=\"%s\", iov_len=%zu}], 1) = %zu%s\n", + fds[0], toread, ntoread + 1, ntoread, + ntoread == ntowrite ? "" : " (INJECTED)"); + + tprintf("+++ exited with 0 +++\n"); + return 0; +} diff --git a/tests/lua.sh b/tests/lua.sh new file mode 100644 index 00000000..6be797d3 --- /dev/null +++ b/tests/lua.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +. "${srcdir=.}/init.sh" + +SCRIPTFILE=lua-script.lua + +run_strace_with_script() +{ + cat > "$SCRIPTFILE" || fail_ "cannot write $SCRIPTFILE" + run_strace -l "$SCRIPTFILE" "$@" +} -- 2.11.0 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel