/* * Copyright (c) 2001, 2018, 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 nsk.share.jdwp; import nsk.share.*; import nsk.share.jpda.*; import java.util.*; import java.io.*; /** * This class is used to interact with debugee VM using JDWP features. *
* This class is an mirror of debugee VM that is constructed by
* Binder
and uses Transport
object
* to interact with debugee VM.
*
* In addition to the general abities to control of debugee VM process,
* provided by the base class DebugeeProcess
, this class
* adds some service methods that uses JDWP protocol to simplify interaction
* with debugee VM (such as finding classes, setting breakpoints,
* handling events, and so on.).
*
* @see Binder
* @see Transport
* @see DebugeeProcess
*/
abstract public class Debugee extends DebugeeProcess {
/** Binder that creates this debugee. */
protected Binder binder = null;
protected LinkedListDebugee
object for the given binder. */
protected Debugee (Binder binder) {
super(binder);
this.argumentHandler = binder.getArgumentHandler();
this.binder = binder;
prefix = "Debugee> ";
}
/** Return Binder
of the debugee object. */
public Binder getBinder() {
return binder;
}
/** Return Transport
of the debugee object. */
public Transport getTransport() {
return transport;
}
/**
* Prepare transport object for establishing connection.
* This may change connection options in argumentHandler
.
*
* @return specific address string if listening has started or null otherwise
*/
public String prepareTransport(ArgumentHandler argumentHandler) {
String address = null;
try {
if (argumentHandler.isSocketTransport()) {
SocketTransport socket_transport = new SocketTransport(log);
if (argumentHandler.isListeningConnector()) {
int port = 0;
if (argumentHandler.isTransportAddressDynamic()) {
port = socket_transport.bind(0);
// argumentHandler.setTransportPortNumber(port);
} else {
port = argumentHandler.getTransportPortNumber();
socket_transport.bind(port);
}
address = argumentHandler.getTestHost() + ":" + port;
}
transport = socket_transport;
/*
} else if (argumentHandler.isShmemTransport()) {
ShmemTransport shmem_transport = new ShmemTransport(log);
if (argumentHandler.isListeningConnector()) {
String sharedName = agrHandler.getTransportSharedName();
shmem_transport.bind(sharedName);
address = sharedName;
}
transport = shmem_transport;
*/
} else {
throw new TestBug("Unexpected transport type: "
+ argumentHandler.getTransportType());
}
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught IOException while preparing for JDWP transport connection:\n\t"
+ e);
}
return address;
}
/**
* Establish connection to debugee VM.
*/
public Transport connect() {
if (transport == null) {
throw new Failure("Attemt to establish JDWP connection for not prepared transport");
}
try {
if (argumentHandler.isSocketTransport()) {
display("Establishing JDWP socket connection");
SocketTransport socket_transport = (SocketTransport)transport;
int transportPort = argumentHandler.getTransportPortNumber();
if (argumentHandler.isAttachingConnector()) {
String debugeeHost = argumentHandler.getDebugeeHost();
display("Attaching to debugee: " + debugeeHost + ":" + transportPort);
socket_transport.attach(debugeeHost, transportPort);
} else if (argumentHandler.isListeningConnector()) {
display("Listening from debugee");
socket_transport.accept();
} else {
throw new TestBug("Unexpected connector type: "
+ argumentHandler.getConnectorType());
}
/*
} else if (argumentHandler.isShmemTransport()) {
display("Establishing JDWP shared-memory connection");
ShmemTransport shmem_transport = (ShmemTransport)transport;
String sharedName = argumentHandler.getTransportSharedName();
if (argumentHandler.isAttachingConnector()) {
display("Attaching to debugee: " + sharedName);
shmem_transport.attach(sharedName);
} else if (argumentHandler.isListeningConnector()) {
display("Listening from debugee");
shmem_transport.accept();
} else {
throw new TestBug("Unexpected connector type: "
+ argumentHandler.getConnectorType());
}
*/
} else {
throw new TestBug("Unexpected transport type: "
+ argumentHandler.getTransportType());
}
transport.handshake();
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught IOException while establishing JDWP transport connection:\n\t"
+ e);
}
return transport;
}
// --------------------------------------------------- //
/**
* Waits for VM_INIT event from debugee VM.
*/
public void waitForVMInit() {
String eventName = "VirtualMachine.VM_START";
EventPacket packet = receiveEventFor(JDWP.EventKind.VM_START, eventName);
// String versionInfo = getVersionInfo();
// display("Target VM started:\n" + versionInfo);
}
/**
* Waits for VM_DEATH event from debugee VM.
*/
public void waitForVMDeath() {
String eventName = "VirtualMachine.VM_DEATH";
EventPacket packet = receiveEventFor(JDWP.EventKind.VM_DEATH, eventName);
}
/**
* Wait for class loaded on debugee start up and return its classID.
* Debuggee should be initially suspended and it will also left suspended
* by the CLASS_PREPARE event request.
*/
public long waitForClassLoaded(String className, byte suspendPolicy) {
// make request for CLASS_PREPARE_EVENT for this class name
int requestID = requestClassPrepareEvent(className, suspendPolicy);
// resume initially suspended debugee
resume();
// wait for CLASS_PREPARE_EVENT
return waitForClassPrepareEvent(requestID, className);
}
/**
* Wait for classes loaded on debugee start up and return their classIDs.
* Debuggee should be initially suspended and it will also left suspended
* by the CLASS_PREPARE event request.
*/
public long[] waitForClassesLoaded(String classNames[], byte suspendPolicy) {
int count = classNames.length;
// make requests for CLASS_PREPARE_EVENT for these class names
int[] requestIDs = new int[count];
for (int i = 0; i < count; i++) {
requestIDs[i] = requestClassPrepareEvent(classNames[i], suspendPolicy);
}
// resume initially suspended debugee
resume();
return waitForClassPrepareEvents(requestIDs, classNames);
}
/**
* Wait for breakpoint reached and return threadIDs.
* Debuggee should be initially suspended and it will also left suspended
* by the BREAKPOINT event request.
*/
public long waitForBreakpointReached(long classID, String methodName,
int line, byte suspendPolicy) {
// query debuggee for methodID
long methodID = getMethodID(classID, methodName, true);
// create BREAKPOINT event request
int requestID = requestBreakpointEvent(JDWP.TypeTag.CLASS, classID, methodID,
line, suspendPolicy);
// resume initially suspended debugee
resume();
// wait for BREAKPOINT event
return waitForBreakpointEvent(requestID);
}
// --------------------------------------------------- //
/**
* Wait for CLASS_PREPARE event made by given request received
* and return classID.
* Debuggee will be left suspended by the CLASS_PREPARE event.
*/
public long waitForClassPrepareEvent(int requestID, String className) {
String error = "Error occured while waiting for CLASS_PREPARE event for class:\n\t"
+ className;
String signature = "L" + className.replace('.', '/') + ";";
long classID = 0;
// wait for CLASS_PREPARE event
for(;;) {
EventPacket event = receiveEvent();
byte eventSuspendPolicy = 0;
long eventThreadID = 0;
try {
eventSuspendPolicy = event.getByte();
int events = event.getInt();
for (int i = 0; i < events; i++) {
// check event kind
byte eventKind = event.getByte();
if (eventKind == JDWP.EventKind.VM_DEATH) {
complain("Unexpected VM_DEATH event received: " + eventKind
+ " (expected: " + JDWP.EventKind.CLASS_PREPARE +")");
throw new Failure(error);
} else if (eventKind != JDWP.EventKind.CLASS_PREPARE) {
complain("Unexpected event kind received: " + eventKind
+ " (expected: " + JDWP.EventKind.CLASS_PREPARE +")");
throw new Failure(error);
}
// extract CLASS_PREPARE event specific data
int eventRequestID = event.getInt();
eventThreadID = event.getObjectID();
byte eventRefTypeTag = event.getByte();
long eventClassID = event.getReferenceTypeID();
String eventClassSignature = event.getString();
int eventClassStatus = event.getInt();
// check if event was single
if (events > 1) {
complain("Not single CLASS_PREPARE event received for class:\n\t"
+ eventClassSignature);
throw new Failure(error);
}
// check if event is for expected class
if (eventClassSignature.equals(signature)) {
// check if event is because of expected request
if (eventRequestID != requestID) {
complain("CLASS_PREPARE event with unexpected requestID ("
+ eventRequestID + ") received for class:\n\t"
+ eventClassSignature);
throw new Failure(error);
}
// remove event request
clearEventRequest(JDWP.EventKind.CLASS_PREPARE, requestID);
return eventClassID;
} else {
complain("Unexpected CLASS_PREPARE event received with class signature:\n"
+ " " + eventClassSignature);
}
}
} catch (BoundException e) {
complain("Unable to extract data from event packet while waiting for CLASS_PREPARE event:\n\t"
+ e.getMessage() + "\n" + event);
throw new Failure(error);
}
// resume debuggee according to event suspend policy
resumeEvent(eventSuspendPolicy, eventThreadID);
}
}
/**
* Wait for CLASS_PREPARE events made by given requests received
* and return classIDs.
* Debuggee will be left suspended by the CLASS_PREPARE event.
*/
public long[] waitForClassPrepareEvents(int requestIDs[], String classNames[]) {
int count = classNames.length;
String error = "Error occured while waiting for " + count + " CLASS_PREPARE events";
// prepare expected class signatures
String[] signatures = new String[count];
for (int i = 0; i < count; i++) {
signatures[i] = "L" + classNames[i].replace('.', '/') + ";";
}
// clear list of classIDs
long[] classIDs = new long[count];
for (int i = 0; i < count; i++) {
classIDs[i] = 0;
}
// wait for all expected CLASS_PREPARE events
int received = 0;
for(;;) {
EventPacket event = receiveEvent();
byte eventSuspendPolicy = 0;
long eventThreadID = 0;
try {
eventSuspendPolicy = event.getByte();
int events = event.getInt();
for (int i = 0; i < events; i++) {
// check event kind
byte eventKind = event.getByte();
if (eventKind == JDWP.EventKind.VM_DEATH) {
complain("Unexpected VM_DEATH event received: " + eventKind
+ " (expected: " + JDWP.EventKind.CLASS_PREPARE +")");
throw new Failure(error);
} else if (eventKind != JDWP.EventKind.CLASS_PREPARE) {
complain("Unexpected event kind received: " + eventKind
+ " (expected: " + JDWP.EventKind.CLASS_PREPARE +")");
throw new Failure(error);
}
// extracy CLASS_PREPARE event specific data
int eventRequestID = event.getInt();
eventThreadID = event.getObjectID();
byte eventRefTypeTag = event.getByte();
long eventClassID = event.getReferenceTypeID();
String eventClassSignature = event.getString();
int eventClassStatus = event.getInt();
// check if event was single
if (events > 1) {
complain("Not single CLASS_PREPARE event received for class:\n\t"
+ eventClassSignature);
}
// find appropriate class by signature
boolean found = false;
for (int j = 0; j < count; j++) {
if (eventClassSignature.equals(signatures[j])) {
found = true;
// check if event is not duplicated
if (classIDs[j] != 0) {
complain("Extra CLASS_PREPARE event recieved for class:\n\t"
+ eventClassSignature);
} else {
classIDs[j] = eventClassID;
received ++;
}
// check if event is because of expected request
if (eventRequestID != requestIDs[j]) {
complain("CLASS_PREPARE event with unexpected requestID ("
+ requestIDs[j] + ") received for class:\n\t"
+ eventClassSignature);
} else {
clearEventRequest(JDWP.EventKind.CLASS_PREPARE, requestIDs[j]);
}
}
}
if (!found) {
log.complain("Unexpected CLASS_PREPARE event received with class signature:\n"
+ " " + eventClassSignature);
}
}
} catch (BoundException e) {
complain("Unable to extract data from event packet while waiting for CLASS_PREPARE event:\n\t"
+ e.getMessage() + "\n" + event);
throw new Failure(error);
}
// if all events received return without resuming
if (received >= count)
return classIDs;
// resume debuggee according to events suspend policy
resumeEvent(eventSuspendPolicy, eventThreadID);
}
}
/**
* Wait for BREAKPOINT event made by the given request and return threadID.
* Debuggee will be left suspended by the BREAKPOINT event.
*/
public long waitForBreakpointEvent(int requestID) {
String error = "Error occured while waiting for BREAKPOINT event for ";
for(;;) {
EventPacket event = receiveEvent();
byte eventSuspendPolicy = 0;
long eventThreadID = 0;
try {
eventSuspendPolicy = event.getByte();
int events = event.getInt();
for (int i = 0; i < events; i++) {
// check event kind
byte eventKind = event.getByte();
if (eventKind == JDWP.EventKind.VM_DEATH) {
complain("Unexpected VM_DEATH event received: " + eventKind
+ " (expected: " + JDWP.EventKind.BREAKPOINT +")");
throw new Failure(error);
} else if (eventKind != JDWP.EventKind.BREAKPOINT) {
complain("Unexpected event kind received: " + eventKind
+ " (expected: " + JDWP.EventKind.BREAKPOINT +")");
throw new Failure(error);
}
// extrack specific BREAKPOINT event data
int eventRequestID = event.getInt();
eventThreadID = event.getObjectID();
JDWP.Location eventLocation = event.getLocation();
if (eventRequestID == requestID) {
clearEventRequest(JDWP.EventKind.BREAKPOINT, requestID);
return eventThreadID;
} else {
complain("Unexpected BREAKPOINT event received with requestID: "
+ eventRequestID + " (expected: " + requestID + ")");
}
}
} catch (BoundException e) {
complain("Unable to extract data from event packet while waiting for BREAKPOINT event:\n\t"
+ e.getMessage() + "\n" + event);
throw new Failure(error);
}
resumeEvent(eventSuspendPolicy, eventThreadID);
}
}
/**
* Resume debuggee according given event suspend policy.
*/
public void resumeEvent(byte suspendPolicy, long threadID) {
if (suspendPolicy == JDWP.SuspendPolicy.NONE) {
// do nothing
} else if (suspendPolicy == JDWP.SuspendPolicy.EVENT_THREAD) {
resumeThread(threadID);
} else if (suspendPolicy == JDWP.SuspendPolicy.ALL) {
resume();
} else {
throw new Failure("Unexpected event suspend policy while resuming debuggee: "
+ suspendPolicy);
}
}
// --------------------------------------------------- //
/**
* Query target VM for version info.
*/
public String getVersionInfo() {
String commandName = "VirtualMachine.Version";
CommandPacket command =
new CommandPacket(JDWP.Command.VirtualMachine.Version);
ReplyPacket reply = receiveReplyFor(command, commandName);
try {
String description = reply.getString();
int jdwpMajor = reply.getInt();
int jdwpMinor = reply.getInt();
String vmVersion = reply.getString();
String vmName = reply.getString();
return description;
} catch (BoundException e) {
complain("Unable to parse reply packet for " + commandName + " command:\n\t"
+ e.getMessage());
display("Reply packet:\n" + reply);
throw new Failure("Error occured while getting JDWP and VM version info");
}
}
/**
* Query target VM about VM dependent ID sizes.
*/
public void queryForIDSizes() {
String commandName = "VirtualMachine.IDSizes";
CommandPacket command = new CommandPacket(JDWP.Command.VirtualMachine.IDSizes);
ReplyPacket reply = receiveReplyFor(command);
try {
reply.resetPosition();
JDWP.TypeSize.FIELD_ID = reply.getInt();
JDWP.TypeSize.METHOD_ID = reply.getInt();
JDWP.TypeSize.OBJECT_ID = reply.getInt();
JDWP.TypeSize.REFERENCE_TYPE_ID = reply.getInt();
JDWP.TypeSize.FRAME_ID = reply.getInt();
} catch (BoundException e) {
complain("Unable to parse reply packet for " + commandName + " command:\n\t"
+ e.getMessage());
display("Reply packet:\n" + reply);
throw new Failure("Error occured while getting VM dependent ID sizes");
}
JDWP.TypeSize.CalculateSizes();
}
// --------------------------------------------------- //
/**
* Suspend the debugee VM by sending VirtualMachine.Suspend command.
*/
public void suspend() {
String commandName = "VirtualMachine.Suspend";
CommandPacket command = new CommandPacket(JDWP.Command.VirtualMachine.Suspend);
ReplyPacket reply = receiveReplyFor(command, commandName);
}
/**
* Resume the debugee VM by sending VirtualMachine.Resume command.
*/
public void resume() {
String commandName = "VirtualMachine.Resume";
CommandPacket command = new CommandPacket(JDWP.Command.VirtualMachine.Resume);
ReplyPacket reply = receiveReplyFor(command, commandName);
}
/**
* Dispose the debugee VM by sending VirtualMachine.Dispose command.
*/
public void dispose() {
String commandName = "VirtualMachine.Dispose";
CommandPacket command = new CommandPacket(JDWP.Command.VirtualMachine.Dispose);
ReplyPacket reply = receiveReplyFor(command, commandName);
}
// --------------------------------------------------- //
/**
* Sends JDWP command packet.
*/
public void sendCommand(CommandPacket packet, String commandName) {
try {
transport.write(packet);
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
complain("Caught IOException while sending command packet for "
+ commandName + ":\n\t" + e);
display("Command packet:\n" + packet);
throw new Failure("Error occured while sending command: " + commandName);
}
}
/**
* Receive next JDWP packet.
*/
/*
public Packet receivePacket() {
try {
ReplyPacket packet = new ReplyPacket();
transport.read(packet);
return packet;
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught IOException while receiving reply packet:\n\t" + e);
}
}
*/
/**
* Receive next JDWP reply packet.
*/
public ReplyPacket receiveReply() {
try {
for (;;) {
Packet packet = new Packet();
transport.read(packet);
if (packet.getFlags() == JDWP.Flag.REPLY_PACKET) {
ReplyPacket reply = new ReplyPacket(packet);
return reply;
}
EventPacket event = new EventPacket(packet);
display("Placing received event packet into queue");
eventQueue.add(event);
}
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught IOException while receiving reply packet:\n\t" + e);
}
}
/**
* Get next JDWP event packet by reading from transport or getting stored
* event in the event queue.
*/
public EventPacket getEventPacket() throws IOException {
// check events queue first
if (!eventQueue.isEmpty()) {
EventPacket event = (EventPacket)(eventQueue.removeFirst());
return event;
}
// read from transport
Packet packet = new Packet();
transport.read(packet);
EventPacket event = new EventPacket(packet);
return event;
}
/**
* Get next JDWP event packet by reading from transport for specified timeout
* or getting stored event in the event queue.
*/
public EventPacket getEventPacket(long timeout) throws IOException {
transport.setReadTimeout(timeout);
return getEventPacket();
}
/**
* Receive next JDWP event packet.
*/
public EventPacket receiveEvent() {
EventPacket packet = null;
try {
packet = getEventPacket();
} catch (IOException e) {
e.printStackTrace(log.getOutStream());
throw new Failure("Caught IOException while receiving event packet:\n\t" + e);
}
if (packet.getFlags() == JDWP.Flag.REPLY_PACKET) {
ReplyPacket reply = new ReplyPacket(packet);
log.complain("Unexpected reply packet received with id: "
+ reply.getPacketID());
log.display("Reply packet:\n" + reply);
throw new Failure("Unexpected reply packet received instead of event packet");
}
return packet;
}
/**
* Send specified command packet, receive and check reply packet.
*
* @throws Failure if exception caught in sending and reading packets
*/
public ReplyPacket receiveReplyFor(CommandPacket command) {
return receiveReplyFor(command, Packet.toHexString(command.getCommand(), 4));
}
/**
* Send specified command packet, receive and check reply packet.
*
* @throws Failure if exception caught in sending and reading packets
*/
public ReplyPacket receiveReplyFor(CommandPacket command, String commandName) {
ReplyPacket reply = null;
sendCommand(command, commandName);
reply = receiveReply();
try {
reply.checkHeader(command.getPacketID());
} catch (BoundException e) {
complain("Wrong header of reply packet for command "+ commandName + ":\n\t"
+ e.getMessage());
display("Reply packet:\n" + reply);
throw new Failure("Wrong reply packet received for command: " + commandName);
}
return reply;
}
/**
* Receive and check event packet for specified event kind.
*
* @throws Failure if exception caught in sending and reading packets
*/
public EventPacket receiveEventFor(int eventKind, String eventName) {
EventPacket event = null;
event = receiveEvent();
try {
event.checkHeader(eventKind);
} catch (BoundException e) {
complain("Wrong header of event packet for expected "+ eventName + " event:\n\t"
+ e.getMessage());
display("Event packet:\n" + event);
throw new Failure("Wrong event packet received for expected event: " + eventName);
}
return event;
}
// --------------------------------------------------- //
/**
* Check common VM capability.
*/
public boolean getCapability(int capability, String name) {
String commandName = "VirtualMachine.Capabilities";
int count = JDWP.Capability.CAN_GET_MONITOR_INFO + 1;
if (capability < 0 || capability >= count) {
throw new TestBug("Illegal capability number (" + capability
+ ") while checking for VM capability: " + name);
}
CommandPacket command =
new CommandPacket(JDWP.Command.VirtualMachine.Capabilities);
ReplyPacket reply = receiveReplyFor(command, commandName);
try {
reply.resetPosition();
for (int i = 0; i < count; i++) {
byte value = reply.getByte();
if (i == capability) {
return (value != 0);
}
}
} catch (BoundException e) {
complain("Unable to parse reply packet for " + commandName + " command:\n\t"
+ e.getMessage());
display("Reply packet:\n" + reply);
throw new Failure("Error occured while getting VM capability: "
+ name);
}
throw new TestBug("Illegal capability number (" + capability
+ ") while checking for VM capability: " + name);
}
/**
* Check new VM capability (since JDWP version 1.4).
*/
public boolean getNewCapability(int capability, String name) {
String commandName = "VirtualMachine.CapabilitiesNew";
int count = JDWP.Capability.CAN_SET_DEFAULT_STRATUM + 1;
if (capability < 0 || capability >= count) {
throw new TestBug("Illegal capability number (" + capability
+ ") while checking for VM new capability: " + name);
}
CommandPacket command =
new CommandPacket(JDWP.Command.VirtualMachine.CapabilitiesNew);
ReplyPacket reply = receiveReplyFor(command, commandName);
try {
reply.resetPosition();
for (int i = 0; i < count; i++) {
byte value = reply.getByte();
if (i == capability) {
return (value != 0);
}
}
} catch (BoundException e) {
complain("Unable to parse reply packet for " + commandName + " command:\n\t"
+ e.getMessage());
display("Reply packet:\n" + reply);
throw new Failure("Error occured while getting VM new capability: "
+ name);
}
throw new TestBug("Illegal capability number (" + capability
+ ") while checking for VM new capability: " + name);
}
// --------------------------------------------------- //
/**
* Return ReferenceTypeID for requested class by given signature.
*/
public long getReferenceTypeID(String classSignature) {
String commandName = "VirtualMachine.ClassesBySignature";
CommandPacket command =
new CommandPacket(JDWP.Command.VirtualMachine.ClassesBySignature);
command.addString(classSignature);
command.setLength();
ReplyPacket reply = receiveReplyFor(command, commandName);
long typeID = 0;
try {
reply.resetPosition();
int classes = reply.getInt();
for (int i = 0; i < classes; i++) {
byte refTypeTag = reply.getByte();
typeID = reply.getReferenceTypeID();
int status = reply.getInt();
}
if (classes < 0) {
throw new Failure("Negative number (" + classes
+ ") of referenceTypeIDs received for signature: "
+ classSignature);
}
if (classes == 0) {
throw new Failure("No any referenceTypeID received for signature: "
+ classSignature);
}
if (classes > 1) {
throw new Failure("Too many (" + classes
+ ") referenceTypeIDs received for signature: "
+ classSignature);
}
} catch (BoundException e) {
complain("Unable to parse reply packet for " + commandName + " command:\n\t"
+ e.getMessage());
display("Reply packet:\n" + reply);
throw new Failure("Error occured while getting referenceTypeID for signature: "
+ classSignature);
}
return typeID;
}
// --------------------------------------------------- //
/**
* Get list of IDs of supertypes (interfaces and classes) for given class.
*/
public long[] getSupertypes(long classID, boolean declared) {
Vectorapproximate
is