-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathlibraryPatcher.h
More file actions
91 lines (78 loc) · 3.15 KB
/
Copy pathlibraryPatcher.h
File metadata and controls
91 lines (78 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#ifndef _LIBRARYPATCHER_H
#define _LIBRARYPATCHER_H
#include "codeCache.h"
#include "spinLock.h"
#include <atomic>
#ifdef __linux__
// Patch libraries' @plt entries
typedef struct _patchEntry {
CodeCache* _lib;
// library's @plt location
void** _location;
// original function
void* _func;
} PatchEntry;
class LibraryPatcher {
friend class LibraryPatcherTestAccessor;
private:
static SpinLock _lock;
// Set by initialize(), which Profiler::start() calls just before the first
// library scan. Patching must not begin any earlier: pthread_create_hook()
// routes newly created threads through Profiler::registerThread(), which
// dereferences state that only exists once the profiler is running. Read from
// the Libraries refresher thread, hence atomic with release/acquire.
static std::atomic<bool> _initialized;
static PatchEntry _patched_entries[MAX_NATIVE_LIBS];
static int _size;
static bool _patch_pthread_create;
// Separate tracking for sigaction patches
static PatchEntry _sigaction_entries[MAX_NATIVE_LIBS];
static int _sigaction_size;
// Separate tracking for socket (send/recv/write/read) patches.
// Each library can contribute up to 4 GOT slots (send/recv/write/read).
static PatchEntry _socket_entries[4 * MAX_NATIVE_LIBS];
static int _socket_size;
static void patch_library_unlocked(CodeCache* lib);
static void patch_pthread_create();
static void patch_pthread_setspecific();
static void patch_sigaction_in_library(CodeCache* lib);
// An address known to lie inside this library; how is_profiler_library()
// recognises the profiler's own mapping.
static const void* self_anchor();
// True when `lib` is the profiler's own library, which must never be patched.
static bool is_profiler_library(CodeCache* lib);
public:
// True while socket hooks are installed; read by Profiler::dlopen_hook
// to decide whether to re-patch after a new library is loaded.
// Set to true after the first batch of libraries is patched in patch_socket_functions().
// Libraries loaded after profiler start are picked up on the next dlopen_hook call,
// which calls install_socket_hooks() to patch them if _socket_active is true.
// Low-probability race: stop() is called only on JVM exit; atomic<bool> is zero-cost insurance.
static std::atomic<bool> _socket_active;
static void initialize();
static void patch_libraries();
static void unpatch_libraries();
static void patch_sigaction();
static bool patch_socket_functions();
static void unpatch_socket_functions();
// Called from Profiler::dlopen_hook after a new library is loaded.
// No-op when socket hooks are not active.
static inline void install_socket_hooks() {
if (_socket_active.load(std::memory_order_acquire)) {
patch_socket_functions();
}
}
};
#else
class LibraryPatcher {
public:
static void initialize() { }
static void patch_libraries() { }
static void unpatch_libraries() { }
static void patch_sigaction() { }
static bool patch_socket_functions() { return false; }
static void unpatch_socket_functions() { }
static void install_socket_hooks() { }
};
#endif
#endif // _LIBRARYPATCHER_H