8292201: serviceability/sa/ClhsdbThreadContext.java fails with "'Thread "Common-Cleaner"' missing from stdout/stderr"

Reviewed-by: amenkov, sspitsyn
This commit is contained in:
Chris Plummer 2022-09-03 16:06:25 +00:00
parent a366e82aa1
commit 767262e67c
11 changed files with 73 additions and 175 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -31,8 +31,8 @@ public class AddressException extends RuntimeException {
this.addr = addr;
}
public AddressException(String detail, long addr) {
super(detail);
public AddressException(String message, long addr) {
super(message);
this.addr = addr;
}
@ -41,6 +41,11 @@ public class AddressException extends RuntimeException {
}
public String getMessage() {
return Long.toHexString(addr);
String msg = super.getMessage();
if (msg != null) {
return msg;
} else {
return Long.toHexString(addr);
}
}
}

View File

@ -64,6 +64,7 @@ public abstract class DebuggerBase implements Debugger {
protected int narrowKlassShift; // shift to decode compressed klass ptrs.
// Should be initialized if desired by calling initCache()
private PageCache cache;
private long pageSize;
// State for faster accessors that don't allocate memory on each read
private boolean useFastAccessors;
@ -177,6 +178,7 @@ public abstract class DebuggerBase implements Debugger {
cache but may not be overridden */
protected final void initCache(long pageSize, long maxNumPages) {
cache = new PageCache(pageSize, maxNumPages, new Fetcher());
this.pageSize = pageSize;
if (machDesc != null) {
bigEndian = machDesc.isBigEndian();
}
@ -232,6 +234,19 @@ public abstract class DebuggerBase implements Debugger {
}
}
/** If an address for a 64-bit value starts on the last 32-bit word of a
page, then we can't use the page cache to read it because it will cause
an ArrayIndexOutOfBoundsException when reading past the end of the page. */
private boolean canUsePageCacheFor64bitRead(long address) {
long pageMask = ~(pageSize - 1);
if ((address & pageMask) != ((address + 4) & pageMask)) {
// This address starts on the last 32-bit word of the page.
// Cannot use the page cache in that case.
return false;
}
return true;
}
public boolean readJBoolean(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
@ -256,8 +271,6 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public char readJChar(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
@ -270,13 +283,11 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public double readJDouble(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
utils.checkAlignment(address, jdoubleSize);
if (useFastAccessors) {
if (useFastAccessors && canUsePageCacheFor64bitRead(address)) {
return cache.getDouble(address, bigEndian);
} else {
byte[] data = readBytes(address, jdoubleSize);
@ -284,8 +295,6 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public float readJFloat(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
@ -298,8 +307,6 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public int readJInt(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
@ -312,13 +319,11 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public long readJLong(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
utils.checkAlignment(address, jlongSize);
if (useFastAccessors) {
if (useFastAccessors && canUsePageCacheFor64bitRead(address)) {
return cache.getLong(address, bigEndian);
} else {
byte[] data = readBytes(address, jlongSize);
@ -326,8 +331,6 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public short readJShort(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
@ -340,13 +343,11 @@ public abstract class DebuggerBase implements Debugger {
}
}
// NOTE: assumes value does not span pages (may be bad assumption on
// Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
public long readCInteger(long address, long numBytes, boolean isUnsigned)
throws UnmappedAddressException, UnalignedAddressException {
checkConfigured();
utils.checkAlignment(address, numBytes);
if (useFastAccessors) {
if (useFastAccessors && (numBytes != 8 || canUsePageCacheFor64bitRead(address))) {
if (isUnsigned) {
switch((int) numBytes) {
case 1: return cache.getByte(address) & 0xFF;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2022, 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
@ -29,10 +29,13 @@ package sun.jvm.hotspot.debugger;
public class DebuggerUtilities {
protected long addressSize;
protected boolean isBigEndian;
protected boolean supports32bitAlignmentOf64bitTypes;
public DebuggerUtilities(long addressSize, boolean isBigEndian) {
public DebuggerUtilities(long addressSize, boolean isBigEndian,
boolean supports32bitAlignmentOf64bitTypes) {
this.addressSize = addressSize;
this.isBigEndian = isBigEndian;
this.supports32bitAlignmentOf64bitTypes = supports32bitAlignmentOf64bitTypes;
}
public String addressValueToString(long address) {
@ -53,6 +56,13 @@ public class DebuggerUtilities {
}
public void checkAlignment(long address, long alignment) {
// Allow 32-bit alignment for 64-bit types on some hosts.
if (supports32bitAlignmentOf64bitTypes) {
if (address % 4 == 0) {
return;
}
}
if (address % alignment != 0) {
throw new UnalignedAddressException("Trying to read at address: " +
addressValueToString(address) +

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -56,4 +56,10 @@ public interface MachineDescription extends Serializable {
/** Indicates whether the underlying machine supports the LP64 data
model (currently only SPARC/64). */
public boolean isLP64();
/** Indicates whether the underlying machine supports 64-bit types
that are only 32-bit aligned. */
default public boolean supports32bitAlignmentOf64bitTypes() {
return false;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -32,4 +32,8 @@ public class MachineDescriptionIntelX86 extends MachineDescriptionTwosComplement
public boolean isBigEndian() {
return false;
}
public boolean supports32bitAlignmentOf64bitTypes() {
return true;
}
}

View File

@ -188,20 +188,8 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
boolean useCache) throws DebuggerException {
this.machDesc = machDesc;
utils = new DebuggerUtilities(machDesc.getAddressSize(),
machDesc.isBigEndian()) {
public void checkAlignment(long address, long alignment) {
// Need to override default checkAlignment because we need to
// relax alignment constraints on Bsd/x86
if ( (address % alignment != 0)
&&(alignment != 8 || address % 4 != 0)) {
throw new UnalignedAddressException(
"Trying to read at address: "
+ addressValueToString(address)
+ " with alignment: " + alignment,
address);
}
}
};
machDesc.isBigEndian(),
machDesc.supports32bitAlignmentOf64bitTypes());
if (useCache) {
// This is a cache of 64k of 4K pages, or 256 MB.
@ -484,30 +472,6 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
}
}
/** Need to override this to relax alignment checks on x86. */
public long readCInteger(long address, long numBytes, boolean isUnsigned)
throws UnmappedAddressException, UnalignedAddressException {
// Only slightly relaxed semantics -- this is a hack, but is
// necessary on x86 where it seems the compiler is
// putting some global 64-bit data on 32-bit boundaries
if (numBytes == 8) {
utils.checkAlignment(address, 4);
} else {
utils.checkAlignment(address, numBytes);
}
byte[] data = readBytes(address, numBytes);
return utils.dataToCInteger(data, isUnsigned);
}
// Overridden from DebuggerBase because we need to relax alignment
// constraints on x86
public long readJLong(long address)
throws UnmappedAddressException, UnalignedAddressException {
utils.checkAlignment(address, jintSize);
byte[] data = readBytes(address, jlongSize);
return utils.dataToJLong(data, jlongSize);
}
//----------------------------------------------------------------------
// Address access. Can not be package private, but should only be
// accessed by the architecture-specific subpackages.

View File

@ -207,20 +207,8 @@ public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger {
boolean useCache) throws DebuggerException {
this.machDesc = machDesc;
utils = new DebuggerUtilities(machDesc.getAddressSize(),
machDesc.isBigEndian()) {
public void checkAlignment(long address, long alignment) {
// Need to override default checkAlignment because we need to
// relax alignment constraints on Linux/x86
if ( (address % alignment != 0)
&&(alignment != 8 || address % 4 != 0)) {
throw new UnalignedAddressException(
"Trying to read at address: "
+ addressValueToString(address)
+ " with alignment: " + alignment,
address);
}
}
};
machDesc.isBigEndian(),
machDesc.supports32bitAlignmentOf64bitTypes());
if (useCache) {
// This is a cache of 64k of 4K pages, or 256 MB.
@ -541,30 +529,6 @@ public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger {
}
}
/** Need to override this to relax alignment checks on x86. */
public long readCInteger(long address, long numBytes, boolean isUnsigned)
throws UnmappedAddressException, UnalignedAddressException {
// Only slightly relaxed semantics -- this is a hack, but is
// necessary on x86 where it seems the compiler is
// putting some global 64-bit data on 32-bit boundaries
if (numBytes == 8) {
utils.checkAlignment(address, 4);
} else {
utils.checkAlignment(address, numBytes);
}
byte[] data = readBytes(address, numBytes);
return utils.dataToCInteger(data, isUnsigned);
}
// Overridden from DebuggerBase because we need to relax alignment
// constraints on x86
public long readJLong(long address)
throws UnmappedAddressException, UnalignedAddressException {
utils.checkAlignment(address, jintSize);
byte[] data = readBytes(address, jlongSize);
return utils.dataToJLong(data, jlongSize);
}
//----------------------------------------------------------------------
// Address access. Can not be package private, but should only be
// accessed by the architecture-specific subpackages.

View File

@ -43,27 +43,24 @@ import sun.jvm.hotspot.debugger.remote.ppc64.*;
public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger {
private RemoteDebugger remoteDebugger;
private RemoteThreadFactory threadFactory;
private boolean unalignedAccessesOkay = false;
private static final int cacheSize = 256 * 1024 * 1024; // 256 MB
public RemoteDebuggerClient(RemoteDebugger remoteDebugger) throws DebuggerException {
super();
try {
this.remoteDebugger = remoteDebugger;
machDesc = remoteDebugger.getMachineDescription();
utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
this.machDesc = remoteDebugger.getMachineDescription();
utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian(),
machDesc.supports32bitAlignmentOf64bitTypes());
int cachePageSize = 4096;
int cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
String cpu = remoteDebugger.getCPU();
if (cpu.equals("x86")) {
threadFactory = new RemoteX86ThreadFactory(this);
unalignedAccessesOkay = true;
} else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
threadFactory = new RemoteAMD64ThreadFactory(this);
unalignedAccessesOkay = true;
} else if (cpu.equals("ppc64")) {
threadFactory = new RemotePPC64ThreadFactory(this);
unalignedAccessesOkay = true;
} else {
try {
Class tf = Class.forName("sun.jvm.hotspot.debugger.remote." +
@ -74,7 +71,6 @@ public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger {
} catch (Exception e) {
throw new DebuggerException("Thread access for CPU architecture " + cpu + " not yet supported");
}
unalignedAccessesOkay = false;
}
// Cache portion of the remote process's address space.
@ -228,41 +224,6 @@ public class RemoteDebuggerClient extends DebuggerBase implements JVMDebugger {
}
}
/** Need to override this to relax alignment checks on x86. */
public long readCInteger(long address, long numBytes, boolean isUnsigned)
throws UnmappedAddressException, UnalignedAddressException {
if (!unalignedAccessesOkay) {
utils.checkAlignment(address, numBytes);
} else {
// Only slightly relaxed semantics -- this is a hack, but is
// necessary on x86 where it seems the compiler is
// putting some global 64-bit data on 32-bit boundaries
if (numBytes == 8) {
utils.checkAlignment(address, 4);
} else {
utils.checkAlignment(address, numBytes);
}
}
byte[] data = readBytes(address, numBytes);
return utils.dataToCInteger(data, isUnsigned);
}
// Overridden from DebuggerBase because we need to relax alignment
// constraints on x86
public long readJLong(long address)
throws UnmappedAddressException, UnalignedAddressException {
// FIXME: allow this to be configurable. Undesirable to add a
// dependency on the runtime package here, though, since this
// package should be strictly underneath it.
if (unalignedAccessesOkay) {
utils.checkAlignment(address, jintSize);
} else {
utils.checkAlignment(address, jlongSize);
}
byte[] data = readBytes(address, jlongSize);
return utils.dataToJLong(data, jlongSize);
}
//--------------------------------------------------------------------------------
// Implementation of JVMDebugger interface

View File

@ -95,20 +95,8 @@ public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger
public WindbgDebuggerLocal(MachineDescription machDesc,
boolean useCache) throws DebuggerException {
this.machDesc = machDesc;
utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian()) {
public void checkAlignment(long address, long alignment) {
// Need to override default checkAlignment because we need to
// relax alignment constraints on Windows/x86
if ( (address % alignment != 0)
&&(alignment != 8 || address % 4 != 0)) {
throw new UnalignedAddressException(
"Trying to read at address: "
+ addressValueToString(address)
+ " with alignment: " + alignment,
address);
}
}
};
utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian(),
machDesc.supports32bitAlignmentOf64bitTypes());
String cpu = PlatformInfo.getCPU();
if (cpu.equals("x86")) {
@ -269,22 +257,6 @@ public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger
return getThreadIdFromSysId0(sysId);
}
//----------------------------------------------------------------------
// Overridden from DebuggerBase because we need to relax alignment
// constraints on x86
public long readJLong(long address)
throws UnmappedAddressException, UnalignedAddressException {
checkJavaConfigured();
// FIXME: allow this to be configurable. Undesirable to add a
// dependency on the runtime package here, though, since this
// package should be strictly underneath it.
// utils.checkAlignment(address, jlongSize);
utils.checkAlignment(address, jintSize);
byte[] data = readBytes(address, jlongSize);
return utils.dataToJLong(data, jlongSize);
}
//--------------------------------------------------------------------------------
// Internal routines (for implementation of WindbgAddress).
// These must not be called until the MachineDescription has been set up.

View File

@ -217,6 +217,15 @@ public class ClhsdbFindPC {
expStrMap.put(cmdStr, List.of("Is of type JavaThread"));
runTest(withCore, cmds, expStrMap);
// Use findpc on an address that is only 4 byte aligned and is the
// last 4 bytes of a 4k page. This is for testing JDK-8292201.
String badAddress = tid.substring(0, tid.length() - 3) + "ffc";
cmdStr = "findpc " + badAddress;
cmds = List.of(cmdStr);
expStrMap = new HashMap<>();
expStrMap.put(cmdStr, List.of("In unknown location"));
runTest(withCore, cmds, expStrMap);
// Run findpc on a java stack address. We can find one in the jstack output.
// "main" #1 prio=5 tid=... nid=0x277e0 waiting on condition [0x0000008025aef000]
// The stack address is the last word between the brackets.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, 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
@ -71,12 +71,14 @@ public class JShellHeapDumpTest {
launcher.addToolArg("--pid=" + Long.toString(jShellPID));
ProcessBuilder processBuilder = SATestUtils.createProcessBuilder(launcher);
long startTime = System.currentTimeMillis();
OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
System.out.println("jhsdb jmap stdout:");
System.out.println(output.getStdout());
System.out.println("jhsdb jmap stderr:");
System.out.println(output.getStderr());
System.out.println("###### End of all output:");
long elapsedTime = System.currentTimeMillis() - startTime;
System.out.println("###### End of all output which took " + elapsedTime + "ms");
output.shouldHaveExitValue(0);
} catch (Exception ex) {
throw new RuntimeException("Test ERROR " + ex, ex);