8250801: Add clhsdb "threadcontext" command

Reviewed-by: sspitsyn, kevinw
This commit is contained in:
Chris Plummer 2022-01-18 19:21:13 +00:00
parent fd9fb9a4af
commit bdfa15d92c
3 changed files with 167 additions and 5 deletions
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot
test/hotspot/jtreg/serviceability/sa

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -1671,19 +1671,54 @@ public class CommandProcessor {
}
}
},
new Command("threadcontext", "threadcontext [-v] { -a | id }", false) {
public void doit(Tokens t) {
boolean verbose = false;
if (t.countTokens() == 2) {
if (t.nextToken().equals("-v")) {
verbose = true;
} else {
usage();
return;
}
}
if (t.countTokens() != 1) {
usage();
return;
}
String id = t.nextToken();
Threads threads = VM.getVM().getThreads();
boolean all = id.equals("-a");
for (int i = 0; i < threads.getNumberOfThreads(); i++) {
JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(id)) {
out.format("Thread \"%s\" id=%s Address=%s\n",
thread.getThreadName(), bos.toString(), thread.getAddress());
thread.printThreadContextOn(out, verbose);
out.println(" ");
if (!all) return;
}
}
if (!all) {
out.println("Couldn't find thread " + id);
}
}
},
new Command("thread", "thread { -a | id }", false) {
public void doit(Tokens t) {
if (t.countTokens() != 1) {
usage();
} else {
String name = t.nextToken();
String id = t.nextToken();
Threads threads = VM.getVM().getThreads();
boolean all = name.equals("-a");
boolean all = id.equals("-a");
for (int i = 0; i < threads.getNumberOfThreads(); i++) {
JavaThread thread = threads.getJavaThreadAt(i);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
if (all || bos.toString().equals(id)) {
out.println("Thread " + bos.toString() + " Address " + thread.getAddress());
thread.printInfoOn(out);
out.println(" ");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, 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
@ -481,6 +481,25 @@ public class JavaThread extends Thread {
return access.getLastSP(addr);
}
// Print the contents of all registers in the thread's context
public void printThreadContextOn(PrintStream out, boolean verbose){
ThreadContext tc = getThreadProxy().getContext();
for (int r = 0; r < tc.getNumRegisters(); r++) {
Address regAddr = tc.getRegisterAsAddress(r);
System.out.format("%s: %s", tc.getRegisterName(r), regAddr);
if (regAddr == null) {
System.out.println();
} else {
PointerLocation l = PointerFinder.find(regAddr);
if (l.isUnknown()) {
System.out.println();
} else {
System.out.print(": ");
l.printOn(System.out, false, verbose);
}
}
}
}
public void printThreadInfoOn(PrintStream out){
Oop threadOop = this.getThreadObj();

@ -0,0 +1,108 @@
/*
* Copyright (c) 2021, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.test.lib.apps.LingeredApp;
import jtreg.SkippedException;
/**
* @test
* @summary Test clhsdb where command
* @requires vm.hasSA
* @library /test/lib
* @run main/othervm ClhsdbThreadContext
*/
public class ClhsdbThreadContext {
public static void main(String[] args) throws Exception {
System.out.println("Starting ClhsdbThreadContext test");
LingeredApp theApp = null;
try {
ClhsdbLauncher test = new ClhsdbLauncher();
theApp = LingeredApp.startApp();
System.out.println("Started LingeredApp with pid " + theApp.getPid());
// Run threadcontext on all threads
String cmdStr = "threadcontext -a";
List<String> cmds = List.of(cmdStr);
Map<String, List<String>> expStrMap = new HashMap<>();
expStrMap.put(cmdStr, List.of(
"Thread \"Common-Cleaner\"",
"Thread \"Service Thread\"",
"Thread \"Finalizer\"",
"Thread \"SteadyStateThread\"",
"In java stack for thread \"SteadyStateThread\""));
String cmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);
// Run threadcontext on all threads in verbose mode
cmdStr = "threadcontext -v -a";
cmds = List.of(cmdStr);
expStrMap = new HashMap<>();
expStrMap.put(cmdStr, List.of(
"Thread \"Common-Cleaner\"",
"Thread \"Service Thread\"",
"Thread \"Finalizer\"",
"Thread \"SteadyStateThread\""));
Map<String, List<String>> unexpStrMap = new HashMap<>();
unexpStrMap.put(cmdStr, List.of(
"In java stack for thread \"SteadyStateThread\""));
test.run(theApp.getPid(), cmds, expStrMap, unexpStrMap);
// Look for a line like the following and parse the threadID out of it.
// Thread "SteadyStateThread" id=18010 Address=0x000014bf103eaf50
String[] parts = cmdOutput.split("Thread \"SteadyStateThread\" id=");
String[] tokens = parts[1].split(" ");
String threadID = tokens[0];
// Run threadcontext on the SteadyStateThread in verbose mode
cmdStr = "threadcontext -v " + threadID;
cmds = List.of(cmdStr);
expStrMap = new HashMap<>();
expStrMap.put(cmdStr, List.of(
"Thread \"SteadyStateThread\"",
"java.lang.Thread.State: BLOCKED",
"In java stack \\[0x\\p{XDigit}+,0x\\p{XDigit}+,0x\\p{XDigit}+\\] for thread"));
unexpStrMap = new HashMap<>();
unexpStrMap.put(cmdStr, List.of(
"Thread \"Common-Cleaner\"",
"Thread \"Service Thread\"",
"Thread \"Finalizer\""));
test.run(theApp.getPid(), cmds, expStrMap, unexpStrMap);
// Run threadcontext on all threads in verbose mode
} catch (SkippedException se) {
throw se;
} catch (Exception ex) {
throw new RuntimeException("Test ERROR " + ex, ex);
} finally {
LingeredApp.stopApp(theApp);
}
System.out.println("Test PASSED");
}
}