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