1 /*
2  * Copyright (c) 1997, 2013, 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  */
24 
25 #include "precompiled.hpp"
26 #include "prims/jvm.h"
27 #include "runtime/arguments.hpp"
28 #include "decoder_windows.hpp"
29 
WindowsDecoder()30 WindowsDecoder::WindowsDecoder() {
31   _dbghelp_handle = NULL;
32   _can_decode_in_vm = false;
33   _pfnSymGetSymFromAddr64 = NULL;
34   _pfnUndecorateSymbolName = NULL;
35 #ifdef AMD64
36   _pfnStackWalk64 = NULL;
37   _pfnSymFunctionTableAccess64 = NULL;
38   _pfnSymGetModuleBase64 = NULL;
39 #endif
40   _decoder_status = no_error;
41   initialize();
42 }
43 
initialize()44 void WindowsDecoder::initialize() {
45   if (!has_error() && _dbghelp_handle == NULL) {
46     HMODULE handle = ::LoadLibrary("dbghelp.dll");
47     if (!handle) {
48       _decoder_status = helper_not_found;
49       return;
50     }
51 
52     _dbghelp_handle = handle;
53 
54     pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions");
55     pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize");
56     _pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64");
57     _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName");
58 
59     if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
60       uninitialize();
61       _decoder_status = helper_func_error;
62       return;
63     }
64 
65 #ifdef AMD64
66     _pfnStackWalk64 = (pfn_StackWalk64)::GetProcAddress(handle, "StackWalk64");
67     _pfnSymFunctionTableAccess64 = (pfn_SymFunctionTableAccess64)::GetProcAddress(handle, "SymFunctionTableAccess64");
68     _pfnSymGetModuleBase64 = (pfn_SymGetModuleBase64)::GetProcAddress(handle, "SymGetModuleBase64");
69     if (_pfnStackWalk64 == NULL || _pfnSymFunctionTableAccess64 == NULL || _pfnSymGetModuleBase64 == NULL) {
70       // We can't call StackWalk64 to walk the stack, but we are still
71       // able to decode the symbols. Let's limp on.
72       _pfnStackWalk64 = NULL;
73       _pfnSymFunctionTableAccess64 = NULL;
74       _pfnSymGetModuleBase64 = NULL;
75     }
76 #endif
77 
78     HANDLE hProcess = ::GetCurrentProcess();
79     _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
80     if (!_pfnSymInitialize(hProcess, NULL, TRUE)) {
81       _pfnSymGetSymFromAddr64 = NULL;
82       _pfnUndecorateSymbolName = NULL;
83       ::FreeLibrary(handle);
84       _dbghelp_handle = NULL;
85       _decoder_status = helper_init_error;
86       return;
87     }
88 
89     // set pdb search paths
90     pfn_SymSetSearchPath  _pfn_SymSetSearchPath =
91       (pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath");
92     pfn_SymGetSearchPath  _pfn_SymGetSearchPath =
93       (pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath");
94     if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) {
95       char paths[MAX_PATH];
96       int  len = sizeof(paths);
97       if (!_pfn_SymGetSearchPath(hProcess, paths, len)) {
98         paths[0] = '\0';
99       } else {
100         // available spaces in path buffer
101         len -= (int)strlen(paths);
102       }
103 
104       char tmp_path[MAX_PATH];
105       DWORD dwSize;
106       HMODULE hJVM = ::GetModuleHandle("jvm.dll");
107       tmp_path[0] = '\0';
108       // append the path where jvm.dll is located
109       if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
110         while (dwSize > 0 && tmp_path[dwSize] != '\\') {
111           dwSize --;
112         }
113 
114         tmp_path[dwSize] = '\0';
115 
116         if (dwSize > 0 && len > (int)dwSize + 1) {
117           strncat(paths, os::path_separator(), 1);
118           strncat(paths, tmp_path, dwSize);
119           len -= dwSize + 1;
120         }
121       }
122 
123       // append $JRE/bin. Arguments::get_java_home actually returns $JRE
124       // path
125       char *p = Arguments::get_java_home();
126       assert(p != NULL, "empty java home");
127       size_t java_home_len = strlen(p);
128       if (len > (int)java_home_len + 5) {
129         strncat(paths, os::path_separator(), 1);
130         strncat(paths, p, java_home_len);
131         strncat(paths, "\\bin", 4);
132         len -= (int)(java_home_len + 5);
133       }
134 
135       // append $JDK/bin path if it exists
136       assert(java_home_len < MAX_PATH, "Invalid path length");
137       // assume $JRE is under $JDK, construct $JDK/bin path and
138       // see if it exists or not
139       if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
140         strncpy(tmp_path, p, java_home_len - 3);
141         tmp_path[java_home_len - 3] = '\0';
142         strncat(tmp_path, "bin", 3);
143 
144         // if the directory exists
145         DWORD dwAttrib = GetFileAttributes(tmp_path);
146         if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
147             (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
148           // tmp_path should have the same length as java_home_len, since we only
149           // replaced 'jre' with 'bin'
150           if (len > (int)java_home_len + 1) {
151             strncat(paths, os::path_separator(), 1);
152             strncat(paths, tmp_path, java_home_len);
153           }
154         }
155       }
156 
157       _pfn_SymSetSearchPath(hProcess, paths);
158     }
159 
160      // find out if jvm.dll contains private symbols, by decoding
161      // current function and comparing the result
162      address addr = (address)Decoder::demangle;
163      char buf[MAX_PATH];
164      if (decode(addr, buf, sizeof(buf), NULL)) {
165        _can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
166      }
167   }
168 }
169 
uninitialize()170 void WindowsDecoder::uninitialize() {
171   _pfnSymGetSymFromAddr64 = NULL;
172   _pfnUndecorateSymbolName = NULL;
173 #ifdef AMD64
174   _pfnStackWalk64 = NULL;
175   _pfnSymFunctionTableAccess64 = NULL;
176   _pfnSymGetModuleBase64 = NULL;
177 #endif
178   if (_dbghelp_handle != NULL) {
179     ::FreeLibrary(_dbghelp_handle);
180   }
181   _dbghelp_handle = NULL;
182 }
183 
can_decode_C_frame_in_vm() const184 bool WindowsDecoder::can_decode_C_frame_in_vm() const {
185   return  (!has_error() && _can_decode_in_vm);
186 }
187 
188 
decode(address addr,char * buf,int buflen,int * offset,const char * modulepath)189 bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath)  {
190   if (_pfnSymGetSymFromAddr64 != NULL) {
191     PIMAGEHLP_SYMBOL64 pSymbol;
192     char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
193     pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
194     pSymbol->MaxNameLength = MAX_PATH;
195     pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
196     DWORD64 displacement;
197     if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
198       if (buf != NULL) {
199         if (demangle(pSymbol->Name, buf, buflen)) {
200           jio_snprintf(buf, buflen, "%s", pSymbol->Name);
201         }
202       }
203       if(offset != NULL) *offset = (int)displacement;
204       return true;
205     }
206   }
207   if (buf != NULL && buflen > 0) buf[0] = '\0';
208   if (offset != NULL) *offset = -1;
209   return false;
210 }
211 
demangle(const char * symbol,char * buf,int buflen)212 bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
213   return _pfnUndecorateSymbolName != NULL &&
214          _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE);
215 }
216 
217 #ifdef AMD64
StackWalk64(DWORD MachineType,HANDLE hProcess,HANDLE hThread,LPSTACKFRAME64 StackFrame,PVOID ContextRecord,PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress)218 BOOL WindowsDbgHelp::StackWalk64(DWORD MachineType,
219                                  HANDLE hProcess,
220                                  HANDLE hThread,
221                                  LPSTACKFRAME64 StackFrame,
222                                  PVOID ContextRecord,
223                                  PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
224                                  PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
225                                  PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
226                                  PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) {
227   DecoderLocker locker;
228   WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
229 
230   if (!wd->has_error() && wd->_pfnStackWalk64) {
231     return wd->_pfnStackWalk64(MachineType,
232                                hProcess,
233                                hThread,
234                                StackFrame,
235                                ContextRecord,
236                                ReadMemoryRoutine,
237                                FunctionTableAccessRoutine,
238                                GetModuleBaseRoutine,
239                                TranslateAddress);
240   } else {
241     return false;
242   }
243 }
244 
SymFunctionTableAccess64(HANDLE hProcess,DWORD64 AddrBase)245 PVOID WindowsDbgHelp::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
246   DecoderLocker locker;
247   WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
248 
249   if (!wd->has_error() && wd->_pfnSymFunctionTableAccess64) {
250     return wd->_pfnSymFunctionTableAccess64(hProcess, AddrBase);
251   } else {
252     return NULL;
253   }
254 }
255 
pfnSymFunctionTableAccess64()256 pfn_SymFunctionTableAccess64 WindowsDbgHelp::pfnSymFunctionTableAccess64() {
257   DecoderLocker locker;
258   WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
259 
260   if (!wd->has_error()) {
261     return wd->_pfnSymFunctionTableAccess64;
262   } else {
263     return NULL;
264   }
265 }
266 
pfnSymGetModuleBase64()267 pfn_SymGetModuleBase64 WindowsDbgHelp::pfnSymGetModuleBase64() {
268   DecoderLocker locker;
269   WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
270 
271   if (!wd->has_error()) {
272     return wd->_pfnSymGetModuleBase64;
273   } else {
274     return NULL;
275   }
276 }
277 
278 #endif // AMD64
279