/* * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ #include "sun_jvm_hotspot_asm_Disassembler.h" #ifdef _WINDOWS #define snprintf _snprintf #define vsnprintf _vsnprintf #include #include #include #ifdef _DEBUG #include #endif #else #include #include #include #endif #include #include #include #include #include #ifdef _WINDOWS static int getLastErrorString(char *buf, size_t len) { long errval; if ((errval = GetLastError()) != 0) { /* DOS error */ size_t n = (size_t)FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errval, 0, buf, (DWORD)len, NULL); if (n > 3) { /* Drop final '.', CR, LF */ if (buf[n - 1] == '\n') n--; if (buf[n - 1] == '\r') n--; if (buf[n - 1] == '.') n--; buf[n] = '\0'; } return (int)n; } if (errno != 0) { /* C runtime error that has no corresponding DOS error code */ const char *s = strerror(errno); size_t n = strlen(s); if (n >= len) n = len - 1; strncpy(buf, s, n); buf[n] = '\0'; return (int)n; } return 0; } #endif /* _WINDOWS */ /* * Class: sun_jvm_hotspot_asm_Disassembler * Method: load_library * Signature: (Ljava/lang/String;)L */ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIEnv * env, jclass disclass, jstring libname_s) { uintptr_t func = 0; const char* error_message = NULL; jboolean isCopy; const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); char buffer[128]; #ifdef _WINDOWS HINSTANCE hsdis_handle; snprintf(buffer, sizeof(buffer), "%s.dll", libname); hsdis_handle = LoadLibrary(buffer); if (hsdis_handle != NULL) { func = (uintptr_t)GetProcAddress(hsdis_handle, "decode_instructions_virtual"); } if (func == 0) { getLastErrorString(buffer, sizeof(buffer)); error_message = buffer; } #else void* hsdis_handle; snprintf(buffer, sizeof(buffer), "%s.so", libname); hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL); if (hsdis_handle != NULL) { func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual"); } if (func == 0) { error_message = dlerror(); } #endif (*env)->ReleaseStringUTFChars(env, libname_s, libname); if (func == 0) { jclass eclass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); (*env)->ThrowNew(env, eclass, error_message); } return (jlong)func; } typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, unsigned char* start, uintptr_t length, void* (*event_callback)(void*, const char*, void*), void* event_stream, int (*printf_callback)(void*, const char*, ...), void* printf_stream, const char* options); typedef struct { JNIEnv* env; jobject dis; jobject visitor; jmethodID handle_event; jmethodID raw_print; char buffer[4096]; } decode_env; static void* event_to_env(void* env_pv, const char* event, void* arg) { decode_env* denv = (decode_env*)env_pv; JNIEnv* env = denv->env; jstring event_string = (*env)->NewStringUTF(env, event); jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor, event_string, (jlong) (uintptr_t)arg); if ((*env)->ExceptionOccurred(env) != NULL) { /* ignore exceptions for now */ (*env)->ExceptionClear(env); result = 0; } return (void*)(uintptr_t)result; } static int printf_to_env(void* env_pv, const char* format, ...) { jstring output; va_list ap; int cnt; decode_env* denv = (decode_env*)env_pv; JNIEnv* env = denv->env; size_t flen = strlen(format); const char* raw = NULL; if (flen == 0) return 0; if (flen < 2 || strchr(format, '%') == NULL) { raw = format; } else if (format[0] == '%' && format[1] == '%' && strchr(format+2, '%') == NULL) { // happens a lot on machines with names like %foo flen--; raw = format+1; } if (raw != NULL) { jstring output = (*env)->NewStringUTF(env, raw); (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); if ((*env)->ExceptionOccurred(env) != NULL) { /* ignore exceptions for now */ (*env)->ExceptionClear(env); } return (int) flen; } va_start(ap, format); cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap); va_end(ap); output = (*env)->NewStringUTF(env, denv->buffer); (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); if ((*env)->ExceptionOccurred(env) != NULL) { /* ignore exceptions for now */ (*env)->ExceptionClear(env); } return cnt; } /* * Class: sun_jvm_hotspot_asm_Disassembler * Method: decode * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V */ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env, jobject dis, jobject visitor, jlong startPc, jbyteArray code, jstring options_s, jlong decode_instructions_virtual) { jboolean isCopy; jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy); jbyte* end = start + (*env)->GetArrayLength(env, code); const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy); jclass disclass = (*env)->GetObjectClass(env, dis); decode_env denv; denv.env = env; denv.dis = dis; denv.visitor = visitor; denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent", "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J"); if ((*env)->ExceptionOccurred(env)) { return; } denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint", "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V"); if ((*env)->ExceptionOccurred(env)) { return; } (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc, startPc + end - start, (unsigned char*)start, end - start, &event_to_env, (void*) &denv, &printf_to_env, (void*) &denv, options); /* cleanup */ (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); (*env)->ReleaseStringUTFChars(env, options_s, options); }