--- /dev/null Thu Sep 17 16:09:22 2009 +++ new/agent/src/share/native/sadis.c Thu Sep 17 16:09:22 2009 @@ -0,0 +1,254 @@ +/* + * 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); +}