Path: blob/master/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c
41152 views
/*1* Copyright (c) 2012, 2021, 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* disassembler. It should compile on Linux 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 _WINDOWS35// Disable CRT security warning against _snprintf36#pragma warning (disable : 4996)3738#define snprintf _snprintf39#define vsnprintf _vsnprintf4041#include <windows.h>42#include <sys/types.h>43#include <sys/stat.h>44#ifdef _DEBUG45#include <crtdbg.h>46#endif4748#else4950#include <string.h>51#include <dlfcn.h>5253#ifndef __APPLE__54#include <link.h>55#endif5657#endif5859#include <limits.h>60#include <stdio.h>61#include <stdarg.h>62#include <stdlib.h>63#include <errno.h>6465#ifdef _WINDOWS66#define JVM_MAXPATHLEN _MAX_PATH67#else68#include <sys/param.h>69#define JVM_MAXPATHLEN MAXPATHLEN70#endif7172#include "jni_util.h"737475/*76* Class: sun_jvm_hotspot_asm_Disassembler77* Method: load_library78* Signature: (Ljava/lang/String;)J79*/80JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIEnv * env,81jclass disclass,82jstring libname_s) {83uintptr_t func = 0;84const char *error_message = NULL;85const char *libname = NULL;8687#ifdef _WINDOWS88char buffer[JVM_MAXPATHLEN];89HINSTANCE hsdis_handle = (HINSTANCE) NULL;90#else91void* hsdis_handle = NULL;92#endif9394libname = (*env)->GetStringUTFChars(env, libname_s, NULL);95if (libname == NULL || (*env)->ExceptionOccurred(env)) {96return 0;97}9899/* Load the hsdis library */100#ifdef _WINDOWS101hsdis_handle = LoadLibrary(libname);102if (hsdis_handle != NULL) {103func = (uintptr_t)GetProcAddress(hsdis_handle, "decode_instructions_virtual");104}105if (func == 0) {106getLastErrorString(buffer, sizeof(buffer));107error_message = buffer;108}109#else110hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);111if (hsdis_handle != NULL) {112func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual");113}114if (func == 0) {115error_message = dlerror();116}117#endif118119(*env)->ReleaseStringUTFChars(env, libname_s, libname);120121if (func == 0) {122/* Couldn't find entry point. error_message should contain some123* platform dependent error message.124*/125jstring s = JNU_NewStringPlatform(env, error_message);126if (s != NULL) {127jobject x = JNU_NewObjectByName(env, "sun/jvm/hotspot/debugger/DebuggerException", "(Ljava/lang/String;)V", s);128if (x != NULL) {129(*env)->Throw(env, x);130}131}132}133return (jlong)func;134}135136/* signature of decode_instructions_virtual from hsdis.h */137typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,138unsigned char* start, uintptr_t length,139void* (*event_callback)(void*, const char*, void*),140void* event_stream,141int (*printf_callback)(void*, const char*, ...),142void* printf_stream,143const char* options,144int newline);145146/* container for call back state when decoding instructions */147typedef struct {148JNIEnv* env;149jobject dis;150jobject visitor;151jmethodID handle_event;152jmethodID raw_print;153char buffer[4096];154} decode_env;155156157/* event callback binding to Disassembler.handleEvent */158static void* event_to_env(void* env_pv, const char* event, void* arg) {159jlong result = 0;160decode_env* denv = (decode_env*)env_pv;161JNIEnv* env = denv->env;162jstring event_string = (*env)->NewStringUTF(env, event);163if ((*env)->ExceptionOccurred(env)) {164return NULL;165}166167result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor,168event_string, (jlong) (uintptr_t)arg);169if ((*env)->ExceptionOccurred(env)) {170/* ignore exceptions for now */171(*env)->ExceptionClear(env);172return NULL;173}174175return (void*)(uintptr_t)result;176}177178/* printing callback binding to Disassembler.rawPrint */179static int printf_to_env(void* env_pv, const char* format, ...) {180jstring output;181va_list ap;182int cnt;183decode_env* denv = (decode_env*)env_pv;184JNIEnv* env = denv->env;185size_t flen = strlen(format);186const char* raw = NULL;187188if (flen == 0) return 0;189if (flen < 2 ||190strchr(format, '%') == NULL) {191raw = format;192} else if (format[0] == '%' && format[1] == '%' &&193strchr(format+2, '%') == NULL) {194// happens a lot on machines with names like %foo195flen--;196raw = format+1;197}198if (raw != NULL) {199jstring output = (*env)->NewStringUTF(env, raw);200if (!(*env)->ExceptionOccurred(env)) {201/* make sure that UTF allocation doesn't cause OOM */202(*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);203}204if ((*env)->ExceptionOccurred(env)) {205/* ignore exceptions for now */206(*env)->ExceptionClear(env);207}208return (int) flen;209}210va_start(ap, format);211cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap);212va_end(ap);213214output = (*env)->NewStringUTF(env, denv->buffer);215if (!(*env)->ExceptionOccurred(env)) {216/* make sure that UTF allocation doesn't cause OOM */217(*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);218}219220if ((*env)->ExceptionOccurred(env)) {221/* ignore exceptions for now */222(*env)->ExceptionClear(env);223}224225return cnt;226}227228/*229* Class: sun_jvm_hotspot_asm_Disassembler230* Method: decode231* Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V232*/233JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env,234jobject dis,235jobject visitor,236jlong startPc,237jbyteArray code,238jstring options_s,239jlong decode_instructions_virtual) {240jbyte *start = NULL;241jbyte *end = NULL;242jclass disclass = NULL;243const char *options = NULL;244decode_env denv;245246start = (*env)->GetByteArrayElements(env, code, NULL);247if ((*env)->ExceptionOccurred(env)) {248return;249}250end = start + (*env)->GetArrayLength(env, code);251options = (*env)->GetStringUTFChars(env, options_s, NULL);252if ((*env)->ExceptionOccurred(env)) {253(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);254return;255}256disclass = (*env)->GetObjectClass(env, dis);257258denv.env = env;259denv.dis = dis;260denv.visitor = visitor;261262/* find Disassembler.handleEvent callback */263denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent",264"(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J");265if ((*env)->ExceptionOccurred(env)) {266(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);267(*env)->ReleaseStringUTFChars(env, options_s, options);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)) {275(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);276(*env)->ReleaseStringUTFChars(env, options_s, options);277return;278}279280/* decode the buffer */281(*(decode_func)(uintptr_t)decode_instructions_virtual)((uintptr_t) startPc,282startPc + end - start,283(unsigned char*)start,284end - start,285&event_to_env, (void*) &denv,286&printf_to_env, (void*) &denv,287options, 0 /* newline */);288289/* cleanup */290(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);291(*env)->ReleaseStringUTFChars(env, options_s, options);292}293294295