* Makefile.am: Build with LuaJIT if configured so.
(strace_SOURCES): Add defs_reuse.h.
* configure.ac: Add new --with-luajit configure option.
* defs.h: Move code that needs to be fed to LuaJIT's FFI to...
* defs_reuse.h: ...new file.
* strace.c: Initial support for Lua scripting.
(init): New -l option (if built with Lua scripting support).
(luajit_next_sc, check_lua, luajit_init): New functions.
(main): run Lua script, if built with Lua scripting support and a script
was provided.
---
 Makefile.am  |   6 +++
 configure.ac |  34 +++++++++++++
 defs.h       |  34 +------------
 defs_reuse.h |  58 ++++++++++++++++++++++
 strace.c     | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 259 insertions(+), 33 deletions(-)
 create mode 100644 defs_reuse.h

diff --git a/Makefile.am b/Makefile.am
index 3d6eba1e..a7c4bce6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -100,6 +100,7 @@ strace_SOURCES =    \
        copy_file_range.c \
        count.c         \
        defs.h          \
+       defs_reuse.h    \
        desc.c          \
        dirent.c        \
        dirent64.c      \
@@ -276,6 +277,11 @@ strace_LDFLAGS += $(libunwind_LDFLAGS)
 strace_LDADD += $(libunwind_LIBS)
 endif
 
+if USE_LUAJIT
+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..b853c294 100644
--- a/configure.ac
+++ b/configure.ac
@@ -715,6 +715,40 @@ 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) ;;
+             *)     luajit_lib="${withval}" ;;
+             esac],
+            [:]
+)
+AS_IF([test "x$luajit_lib" != xno],
+      [AS_IF([test "x$force_luajit" = xyes],
+            [PKG_CHECK_MODULES([luajit], [$luajit_lib], [use_luajit=yes])],
+            [PKG_CHECK_MODULES([luajit], [$luajit_lib], [use_luajit=yes], [:])]
+       )
+      ]
+)
+
+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..01a8c125 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_reuse.h"
 
 /* TCB flags */
 /* We have attached to this process, but did not see it stopping yet */
diff --git a/defs_reuse.h b/defs_reuse.h
new file mode 100644
index 00000000..a6a8f8ca
--- /dev/null
+++ b/defs_reuse.h
@@ -0,0 +1,58 @@
+#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 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(};)
+
+#ifdef USE_LUAJIT
+CONTENT(
+struct strace_luajit_funcs {
+       struct tcb * (*next_sc)(void);
+};
+)
+#endif
+
+#undef STRINGIFY
+#undef CONTENT
diff --git a/strace.c b/strace.c
index 5a1bcff3..30004444 100644
--- a/strace.c
+++ b/strace.c
@@ -45,6 +45,11 @@
 # 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"
@@ -166,6 +171,11 @@ static volatile sig_atomic_t interrupted;
 static volatile int interrupted;
 #endif
 
+#ifdef USE_LUAJIT
+static lua_State *L = NULL;
+static void luajit_init(const char *scriptfile);
+#endif
+
 #ifndef HAVE_STRERROR
 
 #if !HAVE_DECL_SYS_ERRLIST
@@ -216,6 +226,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\
@@ -1645,6 +1660,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 +1773,11 @@ init(int argc, char *argv[])
                        stack_trace_enabled = true;
                        break;
 #endif
+#ifdef USE_LUAJIT
+               case 'l':
+                       luajit_init(optarg);
+                       break;
+#endif
                case 'E':
                        if (putenv(optarg) < 0)
                                die_out_of_memory();
@@ -2637,6 +2660,137 @@ terminate(void)
        exit(exit_code);
 }
 
+#ifdef USE_LUAJIT
+static struct tcb *
+luajit_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;                                                  
        \
+               terminate();                                                    
        \
+       }
+
+       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:
+                                       return current_tcp;
+                               default:
+                                       res = 
syscall_entering_trace(current_tcp, &sig);
+                                       syscall_entering_finish(current_tcp, 
res);
+                               }
+                       } else {
+                               res = syscall_exiting_decode(current_tcp, &tv);
+                               switch (res) {
+                               case 0:
+                                       break;
+                               case 1:
+                                       return current_tcp;
+                               default:
+                                       res = 
syscall_exiting_trace(current_tcp, tv, res);
+                                       syscall_exiting_finish(current_tcp);
+                               }
+                       }
+                       MBRESTART(res, sig);
+               } else {
+                       if (!dispatch_event(ret, &status, &si)) {
+                               terminate();
+                       }
+               }
+       }
+# undef MBRESTART
+}
+
+static void
+check_lua(int ret)
+{
+       if (ret == 0)
+               return;
+       const char *msg = lua_tostring(L, -1);
+       if (!msg)
+               msg = "(error object can't be converted to string)";
+       error_msg_and_die("lua: %s", msg);
+}
+
+static void
+luajit_init(const char *scriptfile)
+{
+       static struct strace_luajit_funcs funcs = {
+               .next_sc = luajit_next_sc,
+       };
+
+       if (L)
+               /* already initialized? */
+               error_msg_and_help("multiple -l arguments");
+
+       if (!(L = luaL_newstate()))
+               die_out_of_memory();
+
+       luaL_openlibs(L);
+       /* L: - */
+       check_lua(luaL_loadfile(L, scriptfile)); /* L: chunk */
+       lua_getglobal(L, "require"); /* L: chunk require */
+       lua_pushstring(L, "ffi"); /* L: chunk require "ffi" */
+       check_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 "defs_reuse.h"
+# undef FFI_CDEF
+       ); /* L: chunk ffi cdef ? */
+       luaL_pushresult(&b); /* L: chunk ffi cdef str */
+       check_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 
lightuserdata */
+       check_lua(lua_pcall(L, 2, 1, 0)); /* L: chunk ffi table funcs */
+       lua_getfield(L, -1, "next_sc"); /* L: chunk ffi table funcs next_sc */
+       lua_setfield(L, -3, "next_sc"); /* L: chunk ffi table funcs */
+       lua_pop(L, 1); /* L: chunk ffi table */
+       lua_setglobal(L, "strace"); /* L: chunk ffi */
+       lua_pop(L, 1); /* L: chunk */
+}
+#endif /* USE_LUAJIT */
+
 int
 main(int argc, char *argv[])
 {
@@ -2644,6 +2798,12 @@ main(int argc, char *argv[])
 
        exit_code = !nprocs;
 
+#ifdef USE_LUAJIT
+       if (L) {
+               /* L: chunk */
+               check_lua(lua_pcall(L, 0, 0, 0)); /* L: - */
+       }
+#endif
        int status;
        siginfo_t si;
        while (dispatch_event(next_event(&status, &si), &status, &si))
-- 
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

Reply via email to