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 
get_dwarf_context(JNIEnv * env,jobject obj)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"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_init0(JNIEnv * env,jclass this_cls)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"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_createDwarfContext(JNIEnv * env,jclass this_cls,jlong lib)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     if (!env->ExceptionOccurred()) {
108         env->ThrowNew(ex_cls, "DWARF not found");
109     }
110     return 0L;
111   }
112 
113   return reinterpret_cast<jlong>(parser);
114 }
115 
116 /*
117  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
118  * Method:    destroyDwarfContext
119  * Signature: (J)V
120  */
121 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_destroyDwarfContext(JNIEnv * env,jclass this_cls,jlong context)122 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_destroyDwarfContext
123   (JNIEnv *env, jclass this_cls, jlong context) {
124   DwarfParser *parser = reinterpret_cast<DwarfParser *>(context);
125   delete parser;
126 }
127 
128 /*
129  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
130  * Method:    isIn0
131  * Signature: (J)Z
132  */
133 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isIn0(JNIEnv * env,jobject this_obj,jlong pc)134 JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isIn0
135   (JNIEnv *env, jobject this_obj, jlong pc) {
136   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
137   return static_cast<jboolean>(parser->is_in(pc));
138 }
139 
140 /*
141  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
142  * Method:    processDwarf0
143  * Signature: (J)V
144  */
145 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_processDwarf0(JNIEnv * env,jobject this_obj,jlong pc)146 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_processDwarf0
147   (JNIEnv *env, jobject this_obj, jlong pc) {
148   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
149   if (!parser->process_dwarf(pc)) {
150     jclass ex_cls = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
151     if (!env->ExceptionOccurred()) {
152         env->ThrowNew(ex_cls, "Could not find PC in DWARF");
153     }
154     return;
155   }
156 }
157 
158 /*
159  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
160  * Method:    getCFARegister
161  * Signature: ()I
162  */
163 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFARegister(JNIEnv * env,jobject this_obj)164 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFARegister
165   (JNIEnv *env, jobject this_obj) {
166   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
167   switch (parser->get_cfa_register()) {
168     case RAX: return sa_RAX;
169     case RDX: return sa_RDX;
170     case RCX: return sa_RCX;
171     case RBX: return sa_RBX;
172     case RSI: return sa_RSI;
173     case RDI: return sa_RDI;
174     case RBP: return sa_RBP;
175     case RSP: return sa_RSP;
176     case R8:  return sa_R8;
177     case R9:  return sa_R9;
178     case R10: return sa_R10;
179     case R11: return sa_R11;
180     case R12: return sa_R12;
181     case R13: return sa_R13;
182     case R14: return sa_R14;
183     case R15: return sa_R15;
184     default:  return -1;
185   }
186 }
187 
188 /*
189  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
190  * Method:    getCFAOffset
191  * Signature: ()I
192  */
193 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFAOffset(JNIEnv * env,jobject this_obj)194 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFAOffset
195   (JNIEnv *env, jobject this_obj) {
196   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
197   return parser->get_cfa_offset();
198 }
199 
200 /*
201  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
202  * Method:    getReturnAddressOffsetFromCFA
203  * Signature: ()I
204  */
205 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getReturnAddressOffsetFromCFA(JNIEnv * env,jobject this_obj)206 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getReturnAddressOffsetFromCFA
207   (JNIEnv *env, jobject this_obj) {
208   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
209   return parser->get_ra_cfa_offset();
210 }
211 
212 /*
213  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
214  * Method:    getBasePointerOffsetFromCFA
215  * Signature: ()I
216  */
217 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getBasePointerOffsetFromCFA(JNIEnv * env,jobject this_obj)218 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getBasePointerOffsetFromCFA
219   (JNIEnv *env, jobject this_obj) {
220   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
221   return parser->get_bp_cfa_offset();
222 }
223 
224 /*
225  * Class:     sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
226  * Method:    isBPOffsetAvailable
227  * Signature: ()Z
228  */
229 extern "C"
Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isBPOffsetAvailable(JNIEnv * env,jobject this_obj)230 JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isBPOffsetAvailable
231   (JNIEnv *env, jobject this_obj) {
232   DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
233   return parser->is_bp_offset_available();
234 }
235 
236