Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java
41161 views
1
/*
2
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
package vm.mlvm.share.jdi;
25
26
import java.util.Arrays;
27
import java.util.HashMap;
28
import java.util.List;
29
import java.util.Map;
30
31
import nsk.share.jdi.Binder;
32
import nsk.share.jdi.Debugee;
33
import vm.mlvm.share.Env;
34
import vm.mlvm.share.MlvmTest;
35
import vm.mlvm.share.jpda.StratumUtils;
36
import vm.share.options.Option;
37
38
import com.sun.jdi.AbsentInformationException;
39
import com.sun.jdi.IncompatibleThreadStateException;
40
import com.sun.jdi.LocalVariable;
41
import com.sun.jdi.Location;
42
import com.sun.jdi.Method;
43
import com.sun.jdi.ReferenceType;
44
import com.sun.jdi.StackFrame;
45
import com.sun.jdi.ThreadReference;
46
import com.sun.jdi.Value;
47
import com.sun.jdi.VirtualMachine;
48
import com.sun.jdi.VMDisconnectedException;
49
import com.sun.jdi.event.BreakpointEvent;
50
import com.sun.jdi.event.ClassPrepareEvent;
51
import com.sun.jdi.event.Event;
52
import com.sun.jdi.event.EventIterator;
53
import com.sun.jdi.event.EventQueue;
54
import com.sun.jdi.event.EventSet;
55
import com.sun.jdi.event.StepEvent;
56
import com.sun.jdi.event.VMDisconnectEvent;
57
import com.sun.jdi.request.BreakpointRequest;
58
import com.sun.jdi.request.ClassPrepareRequest;
59
import com.sun.jdi.request.EventRequest;
60
import com.sun.jdi.request.EventRequestManager;
61
import com.sun.jdi.request.StepRequest;
62
63
/**
64
* Option value syntax:
65
*
66
* <pre>
67
* breakpoints := breakpoint breakpoints?
68
* breakpoint := implicitOpt? methodName options? stratum? subBreakpoints?
69
*
70
* implicitOpt := "~"
71
*
72
* methodName := STRING
73
* methodName := className "." STRING
74
* className := STRING
75
*
76
* options :=
77
* options := ":" option options
78
* option := lineOption | requiredHitsOption | stepsToTraceOption
79
* lineOption := "L" INTEGER // Line number
80
* requiredHitsOption := "H" INTEGER | "H*" // Required number of hits
81
* stepsToTraceOption := "S" INTEGER // Steps to trace when this breakpoint is hit
82
*
83
* stratum := "/" stratumName "=" stratumSourceName ":" stratumSourceLine // Also check stratum information when this breakpoint is hit
84
* stratumName := STRING
85
* stratumSourceName := STRING
86
* stratumSourceLine := INTEGER
87
*
88
* subBreakpoints := "=>(" breakpoints ")" // subBreakpoints are only set when its main breakpoint is hit.
89
* </pre>
90
*/
91
92
public abstract class JDIBreakpointTest extends MlvmTest {
93
94
@Option(name="debugger.debuggeeClass", default_value="", description="Debuggee class name")
95
public String _debuggeeClass = "DEBUGGEE-CLASS-NOT-DEFINED";
96
97
@Option(name="debugger.terminateWhenAllBPHit", default_value="", description="Hang up in specified point")
98
public boolean _terminateWhenAllBreakpointsHit;
99
100
protected static int _jdiEventWaitTimeout = 3000;
101
102
private static final int MAX_EVENT_COUNT = 50000;
103
104
private static final int SHORT_STACK_TRACE_FRAMES_NUM = 2;
105
106
protected VirtualMachine _vm;
107
protected EventQueue _eventQueue;
108
109
private abstract static class BreakpointListIterator {
110
List<BreakpointInfo> _biList;
111
112
public BreakpointListIterator(List<BreakpointInfo> biList) {
113
_biList = biList;
114
}
115
116
public Object go() throws Throwable {
117
return iterate(_biList);
118
}
119
120
public Object iterate(List<BreakpointInfo> biList) throws Throwable {
121
for ( BreakpointInfo bi : biList ) {
122
Object result = apply(bi);
123
if ( result != null )
124
return result;
125
126
if ( bi.subBreakpoints != null ) {
127
result = iterate(bi.subBreakpoints);
128
if ( result != null )
129
return result;
130
}
131
}
132
133
return null;
134
}
135
136
protected abstract Object apply(BreakpointInfo bi) throws Throwable;
137
}
138
139
protected String getDebuggeeClassName() throws Throwable {
140
String debuggeeClass = _debuggeeClass.trim();
141
if ( debuggeeClass == null || debuggeeClass.isEmpty() )
142
throw new Exception("Please specify debuggee class name");
143
144
return debuggeeClass;
145
}
146
147
protected abstract List<BreakpointInfo> getBreakpoints(String debuggeeClassName);
148
149
protected boolean getTerminateWhenAllBPHit() {
150
return _terminateWhenAllBreakpointsHit;
151
}
152
153
protected void breakpointEventHook(BreakpointEvent bpe) {}
154
protected void stepEventHook(StepEvent se) {}
155
protected void classPrepareEventHook(ClassPrepareEvent cpe) {}
156
protected void eventHook(Event e) {}
157
158
@Override
159
public boolean run() throws Throwable {
160
JDIBreakpointTest._jdiEventWaitTimeout = getArgumentParser().getWaitTime() * 60000;
161
162
boolean terminateWhenAllBPHit = getTerminateWhenAllBPHit();
163
164
final String debuggeeClass = getDebuggeeClassName();
165
166
Binder binder = new Binder((ArgumentHandler) getArgumentParser(), getLog());
167
168
Debugee debuggee = binder.bindToDebugee(debuggeeClass);
169
if (debuggee == null)
170
throw new Exception("Can't launch debuggee");
171
172
debuggee.redirectOutput(getLog());
173
174
_vm = debuggee.VM();
175
_eventQueue = _vm.eventQueue();
176
EventRequestManager erm = _vm.eventRequestManager();
177
178
// Breakpoints
179
180
final List<BreakpointInfo> breakpoints = getBreakpoints(debuggeeClass);
181
182
final HashMap<String, ClassPrepareRequest> bpClassNames = new HashMap<String, ClassPrepareRequest>();
183
184
new BreakpointListIterator(breakpoints) {
185
@Override protected Object apply(BreakpointInfo bi) {
186
if ( bi.className.isEmpty() )
187
bi.className = debuggeeClass;
188
bpClassNames.put(bi.className, null);
189
return null;
190
}
191
}.go();
192
193
for (String className : bpClassNames.keySet()) {
194
Env.traceNormal("Requesting ClassPrepareEvent for [" + className + "]");
195
196
ClassPrepareRequest cpReq = erm.createClassPrepareRequest();
197
cpReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
198
cpReq.addClassFilter(className);
199
cpReq.enable();
200
201
bpClassNames.put(className, cpReq);
202
}
203
204
_vm.resume();
205
206
StepRequest currentStepReq = null;
207
int stepsToTrace = 0;
208
int stepCount = 0;
209
boolean stop = false;
210
211
EVENT_LOOP: while (!stop) {
212
EventIterator ei = getNextEvent();
213
214
Map<Location, ThreadReference> currentLocations = new HashMap<Location, ThreadReference>();
215
216
while (ei.hasNext()) {
217
Event e = ei.next();
218
Env.traceVerbose("Got JDI event: " + e);
219
eventHook(e);
220
if (e instanceof VMDisconnectEvent)
221
break EVENT_LOOP;
222
223
ThreadReference thread = null;
224
Location location = null;
225
boolean fullStackTrace = false;
226
227
if (e instanceof ClassPrepareEvent) {
228
ClassPrepareEvent cpe = (ClassPrepareEvent) e;
229
classPrepareEventHook(cpe);
230
231
ReferenceType classRef = cpe.referenceType();
232
233
setBreakpoints(erm, breakpoints, classRef);
234
235
} else if (e instanceof BreakpointEvent) {
236
237
BreakpointEvent bpe = (BreakpointEvent) e;
238
breakpointEventHook(bpe);
239
thread = bpe.thread();
240
location = bpe.location();
241
fullStackTrace = true;
242
243
} else if (e instanceof StepEvent) {
244
245
StepEvent se = (StepEvent) e;
246
stepEventHook(se);
247
thread = se.thread();
248
location = se.location();
249
}
250
251
if (thread != null) {
252
try {
253
Env.traceDebug("Event thread suspends: " + thread.suspendCount());
254
if (thread.suspendCount() > 0)
255
Env.traceDebug("Stack trace:" + getStackTraceStr(thread.frames(), fullStackTrace));
256
257
currentLocations.put(location, thread);
258
259
} catch (IncompatibleThreadStateException ex) {
260
Env.traceNormal("Exception: ", ex);
261
}
262
}
263
264
if (++stepCount > MAX_EVENT_COUNT) {
265
Env.display("Maximum number of events reached ("
266
+ MAX_EVENT_COUNT + ") for this test. Exiting.");
267
stop = true;
268
}
269
}
270
271
for (Map.Entry<Location, ThreadReference> e : currentLocations.entrySet()) {
272
final Location location = e.getKey();
273
final ThreadReference thread = e.getValue();
274
275
BreakpointInfo bpInfo = (BreakpointInfo) new BreakpointListIterator(breakpoints) {
276
@Override protected Object apply(BreakpointInfo bi) throws Throwable {
277
if ( location.method().name().equals(bi.methodName) && location.codeIndex() == bi.bci )
278
return bi;
279
else
280
return null;
281
}
282
}.go();
283
284
int s = 0;
285
286
if (bpInfo != null) {
287
Env.traceNormal("Execution hit our breakpoint: [" + bpInfo.methodName + ":" + bpInfo.methodLine + "] on step " + stepCount);
288
289
bpInfo.hits++;
290
s = bpInfo.stepsToTrace;
291
292
if (bpInfo.stratumInfo != null) {
293
if ( ! StratumUtils.checkStratum(location, bpInfo.stratumInfo) )
294
markTestFailed("Stratum " + bpInfo.stratumInfo + " mismatch");
295
}
296
297
if ( bpInfo.subBreakpoints != null ) {
298
Env.traceNormal("Enabling sub-breakpoints");
299
for ( BreakpointInfo subBP : bpInfo.subBreakpoints ) {
300
if ( subBP.type == BreakpointInfo.Type.IMPLICIT )
301
continue;
302
303
if ( subBP.bpReq == null ) {
304
Env.complain("Breakpoint " + subBP + " was not set. Skipping.");
305
continue;
306
}
307
308
if ( subBP.bpReq.isEnabled() ) {
309
Env.traceVerbose("Breakpoint " + subBP + " is already enabled. Skipping.");
310
continue;
311
}
312
313
subBP.bpReq.enable();
314
}
315
}
316
317
if ( terminateWhenAllBPHit && areAllBreakpointsHit(breakpoints) ) {
318
Env.traceNormal("All breakpoints are hit. Terminating.");
319
stop = true;
320
s = 0;
321
}
322
}
323
324
if (s > 0) {
325
Env.traceVerbose("Stepping " + s + " step or breakpoint events from here");
326
stepsToTrace = s;
327
328
if (currentStepReq == null) {
329
currentStepReq = erm.createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO);
330
currentStepReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
331
currentStepReq.enable();
332
}
333
} else {
334
if (currentStepReq != null && --stepsToTrace <= 0) {
335
Env.traceVerbose("Continue without stepping");
336
erm.deleteEventRequest(currentStepReq);
337
currentStepReq = null;
338
}
339
}
340
}
341
342
Env.traceDebug("Resuming execution");
343
_vm.resume();
344
}
345
346
new BreakpointListIterator(breakpoints) {
347
@Override protected Object apply(BreakpointInfo bi) {
348
if (!bi.isHit()) {
349
markTestFailed("Breakpoint for method "
350
+ bi.methodName
351
+ ": required hits "
352
+ (bi.requiredHits == null ? "> 0" : (" = " + bi.requiredHits))
353
+ "; actual hits = " + bi.hits);
354
} else {
355
Env.display("Breakpoint for method " + bi.methodName + " was hit " + bi.hits + " times. OK.");
356
}
357
358
return null;
359
}
360
}.go();
361
362
if (!debuggee.terminated()) {
363
try {
364
debuggee.dispose();
365
} catch (VMDisconnectedException ignore) {
366
}
367
}
368
369
debuggee.waitFor();
370
return true;
371
}
372
373
private void setBreakpoints(
374
final EventRequestManager erm,
375
final List<BreakpointInfo> breakpoints,
376
final ReferenceType classRef)
377
throws Throwable {
378
379
Env.traceNormal("Setting breakpoints for class [" + classRef + "]");
380
381
new BreakpointListIterator(breakpoints) {
382
@Override
383
protected Object apply(BreakpointInfo bpInfo) throws Throwable {
384
if ( bpInfo.className.equals(classRef.name()) ) {
385
386
List<Method> methods = classRef.methodsByName(bpInfo.methodName);
387
if (methods.size() == 0)
388
throw new Exception("No method named [" + bpInfo.methodName + "]");
389
390
Method method = (Method) methods.get(0);
391
List<Location> allLineLocations = method.allLineLocations();
392
393
Env.traceVerbose("Method [" + method.name() + "] locations: " + Arrays.toString(allLineLocations.toArray()));
394
395
if (bpInfo.methodLine > allLineLocations.size())
396
throw new Exception("TEST BUG: no breakpoint line " + bpInfo.methodLine);
397
398
Location lineLocation = (Location) allLineLocations.get(bpInfo.methodLine);
399
bpInfo.bci = lineLocation.codeIndex();
400
bpInfo.hits = 0;
401
402
if ( bpInfo.type == BreakpointInfo.Type.EXPLICIT ) {
403
BreakpointRequest bpReq = erm.createBreakpointRequest(lineLocation);
404
// bpReq.addThreadFilter(mainThread);
405
bpReq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
406
407
if ( ! bpInfo.isConditional )
408
bpReq.enable();
409
410
bpInfo.bpReq = bpReq;
411
Env.traceNormal("Breakpoint request for [" + method.name() + "]: " + bpReq);
412
} else {
413
Env.traceNormal("Implicit breakpoint " + "[" + bpInfo.methodName + ":" + bpInfo.methodLine + "]");
414
}
415
416
}
417
418
return null;
419
}
420
}.go();
421
}
422
423
private static boolean areAllBreakpointsHit(List<BreakpointInfo> breakpoints) throws Throwable {
424
return null == new BreakpointListIterator(breakpoints) {
425
@Override
426
protected Object apply(BreakpointInfo bi) throws Throwable {
427
return bi.isHit() ? null : bi;
428
}
429
}.go();
430
}
431
432
public static String getStackTraceStr(List<StackFrame> frames, boolean full)
433
throws AbsentInformationException {
434
StringBuffer buf = new StringBuffer();
435
436
int frameNum = 0;
437
for (StackFrame f : frames) {
438
Location l = f.location();
439
440
buf.append(String.format("#%-4d", frameNum))
441
.append(l.method())
442
.append("\n source: ")
443
.append(l.sourcePath())
444
.append(":")
445
.append(l.lineNumber())
446
.append("; bci=")
447
.append(l.codeIndex())
448
.append("\n class: ")
449
.append(l.declaringType())
450
.append("\n strata: ")
451
.append(StratumUtils.getStrataStr(f))
452
.append("\n locals: ");
453
454
try {
455
for (Map.Entry<LocalVariable, Value> m : f.getValues(f.visibleVariables()).entrySet()) {
456
LocalVariable lv = m.getKey();
457
buf.append("\n ");
458
459
if (lv.isArgument()) {
460
buf.append("[arg] ");
461
}
462
buf.append(lv.name())
463
.append(" (")
464
.append(lv.typeName())
465
.append(") = [")
466
.append(m.getValue())
467
.append("]; ");
468
}
469
} catch (AbsentInformationException e) {
470
buf.append("NO INFORMATION")
471
.append("\n arguments: ");
472
473
List<Value> argumentValues = f.getArgumentValues();
474
475
if (argumentValues == null || argumentValues.size() == 0) {
476
buf.append("none");
477
} else {
478
int n = 0;
479
for (Value v : argumentValues) {
480
buf.append("\n arg");
481
482
if (v == null) {
483
buf.append(n)
484
.append(" [null]");
485
} else {
486
buf.append(n)
487
.append(" (")
488
.append(v.type())
489
.append(") = [")
490
.append(v)
491
.append("]; ");
492
}
493
n++;
494
}
495
}
496
}
497
498
buf.append("\n\n");
499
500
++frameNum;
501
if (!full && frameNum >= SHORT_STACK_TRACE_FRAMES_NUM) {
502
buf.append("...\n");
503
break;
504
}
505
}
506
return buf.toString();
507
}
508
509
protected EventIterator getNextEvent() throws Throwable {
510
EventSet eventSet = _eventQueue.remove(_jdiEventWaitTimeout);
511
if (eventSet == null)
512
throw new Exception("Timed out while waiting for an event");
513
514
return eventSet.eventIterator();
515
}
516
517
}
518
519