-
Notifications
You must be signed in to change notification settings - Fork 751
/
Copy pathdump.c
388 lines (333 loc) · 12 KB
/
dump.c
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/*******************************************************************************
* Copyright IBM Corp. and others 1998
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/
#include "jni.h"
#include "j9.h"
#include "util_api.h"
#include "ut_j9jcl.h"
#include "rasdump_api.h"
#define COM_IBM_JVM_DUMP "com.ibm.jvm.Dump."
static void raiseExceptionFor(JNIEnv *env, omr_error_t result);
/*
* Cause a HeapDump to be caused.
*
* Returns the return value of the creation - 0 on success.
*/
jint JNICALL
Java_com_ibm_jvm_Dump_HeapDumpImpl(JNIEnv *env, jclass clazz)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "heap", "com.ibm.jvm.Dump.HeapDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
/*
* Cause a JavaDump to be caused.
*
* Returns the return value of the creation - 0 on success.
*/
jint JNICALL
Java_com_ibm_jvm_Dump_JavaDumpImpl(JNIEnv *env, jclass clazz)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "java", "com.ibm.jvm.Dump.JavaDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
/*
* Cause a SystemDump to be caused.
*
* Returns the return value of the creation - 0 on success.
*/
jint JNICALL
Java_com_ibm_jvm_Dump_SystemDumpImpl(JNIEnv *env, jclass clazz)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "system", "com.ibm.jvm.Dump.SystemDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
/*
* Cause a SnapDump to be caused.
*
* Returns the return value of the creation - 0 on success.
*/
jint JNICALL
Java_com_ibm_jvm_Dump_SnapDumpImpl(JNIEnv *env, jclass clazz) {
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "Snap", "com.ibm.jvm.Dump.SnapDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
/* Scan the dump type string for "tool". Done in C to make sure we
* can use the same logic as the dump code and avoid anyone doing
* anything clever like finding multiple UTF-8 characters that map
* to the ascii letters for "tool".
*/
static jboolean scanDumpTypeForToolDump(char **typeString)
{
/* Check for the string "tool" as a dump type. (Appears before + or :) */
char *endPtr = *typeString + strlen(*typeString);
if( strchr(*typeString, ':') != NULL ) {
endPtr = strchr(*typeString, ':');
}
do {
/* Check for a tool dump option. */
if( try_scan(typeString, "tool") ) {
/* Check for a well-formed dump option */
if ( *typeString[0] == '+' ||
*typeString[0] == ':' ||
*typeString[0] == '\0' ) {
return JNI_TRUE;
}
} else {
/* Any more dump types? */
if( strchr(*typeString, '+') != NULL ) {
*typeString = strchr(*typeString, '+') + 1;
} else {
break; /* No more dump types. */
}
}
} while ( *typeString < endPtr);
return JNI_FALSE;
}
jboolean JNICALL
Java_com_ibm_jvm_Dump_isToolDump(JNIEnv *env, jclass clazz, jstring jopts) {
char *optsBuffer = NULL;
int optsLength = 0;
jboolean retVal = JNI_FALSE;
PORT_ACCESS_FROM_ENV(env);
if( jopts == NULL ) {
return FALSE;
}
optsLength = (*env)->GetStringUTFLength(env, jopts);
optsBuffer = j9mem_allocate_memory(optsLength+1, J9MEM_CATEGORY_VM_JCL);
if( optsBuffer != NULL ) {
char * optsBufferPtr = optsBuffer;
memset(optsBuffer, 0, optsLength+1);
(*env)->GetStringUTFRegion(env, jopts, 0, optsLength, optsBuffer);
retVal = scanDumpTypeForToolDump(&optsBufferPtr);
j9mem_free_memory(optsBuffer);
} else {
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory triggering dump");
}
/* Just return if we can't load the exception class. */
retVal = JNI_FALSE;
}
return retVal;
}
jstring JNICALL
Java_com_ibm_jvm_Dump_triggerDumpsImpl (JNIEnv *env, jclass clazz, jstring jopts, jstring jevent)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
char *optsBuffer = NULL;
char *eventBuffer = NULL;
char fileName[EsMaxPath+1];
int optsLength = 0;
int eventLength = 0;
omr_error_t result = OMR_ERROR_NONE;
jstring toReturn = NULL;
PORT_ACCESS_FROM_ENV(env);
/* Java code will have checked jopts is not null. */
optsLength = (*env)->GetStringUTFLength(env, jopts);
eventLength = (*env)->GetStringUTFLength(env, jevent);
optsBuffer = j9mem_allocate_memory(optsLength+1, J9MEM_CATEGORY_VM_JCL);
eventBuffer = j9mem_allocate_memory(strlen(COM_IBM_JVM_DUMP) + eventLength + 1, J9MEM_CATEGORY_VM_JCL);
/* Copy the file name string, avoid holding locks on things. */
if( optsBuffer != NULL && eventBuffer != NULL) {
memset(optsBuffer, 0, optsLength+1);
memset(eventBuffer, 0, strlen(COM_IBM_JVM_DUMP) + eventLength + 1);
/* Prefix the dump detail with com.ibm.jvm.Dump so createOneOffDumpAgent can
* be sure of the source and prevent tool dumps from being run. (Avoiding
* a back door to Runtime.exec() )
*/
strcpy(eventBuffer, COM_IBM_JVM_DUMP);
memset(fileName, 0, sizeof(fileName));
(*env)->GetStringUTFRegion(env, jopts, 0, optsLength, optsBuffer);
(*env)->GetStringUTFRegion(env, jevent, 0, eventLength, eventBuffer + strlen(eventBuffer));
result = vm->j9rasDumpFunctions->triggerOneOffDump(vm, optsBuffer, eventBuffer, fileName, sizeof(fileName));
if (OMR_ERROR_NONE == result) {
jstring actualFile = NULL;
actualFile = (*env)->NewStringUTF(env, fileName);
toReturn = actualFile;
} else {
raiseExceptionFor(env, result);
}
} else {
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory triggering dump");
}
/* Just return if we can't load the exception class. */
}
if( optsBuffer != NULL ) {
j9mem_free_memory(optsBuffer);
}
if( eventBuffer != NULL ) {
j9mem_free_memory(eventBuffer);
}
return toReturn;
}
jstring JNICALL
Java_openj9_internal_tools_attach_target_DiagnosticUtils_triggerDumpsImpl(JNIEnv *env, jclass clazz, jstring jopts, jstring jevent)
{
return Java_com_ibm_jvm_Dump_triggerDumpsImpl(env, clazz, jopts, jevent);
}
void JNICALL
Java_com_ibm_jvm_Dump_setDumpOptionsImpl (JNIEnv *env, jclass clazz, jstring jopts)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
char *optsBuffer = NULL;
int optsLength = 0;
omr_error_t result = OMR_ERROR_NONE;
PORT_ACCESS_FROM_ENV(env);
/* Java code will have checked jopts is not null. */
optsLength = (*env)->GetStringUTFLength(env, jopts);
optsBuffer = j9mem_allocate_memory(optsLength+1, J9MEM_CATEGORY_VM_JCL);
if( optsBuffer != NULL ) {
memset(optsBuffer, 0, optsLength+1);
(*env)->GetStringUTFRegion(env, jopts, 0, optsLength, optsBuffer);
if (!(*env)->ExceptionCheck(env)) {
/* Pass option to the dump facade */
result = vm->j9rasDumpFunctions->setDumpOption(vm, optsBuffer);
/* Map back to exception */
if (OMR_ERROR_NONE != result) {
raiseExceptionFor(env, result);
}
}
} else {
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory setting dump options");
}
/* Just return if we can't load the exception class as an exception will be pending. */
}
if( optsBuffer != NULL ) {
j9mem_free_memory(optsBuffer);
}
}
jstring JNICALL
Java_com_ibm_jvm_Dump_queryDumpOptionsImpl (JNIEnv *env, jclass clazz) {
#define BUFFER_SIZE 10240
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
jint buffer_size = BUFFER_SIZE;
char options_buffer[BUFFER_SIZE];
char* options_ptr = NULL;
jint data_size;
jint* data_size_ptr = &data_size;
jstring toReturn = NULL;
omr_error_t result = OMR_ERROR_NONE;
PORT_ACCESS_FROM_ENV(env);
memset(options_buffer, 0, buffer_size);
result = vm->j9rasDumpFunctions->queryVmDump(vm, buffer_size, options_buffer, data_size_ptr);
/* Insufficient buffer space, malloc. */
/* Retry in case someone is updating the agents while we run. */
while( data_size > buffer_size) {
buffer_size = data_size;
if( options_ptr != NULL ) {
j9mem_free_memory(options_ptr);
options_ptr = NULL;
}
options_ptr = j9mem_allocate_memory(buffer_size, J9MEM_CATEGORY_VM_JCL);
if( options_ptr != NULL ) {
memset(options_ptr, 0, buffer_size);
result = vm->j9rasDumpFunctions->queryVmDump(vm, buffer_size, options_ptr, data_size_ptr);
} else {
result = OMR_ERROR_OUT_OF_NATIVE_MEMORY;
break; /* malloc failed */
}
}
if (OMR_ERROR_NONE == result) {
if( options_ptr == NULL ) {
toReturn = (*env)->NewStringUTF(env, options_buffer);
} else {
toReturn = (*env)->NewStringUTF(env, options_ptr);
}
} else {
/* Map back to exception */
raiseExceptionFor(env, result);
}
if( options_ptr != NULL ) {
j9mem_free_memory(options_ptr);
}
return toReturn;
}
void JNICALL
Java_com_ibm_jvm_Dump_resetDumpOptionsImpl (JNIEnv *env, jclass clazz)
{
omr_error_t result = OMR_ERROR_NONE;
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
/* request dump reset from dump module */
result = vm->j9rasDumpFunctions->resetDumpOptions(vm);
/* Not much error handling we can do but this can fail if the dump configuration
* is locked while a dump is in progress. */
/* Map back to exception */
if (OMR_ERROR_NONE != result) {
raiseExceptionFor(env, result);
}
}
/**
* Raise exception for OMR error code that is passed in.
*
* Dump.queryDumpOptions() will never return DumpConfigurationUnavailableException according to the published API.
* Java_com_ibm_jvm_Dump_queryDumpOptionsImpl() calls raiseExceptionFor() only when queryVmDump() returns
* OMR_ERROR_OUT_OF_NATIVE_MEMORY, the return case of OMR_ERROR_ILLEGAL_ARGUMENT will never happen for raiseException().
*
* @param[in] env The JNIEnv* of the current thread.
* @param[in] result The OMR error code.
*/
static void
raiseExceptionFor(JNIEnv *env, omr_error_t result)
{
jclass exceptionClass = NULL;
switch (result) {
case OMR_ERROR_INTERNAL:
exceptionClass = (*env)->FindClass(env, "openj9/management/internal/InvalidDumpOptionExceptionBase");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Error in dump options.");
}
/* Just return if we can't load the exception class. */
break;
case OMR_ERROR_OUT_OF_NATIVE_MEMORY:
exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory setting dump option");
}
/* Just return if we can't load the exception class. */
break;
case OMR_ERROR_NOT_AVAILABLE:
exceptionClass = (*env)->FindClass(env, "openj9/management/internal/DumpConfigurationUnavailableExceptionBase");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Dump configuration cannot be changed while a dump is in progress.");
}
/* Just return if we can't load the exception class. */
break;
default:
Assert_JCL_unreachable();
break;
}
}