2016-01-14 12:35:21 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015, 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.
|
|
|
|
*/
|
|
|
|
package utils;
|
|
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Scanner;
|
|
|
|
import java.util.regex.MatchResult;
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* jstack default format 2008-03-05 18:36:26 Full thread dump Java HotSpot(TM)
|
|
|
|
* Client VM (11.0-b11 mixed mode):
|
|
|
|
*
|
|
|
|
* "Thread-16" #10 daemon prio=3 os_prio=0 tid=0x0814d800 nid=0x1d runnable
|
|
|
|
* [0xf394d000..0xf394d9f0] java.lang.Thread.State: RUNNABLE at
|
|
|
|
* java.net.SocketInputStream.socketRead0(Native Method) at
|
|
|
|
* java.net.SocketInputStream.read(SocketInputStream.java:129) at
|
|
|
|
* java.net.SocketInputStream.read(SocketInputStream.java:182) at
|
|
|
|
* java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2249)
|
|
|
|
* at
|
|
|
|
* java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2542)
|
|
|
|
* at
|
|
|
|
* java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2552)
|
|
|
|
* at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1297) at
|
|
|
|
* java.io.ObjectInputStream.readObject(ObjectInputStream.java:351) at
|
|
|
|
* tmtools.share.debuggee.DebuggeeProtocolHandler.run(DebuggeeProtocolHandler.java:32)
|
|
|
|
*
|
|
|
|
* Locked ownable synchronizers: - None ....
|
|
|
|
*
|
|
|
|
* Note that os_prio field is optional and will be printed only if JVM was able
|
|
|
|
* to get native thread priority.
|
|
|
|
*/
|
|
|
|
public class DefaultFormat implements Format {
|
|
|
|
|
|
|
|
protected String threadInfoPattern() {
|
|
|
|
return "^\"(.*)\"\\s(#\\d+\\s|)(daemon\\s|)prio=(.+)\\s(os_prio=(.+)\\s|)tid=(.+)\\snid=(.+)\\s("
|
|
|
|
+ Consts.UNKNOWN
|
|
|
|
+ "|runnable|waiting\\son\\scondition|in\\sObject\\.wait\\(\\)|waiting\\sfor\\smonitor\\sentry)((.*))$";
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String methodInfoPattern() {
|
|
|
|
return "^\\s+at\\s(.+)\\((.*?)(\\:|\\))((.*?))\\)?$";
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String extendedStatusPattern() {
|
|
|
|
return "\\s+java\\.lang\\.Thread\\.State\\:\\s((.+))$";
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String jniGlobalRefInfoPattern() {
|
|
|
|
return "^JNI\\sglobal\\sreferences:\\s((.+))$";
|
|
|
|
}
|
|
|
|
|
2016-01-28 11:58:57 +00:00
|
|
|
// Sample string that matches the pattern:
|
|
|
|
// waiting on <0x000000008f64e6d0> (a java.lang.Object)
|
2016-01-14 12:35:21 +00:00
|
|
|
protected String monitorInfoPattern() {
|
|
|
|
return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>\\s\\(((.*))\\)$";
|
|
|
|
}
|
|
|
|
|
2016-01-28 11:58:57 +00:00
|
|
|
// Sample string that matches the pattern:
|
|
|
|
// waiting on <no object reference available>
|
|
|
|
protected String monitorInfoNoObjectRefPattern() {
|
|
|
|
return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>$";
|
|
|
|
}
|
|
|
|
|
2016-01-14 12:35:21 +00:00
|
|
|
protected String vmVersionInfoPattern() {
|
|
|
|
return "Full\\sthread\\sdump\\s.*";
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String ownableSynchronizersPattern() {
|
|
|
|
return "^\\s+\\-\\s(\\<.*\\>\\s\\(((.*))\\)|None)$";
|
|
|
|
}
|
|
|
|
|
|
|
|
public JStack parse(String stack) {
|
|
|
|
JStack result = new JStack();
|
|
|
|
Scanner scanner = new Scanner(stack);
|
|
|
|
|
|
|
|
// parsing thread stacks
|
|
|
|
ThreadStack currentThreadStack = null;
|
|
|
|
MethodInfo currentMethodInfo = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
while (scanner.hasNextLine()) {
|
|
|
|
String line = scanner.nextLine();
|
|
|
|
if (line.matches(threadInfoPattern())) {
|
|
|
|
currentThreadStack = parseThreadInfo(line);
|
|
|
|
result.addThreadStack(currentThreadStack.getThreadName(), currentThreadStack);
|
|
|
|
} else if (line.matches(methodInfoPattern())) {
|
|
|
|
currentMethodInfo = parseMethodInfo(line);
|
|
|
|
currentThreadStack.addMethod(currentMethodInfo);
|
|
|
|
} else if (line.matches(monitorInfoPattern())) {
|
2016-01-28 11:58:57 +00:00
|
|
|
MonitorInfo mi = parseMonitorInfo(line, monitorInfoPattern());
|
|
|
|
currentMethodInfo.getLocks().add(mi);
|
|
|
|
} else if (line.matches(monitorInfoNoObjectRefPattern())) {
|
|
|
|
MonitorInfo mi = parseMonitorInfo(line, monitorInfoNoObjectRefPattern());
|
2016-01-14 12:35:21 +00:00
|
|
|
currentMethodInfo.getLocks().add(mi);
|
|
|
|
} else if (line.matches(extendedStatusPattern())) {
|
|
|
|
currentThreadStack.setExtendedStatus(parseExtendedStatus(line));
|
|
|
|
} else if (line.matches(vmVersionInfoPattern())) {
|
|
|
|
result.setVmVersion(line);
|
|
|
|
} else if (line.matches(ownableSynchronizersPattern())) {
|
|
|
|
currentThreadStack.getLockOSList().add(parseLockInfo(line));
|
|
|
|
} else if (line.matches(jniGlobalRefInfoPattern())) {
|
|
|
|
result.setJniGlobalReferences(parseJNIGlobalRefs(line));
|
|
|
|
} else if (line.length() != 0) {
|
|
|
|
System.err.println("[Warning] Unknown string: " + line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scanner.close();
|
|
|
|
|
|
|
|
} catch (NullPointerException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
throw new RuntimeException("Unexpected format in jstack output");
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-01-28 11:58:57 +00:00
|
|
|
private MonitorInfo parseMonitorInfo(String line, String pattern) {
|
2016-01-14 12:35:21 +00:00
|
|
|
Scanner s = new Scanner(line);
|
2016-01-28 11:58:57 +00:00
|
|
|
s.findInLine(pattern);
|
2016-01-14 12:35:21 +00:00
|
|
|
MonitorInfo mi = new MonitorInfo();
|
|
|
|
MatchResult res = s.match();
|
|
|
|
|
|
|
|
mi.setType(res.group(1));
|
|
|
|
mi.setMonitorAddress(res.group(2));
|
2016-01-28 11:58:57 +00:00
|
|
|
if (res.groupCount() > 2) {
|
|
|
|
mi.setMonitorClass(res.group(3));
|
|
|
|
}
|
2016-01-14 12:35:21 +00:00
|
|
|
return mi;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String parseExtendedStatus(String line) {
|
|
|
|
Scanner s = new Scanner(line);
|
|
|
|
s.findInLine(extendedStatusPattern());
|
|
|
|
String result = s.match().group(1);
|
|
|
|
s.close();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String parseJNIGlobalRefs(String line) {
|
|
|
|
Scanner s = new Scanner(line);
|
|
|
|
s.findInLine(jniGlobalRefInfoPattern());
|
|
|
|
String result = s.match().group(1);
|
|
|
|
s.close();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected ThreadStack parseThreadInfo(String threadInfo) {
|
|
|
|
Scanner s = new Scanner(threadInfo);
|
|
|
|
ThreadStack result = new ThreadStack();
|
|
|
|
|
|
|
|
// parsing thread info
|
|
|
|
s.findInLine(threadInfoPattern());
|
|
|
|
MatchResult res = s.match();
|
|
|
|
|
|
|
|
result.setThreadName(res.group(1));
|
|
|
|
|
|
|
|
result.setType(res.group(3));
|
|
|
|
|
|
|
|
result.setPriority(res.group(4));
|
|
|
|
result.setTid(res.group(7));
|
|
|
|
result.setNid(res.group(8));
|
|
|
|
result.setStatus(res.group(9));
|
|
|
|
|
|
|
|
s.close();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected MethodInfo parseMethodInfo(String line) {
|
|
|
|
|
|
|
|
MethodInfo result = new MethodInfo();
|
|
|
|
Scanner s = new Scanner(line);
|
|
|
|
|
|
|
|
s.findInLine(methodInfoPattern());
|
|
|
|
MatchResult rexp = s.match();
|
|
|
|
if (rexp.group(4) != null && rexp.group(4).length() > 0) {
|
|
|
|
// line " at tmtools.jstack.share.utils.Utils.sleep(Utils.java:29)"
|
|
|
|
result.setName(rexp.group(1));
|
|
|
|
result.setCompilationUnit(rexp.group(2));
|
|
|
|
result.setLine(rexp.group(4));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// line " at java.lang.Thread.sleep(Native Method)"
|
|
|
|
result.setName(rexp.group(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
s.close();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String dumpStackTraces() {
|
|
|
|
StringBuffer result = new StringBuffer();
|
|
|
|
Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
|
|
|
|
|
|
|
|
// adding data and vm version
|
|
|
|
result.append(Consts.UNKNOWN + "\n");
|
|
|
|
result.append(Consts.UNKNOWN + "\n\n");
|
|
|
|
|
|
|
|
for (Thread t : stacks.keySet()) {
|
|
|
|
|
|
|
|
result.append("\"" + t.getName() + "\"");
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
|
|
|
|
// status
|
|
|
|
if (t.isDaemon()) {
|
|
|
|
result.append("daemon");
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
// priority
|
|
|
|
result.append("prio=" + t.getPriority());
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
|
|
|
|
// tid
|
|
|
|
result.append("tid=" + Consts.UNKNOWN);
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
|
|
|
|
// nid
|
|
|
|
result.append("nid=" + Consts.UNKNOWN);
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
|
|
|
|
// status
|
|
|
|
result.append(Consts.UNKNOWN);
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
|
|
|
|
result.append("\n");
|
|
|
|
|
|
|
|
// extended status
|
|
|
|
result.append(" java.lang.Thread.State: "
|
|
|
|
+ String.valueOf(Thread.currentThread().getState()));
|
|
|
|
result.append(Consts.SEPARATOR);
|
|
|
|
result.append("\n");
|
|
|
|
|
|
|
|
for (StackTraceElement st : stacks.get(t)) {
|
|
|
|
result.append(" at " + st.toString() + "\n");
|
|
|
|
}
|
|
|
|
result.append("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append(Consts.JNI_GLOBAL_REF + Consts.UNKNOWN + "\n");
|
|
|
|
return result.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected LockInfo parseLockInfo(String line) {
|
|
|
|
LockInfo res = new LockInfo();
|
|
|
|
|
|
|
|
Scanner s = new Scanner(line);
|
|
|
|
s.findInLine(ownableSynchronizersPattern());
|
|
|
|
|
|
|
|
MatchResult matchRes = s.match();
|
|
|
|
String lock = matchRes.group(1).equals("None") ? matchRes.group(1) : matchRes.group(2);
|
|
|
|
res.setLock(lock);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|