* Makefile.am (strace_SOURCES): Add defs_shared.h and ffi.h.
* basic_filters.c (syscall_classes): make global and terminate by a
null entry.
(lookup_class): use global null entry-terminated variable.
* defs.h (TCB_AD_HOC_INJECT, TCB_HOOK): New TCB flags.
(QUAL_HOOK_ENTRY, QUAL_HOOK_EXIT): New qualifier flags.
(RVAL_HOOKED): New return value flag.
(struct ioctlent, struct tcb): move to...
* defs_shared.h: ...new file.
* ffi.h: New file.
* filter_qualify.c (qual_flags): Introduce QUALBIT macro and use it.
* number_set.c (number_unsetbit, remove_number_from_set,
extend_set_with_number, make_number_set_universal,
extend_set_array_with_number, make_number_set_array_universal): New
functions.
* strace.c (enum trace_event): Introduce new TE_SYSCALL_STOP_HOOK_EXIT
trace event.
(enum hook_state): New enumeration.
(trace_syscall): Add a hook state argument.
(dispatch_event): Add a "hooked" argument, support invoking with
TE_SYSCALL_STOP_HOOK_EXIT event.
* syscall.c: (errnoent_vec, nerrnoent_vec, signalent_vec,
nsignalent_vec, ioctlent_vec, nioctlent_vec, personality_wordsize,
personality_klongsize): New global variables.
(personality_names): New global variable (if SUPPORTED_PERSONALITIES >
1).
(update_personality): Use personality_names for reporting personality
name.
(tcb_inject_opts): Introduce step argument, change return type to struct
inject_data, rename to tcb_inject_data.
(tamper_with_syscall_entering): Don't copy inject_vec here and do
counter decrement logic here; pass true as a second argument to
tcb_inject_data.
(tamper_with_syscall_exiting): Pass false as a second argument to
tcb_inject_data.
(syscall_ad_hoc_inject): New function.
(syscall_entering_trace): Perform ad hoc injection even if the syscall
is not traced.
(syscall_exiting_decode): Don't return 0 ("bail out") if exiting hook is
set up for this syscall, or if an ad hoc injection was performed.
Call tamper_with_syscall_exiting on success.
(syscall_exiting_trace): Don't call tamper_with_syscall_exiting, check
if the syscall is not traced again.
(syscall_exiting_finish): Clear TCB_AD_HOC_INJECT bit.
* sysent.h: Modify to support inclusing with FFI_CDEF defined.
---
 Makefile.am      |   2 +
 basic_filters.c  |  60 ++++++++-------
 defs.h           |  59 ++++++---------
 defs_shared.h    |  63 ++++++++++++++++
 ffi.h            |  19 +++++
 filter_qualify.c |  20 ++---
 number_set.c     |  47 ++++++++++++
 number_set.h     |  16 ++++
 strace.c         |  63 ++++++++++++----
 syscall.c        | 220 +++++++++++++++++++++++++++++++++++++++----------------
 sysent.h         |  24 +++++-
 11 files changed, 436 insertions(+), 157 deletions(-)
 create mode 100644 defs_shared.h
 create mode 100644 ffi.h

diff --git a/Makefile.am b/Makefile.am
index 4aa9846c..0ab788b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -107,6 +107,7 @@ strace_SOURCES =    \
        copy_file_range.c \
        count.c         \
        defs.h          \
+       defs_shared.h   \
        desc.c          \
        dirent.c        \
        dirent64.c      \
@@ -132,6 +133,7 @@ strace_SOURCES =    \
        fetch_struct_stat.c \
        fetch_struct_stat64.c \
        fetch_struct_statfs.c \
+       ffi.h           \
        file_handle.c   \
        file_ioctl.c    \
        filter_qualify.c \
diff --git a/basic_filters.c b/basic_filters.c
index 7b7f0a54..0f31fd32 100644
--- a/basic_filters.c
+++ b/basic_filters.c
@@ -94,40 +94,38 @@ qualify_syscall_regex(const char *s, struct number_set *set)
        return found;
 }
 
