1 /* 2 * Copyright (c) 2002, 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 <jni.h> 26 #include "libproc.h" 27 28 #include <elf.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <fcntl.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <limits.h> 35 36 #if defined(x86_64) && !defined(amd64) 37 #define amd64 1 38 #endif 39 40 #ifdef i386 41 #include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h" 42 #endif 43 44 #ifdef amd64 45 #include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" 46 #endif 47 48 #if defined(sparc) || defined(sparcv9) 49 #include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h" 50 #endif 51 52 static jfieldID p_ps_prochandle_ID = 0; 53 static jfieldID threadList_ID = 0; 54 static jfieldID loadObjectList_ID = 0; 55 56 static jmethodID createClosestSymbol_ID = 0; 57 static jmethodID createLoadObject_ID = 0; 58 static jmethodID getThreadForThreadId_ID = 0; 59 static jmethodID listAdd_ID = 0; 60 61 #define CHECK_EXCEPTION_(value) if ((*env)->ExceptionOccurred(env)) { return value; } 62 #define CHECK_EXCEPTION if ((*env)->ExceptionOccurred(env)) { return;} 63 #define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throw_new_debugger_exception(env, str); return value; } 64 #define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;} 65 66 void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) { 67 jclass clazz; 68 clazz = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"); 69 CHECK_EXCEPTION; 70 (*env)->ThrowNew(env, clazz, errMsg); 71 } 72 73 struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) { 74 jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID); 75 return (struct ps_prochandle*)(intptr_t)ptr; 76 } 77 78 /* 79 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 80 * Method: init0 81 * Signature: ()V 82 */ 83 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_init0 84 (JNIEnv *env, jclass cls) { 85 jclass listClass; 86 87 if (init_libproc(getenv("LIBSAPROC_DEBUG") != NULL) != true) { 88 THROW_NEW_DEBUGGER_EXCEPTION("can't initialize libproc"); 89 } 90 91 // fields we use 92 p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J"); 93 CHECK_EXCEPTION; 94 threadList_ID = (*env)->GetFieldID(env, cls, "threadList", "Ljava/util/List;"); 95 CHECK_EXCEPTION; 96 loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;"); 97 CHECK_EXCEPTION; 98 99 // methods we use 100 createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol", 101 "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;"); 102 CHECK_EXCEPTION; 103 createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject", 104 "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;"); 105 CHECK_EXCEPTION; 106 getThreadForThreadId_ID = (*env)->GetMethodID(env, cls, "getThreadForThreadId", 107 "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;"); 108 CHECK_EXCEPTION; 109 // java.util.List method we call 110 listClass = (*env)->FindClass(env, "java/util/List"); 111 CHECK_EXCEPTION; 112 listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z"); 113 CHECK_EXCEPTION; 114 } 115 116 JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getAddressSize 117 (JNIEnv *env, jclass cls) 118 { 119 #ifdef _LP64 120 return 8; 121 #else 122 return 4; 123 #endif 124 125 } 126 127 128 static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) { 129 int n = 0, i = 0; 130 131 // add threads 132 n = get_num_threads(ph); 133 for (i = 0; i < n; i++) { 134 jobject thread; 135 jobject threadList; 136 lwpid_t lwpid; 137 138 lwpid = get_lwp_id(ph, i); 139 thread = (*env)->CallObjectMethod(env, this_obj, getThreadForThreadId_ID, 140 (jlong)lwpid); 141 CHECK_EXCEPTION; 142 threadList = (*env)->GetObjectField(env, this_obj, threadList_ID); 143 CHECK_EXCEPTION; 144 (*env)->CallBooleanMethod(env, threadList, listAdd_ID, thread); 145 CHECK_EXCEPTION; 146 } 147 148 // add load objects 149 n = get_num_libs(ph); 150 for (i = 0; i < n; i++) { 151 uintptr_t base; 152 const char* name; 153 jobject loadObject; 154 jobject loadObjectList; 155 jstring str; 156 157 base = get_lib_base(ph, i); 158 name = get_lib_name(ph, i); 159 160 str = (*env)->NewStringUTF(env, name); 161 CHECK_EXCEPTION; 162 loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, str, (jlong)0, (jlong)base); 163 CHECK_EXCEPTION; 164 loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID); 165 CHECK_EXCEPTION; 166 (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject); 167 CHECK_EXCEPTION; 168 } 169 } 170 171 172 /* 173 * Verify that a named ELF binary file (core or executable) has the same 174 * bitness as ourselves. 175 * Throw an exception if there is a mismatch or other problem. 176 * 177 * If we proceed using a mismatched debugger/debuggee, the best to hope 178 * for is a missing symbol, the worst is a crash searching for debug symbols. 179 */ 180 void verifyBitness(JNIEnv *env, const char *binaryName) { 181 int fd = open(binaryName, O_RDONLY); 182 if (fd < 0) { 183 THROW_NEW_DEBUGGER_EXCEPTION("cannot open binary file"); 184 } 185 unsigned char elf_ident[EI_NIDENT]; 186 int i = read(fd, &elf_ident, sizeof(elf_ident)); 187 close(fd); 188 189 if (i < 0) { 190 THROW_NEW_DEBUGGER_EXCEPTION("cannot read binary file"); 191 } 192 #ifndef _LP64 193 if (elf_ident[EI_CLASS] == ELFCLASS64) { 194 THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use 64-bit java for debugger"); 195 } 196 #else 197 if (elf_ident[EI_CLASS] != ELFCLASS64) { 198 THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger"); 199 } 200 #endif 201 } 202 203 204 /* 205 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 206 * Method: attach0 207 * Signature: (I)V 208 */ 209 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__I 210 (JNIEnv *env, jobject this_obj, jint jpid) { 211 212 // For bitness checking, locate binary at /proc/jpid/exe 213 char buf[PATH_MAX]; 214 snprintf((char *) &buf, PATH_MAX, "/proc/%d/exe", jpid); 215 verifyBitness(env, (char *) &buf); 216 CHECK_EXCEPTION; 217 218 struct ps_prochandle* ph; 219 if ( (ph = Pgrab(jpid)) == NULL) { 220 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); 221 } 222 (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); 223 fillThreadsAndLoadObjects(env, this_obj, ph); 224 } 225 226 /* 227 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 228 * Method: attach0 229 * Signature: (Ljava/lang/String;Ljava/lang/String;)V 230 */ 231 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 232 (JNIEnv *env, jobject this_obj, jstring execName, jstring coreName) { 233 const char *execName_cstr; 234 const char *coreName_cstr; 235 jboolean isCopy; 236 struct ps_prochandle* ph; 237 238 execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy); 239 CHECK_EXCEPTION; 240 coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); 241 CHECK_EXCEPTION; 242 243 verifyBitness(env, execName_cstr); 244 CHECK_EXCEPTION; 245 246 if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { 247 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 248 (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); 249 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file"); 250 } 251 (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); 252 (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); 253 (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); 254 fillThreadsAndLoadObjects(env, this_obj, ph); 255 } 256 257 /* 258 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 259 * Method: detach0 260 * Signature: ()V 261 */ 262 JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_detach0 263 (JNIEnv *env, jobject this_obj) { 264 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 265 if (ph != NULL) { 266 Prelease(ph); 267 } 268 } 269 270 /* 271 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 272 * Method: lookupByName0 273 * Signature: (Ljava/lang/String;Ljava/lang/String;)J 274 */ 275 JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByName0 276 (JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) { 277 const char *objectName_cstr, *symbolName_cstr; 278 jlong addr; 279 jboolean isCopy; 280 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 281 282 objectName_cstr = NULL; 283 if (objectName != NULL) { 284 objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy); 285 CHECK_EXCEPTION_(0); 286 } 287 symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy); 288 CHECK_EXCEPTION_(0); 289 290 addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr); 291 292 if (objectName_cstr != NULL) { 293 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr); 294 } 295 (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr); 296 return addr; 297 } 298 299 /* 300 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 301 * Method: lookupByAddress0 302 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; 303 */ 304 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByAddress0 305 (JNIEnv *env, jobject this_obj, jlong addr) { 306 uintptr_t offset; 307 jobject obj; 308 jstring str; 309 const char* sym = NULL; 310 311 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 312 sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); 313 if (sym == NULL) return 0; 314 str = (*env)->NewStringUTF(env, sym); 315 CHECK_EXCEPTION_(NULL); 316 obj = (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, str, (jlong)offset); 317 CHECK_EXCEPTION_(NULL); 318 return obj; 319 } 320 321 /* 322 * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal 323 * Method: readBytesFromProcess0 324 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; 325 */ 326 JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_readBytesFromProcess0 327 (JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) { 328 329 jboolean isCopy; 330 jbyteArray array; 331 jbyte *bufPtr; 332 ps_err_e err; 333 334 array = (*env)->NewByteArray(env, numBytes); 335 CHECK_EXCEPTION_(0); 336 bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); 337 CHECK_EXCEPTION_(0); 338 339 err = ps_pdread(get_proc_handle(env, this_obj), (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); 340 (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); 341 return (err == PS_OK)? array : 0; 342 } 343 344 #if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) || defined(aarch64) 345 JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 346 (JNIEnv *env, jobject this_obj, jint lwp_id) { 347 348 struct user_regs_struct gregs; 349 jboolean isCopy; 350 jlongArray array; 351 jlong *regs; 352 int i; 353 354 struct ps_prochandle* ph = get_proc_handle(env, this_obj); 355 if (get_lwp_regs(ph, lwp_id, &gregs) != true) { 356 THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0); 357 } 358 359 #undef NPRGREG 360 #ifdef i386 361 #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG 362 #endif 363 #ifdef amd64 364 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG 365 #endif 366 #ifdef aarch64 367 #define NPRGREG 32 368 #endif 369 #if defined(sparc) || defined(sparcv9) 370 #define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG 371 #endif 372 373 array = (*env)->NewLongArray(env, NPRGREG); 374 CHECK_EXCEPTION_(0); 375 regs = (*env)->GetLongArrayElements(env, array, &isCopy); 376 377 #undef REG_INDEX 378 379 #ifdef i386 380 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##reg 381 382 regs[REG_INDEX(GS)] = (uintptr_t) gregs.xgs; 383 regs[REG_INDEX(FS)] = (uintptr_t) gregs.xfs; 384 regs[REG_INDEX(ES)] = (uintptr_t) gregs.xes; 385 regs[REG_INDEX(DS)] = (uintptr_t) gregs.xds; 386 regs[REG_INDEX(EDI)] = (uintptr_t) gregs.edi; 387 regs[REG_INDEX(ESI)] = (uintptr_t) gregs.esi; 388 regs[REG_INDEX(FP)] = (uintptr_t) gregs.ebp; 389 regs[REG_INDEX(SP)] = (uintptr_t) gregs.esp; 390 regs[REG_INDEX(EBX)] = (uintptr_t) gregs.ebx; 391 regs[REG_INDEX(EDX)] = (uintptr_t) gregs.edx; 392 regs[REG_INDEX(ECX)] = (uintptr_t) gregs.ecx; 393 regs[REG_INDEX(EAX)] = (uintptr_t) gregs.eax; 394 regs[REG_INDEX(PC)] = (uintptr_t) gregs.eip; 395 regs[REG_INDEX(CS)] = (uintptr_t) gregs.xcs; 396 regs[REG_INDEX(SS)] = (uintptr_t) gregs.xss; 397 398 #endif /* i386 */ 399 400 #ifdef amd64 401 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg 402 403 regs[REG_INDEX(R15)] = gregs.r15; 404 regs[REG_INDEX(R14)] = gregs.r14; 405 regs[REG_INDEX(R13)] = gregs.r13; 406 regs[REG_INDEX(R12)] = gregs.r12; 407 regs[REG_INDEX(RBP)] = gregs.rbp; 408 regs[REG_INDEX(RBX)] = gregs.rbx; 409 regs[REG_INDEX(R11)] = gregs.r11; 410 regs[REG_INDEX(R10)] = gregs.r10; 411 regs[REG_INDEX(R9)] = gregs.r9; 412 regs[REG_INDEX(R8)] = gregs.r8; 413 regs[REG_INDEX(RAX)] = gregs.rax; 414 regs[REG_INDEX(RCX)] = gregs.rcx; 415 regs[REG_INDEX(RDX)] = gregs.rdx; 416 regs[REG_INDEX(RSI)] = gregs.rsi; 417 regs[REG_INDEX(RDI)] = gregs.rdi; 418 regs[REG_INDEX(RIP)] = gregs.rip; 419 regs[REG_INDEX(CS)] = gregs.cs; 420 regs[REG_INDEX(RSP)] = gregs.rsp; 421 regs[REG_INDEX(SS)] = gregs.ss; 422 regs[REG_INDEX(FSBASE)] = gregs.fs_base; 423 regs[REG_INDEX(GSBASE)] = gregs.gs_base; 424 regs[REG_INDEX(DS)] = gregs.ds; 425 regs[REG_INDEX(ES)] = gregs.es; 426 regs[REG_INDEX(FS)] = gregs.fs; 427 regs[REG_INDEX(GS)] = gregs.gs; 428 429 #endif /* amd64 */ 430 431 #if defined(sparc) || defined(sparcv9) 432 433 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_##reg 434 435 #ifdef _LP64 436 regs[REG_INDEX(R_PSR)] = gregs.tstate; 437 regs[REG_INDEX(R_PC)] = gregs.tpc; 438 regs[REG_INDEX(R_nPC)] = gregs.tnpc; 439 regs[REG_INDEX(R_Y)] = gregs.y; 440 #else 441 regs[REG_INDEX(R_PSR)] = gregs.psr; 442 regs[REG_INDEX(R_PC)] = gregs.pc; 443 regs[REG_INDEX(R_nPC)] = gregs.npc; 444 regs[REG_INDEX(R_Y)] = gregs.y; 445 #endif 446 regs[REG_INDEX(R_G0)] = 0 ; 447 regs[REG_INDEX(R_G1)] = gregs.u_regs[0]; 448 regs[REG_INDEX(R_G2)] = gregs.u_regs[1]; 449 regs[REG_INDEX(R_G3)] = gregs.u_regs[2]; 450 regs[REG_INDEX(R_G4)] = gregs.u_regs[3]; 451 regs[REG_INDEX(R_G5)] = gregs.u_regs[4]; 452 regs[REG_INDEX(R_G6)] = gregs.u_regs[5]; 453 regs[REG_INDEX(R_G7)] = gregs.u_regs[6]; 454 regs[REG_INDEX(R_O0)] = gregs.u_regs[7]; 455 regs[REG_INDEX(R_O1)] = gregs.u_regs[8]; 456 regs[REG_INDEX(R_O2)] = gregs.u_regs[ 9]; 457 regs[REG_INDEX(R_O3)] = gregs.u_regs[10]; 458 regs[REG_INDEX(R_O4)] = gregs.u_regs[11]; 459 regs[REG_INDEX(R_O5)] = gregs.u_regs[12]; 460 regs[REG_INDEX(R_O6)] = gregs.u_regs[13]; 461 regs[REG_INDEX(R_O7)] = gregs.u_regs[14]; 462 #endif /* sparc */ 463 464 #if defined(aarch64) 465 466 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg 467 468 #endif /* aarch64 */ 469 470 471 (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT); 472 return array; 473 } 474 #endif