1 /*
2 * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 #include "jni.h"
24 #include "native_thread.h"
25 #ifdef _WIN32
26 #include <windows.h>
27 #include <process.h>
28 #include <vdmdbg.h>
29 #include <dbghelp.h>
30 #else /* _WIN32 */
31 #include <unistd.h>
32 #include <signal.h>
33 #endif /* _WIN32 */
34 #include "jni_tools.h"
35
36 extern "C" {
37
38 /*
39 * Class: vm_share_ProcessUtils
40 * Method: sendSignal
41 * Signature: ()Z
42 */
Java_vm_share_ProcessUtils_sendSignal(JNIEnv * env,jclass klass,jint signalNum)43 JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_sendSignal
44 (JNIEnv *env, jclass klass, jint signalNum) {
45 #ifdef _WIN32
46 /* TODO TODO TODO
47 int dw;
48 LPVOID lpMsgBuf;
49 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
50 dw = GetLastError();
51 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
52 NULL,
53 dw,
54 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
55 (LPTSTR) &lpMsgBuf,
56 0,
57 NULL
58 );
59 printf("%s\n", (LPTSTR)lpMsgBuf);
60 LocalFree(lpMsgBuf);
61 return JNI_FALSE;
62 }
63 */
64 return JNI_TRUE;
65 #else /* _WIN32 */
66 if (kill(getpid(), signalNum) < 0)
67 return JNI_FALSE;
68 return JNI_TRUE;
69 #endif /* _WIN32 */
70 }
71
72 /*
73 * Class: vm_share_ProcessUtils
74 * Method: sendCtrlBreak
75 * Signature: ()Z
76 */
Java_vm_share_ProcessUtils_sendCtrlBreak(JNIEnv * env,jclass klass)77 JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_sendCtrlBreak
78 (JNIEnv *env, jclass klass) {
79 #ifdef _WIN32
80 int dw;
81 LPVOID lpMsgBuf;
82 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)) {
83 dw = GetLastError();
84 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
85 NULL,
86 dw,
87 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
88 (LPTSTR) &lpMsgBuf,
89 0,
90 NULL
91 );
92 printf("%s\n", (LPTSTR)lpMsgBuf);
93 LocalFree(lpMsgBuf);
94 return JNI_FALSE;
95 }
96 return JNI_TRUE;
97 #else /* _WIN32 */
98 if (kill(getpid(), SIGQUIT) < 0)
99 return JNI_FALSE;
100 return JNI_TRUE;
101 #endif /* _WIN32 */
102 }
103
104 #ifdef _WIN32
105 static BOOL (WINAPI *_MiniDumpWriteDump) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,
106 PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);
reportLastError(const char * msg)107 void reportLastError(const char *msg) {
108 long errcode = GetLastError();
109 if (errcode != 0) {
110 DWORD len = 0;
111 char *buf;
112 size_t n = (size_t)FormatMessage(
113 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,
114 NULL,
115 errcode,
116 0,
117 (LPSTR) &buf,
118 (DWORD)len,
119 NULL);
120 if (n > 3) {
121 /* Drop final '.', CR, LF */
122 if (buf[n - 1] == '\n') n--;
123 if (buf[n - 1] == '\r') n--;
124 if (buf[n - 1] == '.') n--;
125 buf[n] = '\0';
126 }
127 printf("%s: %s\n", msg, buf);
128 LocalFree(buf);
129 }
130 }
131
132 #endif /* _WIN32 */
133
doDumpCore()134 jboolean doDumpCore() {
135 #ifdef _WIN32
136 char path[MAX_PATH];
137 DWORD size;
138 DWORD pathLen = (DWORD) sizeof(path);
139 HINSTANCE dbghelp;
140 MINIDUMP_EXCEPTION_INFORMATION* pmei;
141
142 HANDLE hProcess = GetCurrentProcess();
143 DWORD processId = GetCurrentProcessId();
144 HANDLE dumpFile;
145 MINIDUMP_TYPE dumpType;
146 static const char* cwd;
147 static const char* name = "DBGHELP.DLL";
148
149 printf("# TEST: creating Windows minidump...\n");
150 size = GetSystemDirectory(path, pathLen);
151 if (size > 0) {
152 strcat(path, "\\");
153 strcat(path, name);
154 dbghelp = LoadLibrary(path);
155 if (dbghelp == NULL)
156 reportLastError("Load DBGHELP.DLL from system directory");
157 } else {
158 printf("GetSystemDirectory returned 0\n");
159 }
160
161 // try Windows directory
162 if (dbghelp == NULL) {
163 size = GetWindowsDirectory(path, pathLen);
164 if (size > 6) {
165 strcat(path, "\\");
166 strcat(path, name);
167 dbghelp = LoadLibrary(path);
168 if (dbghelp == NULL) {
169 reportLastError("Load DBGHELP.DLL from Windows directory");
170 }
171 }
172 }
173 if (dbghelp == NULL) {
174 printf("Failed to load DBGHELP.DLL\n");
175 return JNI_FALSE;
176 }
177
178 _MiniDumpWriteDump =
179 (BOOL(WINAPI *)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,
180 PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION))
181 GetProcAddress(dbghelp, "MiniDumpWriteDump");
182
183 if (_MiniDumpWriteDump == NULL) {
184 printf("Failed to find MiniDumpWriteDump() in module dbghelp.dll");
185 return JNI_FALSE;
186 }
187 dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData);
188
189 // Older versions of dbghelp.h doesn't contain all the dumptypes we want, dbghelp.h with
190 // API_VERSION_NUMBER 11 or higher contains the ones we want though
191 #if API_VERSION_NUMBER >= 11
192 dumpType = (MINIDUMP_TYPE)(dumpType | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo |
193 MiniDumpWithUnloadedModules);
194 #endif
195
196 dumpFile = CreateFile("core.mdmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
197
198 if (dumpFile == INVALID_HANDLE_VALUE) {
199 reportLastError("Failed to create file for dumping");
200 return JNI_FALSE;
201 }
202 pmei = NULL;
203
204
205 // Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all
206 // the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then.
207 if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == FALSE &&
208 _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == FALSE) {
209 reportLastError("Call to MiniDumpWriteDump() failed");
210 return JNI_FALSE;
211 }
212
213 CloseHandle(dumpFile);
214 printf("# TEST: minidump created\n");
215 // Emulate Unix behaviour - exit process.
216 ExitProcess(137);
217
218 return JNI_TRUE;
219 #else /* _WIN32 */
220 if (kill(getpid(), SIGSEGV) < 0)
221 return JNI_FALSE;
222 return JNI_TRUE;
223 #endif /* _WIN32 */
224
225 }
226
227 /*
228 * Class: vm_share_ProcessUtils
229 * Method: dumpCore
230 * Signature: ()Z
231 */
Java_vm_share_ProcessUtils_dumpCore(JNIEnv * env,jclass klass)232 JNIEXPORT jboolean JNICALL Java_vm_share_ProcessUtils_dumpCore
233 (JNIEnv *env, jclass klass)
234 {
235 return doDumpCore();
236 }
237
238 /*
239 * Class: vm_share_ProcessUtils
240 * Method: getPid
241 * Signature: ()I
242 */
Java_vm_share_ProcessUtils_getPid(JNIEnv * env,jclass klass)243 JNIEXPORT jint JNICALL Java_vm_share_ProcessUtils_getPid
244 (JNIEnv *env, jclass klass) {
245 #ifdef _WIN32
246 return _getpid();
247 #else /* _WIN32 */
248 return getpid();
249 #endif /* _WIN32 */
250 }
251
252
253 /*
254 * Class: vm_share_ProcessUtils
255 * Method: getPid
256 * Signature: ()I
257 */
Java_vm_share_ProcessUtils_getWindowsPid(JNIEnv * env,jclass klass,jlong handle)258 JNIEXPORT jint JNICALL Java_vm_share_ProcessUtils_getWindowsPid
259 (JNIEnv *env, jclass klass, jlong handle) {
260 #ifdef _WIN32
261 return GetProcessId((HANDLE) handle);
262 #else /* _WIN32 */
263 return -1;
264 #endif /* _WIN32 */
265 }
266
267 }
268