+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       },
+       {}
+};
+
 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;
                }
        }
 
diff --git a/defs.h b/defs.h
index 34261f2e..f4252fa5 100644
--- a/defs.h
+++ b/defs.h
@@ -175,11 +175,6 @@ extern char *stpcpy(char *dst, const char *src);
 # define PERSONALITY2_INCLUDE_FUNCS "empty.h"
 #endif
 
-typedef struct ioctlent {
-       const char *symbol;
-       unsigned int code;
-} struct_ioctlent;
-
 #define INJECT_F_SIGNAL 1
 #define INJECT_F_RETVAL 2
 
@@ -197,39 +192,7 @@ struct inject_opts {
 
 #define MAX_ERRNO_VALUE                        4095
 
-/* 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_shared.h"
 
 /* TCB flags */
 /* We have attached to this process, but did not see it stopping yet */
@@ -253,6 +216,8 @@ struct tcb {
 #define TCB_TAMPERED   0x40    /* A syscall has been tampered with */
 #define TCB_HIDE_LOG   0x80    /* We should hide everything (until execve) */
 #define TCB_SKIP_DETACH_ON_FIRST_EXEC  0x100   /* -b execve should skip detach 
on first execve */
+#define TCB_AD_HOC_INJECT      0x200   /* an ad hoc injection was performed by 
Lua script */
+#define TCB_HOOK       0x400   /* there is Lua hook for this syscall entry or 
exit */
 
 /* qualifier flags */
 #define QUAL_TRACE     0x001   /* this system call should be traced */
@@ -260,6 +225,8 @@ struct tcb {
 #define QUAL_VERBOSE   0x004   /* decode the structures of this syscall */
 #define QUAL_RAW       0x008   /* print all args in hex for this syscall */
 #define QUAL_INJECT    0x010   /* tamper with this system call on purpose */
+#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)
 
@@ -318,6 +285,8 @@ extern const struct xlat whence_codes[];
 #define RVAL_IOCTL_DECODED 0200        /* ioctl sub-parser successfully decoded
                                   the argument */
 
+#define RVAL_HOOKED    0400    /* there is Lua hook for this syscall entry or 
exit */
+
 #define IOCTL_NUMBER_UNKNOWN 0
 #define IOCTL_NUMBER_HANDLED 1
 #define IOCTL_NUMBER_STOP_LOOKUP 010
@@ -362,6 +331,7 @@ typedef enum {
        CFLAG_ONLY_STATS,
        CFLAG_BOTH
 } cflag_t;
+extern const struct syscall_class syscall_classes[];
 extern cflag_t cflag;
 extern bool debug_flag;
 extern bool Tflag;
@@ -950,6 +920,19 @@ extern const char *const errnoent0[];
 extern const char *const signalent0[];
 extern const struct_ioctlent ioctlent0[];
 
+extern const char *const *errnoent_vec[SUPPORTED_PERSONALITIES];
+extern const char *const *signalent_vec[SUPPORTED_PERSONALITIES];
+extern const struct_ioctlent *const ioctlent_vec[SUPPORTED_PERSONALITIES];
+extern const unsigned int nerrnoent_vec[SUPPORTED_PERSONALITIES];
+extern const unsigned int nsignalent_vec[SUPPORTED_PERSONALITIES];
+extern const unsigned int nioctlent_vec[SUPPORTED_PERSONALITIES];
+
+extern const int personality_wordsize[SUPPORTED_PERSONALITIES];
+extern const int personality_klongsize[SUPPORTED_PERSONALITIES];
+#if SUPPORTED_PERSONALITIES > 1
+extern const char *const personality_names[];
+#endif
+
 #if SUPPORTED_PERSONALITIES > 1
 extern const struct_sysent *sysent;
 extern const char *const *errnoent;
diff --git a/defs_shared.h b/defs_shared.h
new file mode 100644
index 00000000..1113fc0c
--- /dev/null
+++ b/defs_shared.h
@@ -0,0 +1,63 @@
+/*
+ * Should only be included without FFI_CDEF from defs.h, so no include guards.
+ */
+
+#include "ffi.h"
+
+FFI_CONTENT(
+struct syscall_class {
+       const char *name;
+       unsigned int value;
+};
+)
+
+FFI_CONTENT(
+typedef struct ioctlent {
+       const char *symbol;
+       unsigned int code;
+} struct_ioctlent;
+)
+
+/* Trace Control Block */
+FFI_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
+FFI_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 */
+
+FFI_CONTENT(
+};
+)
diff --git a/ffi.h b/ffi.h
new file mode 100644
index 00000000..7b89e7a4
--- /dev/null
+++ b/ffi.h
@@ -0,0 +1,19 @@
+#ifndef STRACE_FFI_H
+#define STRACE_FFI_H
+
+#include "macros.h"
+
+#define FFI_CONCAT(a, b) a ## b
+#define FFI_CONCAT2(a, b) FFI_CONCAT(a, b)
+
+/*
+ * FFI_CONTENT expands to FFI_CONTENT_ (which strigifies its arguments) when
+ * FFI_CDEF is defined, and to FFI_CONTENT_FFI_CDEF (which simply expands to 
its
+ * arguments) when it is not.
+ */
+#define FFI_CONTENT FFI_CONCAT2(FFI_CONTENT_, FFI_CDEF)
+
+#define FFI_CONTENT_(...)         STRINGIFY(__VA_ARGS__)
+#define FFI_CONTENT_FFI_CDEF(...) __VA_ARGS__
+
+#endif /* !STRACE_FFI_H */
diff --git a/filter_qualify.c b/filter_qualify.c
index 5b0ef28c..71766fd1 100644
--- a/filter_qualify.c
+++ b/filter_qualify.c
@@ -360,14 +360,14 @@ qualify(const char *str)
 unsigned int
 qual_flags(const unsigned int scno)
 {
-       return  (is_number_in_set_array(scno, trace_set, current_personality)
-                  ? QUAL_TRACE : 0)
-               | (is_number_in_set_array(scno, abbrev_set, current_personality)
-                  ? QUAL_ABBREV : 0)
-               | (is_number_in_set_array(scno, verbose_set, 
current_personality)
-                  ? QUAL_VERBOSE : 0)
-               | (is_number_in_set_array(scno, raw_set, current_personality)
-                  ? QUAL_RAW : 0)
-               | (is_number_in_set_array(scno, inject_set, current_personality)
-                  ? QUAL_INJECT : 0);
+#define QUALBIT(set, qualbit) \
+       (is_number_in_set_array(scno, set, current_personality) ? qualbit : 0)
+
+       return    QUALBIT(trace_set, QUAL_TRACE)
+               | QUALBIT(abbrev_set, QUAL_ABBREV)
+               | QUALBIT(verbose_set, QUAL_VERBOSE)
+               | QUALBIT(raw_set, QUAL_RAW)
+               | QUALBIT(inject_set, QUAL_INJECT)
+               ;
+#undef QUALBIT
 }
diff --git a/number_set.c b/number_set.c
index b8aa28c7..a2e049a1 100644
--- a/number_set.c
+++ b/number_set.c
@@ -50,6 +50,12 @@ number_setbit(const unsigned int i, number_slot_t *const vec)
        vec[i / BITS_PER_SLOT] |= (number_slot_t) 1 << (i % BITS_PER_SLOT);
 }
 
+static void
+number_unsetbit(const unsigned int i, number_slot_t *const vec)
+{
+       vec[i / BITS_PER_SLOT] &= ~((number_slot_t) 1 << (i % BITS_PER_SLOT));
+}
+
 static bool
 number_isset(const unsigned int i, const number_slot_t *const vec)
 {
@@ -97,6 +103,29 @@ add_number_to_set(const unsigned int number, struct 
number_set *const set)
 }
 
 void
+remove_number_from_set(const unsigned int number, struct number_set *const set)
+{
+       if (number / BITS_PER_SLOT < set->nslots)
+               number_unsetbit(number, set->vec);
+}
+
+void
+extend_set_with_number(const unsigned int number, struct number_set *const set)
+{
+       if (set->not)
+               remove_number_from_set(number, set);
+       else
+               add_number_to_set(number, set);
+}
+
+void
+make_number_set_universal(struct number_set *const set)
+{
+       free(set->vec);
+       *set = (struct number_set) { .not = true };
+}
+
+void
 add_number_to_set_array(const unsigned int number, struct number_set *const 
set,
                        const unsigned int idx)
 {
@@ -104,6 +133,14 @@ add_number_to_set_array(const unsigned int number, struct 
number_set *const set,
 }
 
 void
+extend_set_array_with_number(const unsigned int number,
+                            struct number_set *const set,
+                            const unsigned int idx)
+{
+       extend_set_with_number(number, &set[idx]);
+}
+
+void
 clear_number_set_array(struct number_set *const set, const unsigned int nmemb)
 {
        unsigned int i;
@@ -125,6 +162,16 @@ invert_number_set_array(struct number_set *const set, 
const unsigned int nmemb)
                set[i].not = !set[i].not;
 }
 
+void
+make_number_set_array_universal(struct number_set *set,
+                               const unsigned int nmemb)
+{
+       unsigned int i;
+
+       for (i = 0; i < nmemb; ++i)
+               make_number_set_universal(&set[i]);
+}
+
 struct number_set *
 alloc_number_set_array(const unsigned int nmemb)
 {
diff --git a/number_set.h b/number_set.h
index ec53bc1b..953b1545 100644
--- a/number_set.h
+++ b/number_set.h
@@ -45,6 +45,22 @@ extern void
 add_number_to_set(unsigned int number, struct number_set *);
 
 extern void
+remove_number_from_set(unsigned int number, struct number_set *);
+
+extern void
+extend_set_with_number(unsigned int number, struct number_set *);
+
+extern void
+make_number_set_universal(struct number_set *);
+
+extern void
+make_number_set_array_universal(struct number_set *, unsigned int nmemb);
+
+extern void
+extend_set_array_with_number(const unsigned int number,
+       struct number_set *const set, const unsigned int idx);
+
+extern void
 add_number_to_set_array(unsigned int number, struct number_set *, unsigned int 
idx);
 
 extern void
diff --git a/strace.c b/strace.c
index 6ed86a6f..7b8a0e24 100644
--- a/strace.c
+++ b/strace.c
@@ -2216,6 +2216,9 @@ enum trace_event {
         */
        TE_SYSCALL_STOP,
 
+       /* Syscall entry or exit, after hook. */
+       TE_SYSCALL_STOP_HOOK_EXIT,
+
        /*
         * Tracee received signal with number WSTOPSIG(*pstatus); signal info
         * is written to *si.  Restart the tracee (with that signal number
@@ -2406,24 +2409,47 @@ next_event(int *pstatus, siginfo_t *si)
        }
 }
 
+enum hook_state {
+       HOOK_ENTER,
+       HOOK_EXIT,
+       HOOK_IGNORE,
+};
+
 static int
-trace_syscall(struct tcb *tcp, unsigned int *sig)
+trace_syscall(struct tcb *tcp, unsigned int *sig, enum hook_state state)
 {
        if (entering(tcp)) {
-               int res = syscall_entering_decode(tcp);
-               switch (res) {
-               case 0:
-                       return 0;
-               case 1:
+               int res;
+               switch (state) {
+               case HOOK_ENTER:
+               case HOOK_IGNORE:
+                       res = syscall_entering_decode(tcp);
+                       if (res == 0)
+                               return 0;
+                       if (res == 1)
+                               if (state == HOOK_ENTER &&
+                                   (tcp->qual_flg & QUAL_HOOK_ENTRY))
+                                       return RVAL_HOOKED;
+                       /* Fall through */
+               case HOOK_EXIT:
                        res = syscall_entering_trace(tcp, sig);
                }
                syscall_entering_finish(tcp, res);
                return res;
        } else {
-               struct timeval tv = {};
-               int res = syscall_exiting_decode(tcp, &tv);
-               if (res != 0) {
-                       res = syscall_exiting_trace(tcp, tv, res);
+               static struct timeval tv;
+               int res = 1;
+               switch (state) {
+               case HOOK_ENTER:
+               case HOOK_IGNORE:
+                       res = syscall_exiting_decode(tcp, &tv);
+                       if (res == 1 && state == HOOK_ENTER &&
+                           (tcp->qual_flg & QUAL_HOOK_EXIT))
+                               return RVAL_HOOKED;
+                       /* Fall through */
+               case HOOK_EXIT:
+                       if (res != 0)
+                               res = syscall_exiting_trace(tcp, tv, res);
                }
                syscall_exiting_finish(tcp);
                return res;
@@ -2432,10 +2458,11 @@ trace_syscall(struct tcb *tcp, unsigned int *sig)
 
 /* Returns true iff the main trace loop has to continue. */
 static bool
-dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
+dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si, bool hooked)
 {
        unsigned int restart_op = PTRACE_SYSCALL;
        unsigned int restart_sig = 0;
+       int res;
 
        switch (ret) {
        case TE_BREAK:
@@ -2448,7 +2475,17 @@ dispatch_event(enum trace_event ret, int *pstatus, 
siginfo_t *si)
                break;
 
        case TE_SYSCALL_STOP:
-               if (trace_syscall(current_tcp, &restart_sig) < 0) {
+       case TE_SYSCALL_STOP_HOOK_EXIT:
+               res = trace_syscall(current_tcp, &restart_sig,
+                       hooked ? (ret == TE_SYSCALL_STOP ? HOOK_ENTER : 
HOOK_EXIT) :
+                       HOOK_IGNORE);
+
+               if (res == RVAL_HOOKED) {
+                       current_tcp->flags |= TCB_HOOK;
+                       return true;
+               }
+
+               if (res < 0) {
                        /*
                         * ptrace() failed in trace_syscall().
                         * Likely a result of process disappearing mid-flight.
@@ -2593,7 +2630,7 @@ main(int argc, char *argv[])
 
        int status;
        siginfo_t si;
-       while (dispatch_event(next_event(&status, &si), &status, &si))
+       while (dispatch_event(next_event(&status, &si), &status, &si, false))
                ;
        terminate();
 }
diff --git a/syscall.c b/syscall.c
index b1047feb..abc3f80c 100644
--- a/syscall.c
+++ b/syscall.c
@@ -160,6 +160,16 @@ enum {
 #endif
 };
 
+const char *const *errnoent_vec[SUPPORTED_PERSONALITIES] = {
+       errnoent0,
+#if SUPPORTED_PERSONALITIES > 1
+       errnoent1,
+# if SUPPORTED_PERSONALITIES > 2
+       errnoent2,
+# endif
+#endif
+};
+
 enum {
        nerrnos0 = ARRAY_SIZE(errnoent0)
 #if SUPPORTED_PERSONALITIES > 1
@@ -170,6 +180,16 @@ enum {
 #endif
 };
 
+const unsigned int nerrnoent_vec[] = {
+       nerrnos0,
+#if SUPPORTED_PERSONALITIES > 1
+       nerrnos1,
+# if SUPPORTED_PERSONALITIES > 2
+       nerrnos2,
+# endif
+#endif
+};
+
 enum {
        nsignals0 = ARRAY_SIZE(signalent0)
 #if SUPPORTED_PERSONALITIES > 1
@@ -180,6 +200,26 @@ enum {
 #endif
 };
 
+const char *const *signalent_vec[SUPPORTED_PERSONALITIES] = {
+       signalent0,
+#if SUPPORTED_PERSONALITIES > 1
+       signalent1,
+# if SUPPORTED_PERSONALITIES > 2
+       signalent2,
+# endif
+#endif
+};
+
+const unsigned int nsignalent_vec[] = {
+       nsignals0,
+#if SUPPORTED_PERSONALITIES > 1
+       nsignals1,
+# if SUPPORTED_PERSONALITIES > 2
+       nsignals2,
+# endif
+#endif
+};
+
 enum {
        nioctlents0 = ARRAY_SIZE(ioctlent0)
 #if SUPPORTED_PERSONALITIES > 1
@@ -190,6 +230,26 @@ enum {
 #endif
 };
 
+const unsigned int nioctlent_vec[] = {
+       nioctlents0,
+#if SUPPORTED_PERSONALITIES > 1
+       nioctlents1,
+# if SUPPORTED_PERSONALITIES > 2
+       nioctlents2,
+# endif
+#endif
+};
+
+const struct_ioctlent *const ioctlent_vec[SUPPORTED_PERSONALITIES] = {
+       ioctlent0,
+#if SUPPORTED_PERSONALITIES > 1
+       ioctlent1,
+# if SUPPORTED_PERSONALITIES > 2
+       ioctlent2,
+# endif
+#endif
+};
+
 #if SUPPORTED_PERSONALITIES > 1
 const struct_sysent *sysent = sysent0;
 const char *const *errnoent = errnoent0;
@@ -222,29 +282,55 @@ const struct_sysent *const 
sysent_vec[SUPPORTED_PERSONALITIES] = {
 #endif
 };
 
+const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
+       PERSONALITY0_WORDSIZE,
 #if SUPPORTED_PERSONALITIES > 1
+       PERSONALITY1_WORDSIZE,
+#endif
+#if SUPPORTED_PERSONALITIES > 2
+       PERSONALITY2_WORDSIZE,
+#endif
+};
+
+const int personality_klongsize[SUPPORTED_PERSONALITIES] = {
+       PERSONALITY0_KLONGSIZE,
+#if SUPPORTED_PERSONALITIES > 1
+       PERSONALITY1_KLONGSIZE,
+#endif
+#if SUPPORTED_PERSONALITIES > 2
+       PERSONALITY2_KLONGSIZE,
+#endif
+};
+
+#if SUPPORTED_PERSONALITIES > 1
+
+const char *const personality_names[] =
+# if defined POWERPC64
+       {"64 bit", "32 bit"}
+# elif defined X86_64
+       {"64 bit", "32 bit", "x32"}
+# elif defined X32
+       {"x32", "32 bit"}
+# elif defined AARCH64
+       {"64 bit", "32 bit"}
+# elif defined TILE
+       {"64-bit", "32-bit"}
+# else
+#  error Add personality names for your achitecture.
+# endif
+       ;
+
 unsigned current_personality;
 
 # ifndef current_wordsize
 unsigned current_wordsize;
-static const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
-       PERSONALITY0_WORDSIZE,
-       PERSONALITY1_WORDSIZE,
-# if SUPPORTED_PERSONALITIES > 2
-       PERSONALITY2_WORDSIZE,
 # endif
-};
+# ifndef current_klongsize
+unsigned current_klongsize;
 # endif
 
 # ifndef current_klongsize
 unsigned current_klongsize;
-static const int personality_klongsize[SUPPORTED_PERSONALITIES] = {
-       PERSONALITY0_KLONGSIZE,
-       PERSONALITY1_KLONGSIZE,
-#  if SUPPORTED_PERSONALITIES > 2
-       PERSONALITY2_KLONGSIZE,
-#  endif
-};
 # endif
 
 void
@@ -307,21 +393,10 @@ update_personality(struct tcb *tcp, unsigned int 
personality)
                return;
        tcp->currpers = personality;
 
-# undef PERSONALITY_NAMES
-# if defined X86_64
-#  define PERSONALITY_NAMES {"64 bit", "32 bit", "x32"}
-# elif defined X32
-#  define PERSONALITY_NAMES {"x32", "32 bit"}
-# elif SUPPORTED_PERSONALITIES == 2
-#  define PERSONALITY_NAMES {"64 bit", "32 bit"}
-# endif
-# ifdef PERSONALITY_NAMES
        if (!qflag) {
-               static const char *const names[] = PERSONALITY_NAMES;
                error_msg("[ Process PID=%d runs in %s mode. ]",
-                         tcp->pid, names[personality]);
+                         tcp->pid, personality_names[personality]);
        }
-# endif
 }
 #endif
 
@@ -539,18 +614,11 @@ static int arch_set_success(struct tcb *);
 
 struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES];
 
-static struct inject_opts *
-tcb_inject_opts(struct tcb *tcp)
-{
-       return (scno_in_range(tcp->scno) && 
tcp->inject_vec[current_personality])
-              ? &tcp->inject_vec[current_personality][tcp->scno] : NULL;
-}
-
-
-static long
-tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo)
+static struct inject_data
+tcb_inject_data(struct tcb *tcp, bool step)
 {
-       if (!tcp->inject_vec[current_personality]) {
+       if (step && !tcp->inject_vec[current_personality] &&
+           inject_vec[current_personality]) {
                tcp->inject_vec[current_personality] =
                        xcalloc(nsyscalls, sizeof(**inject_vec));
                memcpy(tcp->inject_vec[current_personality],
@@ -558,21 +626,31 @@ tamper_with_syscall_entering(struct tcb *tcp, unsigned 
int *signo)
                       nsyscalls * sizeof(**inject_vec));
        }
 
-       struct inject_opts *opts = tcb_inject_opts(tcp);
-
-       if (!opts || opts->first == 0)
-               return 0;
-
-       --opts->first;
-
-       if (opts->first != 0)
-               return 0;
+       struct inject_opts *opts =
+               scno_in_range(tcp->scno) && tcp->inject_vec[current_personality]
+               ? &tcp->inject_vec[current_personality][tcp->scno] : NULL;
+       struct inject_data res = {};
+       if (opts) {
+               if (step) {
+                       if (opts->first != 0 && --opts->first == 0) {
+                               res = opts->data;
+                               opts->first = opts->step;
+                       }
+               } else {
+                       res = opts->data;
+               }
+       }
+       return res;
+}
 
-       opts->first = opts->step;
+static long
+tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo)
+{
+       struct inject_data data = tcb_inject_data(tcp, true);
 
-       if (opts->data.flags & INJECT_F_SIGNAL)
-               *signo = opts->data.signo;
-       if (opts->data.flags & INJECT_F_RETVAL && !arch_set_scno(tcp, -1))
+       if (data.flags & INJECT_F_SIGNAL)
+               *signo = data.signo;
+       if ((data.flags & INJECT_F_RETVAL) && !arch_set_scno(tcp, -1))
                tcp->flags |= TCB_TAMPERED;
 
        return 0;
@@ -581,22 +659,22 @@ tamper_with_syscall_entering(struct tcb *tcp, unsigned 
int *signo)
 static long
 tamper_with_syscall_exiting(struct tcb *tcp)
 {
-       struct inject_opts *opts = tcb_inject_opts(tcp);
+       struct inject_data data = tcb_inject_data(tcp, false);
 
-       if (!opts)
+       if (!(data.flags & INJECT_F_RETVAL))
                return 0;
 
-       if (opts->data.rval >= 0) {
+       if (data.rval >= 0) {
                kernel_long_t u_rval = tcp->u_rval;
 
-               tcp->u_rval = opts->data.rval;
+               tcp->u_rval = data.rval;
                if (arch_set_success(tcp)) {
                        tcp->u_rval = u_rval;
                } else {
                        tcp->u_error = 0;
                }
        } else {
-               unsigned long new_error = -opts->data.rval;
+               unsigned long new_error = -data.rval;
 
                if (new_error != tcp->u_error && new_error <= MAX_ERRNO_VALUE) {
                        unsigned long u_error = tcp->u_error;
@@ -659,6 +737,12 @@ syscall_entering_decode(struct tcb *tcp)
        return 1;
 }
 
+static bool
+syscall_ad_hoc_injected(struct tcb *tcp)
+{
+       return (tcp->qual_flg & QUAL_INJECT) && (tcp->flags & 
TCB_AD_HOC_INJECT);
+}
+
 int
 syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
 {
@@ -679,20 +763,20 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
 
        if (!traced(tcp) || (tracing_paths && !pathtrace_match(tcp))) {
                tcp->flags |= TCB_FILTERED;
-               return 0;
+               goto maybe_ad_hoc_tamper;
        }
 
        tcp->flags &= ~TCB_FILTERED;
 
        if (hide_log(tcp)) {
-               return 0;
+               goto maybe_ad_hoc_tamper;
        }
 
        if (inject(tcp))
                tamper_with_syscall_entering(tcp, sig);
 
        if (cflag == CFLAG_ONLY_STATS) {
-               return 0;
+               goto maybe_ad_hoc_tamper;
        }
 
 #ifdef USE_LIBUNWIND
@@ -707,6 +791,11 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
        int res = raw(tcp) ? printargs(tcp) : tcp->s_ent->sys_func(tcp);
        fflush(tcp->outf);
        return res;
+
+maybe_ad_hoc_tamper:
+       if (syscall_ad_hoc_injected(tcp))
+               tamper_with_syscall_entering(tcp, sig);
+       return 0;
 }
 
 void
@@ -747,21 +836,28 @@ 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) && !syscall_ad_hoc_injected(tcp))
                return 0;
 
        get_regs(tcp->pid);
 #if SUPPORTED_PERSONALITIES > 1
        update_personality(tcp, tcp->currpers);
 #endif
-       return get_regs_error ? -1 : get_syscall_result(tcp);
+       if (get_regs_error || get_syscall_result(tcp) == -1)
+               return -1;
+
+       if (syserror(tcp) && syscall_tampered(tcp))
+               tamper_with_syscall_exiting(tcp);
+
+       return 1;
 }
 
 int
 syscall_exiting_trace(struct tcb *tcp, struct timeval tv, int res)
 {
-       if (syserror(tcp) && syscall_tampered(tcp))
-               tamper_with_syscall_exiting(tcp);
+       if (filtered(tcp) || hide_log(tcp))
+               return 0;
 
        if (cflag) {
                count_syscall(tcp, &tv);
@@ -970,7 +1066,7 @@ syscall_exiting_trace(struct tcb *tcp, struct timeval tv, 
int res)
 void
 syscall_exiting_finish(struct tcb *tcp)
 {
-       tcp->flags &= ~(TCB_INSYSCALL | TCB_TAMPERED);
+       tcp->flags &= ~(TCB_INSYSCALL | TCB_TAMPERED | TCB_AD_HOC_INJECT);
        tcp->sys_func_rval = 0;
        free_tcb_priv_data(tcp);
 }
diff --git a/sysent.h b/sysent.h
index 92de7468..15b83693 100644
--- a/sysent.h
+++ b/sysent.h
@@ -1,13 +1,31 @@
-#ifndef STRACE_SYSENT_H
-#define STRACE_SYSENT_H
+#if !defined(STRACE_SYSENT_H) || defined(FFI_CDEF)
+#ifndef FFI_CDEF
+# define STRACE_SYSENT_H
+#endif
 
+#include "ffi.h"
+
+FFI_CONTENT(
 typedef struct sysent {
        unsigned nargs;
        int     sys_flags;
+)
+/* We don't want to expose sen and sys_func to LuaJIT */
+#ifdef FFI_CDEF
+FFI_CONTENT(
+       int priv1;
+       void *priv2;
+)
+#else
+FFI_CONTENT(
        int     sen;
        int     (*sys_func)();
+)
+#endif
+FFI_CONTENT(
        const char *sys_name;
 } struct_sysent;
+)
 
 #define TRACE_FILE                     00000001        /* Trace file-related 
syscalls. */
 #define TRACE_IPC                      00000002        /* Trace IPC-related 
syscalls. */
@@ -29,4 +47,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

Reply via email to