This change also defines currpers field of struct tcb if LuaJIT is enabled, even if SUPPORTED_PERSONALITIES == 1.
* Makefile.am: Build with LuaJIT if configured so. (strace_SOURCES): Add defs_tcb.h, syscall_class.h. * configure.ac: Add new --with-luajit configure option. * defs.h (QUAL_HOOK_ENTRY, QUAL_HOOK_EXIT): new qual flags. Move definition of struct tcb that needs to be fed to LuaJIT's FFI to... * defs_tcb.h: ...new file. * luajit.h: New file. * luajit_funcs.h: Likewise. * luajit_lib.h: Likewise. * mpers_type.h (STRINGIFY): Rename to MPERS_STRINGIFY so that it does not pollute the global namespace. * qualify.c (syscall_classes): move syscall classes list to the global scope, terminate it with a null entry. (hook_entry_set, hook_exit_set): New sets (if built with LuaJIT support). (lookup_class): Use global, null entry-terminated list of syscall classes. (qual_flags): If built with LuaJIT, return QUAL_HOOK_ENTRY/QUAL_HOOK_EXIT flags. (set_hook_qual): New function. * strace.c (alloctcb): update the condition of presence of currpers field. (init): New -l option (if built with LuaJIT support). (main): run Lua script, if built with Lua scripting support and a script was provided. * syscall.c (syscall_exiting_decode): don't bail out if QUAL_HOOK_EXIT flag for this syscall it set. * syscall_class.h: New file. * sysent.h: Modify to support inclusion with FFI_CDEF. --- Makefile.am | 8 +++ configure.ac | 36 ++++++++++ defs.h | 39 ++-------- defs_tcb.h | 56 +++++++++++++++ luajit.h | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ luajit_funcs.h | 30 ++++++++ luajit_lib.h | 70 ++++++++++++++++++ mpers_type.h | 4 +- qualify.c | 85 +++++++++++++--------- strace.c | 35 ++++++++- syscall.c | 2 +- syscall_class.h | 27 +++++++ sysent.h | 31 +++++++- 13 files changed, 567 insertions(+), 72 deletions(-) create mode 100644 defs_tcb.h create mode 100644 luajit.h create mode 100644 luajit_funcs.h create mode 100644 luajit_lib.h create mode 100644 syscall_class.h diff --git a/Makefile.am b/Makefile.am index 80f8a341..7054477e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -100,6 +100,7 @@ strace_SOURCES = \ copy_file_range.c \ count.c \ defs.h \ + defs_tcb.h \ desc.c \ dirent.c \ dirent64.c \ @@ -242,6 +243,7 @@ strace_SOURCES = \ strace.c \ swapon.c \ syscall.c \ + syscall_class.h \ sysctl.c \ sysent.h \ sysinfo.c \ @@ -277,6 +279,12 @@ strace_LDFLAGS += $(libunwind_LDFLAGS) strace_LDADD += $(libunwind_LIBS) endif +if USE_LUAJIT +strace_SOURCES += luajit.h luajit_lib.h luajit_funcs.h +strace_CPPFLAGS += $(LUAJIT_CFLAGS) +strace_LDADD += $(LUAJIT_LIBS) +endif + @CODE_COVERAGE_RULES@ CODE_COVERAGE_BRANCH_COVERAGE = 1 CODE_COVERAGE_GENHTML_OPTIONS = $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) \ diff --git a/configure.ac b/configure.ac index dc49d397..afa1b2f2 100644 --- a/configure.ac +++ b/configure.ac @@ -715,6 +715,42 @@ AC_SUBST(dl_LIBS) AC_PATH_PROG([PERL], [perl]) +dnl LuaJIT scripting support +use_luajit=no +force_luajit=no +luajit_lib=luajit +LUAJIT_LIBS= +LUAJIT_CFLAGS= +AC_ARG_WITH([luajit], + [AS_HELP_STRING([--with-luajit], + [build with LuaJIT scripting support])], + [case "${withval}" in + yes) force_luajit=yes ;; + check) ;; + *) force_luajit=yes; luajit_lib="${withval}" ;; + esac], + [:] +) +AS_IF([test "x$luajit_lib" != xno], + [PKG_CHECK_MODULES([LUAJIT], + [$luajit_lib], + [use_luajit=yes], + [AS_IF([test "x$force_luajit" = xyes], + [AC_MSG_ERROR([cannot find luajit library: $luajit_lib])] + )] + )] +) + +dnl enable LuaJIT +AC_MSG_CHECKING([whether to enable Lua scripting]) +if test "x$use_luajit" = xyes; then + AC_DEFINE([USE_LUAJIT], 1, [Enable Lua scripting support]) + AC_SUBST(LUAJIT_LIBS) + AC_SUBST(LUAJIT_CFLAGS) +fi +AM_CONDITIONAL([USE_LUAJIT], [test "x$use_luajit" = xyes]) +AC_MSG_RESULT([$use_luajit]) + dnl stack trace with libunwind libunwind_CPPFLAGS= libunwind_LDFLAGS= diff --git a/defs.h b/defs.h index 6449bce9..8641929b 100644 --- a/defs.h +++ b/defs.h @@ -208,39 +208,7 @@ struct inject_opts { #define MAX_ERRNO_VALUE 4095 #define INJECT_OPTS_RVAL_DEFAULT (-(MAX_ERRNO_VALUE + 1)) -/* Trace Control Block */ -struct tcb { - int flags; /* See below for TCB_ values */ - int pid; /* If 0, this tcb is free */ - int qual_flg; /* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */ - unsigned long u_error; /* Error code */ - kernel_ulong_t scno; /* System call number */ - kernel_ulong_t u_arg[MAX_ARGS]; /* System call arguments */ - kernel_long_t u_rval; /* Return value */ -#if SUPPORTED_PERSONALITIES > 1 - unsigned int currpers; /* Personality at the time of scno update */ -#endif - int sys_func_rval; /* Syscall entry parser's return value */ - int curcol; /* Output column for this process */ - FILE *outf; /* Output file for this process */ - const char *auxstr; /* Auxiliary info from syscall (see RVAL_STR) */ - void *_priv_data; /* Private data for syscall decoding functions */ - void (*_free_priv_data)(void *); /* Callback for freeing priv_data */ - const struct_sysent *s_ent; /* sysent[scno] or dummy struct for bad scno */ - const struct_sysent *s_prev_ent; /* for "resuming interrupted SYSCALL" msg */ - struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES]; - struct timeval stime; /* System time usage as of last process wait */ - struct timeval dtime; /* Delta for system time usage */ - struct timeval etime; /* Syscall entry time */ - -#ifdef USE_LIBUNWIND - struct UPT_info* libunwind_ui; - struct mmap_cache_t* mmap_cache; - unsigned int mmap_cache_size; - unsigned int mmap_cache_generation; - struct queue_t* queue; -#endif -}; +#include "defs_tcb.h" /* TCB flags */ /* We have attached to this process, but did not see it stopping yet */ @@ -274,6 +242,8 @@ struct tcb { #define QUAL_SIGNAL 0x100 /* report events with this signal */ #define QUAL_READ 0x200 /* dump data read from this file descriptor */ #define QUAL_WRITE 0x400 /* dump data written to this file descriptor */ +#define QUAL_HOOK_ENTRY 0x800 /* return this syscall on entry from next_sc() */ +#define QUAL_HOOK_EXIT 0x1000 /* return this syscall on exit from next_sc() */ #define DEFAULT_QUAL_FLAGS (QUAL_TRACE | QUAL_ABBREV | QUAL_VERBOSE) @@ -658,6 +628,9 @@ extern struct number_set signal_set; extern bool is_number_in_set(unsigned int number, const struct number_set *); extern void qualify(const char *); extern unsigned int qual_flags(const unsigned int); +#ifdef USE_LUAJIT +extern void set_hook_qual(unsigned int scno, unsigned int pers, bool entry_hook, bool exit_hook); +#endif #define DECL_IOCTL(name) \ extern int \ diff --git a/defs_tcb.h b/defs_tcb.h new file mode 100644 index 00000000..f15f2864 --- /dev/null +++ b/defs_tcb.h @@ -0,0 +1,56 @@ +/* + * Should only be included without FFI_CDEF from defs.h, so no include guards. + */ + +#define STRINGIFY(...) #__VA_ARGS__ +#ifdef FFI_CDEF +# define CONTENT(...) STRINGIFY(__VA_ARGS__) +#else +# define CONTENT(...) __VA_ARGS__ +#endif + +CONTENT( +struct tcb { + int flags; /* See below for TCB_ values */ + int pid; /* If 0, this tcb is free */ + int qual_flg; /* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */ + unsigned long u_error; /* Error code */ + kernel_ulong_t scno; /* System call number */ + kernel_ulong_t u_arg[MAX_ARGS]; /* System call arguments */ + kernel_long_t u_rval; /* Return value */ +) + +#if defined(USE_LUAJIT) || SUPPORTED_PERSONALITIES > 1 +CONTENT( + unsigned int currpers; /* Personality at the time of scno update */ +) +#endif + +#ifndef FFI_CDEF + int sys_func_rval; /* Syscall entry parser's return value */ + int curcol; /* Output column for this process */ + FILE *outf; /* Output file for this process */ + const char *auxstr; /* Auxiliary info from syscall (see RVAL_STR) */ + void *_priv_data; /* Private data for syscall decoding functions */ + void (*_free_priv_data)(void *); /* Callback for freeing priv_data */ + const struct_sysent *s_ent; /* sysent[scno] or dummy struct for bad scno */ + const struct_sysent *s_prev_ent; /* for "resuming interrupted SYSCALL" msg */ + struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES]; + struct timeval stime; /* System time usage as of last process wait */ + struct timeval dtime; /* Delta for system time usage */ + struct timeval etime; /* Syscall entry time */ +# ifdef USE_LIBUNWIND + struct UPT_info* libunwind_ui; + struct mmap_cache_t* mmap_cache; + unsigned int mmap_cache_size; + unsigned int mmap_cache_generation; + struct queue_t* queue; +# endif +#endif /* FFI_CDEF */ + +CONTENT( +}; +) + +#undef STRINGIFY +#undef CONTENT diff --git a/luajit.h b/luajit.h new file mode 100644 index 00000000..62865673 --- /dev/null +++ b/luajit.h @@ -0,0 +1,216 @@ +/* + * Should only be included from strace.c, so no include guards. + */ + +#include "luajit_funcs.h" + +#define L script_L + +#define LUAJIT_FUNC(name) luajit_func_ ## name + +static struct tcb * +LUAJIT_FUNC(next_sc)(void) +{ + static struct timeval tv = {}; + static bool first = true; + +#define MBRESTART(res, sig) \ + if ((res) >= 0 && ptrace_restart(PTRACE_SYSCALL, current_tcp, sig) < 0) { \ + /* Note: ptrace_restart emitted error message */ \ + exit_code = 1; \ + return NULL; \ + } + + if (!first) { + unsigned int sig = 0; + int res; + if (entering(current_tcp)) { + res = syscall_entering_trace(current_tcp, &sig); + syscall_entering_finish(current_tcp, res); + } else { + res = syscall_exiting_trace(current_tcp, tv, 1); + syscall_exiting_finish(current_tcp); + } + MBRESTART(res, sig); + } + first = false; + + while (1) { + int status; + siginfo_t si; + enum trace_event ret = next_event(&status, &si); + if (ret == TE_SYSCALL_STOP) { + unsigned int sig = 0; + int res; + if (entering(current_tcp)) { + res = syscall_entering_decode(current_tcp); + switch (res) { + case 0: + break; + case 1: + if (current_tcp->qual_flg & QUAL_HOOK_ENTRY) + return current_tcp; + res = syscall_entering_trace(current_tcp, &sig); + /* fall through */ + default: + syscall_entering_finish(current_tcp, res); + } + } else { + res = syscall_exiting_decode(current_tcp, &tv); + switch (res) { + case 0: + break; + case 1: + if (current_tcp->qual_flg & QUAL_HOOK_EXIT) + return current_tcp; + /* fall through */ + default: + res = syscall_exiting_trace(current_tcp, tv, res); + } + syscall_exiting_finish(current_tcp); + } + MBRESTART(res, sig); + } else { + if (!dispatch_event(ret, &status, &si)) { + return NULL; + } + } + } +#undef MBRESTART +} + +static bool +LUAJIT_FUNC(monitor)(unsigned int scno, unsigned int pers, bool entry_hook, bool exit_hook) +{ + if (pers >= SUPPORTED_PERSONALITIES || scno >= nsyscall_vec[pers]) + return false; + set_hook_qual(scno, pers, entry_hook, exit_hook); + return true; +} + +static const char * +get_lua_msg(void) +{ + const char *msg = lua_tostring(L, -1); + return msg ? msg : "(error object can't be converted to string)"; +} + +static void +assert_lua_impl(int ret, const char *expr, const char *file, int line) +{ + if (ret == 0) + return; + error_msg_and_die("assert_lua(%s) failed at %s:%d: %s", expr, file, + line, get_lua_msg()); +} + +#define assert_lua(expr) assert_lua_impl(expr, #expr, __FILE__, __LINE__) + +static void +check_lua(int ret) +{ + if (ret == 0) + return; + error_msg_and_die("lua: %s", get_lua_msg()); +} + +static void +init_luajit(const char *scriptfile) +{ + static struct strace_luajit_funcs funcs = { +#define X(rettype, name, ...) LUAJIT_FUNC(name), +LUAJIT_FUNCS_XPAND() +#undef X + }; + + if (L) + /* already initialized? */ + error_msg_and_help("multiple -l arguments"); + + if (!(L = luaL_newstate())) + die_out_of_memory(); + + luaL_openlibs(L); + /* L: - */ + assert_lua(luaL_loadfile(L, scriptfile)); /* L: chunk */ + lua_getglobal(L, "require"); /* L: chunk require */ + lua_pushstring(L, "ffi"); /* L: chunk require "ffi" */ + assert_lua(lua_pcall(L, 1, 1, 0)); /* L: chunk ffi */ + lua_getfield(L, -1, "cdef"); /* L: chunk ffi cdef */ + luaL_Buffer b; + luaL_buffinit(L, &b); /* L: chunk ffi cdef ? */ + { + char buf[128]; + snprintf(buf, sizeof(buf), + "typedef int%zu_t kernel_long_t;" + "typedef uint%zu_t kernel_ulong_t;", + sizeof(kernel_long_t) * 8, + sizeof(kernel_ulong_t) * 8); + luaL_addstring(&b, buf); /* L: chunk ffi cdef ? */ + } + luaL_addstring(&b, +#define FFI_CDEF +#include "sysent.h" +#include "defs_tcb.h" +#include "luajit_funcs.h" +#include "syscall_class.h" +#undef FFI_CDEF + ); /* L: chunk ffi cdef ? */ + luaL_pushresult(&b); /* L: chunk ffi cdef str */ + assert_lua(lua_pcall(L, 1, 0, 0)); /* L: chunk ffi */ + lua_newtable(L); /* L: chunk ffi table */ + lua_getfield(L, -2, "cast"); /* L: chunk ffi table cast */ + lua_pushstring(L, "struct strace_luajit_funcs *"); /* L: chunk ffi table cast str */ + lua_pushlightuserdata(L, &funcs); /* L: chunk ffi table cast str ptr */ + + assert_lua(lua_pcall(L, 2, 1, 0)); /* L: chunk ffi table funcs */ + +#define X(rettype, name, ...) \ + lua_getfield(L, -1, #name); /* L: chunk ffi table funcs func */ \ + lua_setfield(L, -3, #name); /* L: chunk ffi table funcs */ +LUAJIT_FUNCS_XPAND() +#undef X + + lua_pop(L, 1); /* L: chunk ffi table */ + + lua_pushinteger(L, SUPPORTED_PERSONALITIES); /* L: chunk ffi table number */ + lua_setfield(L, -2, "npersonalities"); /* L: chunk ffi table */ + +#define EXPOSE(typestr, var) \ + lua_getfield(L, -2, "cast"); /* L: chunk ffi table cast */ \ + lua_pushstring(L, typestr); /* L: chunk ffi table cast str */ \ + lua_pushlightuserdata(L, (void *) var); /* L: chunk ffi table cast str ptr */ \ + assert_lua(lua_pcall(L, 2, 1, 0)); /* L: chunk ffi table var */ \ + lua_setfield(L, -2, #var); /* L: chunk ffi table */ + + EXPOSE("const struct_sysent **", sysent_vec) + EXPOSE("const unsigned int *", nsyscall_vec) + EXPOSE("const struct syscall_class *", syscall_classes) + +#undef EXPOSE + + lua_setglobal(L, "strace"); /* L: chunk ffi */ + lua_pop(L, 1); /* L: chunk */ + + const char *code = +#include "luajit_lib.h" + ; + assert_lua(luaL_dostring(L, code)); +} + +static void ATTRIBUTE_NORETURN +run_luajit(void) +{ + /* L: chunk */ + check_lua(lua_pcall(L, 0, 0, 0)); /* L: - */ + + lua_getglobal(L, "strace"); /* L: strace */ + lua_getfield(L, -1, "_run"); /* L: strace _run */ + check_lua(lua_pcall(L, 0, 0, 0)); /* L: strace */ + + terminate(); +} + +#undef assert_lua +#undef LUAJIT_FUNC +#undef L diff --git a/luajit_funcs.h b/luajit_funcs.h new file mode 100644 index 00000000..4ed16560 --- /dev/null +++ b/luajit_funcs.h @@ -0,0 +1,30 @@ +#if !defined(STRACE_LUAJIT_FUNCS_H) || defined(FFI_CDEF) +#ifndef FFI_CDEF +# define STRACE_LUAJIT_FUNCS_H +#endif + +#define STRINGIFY(...) #__VA_ARGS__ +#ifdef FFI_CDEF +# define CONTENT(...) STRINGIFY(__VA_ARGS__) +#else +# define CONTENT(...) __VA_ARGS__ +#endif + +#define LUAJIT_FUNCS_XPAND() \ + X(struct tcb *, next_sc, void) \ + X(bool, monitor, unsigned int scno, unsigned int pers, \ + bool entry_hook, bool exit_hook) \ + /* end */ + +#define X(rettype, name, ...) rettype (*name)(__VA_ARGS__); +CONTENT( +struct strace_luajit_funcs { + LUAJIT_FUNCS_XPAND() +}; +) +#undef X + +#undef STRINGIFY +#undef CONTENT + +#endif /* !defined(STRACE_LUAJIT_FUNCS_H) || defined(FFI_CDEF) */ diff --git a/luajit_lib.h b/luajit_lib.h new file mode 100644 index 00000000..5f97b0ea --- /dev/null +++ b/luajit_lib.h @@ -0,0 +1,70 @@ +#define STRINGIFY(...) #__VA_ARGS__ +#define STRVAL(...) STRINGIFY(__VA_ARGS__) + +"do\n\ + local ffi = require 'ffi'\n\ + local bit = require 'bit'\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(tcp)\n\ + f(tcp)\n\ + g(tcp)\n\ + end\n\ + end\n\ + function strace.hook(scname, how, cb)\n\ + local en, ex = false, false\n\ + if how == 'entering' then\n\ + en = true\n\ + elseif how == 'exiting' then\n\ + ex = true\n\ + elseif how == 'both' then\n\ + en, ex = true, true\n\ + else\n\ + error('unknown \"how\" value')\n\ + end\n\ + local found = false\n\ + for p = 0, strace.npersonalities - 1 do\n\ + for i = 0, tonumber(strace.nsyscall_vec[p]) - 1 do\n\ + local s = strace.sysent_vec[p][i].sys_name\n\ + if s ~= nil and ffi.string(s) == scname then\n\ + assert(strace.monitor(i, p, en, ex))\n\ + if en then strace._en[p][i] = chain(strace._en[p][i], cb) end\n\ + if ex then strace._ex[p][i] = chain(strace._ex[p][i], cb) end\n\ + found = true\n\ + end\n\ + end\n\ + end\n\ + if not found then\n\ + error('syscall not found')\n\ + end\n\ + end\n\ + function strace.entering(tcp)\n\ + return bit.band(tcp.flags, " STRVAL(TCB_INSYSCALL) ") == 0\n\ + end\n\ + function strace.exiting(tcp)\n\ + return bit.band(tcp.flags, " STRVAL(TCB_INSYSCALL) ") ~= 0\n\ + end\n\ + function strace.at_exit(f)\n\ + strace._at_exit = f\n\ + end\n\ + function strace._run()\n\ + while true do\n\ + local tcp = strace.next_sc()\n\ + if tcp == nil then\n\ + if strace._at_exit then strace._at_exit() end\n\ + break\n\ + end\n\ + local cb = (strace.entering(tcp) and strace._en or strace._ex)[tonumber(tcp.currpers)][tonumber(tcp.scno)]\n\ + cb(tcp)\n\ + end\n\ + end\n\ +end\n\ +" + +#undef STRINGIFY +#undef STRVAL diff --git a/mpers_type.h b/mpers_type.h index ecb1efa8..26c00767 100644 --- a/mpers_type.h +++ b/mpers_type.h @@ -31,8 +31,8 @@ #define STRACE_MPERS_TYPE_H #ifdef IN_MPERS -# define STRINGIFY(a) #a -# define DEF_MPERS_TYPE(args) STRINGIFY(args.h) +# define MPERS_STRINGIFY(a) #a +# define DEF_MPERS_TYPE(args) MPERS_STRINGIFY(args.h) # ifdef MPERS_IS_m32 # define MPERS_PREFIX m32_ # define MPERS_DEFS "m32_type_defs.h" diff --git a/qualify.c b/qualify.c index de1141d6..b44af1c0 100644 --- a/qualify.c +++ b/qualify.c @@ -28,8 +28,34 @@ #include "defs.h" #include "nsig.h" +#include "syscall_class.h" #include <regex.h> +const struct syscall_class syscall_classes[] = { + { "desc", TRACE_DESC }, + { "file", TRACE_FILE }, + { "memory", TRACE_MEMORY }, + { "process", TRACE_PROCESS }, + { "signal", TRACE_SIGNAL }, + { "ipc", TRACE_IPC }, + { "network", TRACE_NETWORK }, + { "%desc", TRACE_DESC }, + { "%file", TRACE_FILE }, + { "%memory", TRACE_MEMORY }, + { "%process", TRACE_PROCESS }, + { "%signal", TRACE_SIGNAL }, + { "%ipc", TRACE_IPC }, + { "%network", TRACE_NETWORK }, + { "%stat", TRACE_STAT }, + { "%lstat", TRACE_LSTAT }, + { "%fstat", TRACE_FSTAT }, + { "%%stat", TRACE_STAT_LIKE }, + { "%statfs", TRACE_STATFS }, + { "%fstatfs", TRACE_FSTATFS }, + { "%%statfs", TRACE_STATFS_LIKE }, + {} +}; + typedef unsigned int number_slot_t; #define BITS_PER_SLOT (sizeof(number_slot_t) * 8) @@ -48,6 +74,10 @@ static struct number_set inject_set[SUPPORTED_PERSONALITIES]; static struct number_set raw_set[SUPPORTED_PERSONALITIES]; static struct number_set trace_set[SUPPORTED_PERSONALITIES]; static struct number_set verbose_set[SUPPORTED_PERSONALITIES]; +#ifdef USE_LUAJIT +static struct number_set hook_entry_set[SUPPORTED_PERSONALITIES]; +static struct number_set hook_exit_set[SUPPORTED_PERSONALITIES]; +#endif static void number_setbit(const unsigned int i, number_slot_t *const vec) @@ -245,37 +275,10 @@ qualify_syscall_regex(const char *s, struct number_set *set) static unsigned int lookup_class(const char *s) { - static const struct { - const char *name; - unsigned int value; - } syscall_class[] = { - { "desc", TRACE_DESC }, - { "file", TRACE_FILE }, - { "memory", TRACE_MEMORY }, - { "process", TRACE_PROCESS }, - { "signal", TRACE_SIGNAL }, - { "ipc", TRACE_IPC }, - { "network", TRACE_NETWORK }, - { "%desc", TRACE_DESC }, - { "%file", TRACE_FILE }, - { "%memory", TRACE_MEMORY }, - { "%process", TRACE_PROCESS }, - { "%signal", TRACE_SIGNAL }, - { "%ipc", TRACE_IPC }, - { "%network", TRACE_NETWORK }, - { "%stat", TRACE_STAT }, - { "%lstat", TRACE_LSTAT }, - { "%fstat", TRACE_FSTAT }, - { "%%stat", TRACE_STAT_LIKE }, - { "%statfs", TRACE_STATFS }, - { "%fstatfs", TRACE_FSTATFS }, - { "%%statfs", TRACE_STATFS_LIKE }, - }; - - unsigned int i; - for (i = 0; i < ARRAY_SIZE(syscall_class); ++i) { - if (strcmp(s, syscall_class[i].name) == 0) { - return syscall_class[i].value; + const struct syscall_class *c; + for (c = syscall_classes; c->name; ++c) { + if (strcmp(s, c->name) == 0) { + return c->value; } } @@ -693,5 +696,23 @@ qual_flags(const unsigned int scno) | (is_number_in_set(scno, &raw_set[current_personality]) ? QUAL_RAW : 0) | (is_number_in_set(scno, &inject_set[current_personality]) - ? QUAL_INJECT : 0); + ? QUAL_INJECT : 0) +#ifdef USE_LUAJIT + | (is_number_in_set(scno, &hook_entry_set[current_personality]) + ? QUAL_HOOK_ENTRY : 0) + | (is_number_in_set(scno, &hook_exit_set[current_personality]) + ? QUAL_HOOK_EXIT : 0) +#endif + ; +} + +#ifdef USE_LUAJIT +void +set_hook_qual(unsigned int scno, unsigned int pers, bool entry_hook, bool exit_hook) +{ + if (entry_hook) + add_number_to_set(scno, &hook_entry_set[pers]); + if (exit_hook) + add_number_to_set(scno, &hook_exit_set[pers]); } +#endif diff --git a/strace.c b/strace.c index 5a1bcff3..5d6ffdf4 100644 --- a/strace.c +++ b/strace.c @@ -45,10 +45,16 @@ # include <sys/prctl.h> #endif #include <asm/unistd.h> +#ifdef USE_LUAJIT +# include <lua.h> +# include <lualib.h> +# include <lauxlib.h> +#endif #include "scno.h" #include "ptrace.h" #include "printsiginfo.h" +#include "syscall_class.h" /* In some libc, these aren't declared. Do it ourself: */ extern char **environ; @@ -166,6 +172,11 @@ static volatile sig_atomic_t interrupted; static volatile int interrupted; #endif +#ifdef USE_LUAJIT +static lua_State *script_L = NULL; +static void init_luajit(const char *scriptfile); +#endif + #ifndef HAVE_STRERROR #if !HAVE_DECL_SYS_ERRLIST @@ -216,6 +227,11 @@ Output format:\n\ -k obtain stack trace between each syscall (experimental)\n\ " #endif +#ifdef USE_LUAJIT +"\ + -l file run a Lua script from FILE\n\ +" +#endif "\ -o file send trace output to FILE instead of stderr\n\ -q suppress messages about attaching, detaching, etc.\n\ @@ -768,7 +784,7 @@ alloctcb(int pid) if (!tcp->pid) { memset(tcp, 0, sizeof(*tcp)); tcp->pid = pid; -#if SUPPORTED_PERSONALITIES > 1 +#if defined(USE_LUAJIT) || SUPPORTED_PERSONALITIES > 1 tcp->currpers = current_personality; #endif @@ -1645,6 +1661,9 @@ init(int argc, char *argv[]) #ifdef USE_LIBUNWIND "k" #endif +#ifdef USE_LUAJIT + "l:" +#endif "D" "a:e:o:O:p:s:S:u:E:P:I:")) != EOF) { switch (c) { @@ -1755,6 +1774,11 @@ init(int argc, char *argv[]) stack_trace_enabled = true; break; #endif +#ifdef USE_LUAJIT + case 'l': + init_luajit(optarg); + break; +#endif case 'E': if (putenv(optarg) < 0) die_out_of_memory(); @@ -2637,6 +2661,10 @@ terminate(void) exit(exit_code); } +#ifdef USE_LUAJIT +# include "luajit.h" +#endif + int main(int argc, char *argv[]) { @@ -2644,6 +2672,11 @@ main(int argc, char *argv[]) exit_code = !nprocs; +#ifdef USE_LUAJIT + if (script_L) + run_luajit(); +#endif + int status; siginfo_t si; while (dispatch_event(next_event(&status, &si), &status, &si)) diff --git a/syscall.c b/syscall.c index 0250540c..896119a9 100644 --- a/syscall.c +++ b/syscall.c @@ -790,7 +790,7 @@ syscall_exiting_decode(struct tcb *tcp, struct timeval *ptv) } #endif - if (filtered(tcp) || hide_log(tcp)) + if ((filtered(tcp) || hide_log(tcp)) && !(tcp->qual_flg & QUAL_HOOK_EXIT)) return 0; get_regs(tcp->pid); diff --git a/syscall_class.h b/syscall_class.h new file mode 100644 index 00000000..a39d5bdf --- /dev/null +++ b/syscall_class.h @@ -0,0 +1,27 @@ +#if !defined(STRACE_SYSCALL_CLASS_H) || defined(FFI_CDEF) +#ifndef FFI_CDEF +# define STRACE_SYSCALL_CLASS_H +#endif + +#define STRINGIFY(...) #__VA_ARGS__ +#ifdef FFI_CDEF +# define CONTENT(...) STRINGIFY(__VA_ARGS__) +#else +# define CONTENT(...) __VA_ARGS__ +#endif + +CONTENT( +struct syscall_class { + const char *name; + unsigned int value; +}; +) + +#undef STRINGIFY +#undef CONTENT + +#ifndef FFI_CDEF +extern const struct syscall_class syscall_classes[]; +#endif + +#endif /* !defined(STRACE_SYSCALL_CLASS_H) || defined(FFI_CDEF) */ diff --git a/sysent.h b/sysent.h index 92de7468..94c81da9 100644 --- a/sysent.h +++ b/sysent.h @@ -1,13 +1,38 @@ -#ifndef STRACE_SYSENT_H -#define STRACE_SYSENT_H +#if !defined(STRACE_SYSENT_H) || defined(FFI_CDEF) +#ifndef FFI_CDEF +# define STRACE_SYSENT_H +#endif +#define STRINGIFY(...) #__VA_ARGS__ +#ifdef FFI_CDEF +# define CONTENT(...) STRINGIFY(__VA_ARGS__) +#else +# define CONTENT(...) __VA_ARGS__ +#endif + +CONTENT( typedef struct sysent { unsigned nargs; int sys_flags; int sen; +) +/* We don't want to expose sys_func to LuaJIT */ +#ifdef FFI_CDEF +CONTENT( + char priv[sizeof(int(*)())]; +) +#else +CONTENT( int (*sys_func)(); +) +#endif +CONTENT( const char *sys_name; } struct_sysent; +) + +#undef STRINGIFY +#undef CONTENT #define TRACE_FILE 00000001 /* Trace file-related syscalls. */ #define TRACE_IPC 00000002 /* Trace IPC-related syscalls. */ @@ -29,4 +54,4 @@ typedef struct sysent { #define TRACE_FSTAT 00400000 /* Trace *fstat{,at}{,64} syscalls. */ #define TRACE_STAT_LIKE 01000000 /* Trace *{,l,f}stat{,x,at}{,64} syscalls. */ -#endif /* !STRACE_SYSENT_H */ +#endif /* !defined(STRACE_SYSENT_H) || defined(FFI_CDEF) */ -- 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