diff --git a/api/docs/release.dox b/api/docs/release.dox
index bdf2b61ef6d..a9ace348c7b 100644
--- a/api/docs/release.dox
+++ b/api/docs/release.dox
@@ -219,6 +219,10 @@ Further non-compatibility-affecting changes include:
physical cpus.
- Added #DR_DISALLOW_UNSAFE_STATIC and dr_disallow_unsafe_static_behavior()
for sanity checks to help support statically-linked clients.
+ - Added drmgr_register_pre_syscall_event_user_data() and
+ drmgr_unregister_pre_syscall_event_user_data() to enable passing of user data.
+ - Added drmgr_register_post_syscall_event_user_data() and
+ drmgr_unregister_post_syscall_event_user_data() to enable passing of user data.
**************************************************
diff --git a/ext/drmgr/drmgr.c b/ext/drmgr/drmgr.c
index 4aae11b9762..2b71c782ab3 100644
--- a/ext/drmgr/drmgr.c
+++ b/ext/drmgr/drmgr.c
@@ -124,15 +124,21 @@ typedef struct _generic_event_entry_t {
void (*cb_user_data)(void *, void *);
} thread_cb;
void (*cls_cb)(void *, bool);
- bool (*presys_cb)(void *, int);
- void (*postsys_cb)(void *, int);
+ union {
+ bool (*cb_no_user_data)(void *, int);
+ bool (*cb_user_data)(void *, int, void *);
+ } presys_cb;
+ union {
+ void (*cb_no_user_data)(void *, int);
+ void (*cb_user_data)(void *, int, void *);
+ } postsys_cb;
union {
void (*cb_no_user_data)(void *, const module_data_t *, bool);
- void (*cb_user_data)(void *, const module_data_t *, bool, void *user_data);
+ void (*cb_user_data)(void *, const module_data_t *, bool, void *);
} modload_cb;
union {
void (*cb_no_user_data)(void *, const module_data_t *);
- void (*cb_user_data)(void *, const module_data_t *, void *user_data);
+ void (*cb_user_data)(void *, const module_data_t *, void *);
} modunload_cb;
void (*kernel_xfer_cb)(void *, const dr_kernel_xfer_info_t *);
#ifdef UNIX
@@ -1360,6 +1366,16 @@ drmgr_register_pre_syscall_event_ex(bool (*func)(void *drcontext, int sysnum),
(void (*)(void)) func, priority, false, NULL);
}
+DR_EXPORT
+bool
+drmgr_register_pre_syscall_event_user_data(bool (*func)(void *drcontext, int sysnum,
+ void *user_data),
+ drmgr_priority_t *priority, void *user_data)
+{
+ return drmgr_generic_event_add(&cblist_presys, presys_event_lock,
+ (void (*)(void)) func, priority, true, user_data);
+}
+
DR_EXPORT
bool
drmgr_unregister_pre_syscall_event(bool (*func)(void *drcontext, int sysnum))
@@ -1368,6 +1384,15 @@ drmgr_unregister_pre_syscall_event(bool (*func)(void *drcontext, int sysnum))
(void (*)(void)) func);
}
+DR_EXPORT
+bool
+drmgr_unregister_pre_syscall_event_user_data(bool (*func)(void *drcontext, int sysnum,
+ void *user_data))
+{
+ return drmgr_generic_event_remove(&cblist_presys, presys_event_lock,
+ (void (*)(void)) func);
+}
+
static bool
drmgr_presyscall_event(void *drcontext, int sysnum)
{
@@ -1383,7 +1408,18 @@ drmgr_presyscall_event(void *drcontext, int sysnum)
for (i = 0; i < iter.num; i++) {
if (!iter.cbs.generic[i].pri.valid)
continue;
- execute = (*iter.cbs.generic[i].cb.presys_cb)(drcontext, sysnum) && execute;
+ bool is_using_user_data = iter.cbs.generic[i].is_using_user_data;
+ void *user_data = iter.cbs.generic[i].user_data;
+ if (is_using_user_data == false) {
+ execute = (*iter.cbs.generic[i].cb.presys_cb.cb_no_user_data)(drcontext,
+ sysnum)
+ && execute;
+ } else {
+ execute = (*iter.cbs.generic[i].cb.presys_cb.cb_user_data)(drcontext,
+ sysnum,
+ user_data)
+ && execute;
+ }
}
/* We used to track NtCallbackReturn for CLS (before DR provided the kernel xfer
@@ -1407,12 +1443,22 @@ drmgr_register_post_syscall_event(void (*func)(void *drcontext, int sysnum))
DR_EXPORT
bool
drmgr_register_post_syscall_event_ex(void (*func)(void *drcontext, int sysnum),
- drmgr_priority_t *priority)
+ drmgr_priority_t *priority)
{
return drmgr_generic_event_add(&cblist_postsys, postsys_event_lock,
(void (*)(void)) func, priority, false, NULL);
}
+DR_EXPORT
+bool
+drmgr_register_post_syscall_event_user_data(void (*func)(void *drcontext, int sysnum,
+ void *user_data),
+ drmgr_priority_t *priority, void *user_data)
+{
+ return drmgr_generic_event_add(&cblist_postsys, postsys_event_lock,
+ (void (*)(void)) func, priority, true, user_data);
+}
+
DR_EXPORT
bool
drmgr_unregister_post_syscall_event(void (*func)(void *drcontext, int sysnum))
@@ -1421,6 +1467,15 @@ drmgr_unregister_post_syscall_event(void (*func)(void *drcontext, int sysnum))
(void (*)(void)) func);
}
+DR_EXPORT
+bool
+drmgr_unregister_post_syscall_event_user_data(void (*func)(void *drcontext, int sysnum,
+ void *user_data))
+{
+ return drmgr_generic_event_remove(&cblist_postsys, postsys_event_lock,
+ (void (*)(void)) func);
+}
+
static void
drmgr_postsyscall_event(void *drcontext, int sysnum)
{
@@ -1435,7 +1490,14 @@ drmgr_postsyscall_event(void *drcontext, int sysnum)
for (i = 0; i < iter.num; i++) {
if (!iter.cbs.generic[i].pri.valid)
continue;
- (*iter.cbs.generic[i].cb.postsys_cb)(drcontext, sysnum);
+ bool is_using_user_data = iter.cbs.generic[i].is_using_user_data;
+ void *user_data = iter.cbs.generic[i].user_data;
+ if (is_using_user_data == false)
+ (*iter.cbs.generic[i].cb.postsys_cb.cb_no_user_data)(drcontext, sysnum);
+ else {
+ (*iter.cbs.generic[i].cb.postsys_cb.cb_user_data)(drcontext, sysnum,
+ user_data);
+ }
}
cblist_delete_local(drcontext, &iter, BUFFER_SIZE_ELEMENTS(local));
}
diff --git a/ext/drmgr/drmgr.h b/ext/drmgr/drmgr.h
index 7fc40d3debf..e97c86b181d 100644
--- a/ext/drmgr/drmgr.h
+++ b/ext/drmgr/drmgr.h
@@ -859,6 +859,19 @@ bool
drmgr_register_pre_syscall_event_ex(bool (*func)(void *drcontext, int sysnum),
drmgr_priority_t *priority);
+DR_EXPORT
+/**
+ * Registers a callback function for the pre-syscall event,
+ * ordered by \p priority. Allows for the passing of user data \p user_data
+ * which is available upon the execution of the callback.
+ * \return whether successful.
+ */
+bool
+drmgr_register_pre_syscall_event_user_data(bool (*func)(void *drcontext, int sysnum,
+ void *user_data),
+ drmgr_priority_t *priority,
+ void *user_data);
+
DR_EXPORT
/**
* Unregister a callback function for the pre-syscall event.
@@ -868,6 +881,16 @@ DR_EXPORT
bool
drmgr_unregister_pre_syscall_event(bool (*func)(void *drcontext, int sysnum));
+DR_EXPORT
+/**
+ * Unregister a callback function, which takes user data, for the pre-syscall event.
+ * \return true if unregistration is successful and false if it is not
+ * (e.g., \p func was not registered).
+ */
+bool
+drmgr_unregister_pre_syscall_event_user_data(bool (*func)(void *drcontext, int sysnum,
+ void *user_data));
+
DR_EXPORT
/**
* Registers a callback function for the post-syscall event, which
@@ -889,7 +912,20 @@ DR_EXPORT
*/
bool
drmgr_register_post_syscall_event_ex(void (*func)(void *drcontext, int sysnum),
- drmgr_priority_t *priority);
+ drmgr_priority_t *priority);
+
+DR_EXPORT
+/**
+ * Registers a callback function for the post-syscall event,
+ * ordered by \p priority. Allows for the passing of user data \p user_data
+ * which is available upon the execution of the callback.
+ * \return whether successful.
+ */
+bool
+drmgr_register_post_syscall_event_user_data(void (*func)(void *drcontext, int sysnum,
+ void *user_data),
+ drmgr_priority_t *priority,
+ void *user_data);
DR_EXPORT
/**
@@ -900,6 +936,16 @@ DR_EXPORT
bool
drmgr_unregister_post_syscall_event(void (*func)(void *drcontext, int sysnum));
+DR_EXPORT
+/**
+ * Unregister a callback function, which takes user data, for the post-syscall event.
+ * \return true if unregistration is successful and false if it is not
+ * (e.g., \p func was not registered).
+ */
+bool
+drmgr_unregister_post_syscall_event_user_data(void (*func)(void *drcontext, int sysnum,
+ void *user_data));
+
DR_EXPORT
/**
* Registers a callback function for the module load event, which
diff --git a/suite/tests/client-interface/drmgr-test.dll.c b/suite/tests/client-interface/drmgr-test.dll.c
index 2f7f6d5813b..6bac2cda78b 100755
--- a/suite/tests/client-interface/drmgr-test.dll.c
+++ b/suite/tests/client-interface/drmgr-test.dll.c
@@ -55,9 +55,13 @@ static int cls_idx;
static thread_id_t main_thread;
static int cb_depth;
static volatile bool in_syscall_A;
+static volatile bool in_syscall_A_user_data;
static volatile bool in_syscall_B;
+static volatile bool in_syscall_B_user_data;
static volatile bool in_post_syscall_A;
+static volatile bool in_post_syscall_A_user_data;
static volatile bool in_post_syscall_B;
+static volatile bool in_post_syscall_B_user_data;
static volatile bool in_event_thread_init;
static volatile bool in_event_thread_init_ex;
static volatile bool in_event_thread_init_user_data;
@@ -97,9 +101,13 @@ static void event_mod_unload(void *drcontext, const module_data_t *mod,
void *user_data);
static bool event_filter_syscall(void *drcontext, int sysnum);
static bool event_pre_sys_A(void *drcontext, int sysnum);
+static bool event_pre_sys_A_user_data(void *drcontext, int sysnum, void *user_data);
static bool event_pre_sys_B(void *drcontext, int sysnum);
+static bool event_pre_sys_B_user_data(void *drcontext, int sysnum, void *user_data);
static void event_post_sys_A(void *drcontext, int sysnum);
+static void event_post_sys_A_user_data(void *drcontext, int sysnum, void *user_data);
static void event_post_sys_B(void *drcontext, int sysnum);
+static void event_post_sys_B_user_data(void *drcontext, int sysnum, void *user_data);
static dr_emit_flags_t event_bb_analysis(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating,
OUT void **user_data);
@@ -128,7 +136,11 @@ static dr_emit_flags_t one_time_bb_event(void *drcontext, void *tag, instrlist_t
bool for_trace, bool translating);
static void event_kernel_xfer(void *drcontext, const dr_kernel_xfer_info_t *info);
+/* The following test values are arbitrary */
+
static const uintptr_t thread_user_data_test = 9090;
+static const uintptr_t syscall_A_user_data_test = 7189;
+static const uintptr_t syscall_B_user_data_test = 3218;
static const uintptr_t mod_user_data_test = 1070;
DR_EXPORT void
@@ -138,8 +150,15 @@ dr_init(client_id_t id)
drmgr_priority_t priority4 = {sizeof(priority), "drmgr-test4", NULL, NULL, 0};
drmgr_priority_t sys_pri_A = {sizeof(priority), "drmgr-test-A",
NULL, NULL, 10};
+ drmgr_priority_t sys_pri_A_user_data = {sizeof(priority),
+ "drmgr-test-A-usr-data-test",
+ "drmgr-test-A", NULL, 9};
drmgr_priority_t sys_pri_B = {sizeof(priority), "drmgr-test-B",
- "drmgr-test-A", NULL, 5};
+ "drmgr-test-A-usr-data-test", NULL, 5};
+ drmgr_priority_t sys_pri_B_user_data = {sizeof(priority),
+ "drmgr-test-B-usr-data-test",
+ "drmgr-test-B",
+ NULL, 4};
drmgr_priority_t thread_init_null_user_data_pri = {sizeof(priority),
"drmgr-t-in-null-user-data-test",
NULL, NULL, -3};
@@ -217,10 +236,22 @@ dr_init(client_id_t id)
dr_register_filter_syscall_event(event_filter_syscall);
ok = drmgr_register_pre_syscall_event_ex(event_pre_sys_A, &sys_pri_A) &&
- drmgr_register_pre_syscall_event_ex(event_pre_sys_B, &sys_pri_B);
+ drmgr_register_pre_syscall_event_user_data(event_pre_sys_A_user_data,
+ &sys_pri_A_user_data,
+ (void *) syscall_A_user_data_test) &&
+ drmgr_register_pre_syscall_event_ex(event_pre_sys_B, &sys_pri_B) &&
+ drmgr_register_pre_syscall_event_user_data(event_pre_sys_B_user_data,
+ &sys_pri_B_user_data,
+ (void *) syscall_B_user_data_test);
CHECK(ok, "drmgr register sys failed");
ok = drmgr_register_post_syscall_event_ex(event_post_sys_A, &sys_pri_A) &&
- drmgr_register_post_syscall_event_ex(event_post_sys_B, &sys_pri_B);
+ drmgr_register_post_syscall_event_user_data(event_post_sys_A_user_data,
+ &sys_pri_A_user_data,
+ (void *) syscall_A_user_data_test) &&
+ drmgr_register_post_syscall_event_ex(event_post_sys_B, &sys_pri_B) &&
+ drmgr_register_post_syscall_event_user_data(event_post_sys_B_user_data,
+ &sys_pri_B_user_data,
+ (void *) syscall_B_user_data_test);
CHECK(ok, "drmgr register sys failed");
syslock = dr_mutex_create();
@@ -601,6 +632,22 @@ event_pre_sys_A(void *drcontext, int sysnum)
return true;
}
+static bool
+event_pre_sys_A_user_data(void *drcontext, int sysnum, void *user_data)
+{
+ if (!in_syscall_A_user_data) {
+ dr_mutex_lock(syslock);
+ if (!in_syscall_A_user_data) {
+ dr_fprintf(STDERR, "in pre_sys_A_user_data\n");
+ in_syscall_A_user_data = true;
+ CHECK(user_data == (void *) syscall_A_user_data_test,
+ "incorrect user data pre-syscall A");
+ }
+ dr_mutex_unlock(syslock);
+ }
+ return true;
+}
+
static bool
event_pre_sys_B(void *drcontext, int sysnum)
{
@@ -615,6 +662,22 @@ event_pre_sys_B(void *drcontext, int sysnum)
return true;
}
+static bool
+event_pre_sys_B_user_data(void *drcontext, int sysnum, void *user_data)
+{
+ if (!in_syscall_B_user_data) {
+ dr_mutex_lock(syslock);
+ if (!in_syscall_B_user_data) {
+ dr_fprintf(STDERR, "in pre_sys_B_user_data\n");
+ in_syscall_B_user_data = true;
+ CHECK(user_data == (void *) syscall_B_user_data_test,
+ "incorrect user data pre-syscall B");
+ }
+ dr_mutex_unlock(syslock);
+ }
+ return true;
+}
+
static void
event_post_sys_A(void *drcontext, int sysnum)
{
@@ -628,6 +691,21 @@ event_post_sys_A(void *drcontext, int sysnum)
}
}
+static void
+event_post_sys_A_user_data(void *drcontext, int sysnum, void *user_data)
+{
+ if (!in_post_syscall_A_user_data) {
+ dr_mutex_lock(syslock);
+ if (!in_post_syscall_A_user_data) {
+ dr_fprintf(STDERR, "in post_sys_A_user_data\n");
+ in_post_syscall_A_user_data = true;
+ CHECK(user_data == (void *) syscall_A_user_data_test,
+ "incorrect user data post-syscall A");
+ }
+ dr_mutex_unlock(syslock);
+ }
+}
+
static void
event_post_sys_B(void *drcontext, int sysnum)
{
@@ -641,6 +719,19 @@ event_post_sys_B(void *drcontext, int sysnum)
}
}
+static void
+event_post_sys_B_user_data(void *drcontext, int sysnum, void *user_data)
+{
+ if (!in_post_syscall_B_user_data) {
+ dr_mutex_lock(syslock);
+ if (!in_post_syscall_B_user_data) {
+ dr_fprintf(STDERR, "in post_sys_B_user_data\n");
+ in_post_syscall_B_user_data = true;
+ }
+ dr_mutex_unlock(syslock);
+ }
+}
+
/* test unregistering from inside an event */
static dr_emit_flags_t
one_time_bb_event(void *drcontext, void *tag, instrlist_t *bb,
diff --git a/suite/tests/client-interface/drmgr-test.templatex b/suite/tests/client-interface/drmgr-test.templatex
index 25ecf4d8bb4..7cbb6033645 100755
--- a/suite/tests/client-interface/drmgr-test.templatex
+++ b/suite/tests/client-interface/drmgr-test.templatex
@@ -2,10 +2,14 @@ in event_thread_init_null_user_data
in event_thread_init_user_data
in event_thread_init_ex
in event_thread_init
+in pre_sys_B_user_data
in pre_sys_B
+in pre_sys_A_user_data
in pre_sys_A
/* B is here with late injection */
+in post_sys_B_user_data
in post_sys_B
+in post_sys_A_user_data
in post_sys_A
#ifdef UNIX
B