-
Notifications
You must be signed in to change notification settings - Fork 9
feat: macOS feasibility incorporation #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
probe_src/libprobe/src/prov_buffer.c
Outdated
| * We promise not to read those fields in this function. | ||
| */ | ||
| static void prov_log_try(struct Op op) { | ||
| #ifdef CLONE_VFORK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we not need this ifdef since x & CLONE_VFORK will always be 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
incorporated ( removed CLONE_VFORKdefinition from prov_buffer.c )
| * Generate a macOS interpose struct | ||
| * Types from: http://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h | ||
| */ | ||
| #define OSX_INTERPOSE_STRUCT(NEW, OLD) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally, pre-processor macros would be the right way to eliminate duplicated code.
In this particular case, the C code is generated from Python in generator/gen_libc_hooks.py, and there isn't a good way to emit code that calls the C preprocessor macros. It would be better to implement the logic directly in Python.
Therefore, for the above file, can you write out what it should be after expanding the pre-processor macros?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that in Linux, the shared library needs to define a function with the name we want to interpose (e.g., open), and load the real/underlying function with a new name (e.g., unwrapped_open) using dlsym.
In Mac, it seems that we define a function with the new name (e.g., my_open), and call the real/underlying function with the original name (open)
__attribute__ ((section ("__DATA,__interpose"))) = {
(const void*)(unsigned long)&my_open,
(const void*)(unsigned long)&open
};
The meaning of the name open is reversed: in Linux its the wrapper; in Mac it's the underlying function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is of course salvageable. We should always call unwrapped_open and wrapped_open to eliminate confusion, but alias one of them to the "original name" based on platform.
#ifdef linux
#define wrapped_open open
#else if apple
#define unwrapped_open open
#endif
We hardly ever call the wrapped versions, always the unwrapped, which are already called as unwrapped_ in our code.
But I wanted to confirm that this is the only way to interpose functions in Mac before doing that. So please let me know.
Co-authored-by: Jenna Fligor <jenna@fligor.net>
Co-authored-by: Jenna Fligor <jenna@fligor.net>
Co-authored-by: Jenna Fligor <jenna@fligor.net>
| if (!__process_inited) { | ||
| __process_inited = true; | ||
|
|
||
| DEBUG("Initializing process"); | ||
| init_function_pointers(); | ||
| check_function_pointers(); | ||
| init_process_global_state(); | ||
|
|
||
| pthread_key_create(&tld_key, free); | ||
|
|
||
| __process_inited_done = true; | ||
| } | ||
| while (!__process_inited_done) { | ||
| sched_yield(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there may be a race if multiple threads try to init at the same. I think I specified the algorihtm incorrectly (slightly the first time). Here's what it should be:
if (is process inited) {
if (test_and_set(is first thread)) {
... do your process initialization you have here
is process initted = true;
} else {
// process is not initted, but someone else is already handling it.
while (!process is inited) { sched_yield(); }
}
}
// process is inited here. Yay!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_and_set should be replaced __sync_bool_compare_and_swap
Description:
Making
PROBEfeasible for macOS systems.Changes:
Worked out how to interpose in macOS, added a test program (
test_program.c), which interposes thefopencall and calls the underlying call. The mentioned changes are in filesinterpose.h,interpose.c,test_program.c. Steps to runtest_program.cwith interposition:clang -dynamiclib -o libinterpose.dylib interpose.cclang -o test_program test_program.cexport DYLD_INSERT_LIBRARIES=$(pwd)/libinterpose.dylib./test_programAdded macOS architecture in
flake.nixEdited
Makefileto be adjustable for both linux and macOS.The rest of the changes have been made either to add replacement libraries for macOS, added
ifndefwith code blocks which are linux or macOS specific. Added dummy definitions liketypedef thrd_t intfor macros which are not available on macOS. Guarded dummy definitions withifndefQuestions and next steps: