Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/agent/src/share/native/sadis.c
38806 views
/*1* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "sun_jvm_hotspot_asm_Disassembler.h"2526/*27* This file implements a binding between Java and the hsdis28* dissasembler. It should compile on Linux/Solaris and Windows.29* The only platform dependent pieces of the code for doing30* dlopen/dlsym to find the entry point in hsdis. All the rest is31* standard JNI code.32*/3334#ifdef _WINDOWS3536#define snprintf _snprintf37#define vsnprintf _vsnprintf3839#include <windows.h>40#include <sys/types.h>41#include <sys/stat.h>42#ifdef _DEBUG43#include <crtdbg.h>44#endif4546#else4748#include <string.h>49#include <dlfcn.h>5051#ifndef __APPLE__52#include <link.h>53#endif5455#endif5657#include <limits.h>58#include <stdio.h>59#include <stdarg.h>60#include <stdlib.h>61#include <errno.h>6263#ifdef _WINDOWS64static int getLastErrorString(char *buf, size_t len)65{66long errval;6768if ((errval = GetLastError()) != 0)69{70/* DOS error */71size_t n = (size_t)FormatMessage(72FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,73NULL,74errval,750,76buf,77(DWORD)len,78NULL);79if (n > 3) {80/* Drop final '.', CR, LF */81if (buf[n - 1] == '\n') n--;82if (buf[n - 1] == '\r') n--;83if (buf[n - 1] == '.') n--;84buf[n] = '\0';85}86return (int)n;87}8889if (errno != 0)90{91/* C runtime error that has no corresponding DOS error code */92const char *s = strerror(errno);93size_t n = strlen(s);94if (n >= len) n = len - 1;95strncpy(buf, s, n);96buf[n] = '\0';97return (int)n;98}99return 0;100}101#endif /* _WINDOWS */102103/*104* Class: sun_jvm_hotspot_asm_Disassembler105* Method: load_library106* Signature: (Ljava/lang/String;)L107*/108JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIEnv * env,109jclass disclass,110jstring jrepath_s,111jstring libname_s) {112uintptr_t func = 0;113const char* error_message = NULL;114jboolean isCopy;115116const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/117const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy);118char buffer[128];119120/* Load the hsdis library */121#ifdef _WINDOWS122HINSTANCE hsdis_handle;123hsdis_handle = LoadLibrary(libname);124if (hsdis_handle == NULL) {125snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname);126hsdis_handle = LoadLibrary(buffer);127}128if (hsdis_handle != NULL) {129func = (uintptr_t)GetProcAddress(hsdis_handle, "decode_instructions_virtual");130}131if (func == 0) {132getLastErrorString(buffer, sizeof(buffer));133error_message = buffer;134}135#else136void* hsdis_handle;137hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);138if (hsdis_handle == NULL) {139snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname);140hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL);141}142if (hsdis_handle != NULL) {143func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual");144}145if (func == 0) {146error_message = dlerror();147}148#endif149150(*env)->ReleaseStringUTFChars(env, libname_s, libname);151(*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath);152153if (func == 0) {154/* Couldn't find entry point. error_message should contain some155* platform dependent error message.156*/157jclass eclass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");158(*env)->ThrowNew(env, eclass, error_message);159}160return (jlong)func;161}162163/* signature of decode_instructions_virtual from hsdis.h */164typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,165unsigned char* start, uintptr_t length,166void* (*event_callback)(void*, const char*, void*),167void* event_stream,168int (*printf_callback)(void*, const char*, ...),169void* printf_stream,170const char* options,171int newline);172173/* container for call back state when decoding instructions */174typedef struct {175JNIEnv* env;176jobject dis;177jobject visitor;178jmethodID handle_event;179jmethodID raw_print;180char buffer[4096];181} decode_env;182183184/* event callback binding to Disassembler.handleEvent */185static void* event_to_env(void* env_pv, const char* event, void* arg) {186decode_env* denv = (decode_env*)env_pv;187JNIEnv* env = denv->env;188jstring event_string = (*env)->NewStringUTF(env, event);189jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor,190event_string, (jlong) (uintptr_t)arg);191if ((*env)->ExceptionOccurred(env) != NULL) {192/* ignore exceptions for now */193(*env)->ExceptionClear(env);194result = 0;195}196return (void*)(uintptr_t)result;197}198199/* printing callback binding to Disassembler.rawPrint */200static int printf_to_env(void* env_pv, const char* format, ...) {201jstring output;202va_list ap;203int cnt;204decode_env* denv = (decode_env*)env_pv;205JNIEnv* env = denv->env;206size_t flen = strlen(format);207const char* raw = NULL;208209if (flen == 0) return 0;210if (flen < 2 ||211strchr(format, '%') == NULL) {212raw = format;213} else if (format[0] == '%' && format[1] == '%' &&214strchr(format+2, '%') == NULL) {215// happens a lot on machines with names like %foo216flen--;217raw = format+1;218}219if (raw != NULL) {220jstring output = (*env)->NewStringUTF(env, raw);221(*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);222if ((*env)->ExceptionOccurred(env) != NULL) {223/* ignore exceptions for now */224(*env)->ExceptionClear(env);225}226return (int) flen;227}228va_start(ap, format);229cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap);230va_end(ap);231232output = (*env)->NewStringUTF(env, denv->buffer);233(*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);234if ((*env)->ExceptionOccurred(env) != NULL) {235/* ignore exceptions for now */236(*env)->ExceptionClear(env);237}238return cnt;239}240241/*242* Class: sun_jvm_hotspot_asm_Disassembler243* Method: decode244* Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V245*/246JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env,247jobject dis,248jobject visitor,249jlong startPc,250jbyteArray code,251jstring options_s,252jlong decode_instructions_virtual) {253jboolean isCopy;254jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy);255jbyte* end = start + (*env)->GetArrayLength(env, code);256const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy);257jclass disclass = (*env)->GetObjectClass(env, dis);258259decode_env denv;260denv.env = env;261denv.dis = dis;262denv.visitor = visitor;263264/* find Disassembler.handleEvent callback */265denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent",266"(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J");267if ((*env)->ExceptionOccurred(env)) {268return;269}270271/* find Disassembler.rawPrint callback */272denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint",273"(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V");274if ((*env)->ExceptionOccurred(env)) {275return;276}277278/* decode the buffer */279(*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc,280startPc + end - start,281(unsigned char*)start,282end - start,283&event_to_env, (void*) &denv,284&printf_to_env, (void*) &denv,285options, 0 /* newline */);286287/* cleanup */288(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);289(*env)->ReleaseStringUTFChars(env, options_s, options);290}291292293