Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/Debugee.java
41161 views
1
/*
2
* Copyright (c) 2001, 2020, 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 nsk.share.jdi;
25
26
import nsk.share.*;
27
import nsk.share.jpda.*;
28
29
import com.sun.jdi.*;
30
import com.sun.jdi.request.*;
31
import com.sun.jdi.event.*;
32
33
import java.util.*;
34
35
/**
36
* This class is used to interact with debugee VM using JDI features.
37
* <p>
38
* This class is wrapper for debugee VM constructed by <code>Binder</code>
39
* and it uses <code>com.sun.jdi.VirtualMachine</code> to interact with debugee VM.
40
* <p>
41
* In addition to the general abities to control of debugee VM process,
42
* provided by the base class <code>DebugeeProcess</code>, this class
43
* adds also several service methods over the JDI features to simplify interaction
44
* with debugee VM (such as finding classes, setting breakpoints,
45
* handling events, and so on.).
46
*
47
* @see Binder
48
* @see DebugeeProcess
49
*/
50
abstract public class Debugee extends DebugeeProcess {
51
52
/**
53
* Mirror of the debugee VM. This must be initialized by every
54
* particular non-abstract class extending Debugee class.
55
*/
56
protected VirtualMachine vm = null;
57
58
/** Binder that created this debugee. */
59
protected Binder binder = null;
60
61
/** Argument handler. */
62
protected ArgumentHandler argumentHandler = null;
63
64
/** Create new <code>Debugee</code> object for a given binder. */
65
protected Debugee (Binder binder) {
66
super(binder);
67
this.binder = binder;
68
this.argumentHandler = (ArgumentHandler)binder.getArgumentHandler();
69
}
70
71
/** Setup <code>Debugee</code> object with given VM mirror. */
72
public void setupVM(VirtualMachine vm) {
73
if (this.vm != null) {
74
throw new TestBug("Setting duplicated VM mirror for Debugee object");
75
}
76
this.vm = vm;
77
int traceMode = argumentHandler.getTraceMode();
78
if (traceMode != VirtualMachine.TRACE_NONE) {
79
display("Setting JDI trace mode to: " + argumentHandler.getTraceModeString());
80
setDebugTraceMode(traceMode);
81
}
82
}
83
84
/** Return <code>Binder</code> of the debugee object. */
85
public Binder getBinder() {
86
return binder;
87
}
88
89
/** Return JDI mirror of the debugee VM. */
90
public VirtualMachine VM() {
91
return vm;
92
}
93
94
/** Return <code>EventRequestManager</code> of the debugee object. */
95
public EventRequestManager getEventRequestManager() {
96
return vm.eventRequestManager();
97
}
98
99
// --------------------------------------------------- //
100
101
/** List of the currently running threads. */
102
public ThreadReference[] threads () {
103
List list = vm.allThreads();
104
int size = list.size();
105
ThreadReference array[] = new ThreadReference[size];
106
Iterator iterator = list.iterator();
107
for (int i = 0; i < size; i++)
108
array[i] = (ThreadReference) iterator.next();
109
if (iterator.hasNext())
110
throw new Oddity("extra element in a list?");
111
return array;
112
}
113
114
/** List of all types loaded by the debugee VM. */
115
public ReferenceType[] classes() {
116
return classes(null);
117
}
118
119
/**
120
* List of all classes of the given <code>name</code> loaded by
121
* the debugee VM; or list of all classes, if <code>name</code>
122
* is <code>null</code>.
123
*/
124
private ReferenceType[] classes (String name) {
125
List list = (name==null)? vm.allClasses(): vm.classesByName(name);
126
int size = list.size();
127
ReferenceType array[] = new ReferenceType [ size ];
128
Iterator iterator = list.iterator();
129
for (int i=0; i<size; i++)
130
array[i] = (ReferenceType) iterator.next();
131
if (iterator.hasNext())
132
throw new Oddity("extra element in a list?");
133
return array;
134
}
135
136
// --------------------------------------------------- //
137
138
/**
139
* Return mirror for the only class of the given <code>name</code>
140
* loaded by the debugee VM; or throw TestBug exception if there
141
* are more than one such class found. TestFailure exception
142
* will be thrown in case when mirrors for classes with different
143
* names or duplicated mirrors were returned.
144
* Return <code>null</code> if there is no such class loaded.
145
*/
146
public ReferenceType classByName (String name) {
147
ReferenceType classes[] = this.classes(name);
148
149
// if on first call debuggee doesn't return needed class try get this class one more time after delay to avoid 6446633
150
if (classes == null || classes.length == 0) {
151
try {
152
Thread.sleep(1000);
153
}
154
catch(InterruptedException e) {
155
throw new TestBug("Unexpected InterruptedException");
156
}
157
158
classes = this.classes(name);
159
}
160
161
if (classes == null || classes.length == 0)
162
return null;
163
164
// analyze returned mirrors and throw appropriate exception
165
if (classes.length > 1) {
166
boolean duplicatesFound = false;
167
boolean differentNamesFound = false;
168
boolean visited[] = new boolean[classes.length];
169
complain("Classes that were found for name \"" + name + "\":");
170
for(ReferenceType klass : classes) {
171
complain("\t" + klass);
172
}
173
for(int c = 0; c < classes.length; c++) {
174
if(visited[c]) {
175
continue;
176
}
177
if(!classes[c].name().equals(name)) {
178
differentNamesFound = true;
179
continue;
180
}
181
for(int i = c + 1; i < classes.length; i++) {
182
if(visited[i]) {
183
continue;
184
} else {
185
visited[i] = true;
186
}
187
if(classes[c].classLoader() == classes[i].classLoader()) {
188
duplicatesFound = true;
189
}
190
}
191
}
192
if(duplicatesFound) {
193
throw new TestFailure("classes with the same name and " +
194
"loaded with the same class loader " +
195
"were found.");
196
} else if(differentNamesFound) {
197
throw new TestFailure("class with name different from '" + name +
198
"' was returned by VirutualMachine.classesByName.");
199
} else {
200
throw new TestBug("found " + classes.length + " such classes: " + name);
201
}
202
}
203
return classes[0];
204
}
205
206
/**
207
* Return mirror for the only method of the given <code>refType</code>
208
* class in the debugee VM; or throw TestBug exception if there
209
* are more than one such method found. Return <code>null</code> if
210
* there is no such method found.
211
*/
212
public Method methodByName(ReferenceType refType, String name) {
213
List methods = refType.methodsByName(name);
214
if (methods == null || methods.isEmpty()) return null;
215
if (methods.size() > 1)
216
throw new TestBug(
217
"found " + methods.size() + " such methods: " + name);
218
Method method = (Method)methods.get(0);
219
return method;
220
}
221
222
/**
223
* Return a currently running thread of the given <code>name</code>; or
224
* throw TestBug exception if there are more than one such thread found.
225
* Return <code>null</code> if there is no such thread.
226
*/
227
public ThreadReference threadByName (String name) {
228
ThreadReference threads[] = this.threads();
229
int count = 0, index = -1;
230
for (int i = 0; i < threads.length; i++) {
231
if (threads[i].name().compareTo(name)==0) {
232
count++;
233
index = i;
234
}
235
}
236
if (count == 0)
237
return null;
238
if (count > 1)
239
throw new TestBug(
240
"found " + count + " such threads: " + name);
241
return threads[index];
242
}
243
244
245
public ThreadReference threadByNameOrThrow(String name) throws JDITestRuntimeException {
246
247
List all = vm.allThreads();
248
ListIterator li = all.listIterator();
249
for (; li.hasNext(); ) {
250
ThreadReference thread = (ThreadReference) li.next();
251
if (thread.name().equals(name))
252
return thread;
253
}
254
throw new JDITestRuntimeException("** Thread IS NOT found ** : " + name);
255
}
256
257
// --------------------------------------------------- //
258
259
/**
260
* Returns Location object for given line number in specified method or null
261
* if no location for this line is found.
262
*
263
* @param method method mirror containing given line number
264
* @param line line number to find location
265
*/
266
public Location getLineLocation(Method method, int line) {
267
List locs = null;
268
try {
269
locs = method.allLineLocations();
270
} catch(AbsentInformationException e) {
271
throw new TestBug("Unable to find location for line " + line + ": " + e);
272
}
273
Iterator iter = locs.iterator();
274
while (iter.hasNext()) {
275
Location location = (Location)iter.next();
276
if (location.lineNumber() == line) {
277
return location;
278
}
279
}
280
return null;
281
}
282
283
/**
284
* Returns Location object for given line number in specified reference type or null
285
* if no location for this line is found.
286
*
287
* @param refType reference type mirror containing given line number
288
* @param line line number to find location
289
*/
290
public Location getLineLocation(ReferenceType refType, int line) {
291
List locs = null;
292
try {
293
locs = refType.allLineLocations();
294
} catch(AbsentInformationException e) {
295
throw new TestBug("Unable to find location for line " + line + ": " + e);
296
}
297
Iterator iter = locs.iterator();
298
while (iter.hasNext()) {
299
Location location = (Location)iter.next();
300
if (location.lineNumber() == line) {
301
return location;
302
}
303
}
304
return null;
305
}
306
307
// --------------------------------------------------- //
308
309
/**
310
* Make disabled breakpoint to given location and return BreakpointRequest.
311
*
312
* @param location location to set breakpoint
313
*
314
* @see #setBreakpoint(Method, int)
315
* @see #setBreakpoint(ReferenceType, String, int)
316
*/
317
public BreakpointRequest makeBreakpoint(Location location) {
318
EventRequestManager evm = getEventRequestManager();
319
BreakpointRequest request = evm.createBreakpointRequest(location);
320
display("Breakpoint set:\n\t" + request);
321
return request;
322
}
323
324
/**
325
* Make disabled breakpoint to given line number in specified method
326
* and return BreakpointRequest.
327
*
328
* @param method method mirror to set breakpoint
329
* @param lineNumber line number inside the method
330
*
331
* @throws Failure if no location found for specified line number
332
*
333
* @see #makeBreakpoint(Location)
334
* @see #makeBreakpoint(ReferenceType, String, int)
335
*/
336
public BreakpointRequest makeBreakpoint(Method method, int lineNumber) {
337
Location location = getLineLocation(method, lineNumber);
338
if (location == null) {
339
throw new Failure("No location found for setting breakpoint to line " + lineNumber);
340
}
341
return makeBreakpoint(location);
342
}
343
344
/**
345
* Make disabled breakpoint to given line number for specified method name
346
* of the given reference type and return BreakpointRequest.
347
*
348
* @param refType reference type for specified method
349
* @param methodName method name to set breakpoint
350
* @param lineNumber line number inside the method
351
*
352
* @throws Failure if no location found for specified line number
353
*
354
* @see #makeBreakpoint(Method, int)
355
*/
356
public BreakpointRequest makeBreakpoint(ReferenceType refType,
357
String methodName, int lineNumber) {
358
Method method = methodByName(refType, methodName);
359
if (method == null) {
360
throw new Failure("No method found for setting breakpoint: " + methodName);
361
}
362
return makeBreakpoint(method, lineNumber);
363
}
364
365
/**
366
* Set and enable breakpoint to given line number for specified method
367
* and return BreakpointRequest.
368
*
369
* @param method method mirror to set breakpoint
370
* @param lineNumber line number inside the method
371
*
372
* @throws Failure if no location found for specified line number
373
*
374
* @see #setBreakpoint(ReferenceType, String, int)
375
*/
376
public BreakpointRequest setBreakpoint(Method method, int lineNumber) {
377
BreakpointRequest request = makeBreakpoint(method, lineNumber);
378
request.enable();
379
return request;
380
}
381
382
/**
383
* Set and enable breakpoint to given line number for specified method name
384
* of the given reference type and return BreakpointRequest.
385
*
386
* @param refType reference type for specified method
387
* @param methodName method name to set breakpoint
388
* @param lineNumber line number inside the method
389
*
390
* @throws Failure if no location found for specified line number
391
*
392
* @see #setBreakpoint(Method, int)
393
*/
394
public BreakpointRequest setBreakpoint(ReferenceType refType,
395
String methodName, int lineNumber) {
396
BreakpointRequest request = makeBreakpoint(refType, methodName, lineNumber);
397
request.enable();
398
return request;
399
}
400
401
// --------------------------------------------------- //
402
403
/** Suspend the debugee VM. */
404
public void suspend() {
405
vm.suspend();
406
}
407
408
/** Resume the debugee VM. */
409
public void resume() {
410
vm.resume();
411
}
412
413
/** Dispose the debugee VM. */
414
public void dispose() {
415
vm.dispose();
416
}
417
418
/*
419
* Set internal JDI tracing mode.
420
*/
421
public void setDebugTraceMode(int traceMode) {
422
vm.setDebugTraceMode(traceMode);
423
}
424
425
// --------------------------------------------------- //
426
427
/**
428
* Wait for the requested event and skip other events.
429
*
430
* @param request non-null value for events generated by this
431
* event request; null value for <code>VMStartEvent</code>.
432
* @param timeout timeout in milliseconds to wait for the requested event.
433
*
434
* @throws InterruptedException if another thread has interrupted this thread
435
*/
436
public Event waitingEvent(EventRequest request, long timeout)
437
throws InterruptedException {
438
439
if (request == null) {
440
throw new Failure("Null request specified for waiting events: " + request);
441
}
442
443
long timeToFinish = System.currentTimeMillis() + timeout;
444
long timeLeft = timeout;
445
boolean exit = false;
446
447
display("Waiting for event by request:\n\t" + request);
448
449
EventQueue eventQueue = vm.eventQueue();
450
while (timeLeft > 0 && !exit) {
451
452
EventSet eventSet = eventQueue.remove(timeLeft);
453
if (eventSet == null) {
454
continue;
455
}
456
457
EventIterator eventIterator = eventSet.eventIterator();
458
while (eventIterator.hasNext()) {
459
460
Event event = eventIterator.nextEvent();
461
EventRequest eventRequest = event.request();
462
463
if (request == eventRequest || request.equals(eventRequest)) {
464
display("Got requested event:\n\t" + event);
465
return event;
466
} else if (event instanceof VMDeathEvent) {
467
display("Ignore unexpected VMDeathEvent");
468
} else if (event instanceof VMDisconnectEvent) {
469
display("Got unexpected VMDisconnectEvent");
470
exit = true;
471
break;
472
} else {
473
display("Ignore unexpected event:\n\t" + event);
474
} // if
475
476
} // while
477
478
timeLeft = timeToFinish - System.currentTimeMillis();
479
480
} // while
481
482
return null;
483
}
484
485
/*
486
* Wait for VM to initialize by receiving initial VM_START event for specified timeout.
487
*/
488
public void waitForVMInit(long timeout) {
489
waitForVMInit(vm ,log, timeout);
490
}
491
492
/*
493
* This static method is also used by nsk.share.jdi.ConnectorTest
494
*/
495
static public void waitForVMInit(VirtualMachine vm, Log log, long timeout) {
496
try {
497
EventSet eventSet = vm.eventQueue().remove(timeout);
498
if (eventSet == null) {
499
throw new Failure("No VMStartEvent received for timeout: " + timeout + " ms");
500
}
501
EventIterator iterator = eventSet.eventIterator();
502
while (iterator.hasNext()) {
503
Event event = iterator.nextEvent();
504
if (event == null) {
505
throw new Failure("Null event received instead of VMStartEvent");
506
}
507
if (event instanceof VMStartEvent) {
508
log.display("Initial VMStartEvent received: " + event);
509
} else {
510
throw new Failure("Unexpected event received instead of VMStartEvent: " + event);
511
}
512
}
513
int suspendPolicy = eventSet.suspendPolicy();
514
if (suspendPolicy != EventRequest.SUSPEND_ALL) {
515
throw new Failure("Suspend policy of VMStartEvent is not SUSPEND_ALL: " + suspendPolicy);
516
}
517
} catch (InterruptedException e) {
518
e.printStackTrace(log.getOutStream());
519
throw new Failure("Thread interrupted while waiting for VMStartEvent:\n\t" + e);
520
}
521
}
522
523
// --------------------------------------------------- //
524
525
/**
526
* Bind to debuggee VM using <code>Binder</code> and make initial
527
* synchronization via IOPipe.
528
*
529
* @param argHandler command line arguments handler to make <code>Binder</code> object
530
* @param log <code>Log</code> object to log messages
531
* @param mainClassName main class of debugee
532
*
533
* @throws Failure if there were problems with binding to debuggee VM
534
*
535
* @see Binder#bindToDebugee(String)
536
*/
537
public static Debugee prepareDebugee(ArgumentHandler argHandler, Log log,
538
String mainClassName) {
539
Binder binder = new Binder(argHandler, log);
540
Debugee debugee = binder.bindToDebugee(mainClassName);
541
542
debugee.createIOPipe();
543
544
debugee.redirectStderr(log, DEBUGEE_STDERR_LOG_PREFIX);
545
debugee.resume();
546
547
debugee.receiveExpectedSignal("ready");
548
549
return debugee;
550
}
551
552
/**
553
* Send <code>"quit"</code> signal, wait for debugee VM exit and check exit.
554
*
555
* @throws Failure if exit status is not <code>Consts.JCK_STATUS_BASE</code>
556
*
557
* @see #endDebugee()
558
*/
559
public void quit() {
560
sendSignal("quit");
561
int status = endDebugee();
562
if ( status != Consts.JCK_STATUS_BASE ) {
563
throw new Failure("Got unexpected debugee VM exit status: " + status
564
+ " (not " + Consts.JCK_STATUS_BASE + ")");
565
}
566
display("Got expected debugee VM exit status: " + status);
567
}
568
569
/*
570
* Dispose debuggee VM, wait for it to exit, close all resources and return
571
* exit status code.
572
*/
573
public int endDebugee() {
574
int status = waitFor();
575
if (vm != null) {
576
try {
577
vm.dispose();
578
} catch (VMDisconnectedException ignore) {
579
}
580
vm = null;
581
}
582
return status;
583
}
584
585
/*
586
* Print information about all threads in debuggee VM
587
*/
588
protected void printThreadsInfo(VirtualMachine vm) {
589
try {
590
log.display("------------ Try to print debuggee threads before killing process ------------");
591
if (vm == null) {
592
log.display("Can't print threads info because 'vm' is null");
593
return;
594
}
595
List<ThreadReference> threads = vm.allThreads();
596
log.display("Threads: " + threads);
597
log.display("Total threads: " + threads.size());
598
for (ThreadReference thread : threads) {
599
log.display("\nThread: " + thread.name());
600
log.display("Is suspended: " + thread.isSuspended());
601
log.display("Is at breakpoint: " + thread.isAtBreakpoint());
602
boolean wasSuspended = false;
603
try {
604
if (!thread.isSuspended()) {
605
log.display("\n suspend thread to get its stack \n");
606
thread.suspend();
607
wasSuspended = true;
608
}
609
log.display("Stack frame count: " + thread.frameCount());
610
if (thread.frameCount() > 0) {
611
log.display("Frames:");
612
for (StackFrame frame : thread.frames()) {
613
Location location = frame.location();
614
log.display(location.declaringType().name() + "." + location.method().name() + ", line: " + location.lineNumber());
615
}
616
}
617
} finally {
618
if (wasSuspended) {
619
log.display("\n resume thread \n");
620
thread.resume();
621
}
622
}
623
}
624
log.display("----------------------------------------------------------------------");
625
} catch (Throwable t) {
626
log.complain("");
627
t.printStackTrace(log.getOutStream());
628
}
629
}
630
631
/**
632
* Force debugge VM to exit using JDI interface if possible.
633
*/
634
protected void killDebugee() {
635
try {
636
// print information about debuggee threads to simplify failure analysis
637
printThreadsInfo(vm);
638
} finally {
639
if (vm != null) {
640
try {
641
display("Killing debuggee by forcing target VM to exit");
642
vm.exit(97);
643
display("Debugee VM successfully forced to exit");
644
vm = null;
645
} catch (VMDisconnectedException e) {
646
display("Ignore VMDisconnectedException while forcing debuggee VM to exit:\n\t"
647
+ e);
648
}
649
}
650
}
651
}
652
653
}
654
655