From a1546a9550bb46bc8847da7d6432c8de0c3352c3 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Mon, 24 Aug 2015 14:42:47 +0200 Subject: [PATCH] Add private data field to struct tcb 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 Signed-off-by: Dmitry V. Levin --- defs.h | 17 +++++++++++++++++ strace.c | 33 +++++++++++++++++++++++++++++++++ syscall.c | 2 ++ 3 files changed, 52 insertions(+) diff --git a/defs.h b/defs.h index cf55f114..4b7e8edd 100644 --- 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)) diff --git a/strace.c b/strace.c index 564f1cc8..9e2fc08c 100644 --- 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); diff --git a/syscall.c b/syscall.c index c61f827e..5c83818c 100644 --- 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; } -- 2.40.0