99#include " counters.h"
1010#include " profiler.h"
1111#include " guards.h"
12+ #include " nativeSocketInterposer.h"
1213
1314#include < cassert>
1415#include < dlfcn.h>
@@ -24,6 +25,9 @@ PatchEntry LibraryPatcher::_patched_entries[MAX_NATIVE_LIBS];
2425int LibraryPatcher::_size = 0 ;
2526PatchEntry LibraryPatcher::_sigaction_entries[MAX_NATIVE_LIBS ];
2627int LibraryPatcher::_sigaction_size = 0 ;
28+ PatchEntry LibraryPatcher::_socket_entries[MAX_NATIVE_IO_HOOKS * MAX_NATIVE_LIBS ];
29+ int LibraryPatcher::_socket_size = 0 ;
30+ std::atomic<bool > LibraryPatcher::_socket_active{false };
2731
2832void LibraryPatcher::initialize () {
2933 if (_profiler_name == nullptr ) {
@@ -382,4 +386,114 @@ void LibraryPatcher::patch_sigaction() {
382386 }
383387}
384388
389+ bool LibraryPatcher::patch_socket_functions () {
390+ static void * cached_originals[NativeSocketInterposer::NUM_NATIVE_IO_HOOKS ] = {};
391+ static bool cached = false ;
392+
393+ const NativeSocketInterposer::NativeIoHookSpec* hooks =
394+ NativeSocketInterposer::hookSpecs ();
395+
396+ if (!cached) {
397+ for (int hook_index = 0 ; hook_index < NativeSocketInterposer::NUM_NATIVE_IO_HOOKS ;
398+ hook_index++) {
399+ void * original = dlsym (RTLD_NEXT , hooks[hook_index].name );
400+ if (original == nullptr ) {
401+ original = dlsym (RTLD_DEFAULT , hooks[hook_index].name );
402+ }
403+ if (original == hooks[hook_index].hook ) {
404+ original = nullptr ;
405+ }
406+ cached_originals[hook_index] = original;
407+ }
408+ cached = true ;
409+ }
410+
411+ bool any_original = false ;
412+ for (int hook_index = 0 ; hook_index < NativeSocketInterposer::NUM_NATIVE_IO_HOOKS ;
413+ hook_index++) {
414+ any_original |= cached_originals[hook_index] != nullptr ;
415+ }
416+ if (!any_original) {
417+ return false ;
418+ }
419+
420+ const CodeCacheArray& native_libs = Libraries::instance ()->native_libs ();
421+ int num_of_libs = native_libs.count ();
422+ int capped = num_of_libs <= MAX_NATIVE_LIBS ? num_of_libs : MAX_NATIVE_LIBS ;
423+ bool is_self[MAX_NATIVE_LIBS ];
424+ for (int index = 0 ; index < capped; index++) {
425+ CodeCache* lib = native_libs.at (index);
426+ is_self[index] = false ;
427+ if (lib == nullptr || lib->name () == nullptr ) {
428+ continue ;
429+ }
430+ char path[PATH_MAX ];
431+ char * resolved_path = realpath (lib->name (), path);
432+ is_self[index] = _profiler_name != nullptr && resolved_path != nullptr &&
433+ strcmp (resolved_path, _profiler_name) == 0 ;
434+ }
435+
436+ ExclusiveLockGuard locker (&_lock);
437+ if (_socket_size == 0 ) {
438+ for (int hook_index = 0 ; hook_index < NativeSocketInterposer::NUM_NATIVE_IO_HOOKS ;
439+ hook_index++) {
440+ if (cached_originals[hook_index] != nullptr ) {
441+ NativeSocketInterposer::setOriginalFunction (hook_index,
442+ cached_originals[hook_index]);
443+ }
444+ }
445+ }
446+
447+ auto try_patch_slot = [](void ** location, void * hook, const char * name,
448+ CodeCache* lib) {
449+ if (location == nullptr ) {
450+ return ;
451+ }
452+ for (int index = 0 ; index < _socket_size; index++) {
453+ if (_socket_entries[index]._location == location) {
454+ return ;
455+ }
456+ }
457+ if (_socket_size >= MAX_NATIVE_IO_HOOKS * MAX_NATIVE_LIBS ) {
458+ Log::warn (" socket I/O patch table full, skipping %s in %s" , name,
459+ lib != nullptr ? lib->name () : " ?" );
460+ return ;
461+ }
462+ _socket_entries[_socket_size]._lib = lib;
463+ _socket_entries[_socket_size]._location = location;
464+ _socket_entries[_socket_size]._func =
465+ reinterpret_cast <void *>(__atomic_load_n (location, __ATOMIC_ACQUIRE));
466+ __atomic_store_n (location, hook, __ATOMIC_RELEASE);
467+ _socket_size++;
468+ };
469+
470+ for (int index = 0 ; index < capped; index++) {
471+ CodeCache* lib = native_libs.at (index);
472+ if (lib == nullptr || lib->name () == nullptr || is_self[index]) {
473+ continue ;
474+ }
475+ for (int hook_index = 0 ; hook_index < NativeSocketInterposer::NUM_NATIVE_IO_HOOKS ;
476+ hook_index++) {
477+ if (cached_originals[hook_index] == nullptr ) {
478+ continue ;
479+ }
480+ try_patch_slot (reinterpret_cast <void **>(lib->findImport (hooks[hook_index].import_id )),
481+ hooks[hook_index].hook , hooks[hook_index].name , lib);
482+ }
483+ }
484+
485+ _socket_active.store (true , std::memory_order_release);
486+ return true ;
487+ }
488+
489+ void LibraryPatcher::unpatch_socket_functions () {
490+ ExclusiveLockGuard locker (&_lock);
491+ for (int index = 0 ; index < _socket_size; index++) {
492+ __atomic_store_n (_socket_entries[index]._location , _socket_entries[index]._func ,
493+ __ATOMIC_RELEASE);
494+ }
495+ _socket_active.store (false , std::memory_order_release);
496+ _socket_size = 0 ;
497+ }
498+
385499#endif // __linux__
0 commit comments