1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2020, NTT DATA.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #include <jni.h>
  27 
  28 #include "dwarf.hpp"
  29 #include "libproc.h"
  30 
  31 #define CHECK_EXCEPTION if (env->ExceptionOccurred()) { return; }
  32 
  33 static jfieldID p_dwarf_context_ID = 0;
  34 static jint sa_RAX = -1;
  35 static jint sa_RDX = -1;
  36 static jint sa_RCX = -1;
  37 static jint sa_RBX = -1;
  38 static jint sa_RSI = -1;
  39 static jint sa_RDI = -1;
  40 static jint sa_RBP = -1;
  41 static jint sa_RSP = -1;
  42 static jint sa_R8  = -1;
  43 static jint sa_R9  = -1;
  44 static jint sa_R10 = -1;
  45 static jint sa_R11 = -1;
  46 static jint sa_R12 = -1;
  47 static jint sa_R13 = -1;
  48 static jint sa_R14 = -1;
  49 static jint sa_R15 = -1;
  50 
  51 static jlong get_dwarf_context(JNIEnv *env, jobject obj) {
  52   return env->GetLongField(obj, p_dwarf_context_ID);
  53 }
  54 
  55 #define SET_REG(env, reg, reg_cls) \
  56   jfieldID reg##_ID = env->GetStaticFieldID(reg_cls, #reg, "I"); \
  57   CHECK_EXCEPTION \
  58   sa_##reg = env->GetStaticIntField(reg_cls, reg##_ID); \
  59   CHECK_EXCEPTION
  60 
  61 /*
  62  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
  63  * Method:    init0
  64  * Signature: ()V
  65  */
  66 extern "C"
  67 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_init0
  68   (JNIEnv *env, jclass this_cls) {
  69   jclass cls = env->FindClass("sun/jvm/hotspot/debugger/linux/amd64/DwarfParser");
  70   CHECK_EXCEPTION
  71   p_dwarf_context_ID = env->GetFieldID(cls, "p_dwarf_context", "J");
  72   CHECK_EXCEPTION
  73 
  74   jclass reg_cls = env->FindClass("sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext");
  75   CHECK_EXCEPTION
  76   SET_REG(env, RAX, reg_cls);
  77   SET_REG(env, RDX, reg_cls);
  78   SET_REG(env, RCX, reg_cls);
  79   SET_REG(env, RBX, reg_cls);
  80   SET_REG(env, RSI, reg_cls);
  81   SET_REG(env, RDI, reg_cls);
  82   SET_REG(env, RBP, reg_cls);
  83   SET_REG(env, RSP, reg_cls);
  84   SET_REG(env, R8,  reg_cls);
  85   SET_REG(env, R9,  reg_cls);
  86   SET_REG(env, R10, reg_cls);
  87   SET_REG(env, R11, reg_cls);
  88   SET_REG(env, R12, reg_cls);
  89   SET_REG(env, R13, reg_cls);
  90   SET_REG(env, R14, reg_cls);
  91   SET_REG(env, R15, reg_cls);
  92 }
  93 
  94 /*
  95  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
  96  * Method:    createDwarfContext
  97  * Signature: (J)J
  98  */
  99 extern "C"
 100 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_createDwarfContext
 101   (JNIEnv *env, jclass this_cls, jlong lib) {
 102   jlong result = 0L;
 103 
 104   DwarfParser *parser = new DwarfParser(reinterpret_cast<lib_info *>(lib));
 105   if (!parser->is_parseable()) {
 106     jclass ex_cls = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
 107     env->ThrowNew(ex_cls, "DWARF not found");
 108     return 0L;
 109   }
 110 
 111   return reinterpret_cast<jlong>(parser);
 112 }
 113 
 114 /*
 115  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 116  * Method:    destroyDwarfContext
 117  * Signature: (J)V
 118  */
 119 extern "C"
 120 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_destroyDwarfContext
 121   (JNIEnv *env, jclass this_cls, jlong context) {
 122   DwarfParser *parser = reinterpret_cast<DwarfParser *>(context);
 123   delete parser;
 124 }
 125 
 126 /*
 127  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 128  * Method:    isIn0
 129  * Signature: (J)Z
 130  */
 131 extern "C"
 132 JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isIn0
 133   (JNIEnv *env, jobject this_obj, jlong pc) {
 134   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 135   return static_cast<jboolean>(parser->is_in(pc));
 136 }
 137 
 138 /*
 139  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 140  * Method:    processDwarf0
 141  * Signature: (J)V
 142  */
 143 extern "C"
 144 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_processDwarf0
 145   (JNIEnv *env, jobject this_obj, jlong pc) {
 146   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 147   if (!parser->process_dwarf(pc)) {
 148     jclass ex_cls = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
 149     env->ThrowNew(ex_cls, "Could not find PC in DWARF");
 150     return;
 151   }
 152 }
 153 
 154 /*
 155  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 156  * Method:    getCFARegister
 157  * Signature: ()I
 158  */
 159 extern "C"
 160 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFARegister
 161   (JNIEnv *env, jobject this_obj) {
 162   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 163   switch (parser->get_cfa_register()) {
 164     case RAX: return sa_RAX;
 165     case RDX: return sa_RDX;
 166     case RCX: return sa_RCX;
 167     case RBX: return sa_RBX;
 168     case RSI: return sa_RSI;
 169     case RDI: return sa_RDI;
 170     case RBP: return sa_RBP;
 171     case RSP: return sa_RSP;
 172     case R8:  return sa_R8;
 173     case R9:  return sa_R9;
 174     case R10: return sa_R10;
 175     case R11: return sa_R11;
 176     case R12: return sa_R12;
 177     case R13: return sa_R13;
 178     case R14: return sa_R14;
 179     case R15: return sa_R15;
 180     default:  return -1;
 181   }
 182 }
 183 
 184 /*
 185  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 186  * Method:    getCFAOffset
 187  * Signature: ()I
 188  */
 189 extern "C"
 190 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFAOffset
 191   (JNIEnv *env, jobject this_obj) {
 192   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 193   return parser->get_cfa_offset();
 194 }
 195 
 196 /*
 197  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 198  * Method:    getReturnAddressOffsetFromCFA
 199  * Signature: ()I
 200  */
 201 extern "C"
 202 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getReturnAddressOffsetFromCFA
 203   (JNIEnv *env, jobject this_obj) {
 204   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 205   return parser->get_ra_cfa_offset();
 206 }
 207 
 208 /*
 209  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 210  * Method:    getBasePointerOffsetFromCFA
 211  * Signature: ()I
 212  */
 213 extern "C"
 214 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getBasePointerOffsetFromCFA
 215   (JNIEnv *env, jobject this_obj) {
 216   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 217   return parser->get_bp_cfa_offset();
 218 }
 219 
 220 /*
 221  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
 222  * Method:    isBPOffsetAvailable
 223  * Signature: ()Z
 224  */
 225 extern "C"
 226 JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isBPOffsetAvailable
 227   (JNIEnv *env, jobject this_obj) {
 228   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
 229   return parser->is_bp_offset_available();
 230 }
 231