1 /* 2 * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 #include "sun_jvm_hotspot_asm_Disassembler.h" 26 27 #ifdef _WINDOWS 28 29 #define snprintf _snprintf 30 #define vsnprintf _vsnprintf 31 32 #include <windows.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #ifdef _DEBUG 36 #include <crtdbg.h> 37 #endif 38 39 #else 40 41 #include <strings.h> 42 #include <dlfcn.h> 43 #include <link.h> 44 45 #endif 46 47 #include <limits.h> 48 #include <stdio.h> 49 #include <stdarg.h> 50 #include <stdlib.h> 51 #include <errno.h> 52 53 #ifdef _WINDOWS 54 static int getLastErrorString(char *buf, size_t len) 55 { 56 long errval; 57 58 if ((errval = GetLastError()) != 0) 59 { 60 /* DOS error */ 61 size_t n = (size_t)FormatMessage( 62 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 63 NULL, 64 errval, 65 0, 66 buf, 67 (DWORD)len, 68 NULL); 69 if (n > 3) { 70 /* Drop final '.', CR, LF */ 71 if (buf[n - 1] == '\n') n--; 72 if (buf[n - 1] == '\r') n--; 73 if (buf[n - 1] == '.') n--; 74 buf[n] = '\0'; 75 } 76 return (int)n; 77 } 78 79 if (errno != 0) 80 { 81 /* C runtime error that has no corresponding DOS error code */ 82 const char *s = strerror(errno); 83 size_t n = strlen(s); 84 if (n >= len) n = len - 1; 85 strncpy(buf, s, n); 86 buf[n] = '\0'; 87 return (int)n; 88 } 89 return 0; 90 } 91 #endif /* _WINDOWS */ 92 93 /* 94 * Class: sun_jvm_hotspot_asm_Disassembler 95 * Method: load_library 96 * Signature: (Ljava/lang/String;)L 97 */ 98 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIEnv * env, 99 jclass disclass, 100 jstring libname_s) { 101 uintptr_t func = 0; 102 const char* error_message = NULL; 103 jboolean isCopy; 104 const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); 105 char buffer[128]; 106 #ifdef _WINDOWS 107 HINSTANCE hsdis_handle; 108 snprintf(buffer, sizeof(buffer), "%s.dll", libname); 109 hsdis_handle = LoadLibrary(buffer); 110 if (hsdis_handle != NULL) { 111 func = (uintptr_t)GetProcAddress(hsdis_handle, "decode_instructions_virtual"); 112 } 113 if (func == 0) { 114 getLastErrorString(buffer, sizeof(buffer)); 115 error_message = buffer; 116 } 117 #else 118 void* hsdis_handle; 119 snprintf(buffer, sizeof(buffer), "%s.so", libname); 120 hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL); 121 if (hsdis_handle != NULL) { 122 func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual"); 123 } 124 if (func == 0) { 125 error_message = dlerror(); 126 } 127 #endif 128 (*env)->ReleaseStringUTFChars(env, libname_s, libname); 129 if (func == 0) { 130 jclass eclass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); 131 (*env)->ThrowNew(env, eclass, error_message); 132 } 133 return (jlong)func; 134 } 135 136 typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, 137 unsigned char* start, uintptr_t length, 138 void* (*event_callback)(void*, const char*, void*), 139 void* event_stream, 140 int (*printf_callback)(void*, const char*, ...), 141 void* printf_stream, 142 const char* options); 143 144 typedef struct { 145 JNIEnv* env; 146 jobject dis; 147 jobject visitor; 148 jmethodID handle_event; 149 jmethodID raw_print; 150 char buffer[4096]; 151 } decode_env; 152 153 static void* event_to_env(void* env_pv, const char* event, void* arg) { 154 decode_env* denv = (decode_env*)env_pv; 155 JNIEnv* env = denv->env; 156 jstring event_string = (*env)->NewStringUTF(env, event); 157 jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor, 158 event_string, (jlong) (uintptr_t)arg); 159 if ((*env)->ExceptionOccurred(env) != NULL) { 160 /* ignore exceptions for now */ 161 (*env)->ExceptionClear(env); 162 result = 0; 163 } 164 return (void*)(uintptr_t)result; 165 } 166 167 static int printf_to_env(void* env_pv, const char* format, ...) { 168 jstring output; 169 va_list ap; 170 int cnt; 171 decode_env* denv = (decode_env*)env_pv; 172 JNIEnv* env = denv->env; 173 size_t flen = strlen(format); 174 const char* raw = NULL; 175 176 if (flen == 0) return 0; 177 if (flen < 2 || 178 strchr(format, '%') == NULL) { 179 raw = format; 180 } else if (format[0] == '%' && format[1] == '%' && 181 strchr(format+2, '%') == NULL) { 182 // happens a lot on machines with names like %foo 183 flen--; 184 raw = format+1; 185 } 186 if (raw != NULL) { 187 jstring output = (*env)->NewStringUTF(env, raw); 188 (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); 189 if ((*env)->ExceptionOccurred(env) != NULL) { 190 /* ignore exceptions for now */ 191 (*env)->ExceptionClear(env); 192 } 193 return (int) flen; 194 } 195 va_start(ap, format); 196 cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap); 197 va_end(ap); 198 199 output = (*env)->NewStringUTF(env, denv->buffer); 200 (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); 201 if ((*env)->ExceptionOccurred(env) != NULL) { 202 /* ignore exceptions for now */ 203 (*env)->ExceptionClear(env); 204 } 205 return cnt; 206 } 207 208 /* 209 * Class: sun_jvm_hotspot_asm_Disassembler 210 * Method: decode 211 * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V 212 */ 213 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env, 214 jobject dis, 215 jobject visitor, 216 jlong startPc, 217 jbyteArray code, 218 jstring options_s, 219 jlong decode_instructions_virtual) { 220 jboolean isCopy; 221 jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy); 222 jbyte* end = start + (*env)->GetArrayLength(env, code); 223 const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy); 224 jclass disclass = (*env)->GetObjectClass(env, dis); 225 226 decode_env denv; 227 denv.env = env; 228 denv.dis = dis; 229 denv.visitor = visitor; 230 231 denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent", 232 "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J"); 233 if ((*env)->ExceptionOccurred(env)) { 234 return; 235 } 236 237 denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint", 238 "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V"); 239 if ((*env)->ExceptionOccurred(env)) { 240 return; 241 } 242 243 (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc, 244 startPc + end - start, 245 (unsigned char*)start, 246 end - start, 247 &event_to_env, (void*) &denv, 248 &printf_to_env, (void*) &denv, 249 options); 250 251 /* cleanup */ 252 (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); 253 (*env)->ReleaseStringUTFChars(env, options_s, options); 254 }