]> granicus.if.org Git - strace/commitdiff
Add private data field to struct tcb
authorPatrik Jakobsson <patrik.jakobsson@linux.intel.com>
Mon, 24 Aug 2015 12:42:47 +0000 (14:42 +0200)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 18 Jul 2016 22:12:44 +0000 (22:12 +0000)
We need to be able to store private data in the struct tcb across it's
lifetime.  To ensure proper deallocation of this stored data a callback
must be provided along with the data.  The callback is executed
automatically on exiting syscall, and when the life of the tcb ends.

* defs.h (struct tcb): Add _priv_data and _free_priv_data fields.
(get_tcb_priv_data, set_tcb_priv_data, free_tcb_priv_data):
New prototypes.
(get_tcb_priv_ulong, set_tcb_priv_ulong): New static inline functions.
* strace.c (get_tcb_priv_data, set_tcb_priv_data, free_tcb_priv_data):
New functions.
(droptcb): Call free_tcb_priv_data.
* syscall.c (trace_syscall_exiting): Call free_tcb_priv_data
when clearing TCB_INSYSCALL flag.

Signed-off-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>
Signed-off-by: Dmitry V. Levin <ldv@altlinux.org>
defs.h
strace.c
syscall.c

diff --git a/defs.h b/defs.h
index cf55f11432e41f2939ee85093be42c88df0ffd1b..4b7e8eddbe13a59cff39aaf93400c89e77787474 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -314,6 +314,8 @@ struct tcb {
        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 timeval stime;   /* System time usage as of last process wait */
@@ -531,6 +533,21 @@ extern bool is_erestart(struct tcb *);
 extern void temporarily_clear_syserror(struct tcb *);
 extern void restore_cleared_syserror(struct tcb *);
 
+extern void *get_tcb_priv_data(const struct tcb *);
+extern int set_tcb_priv_data(struct tcb *, void *priv_data,
+                            void (*free_priv_data)(void *));
+extern void free_tcb_priv_data(struct tcb *);
+
+static inline unsigned long get_tcb_priv_ulong(const struct tcb *tcp)
+{
+       return (unsigned long) get_tcb_priv_data(tcp);
+}
+
+static inline int set_tcb_priv_ulong(struct tcb *tcp, unsigned long val)
+{
+       return set_tcb_priv_data(tcp, (void *) val, 0);
+}
+
 extern int umoven(struct tcb *, long, unsigned int, void *);
 #define umove(pid, addr, objp) \
        umoven((pid), (addr), sizeof(*(objp)), (void *) (objp))
index 564f1cc88279ec5f65f743d493cf4da1b43fd052..9e2fc08c0bb3d725d55faf2b87683b93144a8d58 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -746,12 +746,45 @@ alloctcb(int pid)
        error_msg_and_die("bug in alloctcb");
 }
 
+void *
+get_tcb_priv_data(const struct tcb *tcp)
+{
+       return tcp->_priv_data;
+}
+
+int
+set_tcb_priv_data(struct tcb *tcp, void *const priv_data,
+                 void (*const free_priv_data)(void *))
+{
+       if (tcp->_priv_data)
+               return -1;
+
+       tcp->_free_priv_data = free_priv_data;
+       tcp->_priv_data = priv_data;
+
+       return 0;
+}
+
+void
+free_tcb_priv_data(struct tcb *tcp)
+{
+       if (tcp->_priv_data) {
+               if (tcp->_free_priv_data) {
+                       tcp->_free_priv_data(tcp->_priv_data);
+                       tcp->_free_priv_data = NULL;
+               }
+               tcp->_priv_data = NULL;
+       }
+}
+
 static void
 droptcb(struct tcb *tcp)
 {
        if (tcp->pid == 0)
                return;
 
+       free_tcb_priv_data(tcp);
+
 #ifdef USE_LIBUNWIND
        if (stack_trace_enabled) {
                unwind_tcb_fin(tcp);
index c61f827ee153d0638547902323eb670a07523245..5c83818c3cd34d8bec3674508e18af9aa8dac2f5 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -904,6 +904,7 @@ trace_syscall_exiting(struct tcb *tcp)
                line_ended();
                tcp->flags &= ~TCB_INSYSCALL;
                tcp->sys_func_rval = 0;
+               free_tcb_priv_data(tcp);
                return res;
        }
        tcp->s_prev_ent = tcp->s_ent;
@@ -1085,6 +1086,7 @@ trace_syscall_exiting(struct tcb *tcp)
  ret:
        tcp->flags &= ~TCB_INSYSCALL;
        tcp->sys_func_rval = 0;
+       free_tcb_priv_data(tcp);
        return 0;
 }