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