Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/j9vm/asgct.cpp
5985 views
1
/*******************************************************************************
2
* Copyright (c) 2021, 2022 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "j9.h"
24
#include "j9protos.h"
25
#include "ut_j9scar.h"
26
#include "rommeth.h"
27
#include "vmhook.h"
28
29
#if defined(LINUX) && defined(J9VM_ARCH_X86) && defined(J9VM_ENV_DATA64)
30
#include <ucontext.h>
31
#define ASGCT_SUPPORTED
32
#endif /* defined(LINUX) && defined(J9VM_ARCH_X86) && defined(J9VM_ENV_DATA64) */
33
34
extern "C" {
35
36
#define AGCT_LINE_NUMBER_NATIVE_METHOD -3
37
38
enum {
39
ticks_no_Java_frame = 0, // new thread
40
ticks_no_class_load = -1, // jmethodIds are not available
41
ticks_GC_active = -2, // GC action
42
ticks_unknown_not_Java = -3, // ¯\_(ツ)_/¯
43
ticks_not_walkable_not_Java = -4, // ¯\_(ツ)_/¯
44
ticks_unknown_Java = -5, // ¯\_(ツ)_/¯
45
ticks_not_walkable_Java = -6, // ¯\_(ツ)_/¯
46
ticks_unknown_state = -7, // ¯\_(ツ)_/¯
47
ticks_thread_exit = -8, // dying thread
48
ticks_deopt = -9, // mid-deopting code
49
ticks_safepoint = -10 // ¯\_(ツ)_/¯
50
};
51
52
typedef struct {
53
jint lineno;
54
jmethodID method_id;
55
} ASGCT_CallFrame;
56
57
typedef struct {
58
JNIEnv *env_id;
59
jint num_frames;
60
ASGCT_CallFrame *frames;
61
} ASGCT_CallTrace;
62
63
#if defined(ASGCT_SUPPORTED)
64
65
extern J9JavaVM *BFUjavaVM;
66
67
#define TRIGGER_SEGV() *(UDATA*)UDATA_MAX = UDATA_MAX
68
69
static UDATA
70
asyncFrameIterator(J9VMThread * currentThread, J9StackWalkState * walkState)
71
{
72
ASGCT_CallFrame *frame = (ASGCT_CallFrame*)walkState->userData1;
73
J9Method *method = walkState->method;
74
J9JavaVM * vm = currentThread->javaVM;
75
J9Class * declaringClass = J9_CLASS_FROM_METHOD(method);
76
UDATA methodIndex = getMethodIndexUnchecked(method);
77
/* If any of the following are true, trigger a SEGV which will
78
* be caught in the caller.
79
*
80
* - method index is invalid (i.e. method was invalid)
81
* - method IDs for the class not pre-initialized
82
* - method ID for the method not pre-initialized
83
*
84
* Only completely valid stack walks will result in any samples
85
* being returned. This is better than simply ignoring bad methods
86
* and continuing, which would result in inaccurate traces.
87
*/
88
if (UDATA_MAX == methodIndex) {
89
TRIGGER_SEGV();
90
}
91
void ** jniIDs = declaringClass->jniIDs;
92
if (NULL == jniIDs) {
93
TRIGGER_SEGV();
94
}
95
J9JNIMethodID * methodID = (J9JNIMethodID*)(jniIDs[methodIndex]);
96
if (NULL == methodID) {
97
TRIGGER_SEGV();
98
}
99
frame->method_id = (jmethodID)methodID;
100
J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(method);
101
if (J9_ARE_ANY_BITS_SET(romMethod->modifiers, J9AccNative)) {
102
frame->lineno = AGCT_LINE_NUMBER_NATIVE_METHOD;
103
} else {
104
frame->lineno = (jint)walkState->bytecodePCOffset;
105
}
106
walkState->userData1 = (void*)(frame + 1);
107
return J9_STACKWALK_KEEP_ITERATING;
108
}
109
110
static UDATA
111
emptySignalHandler(J9PortLibrary *portLibrary, U_32 gpType, void *gpInfo, void *handler_arg)
112
{
113
return J9PORT_SIG_EXCEPTION_RETURN;
114
}
115
116
typedef struct {
117
ASGCT_CallTrace *trace;
118
jint depth;
119
void *ucontext;
120
J9VMThread *currentThread;
121
jint num_frames;
122
U_8 *pc;
123
UDATA *sp;
124
UDATA *arg0EA;
125
J9Method *literals;
126
void *jitArtifactSearchCache;
127
UDATA privateFlags2;
128
} ASGCT_parms;
129
130
static UDATA
131
protectedASGCT(J9PortLibrary *portLib, void *arg)
132
{
133
ASGCT_parms *parms = (ASGCT_parms*)arg;
134
J9VMThread *targetThread = (J9VMThread*)parms->trace->env_id;
135
Assert_SC_true(NULL != targetThread);
136
J9VMThread *currentThread = BFUjavaVM->internalVMFunctions->currentVMThread(BFUjavaVM);
137
/* ASGCT is only callable with the JNIEnv of the current thread */
138
Assert_SC_true(targetThread == currentThread);
139
J9SFJITResolveFrame resolveFrame = {0};
140
parms->currentThread = currentThread;
141
/* Back up the J9VMThread root values for restoration in the caller */
142
parms->pc = currentThread->pc;
143
parms->sp = currentThread->sp;
144
parms->arg0EA = currentThread->arg0EA;
145
parms->literals = currentThread->literals;
146
parms->num_frames = ticks_not_walkable_Java;
147
parms->jitArtifactSearchCache = currentThread->jitArtifactSearchCache;
148
parms->privateFlags2 = currentThread->privateFlags2;
149
/* Disable the JIT metadata cache. The cache may be in an inconsistent state, and may
150
* need to allocate memory (which is undesireable in a signal handler).
151
*/
152
currentThread->jitArtifactSearchCache = (void*)((UDATA)currentThread->jitArtifactSearchCache | J9_STACKWALK_NO_JIT_CACHE);
153
/* Disable trace and assertions. The current thread may be in the process of updating the trace
154
* buffers when it was interrupted. Assertions during ASGCT are also undesireable, better to let
155
* the thread continue on to crash, which is handled.
156
*/
157
currentThread->privateFlags2 |= J9_PRIVATE_FLAGS2_ASYNC_GET_CALL_TRACE;
158
J9JITConfig *jitConfig = BFUjavaVM->jitConfig;
159
if (NULL != jitConfig) {
160
void *ucontext = parms->ucontext;
161
if (NULL != ucontext) {
162
greg_t *regs = ((ucontext_t*)ucontext)->uc_mcontext.gregs;
163
greg_t rip = regs[REG_RIP];
164
J9JITExceptionTable *metaData = jitConfig->jitGetExceptionTableFromPC(currentThread, rip);
165
if (NULL != metaData) {
166
greg_t rsp = regs[REG_RSP];
167
/* Build a JIT resolve frame on the C stack to avoid writing to the java
168
* stack in the signal handler. Update the J9VMThread roots to point to
169
* the resolve frame (will be restored in the caller).
170
*/
171
resolveFrame.savedJITException = NULL;
172
resolveFrame.specialFrameFlags = J9_SSF_JIT_RESOLVE;
173
resolveFrame.parmCount = 0;
174
resolveFrame.returnAddress = (U_8*)rip;
175
resolveFrame.taggedRegularReturnSP = (UDATA*)(((U_8 *)rsp) + J9SF_A0_INVISIBLE_TAG);
176
currentThread->pc = (U_8*)J9SF_FRAME_TYPE_JIT_RESOLVE;
177
currentThread->arg0EA = (UDATA*)&(resolveFrame.taggedRegularReturnSP);
178
currentThread->literals = NULL;
179
currentThread->sp = (UDATA*)&resolveFrame;
180
}
181
}
182
}
183
J9StackWalkState walkState = {0};
184
walkState.walkThread = currentThread;
185
walkState.skipCount = 0;
186
walkState.maxFrames = parms->depth;
187
walkState.flags = J9_STACKWALK_INCLUDE_NATIVES | J9_STACKWALK_VISIBLE_ONLY
188
| J9_STACKWALK_RECORD_BYTECODE_PC_OFFSET | J9_STACKWALK_COUNT_SPECIFIED
189
| J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_NO_ERROR_REPORT;
190
walkState.userData1 = (void*)parms->trace->frames;
191
walkState.frameWalkFunction = asyncFrameIterator;
192
UDATA result = BFUjavaVM->walkStackFrames(currentThread, &walkState);
193
if (J9_STACKWALK_RC_NONE == result) {
194
parms->num_frames = (jint)walkState.framesWalked;
195
}
196
return 0;
197
}
198
199
#endif /* ASGCT_SUPPORTED */
200
201
void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void *ucontext)
202
{
203
J9VMThread *currentThread = NULL;
204
jint num_frames = ticks_unknown_not_Java;
205
#if defined(ASGCT_SUPPORTED)
206
if (NULL != BFUjavaVM) {
207
/* ASGCT requires that the JVMTI ClassLoad event be hooked (in order to pre-create the method IDs) */
208
Assert_SC_true(J9_EVENT_IS_HOOKED(BFUjavaVM->hookInterface, J9HOOK_VM_CLASS_LOAD));
209
/* ASGCT is not supported when running with -Xrs because the stack may be in an inconsistent state
210
* which will result in a crash during the stack walk.
211
*/
212
Assert_SC_true(J9_ARE_NO_BITS_SET(BFUjavaVM->sigFlags, J9_SIG_XRS_SYNC));
213
PORT_ACCESS_FROM_JAVAVM(BFUjavaVM);
214
ASGCT_parms parms = { trace, depth, ucontext, currentThread, num_frames, NULL, NULL, NULL, NULL, NULL, 0 };
215
UDATA result = 0;
216
j9sig_protect(
217
protectedASGCT, (void*)&parms,
218
emptySignalHandler, NULL,
219
J9PORT_SIG_FLAG_SIGALLSYNC | J9PORT_SIG_FLAG_MAY_RETURN,
220
&result);
221
num_frames = parms.num_frames;
222
currentThread = parms.currentThread;
223
if (NULL != currentThread) {
224
/* Restore any modified J9VMThread fields */
225
currentThread->jitArtifactSearchCache = parms.jitArtifactSearchCache;
226
currentThread->privateFlags2 = parms.privateFlags2;
227
currentThread->pc = parms.pc;
228
currentThread->sp = parms.sp;
229
currentThread->arg0EA = parms.arg0EA;
230
currentThread->literals = parms.literals;
231
}
232
}
233
#endif /* ASGCT_SUPPORTED */
234
trace->num_frames = num_frames;
235
}
236
237
} /* extern "C" */
238
239