Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java
41161 views
/*1* Copyright (c) 2011, 2019, 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*/2223package vm.mlvm.share.jdi;2425import java.util.Arrays;26import java.util.HashMap;27import java.util.List;28import java.util.Map;2930import nsk.share.jdi.Binder;31import nsk.share.jdi.Debugee;32import vm.mlvm.share.Env;33import vm.mlvm.share.MlvmTest;34import vm.mlvm.share.jpda.StratumUtils;35import vm.share.options.Option;3637import com.sun.jdi.AbsentInformationException;38import com.sun.jdi.IncompatibleThreadStateException;39import com.sun.jdi.LocalVariable;40import com.sun.jdi.Location;41import com.sun.jdi.Method;42import com.sun.jdi.ReferenceType;43import com.sun.jdi.StackFrame;44import com.sun.jdi.ThreadReference;45import com.sun.jdi.Value;46import com.sun.jdi.VirtualMachine;47import com.sun.jdi.VMDisconnectedException;48import com.sun.jdi.event.BreakpointEvent;49import com.sun.jdi.event.ClassPrepareEvent;50import com.sun.jdi.event.Event;51import com.sun.jdi.event.EventIterator;52import com.sun.jdi.event.EventQueue;53import com.sun.jdi.event.EventSet;54import com.sun.jdi.event.StepEvent;55import com.sun.jdi.event.VMDisconnectEvent;56import com.sun.jdi.request.BreakpointRequest;57import com.sun.jdi.request.ClassPrepareRequest;58import com.sun.jdi.request.EventRequest;59import com.sun.jdi.request.EventRequestManager;60import com.sun.jdi.request.StepRequest;6162/**63* Option value syntax:64*65* <pre>66* breakpoints := breakpoint breakpoints?67* breakpoint := implicitOpt? methodName options? stratum? subBreakpoints?68*69* implicitOpt := "~"70*71* methodName := STRING72* methodName := className "." STRING73* className := STRING74*75* options :=76* options := ":" option options77* option := lineOption | requiredHitsOption | stepsToTraceOption78* lineOption := "L" INTEGER // Line number79* requiredHitsOption := "H" INTEGER | "H*" // Required number of hits80* stepsToTraceOption := "S" INTEGER // Steps to trace when this breakpoint is hit81*82* stratum := "/" stratumName "=" stratumSourceName ":" stratumSourceLine // Also check stratum information when this breakpoint is hit83* stratumName := STRING84* stratumSourceName := STRING85* stratumSourceLine := INTEGER86*87* subBreakpoints := "=>(" breakpoints ")" // subBreakpoints are only set when its main breakpoint is hit.88* </pre>89*/9091public abstract class JDIBreakpointTest extends MlvmTest {9293@Option(name="debugger.debuggeeClass", default_value="", description="Debuggee class name")94public String _debuggeeClass = "DEBUGGEE-CLASS-NOT-DEFINED";9596@Option(name="debugger.terminateWhenAllBPHit", default_value="", description="Hang up in specified point")97public boolean _terminateWhenAllBreakpointsHit;9899protected static int _jdiEventWaitTimeout = 3000;100101private static final int MAX_EVENT_COUNT = 50000;102103private static final int SHORT_STACK_TRACE_FRAMES_NUM = 2;104105protected VirtualMachine _vm;106protected EventQueue _eventQueue;107108private abstract static class BreakpointListIterator {109List<BreakpointInfo> _biList;110111public BreakpointListIterator(List<BreakpointInfo> biList) {112_biList = biList;113}114115public Object go() throws Throwable {116return iterate(_biList);117}118119public Object iterate(List<BreakpointInfo> biList) throws Throwable {120for ( BreakpointInfo bi : biList ) {121Object result = apply(bi);122if ( result != null )123return result;124125if ( bi.subBreakpoints != null ) {126result = iterate(bi.subBreakpoints);127if ( result != null )128return result;129}130}131132return null;133}134135protected abstract Object apply(BreakpointInfo bi) throws Throwable;136}137138protected String getDebuggeeClassName() throws Throwable {139String debuggeeClass = _debuggeeClass.trim();140if ( debuggeeClass == null || debuggeeClass.isEmpty() )141throw new Exception("Please specify debuggee class name");142143return debuggeeClass;144}145146protected abstract List<BreakpointInfo> getBreakpoints(String debuggeeClassName);147148protected boolean getTerminateWhenAllBPHit() {149return _terminateWhenAllBreakpointsHit;150}151152protected void breakpointEventHook(BreakpointEvent bpe) {}153protected void stepEventHook(StepEvent se) {}154protected void classPrepareEventHook(ClassPrepareEvent cpe) {}155protected void eventHook(Event e) {}156157@Override158public boolean run() throws Throwable {159JDIBreakpointTest._jdiEventWaitTimeout = getArgumentParser().getWaitTime() * 60000;160161boolean terminateWhenAllBPHit = getTerminateWhenAllBPHit();162163final String debuggeeClass = getDebuggeeClassName();164165Binder binder = new Binder((ArgumentHandler) getArgumentParser(), getLog());166167Debugee debuggee = binder.bindToDebugee(debuggeeClass);168if (debuggee == null)169throw new Exception("Can't launch debuggee");170171debuggee.redirectOutput(getLog());172173_vm = debuggee.VM();174_eventQueue = _vm.eventQueue();175EventRequestManager erm = _vm.eventRequestManager();176177// Breakpoints178179final List<BreakpointInfo> breakpoints = getBreakpoints(debuggeeClass);180181final HashMap<String, ClassPrepareRequest> bpClassNames = new HashMap<String, ClassPrepareRequest>();182183new BreakpointListIterator(breakpoints) {184@Override protected Object apply(BreakpointInfo bi) {185if ( bi.className.isEmpty() )186bi.className = debuggeeClass;187bpClassNames.put(bi.className, null);188return null;189}190}.go();191192for (String className : bpClassNames.keySet()) {193Env.traceNormal("Requesting ClassPrepareEvent for [" + className + "]");194195ClassPrepareRequest cpReq = erm.createClassPrepareRequest();196cpReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);197cpReq.addClassFilter(className);198cpReq.enable();199200bpClassNames.put(className, cpReq);201}202203_vm.resume();204205StepRequest currentStepReq = null;206int stepsToTrace = 0;207int stepCount = 0;208boolean stop = false;209210EVENT_LOOP: while (!stop) {211EventIterator ei = getNextEvent();212213Map<Location, ThreadReference> currentLocations = new HashMap<Location, ThreadReference>();214215while (ei.hasNext()) {216Event e = ei.next();217Env.traceVerbose("Got JDI event: " + e);218eventHook(e);219if (e instanceof VMDisconnectEvent)220break EVENT_LOOP;221222ThreadReference thread = null;223Location location = null;224boolean fullStackTrace = false;225226if (e instanceof ClassPrepareEvent) {227ClassPrepareEvent cpe = (ClassPrepareEvent) e;228classPrepareEventHook(cpe);229230ReferenceType classRef = cpe.referenceType();231232setBreakpoints(erm, breakpoints, classRef);233234} else if (e instanceof BreakpointEvent) {235236BreakpointEvent bpe = (BreakpointEvent) e;237breakpointEventHook(bpe);238thread = bpe.thread();239location = bpe.location();240fullStackTrace = true;241242} else if (e instanceof StepEvent) {243244StepEvent se = (StepEvent) e;245stepEventHook(se);246thread = se.thread();247location = se.location();248}249250if (thread != null) {251try {252Env.traceDebug("Event thread suspends: " + thread.suspendCount());253if (thread.suspendCount() > 0)254Env.traceDebug("Stack trace:" + getStackTraceStr(thread.frames(), fullStackTrace));255256currentLocations.put(location, thread);257258} catch (IncompatibleThreadStateException ex) {259Env.traceNormal("Exception: ", ex);260}261}262263if (++stepCount > MAX_EVENT_COUNT) {264Env.display("Maximum number of events reached ("265+ MAX_EVENT_COUNT + ") for this test. Exiting.");266stop = true;267}268}269270for (Map.Entry<Location, ThreadReference> e : currentLocations.entrySet()) {271final Location location = e.getKey();272final ThreadReference thread = e.getValue();273274BreakpointInfo bpInfo = (BreakpointInfo) new BreakpointListIterator(breakpoints) {275@Override protected Object apply(BreakpointInfo bi) throws Throwable {276if ( location.method().name().equals(bi.methodName) && location.codeIndex() == bi.bci )277return bi;278else279return null;280}281}.go();282283int s = 0;284285if (bpInfo != null) {286Env.traceNormal("Execution hit our breakpoint: [" + bpInfo.methodName + ":" + bpInfo.methodLine + "] on step " + stepCount);287288bpInfo.hits++;289s = bpInfo.stepsToTrace;290291if (bpInfo.stratumInfo != null) {292if ( ! StratumUtils.checkStratum(location, bpInfo.stratumInfo) )293markTestFailed("Stratum " + bpInfo.stratumInfo + " mismatch");294}295296if ( bpInfo.subBreakpoints != null ) {297Env.traceNormal("Enabling sub-breakpoints");298for ( BreakpointInfo subBP : bpInfo.subBreakpoints ) {299if ( subBP.type == BreakpointInfo.Type.IMPLICIT )300continue;301302if ( subBP.bpReq == null ) {303Env.complain("Breakpoint " + subBP + " was not set. Skipping.");304continue;305}306307if ( subBP.bpReq.isEnabled() ) {308Env.traceVerbose("Breakpoint " + subBP + " is already enabled. Skipping.");309continue;310}311312subBP.bpReq.enable();313}314}315316if ( terminateWhenAllBPHit && areAllBreakpointsHit(breakpoints) ) {317Env.traceNormal("All breakpoints are hit. Terminating.");318stop = true;319s = 0;320}321}322323if (s > 0) {324Env.traceVerbose("Stepping " + s + " step or breakpoint events from here");325stepsToTrace = s;326327if (currentStepReq == null) {328currentStepReq = erm.createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);329currentStepReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);330currentStepReq.enable();331}332} else {333if (currentStepReq != null && --stepsToTrace <= 0) {334Env.traceVerbose("Continue without stepping");335erm.deleteEventRequest(currentStepReq);336currentStepReq = null;337}338}339}340341Env.traceDebug("Resuming execution");342_vm.resume();343}344345new BreakpointListIterator(breakpoints) {346@Override protected Object apply(BreakpointInfo bi) {347if (!bi.isHit()) {348markTestFailed("Breakpoint for method "349+ bi.methodName350+ ": required hits "351+ (bi.requiredHits == null ? "> 0" : (" = " + bi.requiredHits))352+ "; actual hits = " + bi.hits);353} else {354Env.display("Breakpoint for method " + bi.methodName + " was hit " + bi.hits + " times. OK.");355}356357return null;358}359}.go();360361if (!debuggee.terminated()) {362try {363debuggee.dispose();364} catch (VMDisconnectedException ignore) {365}366}367368debuggee.waitFor();369return true;370}371372private void setBreakpoints(373final EventRequestManager erm,374final List<BreakpointInfo> breakpoints,375final ReferenceType classRef)376throws Throwable {377378Env.traceNormal("Setting breakpoints for class [" + classRef + "]");379380new BreakpointListIterator(breakpoints) {381@Override382protected Object apply(BreakpointInfo bpInfo) throws Throwable {383if ( bpInfo.className.equals(classRef.name()) ) {384385List<Method> methods = classRef.methodsByName(bpInfo.methodName);386if (methods.size() == 0)387throw new Exception("No method named [" + bpInfo.methodName + "]");388389Method method = (Method) methods.get(0);390List<Location> allLineLocations = method.allLineLocations();391392Env.traceVerbose("Method [" + method.name() + "] locations: " + Arrays.toString(allLineLocations.toArray()));393394if (bpInfo.methodLine > allLineLocations.size())395throw new Exception("TEST BUG: no breakpoint line " + bpInfo.methodLine);396397Location lineLocation = (Location) allLineLocations.get(bpInfo.methodLine);398bpInfo.bci = lineLocation.codeIndex();399bpInfo.hits = 0;400401if ( bpInfo.type == BreakpointInfo.Type.EXPLICIT ) {402BreakpointRequest bpReq = erm.createBreakpointRequest(lineLocation);403// bpReq.addThreadFilter(mainThread);404bpReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);405406if ( ! bpInfo.isConditional )407bpReq.enable();408409bpInfo.bpReq = bpReq;410Env.traceNormal("Breakpoint request for [" + method.name() + "]: " + bpReq);411} else {412Env.traceNormal("Implicit breakpoint " + "[" + bpInfo.methodName + ":" + bpInfo.methodLine + "]");413}414415}416417return null;418}419}.go();420}421422private static boolean areAllBreakpointsHit(List<BreakpointInfo> breakpoints) throws Throwable {423return null == new BreakpointListIterator(breakpoints) {424@Override425protected Object apply(BreakpointInfo bi) throws Throwable {426return bi.isHit() ? null : bi;427}428}.go();429}430431public static String getStackTraceStr(List<StackFrame> frames, boolean full)432throws AbsentInformationException {433StringBuffer buf = new StringBuffer();434435int frameNum = 0;436for (StackFrame f : frames) {437Location l = f.location();438439buf.append(String.format("#%-4d", frameNum))440.append(l.method())441.append("\n source: ")442.append(l.sourcePath())443.append(":")444.append(l.lineNumber())445.append("; bci=")446.append(l.codeIndex())447.append("\n class: ")448.append(l.declaringType())449.append("\n strata: ")450.append(StratumUtils.getStrataStr(f))451.append("\n locals: ");452453try {454for (Map.Entry<LocalVariable, Value> m : f.getValues(f.visibleVariables()).entrySet()) {455LocalVariable lv = m.getKey();456buf.append("\n ");457458if (lv.isArgument()) {459buf.append("[arg] ");460}461buf.append(lv.name())462.append(" (")463.append(lv.typeName())464.append(") = [")465.append(m.getValue())466.append("]; ");467}468} catch (AbsentInformationException e) {469buf.append("NO INFORMATION")470.append("\n arguments: ");471472List<Value> argumentValues = f.getArgumentValues();473474if (argumentValues == null || argumentValues.size() == 0) {475buf.append("none");476} else {477int n = 0;478for (Value v : argumentValues) {479buf.append("\n arg");480481if (v == null) {482buf.append(n)483.append(" [null]");484} else {485buf.append(n)486.append(" (")487.append(v.type())488.append(") = [")489.append(v)490.append("]; ");491}492n++;493}494}495}496497buf.append("\n\n");498499++frameNum;500if (!full && frameNum >= SHORT_STACK_TRACE_FRAMES_NUM) {501buf.append("...\n");502break;503}504}505return buf.toString();506}507508protected EventIterator getNextEvent() throws Throwable {509EventSet eventSet = _eventQueue.remove(_jdiEventWaitTimeout);510if (eventSet == null)511throw new Exception("Timed out while waiting for an event");512513return eventSet.eventIterator();514}515516}517518519