jruby-async-profiler 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.gitmodules +3 -0
- data/Gemfile +4 -0
- data/README.md +35 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/Rakefile +6 -0
- data/ext/async-profiler/.gitattributes +1 -0
- data/ext/async-profiler/.gitignore +6 -0
- data/ext/async-profiler/.travis.yml +11 -0
- data/ext/async-profiler/CHANGELOG.md +107 -0
- data/ext/async-profiler/JavaHome.class +0 -0
- data/ext/async-profiler/LICENSE +201 -0
- data/ext/async-profiler/Makefile +66 -0
- data/ext/async-profiler/README.md +487 -0
- data/ext/async-profiler/demo/SwingSet2.svg +2247 -0
- data/ext/async-profiler/docs/cddl1.txt +358 -0
- data/ext/async-profiler/profiler.sh +240 -0
- data/ext/async-profiler/src/allocTracer.cpp +155 -0
- data/ext/async-profiler/src/allocTracer.h +74 -0
- data/ext/async-profiler/src/arch.h +69 -0
- data/ext/async-profiler/src/arguments.cpp +265 -0
- data/ext/async-profiler/src/arguments.h +152 -0
- data/ext/async-profiler/src/codeCache.cpp +128 -0
- data/ext/async-profiler/src/codeCache.h +99 -0
- data/ext/async-profiler/src/engine.cpp +50 -0
- data/ext/async-profiler/src/engine.h +38 -0
- data/ext/async-profiler/src/flameGraph.cpp +770 -0
- data/ext/async-profiler/src/flameGraph.h +118 -0
- data/ext/async-profiler/src/flightRecorder.cpp +727 -0
- data/ext/async-profiler/src/flightRecorder.h +39 -0
- data/ext/async-profiler/src/frameName.cpp +189 -0
- data/ext/async-profiler/src/frameName.h +56 -0
- data/ext/async-profiler/src/itimer.cpp +49 -0
- data/ext/async-profiler/src/itimer.h +43 -0
- data/ext/async-profiler/src/jattach/jattach.c +437 -0
- data/ext/async-profiler/src/java/one/profiler/AsyncProfiler.java +160 -0
- data/ext/async-profiler/src/java/one/profiler/AsyncProfilerMXBean.java +43 -0
- data/ext/async-profiler/src/java/one/profiler/Counter.java +25 -0
- data/ext/async-profiler/src/java/one/profiler/Events.java +28 -0
- data/ext/async-profiler/src/javaApi.cpp +124 -0
- data/ext/async-profiler/src/lockTracer.cpp +161 -0
- data/ext/async-profiler/src/lockTracer.h +55 -0
- data/ext/async-profiler/src/mutex.cpp +33 -0
- data/ext/async-profiler/src/mutex.h +49 -0
- data/ext/async-profiler/src/os.h +45 -0
- data/ext/async-profiler/src/os_linux.cpp +129 -0
- data/ext/async-profiler/src/os_macos.cpp +115 -0
- data/ext/async-profiler/src/perfEvents.h +60 -0
- data/ext/async-profiler/src/perfEvents_linux.cpp +550 -0
- data/ext/async-profiler/src/perfEvents_macos.cpp +64 -0
- data/ext/async-profiler/src/profiler.cpp +952 -0
- data/ext/async-profiler/src/profiler.h +238 -0
- data/ext/async-profiler/src/spinLock.h +66 -0
- data/ext/async-profiler/src/stackFrame.h +57 -0
- data/ext/async-profiler/src/stackFrame_aarch64.cpp +75 -0
- data/ext/async-profiler/src/stackFrame_arm.cpp +58 -0
- data/ext/async-profiler/src/stackFrame_i386.cpp +82 -0
- data/ext/async-profiler/src/stackFrame_x64.cpp +113 -0
- data/ext/async-profiler/src/symbols.h +37 -0
- data/ext/async-profiler/src/symbols_linux.cpp +354 -0
- data/ext/async-profiler/src/symbols_macos.cpp +156 -0
- data/ext/async-profiler/src/vmEntry.cpp +173 -0
- data/ext/async-profiler/src/vmEntry.h +105 -0
- data/ext/async-profiler/src/vmStructs.cpp +104 -0
- data/ext/async-profiler/src/vmStructs.h +112 -0
- data/ext/async-profiler/src/wallClock.cpp +96 -0
- data/ext/async-profiler/src/wallClock.h +56 -0
- data/ext/async-profiler/test/AllocatingTarget.java +26 -0
- data/ext/async-profiler/test/LoadLibraryTest.java +21 -0
- data/ext/async-profiler/test/Target.java +31 -0
- data/ext/async-profiler/test/ThreadsTarget.java +35 -0
- data/ext/async-profiler/test/alloc-smoke-test.sh +36 -0
- data/ext/async-profiler/test/load-library-test.sh +35 -0
- data/ext/async-profiler/test/smoke-test.sh +37 -0
- data/ext/async-profiler/test/thread-smoke-test.sh +32 -0
- data/jruby-async-profiler.gemspec +32 -0
- data/lib/jruby/async/profiler.rb +10 -0
- data/lib/jruby/async/profiler/version.rb +7 -0
- metadata +155 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2016 Andrei Pangin
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#ifndef _PROFILER_H
|
18
|
+
#define _PROFILER_H
|
19
|
+
|
20
|
+
#include <iostream>
|
21
|
+
#include <map>
|
22
|
+
#include <time.h>
|
23
|
+
#include "arch.h"
|
24
|
+
#include "arguments.h"
|
25
|
+
#include "engine.h"
|
26
|
+
#include "flightRecorder.h"
|
27
|
+
#include "mutex.h"
|
28
|
+
#include "spinLock.h"
|
29
|
+
#include "codeCache.h"
|
30
|
+
#include "vmEntry.h"
|
31
|
+
|
32
|
+
|
33
|
+
const char FULL_VERSION_STRING[] =
|
34
|
+
"Async-profiler " PROFILER_VERSION " built on " __DATE__ "\n"
|
35
|
+
"Copyright 2019 Andrei Pangin\n";
|
36
|
+
|
37
|
+
const int MAX_CALLTRACES = 65536;
|
38
|
+
const int MAX_NATIVE_FRAMES = 128;
|
39
|
+
const int RESERVED_FRAMES = 4;
|
40
|
+
const int MAX_NATIVE_LIBS = 2048;
|
41
|
+
const int CONCURRENCY_LEVEL = 16;
|
42
|
+
|
43
|
+
|
44
|
+
static inline int cmp64(u64 a, u64 b) {
|
45
|
+
return a > b ? 1 : a == b ? 0 : -1;
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
union CallTraceBuffer {
|
50
|
+
ASGCT_CallFrame _asgct_frames[1];
|
51
|
+
jvmtiFrameInfo _jvmti_frames[1];
|
52
|
+
};
|
53
|
+
|
54
|
+
|
55
|
+
class CallTraceSample {
|
56
|
+
private:
|
57
|
+
u64 _samples;
|
58
|
+
u64 _counter;
|
59
|
+
int _start_frame; // Offset in frame buffer
|
60
|
+
int _num_frames;
|
61
|
+
|
62
|
+
public:
|
63
|
+
static int comparator(const void* s1, const void* s2) {
|
64
|
+
return cmp64((*(CallTraceSample**)s2)->_counter, (*(CallTraceSample**)s1)->_counter);
|
65
|
+
}
|
66
|
+
|
67
|
+
friend class Profiler;
|
68
|
+
friend class Recording;
|
69
|
+
};
|
70
|
+
|
71
|
+
class MethodSample {
|
72
|
+
private:
|
73
|
+
u64 _samples;
|
74
|
+
u64 _counter;
|
75
|
+
ASGCT_CallFrame _method;
|
76
|
+
|
77
|
+
public:
|
78
|
+
static int comparator(const void* s1, const void* s2) {
|
79
|
+
return cmp64((*(MethodSample**)s2)->_counter, (*(MethodSample**)s1)->_counter);
|
80
|
+
}
|
81
|
+
|
82
|
+
friend class Profiler;
|
83
|
+
};
|
84
|
+
|
85
|
+
|
86
|
+
typedef jboolean JNICALL (*NativeLoadLibraryFunc)(JNIEnv*, jobject, jstring, jboolean);
|
87
|
+
|
88
|
+
enum State {
|
89
|
+
IDLE,
|
90
|
+
RUNNING,
|
91
|
+
TERMINATED
|
92
|
+
};
|
93
|
+
|
94
|
+
class Profiler {
|
95
|
+
private:
|
96
|
+
Mutex _state_lock;
|
97
|
+
State _state;
|
98
|
+
Mutex _thread_names_lock;
|
99
|
+
std::map<int, std::string> _thread_names;
|
100
|
+
FlightRecorder _jfr;
|
101
|
+
Engine* _engine;
|
102
|
+
time_t _start_time;
|
103
|
+
|
104
|
+
u64 _total_samples;
|
105
|
+
u64 _total_counter;
|
106
|
+
u64 _failures[ASGCT_FAILURE_TYPES];
|
107
|
+
u64 _hashes[MAX_CALLTRACES];
|
108
|
+
CallTraceSample _traces[MAX_CALLTRACES];
|
109
|
+
MethodSample _methods[MAX_CALLTRACES];
|
110
|
+
|
111
|
+
SpinLock _locks[CONCURRENCY_LEVEL];
|
112
|
+
CallTraceBuffer* _calltrace_buffer[CONCURRENCY_LEVEL];
|
113
|
+
ASGCT_CallFrame* _frame_buffer;
|
114
|
+
int _frame_buffer_size;
|
115
|
+
int _max_stack_depth;
|
116
|
+
volatile int _frame_buffer_index;
|
117
|
+
bool _frame_buffer_overflow;
|
118
|
+
bool _threads;
|
119
|
+
bool _sync_walk;
|
120
|
+
volatile bool _thread_events_state;
|
121
|
+
|
122
|
+
SpinLock _jit_lock;
|
123
|
+
const void* _jit_min_address;
|
124
|
+
const void* _jit_max_address;
|
125
|
+
CodeCache _java_methods;
|
126
|
+
NativeCodeCache _runtime_stubs;
|
127
|
+
NativeCodeCache* _native_libs[MAX_NATIVE_LIBS];
|
128
|
+
volatile int _native_lib_count;
|
129
|
+
|
130
|
+
JNINativeMethod _load_method;
|
131
|
+
NativeLoadLibraryFunc _original_NativeLibrary_load;
|
132
|
+
static jboolean JNICALL NativeLibraryLoadTrap(JNIEnv* env, jobject self, jstring name, jboolean builtin);
|
133
|
+
void bindNativeLibraryLoad(NativeLoadLibraryFunc entry);
|
134
|
+
|
135
|
+
void* (*_ThreadLocalStorage_thread)();
|
136
|
+
jvmtiError (*_JvmtiEnv_GetStackTrace)(void* self, void* thread, jint start_depth, jint max_frame_count,
|
137
|
+
jvmtiFrameInfo* frame_buffer, jint* count_ptr);
|
138
|
+
|
139
|
+
void addJavaMethod(const void* address, int length, jmethodID method);
|
140
|
+
void removeJavaMethod(const void* address, jmethodID method);
|
141
|
+
void addRuntimeStub(const void* address, int length, const char* name);
|
142
|
+
void updateJitRange(const void* min_address, const void* max_address);
|
143
|
+
|
144
|
+
const char* asgctError(int code);
|
145
|
+
const char* findNativeMethod(const void* address);
|
146
|
+
int getNativeTrace(void* ucontext, ASGCT_CallFrame* frames, int tid, bool* stopped_at_java_frame);
|
147
|
+
int getJavaTraceAsync(void* ucontext, ASGCT_CallFrame* frames, int max_depth);
|
148
|
+
int getJavaTraceJvmti(jvmtiFrameInfo* jvmti_frames, ASGCT_CallFrame* frames, int max_depth);
|
149
|
+
int makeEventFrame(ASGCT_CallFrame* frames, jint event_type, jmethodID event);
|
150
|
+
bool fillTopFrame(const void* pc, ASGCT_CallFrame* frame);
|
151
|
+
bool addressInCode(const void* pc);
|
152
|
+
u64 hashCallTrace(int num_frames, ASGCT_CallFrame* frames);
|
153
|
+
int storeCallTrace(int num_frames, ASGCT_CallFrame* frames, u64 counter);
|
154
|
+
void copyToFrameBuffer(int num_frames, ASGCT_CallFrame* frames, CallTraceSample* trace);
|
155
|
+
u64 hashMethod(jmethodID method);
|
156
|
+
void storeMethod(jmethodID method, jint bci, u64 counter);
|
157
|
+
void initJvmtiFunctions(NativeCodeCache* libjvm);
|
158
|
+
void setThreadName(int tid, const char* name);
|
159
|
+
void updateThreadName(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread);
|
160
|
+
void updateAllThreadNames();
|
161
|
+
Engine* selectEngine(const char* event_name);
|
162
|
+
|
163
|
+
public:
|
164
|
+
static Profiler _instance;
|
165
|
+
|
166
|
+
Profiler() :
|
167
|
+
_state(IDLE),
|
168
|
+
_jfr(),
|
169
|
+
_frame_buffer(NULL),
|
170
|
+
_frame_buffer_size(0),
|
171
|
+
_max_stack_depth(0),
|
172
|
+
_thread_events_state(JVMTI_DISABLE),
|
173
|
+
_jit_lock(),
|
174
|
+
_jit_min_address((const void*)-1),
|
175
|
+
_jit_max_address((const void*)0),
|
176
|
+
_java_methods(),
|
177
|
+
_runtime_stubs("[stubs]"),
|
178
|
+
_native_lib_count(0),
|
179
|
+
_original_NativeLibrary_load(NULL),
|
180
|
+
_ThreadLocalStorage_thread(NULL),
|
181
|
+
_JvmtiEnv_GetStackTrace(NULL) {
|
182
|
+
|
183
|
+
for (int i = 0; i < CONCURRENCY_LEVEL; i++) {
|
184
|
+
_calltrace_buffer[i] = NULL;
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
u64 total_samples() { return _total_samples; }
|
189
|
+
u64 total_counter() { return _total_counter; }
|
190
|
+
time_t uptime() { return time(NULL) - _start_time; }
|
191
|
+
|
192
|
+
void run(Arguments& args);
|
193
|
+
void runInternal(Arguments& args, std::ostream& out);
|
194
|
+
void shutdown(Arguments& args);
|
195
|
+
Error start(Arguments& args, bool reset);
|
196
|
+
Error stop();
|
197
|
+
void switchThreadEvents(jvmtiEventMode mode);
|
198
|
+
void dumpSummary(std::ostream& out);
|
199
|
+
void dumpCollapsed(std::ostream& out, Arguments& args);
|
200
|
+
void dumpFlameGraph(std::ostream& out, Arguments& args, bool tree);
|
201
|
+
void dumpTraces(std::ostream& out, Arguments& args);
|
202
|
+
void dumpFlat(std::ostream& out, Arguments& args);
|
203
|
+
void recordSample(void* ucontext, u64 counter, jint event_type, jmethodID event);
|
204
|
+
NativeCodeCache* jvmLibrary();
|
205
|
+
const void* findSymbol(const char* name);
|
206
|
+
|
207
|
+
// CompiledMethodLoad is also needed to enable DebugNonSafepoints info by default
|
208
|
+
static void JNICALL CompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
|
209
|
+
jint code_size, const void* code_addr,
|
210
|
+
jint map_length, const jvmtiAddrLocationMap* map,
|
211
|
+
const void* compile_info) {
|
212
|
+
_instance.addJavaMethod(code_addr, code_size, method);
|
213
|
+
}
|
214
|
+
|
215
|
+
static void JNICALL CompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
|
216
|
+
const void* code_addr) {
|
217
|
+
_instance.removeJavaMethod(code_addr, method);
|
218
|
+
}
|
219
|
+
|
220
|
+
static void JNICALL DynamicCodeGenerated(jvmtiEnv* jvmti, const char* name,
|
221
|
+
const void* address, jint length) {
|
222
|
+
_instance.addRuntimeStub(address, length, name);
|
223
|
+
}
|
224
|
+
|
225
|
+
static void JNICALL ThreadStart(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
|
226
|
+
_instance.updateThreadName(jvmti, jni, thread);
|
227
|
+
_instance._engine->onThreadStart();
|
228
|
+
}
|
229
|
+
|
230
|
+
static void JNICALL ThreadEnd(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
|
231
|
+
_instance.updateThreadName(jvmti, jni, thread);
|
232
|
+
_instance._engine->onThreadEnd();
|
233
|
+
}
|
234
|
+
|
235
|
+
friend class Recording;
|
236
|
+
};
|
237
|
+
|
238
|
+
#endif // _PROFILER_H
|
@@ -0,0 +1,66 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2017 Andrei Pangin
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#ifndef _SPINLOCK_H
|
18
|
+
#define _SPINLOCK_H
|
19
|
+
|
20
|
+
#include "arch.h"
|
21
|
+
|
22
|
+
|
23
|
+
// Cannot use regular mutexes inside signal handler.
|
24
|
+
// This lock is based on CAS busy loop. GCC atomic builtins imply full barrier.
|
25
|
+
class SpinLock {
|
26
|
+
private:
|
27
|
+
// 0 - unlocked
|
28
|
+
// 1 - exclusive lock
|
29
|
+
// <0 - shared lock
|
30
|
+
volatile int _lock;
|
31
|
+
|
32
|
+
public:
|
33
|
+
SpinLock() : _lock(0) {
|
34
|
+
}
|
35
|
+
|
36
|
+
void reset() {
|
37
|
+
_lock = 0;
|
38
|
+
}
|
39
|
+
|
40
|
+
bool tryLock() {
|
41
|
+
return __sync_bool_compare_and_swap(&_lock, 0, 1);
|
42
|
+
}
|
43
|
+
|
44
|
+
void lock() {
|
45
|
+
while (!tryLock()) {
|
46
|
+
spinPause();
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
void unlock() {
|
51
|
+
__sync_fetch_and_sub(&_lock, 1);
|
52
|
+
}
|
53
|
+
|
54
|
+
void lockShared() {
|
55
|
+
int value;
|
56
|
+
while ((value = _lock) == 1 || !__sync_bool_compare_and_swap(&_lock, value, value - 1)) {
|
57
|
+
spinPause();
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
void unlockShared() {
|
62
|
+
__sync_fetch_and_add(&_lock, 1);
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
#endif // _SPINLOCK_H
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2017 Andrei Pangin
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#ifndef _STACKFRAME_H
|
18
|
+
#define _STACKFRAME_H
|
19
|
+
|
20
|
+
#include <stdint.h>
|
21
|
+
#include <ucontext.h>
|
22
|
+
|
23
|
+
|
24
|
+
class StackFrame {
|
25
|
+
private:
|
26
|
+
ucontext_t* _ucontext;
|
27
|
+
|
28
|
+
uintptr_t stackAt(int slot) {
|
29
|
+
return ((uintptr_t*)sp())[slot];
|
30
|
+
}
|
31
|
+
|
32
|
+
public:
|
33
|
+
StackFrame(void* ucontext) {
|
34
|
+
_ucontext = (ucontext_t*)ucontext;
|
35
|
+
}
|
36
|
+
|
37
|
+
void restore(uintptr_t saved_pc, uintptr_t saved_sp, uintptr_t saved_fp) {
|
38
|
+
pc() = saved_pc;
|
39
|
+
sp() = saved_sp;
|
40
|
+
fp() = saved_fp;
|
41
|
+
}
|
42
|
+
|
43
|
+
uintptr_t& pc();
|
44
|
+
uintptr_t& sp();
|
45
|
+
uintptr_t& fp();
|
46
|
+
|
47
|
+
uintptr_t arg0();
|
48
|
+
uintptr_t arg1();
|
49
|
+
uintptr_t arg2();
|
50
|
+
uintptr_t arg3();
|
51
|
+
|
52
|
+
void ret();
|
53
|
+
|
54
|
+
bool pop(bool trust_frame_pointer);
|
55
|
+
};
|
56
|
+
|
57
|
+
#endif // _STACKFRAME_H
|
@@ -0,0 +1,75 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2017 Andrei Pangin
|
3
|
+
* Copyright 2017 BellSoft LLC
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*
|
17
|
+
* Author: Dmitry Samersoff
|
18
|
+
*/
|
19
|
+
|
20
|
+
#if defined(__aarch64__)
|
21
|
+
|
22
|
+
#include "stackFrame.h"
|
23
|
+
|
24
|
+
|
25
|
+
#define REG_FP 29
|
26
|
+
#define REG_LR 30
|
27
|
+
|
28
|
+
uintptr_t& StackFrame::pc() {
|
29
|
+
return (uintptr_t&)_ucontext->uc_mcontext.pc;
|
30
|
+
}
|
31
|
+
|
32
|
+
uintptr_t& StackFrame::sp() {
|
33
|
+
return (uintptr_t&)_ucontext->uc_mcontext.sp;
|
34
|
+
}
|
35
|
+
|
36
|
+
uintptr_t& StackFrame::fp() {
|
37
|
+
return (uintptr_t&)_ucontext->uc_mcontext.regs[REG_FP];
|
38
|
+
}
|
39
|
+
|
40
|
+
uintptr_t StackFrame::arg0() {
|
41
|
+
return (uintptr_t)_ucontext->uc_mcontext.regs[0];
|
42
|
+
}
|
43
|
+
|
44
|
+
uintptr_t StackFrame::arg1() {
|
45
|
+
return (uintptr_t)_ucontext->uc_mcontext.regs[1];
|
46
|
+
}
|
47
|
+
|
48
|
+
uintptr_t StackFrame::arg2() {
|
49
|
+
return (uintptr_t)_ucontext->uc_mcontext.regs[2];
|
50
|
+
}
|
51
|
+
|
52
|
+
uintptr_t StackFrame::arg3() {
|
53
|
+
return (uintptr_t)_ucontext->uc_mcontext.regs[3];
|
54
|
+
}
|
55
|
+
|
56
|
+
void StackFrame::ret() {
|
57
|
+
_ucontext->uc_mcontext.pc = _ucontext->uc_mcontext.regs[REG_LR];
|
58
|
+
}
|
59
|
+
|
60
|
+
bool StackFrame::pop(bool trust_frame_pointer) {
|
61
|
+
if (fp() == sp()) {
|
62
|
+
// Expected frame layout:
|
63
|
+
// sp 000000nnnnnnnnnn [stack]
|
64
|
+
// sp+8 000000nnnnnnnnnn [link]
|
65
|
+
fp() = stackAt(0);
|
66
|
+
pc() = stackAt(1);
|
67
|
+
sp() += 16;
|
68
|
+
} else {
|
69
|
+
// Hope LR holds correct value
|
70
|
+
pc() = _ucontext->uc_mcontext.regs[REG_LR];
|
71
|
+
}
|
72
|
+
return true;
|
73
|
+
}
|
74
|
+
|
75
|
+
#endif // defined(__aarch64__)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2017 Andrei Pangin
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#if defined(__arm__) || defined(__thumb__)
|
18
|
+
|
19
|
+
#include "stackFrame.h"
|
20
|
+
|
21
|
+
|
22
|
+
uintptr_t& StackFrame::pc() {
|
23
|
+
return (uintptr_t&)_ucontext->uc_mcontext.arm_pc;
|
24
|
+
}
|
25
|
+
|
26
|
+
uintptr_t& StackFrame::sp() {
|
27
|
+
return (uintptr_t&)_ucontext->uc_mcontext.arm_sp;
|
28
|
+
}
|
29
|
+
|
30
|
+
uintptr_t& StackFrame::fp() {
|
31
|
+
return (uintptr_t&)_ucontext->uc_mcontext.arm_fp;
|
32
|
+
}
|
33
|
+
|
34
|
+
uintptr_t StackFrame::arg0() {
|
35
|
+
return (uintptr_t)_ucontext->uc_mcontext.arm_r0;
|
36
|
+
}
|
37
|
+
|
38
|
+
uintptr_t StackFrame::arg1() {
|
39
|
+
return (uintptr_t)_ucontext->uc_mcontext.arm_r1;
|
40
|
+
}
|
41
|
+
|
42
|
+
uintptr_t StackFrame::arg2() {
|
43
|
+
return (uintptr_t)_ucontext->uc_mcontext.arm_r2;
|
44
|
+
}
|
45
|
+
|
46
|
+
uintptr_t StackFrame::arg3() {
|
47
|
+
return (uintptr_t)_ucontext->uc_mcontext.arm_r3;
|
48
|
+
}
|
49
|
+
|
50
|
+
void StackFrame::ret() {
|
51
|
+
_ucontext->uc_mcontext.arm_pc = _ucontext->uc_mcontext.arm_lr;
|
52
|
+
}
|
53
|
+
|
54
|
+
bool StackFrame::pop(bool trust_frame_pointer) {
|
55
|
+
return false;
|
56
|
+
}
|
57
|
+
|
58
|
+
#endif // defined(__arm__) || defined(__thumb__)
|