# HG changeset patch # User coleenp # Date 1362094661 18000 # Node ID 143973ced9ab25c3068fdd614b6d1d601b0bec75 # Parent a506ac816f1435b260c1bc6037573851b4865e70# Parent a140cd9254621cb0f653172583e105ba8e568216 Merge diff -r a506ac816f14 -r 143973ced9ab agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Wed Feb 27 07:35:32 2013 -0500 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Thu Feb 28 18:37:41 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,13 @@ #include #include "libproc.h" +#include +#include +#include +#include +#include +#include + #if defined(x86_64) && !defined(amd64) #define amd64 1 #endif @@ -154,6 +161,39 @@ } } + +/* + * Verify that a named ELF binary file (core or executable) has the same + * bitness as ourselves. + * Throw an exception if there is a mismatch or other problem. + * + * If we proceed using a mismatched debugger/debuggee, the best to hope + * for is a missing symbol, the worst is a crash searching for debug symbols. + */ +void verifyBitness(JNIEnv *env, const char *binaryName) { + int fd = open(binaryName, O_RDONLY); + if (fd < 0) { + THROW_NEW_DEBUGGER_EXCEPTION("cannot open binary file"); + } + unsigned char elf_ident[EI_NIDENT]; + int i = read(fd, &elf_ident, sizeof(elf_ident)); + close(fd); + + if (i < 0) { + THROW_NEW_DEBUGGER_EXCEPTION("cannot read binary file"); + } +#ifndef _LP64 + if (elf_ident[EI_CLASS] == ELFCLASS64) { + THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use 64-bit java for debugger"); + } +#else + if (elf_ident[EI_CLASS] != ELFCLASS64) { + THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger"); + } +#endif +} + + /* * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal * Method: attach0 @@ -162,6 +202,12 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__I (JNIEnv *env, jobject this_obj, jint jpid) { + // For bitness checking, locate binary at /proc/jpid/exe + char buf[PATH_MAX]; + snprintf((char *) &buf, PATH_MAX, "/proc/%d/exe", jpid); + verifyBitness(env, (char *) &buf); + CHECK_EXCEPTION; + struct ps_prochandle* ph; if ( (ph = Pgrab(jpid)) == NULL) { THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); @@ -187,6 +233,9 @@ coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); CHECK_EXCEPTION; + verifyBitness(env, execName_cstr); + CHECK_EXCEPTION; + if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); diff -r a506ac816f14 -r 143973ced9ab agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java Wed Feb 27 07:35:32 2013 -0500 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java Thu Feb 28 18:37:41 2013 -0500 @@ -60,8 +60,13 @@ return null; } + // Check alignment of rbp + if ( dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) { + return null; + } + Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextRBP == null) { + if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) { return null; } Address nextPC = rbp.getAddressAt( 1 * ADDRESS_SIZE); diff -r a506ac816f14 -r 143973ced9ab agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java Wed Feb 27 07:35:32 2013 -0500 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java Thu Feb 28 18:37:41 2013 -0500 @@ -61,8 +61,13 @@ return null; } + // Check alignment of ebp + if ( dbg.getAddressValue(ebp) % ADDRESS_SIZE != 0) { + return null; + } + Address nextEBP = ebp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextEBP == null) { + if (nextEBP == null || nextEBP.lessThanOrEqual(ebp)) { return null; } Address nextPC = ebp.getAddressAt( 1 * ADDRESS_SIZE); diff -r a506ac816f14 -r 143973ced9ab src/share/vm/c1/c1_FrameMap.cpp --- a/src/share/vm/c1/c1_FrameMap.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/c1/c1_FrameMap.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -308,27 +308,6 @@ return sp_offset_for_monitor_base(index) + in_ByteSize(BasicObjectLock::obj_offset_in_bytes()); } -void FrameMap::print_frame_layout() const { - int svar; - tty->print_cr("#####################################"); - tty->print_cr("Frame size in words %d", framesize()); - - if( _num_monitors > 0) { - tty->print_cr("monitor [0]:%d | [%2d]:%d", - in_bytes(sp_offset_for_monitor_base(0)), - in_bytes(sp_offset_for_monitor_base(_num_monitors))); - } - if( _num_spills > 0) { - svar = _num_spills - 1; - if(svar == 0) - tty->print_cr("spill [0]:%d", in_bytes(sp_offset_for_spill(0))); - else - tty->print_cr("spill [0]:%d | [%2d]:%d", in_bytes(sp_offset_for_spill(0)), - svar, - in_bytes(sp_offset_for_spill(svar))); - } -} - // For OopMaps, map a local variable or spill index to an VMReg. // This is the offset from sp() in the frame of the slot for the index, diff -r a506ac816f14 -r 143973ced9ab src/share/vm/c1/c1_FrameMap.hpp --- a/src/share/vm/c1/c1_FrameMap.hpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/c1/c1_FrameMap.hpp Thu Feb 28 18:37:41 2013 -0500 @@ -226,8 +226,6 @@ return make_new_address(sp_offset_for_monitor_object(monitor_index)); } - void print_frame_layout() const; - // Creates Location describing desired slot and returns it via pointer // to Location object. Returns true if the stack frame offset was legal // (as defined by Location::legal_offset_in_bytes()), false otherwise. diff -r a506ac816f14 -r 143973ced9ab src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -373,6 +373,8 @@ " does not exceed used.end() = " PTR_FORMAT "," " yet last_chunk_index_to_check " INTPTR_FORMAT " exceeds last_chunk_index " INTPTR_FORMAT, + last_block, last_block + last_block_size, + used.end(), last_chunk_index_to_check, last_chunk_index)); assert(sp->used_region().end() > used.end(), err_msg("Expansion did not happen: " diff -r a506ac816f14 -r 143973ced9ab src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -694,7 +694,7 @@ if (failed) { if (!failures) { tty->cr(); - tty->print_cr("== CT verification failed: ["PTR_FORMAT","PTR_FORMAT"]"); + tty->print_cr("== CT verification failed: ["PTR_FORMAT","PTR_FORMAT"]", start, end); tty->print_cr("== %sexpecting value: %d", (val_equals) ? "" : "not ", val); failures = true; diff -r a506ac816f14 -r 143973ced9ab src/share/vm/memory/cardTableRS.cpp --- a/src/share/vm/memory/cardTableRS.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/memory/cardTableRS.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -353,7 +353,7 @@ assert(jp >= _begin && jp < _end, err_msg("Error: jp " PTR_FORMAT " should be within " "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", - _begin, _end)); + jp, _begin, _end)); oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj == NULL || (HeapWord*)obj >= _boundary, err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on " diff -r a506ac816f14 -r 143973ced9ab src/share/vm/prims/jvmtiEnter.xsl --- a/src/share/vm/prims/jvmtiEnter.xsl Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/prims/jvmtiEnter.xsl Thu Feb 28 18:37:41 2013 -0500 @@ -773,7 +773,7 @@ JVMTI_ERROR_INVALID_THREAD - - jthread resolved to NULL - jthread = %0x%x + - jthread resolved to NULL - jthread = 0x%x , @@ -782,7 +782,7 @@ JVMTI_ERROR_INVALID_THREAD - - oop is not a thread - jthread = %0x%x + - oop is not a thread - jthread = 0x%x , @@ -794,7 +794,7 @@ JVMTI_ERROR_THREAD_NOT_ALIVE - - not a Java thread - jthread = %0x%x + - not a Java thread - jthread = 0x%x , @@ -838,7 +838,7 @@ JVMTI_ERROR_ILLEGAL_ARGUMENT - - negative depth - jthread = %0x%x + - negative depth - jthread = 0x%x , diff -r a506ac816f14 -r 143973ced9ab src/share/vm/prims/jvmtiEnvBase.cpp --- a/src/share/vm/prims/jvmtiEnvBase.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -997,13 +997,19 @@ // move our object at this point. However, our owner value is safe // since it is either the Lock word on a stack or a JavaThread *. owning_thread = Threads::owning_thread_from_monitor_owner(owner, !at_safepoint); - assert(owning_thread != NULL, "sanity check"); - if (owning_thread != NULL) { // robustness + // Cannot assume (owning_thread != NULL) here because this function + // may not have been called at a safepoint and the owning_thread + // might not be suspended. + if (owning_thread != NULL) { // The monitor's owner either has to be the current thread, at safepoint // or it has to be suspended. Any of these conditions will prevent both // contending and waiting threads from modifying the state of // the monitor. if (!at_safepoint && !JvmtiEnv::is_thread_fully_suspended(owning_thread, true, &debug_bits)) { + // Don't worry! This return of JVMTI_ERROR_THREAD_NOT_SUSPENDED + // will not make it back to the JVM/TI agent. The error code will + // get intercepted in JvmtiEnv::GetObjectMonitorUsage() which + // will retry the call via a VM_GetObjectMonitorUsage VM op. return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } HandleMark hm; diff -r a506ac816f14 -r 143973ced9ab src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/runtime/synchronizer.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -813,6 +813,7 @@ } if (owner != NULL) { + // owning_thread_from_monitor_owner() may also return NULL here return Threads::owning_thread_from_monitor_owner(owner, doLock); } diff -r a506ac816f14 -r 143973ced9ab src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/runtime/thread.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -4285,7 +4285,9 @@ if (owner == (address)p) return p; } } - assert(UseHeavyMonitors == false, "Did not find owning Java thread with UseHeavyMonitors enabled"); + // Cannot assert on lack of success here since this function may be + // used by code that is trying to report useful problem information + // like deadlock detection. if (UseHeavyMonitors) return NULL; // @@ -4303,7 +4305,7 @@ } } } - assert(the_owner != NULL, "Did not find owning Java thread for lock word address"); + // cannot assert on lack of success here; see above comment return the_owner; } diff -r a506ac816f14 -r 143973ced9ab src/share/vm/services/memReporter.cpp --- a/src/share/vm/services/memReporter.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/services/memReporter.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -419,7 +419,7 @@ _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); _output->print("%28s", " "); } else { - _output->print("[" PTR_FORMAT "]%18s", " "); + _output->print("[" PTR_FORMAT "]%18s", pc, " "); } _output->print_cr("(mmap: reserved=%d%s, committed=%d%s)", @@ -596,7 +596,7 @@ _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); _output->print("%28s", " "); } else { - _output->print("[" PTR_FORMAT "]%18s", " "); + _output->print("[" PTR_FORMAT "]%18s", pc, " "); } } diff -r a506ac816f14 -r 143973ced9ab src/share/vm/services/threadService.cpp --- a/src/share/vm/services/threadService.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/services/threadService.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -327,8 +327,28 @@ while (waitingToLockMonitor != NULL || waitingToLockBlocker != NULL) { cycle->add_thread(currentThread); if (waitingToLockMonitor != NULL) { - currentThread = Threads::owning_thread_from_monitor_owner((address)waitingToLockMonitor->owner(), - false /* no locking needed */); + currentThread = Threads::owning_thread_from_monitor_owner( + (address)waitingToLockMonitor->owner(), + false /* no locking needed */); + if (currentThread == NULL) { + // This function is called at a safepoint so the JavaThread + // that owns waitingToLockMonitor should be findable, but + // if it is not findable, then the previous currentThread is + // blocked permanently. We record this as a deadlock. + num_deadlocks++; + + cycle->set_deadlock(true); + + // add this cycle to the deadlocks list + if (deadlocks == NULL) { + deadlocks = cycle; + } else { + last->set_next(cycle); + } + last = cycle; + cycle = new DeadlockCycle(); + break; + } } else { if (concurrent_locks) { if (waitingToLockBlocker->is_a(SystemDictionary::abstract_ownable_synchronizer_klass())) { @@ -841,7 +861,17 @@ owner_desc = " (JVMTI raw monitor),\n which is held by"; } currentThread = Threads::owning_thread_from_monitor_owner( - (address)waitingToLockMonitor->owner(), false /* no locking needed */); + (address)waitingToLockMonitor->owner(), + false /* no locking needed */); + if (currentThread == NULL) { + // The deadlock was detected at a safepoint so the JavaThread + // that owns waitingToLockMonitor should be findable, but + // if it is not findable, then the previous currentThread is + // blocked permanently. + st->print("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc, + (address)waitingToLockMonitor->owner()); + continue; + } } else { st->print(" waiting for ownable synchronizer " INTPTR_FORMAT ", (a %s)", (address)waitingToLockBlocker, diff -r a506ac816f14 -r 143973ced9ab src/share/vm/utilities/numberSeq.cpp --- a/src/share/vm/utilities/numberSeq.cpp Wed Feb 27 07:35:32 2013 -0500 +++ b/src/share/vm/utilities/numberSeq.cpp Thu Feb 28 18:37:41 2013 -0500 @@ -245,7 +245,7 @@ void NumberSeq::dump_on(outputStream* s) { AbsSeq::dump_on(s); - s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f"); + s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f", _last, _maximum); } void TruncatedSeq::dump_on(outputStream* s) {