blob: 4b027426893fd600fba6eff9cadfb082cac8b263 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.server;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.rj.data.RJIO;
import org.eclipse.statet.rj.data.RJIOExternalizable;
import org.eclipse.statet.rj.server.dbg.CallStack;
import org.eclipse.statet.rj.server.dbg.CtrlReport;
import org.eclipse.statet.rj.server.dbg.DbgEnablement;
import org.eclipse.statet.rj.server.dbg.DbgFilterState;
import org.eclipse.statet.rj.server.dbg.DbgRequest;
import org.eclipse.statet.rj.server.dbg.ElementTracepointInstallationRequest;
import org.eclipse.statet.rj.server.dbg.FlagTracepointInstallationRequest;
import org.eclipse.statet.rj.server.dbg.FrameContext;
import org.eclipse.statet.rj.server.dbg.FrameContextDetailRequest;
import org.eclipse.statet.rj.server.dbg.SetDebugReport;
import org.eclipse.statet.rj.server.dbg.SetDebugRequest;
import org.eclipse.statet.rj.server.dbg.TracepointEvent;
import org.eclipse.statet.rj.server.dbg.TracepointStatesUpdate;
/**
* Command item for main loop dbg operations (="op")
*/
public final class DbgCmdItem extends MainCmdItem implements RjsComObject, Externalizable {
// -- C2S sync
public static final byte OP_LOAD_FRAME_LIST= 0001;
public static final byte OP_LOAD_FRAME_CONTEXT= 0002;
public static final byte OP_SET_DEBUG= 0003;
public static final byte OP_REQUEST_SUSPEND= 0004;
// public static final byte OP_CTRL_SUSPEND= 0010;
public static final byte OP_CTRL_RESUME= 0011;
public static final byte OP_CTRL_STEP_INTO= 0012;
public static final byte OP_CTRL_STEP_OVER= 0014;
public static final byte OP_CTRL_STEP_RETURN= 0016;
public static final byte OP_INSTALL_TP_FLAGS= 0020;
public static final byte OP_INSTALL_TP_POSITIONS= 0021;
// -- C2S sync + async
public static final byte OP_SET_ENABLEMENT= 0031;
public static final byte OP_RESET_FILTER_STATE= 0032;
public static final byte OP_UPDATE_TP_STATES= 0034;
// --
public static final byte OP_C2S_S2C= 0040;
// -- S2C sync
public static final byte OP_NOTIFY_TP_EVENTS= 0x41;
private static final int OV_WITHDATA= 0x01000000;
private static final int OV_WITHSTATUS= 0x08000000;
private static Object readRequestData(final RJIO io, final byte type) throws IOException {
switch (type) {
case OP_LOAD_FRAME_LIST:
return null;
case OP_LOAD_FRAME_CONTEXT:
return new FrameContextDetailRequest(io);
case OP_SET_DEBUG:
return new SetDebugRequest(io);
case OP_REQUEST_SUSPEND:
return null;
case OP_CTRL_RESUME:
return new DbgRequest.Resume(io);
case OP_CTRL_STEP_INTO:
return new DbgRequest.StepInto(io);
case OP_CTRL_STEP_OVER:
return new DbgRequest.StepOver(io);
case OP_CTRL_STEP_RETURN:
return new DbgRequest.StepReturn(io);
case OP_SET_ENABLEMENT:
return new DbgEnablement(io);
case OP_RESET_FILTER_STATE:
return new DbgFilterState(io);
case OP_INSTALL_TP_FLAGS:
return new FlagTracepointInstallationRequest(io);
case OP_INSTALL_TP_POSITIONS:
return new ElementTracepointInstallationRequest(io);
case OP_UPDATE_TP_STATES:
return new TracepointStatesUpdate(io);
case OP_NOTIFY_TP_EVENTS:
return readTracepointEvents(io);
default:
break;
}
throw new IOException("Unsupported type= " + type); //$NON-NLS-1$
}
private static Object readAnswerData(final RJIO io, final byte type) throws IOException {
switch (type) {
case OP_LOAD_FRAME_LIST:
return new CallStack(io);
case OP_LOAD_FRAME_CONTEXT:
return new FrameContext(io);
case OP_SET_DEBUG:
return new SetDebugReport(io);
case OP_REQUEST_SUSPEND:
break; // status
case OP_CTRL_RESUME:
case OP_CTRL_STEP_INTO:
case OP_CTRL_STEP_OVER:
case OP_CTRL_STEP_RETURN:
return new CtrlReport(io);
case OP_SET_ENABLEMENT:
case OP_RESET_FILTER_STATE:
break; // status
case OP_INSTALL_TP_FLAGS:
case OP_INSTALL_TP_POSITIONS:
case OP_UPDATE_TP_STATES:
break; // status
default:
break;
}
throw new IOException("Unsupported type= " + type); //$NON-NLS-1$
}
private static void writeList(final List<RJIOExternalizable> list, final RJIO io) throws IOException {
final int l= list.size();
io.writeInt(l);
for (int i= 0; i < l; i++) {
list.get(i).writeExternal(io);
}
}
private static List<TracepointEvent> readTracepointEvents(final RJIO io) throws IOException {
final TracepointEvent[] array= new TracepointEvent[io.readInt()];
for (int i= 0; i < array.length; i++) {
array[i]= new TracepointEvent(io);
}
return ImCollections.newList(array);
}
private byte op;
private Object data;
private RjsStatus status;
/**
* Constructor for new commands
*/
public DbgCmdItem(final byte op, final int options,
final RJIOExternalizable data) {
this.op= op;
this.options= (options & OM_CUSTOM);
if (data != null) {
this.options |= OV_WITHDATA;
}
if (op < OP_NOTIFY_TP_EVENTS) {
this.options |= OV_WAITFORCLIENT;
}
this.data= data;
}
/**
* Constructor for new commands
*/
public DbgCmdItem(final byte op, final int options,
final List<? extends RJIOExternalizable> data) {
assert (op == OP_NOTIFY_TP_EVENTS);
this.op= op;
this.options= (options & OM_CUSTOM);
if (data != null) {
this.options |= OV_WITHDATA;
}
if (op < OP_NOTIFY_TP_EVENTS) {
this.options |= OV_WAITFORCLIENT;
}
this.data= data;
}
/**
* Constructor for automatic deserialization
*/
public DbgCmdItem() {
}
/**
* Constructor for deserialization
*/
public DbgCmdItem(final RJIO io) throws IOException {
readExternal(io);
}
@Override
public void writeExternal(final RJIO io) throws IOException {
io.writeInt(this.options);
io.writeByte(this.op);
if ((this.options & OV_WITHSTATUS) != 0) {
this.status.writeExternal(io);
}
else if ((this.options & OV_WITHDATA) != 0) {
if (this.op == OP_NOTIFY_TP_EVENTS) {
writeList((List<RJIOExternalizable>) this.data, io);
}
else {
((RJIOExternalizable) this.data).writeExternal(io);
}
}
}
@Override
public void writeExternal(final ObjectOutput out) throws IOException {
final RJIO io= RJIO.get(out);
final int check= io.writeCheck1();
writeExternal(io);
io.writeCheck2(check);
io.disconnect(out);
}
private void readExternal(final RJIO io) throws IOException {
this.options= io.readInt();
this.op= io.readByte();
if ((this.options & OV_WITHSTATUS) != 0) {
this.status= new RjsStatus(io);
}
else if ((this.options & OV_WITHDATA) != 0) {
this.data= ((this.options & OV_ANSWER) == 0) ?
readRequestData(io, this.op) :
readAnswerData(io, this.op);
}
}
@Override
public void readExternal(final ObjectInput in) throws IOException {
final RJIO io= RJIO.get(in);
final int check= io.readCheck1();
readExternal(io);
io.readCheck2(check);
io.disconnect(in);
}
@Override
public int getComType() {
return T_DBG;
}
@Override
public byte getCmdType() {
return T_DBG_ITEM;
}
@Override
public void setAnswer(final RjsStatus status) {
assert (status != null);
if (status == RjsStatus.OK_STATUS) {
this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
this.status= null;
this.data= null;
}
else {
this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
this.status= status;
this.data= null;
}
}
public void setAnswer(final RJIOExternalizable data) {
this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
if (data != null) {
this.options |= OV_WITHDATA;
}
this.status= null;
this.data= data;
}
@Override
public byte getOp() {
return this.op;
}
@Override
public boolean isOK() {
return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
}
@Override
public RjsStatus getStatus() {
return this.status;
}
@Override
public String getDataText() {
return null;
}
public Object getData() {
return this.data;
}
@Override
public boolean testEquals(final MainCmdItem other) {
if (!(other instanceof DbgCmdItem)) {
return false;
}
final DbgCmdItem otherItem= (DbgCmdItem) other;
if (getOp() != otherItem.getOp()) {
return false;
}
if (this.options != otherItem.options) {
return false;
}
return true;
}
@Override
public String toString() {
final StringBuffer sb= new StringBuffer(100);
sb.append("DbgCmdItem "); //$NON-NLS-1$
switch (this.op) {
case OP_LOAD_FRAME_LIST:
sb.append("LOAD_FRAME_LIST"); //$NON-NLS-1$
break;
case OP_LOAD_FRAME_CONTEXT:
sb.append("LOAD_FRAME_CONTEXT"); //$NON-NLS-1$
break;
case OP_SET_DEBUG:
sb.append("SET_DEBUG"); //$NON-NLS-1$
break;
case OP_REQUEST_SUSPEND:
sb.append("REQUEST_SUSPEND"); //$NON-NLS-1$
break;
case OP_CTRL_RESUME:
sb.append("CTRL_RESUME"); //$NON-NLS-1$
break;
case OP_CTRL_STEP_INTO:
sb.append("CTRL_STEP_INTO"); //$NON-NLS-1$
break;
case OP_CTRL_STEP_OVER:
sb.append("CTRL_STEP_OVER"); //$NON-NLS-1$
break;
case OP_CTRL_STEP_RETURN:
sb.append("CTRL_STEP_RETURN"); //$NON-NLS-1$
break;
case OP_INSTALL_TP_FLAGS:
sb.append("INSTALL_TP_FLAGS"); //$NON-NLS-1$
break;
case OP_INSTALL_TP_POSITIONS:
sb.append("INSTALL_TP_POSITIONS"); //$NON-NLS-1$
break;
case OP_SET_ENABLEMENT:
sb.append("SET_ENABLEMENT"); //$NON-NLS-1$
break;
case OP_RESET_FILTER_STATE:
sb.append("RESET_FILTER_STATE"); //$NON-NLS-1$
break;
case OP_UPDATE_TP_STATES:
sb.append("UPDATE_TP_STATES"); //$NON-NLS-1$
break;
case OP_NOTIFY_TP_EVENTS:
sb.append("NOTIFY_TP_EVENT"); //$NON-NLS-1$
break;
default:
sb.append(this.op);
break;
}
sb.append("\n\t" + "options= 0x").append(Integer.toHexString(this.options)); //$NON-NLS-1$ //$NON-NLS-2$
if ((this.options & OV_WITHDATA) != 0) {
sb.append("\n<DATA>\n"); //$NON-NLS-1$
sb.append(this.data);
sb.append("\n</DATA>"); //$NON-NLS-1$
}
return sb.toString();
}
}