# HG changeset patch # User coffeys # Date 1421860046 0 # Node ID 9989538b75073e6d9ad9f2510d9ef48c8ea2f141 # Parent 6fe56d3026d56ffff17ce7e72a8461536529ee92# Parent 0ee548a1cda08c884eccd563e2d5fdb6ee769b5a Merge diff -r 0ee548a1cda0 -r 9989538b7507 .hgtags --- a/.hgtags Tue Jan 20 13:47:31 2015 -0800 +++ b/.hgtags Wed Jan 21 17:07:26 2015 +0000 @@ -584,3 +584,6 @@ d2e9a6bec4f2eec8506eed16f7324992a85d8480 hs25.40-b24 25ec4a67433744bbe3406e5069e7fd1876ebbf2f jdk8u40-b21 0f0cb4eeab2d871274f4ffdcd6017d2fdfa89238 hs25.40-b25 +d9349fa8822336e0244da0a8448f3e6b2d62741d jdk8u60-b00 +d9349fa8822336e0244da0a8448f3e6b2d62741d hs25.60-b00 +ebf89088c08ab0508b9002b48dd3d68a340259af hs25.60-b01 diff -r 0ee548a1cda0 -r 9989538b7507 make/hotspot_version --- a/make/hotspot_version Tue Jan 20 13:47:31 2015 -0800 +++ b/make/hotspot_version Wed Jan 21 17:07:26 2015 +0000 @@ -34,8 +34,8 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2015 HS_MAJOR_VER=25 -HS_MINOR_VER=40 -HS_BUILD_NUMBER=25 +HS_MINOR_VER=60 +HS_BUILD_NUMBER=01 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/ppc/vm/frame_ppc.cpp --- a/src/cpu/ppc/vm/frame_ppc.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/ppc/vm/frame_ppc.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -318,3 +318,10 @@ // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); } + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp), _unextended_sp((intptr_t*)sp) { + find_codeblob_and_set_pc_and_deopt_state((address)pc); // also sets _fp and adjusts _unextended_sp +} +#endif diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/sparc/vm/frame_sparc.cpp --- a/src/cpu/sparc/vm/frame_sparc.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -342,7 +342,7 @@ // constructors // Construct an unpatchable, deficient frame -frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) { +void frame::init(intptr_t* sp, address pc, CodeBlob* cb) { #ifdef _LP64 assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp"); #endif @@ -364,6 +364,10 @@ #endif // ASSERT } +frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) { + init(sp, pc, cb); +} + frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) : _sp(sp), _younger_sp(younger_sp), @@ -418,6 +422,13 @@ } } +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) { + init((intptr_t*)sp, (address)pc, NULL); +} +#endif + bool frame::is_interpreted_frame() const { return Interpreter::contains(pc()); } diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/sparc/vm/frame_sparc.hpp --- a/src/cpu/sparc/vm/frame_sparc.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/sparc/vm/frame_sparc.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -164,6 +164,8 @@ enum unpatchable_t { unpatchable }; frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL); + void init(intptr_t* sp, address pc, CodeBlob* cb); + // Walk from sp outward looking for old_sp, and return old_sp's predecessor // (i.e. return the sp from the frame where old_sp is the fp). // Register windows are assumed to be flushed for the stack in question. diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/x86/vm/frame_x86.cpp --- a/src/cpu/x86/vm/frame_x86.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/x86/vm/frame_x86.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -717,3 +717,10 @@ assert(! is_compiled_frame(), "unknown compiled frame size"); return fp(); } + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) { + init((intptr_t*)sp, (intptr_t*)fp, (address)pc); +} +#endif diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/x86/vm/frame_x86.hpp --- a/src/cpu/x86/vm/frame_x86.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/x86/vm/frame_x86.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -187,6 +187,8 @@ frame(intptr_t* sp, intptr_t* fp); + void init(intptr_t* sp, intptr_t* fp, address pc); + // accessors for the instance variables // Note: not necessarily the real 'frame pointer' (see real_fp) intptr_t* fp() const { return _fp; } diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/x86/vm/frame_x86.inline.hpp --- a/src/cpu/x86/vm/frame_x86.inline.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -40,7 +40,7 @@ _deopt_state = unknown; } -inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { +inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { _sp = sp; _unextended_sp = sp; _fp = fp; @@ -58,6 +58,10 @@ } } +inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { + init(sp, fp, pc); +} + inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) { _sp = sp; _unextended_sp = unextended_sp; diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/x86/vm/vm_version_x86.hpp --- a/src/cpu/x86/vm/vm_version_x86.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/x86/vm/vm_version_x86.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -570,10 +570,12 @@ static uint cores_per_cpu() { uint result = 1; if (is_intel()) { - if (supports_processor_topology()) { + bool supports_topology = supports_processor_topology(); + if (supports_topology) { result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus / _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus; - } else { + } + if (!supports_topology || result == 0) { result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); } } else if (is_amd()) { diff -r 0ee548a1cda0 -r 9989538b7507 src/cpu/zero/vm/frame_zero.cpp --- a/src/cpu/zero/vm/frame_zero.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/cpu/zero/vm/frame_zero.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -441,3 +441,10 @@ // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); } + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* sp, void* fp, void* pc) { + Unimplemented(); +} +#endif diff -r 0ee548a1cda0 -r 9989538b7507 src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -264,7 +264,7 @@ CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(NULL, NULL, false); } else { return os::get_sender_for_C_frame(&myframe); } diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/ci/ciTypeFlow.cpp --- a/src/share/vm/ci/ciTypeFlow.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/ci/ciTypeFlow.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -36,6 +36,7 @@ #include "interpreter/bytecodes.hpp" #include "memory/allocation.inline.hpp" #include "opto/compile.hpp" +#include "opto/node.hpp" #include "runtime/deoptimization.hpp" #include "utilities/growableArray.hpp" diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/prims/unsafe.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -322,10 +322,33 @@ UNSAFE_END #ifndef SUPPORTS_NATIVE_CX8 -// Keep old code for platforms which may not have atomic jlong (8 bytes) instructions -// Volatile long versions must use locks if !VM_Version::supports_cx8(). -// support_cx8 is a surrogate for 'supports atomic long memory ops'. +// VM_Version::supports_cx8() is a surrogate for 'supports atomic long memory ops'. +// +// On platforms which do not support atomic compare-and-swap of jlong (8 byte) +// values we have to use a lock-based scheme to enforce atomicity. This has to be +// applied to all Unsafe operations that set the value of a jlong field. Even so +// the compareAndSwapLong operation will not be atomic with respect to direct stores +// to the field from Java code. It is important therefore that any Java code that +// utilizes these Unsafe jlong operations does not perform direct stores. To permit +// direct loads of the field from Java code we must also use Atomic::store within the +// locked regions. And for good measure, in case there are direct stores, we also +// employ Atomic::load within those regions. Note that the field in question must be +// volatile and so must have atomic load/store accesses applied at the Java level. +// +// The locking scheme could utilize a range of strategies for controlling the locking +// granularity: from a lock per-field through to a single global lock. The latter is +// the simplest and is used for the current implementation. Note that the Java object +// that contains the field, can not, in general, be used for locking. To do so can lead +// to deadlocks as we may introduce locking into what appears to the Java code to be a +// lock-free path. +// +// As all the locked-regions are very short and themselves non-blocking we can treat +// them as leaf routines and elide safepoint checks (ie we don't perform any thread +// state transitions even when blocking for the lock). Note that if we do choose to +// add safepoint checks and thread state transitions, we must ensure that we calculate +// the address of the field _after_ we have acquired the lock, else the object may have +// been moved by the GC UNSAFE_ENTRY(jlong, Unsafe_GetLongVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) UnsafeWrapper("Unsafe_GetLongVolatile"); @@ -337,8 +360,8 @@ else { Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); - ObjectLocker ol(p, THREAD); - jlong value = *addr; + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong value = Atomic::load(addr); return value; } } @@ -353,8 +376,8 @@ else { Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); - ObjectLocker ol(p, THREAD); - *addr = x; + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + Atomic::store(x, addr); } } UNSAFE_END @@ -463,8 +486,8 @@ else { Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); - ObjectLocker ol(p, THREAD); - *addr = x; + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + Atomic::store(x, addr); } } #endif @@ -1213,14 +1236,19 @@ UnsafeWrapper("Unsafe_CompareAndSwapLong"); Handle p (THREAD, JNIHandles::resolve(obj)); jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); +#ifdef SUPPORTS_NATIVE_CX8 + return (jlong)(Atomic::cmpxchg(x, addr, e)) == e; +#else if (VM_Version::supports_cx8()) return (jlong)(Atomic::cmpxchg(x, addr, e)) == e; else { jboolean success = false; - ObjectLocker ol(p, THREAD); - if (*addr == e) { *addr = x; success = true; } + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong val = Atomic::load(addr); + if (val == e) { Atomic::store(x, addr); success = true; } return success; } +#endif UNSAFE_END UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time)) diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/runtime/frame.hpp --- a/src/share/vm/runtime/frame.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/runtime/frame.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -91,6 +91,15 @@ // Constructors frame(); +#ifndef PRODUCT + // This is a generic constructor which is only used by pns() in debug.cpp. + // pns (i.e. print native stack) uses this constructor to create a starting + // frame for stack walking. The implementation of this constructor is platform + // dependent (i.e. SPARC doesn't need an 'fp' argument an will ignore it) but + // we want to keep the signature generic because pns() is shared code. + frame(void* sp, void* fp, void* pc); +#endif + // Accessors // pc: Returns the pc at which this frame will continue normally. diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/runtime/mutexLocker.cpp --- a/src/share/vm/runtime/mutexLocker.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/runtime/mutexLocker.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -135,6 +135,10 @@ Mutex* JfrThreadGroups_lock = NULL; #endif +#ifndef SUPPORTS_NATIVE_CX8 +Mutex* UnsafeJlong_lock = NULL; +#endif + #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; static int _num_mutex; @@ -286,6 +290,9 @@ def(JfrStacktrace_lock , Mutex, special, true ); #endif +#ifndef SUPPORTS_NATIVE_CX8 + def(UnsafeJlong_lock , Mutex, special, false); +#endif } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/runtime/mutexLocker.hpp --- a/src/share/vm/runtime/mutexLocker.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/runtime/mutexLocker.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -151,6 +151,10 @@ extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups #endif +#ifndef SUPPORTS_NATIVE_CX8 +extern Mutex* UnsafeJlong_lock; // provides Unsafe atomic updates to jlongs on platforms that don't support cx8 +#endif + // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not // an object lock, and the two do not interoperate. Do not use Mutex-based diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/utilities/debug.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -666,6 +666,13 @@ tty->print_cr(" pm(int pc) - print Method* given compiled PC"); tty->print_cr(" findm(intptr_t pc) - finds Method*"); tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it"); + tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g."); + tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or"); + tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or"); + tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); + tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC"); + tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); + tty->print_cr(" - in dbx do 'frame 1' before calling pns()"); tty->print_cr("misc."); tty->print_cr(" flush() - flushes the log file"); @@ -678,3 +685,56 @@ } #endif // !PRODUCT + +void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) { + + // see if it's a valid frame + if (fr.pc()) { + st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); + + int count = 0; + while (count++ < StackPrintLimit) { + fr.print_on_error(st, buf, buf_size); + st->cr(); + // Compiled code may use EBP register on x86 so it looks like + // non-walkable C frame. Use frame.sender() for java frames. + if (t && t->is_Java_thread()) { + // Catch very first native frame by using stack address. + // For JavaThread stack_base and stack_size should be set. + if (!t->on_local_stack((address)(fr.real_fp() + 1))) { + break; + } + if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) { + RegisterMap map((JavaThread*)t, false); // No update + fr = fr.sender(&map); + } else { + fr = os::get_sender_for_C_frame(&fr); + } + } else { + // is_first_C_frame() does only simple checks for frame pointer, + // it will pass if java compiled code has a pointer in EBP. + if (os::is_first_C_frame(&fr)) break; + fr = os::get_sender_for_C_frame(&fr); + } + } + + if (count > StackPrintLimit) { + st->print_cr("......"); + } + + st->cr(); + } +} + +#ifndef PRODUCT + +extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack + Command c("pns"); + static char buf[O_BUFLEN]; + Thread* t = ThreadLocalStorage::get_thread_slow(); + // Call generic frame constructor (certain arguments may be ignored) + frame fr(sp, fp, pc); + print_native_stack(tty, fr, t, buf, sizeof(buf)); +} + +#endif // !PRODUCT diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/utilities/debug.hpp --- a/src/share/vm/utilities/debug.hpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/utilities/debug.hpp Wed Jan 21 17:07:26 2015 +0000 @@ -265,4 +265,7 @@ void pd_ps(frame f); void pd_obfuscate_location(char *buf, size_t buflen); +class outputStream; +void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size); + #endif // SHARE_VM_UTILITIES_DEBUG_HPP diff -r 0ee548a1cda0 -r 9989538b7507 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Tue Jan 20 13:47:31 2015 -0800 +++ b/src/share/vm/utilities/vmError.cpp Wed Jan 21 17:07:26 2015 +0000 @@ -576,7 +576,7 @@ STEP(120, "(printing native stack)" ) - if (_verbose) { + if (_verbose) { if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) { // We have printed the native stack in platform-specific code // Windows/x64 needs special handling. @@ -584,43 +584,7 @@ frame fr = _context ? os::fetch_frame_from_context(_context) : os::current_frame(); - // see if it's a valid frame - if (fr.pc()) { - st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); - - - int count = 0; - while (count++ < StackPrintLimit) { - fr.print_on_error(st, buf, sizeof(buf)); - st->cr(); - // Compiled code may use EBP register on x86 so it looks like - // non-walkable C frame. Use frame.sender() for java frames. - if (_thread && _thread->is_Java_thread()) { - // Catch very first native frame by using stack address. - // For JavaThread stack_base and stack_size should be set. - if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) { - break; - } - if (fr.is_java_frame()) { - RegisterMap map((JavaThread*)_thread, false); // No update - fr = fr.sender(&map); - } else { - fr = os::get_sender_for_C_frame(&fr); - } - } else { - // is_first_C_frame() does only simple checks for frame pointer, - // it will pass if java compiled code has a pointer in EBP. - if (os::is_first_C_frame(&fr)) break; - fr = os::get_sender_for_C_frame(&fr); - } - } - - if (count > StackPrintLimit) { - st->print_cr("......"); - } - - st->cr(); - } + print_native_stack(st, fr, _thread, buf, sizeof(buf)); } } diff -r 0ee548a1cda0 -r 9989538b7507 test/serviceability/sa/jmap-hashcode/Test8028623.java --- a/test/serviceability/sa/jmap-hashcode/Test8028623.java Tue Jan 20 13:47:31 2015 -0800 +++ b/test/serviceability/sa/jmap-hashcode/Test8028623.java Wed Jan 21 17:07:26 2015 +0000 @@ -33,20 +33,25 @@ import com.oracle.java.testlibrary.JDKToolLauncher; import com.oracle.java.testlibrary.OutputBuffer; +import com.oracle.java.testlibrary.Platform; import com.oracle.java.testlibrary.ProcessTools; import java.io.File; public class Test8028623 { - public static int à = 1; + public static int \u00CB = 1; public static String dumpFile = "heap.out"; public static void main (String[] args) { - System.out.println(Ã); + System.out.println(\u00CB); try { + if (!Platform.shouldSAAttach()) { + System.out.println("SA attach not expected to work - test skipped."); + return; + } int pid = ProcessTools.getProcessId(); JDKToolLauncher jmap = JDKToolLauncher.create("jmap") .addToolArg("-F") diff -r 0ee548a1cda0 -r 9989538b7507 test/testlibrary/com/oracle/java/testlibrary/Platform.java --- a/test/testlibrary/com/oracle/java/testlibrary/Platform.java Tue Jan 20 13:47:31 2015 -0800 +++ b/test/testlibrary/com/oracle/java/testlibrary/Platform.java Wed Jan 21 17:07:26 2015 +0000 @@ -23,12 +23,15 @@ package com.oracle.java.testlibrary; +import com.oracle.java.testlibrary.Utils; + public class Platform { private static final String osName = System.getProperty("os.name"); private static final String dataModel = System.getProperty("sun.arch.data.model"); private static final String vmVersion = System.getProperty("java.vm.version"); private static final String osArch = System.getProperty("os.arch"); private static final String vmName = System.getProperty("java.vm.name"); + private static final String userName = System.getProperty("user.name"); public static boolean isClient() { return vmName.endsWith(" Client VM"); @@ -121,4 +124,56 @@ return osArch; } + /** + * Return a boolean for whether we expect to be able to attach + * the SA to our own processes on this system. + */ + public static boolean shouldSAAttach() throws Exception { + + if (isLinux()) { + return canPtraceAttachLinux(); + } else if (isOSX()) { + return canAttachOSX(); + } else { + // Other platforms expected to work: + return true; + } + } + + /** + * On Linux, first check the SELinux boolean "deny_ptrace" and return false + * as we expect to be denied if that is "1". Then expect permission to attach + * if we are root, so return true. Then return false for an expected denial + * if "ptrace_scope" is 1, and true otherwise. + */ + public static boolean canPtraceAttachLinux() throws Exception { + + // SELinux deny_ptrace: + String deny_ptrace = Utils.fileAsString("/sys/fs/selinux/booleans/deny_ptrace"); + if (deny_ptrace != null && deny_ptrace.contains("1")) { + // ptrace will be denied: + return false; + } + + if (userName.equals("root")) { + return true; + } + + // ptrace_scope: + String ptrace_scope = Utils.fileAsString("/proc/sys/kernel/yama/ptrace_scope"); + if (ptrace_scope != null && ptrace_scope.contains("1")) { + // ptrace will be denied: + return false; + } + + // Otherwise expect to be permitted: + return true; + } + + /** + * On OSX, expect permission to attach only if we are root. + */ + public static boolean canAttachOSX() throws Exception { + return userName.equals("root"); + } } diff -r 0ee548a1cda0 -r 9989538b7507 test/testlibrary/com/oracle/java/testlibrary/Utils.java --- a/test/testlibrary/com/oracle/java/testlibrary/Utils.java Tue Jan 20 13:47:31 2015 -0800 +++ b/test/testlibrary/com/oracle/java/testlibrary/Utils.java Wed Jan 21 17:07:26 2015 +0000 @@ -299,6 +299,35 @@ } /** + * Return the contents of the named file as a single String, + * or null if not found. + * @param filename name of the file to read + * @return String contents of file, or null if file not found. + */ + public static String fileAsString(String filename) { + StringBuilder result = new StringBuilder(); + try { + File file = new File(filename); + if (file.exists()) { + BufferedReader reader = new BufferedReader(new FileReader(file)); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + result.append(line).append("\n"); + } + } else { + // Does not exist: + return null; + } + } catch (Exception e) { + e.printStackTrace(); + } + return result.toString(); + } + + /** * @return Unsafe instance. */ public static synchronized Unsafe getUnsafe() {