src/jdk.hotspot.agent/share/native/libsaproc/sadis.c
changeset 47216 71c04702a3d5
parent 35217 ce4b5303a813
child 49382 3875d7b926a8
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "sun_jvm_hotspot_asm_Disassembler.h"
       
    26 
       
    27 /*
       
    28  *  This file implements a binding between Java and the hsdis
       
    29  *  dissasembler.  It should compile on Linux/Solaris and Windows.
       
    30  *  The only platform dependent pieces of the code for doing
       
    31  *  dlopen/dlsym to find the entry point in hsdis.  All the rest is
       
    32  *  standard JNI code.
       
    33  */
       
    34 
       
    35 #ifdef _WINDOWS
       
    36 // Disable CRT security warning against _snprintf
       
    37 #pragma warning (disable : 4996)
       
    38 
       
    39 #define snprintf  _snprintf
       
    40 #define vsnprintf _vsnprintf
       
    41 
       
    42 #include <windows.h>
       
    43 #include <sys/types.h>
       
    44 #include <sys/stat.h>
       
    45 #ifdef _DEBUG
       
    46 #include <crtdbg.h>
       
    47 #endif
       
    48 
       
    49 #else
       
    50 
       
    51 #include <string.h>
       
    52 #include <dlfcn.h>
       
    53 
       
    54 #ifndef __APPLE__
       
    55 #include <link.h>
       
    56 #endif
       
    57 
       
    58 #endif
       
    59 
       
    60 #include <limits.h>
       
    61 #include <stdio.h>
       
    62 #include <stdarg.h>
       
    63 #include <stdlib.h>
       
    64 #include <errno.h>
       
    65 
       
    66 #ifdef _WINDOWS
       
    67 static int getLastErrorString(char *buf, size_t len)
       
    68 {
       
    69     long errval;
       
    70 
       
    71     if ((errval = GetLastError()) != 0)
       
    72     {
       
    73       /* DOS error */
       
    74       size_t n = (size_t)FormatMessage(
       
    75             FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
       
    76             NULL,
       
    77             errval,
       
    78             0,
       
    79             buf,
       
    80             (DWORD)len,
       
    81             NULL);
       
    82       if (n > 3) {
       
    83         /* Drop final '.', CR, LF */
       
    84         if (buf[n - 1] == '\n') n--;
       
    85         if (buf[n - 1] == '\r') n--;
       
    86         if (buf[n - 1] == '.') n--;
       
    87         buf[n] = '\0';
       
    88       }
       
    89       return (int)n;
       
    90     }
       
    91 
       
    92     if (errno != 0)
       
    93     {
       
    94       /* C runtime error that has no corresponding DOS error code */
       
    95       strerror_s(buf, len, errno);
       
    96       return strlen(buf);
       
    97     }
       
    98     return 0;
       
    99 }
       
   100 #endif /* _WINDOWS */
       
   101 
       
   102 /*
       
   103  * Class:     sun_jvm_hotspot_asm_Disassembler
       
   104  * Method:    load_library
       
   105  * Signature: (Ljava/lang/String;)L
       
   106  */
       
   107 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIEnv * env,
       
   108                                                                            jclass disclass,
       
   109                                                                            jstring jrepath_s,
       
   110                                                                            jstring libname_s) {
       
   111   uintptr_t func = 0;
       
   112   const char *error_message = NULL;
       
   113   const char *jrepath = NULL;
       
   114   const char *libname = NULL;
       
   115   char buffer[128];
       
   116 
       
   117 #ifdef _WINDOWS
       
   118   HINSTANCE hsdis_handle = (HINSTANCE) NULL;
       
   119 #else
       
   120   void* hsdis_handle = NULL;
       
   121 #endif
       
   122 
       
   123   jrepath = (*env)->GetStringUTFChars(env, jrepath_s, NULL); // like $JAVA_HOME/jre/lib/sparc/
       
   124   if (jrepath == NULL || (*env)->ExceptionOccurred(env)) {
       
   125     return 0;
       
   126   }
       
   127 
       
   128   libname = (*env)->GetStringUTFChars(env, libname_s, NULL);
       
   129   if (libname == NULL || (*env)->ExceptionOccurred(env)) {
       
   130     (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath);
       
   131     return 0;
       
   132   }
       
   133 
       
   134   /* Load the hsdis library */
       
   135 #ifdef _WINDOWS
       
   136   hsdis_handle = LoadLibrary(libname);
       
   137   if (hsdis_handle == NULL) {
       
   138     snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname);
       
   139     hsdis_handle = LoadLibrary(buffer);
       
   140   }
       
   141   if (hsdis_handle != NULL) {
       
   142     func = (uintptr_t)GetProcAddress(hsdis_handle, "decode_instructions_virtual");
       
   143   }
       
   144   if (func == 0) {
       
   145     getLastErrorString(buffer, sizeof(buffer));
       
   146     error_message = buffer;
       
   147   }
       
   148 #else
       
   149   hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
       
   150   if (hsdis_handle == NULL) {
       
   151     snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname);
       
   152     hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL);
       
   153   }
       
   154   if (hsdis_handle != NULL) {
       
   155     func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual");
       
   156   }
       
   157   if (func == 0) {
       
   158     error_message = dlerror();
       
   159   }
       
   160 #endif
       
   161 
       
   162   (*env)->ReleaseStringUTFChars(env, libname_s, libname);
       
   163   (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath);
       
   164 
       
   165   if (func == 0) {
       
   166     /* Couldn't find entry point.  error_message should contain some
       
   167      * platform dependent error message.
       
   168      */
       
   169     jclass eclass = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");
       
   170     if ((*env)->ExceptionOccurred(env)) {
       
   171       /* Can't throw exception, probably OOM, so silently return 0 */
       
   172       return (jlong) 0;
       
   173     }
       
   174 
       
   175     (*env)->ThrowNew(env, eclass, error_message);
       
   176   }
       
   177   return (jlong)func;
       
   178 }
       
   179 
       
   180 /* signature of decode_instructions_virtual from hsdis.h */
       
   181 typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,
       
   182                              unsigned char* start, uintptr_t length,
       
   183                              void* (*event_callback)(void*, const char*, void*),
       
   184                              void* event_stream,
       
   185                              int (*printf_callback)(void*, const char*, ...),
       
   186                              void* printf_stream,
       
   187                              const char* options,
       
   188                              int newline);
       
   189 
       
   190 /* container for call back state when decoding instructions */
       
   191 typedef struct {
       
   192   JNIEnv* env;
       
   193   jobject dis;
       
   194   jobject visitor;
       
   195   jmethodID handle_event;
       
   196   jmethodID raw_print;
       
   197   char buffer[4096];
       
   198 } decode_env;
       
   199 
       
   200 
       
   201 /* event callback binding to Disassembler.handleEvent */
       
   202 static void* event_to_env(void* env_pv, const char* event, void* arg) {
       
   203   jlong result = 0;
       
   204   decode_env* denv = (decode_env*)env_pv;
       
   205   JNIEnv* env = denv->env;
       
   206   jstring event_string = (*env)->NewStringUTF(env, event);
       
   207   if ((*env)->ExceptionOccurred(env)) {
       
   208     return NULL;
       
   209   }
       
   210 
       
   211   result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor,
       
   212                                   event_string, (jlong) (uintptr_t)arg);
       
   213   if ((*env)->ExceptionOccurred(env)) {
       
   214     /* ignore exceptions for now */
       
   215     (*env)->ExceptionClear(env);
       
   216     return NULL;
       
   217   }
       
   218 
       
   219   return (void*)(uintptr_t)result;
       
   220 }
       
   221 
       
   222 /* printing callback binding to Disassembler.rawPrint */
       
   223 static int printf_to_env(void* env_pv, const char* format, ...) {
       
   224   jstring output;
       
   225   va_list ap;
       
   226   int cnt;
       
   227   decode_env* denv = (decode_env*)env_pv;
       
   228   JNIEnv* env = denv->env;
       
   229   size_t flen = strlen(format);
       
   230   const char* raw = NULL;
       
   231 
       
   232   if (flen == 0)  return 0;
       
   233   if (flen < 2 ||
       
   234       strchr(format, '%') == NULL) {
       
   235     raw = format;
       
   236   } else if (format[0] == '%' && format[1] == '%' &&
       
   237              strchr(format+2, '%') == NULL) {
       
   238     // happens a lot on machines with names like %foo
       
   239     flen--;
       
   240     raw = format+1;
       
   241   }
       
   242   if (raw != NULL) {
       
   243     jstring output = (*env)->NewStringUTF(env, raw);
       
   244     if (!(*env)->ExceptionOccurred(env)) {
       
   245       /* make sure that UTF allocation doesn't cause OOM */
       
   246       (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);
       
   247     }
       
   248     if ((*env)->ExceptionOccurred(env)) {
       
   249       /* ignore exceptions for now */
       
   250         (*env)->ExceptionClear(env);
       
   251     }
       
   252     return (int) flen;
       
   253   }
       
   254   va_start(ap, format);
       
   255   cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap);
       
   256   va_end(ap);
       
   257 
       
   258   output = (*env)->NewStringUTF(env, denv->buffer);
       
   259   if (!(*env)->ExceptionOccurred(env)) {
       
   260     /* make sure that UTF allocation doesn't cause OOM */
       
   261     (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);
       
   262   }
       
   263 
       
   264   if ((*env)->ExceptionOccurred(env)) {
       
   265     /* ignore exceptions for now */
       
   266     (*env)->ExceptionClear(env);
       
   267   }
       
   268 
       
   269   return cnt;
       
   270 }
       
   271 
       
   272 /*
       
   273  * Class:     sun_jvm_hotspot_asm_Disassembler
       
   274  * Method:    decode
       
   275  * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V
       
   276  */
       
   277 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env,
       
   278                                                                     jobject dis,
       
   279                                                                     jobject visitor,
       
   280                                                                     jlong startPc,
       
   281                                                                     jbyteArray code,
       
   282                                                                     jstring options_s,
       
   283                                                                     jlong decode_instructions_virtual) {
       
   284   jbyte *start = NULL;
       
   285   jbyte *end = NULL;
       
   286   jclass disclass = NULL;
       
   287   const char *options = NULL;
       
   288   decode_env denv;
       
   289 
       
   290   start = (*env)->GetByteArrayElements(env, code, NULL);
       
   291   if ((*env)->ExceptionOccurred(env)) {
       
   292     return;
       
   293   }
       
   294   end = start + (*env)->GetArrayLength(env, code);
       
   295   options = (*env)->GetStringUTFChars(env, options_s, NULL);
       
   296   if ((*env)->ExceptionOccurred(env)) {
       
   297     (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
       
   298     return;
       
   299   }
       
   300   disclass = (*env)->GetObjectClass(env, dis);
       
   301 
       
   302   denv.env = env;
       
   303   denv.dis = dis;
       
   304   denv.visitor = visitor;
       
   305 
       
   306   /* find Disassembler.handleEvent callback */
       
   307   denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent",
       
   308                                           "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J");
       
   309   if ((*env)->ExceptionOccurred(env)) {
       
   310     (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
       
   311     (*env)->ReleaseStringUTFChars(env, options_s, options);
       
   312     return;
       
   313   }
       
   314 
       
   315   /* find Disassembler.rawPrint callback */
       
   316   denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint",
       
   317                                        "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V");
       
   318   if ((*env)->ExceptionOccurred(env)) {
       
   319     (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
       
   320     (*env)->ReleaseStringUTFChars(env, options_s, options);
       
   321     return;
       
   322   }
       
   323 
       
   324   /* decode the buffer */
       
   325   (*(decode_func)(uintptr_t)decode_instructions_virtual)((uintptr_t) startPc,
       
   326                                                          startPc + end - start,
       
   327                                                          (unsigned char*)start,
       
   328                                                          end - start,
       
   329                                                          &event_to_env,  (void*) &denv,
       
   330                                                          &printf_to_env, (void*) &denv,
       
   331                                                          options, 0 /* newline */);
       
   332 
       
   333   /* cleanup */
       
   334   (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
       
   335   (*env)->ReleaseStringUTFChars(env, options_s, options);
       
   336 }