Path: blob/master/test/hotspot/jtreg/serviceability/sa/ClhsdbInspect.java
41152 views
/*1* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 819298526* @summary Test the clhsdb 'inspect' command27* @requires vm.hasSA28* @library /test/lib29* @run main/othervm/timeout=480 ClhsdbInspect30*/3132import java.util.HashMap;33import java.util.List;34import java.util.Map;35import java.util.ArrayList;36import jdk.test.lib.apps.LingeredApp;37import jtreg.SkippedException;3839public class ClhsdbInspect {4041public static void main(String[] args) throws Exception {42System.out.println("Starting the ClhsdbInspect test");4344LingeredAppWithLock theApp = null;45try {46ClhsdbLauncher test = new ClhsdbLauncher();4748theApp = new LingeredAppWithLock();49LingeredApp.startApp(theApp);50System.out.println("Started LingeredApp with pid " + theApp.getPid());5152// Run the 'jstack -v' command to get the address of a Method*,53// the oop address of a java.lang.ref.ReferenceQueue$Lock54// and the oop address of a java.lang.Class object55List<String> cmds = List.of("jstack -v");5657String jstackOutput = test.run(theApp.getPid(), cmds, null, null);5859Map<String, String> tokensMap = new HashMap<>();60tokensMap.put("(a java.lang.Class for LingeredAppWithLock)",61"instance of Oop for java/lang/Class");62tokensMap.put("Method*=", "Type is Method");63tokensMap.put("(a java.lang.ref.ReferenceQueue$Lock)",64"instance of Oop for java/lang/ref/ReferenceQueue\\$Lock");6566String[] lines = jstackOutput.split("\\R");6768for (String key: tokensMap.keySet()) {69cmds = new ArrayList<String>();70Map<String, List<String>> expStrMap = new HashMap<>();7172String addressString = null;73for (String line : lines) {74if (line.contains(key)) {75// Escape the token "Method*=" because the split method uses76// a regex, not just a straight String.77String escapedKey = key.replace("*","\\*");78String[] words = line.split(escapedKey+"|[ ]");79for (String word : words) {80word = word.replace("<","").replace(">","");81if (word.startsWith("0x")) {82addressString = word;83break;84}85}86if (addressString != null)87break;88}89}9091String cmd = "inspect " + addressString;92cmds.add(cmd);93expStrMap.put(cmd, List.of(tokensMap.get(key)));94test.run(theApp.getPid(), cmds, expStrMap, null);95}9697// This part is testing JDK-8261269. When inspecting a java object, we want to make98// sure the address is not printed twice and that "Oop for ..." is not printed twice.99//100// The goal of this test is to dump the Class instance for java.lang.System. It contains101// some Oop statics, and that's where the redundant "Oop for..." was noticed. The script102// looks something like this:103//104// hsdb> class java.lang.System105// java/lang/System @0x000000080000f388106//107// hsdb> inspect 0x000000080000f388108// Type is InstanceKlass (size of 480)109// ...110// OopHandle Klass::_java_mirror: OopHandle @ 0x000000080000f400111// ...112//113// hsdb> examine 0x000000080000f400114// 0x000000080000f400: 0x00007fd8b812e5e8115//116// hsdb> examine 0x00007fd8b812e5e8117// 0x00007fd8b812e5e8: 0x00000007fef00770118//119// hsdb> inspect 0x00000007fef00770120// instance of Oop for java/lang/Class @ 0x00000007fef00770 @ 0x00000007fef00770 (size = 160)121// in: Oop for java/io/BufferedInputStream @ 0x0000000082005b08 Oop for java/io/BufferedInputStream @ 0x0000000082005b08122// out: Oop for java/io/PrintStream @ 0x0000000082007b60 Oop for java/io/PrintStream @ 0x0000000082007b60123// err: Oop for java/io/PrintStream @ 0x000000008200e0c8 Oop for java/io/PrintStream @ 0x000000008200e0c8124125String cmd;126Map<String, List<String>> expStrMap;127Map<String, List<String>> unexpStrMap;128129// Start with the "class java.lang.System"130cmd = "class java.lang.System";131cmds = List.of(cmd);132expStrMap = new HashMap<>();133expStrMap.put(cmd, List.of("java.lang.System @0x"));134String classCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);135136// "inspect" the address produced by the "class java.lang.System". This is the InstanceKlass.137String classAddress = classCmdOutput.substring(classCmdOutput.indexOf("@0x")+1);138lines = classAddress.split("\\R");139classAddress = lines[0];140cmd = "inspect " + classAddress;141cmds = List.of(cmd);142expStrMap = new HashMap<>();143expStrMap.put(cmd, List.of("Type is InstanceKlass", "Klass::_java_mirror: OopHandle @"));144String inspectCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);145146// Get the Klass::_java_mirror value from the InstanceKlass147String mirrorPattern = "Klass::_java_mirror: OopHandle @ ";148String mirrorAddress = inspectCmdOutput.substring(149inspectCmdOutput.indexOf(mirrorPattern) + mirrorPattern.length());150lines = mirrorAddress.split("\\R");151mirrorAddress = lines[0];152153// Use "examine" to do an indirection of the _java_mirror.154cmd = "examine " + mirrorAddress;155cmds = List.of(cmd);156expStrMap = new HashMap<>();157expStrMap.put(cmd, List.of(mirrorAddress + ": 0x"));158String examineCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);159String examineResult = examineCmdOutput.substring(examineCmdOutput.indexOf(": 0x")+2);160lines = examineResult.split("\\R");161examineResult = lines[0].trim(); // examine leaves a trailing space162163// Do another indirection using "examine" to get to the address of the Class instance.164cmd = "examine " + examineResult;165cmds = List.of(cmd);166expStrMap = new HashMap<>();167expStrMap.put(cmd, List.of(examineResult + ": 0x"));168examineCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);169examineResult = examineCmdOutput.substring(examineCmdOutput.indexOf(": 0x")+2);170lines = examineResult.split("\\R");171examineResult = lines[0].trim(); // examine leaves a trailing space172173// inspect the Class instance174String instanceOfString = "instance of Oop for java/lang/Class @ ";175String staticFieldString = "Oop for java/io/BufferedInputStream @";176cmd = "inspect " + examineResult;177cmds = List.of(cmd);178expStrMap = new HashMap<>();179expStrMap.put(cmd, List.of(instanceOfString + examineResult,180"in: " + staticFieldString));181unexpStrMap = new HashMap<>();182// Make sure we don't see the address of the class intance twice, and make sure183// we don't see "Oop for ..." twice for the "in" static field.184unexpStrMap.put(cmd, List.of(185instanceOfString + examineResult + " @ " + examineResult,186"in: " + staticFieldString + " .* " + staticFieldString));187inspectCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, unexpStrMap);188} catch (SkippedException e) {189throw e;190} catch (Exception ex) {191throw new RuntimeException("Test ERROR " + ex, ex);192} finally {193LingeredApp.stopApp(theApp);194}195System.out.println("Test PASSED");196}197}198199200