├── .gitignore
├── README.md
├── commands
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── kaap
│ │ │ └── veiko
│ │ │ └── debuggerforker
│ │ │ └── commands
│ │ │ ├── Command.java
│ │ │ ├── CommandBase.java
│ │ │ ├── CommandStream.java
│ │ │ ├── CommandVisitor.java
│ │ │ ├── MutableCommandPacket.java
│ │ │ ├── MutableReplyPacket.java
│ │ │ ├── UnknownCommand.java
│ │ │ ├── commandsets
│ │ │ ├── CommandIdentifier.java
│ │ │ ├── event
│ │ │ │ ├── CompositeEventCommand.java
│ │ │ │ └── events
│ │ │ │ │ ├── BreakPointEvent.java
│ │ │ │ │ ├── ClassPrepareEvent.java
│ │ │ │ │ ├── ClassUnloadEvent.java
│ │ │ │ │ ├── ExceptionEvent.java
│ │ │ │ │ ├── FieldAccessEvent.java
│ │ │ │ │ ├── FieldModificationEvent.java
│ │ │ │ │ ├── MethodEntryEvent.java
│ │ │ │ │ ├── MethodExitEvent.java
│ │ │ │ │ ├── MethodExitWithReturnValueEvent.java
│ │ │ │ │ ├── MonitorContendedEnterEvent.java
│ │ │ │ │ ├── MonitorContendedEnteredEvent.java
│ │ │ │ │ ├── MonitorWaitEvent.java
│ │ │ │ │ ├── MonitorWaitedEvent.java
│ │ │ │ │ ├── SingleStepEvent.java
│ │ │ │ │ ├── ThreadDeathEvent.java
│ │ │ │ │ ├── ThreadStartEvent.java
│ │ │ │ │ ├── VirtualMachineEvent.java
│ │ │ │ │ ├── VmDeathEvent.java
│ │ │ │ │ └── VmStartEvent.java
│ │ │ ├── eventrequest
│ │ │ │ ├── ClearAllBreakpointsCommand.java
│ │ │ │ ├── ClearEventRequestCommand.java
│ │ │ │ ├── ClearEventRequestReply.java
│ │ │ │ ├── SetEventRequestCommand.java
│ │ │ │ ├── SetEventRequestReply.java
│ │ │ │ └── filters
│ │ │ │ │ └── EventRequestFilter.java
│ │ │ └── virtualmachine
│ │ │ │ ├── DisposeCommand.java
│ │ │ │ ├── DisposeReply.java
│ │ │ │ ├── HoldEventsCommand.java
│ │ │ │ ├── IdSizesReply.java
│ │ │ │ ├── ReleaseEventsCommand.java
│ │ │ │ ├── ResumeCommand.java
│ │ │ │ └── ResumeReply.java
│ │ │ ├── parser
│ │ │ ├── CommandDataReader.java
│ │ │ ├── CommandParser.java
│ │ │ └── CommandType.java
│ │ │ └── util
│ │ │ └── CommandDataUtil.java
│ └── kotlin
│ │ └── kaap
│ │ └── veiko
│ │ └── debuggerforker
│ │ └── commands
│ │ └── commandsets
│ │ └── eventrequest
│ │ └── filters
│ │ ├── ClassExcludeEventRequestFilter.kt
│ │ ├── ClassMatchEventRequestFilter.kt
│ │ ├── ClassOnlyEventRequestFilter.kt
│ │ ├── ConditionalEventRequestFilter.kt
│ │ ├── CountEventRequestFilter.kt
│ │ ├── ExceptionOnlyEventRequestFilter.kt
│ │ ├── FieldOnlyEventRequestFilter.kt
│ │ ├── InstanceOnlyEventRequestFilter.kt
│ │ ├── LocationOnlyEventRequestFilter.kt
│ │ ├── SourceNameMatchEventRequestFilter.kt
│ │ ├── StepEventRequestFilter.kt
│ │ └── ThreadOnlyEventRequestFilter.kt
│ └── test
│ └── java
│ └── kaap
│ └── veiko
│ └── debuggerforker
│ └── commands
│ └── commandsets
│ ├── CommandTestBase.java
│ ├── TestBase.java
│ ├── event
│ └── events
│ │ ├── BreakPointEventTest.java
│ │ ├── ClassPrepareEventTest.java
│ │ ├── ClassUnloadEventTest.java
│ │ ├── EventTestBase.java
│ │ ├── ExceptionEventTest.java
│ │ ├── FieldAccessEventTest.java
│ │ ├── FieldModificationEventTest.java
│ │ ├── MethodEntryEventTest.java
│ │ ├── MethodExitEventTest.java
│ │ ├── MethodExitWithReturnValueEventTest.java
│ │ ├── MonitorContendedEnterEventTest.java
│ │ ├── MonitorContendedEnteredEventTest.java
│ │ ├── MonitorWaitEventTest.java
│ │ ├── MonitorWaitedEventTest.java
│ │ ├── SingleStepEventTest.java
│ │ ├── ThreadDeathEventTest.java
│ │ ├── ThreadStartEventTest.java
│ │ ├── VmDeathEventTest.java
│ │ └── VmStartEventTest.java
│ └── virtualmachine
│ ├── DisposeCommandTest.java
│ ├── DisposeReplyTest.java
│ ├── HoldEventsCommandTest.java
│ ├── IdSizesReplyTest.java
│ └── ReleaseEventsCommandTest.java
├── connections
├── pom.xml
└── src
│ └── main
│ └── java
│ └── kaap
│ └── veiko
│ └── debuggerforker
│ └── connections
│ ├── ConnectorBase.java
│ ├── DebuggerConnector.java
│ └── VMConnector.java
├── integration-tests
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── ee
│ │ │ └── veikokaap
│ │ │ └── debugproxy
│ │ │ └── testframework
│ │ │ ├── DebuggerProcess.java
│ │ │ ├── EventRequestIdentifier.java
│ │ │ ├── JvmProcess.java
│ │ │ ├── SuspendManager.java
│ │ │ └── utils
│ │ │ ├── BreakpointLocation.java
│ │ │ ├── BreakpointUtil.java
│ │ │ └── MarkerFinder.java
│ └── kotlin
│ │ └── ee
│ │ └── veikokaap
│ │ └── debugproxy
│ │ └── testframework
│ │ ├── AsyncTester.kt
│ │ └── SuspendManagerAsyncTester.kt
│ └── test
│ ├── java
│ └── ee
│ │ └── veikokaap
│ │ └── debugproxy
│ │ └── tests
│ │ ├── LoopBreakpointClass.java
│ │ ├── SimpleBreakpointClass.java
│ │ └── StepBreakpointClass.java
│ └── kotlin
│ └── ee
│ └── veikokaap
│ └── debugproxy
│ └── tests
│ ├── doubledebugger
│ ├── SimpleDoubleDebuggerTests.kt
│ └── StepDoubleDebuggerTests.kt
│ ├── singledebugger
│ ├── LoopSingleDebuggerTests.kt
│ ├── SimpleSingleDebuggerTests.kt
│ └── StepSingleDebuggerTests.kt
│ └── testFunctions.kt
├── packet
├── pom.xml
└── src
│ └── main
│ └── java
│ └── kaap
│ └── veiko
│ └── debuggerforker
│ └── packet
│ ├── CommandPacket.java
│ ├── DebuggerPacketStream.java
│ ├── Packet.java
│ ├── PacketSource.java
│ ├── PacketStream.java
│ ├── PacketVisitor.java
│ ├── ReplyPacket.java
│ ├── VirtualMachinePacketStream.java
│ ├── internal
│ ├── ByteBufferDataReader.java
│ ├── ByteBufferDataWriter.java
│ ├── DebuggerPacketTransformer.java
│ ├── PacketBase.java
│ ├── PacketParser.java
│ ├── PacketReader.java
│ ├── PacketStreamBase.java
│ ├── PacketTransformer.java
│ ├── PacketWriter.java
│ └── VmPacketTransformer.java
│ └── utils
│ └── ByteBufferUtil.java
├── pom.xml
├── server-logic
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── kaap
│ │ └── veiko
│ │ └── debuggerforker
│ │ ├── DebugProxyServer.java
│ │ ├── DebuggerProxy.java
│ │ ├── Main.java
│ │ ├── ProxyCommandStream.java
│ │ ├── handlers
│ │ ├── CommandHandler.java
│ │ ├── RequestHandler.java
│ │ └── RequestIdentifier.java
│ │ └── managers
│ │ ├── ChannelInputOutputManager.java
│ │ └── CommandStreamInputOutputManager.java
│ └── resources
│ └── logback.xml
└── types
├── pom.xml
└── src
└── main
└── java
└── kaap
└── veiko
└── debuggerforker
└── types
├── DataReader.java
├── DataType.java
├── DataWriter.java
├── VMInformation.java
└── jdwp
├── ArrayId.java
├── ArrayTypeId.java
├── ClassId.java
├── ClassLoaderId.java
├── ClassObjectId.java
├── DataTypeBase.java
├── EventKind.java
├── FieldId.java
├── FrameId.java
├── IdSizes.java
├── InterfaceId.java
├── Location.java
├── MethodId.java
├── ObjectId.java
├── ReferenceTypeId.java
├── StringId.java
├── TaggedObjectId.java
├── ThreadGroupId.java
├── ThreadId.java
├── Type.java
├── UntaggedValue.java
└── Value.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | /target
3 | /out
4 | *.iml
5 | *.iws
6 | *.ipr
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The code part of my bachelour thesis "Java Virtual Machine multi-debugger proxy server".
2 |
3 | This is the source code of my thesis.
4 | The TeX source code of my thesis is available at https://github.com/veikokaap/bachelor-thesis
5 | The final result is available at https://comserv.cs.ut.ee/ati_thesis/datasheet.php?id=61837&year=2018&language=en
6 |
7 | ## Status
8 |
9 | The main part of the proxy server works.
10 | It is possible to attach the proxy server to a single JVM and then to attach multiple debbugers to the proxy server.
11 | Adding/removing breakpoints mostly works, but this is definitely not a ready product to be actually used for debugging.
12 | As part of the thesis, the most important part was to prove that it is actually even possible to create such a functionality,
13 | but I currently simply don't have the time to finish it.
14 |
15 | There is also a bit of code here that I would like to refactor and that I'm not really proud of that I hope to refactor in the future.
16 |
17 | ## Building
18 |
19 | Run `mvn clean package -DskipTests` to just build the server without running any tests.
20 |
--------------------------------------------------------------------------------
/commands/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jvm-debugger-forker
7 | kaap.veiko
8 | 0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | commands
13 |
14 |
15 |
16 | kaap.veiko
17 | types
18 | ${parent.version}
19 |
20 |
21 | kaap.veiko
22 | packet
23 | ${parent.version}
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/Command.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import kaap.veiko.debuggerforker.packet.Packet;
4 | import kaap.veiko.debuggerforker.packet.PacketSource;
5 | import kaap.veiko.debuggerforker.types.DataWriter;
6 |
7 | public interface Command {
8 | int getCommandSetId();
9 |
10 | int getCommandId();
11 |
12 | boolean isReply();
13 |
14 | void visit(CommandVisitor visitor);
15 |
16 | T getPacket();
17 |
18 | PacketSource getSource();
19 |
20 | void writeCommand(DataWriter writer);
21 | }
22 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/CommandBase.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import kaap.veiko.debuggerforker.commands.parser.CommandType;
4 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
5 | import kaap.veiko.debuggerforker.packet.Packet;
6 | import kaap.veiko.debuggerforker.packet.PacketSource;
7 |
8 | public abstract class CommandBase implements Command {
9 |
10 | private final T packet;
11 | private final CommandIdentifier commandIdentifier;
12 |
13 | protected CommandBase(T packet, CommandIdentifier commandIdentifier) {
14 | this.packet = packet;
15 | this.commandIdentifier = commandIdentifier;
16 | }
17 |
18 | @Override
19 | public T getPacket() {
20 | return packet;
21 | }
22 |
23 | @Override
24 | public PacketSource getSource() {
25 | return packet.getSource();
26 | }
27 |
28 | @Override
29 | public int getCommandSetId() {
30 | return commandIdentifier.getCommandSetId();
31 | }
32 |
33 | @Override
34 | public int getCommandId() {
35 | return commandIdentifier.getCommandId();
36 | }
37 |
38 | @Override
39 | public boolean isReply() {
40 | return commandIdentifier.getType() == CommandType.REPLY;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/CommandStream.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.SelectionKey;
5 | import java.nio.channels.Selector;
6 | import java.nio.channels.SocketChannel;
7 | import java.util.Optional;
8 |
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import kaap.veiko.debuggerforker.commands.parser.CommandParser;
13 | import kaap.veiko.debuggerforker.packet.PacketSource;
14 | import kaap.veiko.debuggerforker.packet.PacketStream;
15 | import kaap.veiko.debuggerforker.types.VMInformation;
16 |
17 | public class CommandStream implements AutoCloseable {
18 |
19 | private static final Logger log = LoggerFactory.getLogger(CommandStream.class);
20 |
21 | private final PacketStream packetStream;
22 | private final VMInformation vmInformation;
23 | private final CommandParser commandParser;
24 |
25 | public CommandStream(PacketStream packetStream, VMInformation vmInformation) {
26 | this.packetStream = packetStream;
27 | this.vmInformation = vmInformation;
28 | this.commandParser = new CommandParser(vmInformation);
29 | }
30 |
31 | public Command read() throws IOException {
32 | return Optional.ofNullable(packetStream.read())
33 | .map(commandParser::parse)
34 | .orElse(null);
35 | }
36 |
37 | public void write(Command command) throws IOException {
38 | if (command != null && command.getPacket() != null) {
39 | packetStream.write(command.getPacket());
40 | }
41 | }
42 |
43 | public SocketChannel getSocketChannel() {
44 | return packetStream.getSocketChannel();
45 | }
46 |
47 | public PacketSource getSource() {
48 | return packetStream.getSource();
49 | }
50 |
51 | public void close() {
52 | packetStream.close();
53 | }
54 |
55 | public boolean isClosed() {
56 | return packetStream.isClosed();
57 | }
58 |
59 | @Override
60 | public boolean equals(Object o) {
61 | if (this == o) {
62 | return true;
63 | }
64 | if (o == null || getClass() != o.getClass()) {
65 | return false;
66 | }
67 |
68 | CommandStream that = (CommandStream) o;
69 |
70 | return packetStream.equals(that.packetStream);
71 | }
72 |
73 | @Override
74 | public int hashCode() {
75 | return packetStream.hashCode();
76 | }
77 |
78 | @Override
79 | public String toString() {
80 | return "CommandStream{" +
81 | "packetStream=" + packetStream +
82 | '}';
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/CommandVisitor.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import kaap.veiko.debuggerforker.commands.commandsets.event.CompositeEventCommand;
4 | import kaap.veiko.debuggerforker.commands.commandsets.eventrequest.ClearAllBreakpointsCommand;
5 | import kaap.veiko.debuggerforker.commands.commandsets.eventrequest.ClearEventRequestCommand;
6 | import kaap.veiko.debuggerforker.commands.commandsets.eventrequest.ClearEventRequestReply;
7 | import kaap.veiko.debuggerforker.commands.commandsets.eventrequest.SetEventRequestCommand;
8 | import kaap.veiko.debuggerforker.commands.commandsets.eventrequest.SetEventRequestReply;
9 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.DisposeCommand;
10 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.DisposeReply;
11 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.HoldEventsCommand;
12 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.IdSizesReply;
13 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.ReleaseEventsCommand;
14 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.ResumeCommand;
15 | import kaap.veiko.debuggerforker.commands.commandsets.virtualmachine.ResumeReply;
16 |
17 | public interface CommandVisitor {
18 | void visit(CompositeEventCommand command);
19 |
20 | void visit(ClearAllBreakpointsCommand command);
21 |
22 | void visit(ClearEventRequestCommand command);
23 |
24 | void visit(SetEventRequestCommand command);
25 |
26 | void visit(SetEventRequestReply command);
27 |
28 | void visit(DisposeCommand command);
29 |
30 | void visit(IdSizesReply command);
31 |
32 | void visit(DisposeReply disposeReply);
33 |
34 | void visit(UnknownCommand packetCommand);
35 |
36 | void visit(HoldEventsCommand holdEventsCommand);
37 |
38 | void visit(ReleaseEventsCommand releaseEventsCommand);
39 |
40 | void visit(ResumeCommand resumeCommand);
41 |
42 | void visit(ClearEventRequestReply clearEventRequestReply);
43 |
44 | void visit(ResumeReply resumeReply);
45 | }
46 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/MutableCommandPacket.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
4 | import kaap.veiko.debuggerforker.packet.CommandPacket;
5 |
6 | public class MutableCommandPacket extends CommandPacket {
7 |
8 | private byte[] data;
9 |
10 | public static MutableCommandPacket create(int packetId, CommandIdentifier commandIdentifier) {
11 | return new MutableCommandPacket(packetId, commandIdentifier.getCommandSetId(), commandIdentifier.getCommandId());
12 | }
13 |
14 | private MutableCommandPacket(int id, short commandSetId, short commandId) {
15 | super(id, commandSetId, commandId, new byte[0], null);
16 | this.data = super.getData();
17 | }
18 |
19 | public void setData(byte[] data) {
20 | this.data = data;
21 | }
22 |
23 | @Override
24 | public byte[] getData() {
25 | return data;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/MutableReplyPacket.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
4 |
5 | public class MutableReplyPacket extends ReplyPacket {
6 |
7 | private byte[] data;
8 |
9 | public static MutableReplyPacket create(int packetId) {
10 | return new MutableReplyPacket(packetId, (short) 0);
11 | }
12 |
13 | private MutableReplyPacket(int id, short errorCode) {
14 | super(id, errorCode, new byte[0], null);
15 | this.data = super.getData();
16 | }
17 |
18 | public void setData(byte[] data) {
19 | this.data = data;
20 | }
21 |
22 | @Override
23 | public byte[] getData() {
24 | return data;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/UnknownCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands;
2 |
3 | import kaap.veiko.debuggerforker.packet.Packet;
4 | import kaap.veiko.debuggerforker.packet.PacketSource;
5 | import kaap.veiko.debuggerforker.types.DataWriter;
6 |
7 | public class UnknownCommand implements Command {
8 |
9 | private final Packet packet;
10 | private final int commandId;
11 | private final int commandSetId;
12 | private final boolean reply;
13 |
14 | public UnknownCommand(Packet packet, int commandSetId, int commandId, boolean reply) {
15 | this.packet = packet;
16 | this.commandSetId = commandSetId;
17 | this.commandId = commandId;
18 | this.reply = reply;
19 | }
20 |
21 | @Override
22 | public int getCommandSetId() {
23 | return commandSetId;
24 | }
25 |
26 | @Override
27 | public int getCommandId() {
28 | return commandId;
29 | }
30 |
31 | @Override
32 | public boolean isReply() {
33 | return reply;
34 | }
35 |
36 | @Override
37 | public void visit(CommandVisitor visitor) {
38 | visitor.visit(this);
39 | }
40 |
41 | @Override
42 | public Packet getPacket() {
43 | return packet;
44 | }
45 |
46 | @Override
47 | public PacketSource getSource() {
48 | return packet.getSource();
49 | }
50 |
51 | @Override
52 | public void writeCommand(DataWriter writer) {
53 | for (byte b : packet.getData()) {
54 | writer.writeByte(b);
55 | }
56 | }
57 |
58 | @Override
59 | public String toString() {
60 | return "UnknownCommand{" +
61 | "packet=" + packet +
62 | '}';
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/CommandIdentifier.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets;
2 |
3 | import static kaap.veiko.debuggerforker.commands.parser.CommandType.COMMAND;
4 | import static kaap.veiko.debuggerforker.commands.parser.CommandType.REPLY;
5 |
6 | import java.io.IOException;
7 | import java.util.Arrays;
8 | import java.util.List;
9 | import java.util.stream.Collectors;
10 |
11 | import kaap.veiko.debuggerforker.commands.parser.CommandType;
12 |
13 | public enum CommandIdentifier {
14 |
15 | DISPOSE_COMMAND(1, 6, COMMAND),
16 | DISPOSE_REPLY(1, 6, REPLY),
17 | ID_SIZES_REPLY(1, 7, REPLY),
18 | RESUME_COMMAND(1, 9, COMMAND),
19 | RESUME_REPLY(1, 9, REPLY),
20 | HOLD_EVENTS_COMMAND(1, 15, COMMAND),
21 | RELEASE_EVENTS_COMMAND(1, 16, COMMAND),
22 |
23 | SET_EVENT_REQUEST_COMMAND(15, 1, COMMAND),
24 | SET_EVENT_REQUEST_REPLY(15, 1, REPLY),
25 | CLEAR_EVENT_REQUEST_COMMAND(15, 2, COMMAND),
26 | CLEAR_EVENT_REQUEST_REPLY(15, 2, REPLY),
27 | CLEAR_ALL_BREAKPOINTS_COMMAND(15, 3, COMMAND),
28 |
29 | COMPOSITE_EVENT_COMMAND(64, 100, COMMAND);
30 |
31 | private final short commandSetId;
32 | private final short commandId;
33 | private final CommandType type;
34 |
35 | CommandIdentifier(int commandSetId, int commandId, CommandType type) {
36 | this.commandSetId = (short) commandSetId;
37 | this.commandId = (short) commandId;
38 | this.type = type;
39 | }
40 |
41 | public static CommandIdentifier of(short commandSet, short command, boolean reply) throws IOException {
42 | List identifiers = Arrays.stream(values())
43 | .filter(ci -> ci.getCommandSetId() == commandSet)
44 | .filter(ci -> ci.getCommandId() == command)
45 | .filter(ci -> reply ? ci.getType().equals(REPLY) : ci.getType().equals(COMMAND))
46 | .collect(Collectors.toList());
47 |
48 | if (identifiers.isEmpty()) {
49 | throw new IOException("Couldn't find the identifier for commandSet=" + commandSet + ", command=" + command + ", reply=" + reply + ".");
50 | }
51 |
52 | return identifiers.get(0);
53 | }
54 |
55 | public short getCommandSetId() {
56 | return commandSetId;
57 | }
58 |
59 | public short getCommandId() {
60 | return commandId;
61 | }
62 |
63 | public CommandType getType() {
64 | return type;
65 | }
66 |
67 | public short getFlags() {
68 | if (type == REPLY) {
69 | return -128;
70 | }
71 | else {
72 | return 0;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/CompositeEventCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event;
2 |
3 | import java.util.List;
4 |
5 | import kaap.veiko.debuggerforker.commands.CommandBase;
6 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
7 | import kaap.veiko.debuggerforker.commands.MutableCommandPacket;
8 | import kaap.veiko.debuggerforker.commands.commandsets.event.events.VirtualMachineEvent;
9 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
10 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
11 | import kaap.veiko.debuggerforker.commands.util.CommandDataUtil;
12 | import kaap.veiko.debuggerforker.packet.CommandPacket;
13 | import kaap.veiko.debuggerforker.types.DataWriter;
14 | import kaap.veiko.debuggerforker.types.VMInformation;
15 |
16 | public class CompositeEventCommand extends CommandBase {
17 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.COMPOSITE_EVENT_COMMAND;
18 |
19 | private final byte suspendPolicy;
20 | private final List events;
21 |
22 | public static CompositeEventCommand create(int packetId, byte suspendPolicy, List events, VMInformation vmInformation) {
23 | MutableCommandPacket packet = MutableCommandPacket.create(packetId, COMMAND_IDENTIFIER);
24 | CompositeEventCommand command = new CompositeEventCommand(packet, suspendPolicy, events);
25 | packet.setData(CommandDataUtil.getCommandDataBytes(command, vmInformation));
26 |
27 | return command;
28 | }
29 |
30 | public static CompositeEventCommand read(CommandDataReader reader) {
31 | byte suspendPolicy = reader.readByte();
32 | List events = VirtualMachineEvent.readList(reader);
33 |
34 | return new CompositeEventCommand((CommandPacket) reader.getPacket(), suspendPolicy, events);
35 | }
36 |
37 | private CompositeEventCommand(CommandPacket packet, byte suspendPolicy, List events) {
38 | super(packet, CommandIdentifier.COMPOSITE_EVENT_COMMAND);
39 | this.suspendPolicy = suspendPolicy;
40 | this.events = events;
41 | }
42 |
43 | @Override
44 | public void writeCommand(DataWriter writer) {
45 | writer.writeByte(suspendPolicy);
46 | VirtualMachineEvent.writeList(writer, events);
47 | }
48 |
49 | public byte getSuspendPolicy() {
50 | return suspendPolicy;
51 | }
52 |
53 | public List getEvents() {
54 | return events;
55 | }
56 |
57 | @Override
58 | public void visit(CommandVisitor visitor) {
59 | visitor.visit(this);
60 | }
61 |
62 | @Override
63 | public String toString() {
64 | return "CompositeEventCommand{" +
65 | "suspendPolicy=" + suspendPolicy +
66 | ", events=" + events +
67 | '}';
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/BreakPointEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 |
11 | @AutoValue
12 | public abstract class BreakPointEvent extends VirtualMachineEvent {
13 | public abstract int getRequestId();
14 | public abstract ThreadId getThread();
15 | public abstract Location getLocation();
16 |
17 | public EventKind getEventKind() {
18 | return EventKind.BREAKPOINT;
19 | }
20 |
21 | public static BreakPointEvent create(int requestId, ThreadId thread, Location location) {
22 | return new AutoValue_BreakPointEvent(requestId, thread, location);
23 | }
24 |
25 | public static BreakPointEvent read(DataReader reader) {
26 | return create(
27 | reader.readInt(),
28 | ThreadId.read(reader),
29 | Location.read(reader)
30 | );
31 | }
32 |
33 | public void write(DataWriter writer) {
34 | writer.writeType(getEventKind());
35 | writer.writeInt(getRequestId());
36 | writer.writeType(getThread());
37 | writer.writeType(getLocation());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ClassPrepareEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 |
11 | @AutoValue
12 | public abstract class ClassPrepareEvent extends VirtualMachineEvent {
13 | public abstract int getRequestId();
14 | public abstract ThreadId getThread();
15 | public abstract byte getRefTypeTag();
16 | public abstract ReferenceTypeId getTypeId();
17 | public abstract String getSignature();
18 | public abstract int getStatus();
19 |
20 | public EventKind getEventKind() {
21 | return EventKind.CLASS_PREPARE;
22 | }
23 |
24 | public static ClassPrepareEvent create(int requestId, ThreadId thread, byte refTypeTag, ReferenceTypeId typeId, String signature, int status) {
25 | return new AutoValue_ClassPrepareEvent(requestId, thread, refTypeTag, typeId, signature, status);
26 | }
27 |
28 | public static ClassPrepareEvent read(DataReader reader) {
29 | return create(
30 | reader.readInt(),
31 | ThreadId.read(reader),
32 | reader.readByte(),
33 | ReferenceTypeId.read(reader),
34 | reader.readString(),
35 | reader.readInt()
36 | );
37 | }
38 |
39 | @Override
40 | public void write(DataWriter writer) {
41 | writer.writeType(getEventKind());
42 | writer.writeInt(getRequestId());
43 | writer.writeType(getThread());
44 | writer.writeByte(getRefTypeTag());
45 | writer.writeType(getTypeId());
46 | writer.writeString(getSignature());
47 | writer.writeInt(getStatus());
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ClassUnloadEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 |
9 | @AutoValue
10 | public abstract class ClassUnloadEvent extends VirtualMachineEvent {
11 | public abstract int getRequestId();
12 | public abstract String getSignature();
13 |
14 | public EventKind getEventKind() {
15 | return EventKind.CLASS_UNLOAD;
16 | }
17 |
18 | public static ClassUnloadEvent create(int requestId, String signature) {
19 | return new AutoValue_ClassUnloadEvent(requestId, signature);
20 | }
21 |
22 | public static ClassUnloadEvent read(DataReader reader) {
23 | return create(
24 | reader.readInt(),
25 | reader.readString()
26 | );
27 | }
28 |
29 | @Override
30 | public void write(DataWriter writer) {
31 | writer.writeType(getEventKind());
32 | writer.writeInt(getRequestId());
33 | writer.writeString(getSignature());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ExceptionEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
10 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
11 |
12 | @AutoValue
13 | public abstract class ExceptionEvent extends VirtualMachineEvent {
14 | public abstract int getRequestId();
15 | public abstract ThreadId getThread();
16 | public abstract Location getLocation();
17 | public abstract TaggedObjectId getException();
18 | public abstract Location getCatchLocation();
19 |
20 | public EventKind getEventKind() {
21 | return EventKind.EXCEPTION;
22 | }
23 |
24 | public static ExceptionEvent create(int requestId, ThreadId thread, Location location, TaggedObjectId exception, Location catchLocation) {
25 | return new AutoValue_ExceptionEvent(requestId, thread, location, exception, catchLocation);
26 | }
27 |
28 | public static ExceptionEvent read(DataReader reader) {
29 | return create(
30 | reader.readInt(),
31 | ThreadId.read(reader),
32 | Location.read(reader),
33 | TaggedObjectId.read(reader),
34 | Location.read(reader)
35 | );
36 | }
37 |
38 | @Override
39 | public void write(DataWriter writer) {
40 | writer.writeType(getEventKind());
41 | writer.writeInt(getRequestId());
42 | writer.writeType(getThread());
43 | writer.writeType(getLocation());
44 | writer.writeType(getException());
45 | writer.writeType(getCatchLocation());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/FieldAccessEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.FieldId;
9 | import kaap.veiko.debuggerforker.types.jdwp.Location;
10 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId;
11 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
12 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
13 |
14 | @AutoValue
15 | public abstract class FieldAccessEvent extends VirtualMachineEvent {
16 | public abstract int getRequestId();
17 | public abstract ThreadId getThread();
18 | public abstract Location getLocation();
19 | public abstract byte getRefTypeTag();
20 | public abstract ReferenceTypeId getTypeId();
21 | public abstract FieldId getFieldId();
22 | public abstract TaggedObjectId getObjectId();
23 |
24 | public EventKind getEventKind() {
25 | return EventKind.FIELD_ACCESS;
26 | }
27 |
28 | public static FieldAccessEvent create(int requestId, ThreadId thread, Location location, byte refTypeTag, ReferenceTypeId typeId, FieldId fieldId, TaggedObjectId objectId) {
29 | return new AutoValue_FieldAccessEvent(requestId, thread, location, refTypeTag, typeId, fieldId, objectId);
30 | }
31 |
32 | public static FieldAccessEvent read(DataReader reader) {
33 | return create(
34 | reader.readInt(),
35 | ThreadId.read(reader),
36 | Location.read(reader),
37 | reader.readByte(),
38 | ReferenceTypeId.read(reader),
39 | FieldId.read(reader),
40 | TaggedObjectId.read(reader)
41 | );
42 | }
43 |
44 | @Override
45 | public void write(DataWriter writer) {
46 | writer.writeType(getEventKind());
47 | writer.writeInt(getRequestId());
48 | writer.writeType(getThread());
49 | writer.writeType(getLocation());
50 | writer.writeByte(getRefTypeTag());
51 | writer.writeType(getTypeId());
52 | writer.writeType(getFieldId());
53 | writer.writeType(getObjectId());
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/FieldModificationEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.FieldId;
9 | import kaap.veiko.debuggerforker.types.jdwp.Location;
10 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId;
11 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
12 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
13 | import kaap.veiko.debuggerforker.types.jdwp.Value;
14 |
15 | @AutoValue
16 | public abstract class FieldModificationEvent extends VirtualMachineEvent {
17 | public abstract int getRequestId();
18 | public abstract ThreadId getThread();
19 | public abstract Location getLocation();
20 | public abstract byte getRefTypeTag();
21 | public abstract ReferenceTypeId getTypeId();
22 | public abstract FieldId getFieldId();
23 | public abstract TaggedObjectId getObjectId();
24 | public abstract Value getValueToBe();
25 |
26 | public EventKind getEventKind() {
27 | return EventKind.FIELD_MODIFICATION;
28 | }
29 |
30 | public static FieldModificationEvent create(int requestId, ThreadId thread, Location location, byte refTypeTag, ReferenceTypeId typeId, FieldId fieldId, TaggedObjectId objectId, Value valueToBe) {
31 | return new AutoValue_FieldModificationEvent(requestId, thread, location, refTypeTag, typeId, fieldId, objectId, valueToBe);
32 | }
33 |
34 | public static FieldModificationEvent read(DataReader reader) {
35 | return create(
36 | reader.readInt(),
37 | ThreadId.read(reader),
38 | Location.read(reader),
39 | reader.readByte(),
40 | ReferenceTypeId.read(reader),
41 | FieldId.read(reader),
42 | TaggedObjectId.read(reader),
43 | Value.read(reader)
44 | );
45 | }
46 |
47 | @Override
48 | public void write(DataWriter writer) {
49 | writer.writeType(getEventKind());
50 | writer.writeInt(getRequestId());
51 | writer.writeType(getThread());
52 | writer.writeType(getLocation());
53 | writer.writeByte(getRefTypeTag());
54 | writer.writeType(getTypeId());
55 | writer.writeType(getFieldId());
56 | writer.writeType(getObjectId());
57 | writer.writeType(getValueToBe());
58 | }
59 | }
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MethodEntryEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 |
11 | @AutoValue
12 | public abstract class MethodEntryEvent extends VirtualMachineEvent {
13 | public abstract int getRequestId();
14 | public abstract ThreadId getThread();
15 | public abstract Location getLocation();
16 |
17 | public EventKind getEventKind() {
18 | return EventKind.METHOD_ENTRY;
19 | }
20 |
21 | public static MethodEntryEvent create(int requestId, ThreadId thread, Location location) {
22 | return new AutoValue_MethodEntryEvent(requestId, thread, location);
23 | }
24 |
25 | public static MethodEntryEvent read(DataReader reader) {
26 | return create(
27 | reader.readInt(),
28 | ThreadId.read(reader),
29 | Location.read(reader)
30 | );
31 | }
32 |
33 | @Override
34 | public void write(DataWriter writer) {
35 | writer.writeType(getEventKind());
36 | writer.writeInt(getRequestId());
37 | writer.writeType(getThread());
38 | writer.writeType(getLocation());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MethodExitEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 |
11 | @AutoValue
12 | public abstract class MethodExitEvent extends VirtualMachineEvent {
13 | public abstract int getRequestId();
14 | public abstract ThreadId getThread();
15 | public abstract Location getLocation();
16 |
17 | public EventKind getEventKind() {
18 | return EventKind.METHOD_EXIT;
19 | }
20 |
21 | public static MethodExitEvent create(int requestId, ThreadId thread, Location location) {
22 | return new AutoValue_MethodExitEvent(requestId, thread, location);
23 | }
24 |
25 | public static MethodExitEvent read(DataReader reader) {
26 | return create(
27 | reader.readInt(),
28 | ThreadId.read(reader),
29 | Location.read(reader)
30 | );
31 | }
32 |
33 | @Override
34 | public void write(DataWriter writer) {
35 | writer.writeType(getEventKind());
36 | writer.writeInt(getRequestId());
37 | writer.writeType(getThread());
38 | writer.writeType(getLocation());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MethodExitWithReturnValueEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 | import kaap.veiko.debuggerforker.types.jdwp.Value;
11 |
12 | @AutoValue
13 | public abstract class MethodExitWithReturnValueEvent extends VirtualMachineEvent {
14 | public abstract int getRequestId();
15 | public abstract ThreadId getThread();
16 | public abstract Location getLocation();
17 | public abstract Value getValue();
18 |
19 | public EventKind getEventKind() {
20 | return EventKind.METHOD_EXIT_WITH_RETURN_VALUE;
21 | }
22 |
23 | public static MethodExitWithReturnValueEvent create(int requestId, ThreadId thread, Location location, Value value) {
24 | return new AutoValue_MethodExitWithReturnValueEvent(requestId, thread, location, value);
25 | }
26 |
27 | public static MethodExitWithReturnValueEvent read(DataReader reader) {
28 | return create(
29 | reader.readInt(),
30 | ThreadId.read(reader),
31 | Location.read(reader),
32 | Value.read(reader)
33 | );
34 | }
35 |
36 | @Override
37 | public void write(DataWriter writer) {
38 | writer.writeType(getEventKind());
39 | writer.writeInt(getRequestId());
40 | writer.writeType(getThread());
41 | writer.writeType(getLocation());
42 | writer.writeType(getValue());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorContendedEnterEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
10 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
11 |
12 | @AutoValue
13 | public abstract class MonitorContendedEnterEvent extends VirtualMachineEvent {
14 | public abstract int getRequestId();
15 | public abstract ThreadId getThread();
16 | public abstract TaggedObjectId getObjectId();
17 | public abstract Location getLocation();
18 |
19 | public EventKind getEventKind() {
20 | return EventKind.MONITOR_CONTENDED_ENTER;
21 | }
22 |
23 | public static MonitorContendedEnterEvent create(int requestId, ThreadId thread, TaggedObjectId objectId, Location location) {
24 | return new AutoValue_MonitorContendedEnterEvent(requestId, thread, objectId, location);
25 | }
26 |
27 | public static MonitorContendedEnterEvent read(DataReader reader) {
28 | return create(
29 | reader.readInt(),
30 | ThreadId.read(reader),
31 | TaggedObjectId.read(reader),
32 | Location.read(reader)
33 | );
34 | }
35 |
36 | @Override
37 | public void write(DataWriter writer) {
38 | writer.writeType(getEventKind());
39 | writer.writeInt(getRequestId());
40 | writer.writeType(getThread());
41 | writer.writeType(getObjectId());
42 | writer.writeType(getLocation());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorContendedEnteredEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
10 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
11 |
12 | @AutoValue
13 | public abstract class MonitorContendedEnteredEvent extends VirtualMachineEvent {
14 | public abstract int getRequestId();
15 | public abstract ThreadId getThread();
16 | public abstract TaggedObjectId getObjectId();
17 | public abstract Location getLocation();
18 |
19 | public EventKind getEventKind() {
20 | return EventKind.MONITOR_CONTENDED_ENTERED;
21 | }
22 |
23 | public static MonitorContendedEnteredEvent create(int requestId, ThreadId thread, TaggedObjectId objectId, Location location) {
24 | return new AutoValue_MonitorContendedEnteredEvent(requestId, thread, objectId, location);
25 | }
26 |
27 | public static MonitorContendedEnteredEvent read(DataReader reader) {
28 | return create(
29 | reader.readInt(),
30 | ThreadId.read(reader),
31 | TaggedObjectId.read(reader),
32 | Location.read(reader)
33 | );
34 | }
35 |
36 | @Override
37 | public void write(DataWriter writer) {
38 | writer.writeType(getEventKind());
39 | writer.writeInt(getRequestId());
40 | writer.writeType(getThread());
41 | writer.writeType(getObjectId());
42 | writer.writeType(getLocation());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorWaitEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
10 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
11 |
12 | @AutoValue
13 | public abstract class MonitorWaitEvent extends VirtualMachineEvent {
14 | public abstract int getRequestId();
15 | public abstract ThreadId getThread();
16 | public abstract TaggedObjectId getObjectId();
17 | public abstract Location getLocation();
18 | public abstract long getTimeout();
19 |
20 | public EventKind getEventKind() {
21 | return EventKind.MONITOR_WAIT;
22 | }
23 |
24 | public static MonitorWaitEvent create(int requestId, ThreadId thread, TaggedObjectId objectId, Location location, long timeout) {
25 | return new AutoValue_MonitorWaitEvent(requestId, thread, objectId, location, timeout);
26 | }
27 |
28 | public static MonitorWaitEvent read(DataReader reader) {
29 | return create(
30 | reader.readInt(),
31 | ThreadId.read(reader),
32 | TaggedObjectId.read(reader),
33 | Location.read(reader),
34 | reader.readLong()
35 | );
36 | }
37 |
38 | @Override
39 | public void write(DataWriter writer) {
40 | writer.writeType(getEventKind());
41 | writer.writeInt(getRequestId());
42 | writer.writeType(getThread());
43 | writer.writeType(getObjectId());
44 | writer.writeType(getLocation());
45 | writer.writeLong(getTimeout());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorWaitedEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
10 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
11 |
12 | @AutoValue
13 | public abstract class MonitorWaitedEvent extends VirtualMachineEvent {
14 | public abstract int getRequestId();
15 | public abstract ThreadId getThread();
16 | public abstract TaggedObjectId getObjectId();
17 | public abstract Location getLocation();
18 | public abstract boolean getTimedOut();
19 |
20 | public EventKind getEventKind() {
21 | return EventKind.MONITOR_WAITED;
22 | }
23 |
24 | public static MonitorWaitedEvent create(int requestId, ThreadId thread, TaggedObjectId objectId, Location location, boolean timedOut) {
25 | return new AutoValue_MonitorWaitedEvent(requestId, thread, objectId, location, timedOut);
26 | }
27 |
28 | public static MonitorWaitedEvent read(DataReader reader) {
29 | return create(
30 | reader.readInt(),
31 | ThreadId.read(reader),
32 | TaggedObjectId.read(reader),
33 | Location.read(reader),
34 | reader.readBoolean()
35 | );
36 | }
37 |
38 | @Override
39 | public void write(DataWriter writer) {
40 | writer.writeType(getEventKind());
41 | writer.writeInt(getRequestId());
42 | writer.writeType(getThread());
43 | writer.writeType(getObjectId());
44 | writer.writeType(getLocation());
45 | writer.writeBoolean(getTimedOut());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/SingleStepEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.Location;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 |
11 | @AutoValue
12 | public abstract class SingleStepEvent extends VirtualMachineEvent {
13 | public abstract int getRequestId();
14 | public abstract ThreadId getThread();
15 | public abstract Location getLocation();
16 |
17 | public EventKind getEventKind() {
18 | return EventKind.SINGLE_STEP;
19 | }
20 |
21 | public static SingleStepEvent create(int requestId, ThreadId thread, Location location) {
22 | return new AutoValue_SingleStepEvent(requestId, thread, location);
23 | }
24 |
25 | public static SingleStepEvent read(DataReader reader) {
26 | return create(
27 | reader.readInt(),
28 | ThreadId.read(reader),
29 | Location.read(reader)
30 | );
31 | }
32 |
33 | @Override
34 | public void write(DataWriter writer) {
35 | writer.writeType(getEventKind());
36 | writer.writeInt(getRequestId());
37 | writer.writeType(getThread());
38 | writer.writeType(getLocation());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ThreadDeathEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
9 |
10 | @AutoValue
11 | public abstract class ThreadDeathEvent extends VirtualMachineEvent {
12 | public abstract int getRequestId();
13 | public abstract ThreadId getThread();
14 |
15 | public EventKind getEventKind() {
16 | return EventKind.THREAD_DEATH;
17 | }
18 |
19 | public static ThreadDeathEvent create(int requestId, ThreadId thread) {
20 | return new AutoValue_ThreadDeathEvent(requestId, thread);
21 | }
22 |
23 | public static ThreadDeathEvent read(DataReader reader) {
24 | return create(
25 | reader.readInt(),
26 | ThreadId.read(reader)
27 | );
28 | }
29 |
30 | @Override
31 | public void write(DataWriter writer) {
32 | writer.writeType(getEventKind());
33 | writer.writeInt(getRequestId());
34 | writer.writeType(getThread());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ThreadStartEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
9 |
10 | @AutoValue
11 | public abstract class ThreadStartEvent extends VirtualMachineEvent {
12 | public abstract int getRequestId();
13 | public abstract ThreadId getThread();
14 |
15 | public EventKind getEventKind() {
16 | return EventKind.THREAD_START;
17 | }
18 |
19 | public static ThreadStartEvent create(int requestId, ThreadId thread) {
20 | return new AutoValue_ThreadStartEvent(requestId, thread);
21 | }
22 |
23 | public static ThreadStartEvent read(DataReader reader) {
24 | return create(
25 | reader.readInt(),
26 | ThreadId.read(reader)
27 | );
28 | }
29 |
30 | @Override
31 | public void write(DataWriter writer) {
32 | writer.writeType(getEventKind());
33 | writer.writeInt(getRequestId());
34 | writer.writeType(getThread());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/VmDeathEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 |
9 | @AutoValue
10 | public abstract class VmDeathEvent extends VirtualMachineEvent {
11 | public abstract int getRequestId();
12 |
13 | public EventKind getEventKind() {
14 | return EventKind.VM_DEATH;
15 | }
16 |
17 | public static VmDeathEvent create(int requestId) {
18 | return new AutoValue_VmDeathEvent(requestId);
19 | }
20 |
21 | public static VmDeathEvent read(DataReader reader) {
22 | return create(reader.readInt());
23 | }
24 |
25 | @Override
26 | public void write(DataWriter writer) {
27 | writer.writeType(getEventKind());
28 | writer.writeInt(getRequestId());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/VmStartEvent.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import com.google.auto.value.AutoValue;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataWriter;
7 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
8 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
9 |
10 | @AutoValue
11 | public abstract class VmStartEvent extends VirtualMachineEvent {
12 | public abstract int getRequestId();
13 | public abstract ThreadId getThread();
14 |
15 | public EventKind getEventKind() {
16 | return EventKind.VM_START;
17 | }
18 |
19 | public static VmStartEvent create(int requestId, ThreadId thread) {
20 | return new AutoValue_VmStartEvent(requestId, thread);
21 | }
22 |
23 | public static VmStartEvent read(DataReader reader) {
24 | return create(
25 | reader.readInt(),
26 | ThreadId.read(reader)
27 | );
28 | }
29 |
30 | @Override
31 | public void write(DataWriter writer) {
32 | writer.writeType(getEventKind());
33 | writer.writeInt(getRequestId());
34 | writer.writeType(getThread());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/ClearAllBreakpointsCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableCommandPacket;
6 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
7 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
8 | import kaap.veiko.debuggerforker.packet.CommandPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class ClearAllBreakpointsCommand extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.CLEAR_ALL_BREAKPOINTS_COMMAND;
13 |
14 | public static ClearAllBreakpointsCommand create(int packetId) {
15 | MutableCommandPacket packet = MutableCommandPacket.create(packetId, COMMAND_IDENTIFIER);
16 | return new ClearAllBreakpointsCommand(packet);
17 | }
18 |
19 | public static ClearAllBreakpointsCommand read(CommandDataReader reader) {
20 | return new ClearAllBreakpointsCommand((CommandPacket) reader.getPacket());
21 | }
22 |
23 | private ClearAllBreakpointsCommand(CommandPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | @Override
28 | public void writeCommand(DataWriter writer) {
29 | }
30 |
31 | @Override
32 | public void visit(CommandVisitor visitor) {
33 | visitor.visit(this);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "ClearAllBreakpointsCommand{}";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/ClearEventRequestReply.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableReplyPacket;
6 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
7 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
8 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class ClearEventRequestReply extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.CLEAR_EVENT_REQUEST_REPLY;
13 |
14 | public static ClearEventRequestReply create(int packetId) {
15 | MutableReplyPacket packet = MutableReplyPacket.create(packetId);
16 |
17 | return new ClearEventRequestReply(packet);
18 | }
19 |
20 | public static ClearEventRequestReply read(CommandDataReader reader) {
21 | return new ClearEventRequestReply((ReplyPacket) reader.getPacket());
22 | }
23 |
24 | private ClearEventRequestReply(ReplyPacket packet) {
25 | super(packet, COMMAND_IDENTIFIER);
26 | }
27 |
28 | @Override
29 | public void writeCommand(DataWriter writer) {
30 | }
31 |
32 | @Override
33 | public void visit(CommandVisitor visitor) {
34 | visitor.visit(this);
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "ClearEventRequestReply{}";
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/SetEventRequestReply.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableReplyPacket;
6 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
7 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
8 | import kaap.veiko.debuggerforker.commands.util.CommandDataUtil;
9 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
10 | import kaap.veiko.debuggerforker.types.DataWriter;
11 | import kaap.veiko.debuggerforker.types.VMInformation;
12 |
13 | public class SetEventRequestReply extends CommandBase {
14 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.SET_EVENT_REQUEST_REPLY;
15 |
16 | private final int requestId;
17 |
18 | public static SetEventRequestReply create(int packetId, int requestId, VMInformation vmInformation) {
19 | MutableReplyPacket packet = MutableReplyPacket.create(packetId);
20 | SetEventRequestReply command = new SetEventRequestReply(packet, requestId);
21 | packet.setData(CommandDataUtil.getCommandDataBytes(command, vmInformation));
22 |
23 | return command;
24 | }
25 |
26 | public static SetEventRequestReply read(CommandDataReader reader) {
27 | int requestId = reader.readInt();
28 | return new SetEventRequestReply((ReplyPacket) reader.getPacket(), requestId);
29 | }
30 |
31 | private SetEventRequestReply(ReplyPacket packet, int requestId) {
32 | super(packet, COMMAND_IDENTIFIER);
33 | this.requestId = requestId;
34 | }
35 |
36 | @Override
37 | public void writeCommand(DataWriter writer) {
38 | writer.writeInt(requestId);
39 | }
40 |
41 | public int getRequestId() {
42 | return requestId;
43 | }
44 |
45 | @Override
46 | public void visit(CommandVisitor visitor) {
47 | visitor.visit(this);
48 | }
49 |
50 | @Override
51 | public boolean equals(Object o) {
52 | if (this == o) {
53 | return true;
54 | }
55 | if (o == null || getClass() != o.getClass()) {
56 | return false;
57 | }
58 |
59 | SetEventRequestReply that = (SetEventRequestReply) o;
60 |
61 | return requestId == that.requestId;
62 | }
63 |
64 | @Override
65 | public int hashCode() {
66 | return requestId;
67 | }
68 |
69 | @Override
70 | public String toString() {
71 | return "SetEventRequestReply{" +
72 | "requestId=" + requestId +
73 | '}';
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/EventRequestFilter.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters;
2 |
3 | import java.util.Collections;
4 | import java.util.List;
5 | import java.util.stream.Collectors;
6 | import java.util.stream.IntStream;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
12 | import kaap.veiko.debuggerforker.types.DataType;
13 | import kaap.veiko.debuggerforker.types.DataWriter;
14 |
15 | public abstract class EventRequestFilter implements DataType {
16 |
17 | private static Logger log = LoggerFactory.getLogger(EventRequestFilter.class);
18 |
19 | public static List readList(CommandDataReader reader) {
20 | int length = reader.readInt();
21 | try {
22 | return IntStream.range(0, length)
23 | .mapToObj(i -> readNext(reader))
24 | .collect(Collectors.toList());
25 | } catch (RuntimeException e) {
26 | log.error("Failed to read EventRequestFilter list due to exception.", e);
27 | return Collections.emptyList();
28 | }
29 | }
30 |
31 | private static EventRequestFilter readNext(CommandDataReader reader) throws RuntimeException {
32 | byte identifier = reader.readByte();
33 | switch (identifier) {
34 | case CountEventRequestFilter.IDENTIFIER:
35 | return CountEventRequestFilter.read(reader);
36 | case ConditionalEventRequestFilter.IDENTIFIER:
37 | return ConditionalEventRequestFilter.read(reader);
38 | case ThreadOnlyEventRequestFilter.IDENTIFIER:
39 | return ThreadOnlyEventRequestFilter.read(reader);
40 | case ClassOnlyEventRequestFilter.IDENTIFIER:
41 | return ClassOnlyEventRequestFilter.read(reader);
42 | case ClassMatchEventRequestFilter.IDENTIFIER:
43 | return ClassMatchEventRequestFilter.read(reader);
44 | case ClassExcludeEventRequestFilter.IDENTIFIER:
45 | return ClassExcludeEventRequestFilter.read(reader);
46 | case LocationOnlyEventRequestFilter.IDENTIFIER:
47 | return LocationOnlyEventRequestFilter.read(reader);
48 | case ExceptionOnlyEventRequestFilter.IDENTIFIER:
49 | return ExceptionOnlyEventRequestFilter.read(reader);
50 | case FieldOnlyEventRequestFilter.IDENTIFIER:
51 | return FieldOnlyEventRequestFilter.read(reader);
52 | case StepEventRequestFilter.IDENTIFIER:
53 | return StepEventRequestFilter.read(reader);
54 | case InstanceOnlyEventRequestFilter.IDENTIFIER:
55 | return InstanceOnlyEventRequestFilter.read(reader);
56 | case SourceNameMatchEventRequestFilter.IDENTIFIER:
57 | return SourceNameMatchEventRequestFilter.read(reader);
58 | default:
59 | throw new RuntimeException("Failed to parse");
60 | }
61 | }
62 |
63 | public static void writeList(DataWriter writer, List filters) {
64 | writer.writeInt(filters.size());
65 |
66 | for (EventRequestFilter filter : filters) {
67 | writer.writeType(filter);
68 | }
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/DisposeCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableCommandPacket;
6 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
7 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
8 | import kaap.veiko.debuggerforker.packet.CommandPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class DisposeCommand extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.DISPOSE_COMMAND;
13 |
14 | public static DisposeCommand create(int packetId) {
15 | MutableCommandPacket packet = MutableCommandPacket.create(packetId, COMMAND_IDENTIFIER);
16 | return new DisposeCommand(packet);
17 | }
18 |
19 | public static DisposeCommand read(CommandDataReader reader) {
20 | return new DisposeCommand((CommandPacket) reader.getPacket());
21 | }
22 |
23 | private DisposeCommand(CommandPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | @Override
28 | public void writeCommand(DataWriter writer) {
29 | }
30 |
31 | @Override
32 | public void visit(CommandVisitor visitor) {
33 | visitor.visit(this);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "DisposeCommand{}";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/DisposeReply.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableReplyPacket;
6 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
7 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
8 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class DisposeReply extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.DISPOSE_REPLY;
13 |
14 | public static DisposeReply create(int packetId) {
15 | MutableReplyPacket packet = MutableReplyPacket.create(packetId);
16 | return new DisposeReply(packet);
17 | }
18 |
19 | public static DisposeReply read(CommandDataReader reader) {
20 | return new DisposeReply((ReplyPacket) reader.getPacket());
21 | }
22 |
23 | private DisposeReply(ReplyPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | protected CommandIdentifier getCommandIdentifier() {
28 | return COMMAND_IDENTIFIER;
29 | }
30 |
31 | @Override
32 | public void writeCommand(DataWriter writer) {
33 | }
34 |
35 | @Override
36 | public void visit(CommandVisitor visitor) {
37 | visitor.visit(this);
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | return "DisposeReply{}";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/HoldEventsCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableCommandPacket;
6 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
7 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
8 | import kaap.veiko.debuggerforker.packet.CommandPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class HoldEventsCommand extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.HOLD_EVENTS_COMMAND;
13 |
14 | public static HoldEventsCommand create(int packetId) {
15 | MutableCommandPacket packet = MutableCommandPacket.create(packetId, COMMAND_IDENTIFIER);
16 | return new HoldEventsCommand(packet);
17 | }
18 |
19 | public static HoldEventsCommand read(CommandDataReader reader) {
20 | return new HoldEventsCommand((CommandPacket) reader.getPacket());
21 | }
22 |
23 | private HoldEventsCommand(CommandPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | @Override
28 | public void writeCommand(DataWriter writer) {
29 | }
30 |
31 | @Override
32 | public void visit(CommandVisitor visitor) {
33 | visitor.visit(this);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "HoldEventsCommand{}";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/IdSizesReply.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableReplyPacket;
6 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
7 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
8 | import kaap.veiko.debuggerforker.commands.util.CommandDataUtil;
9 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
10 | import kaap.veiko.debuggerforker.types.DataWriter;
11 | import kaap.veiko.debuggerforker.types.VMInformation;
12 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
13 |
14 | public class IdSizesReply extends CommandBase {
15 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.ID_SIZES_REPLY;
16 |
17 | private final IdSizes idSizes;
18 |
19 | public static IdSizesReply create(int packetId, IdSizes idSizes, VMInformation vmInformation) {
20 | MutableReplyPacket packet = MutableReplyPacket.create(packetId);
21 | IdSizesReply command = new IdSizesReply(packet, idSizes);
22 | packet.setData(CommandDataUtil.getCommandDataBytes(command, vmInformation));
23 |
24 | return command;
25 | }
26 |
27 | public static IdSizesReply read(CommandDataReader reader) {
28 | IdSizes idSizes = IdSizes.read(reader);
29 | return new IdSizesReply((ReplyPacket) reader.getPacket(), idSizes);
30 | }
31 |
32 | private IdSizesReply(ReplyPacket packet, IdSizes idSizes) {
33 | super(packet, COMMAND_IDENTIFIER);
34 | this.idSizes = idSizes;
35 | }
36 |
37 | @Override
38 | public void writeCommand(DataWriter writer) {
39 | writer.writeType(idSizes);
40 | }
41 |
42 | @Override
43 | public void visit(CommandVisitor visitor) {
44 | visitor.visit(this);
45 | }
46 |
47 | public IdSizes getIdSizes() {
48 | return idSizes;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return "IdSizesReply{" +
54 | "idSizes=" + idSizes +
55 | '}';
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/ReleaseEventsCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableCommandPacket;
6 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
7 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
8 | import kaap.veiko.debuggerforker.packet.CommandPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class ReleaseEventsCommand extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.RELEASE_EVENTS_COMMAND;
13 |
14 | public static ReleaseEventsCommand create(int packetId) {
15 | MutableCommandPacket packet = MutableCommandPacket.create(packetId, COMMAND_IDENTIFIER);
16 | return new ReleaseEventsCommand(packet);
17 | }
18 |
19 | public static ReleaseEventsCommand read(CommandDataReader reader) {
20 | return new ReleaseEventsCommand((CommandPacket) reader.getPacket());
21 | }
22 |
23 | private ReleaseEventsCommand(CommandPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | @Override
28 | public void writeCommand(DataWriter writer) {
29 | }
30 |
31 | @Override
32 | public void visit(CommandVisitor visitor) {
33 | visitor.visit(this);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "ReleaseEventsCommand{}";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/ResumeCommand.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableCommandPacket;
6 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
7 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
8 | import kaap.veiko.debuggerforker.packet.CommandPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class ResumeCommand extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.RESUME_COMMAND;
13 |
14 | public static ResumeCommand create(int packetId) {
15 | MutableCommandPacket packet = MutableCommandPacket.create(packetId, COMMAND_IDENTIFIER);
16 | return new ResumeCommand(packet);
17 | }
18 |
19 | public static ResumeCommand read(CommandDataReader reader) {
20 | return new ResumeCommand((CommandPacket) reader.getPacket());
21 | }
22 |
23 | private ResumeCommand(CommandPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | @Override
28 | public void writeCommand(DataWriter writer) {
29 | }
30 |
31 | @Override
32 | public void visit(CommandVisitor visitor) {
33 | visitor.visit(this);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "ResumeCommand{}";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/ResumeReply.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import kaap.veiko.debuggerforker.commands.CommandBase;
4 | import kaap.veiko.debuggerforker.commands.CommandVisitor;
5 | import kaap.veiko.debuggerforker.commands.MutableReplyPacket;
6 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
7 | import kaap.veiko.debuggerforker.commands.parser.CommandDataReader;
8 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
9 | import kaap.veiko.debuggerforker.types.DataWriter;
10 |
11 | public class ResumeReply extends CommandBase {
12 | private static final CommandIdentifier COMMAND_IDENTIFIER = CommandIdentifier.RESUME_REPLY;
13 |
14 | public static ResumeReply create(int packetId) {
15 | MutableReplyPacket packet = MutableReplyPacket.create(packetId);
16 | return new ResumeReply(packet);
17 | }
18 |
19 | public static ResumeReply read(CommandDataReader reader) {
20 | return new ResumeReply((ReplyPacket) reader.getPacket());
21 | }
22 |
23 | private ResumeReply(ReplyPacket packet) {
24 | super(packet, COMMAND_IDENTIFIER);
25 | }
26 |
27 | @Override
28 | public void writeCommand(DataWriter writer) {
29 | }
30 |
31 | @Override
32 | public void visit(CommandVisitor visitor) {
33 | visitor.visit(this);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "ResumeReply{}";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/parser/CommandParser.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.parser;
2 |
3 | import java.io.IOException;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import kaap.veiko.debuggerforker.commands.Command;
8 | import kaap.veiko.debuggerforker.commands.UnknownCommand;
9 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
10 | import kaap.veiko.debuggerforker.packet.CommandPacket;
11 | import kaap.veiko.debuggerforker.packet.Packet;
12 | import kaap.veiko.debuggerforker.packet.PacketVisitor;
13 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
14 | import kaap.veiko.debuggerforker.types.VMInformation;
15 |
16 | public class CommandParser {
17 | private final static Logger log = LoggerFactory.getLogger(CommandParser.class);
18 |
19 | private final VMInformation vmInformation;
20 | private final CommandPacketFinder commandPacketFinder = new CommandPacketFinder();
21 |
22 | public CommandParser(VMInformation vmInformation) {
23 | this.vmInformation = vmInformation;
24 | }
25 |
26 | public Command parse(Packet packet) {
27 | CommandPacket commandPacket = packet.visit(commandPacketFinder);
28 |
29 | CommandDataReader commandDataReader = new CommandDataReader(packet, vmInformation);
30 | try {
31 | CommandIdentifier identifier = CommandIdentifier.of(commandPacket.getCommandSetId(), commandPacket.getCommandId(), packet.isReply());
32 | return commandDataReader.readCommand(identifier, packet);
33 | }
34 | catch (IOException e) {
35 | log.warn(e.getMessage());
36 | return new UnknownCommand(packet, commandPacket.getCommandSetId(), commandPacket.getCommandId(), packet.isReply());
37 | }
38 | }
39 |
40 | private class CommandPacketFinder implements PacketVisitor {
41 | @Override
42 | public CommandPacket visit(ReplyPacket replyPacket) {
43 | return replyPacket.getCommandPacket();
44 | }
45 |
46 | @Override
47 | public CommandPacket visit(CommandPacket commandPacket) {
48 | return commandPacket;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/parser/CommandType.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.parser;
2 |
3 | public enum CommandType {
4 | REPLY,
5 | COMMAND
6 | }
--------------------------------------------------------------------------------
/commands/src/main/java/kaap/veiko/debuggerforker/commands/util/CommandDataUtil.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.util;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import kaap.veiko.debuggerforker.commands.Command;
6 | import kaap.veiko.debuggerforker.packet.internal.ByteBufferDataWriter;
7 | import kaap.veiko.debuggerforker.types.DataWriter;
8 | import kaap.veiko.debuggerforker.types.VMInformation;
9 |
10 | public class CommandDataUtil {
11 | public static byte[] getCommandDataBytes(Command command, VMInformation vmInformation) {
12 | ByteBuffer buffer = ByteBuffer.allocate(1024);
13 | DataWriter writer = new ByteBufferDataWriter(buffer, vmInformation);
14 | command.writeCommand(writer);
15 |
16 | byte[] bytes = new byte[buffer.position()];
17 | buffer.flip();
18 | buffer.get(bytes);
19 |
20 | return bytes;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/ClassExcludeEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 |
6 | data class ClassExcludeEventRequestFilter(val classPattern: String) : EventRequestFilter() {
7 | override fun write(writer: DataWriter?) = writer!!.run {
8 | writeByte(IDENTIFIER)
9 | writeString(classPattern)
10 | }
11 |
12 | companion object {
13 | const val IDENTIFIER: Byte = 6
14 | @JvmStatic fun read(reader: DataReader) = ClassExcludeEventRequestFilter(reader.readString())
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/ClassMatchEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 |
6 | data class ClassMatchEventRequestFilter(val classPattern: String) : EventRequestFilter() {
7 | override fun write(writer: DataWriter?) = writer!!.run {
8 | writeByte(IDENTIFIER)
9 | writeString(classPattern)
10 | }
11 |
12 | companion object {
13 | const val IDENTIFIER: Byte = 5
14 | @JvmStatic fun read(reader: DataReader) = ClassMatchEventRequestFilter(reader.readString())
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/ClassOnlyEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId
6 |
7 | data class ClassOnlyEventRequestFilter(val clazz: ReferenceTypeId) : EventRequestFilter() {
8 | override fun write(writer: DataWriter?) = writer!!.run {
9 | writeByte(IDENTIFIER)
10 | writeType(clazz)
11 | }
12 |
13 | companion object {
14 | const val IDENTIFIER: Byte = 4
15 | @JvmStatic fun read(reader: DataReader) = ClassOnlyEventRequestFilter(ReferenceTypeId.read(reader))
16 | }
17 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/ConditionalEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 |
6 | data class ConditionalEventRequestFilter(val exprId: Int) : EventRequestFilter() {
7 | override fun write(writer: DataWriter?) = writer!!.run {
8 | writeByte(IDENTIFIER)
9 | writeInt(exprId)
10 | }
11 |
12 | companion object {
13 | const val IDENTIFIER: Byte = 2
14 | @JvmStatic fun read(reader: DataReader) = ConditionalEventRequestFilter(reader.readInt())
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/CountEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 |
6 | data class CountEventRequestFilter(val count: Int) : EventRequestFilter() {
7 | override fun write(writer: DataWriter?) = writer!!.run {
8 | writeByte(IDENTIFIER)
9 | writeInt(count)
10 | }
11 |
12 | companion object {
13 | const val IDENTIFIER: Byte = 1
14 | @JvmStatic fun read(reader: DataReader) = CountEventRequestFilter(reader.readInt())
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/ExceptionOnlyEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId
6 |
7 | data class ExceptionOnlyEventRequestFilter(
8 | val exceptionOrNull: ReferenceTypeId,
9 | val caught: Boolean,
10 | val uncaught: Boolean
11 | ) : EventRequestFilter() {
12 | override fun write(writer: DataWriter?) = writer!!.run {
13 | writeByte(IDENTIFIER)
14 | writeType(exceptionOrNull)
15 | writeBoolean(caught)
16 | writeBoolean(uncaught)
17 | }
18 |
19 | companion object {
20 | const val IDENTIFIER: Byte = 8
21 | @JvmStatic fun read(reader: DataReader) = ExceptionOnlyEventRequestFilter(
22 | ReferenceTypeId.read(reader),
23 | reader.readBoolean(),
24 | reader.readBoolean()
25 | )
26 | }
27 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/FieldOnlyEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.FieldId
6 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId
7 |
8 | data class FieldOnlyEventRequestFilter(
9 | val declaring: ReferenceTypeId,
10 | val fieldId: FieldId
11 | ) : EventRequestFilter() {
12 | override fun write(writer: DataWriter?) = writer!!.run {
13 | writeByte(IDENTIFIER)
14 | writeType(declaring)
15 | writeType(fieldId)
16 | }
17 |
18 | companion object {
19 | const val IDENTIFIER: Byte = 9
20 | @JvmStatic fun read(reader: DataReader) = FieldOnlyEventRequestFilter(
21 | ReferenceTypeId.read(reader),
22 | FieldId.read(reader)
23 | )
24 | }
25 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/InstanceOnlyEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.ObjectId
6 |
7 | data class InstanceOnlyEventRequestFilter(val instance: ObjectId) : EventRequestFilter() {
8 | override fun write(writer: DataWriter?) = writer!!.run {
9 | writeByte(IDENTIFIER)
10 | writeType(instance)
11 | }
12 |
13 | companion object {
14 | const val IDENTIFIER: Byte = 11
15 | @JvmStatic fun read(reader: DataReader) = InstanceOnlyEventRequestFilter(ObjectId.read(reader))
16 | }
17 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/LocationOnlyEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.Location
6 |
7 | data class LocationOnlyEventRequestFilter(val location: Location) : EventRequestFilter() {
8 | override fun write(writer: DataWriter?) = writer!!.run {
9 | writeByte(IDENTIFIER)
10 | writeType(location)
11 | }
12 |
13 | companion object {
14 | const val IDENTIFIER: Byte = 7
15 | @JvmStatic fun read(reader: DataReader) = LocationOnlyEventRequestFilter(Location.read(reader))
16 | }
17 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/SourceNameMatchEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 |
6 | data class SourceNameMatchEventRequestFilter(val sourceNamePattern: String) : EventRequestFilter() {
7 | override fun write(writer: DataWriter?) = writer!!.run {
8 | writeByte(IDENTIFIER)
9 | writeString(sourceNamePattern)
10 | }
11 |
12 | companion object {
13 | const val IDENTIFIER: Byte = 12
14 | @JvmStatic fun read(reader: DataReader) = SourceNameMatchEventRequestFilter(reader.readString())
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/StepEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId
6 |
7 | data class StepEventRequestFilter(
8 | val thread: ThreadId,
9 | val size: Int,
10 | val depth: Int
11 | ) : EventRequestFilter() {
12 | override fun write(writer: DataWriter?) = writer!!.run {
13 | writeByte(IDENTIFIER)
14 | writeType(thread)
15 | writeInt(size)
16 | writeInt(depth)
17 | }
18 |
19 | companion object {
20 | const val IDENTIFIER: Byte = 10
21 | @JvmStatic fun read(reader: DataReader) = StepEventRequestFilter(
22 | ThreadId.read(reader),
23 | reader.readInt(),
24 | reader.readInt()
25 | )
26 | }
27 | }
--------------------------------------------------------------------------------
/commands/src/main/kotlin/kaap/veiko/debuggerforker/commands/commandsets/eventrequest/filters/ThreadOnlyEventRequestFilter.kt:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.eventrequest.filters
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader
4 | import kaap.veiko.debuggerforker.types.DataWriter
5 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId
6 |
7 | data class ThreadOnlyEventRequestFilter(val thread: ThreadId) : EventRequestFilter() {
8 | override fun write(writer: DataWriter?) = writer!!.run {
9 | writeByte(IDENTIFIER)
10 | writeType(thread)
11 | }
12 |
13 | companion object {
14 | const val IDENTIFIER: Byte = 3
15 | @JvmStatic fun read(reader: DataReader) = ThreadOnlyEventRequestFilter(ThreadId.read(reader))
16 | }
17 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/CommandTestBase.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import java.util.concurrent.ThreadLocalRandom;
6 |
7 | import kaap.veiko.debuggerforker.commands.Command;
8 | import kaap.veiko.debuggerforker.commands.parser.CommandType;
9 | import kaap.veiko.debuggerforker.packet.CommandPacket;
10 | import kaap.veiko.debuggerforker.packet.Packet;
11 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
12 |
13 | public abstract class CommandTestBase extends TestBase {
14 |
15 | protected int generateRandomPacketId() {
16 | return ThreadLocalRandom.current().nextInt();
17 | }
18 |
19 | protected void assertCommandIdentifier(CommandIdentifier expectedIdentifier, Command actualCommand) {
20 | boolean expectedIsReply = expectedIdentifier.getType() == CommandType.REPLY;
21 |
22 | assertEquals(expectedIdentifier.getCommandId(), actualCommand.getCommandId());
23 | assertEquals(expectedIdentifier.getCommandSetId(), actualCommand.getCommandSetId());
24 | assertEquals(expectedIsReply, actualCommand.isReply());
25 | }
26 |
27 | protected void assertEqualPackets(Packet expected, Packet actual) {
28 | if (expected instanceof CommandPacket && actual instanceof CommandPacket) {
29 | assertEqualCommandPackets((CommandPacket) expected, (CommandPacket)actual);
30 | }
31 | else if (expected instanceof ReplyPacket && actual instanceof ReplyPacket) {
32 | assertEqualReplyPackets((ReplyPacket) expected, (ReplyPacket)actual);
33 | }
34 | else {
35 | assertTrue("Packets are different types",false);
36 | }
37 | }
38 |
39 | protected void assertEqualReplyPackets(ReplyPacket expected, ReplyPacket actual) {
40 | assertPacketsBase(expected, actual);
41 | assertEquals(expected.getErrorCode(), actual.getErrorCode());
42 | assertEquals(true, actual.isReply());
43 | }
44 |
45 | protected void assertEqualCommandPackets(CommandPacket expected, CommandPacket actual) {
46 | assertPacketsBase(expected, actual);
47 | assertEquals(expected.getCommandId(), actual.getCommandId());
48 | assertEquals(expected.getCommandSetId(), actual.getCommandSetId());
49 | assertEquals(false, actual.isReply());
50 | }
51 |
52 | private void assertPacketsBase(Packet expected, Packet actual) {
53 | assertEquals(expected.getId(), actual.getId());
54 | assertEquals(expected.getLength(), actual.getLength());
55 | assertEquals(expected.getFlags(), actual.getFlags());
56 | assertEquals(expected.isReply(), actual.isReply());
57 | assertArrayEquals(expected.getData(), actual.getData());
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/TestBase.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets;
2 |
3 | import org.junit.Before;
4 |
5 | import kaap.veiko.debuggerforker.types.VMInformation;
6 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
7 |
8 | public abstract class TestBase {
9 | private final VMInformation vmInformation = new VMInformation();
10 |
11 | @Before
12 | public void setup() {
13 | vmInformation.setIdSizes(new IdSizes(6,5,7,6,7));
14 | }
15 |
16 | protected VMInformation getVmInformation() {
17 | return vmInformation;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/BreakPointEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.ClassId;
6 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
7 | import kaap.veiko.debuggerforker.types.jdwp.Location;
8 | import kaap.veiko.debuggerforker.types.jdwp.MethodId;
9 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
10 |
11 | public class BreakPointEventTest extends EventTestBase {
12 | @Test
13 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
14 | assertWrittenEventEqualsReadEvent(EventKind.BREAKPOINT, BreakPointEvent.create(
15 | randomInt(),
16 | randomThreadId(),
17 | randomLocation()
18 | ));
19 | }
20 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ClassPrepareEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 | import kaap.veiko.debuggerforker.types.jdwp.ReferenceTypeId;
7 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
8 |
9 | public class ClassPrepareEventTest extends EventTestBase {
10 | @Test
11 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
12 | assertWrittenEventEqualsReadEvent(EventKind.CLASS_PREPARE, ClassPrepareEvent.create(
13 | randomInt(),
14 | randomThreadId(),
15 | randomByte(),
16 | randomReferenceTypeId(),
17 | randomString(),
18 | randomInt()
19 | ));
20 | }
21 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ClassUnloadEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class ClassUnloadEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.CLASS_UNLOAD, ClassUnloadEvent.create(
11 | randomInt(),
12 | randomString()
13 | ));
14 | }
15 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ExceptionEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.ClassId;
6 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
7 | import kaap.veiko.debuggerforker.types.jdwp.Location;
8 | import kaap.veiko.debuggerforker.types.jdwp.MethodId;
9 | import kaap.veiko.debuggerforker.types.jdwp.ObjectId;
10 | import kaap.veiko.debuggerforker.types.jdwp.TaggedObjectId;
11 | import kaap.veiko.debuggerforker.types.jdwp.ThreadId;
12 |
13 | public class ExceptionEventTest extends EventTestBase {
14 | @Test
15 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
16 | assertWrittenEventEqualsReadEvent(EventKind.EXCEPTION, ExceptionEvent.create(
17 | randomInt(),
18 | randomThreadId(),
19 | randomLocation(),
20 | randomTaggedObjectId(),
21 | randomLocation()
22 | ));
23 | }
24 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/FieldAccessEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class FieldAccessEventTest extends EventTestBase {
8 |
9 | @Test
10 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
11 | assertWrittenEventEqualsReadEvent(EventKind.FIELD_ACCESS, FieldAccessEvent.create(
12 | randomInt(),
13 | randomThreadId(),
14 | randomLocation(),
15 | randomByte(),
16 | randomReferenceTypeId(),
17 | randomFieldId(),
18 | randomTaggedObjectId()
19 | ));
20 | }
21 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/FieldModificationEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class FieldModificationEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.FIELD_MODIFICATION, FieldModificationEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomLocation(),
14 | randomByte(),
15 | randomReferenceTypeId(),
16 | randomFieldId(),
17 | randomTaggedObjectId(),
18 | randomValue()
19 | ));
20 | }
21 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MethodEntryEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MethodEntryEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.METHOD_ENTRY, MethodEntryEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomLocation()
14 | ));
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MethodExitEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MethodExitEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.METHOD_EXIT, MethodExitEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomLocation()
14 | ));
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MethodExitWithReturnValueEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MethodExitWithReturnValueEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.METHOD_EXIT_WITH_RETURN_VALUE, MethodExitWithReturnValueEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomLocation(),
14 | randomValue()
15 | ));
16 | }
17 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorContendedEnterEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MonitorContendedEnterEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.MONITOR_CONTENDED_ENTER, MonitorContendedEnterEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomTaggedObjectId(),
14 | randomLocation()
15 | ));
16 | }
17 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorContendedEnteredEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MonitorContendedEnteredEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.MONITOR_CONTENDED_ENTERED, MonitorContendedEnteredEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomTaggedObjectId(),
14 | randomLocation()
15 | ));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorWaitEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MonitorWaitEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.MONITOR_WAIT, MonitorWaitEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomTaggedObjectId(),
14 | randomLocation(),
15 | randomLong()
16 | ));
17 | }
18 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/MonitorWaitedEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class MonitorWaitedEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.MONITOR_WAITED, MonitorWaitedEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomTaggedObjectId(),
14 | randomLocation(),
15 | randomBoolean()
16 | ));
17 | }
18 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/SingleStepEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class SingleStepEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.SINGLE_STEP, SingleStepEvent.create(
11 | randomInt(),
12 | randomThreadId(),
13 | randomLocation()
14 | ));
15 | }
16 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ThreadDeathEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class ThreadDeathEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.THREAD_DEATH, ThreadDeathEvent.create(
11 | randomInt(),
12 | randomThreadId()
13 | ));
14 | }
15 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/ThreadStartEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class ThreadStartEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.THREAD_START, ThreadStartEvent.create(
11 | randomInt(),
12 | randomThreadId()
13 | ));
14 | }
15 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/VmDeathEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class VmDeathEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.VM_DEATH, VmDeathEvent.create(
11 | randomInt()
12 | ));
13 | }
14 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/event/events/VmStartEventTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.event.events;
2 |
3 | import org.junit.Test;
4 |
5 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
6 |
7 | public class VmStartEventTest extends EventTestBase {
8 | @Test
9 | public void testReadAndWriteEqualsOriginalEvent() throws ReflectiveOperationException {
10 | assertWrittenEventEqualsReadEvent(EventKind.VM_START, VmStartEvent.create(
11 | randomInt(),
12 | randomThreadId()
13 | ));
14 | }
15 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/DisposeCommandTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | import kaap.veiko.debuggerforker.commands.Command;
8 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
9 | import kaap.veiko.debuggerforker.commands.commandsets.CommandTestBase;
10 | import kaap.veiko.debuggerforker.commands.parser.CommandParser;
11 | import kaap.veiko.debuggerforker.packet.Packet;
12 |
13 | public class DisposeCommandTest extends CommandTestBase {
14 |
15 | @Test
16 | public void testCreate() {
17 | int packetId = generateRandomPacketId();
18 |
19 | DisposeCommand command = DisposeCommand.create(packetId);
20 |
21 | assertEquals(packetId, command.getPacket().getId());
22 | assertCommandIdentifier(CommandIdentifier.DISPOSE_COMMAND, command);
23 | }
24 |
25 | @Test
26 | public void testParse() {
27 | int packetId = generateRandomPacketId();
28 | DisposeCommand originalCommand = DisposeCommand.create(packetId);
29 | Packet originalPacket = originalCommand.getPacket();
30 |
31 | CommandParser parser = new CommandParser(getVmInformation());
32 | Command parsedCommand = parser.parse(originalPacket);
33 |
34 | assertEqualPackets(originalPacket, parsedCommand.getPacket());
35 | assertEquals(true, parsedCommand instanceof DisposeCommand);
36 | assertEquals(packetId, parsedCommand.getPacket().getId());
37 | }
38 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/DisposeReplyTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import static kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier.DISPOSE_REPLY;
4 | import static org.junit.Assert.assertEquals;
5 |
6 | import org.junit.Test;
7 |
8 | import kaap.veiko.debuggerforker.commands.Command;
9 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
10 | import kaap.veiko.debuggerforker.commands.commandsets.CommandTestBase;
11 | import kaap.veiko.debuggerforker.commands.parser.CommandParser;
12 | import kaap.veiko.debuggerforker.packet.CommandPacket;
13 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
14 |
15 | public class DisposeReplyTest extends CommandTestBase {
16 |
17 | @Test
18 | public void testCreate() {
19 | int packetId = generateRandomPacketId();
20 |
21 | DisposeReply reply = DisposeReply.create(packetId);
22 |
23 | assertEquals(packetId, reply.getPacket().getId());
24 | assertCommandIdentifier(DISPOSE_REPLY, reply);
25 | }
26 |
27 | @Test
28 | public void testParse() {
29 | int packetId = generateRandomPacketId();
30 | DisposeReply originalReply = DisposeReply.create(packetId);
31 | ReplyPacket originalPacket = originalReply.getPacket();
32 | // Needed for parsing since replies don't contain info about what type they are
33 | originalPacket.setCommandPacket(new CommandPacket(packetId, DISPOSE_REPLY.getCommandSetId(), DISPOSE_REPLY.getCommandId(), new byte[0], null));
34 |
35 | CommandParser parser = new CommandParser(getVmInformation());
36 | Command parsedCommand = parser.parse(originalPacket);
37 |
38 | assertEqualPackets(originalPacket, parsedCommand.getPacket());
39 | assertEquals(true, parsedCommand instanceof DisposeReply);
40 | assertEquals(packetId, parsedCommand.getPacket().getId());
41 | }
42 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/HoldEventsCommandTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import org.junit.Test;
6 |
7 | import kaap.veiko.debuggerforker.commands.Command;
8 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
9 | import kaap.veiko.debuggerforker.commands.commandsets.CommandTestBase;
10 | import kaap.veiko.debuggerforker.commands.parser.CommandParser;
11 | import kaap.veiko.debuggerforker.packet.Packet;
12 |
13 | public class HoldEventsCommandTest extends CommandTestBase {
14 |
15 | @Test
16 | public void testCreate() {
17 | int packetId = generateRandomPacketId();
18 |
19 | HoldEventsCommand command = HoldEventsCommand.create(packetId);
20 |
21 | assertEquals(packetId, command.getPacket().getId());
22 | assertCommandIdentifier(CommandIdentifier.HOLD_EVENTS_COMMAND, command);
23 | }
24 |
25 | @Test
26 | public void testParse() {
27 | int packetId = generateRandomPacketId();
28 | HoldEventsCommand originalCommand = HoldEventsCommand.create(packetId);
29 | Packet originalPacket = originalCommand.getPacket();
30 |
31 | CommandParser parser = new CommandParser(getVmInformation());
32 | Command parsedCommand = parser.parse(originalPacket);
33 |
34 | assertEqualPackets(originalPacket, parsedCommand.getPacket());
35 | assertEquals(true, parsedCommand instanceof HoldEventsCommand);
36 | assertEquals(packetId, parsedCommand.getPacket().getId());
37 | }
38 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/IdSizesReplyTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import static kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier.ID_SIZES_REPLY;
4 | import static org.junit.Assert.assertEquals;
5 |
6 | import org.junit.Test;
7 |
8 | import kaap.veiko.debuggerforker.commands.Command;
9 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
10 | import kaap.veiko.debuggerforker.commands.commandsets.CommandTestBase;
11 | import kaap.veiko.debuggerforker.commands.parser.CommandParser;
12 | import kaap.veiko.debuggerforker.packet.CommandPacket;
13 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
14 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
15 |
16 | public class IdSizesReplyTest extends CommandTestBase {
17 |
18 | @Test
19 | public void testCreate() {
20 | int packetId = generateRandomPacketId();
21 | IdSizes expectedIdSizes = new IdSizes(1, 2, 3, 4, 5);
22 |
23 | IdSizesReply reply = IdSizesReply.create(packetId, expectedIdSizes, getVmInformation());
24 |
25 | assertEquals(packetId, reply.getPacket().getId());
26 | assertCommandIdentifier(ID_SIZES_REPLY, reply);
27 | assertEquals(expectedIdSizes, reply.getIdSizes());
28 | }
29 |
30 | @Test
31 | public void testParse() {
32 | int packetId = generateRandomPacketId();
33 | IdSizes expectedIdSizes = new IdSizes(1, 2, 3, 4, 5);
34 |
35 | IdSizesReply originalCommand = IdSizesReply.create(packetId, expectedIdSizes, getVmInformation());
36 | ReplyPacket originalPacket = originalCommand.getPacket();
37 | // Needed for parsing since replies don't contain info about what type they are
38 | originalPacket.setCommandPacket(new CommandPacket(packetId, ID_SIZES_REPLY.getCommandSetId(), ID_SIZES_REPLY.getCommandId(), new byte[0], null));
39 |
40 | CommandParser parser = new CommandParser(getVmInformation());
41 | Command parsedCommand = parser.parse(originalPacket);
42 |
43 | assertEqualPackets(originalPacket, parsedCommand.getPacket());
44 | assertEquals(true, parsedCommand instanceof IdSizesReply);
45 | assertEquals(packetId, parsedCommand.getPacket().getId());
46 | assertEquals(expectedIdSizes, ((IdSizesReply) parsedCommand).getIdSizes());
47 | }
48 | }
--------------------------------------------------------------------------------
/commands/src/test/java/kaap/veiko/debuggerforker/commands/commandsets/virtualmachine/ReleaseEventsCommandTest.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.commands.commandsets.virtualmachine;
2 |
3 | import static org.junit.Assert.assertEquals;
4 |
5 | import org.junit.Test;
6 |
7 | import kaap.veiko.debuggerforker.commands.Command;
8 | import kaap.veiko.debuggerforker.commands.commandsets.CommandIdentifier;
9 | import kaap.veiko.debuggerforker.commands.commandsets.CommandTestBase;
10 | import kaap.veiko.debuggerforker.commands.parser.CommandParser;
11 | import kaap.veiko.debuggerforker.packet.Packet;
12 |
13 | public class ReleaseEventsCommandTest extends CommandTestBase {
14 |
15 | @Test
16 | public void testCreate() {
17 | int packetId = generateRandomPacketId();
18 |
19 | ReleaseEventsCommand command = ReleaseEventsCommand.create(packetId);
20 |
21 | assertEquals(packetId, command.getPacket().getId());
22 | assertCommandIdentifier(CommandIdentifier.RELEASE_EVENTS_COMMAND, command);
23 | }
24 |
25 | @Test
26 | public void testParse() {
27 | int packetId = generateRandomPacketId();
28 | ReleaseEventsCommand originalCommand = ReleaseEventsCommand.create(packetId);
29 | Packet originalPacket = originalCommand.getPacket();
30 |
31 | CommandParser parser = new CommandParser(getVmInformation());
32 | Command parsedCommand = parser.parse(originalPacket);
33 |
34 | assertEqualPackets(originalPacket, parsedCommand.getPacket());
35 | assertEquals(true, parsedCommand instanceof ReleaseEventsCommand);
36 | assertEquals(packetId, parsedCommand.getPacket().getId());
37 | }
38 | }
--------------------------------------------------------------------------------
/connections/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jvm-debugger-forker
7 | kaap.veiko
8 | 0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | connections
13 |
14 |
15 |
16 | kaap.veiko
17 | packet
18 | ${parent.version}
19 |
20 |
21 | kaap.veiko
22 | types
23 | ${parent.version}
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/connections/src/main/java/kaap/veiko/debuggerforker/connections/ConnectorBase.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.connections;
2 |
3 | import java.io.IOException;
4 | import java.util.Set;
5 | import java.util.concurrent.ConcurrentHashMap;
6 | import java.util.concurrent.atomic.AtomicBoolean;
7 | import java.util.function.Consumer;
8 |
9 | import kaap.veiko.debuggerforker.packet.PacketStream;
10 |
11 | public abstract class ConnectorBase implements AutoCloseable {
12 |
13 | private final Thread thread;
14 | private final AtomicBoolean open = new AtomicBoolean(true);
15 | private final Set connectionHistory = ConcurrentHashMap.newKeySet();
16 | private final int maxOpenConnections;
17 |
18 | protected ConnectorBase(Consumer listener, int maxOpenConnections, String threadName) {
19 | this.maxOpenConnections = maxOpenConnections;
20 | thread = new Thread(() -> {
21 | while (isOpen()) {
22 | connect(listener);
23 | }
24 | }, threadName);
25 | }
26 |
27 | private void connect(Consumer listener) {
28 | if (shouldConnect()) {
29 | try {
30 | T connection = getConnectionBlocking();
31 | if (connection != null) {
32 | listener.accept(connection);
33 | connectionHistory.add(connection);
34 | }
35 | }
36 | catch (Exception e) {
37 | open.set(false);
38 | }
39 | }
40 | else {
41 | try {
42 | Thread.sleep(50);
43 | }
44 | catch (InterruptedException e) {
45 | open.set(false);
46 | Thread.currentThread().interrupt();
47 | }
48 | }
49 | }
50 |
51 | private boolean shouldConnect() {
52 | removeClosedConnectionsFromHistory();
53 | return maxOpenConnections > connectionHistory.size();
54 | }
55 |
56 | private void removeClosedConnectionsFromHistory() {
57 | connectionHistory.stream()
58 | .filter(PacketStream::isClosed)
59 | .forEach(connectionHistory::remove);
60 | }
61 |
62 | private boolean isOpen() {
63 | return open.get() && !Thread.currentThread().isInterrupted();
64 | }
65 |
66 | protected abstract T getConnectionBlocking() throws IOException;
67 |
68 | public void start() {
69 | thread.start();
70 | }
71 |
72 | @Override
73 | public void close() {
74 | open.set(false);
75 |
76 | try {
77 | thread.join(100);
78 | }
79 | catch (InterruptedException e) {
80 | Thread.currentThread().interrupt();
81 | }
82 | finally {
83 | thread.interrupt();
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/connections/src/main/java/kaap/veiko/debuggerforker/connections/DebuggerConnector.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.connections;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.ServerSocketChannel;
7 | import java.nio.channels.SocketChannel;
8 | import java.util.Arrays;
9 | import java.util.function.Consumer;
10 |
11 | import kaap.veiko.debuggerforker.packet.DebuggerPacketStream;
12 | import kaap.veiko.debuggerforker.packet.internal.DebuggerPacketTransformer;
13 | import kaap.veiko.debuggerforker.packet.internal.PacketTransformer;
14 |
15 | public class DebuggerConnector extends ConnectorBase {
16 | private final ServerSocketChannel serverChannel;
17 | private final PacketTransformer packetTransformer = new DebuggerPacketTransformer();
18 |
19 | public static DebuggerConnector create(int port, Consumer listener) throws IOException {
20 | ServerSocketChannel serverChannel = ServerSocketChannel.open();
21 | serverChannel.bind(new InetSocketAddress("127.0.0.1", port));
22 | return new DebuggerConnector(serverChannel, listener);
23 | }
24 |
25 | private DebuggerConnector(ServerSocketChannel serverChannel, Consumer listener) {
26 | super(listener, Integer.MAX_VALUE, "DebuggerConnectorThread");
27 | this.serverChannel = serverChannel;
28 | }
29 |
30 | @Override
31 | protected DebuggerPacketStream getConnectionBlocking() throws IOException {
32 | SocketChannel socketChannel = serverChannel.accept();
33 | socketChannel.configureBlocking(true);
34 | if (!socketChannel.finishConnect()) {
35 | throw new IOException("Failed to connect channel");
36 | }
37 | handshake(socketChannel);
38 | return new DebuggerPacketStream(socketChannel, packetTransformer);
39 | }
40 |
41 | private void handshake(SocketChannel socketChannel) throws IOException {
42 | byte[] handshakeBytes = "JDWP-Handshake".getBytes("UTF-8");
43 |
44 | ByteBuffer inBuffer = ByteBuffer.allocate(handshakeBytes.length);
45 | int bytesRead = 0;
46 | while (bytesRead != -1 && inBuffer.hasRemaining()) {
47 | bytesRead = socketChannel.read(inBuffer);
48 | }
49 | byte[] receivedBytes = inBuffer.array();
50 |
51 | if (!Arrays.equals(handshakeBytes, receivedBytes)) {
52 | throw new IOException("Handshake failed - wrong message from Debugger");
53 | }
54 |
55 | ByteBuffer outBuffer = ByteBuffer.wrap(handshakeBytes);
56 | while (outBuffer.hasRemaining()) {
57 | socketChannel.write(outBuffer);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/connections/src/main/java/kaap/veiko/debuggerforker/connections/VMConnector.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.connections;
2 |
3 | import java.io.IOException;
4 | import java.net.ConnectException;
5 | import java.net.InetSocketAddress;
6 | import java.nio.ByteBuffer;
7 | import java.nio.channels.SocketChannel;
8 | import java.util.Arrays;
9 | import java.util.function.Consumer;
10 |
11 | import kaap.veiko.debuggerforker.packet.VirtualMachinePacketStream;
12 |
13 | public class VMConnector extends ConnectorBase {
14 |
15 | private final InetSocketAddress socketAddress;
16 |
17 | public static VMConnector create(InetSocketAddress socketAddress, Consumer listener) {
18 | return new VMConnector(socketAddress, listener);
19 | }
20 |
21 | private VMConnector(InetSocketAddress socketAddress, Consumer listener) {
22 | super(listener, 1, "VmConnectorThread");
23 | this.socketAddress = socketAddress;
24 | }
25 |
26 | @Override
27 | protected VirtualMachinePacketStream getConnectionBlocking() throws IOException {
28 | SocketChannel socketChannel = connect(socketAddress);
29 | if (socketChannel == null) {
30 | return null;
31 | }
32 |
33 | handshake(socketChannel);
34 | return new VirtualMachinePacketStream(socketChannel);
35 | }
36 |
37 | private SocketChannel connect(InetSocketAddress address) throws IOException {
38 | try {
39 | SocketChannel channel = SocketChannel.open(address);
40 | channel.configureBlocking(true);
41 | if (!channel.finishConnect()) {
42 | throw new IOException("Failed to connect channel");
43 | }
44 | return channel;
45 | }
46 | catch (ConnectException connectException) {
47 | try {
48 | Thread.sleep(50);
49 | return null;
50 | }
51 | catch (InterruptedException interruptedException) {
52 | Thread.currentThread().interrupt();
53 | throw new IOException("Connection failed - InterruptedException before connected to the VM");
54 | }
55 | }
56 | }
57 |
58 | private void handshake(SocketChannel socketChannel) throws IOException {
59 | byte[] handshakeBytes = "JDWP-Handshake".getBytes("UTF-8");
60 |
61 | ByteBuffer outBuffer = ByteBuffer.wrap(handshakeBytes);
62 | while (outBuffer.hasRemaining()) {
63 | socketChannel.write(outBuffer);
64 | }
65 |
66 | ByteBuffer inBuffer = ByteBuffer.allocate(handshakeBytes.length);
67 | int bytesRead = 0;
68 | while (bytesRead != -1 && inBuffer.hasRemaining()) {
69 | bytesRead = socketChannel.read(inBuffer);
70 | }
71 | byte[] receivedBytes = inBuffer.array();
72 |
73 | if (!Arrays.equals(handshakeBytes, receivedBytes)) {
74 | throw new IOException("Handshake failed - wrong message from VM");
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/integration-tests/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jvm-debugger-forker
7 | kaap.veiko
8 | 0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | integration-tests
13 |
14 |
15 |
16 | org.ow2.asm
17 | asm
18 | 6.0
19 |
20 |
21 | org.ow2.asm
22 | asm-commons
23 | 6.0
24 |
25 |
26 | ${project.groupId}
27 | server-logic
28 | ${project.version}
29 |
30 |
31 | com.sun
32 | tools
33 | 1.8
34 | system
35 | ${java.home}/../lib/tools.jar
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/integration-tests/src/main/java/ee/veikokaap/debugproxy/testframework/EventRequestIdentifier.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.testframework;
2 |
3 | import java.lang.reflect.Field;
4 | import com.sun.jdi.request.EventRequest;
5 |
6 | final class EventRequestIdentifier {
7 | private final Class> requestClass;
8 | private final int requestId;
9 |
10 | static EventRequestIdentifier fromEventRequest(EventRequest request) throws ReflectiveOperationException {
11 | Field field = getDeclaredField(request.getClass(), "id");
12 | field.setAccessible(true);
13 | int requestId = field.getInt(request);
14 | return new EventRequestIdentifier(request.getClass(), requestId);
15 | }
16 |
17 | private EventRequestIdentifier(Class> requestClass, int requestId) {
18 | this.requestClass = requestClass;
19 | this.requestId = requestId;
20 | }
21 |
22 | public int getRequestId() {
23 | return requestId;
24 | }
25 |
26 | public Class> getRequestClass() {
27 | return requestClass;
28 | }
29 |
30 | @Override
31 | public boolean equals(Object o) {
32 | if (this == o) {
33 | return true;
34 | }
35 | if (o == null || getClass() != o.getClass()) {
36 | return false;
37 | }
38 |
39 | EventRequestIdentifier that = (EventRequestIdentifier) o;
40 |
41 | if (requestId != that.requestId) {
42 | return false;
43 | }
44 | return requestClass != null ? requestClass.equals(that.requestClass) : that.requestClass == null;
45 | }
46 |
47 | @Override
48 | public int hashCode() {
49 | int result = requestClass != null ? requestClass.hashCode() : 0;
50 | result = 31 * result + requestId;
51 | return result;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "EventRequestIdentifier{" +
57 | "requestClass=" + requestClass +
58 | ", requestId=" + requestId +
59 | '}';
60 | }
61 |
62 | private static Field getDeclaredField(Class> clazz, String fieldName) throws NoSuchFieldException {
63 | if (clazz == null) {
64 | throw new NoSuchFieldException(fieldName);
65 | }
66 |
67 | try {
68 | return clazz.getDeclaredField(fieldName);
69 | }
70 | catch (Exception ignored) {
71 | return getDeclaredField(clazz.getSuperclass(), fieldName);
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/integration-tests/src/main/java/ee/veikokaap/debugproxy/testframework/SuspendManager.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.testframework;
2 |
3 | import java.util.function.Consumer;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | import com.sun.jdi.event.BreakpointEvent;
7 | import com.sun.jdi.event.Event;
8 |
9 | public class SuspendManager {
10 | private final DebuggerProcess parentDebugger;
11 | private final Event event;
12 |
13 | SuspendManager(DebuggerProcess parentDebugger, Event event) {
14 | this.parentDebugger = parentDebugger;
15 | this.event = event;
16 | }
17 |
18 | void resume() {
19 | parentDebugger.resume();
20 | }
21 |
22 | void stepOver(@Nullable Consumer listener) throws Throwable {
23 | BreakpointEvent event = (BreakpointEvent) this.event;
24 | AsyncTester tester = parentDebugger.stepOver(event, listener);
25 | resume();
26 | tester.joinAndTest();
27 | }
28 |
29 | void stepInto(@Nullable Consumer listener) throws Throwable {
30 | BreakpointEvent event = (BreakpointEvent) this.event;
31 | AsyncTester tester = parentDebugger.stepInto(event, listener);
32 | resume();
33 | tester.joinAndTest();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/integration-tests/src/main/java/ee/veikokaap/debugproxy/testframework/utils/BreakpointLocation.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.testframework.utils;
2 |
3 | public class BreakpointLocation {
4 | private final String className;
5 | private final int lineNumber;
6 |
7 | BreakpointLocation(String className, int lineNumber) {
8 | this.className = className;
9 | this.lineNumber = lineNumber;
10 | }
11 |
12 | public String getClassName() {
13 | return className;
14 | }
15 |
16 | public int getLineNumber() {
17 | return lineNumber;
18 | }
19 |
20 | @Override
21 | public boolean equals(Object o) {
22 | if (this == o) {
23 | return true;
24 | }
25 | if (o == null || getClass() != o.getClass()) {
26 | return false;
27 | }
28 |
29 | BreakpointLocation location = (BreakpointLocation) o;
30 |
31 | if (lineNumber != location.lineNumber) {
32 | return false;
33 | }
34 | return className != null ? className.equals(location.className) : location.className == null;
35 | }
36 |
37 | @Override
38 | public int hashCode() {
39 | int result = className != null ? className.hashCode() : 0;
40 | result = 31 * result + lineNumber;
41 | return result;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "BreakpointLocation{" +
47 | "className='" + className + '\'' +
48 | ", lineNumber=" + lineNumber +
49 | '}';
50 | }
51 | }
--------------------------------------------------------------------------------
/integration-tests/src/main/java/ee/veikokaap/debugproxy/testframework/utils/BreakpointUtil.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.testframework.utils;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | public class BreakpointUtil {
7 |
8 | private static final Map> cache = new HashMap<>();
9 |
10 | /**
11 | * Method that's only used for later placing breakpoints on the same line
12 | * @param markerId from 0 to 5
13 | */
14 | public static void mark(int markerId) {
15 | }
16 |
17 | public static BreakpointLocation findBreakLocation(Class clazz, int id) {
18 | if (!cache.containsKey(clazz)) {
19 | cache.put(clazz, MarkerFinder.findLocations(clazz));
20 | }
21 |
22 | return cache.get(clazz).get(id);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/integration-tests/src/main/kotlin/ee/veikokaap/debugproxy/testframework/AsyncTester.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.testframework
2 |
3 | import java.util.concurrent.TimeUnit
4 | import java.util.concurrent.TimeoutException
5 | import java.util.concurrent.atomic.AtomicReference
6 | import java.util.function.Consumer
7 |
8 | open class AsyncTester(private val consumer: Consumer): Consumer {
9 |
10 | protected val exception = AtomicReference(null)
11 | private val thread = AtomicReference(null)
12 |
13 | override fun accept(t: T) {
14 | if (exception.get() != null) {
15 | return // Test previously failed
16 | }
17 |
18 | thread.set(Thread.currentThread())
19 | try {
20 | consumer.accept(t)
21 | } catch (e: Throwable) {
22 | exception.set(e)
23 | }
24 | }
25 |
26 | @Throws(Throwable::class)
27 | fun joinAndTest() {
28 | joinAndTest(Long.MAX_VALUE, TimeUnit.DAYS);
29 | }
30 |
31 | @Throws(Throwable::class)
32 | fun joinAndTest(time: Long, timeUnit: TimeUnit) {
33 | val millis = timeUnit.toMillis(time)
34 | val start = System.currentTimeMillis()
35 |
36 | waitForConsumerRun(millis, start)
37 | if (thread.get() == null) {
38 | throw AssertionError("Consumer hasn't been run in $time $timeUnit")
39 | }
40 |
41 | val timeLeft = timeLeft(millis, start)
42 | if (timeLeft <= 0) {
43 | throwTimeoutException(time, timeUnit)
44 | }
45 | thread.get().join(timeLeft)
46 |
47 | if (thread.get().isAlive) {
48 | throwTimeoutException(time, timeUnit)
49 | }
50 | if (exception.get() != null) {
51 | throw exception.get()
52 | }
53 | }
54 |
55 | private fun throwTimeoutException(time: Long, timeUnit: TimeUnit) {
56 | thread.get().interrupt()
57 | val timeoutException = TimeoutException("Thread should have finished work in $time $timeUnit")
58 | if (exception.get() != null) {
59 | timeoutException.addSuppressed(exception.get())
60 | }
61 | throw timeoutException
62 | }
63 |
64 | private fun timeLeft(millis: Long, start: Long) = millis - (System.currentTimeMillis() - start)
65 |
66 | @Throws(InterruptedException::class)
67 | private fun waitForConsumerRun(millis: Long, start: Long) {
68 | while (thread.get() == null && System.currentTimeMillis() - start < millis) {
69 | Thread.sleep(100)
70 | }
71 | }
72 |
73 | fun failTestWithException(e: Exception) = exception.set(e)
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/integration-tests/src/main/kotlin/ee/veikokaap/debugproxy/testframework/SuspendManagerAsyncTester.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.testframework
2 |
3 | import java.util.*
4 | import java.util.function.Consumer
5 |
6 | class SuspendManagerAsyncTester(consumer: Consumer): AsyncTester(consumer) {
7 |
8 | private var afterQueue: Deque = ArrayDeque();
9 |
10 | override fun accept(t: SuspendManager?) {
11 | super.accept(t);
12 |
13 | if (exception.get() == null) {
14 | afterQueue.forEach{
15 | when (it.afterAction) {
16 | AfterAction.RESUME -> t!!.resume()
17 | AfterAction.STEP_OVER -> t!!.stepOver(it.listener)
18 | AfterAction.STEP_INTO -> t!!.stepInto(it.listener)
19 | }
20 | }
21 | }
22 | }
23 |
24 | infix fun thenResume(u: () -> Unit): SuspendManagerAsyncTester {
25 | afterQueue.addLast(AfterBreak(AfterAction.RESUME, null))
26 | return this
27 | }
28 |
29 | infix fun thenStepOver(listener: ((SuspendManager) -> Unit)?): SuspendManagerAsyncTester {
30 | afterQueue.addLast(AfterBreak(AfterAction.STEP_OVER, listener))
31 | return this
32 | }
33 |
34 | private data class AfterBreak(val afterAction: AfterAction, val listener: ((SuspendManager) -> Unit)?)
35 |
36 | private enum class AfterAction {
37 | RESUME, STEP_OVER, STEP_INTO
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/integration-tests/src/test/java/ee/veikokaap/debugproxy/tests/LoopBreakpointClass.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests;
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil;
4 |
5 | public class LoopBreakpointClass {
6 |
7 | public static final String BEFORE_MESSAGE = "Before breakpoints";
8 | public static final String BREAKPOINT_MESSAGE_PREFIX = "Breakpoint: ";
9 | public static final String AFTER_MESSAGE = "After breakpoints";
10 |
11 | public static String getBreakpointMessage(int breakCount) {
12 | return BREAKPOINT_MESSAGE_PREFIX + breakCount;
13 | }
14 |
15 | public static void main(String[] args) {
16 | System.out.println(BEFORE_MESSAGE);
17 | for (int i = 0; i < 10; i++) {
18 | System.out.println(getBreakpointMessage(i));
19 | BreakpointUtil.mark(0);
20 | }
21 | System.out.println(AFTER_MESSAGE);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/integration-tests/src/test/java/ee/veikokaap/debugproxy/tests/SimpleBreakpointClass.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests;
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil;
4 |
5 | public class SimpleBreakpointClass {
6 | public static void main(String[] args) {
7 | System.out.println("Before breakpoints");
8 | BreakpointUtil.mark(0);
9 | System.out.println("After breakpoint 0");
10 | BreakpointUtil.mark(1);
11 | System.out.println("After breakpoint 1");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/integration-tests/src/test/java/ee/veikokaap/debugproxy/tests/StepBreakpointClass.java:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests;
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil;
4 |
5 | public class StepBreakpointClass {
6 |
7 | public static final String BEFORE_MESSAGE = "Before breakpoints";
8 | public static final String AFTER_BREAKPOINT_0 = "After breakpoint 0";
9 | public static final String STEPPED_OVER = "After step from breakpoint 0";
10 | public static final String AFTER_BREAKPOINT_1 = "After breakpoint 1";
11 | public static final String LAST_MESSAGE = "After breakpoints";
12 |
13 | public static void main(String[] args) {
14 | System.out.println(BEFORE_MESSAGE);
15 | BreakpointUtil.mark(0); System.out.println(AFTER_BREAKPOINT_0);
16 | System.out.println(STEPPED_OVER);
17 | BreakpointUtil.mark(1); System.out.println(AFTER_BREAKPOINT_1);
18 | System.out.println(LAST_MESSAGE);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/integration-tests/src/test/kotlin/ee/veikokaap/debugproxy/tests/doubledebugger/SimpleDoubleDebuggerTests.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests.doubledebugger
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil
4 | import ee.veikokaap.debugproxy.tests.SimpleBreakpointClass
5 | import ee.veikokaap.debugproxy.tests.assertAddedOutput
6 | import ee.veikokaap.debugproxy.tests.runTest
7 | import org.junit.Test
8 | import java.util.concurrent.TimeUnit
9 | import kotlin.test.assertTrue
10 |
11 | open class SimpleDoubleDebuggerTests {
12 |
13 | val testClass = SimpleBreakpointClass::class.java
14 | val firstLocation = BreakpointUtil.findBreakLocation(testClass, 0)
15 | val secondLocation = BreakpointUtil.findBreakLocation(testClass, 1)
16 |
17 | @Test
18 | fun `test single breakpoint with 2 debuggers`() = runTest(testClass) { jvm, firstDebugger, secondDebugger ->
19 | val firstBreak = firstDebugger.breakAt(firstLocation) {
20 | jvm.outputDeque.assertAddedOutput("Before breakpoints")
21 | } thenResume {}
22 |
23 | val secondBreak = secondDebugger.breakAt(firstLocation) {
24 | firstBreak.joinAndTest(4, TimeUnit.SECONDS)
25 | assertTrue(jvm.outputDeque.isEmpty())
26 | } thenResume {}
27 |
28 | firstDebugger.allBreakpointSet()
29 |
30 | secondBreak.joinAndTest()
31 | jvm.waitForExit()
32 |
33 | jvm.outputDeque.assertAddedOutput("After breakpoint 0", "After breakpoint 1")
34 | }
35 |
36 | @Test
37 | fun `test 2 breakpoints with 2 debuggers`() = runTest(testClass) { jvm, firstDebugger, secondDebugger ->
38 | val firstBreak = firstDebugger.breakAt(firstLocation) {
39 | jvm.outputDeque.assertAddedOutput("Before breakpoints")
40 | } thenResume {}
41 |
42 | val secondBreak = secondDebugger.breakAt(secondLocation) {
43 | jvm.outputDeque.assertAddedOutput("After breakpoint 0")
44 | } thenResume {}
45 |
46 | firstDebugger.allBreakpointSet()
47 | secondDebugger.allBreakpointSet()
48 |
49 | firstBreak.joinAndTest()
50 | secondBreak.joinAndTest()
51 | jvm.waitForExit()
52 |
53 | jvm.outputDeque.assertAddedOutput("After breakpoint 1")
54 | }
55 |
56 |
57 | }
--------------------------------------------------------------------------------
/integration-tests/src/test/kotlin/ee/veikokaap/debugproxy/tests/doubledebugger/StepDoubleDebuggerTests.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests.doubledebugger
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil
4 | import ee.veikokaap.debugproxy.tests.StepBreakpointClass
5 | import ee.veikokaap.debugproxy.tests.assertAddedOutput
6 | import ee.veikokaap.debugproxy.tests.runTest
7 | import org.junit.Test
8 |
9 | open class StepDoubleDebuggerTests {
10 |
11 | val testClass = StepBreakpointClass::class.java
12 | val firstBreakpoint = BreakpointUtil.findBreakLocation(testClass, 0)
13 | val secondBreakpoint = BreakpointUtil.findBreakLocation(testClass, 1)
14 |
15 | @Test
16 | fun `test two breakpoints that step to next line with two debuggers`() = runTest(testClass) { jvm, firstDebugger, secondDebugger ->
17 | val firstBreak = firstDebugger.breakAt(firstBreakpoint) {
18 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.BEFORE_MESSAGE)
19 | } thenStepOver {
20 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_0)
21 | } thenResume {}
22 |
23 | val secondBreak = secondDebugger.breakAt(secondBreakpoint) {
24 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER)
25 | } thenStepOver {
26 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_1)
27 | } thenResume {}
28 |
29 | firstDebugger.allBreakpointSet()
30 |
31 | firstBreak.joinAndTest()
32 | secondBreak.joinAndTest()
33 | jvm.waitForExit()
34 |
35 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.LAST_MESSAGE)
36 | }
37 |
38 | @Test
39 | fun `test stepping onto a existing breakpoint with two debuggers`() = runTest(testClass) { jvm, firstDebugger, secondDebugger ->
40 | val firstBreak = firstDebugger.breakAt(firstBreakpoint) {
41 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.BEFORE_MESSAGE)
42 | } thenStepOver {
43 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_0)
44 | } thenStepOver {
45 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER, remove = false)
46 | } thenResume {}
47 |
48 | val secondBreak = secondDebugger.breakAt(secondBreakpoint) {
49 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER, remove = false)
50 | firstBreak.joinAndTest() // wait until first breakpoint and steps have resumed
51 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER)
52 | } thenStepOver {
53 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_1)
54 | } thenResume {}
55 |
56 | firstDebugger.allBreakpointSet()
57 |
58 | firstBreak.joinAndTest()
59 | secondBreak.joinAndTest()
60 | jvm.waitForExit()
61 |
62 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.LAST_MESSAGE)
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/integration-tests/src/test/kotlin/ee/veikokaap/debugproxy/tests/singledebugger/LoopSingleDebuggerTests.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests.singledebugger
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil
4 | import ee.veikokaap.debugproxy.tests.LoopBreakpointClass
5 | import ee.veikokaap.debugproxy.tests.assertAddedOutput
6 | import ee.veikokaap.debugproxy.tests.runTest
7 | import org.junit.Test
8 | import java.util.concurrent.TimeUnit
9 |
10 | open class LoopSingleDebuggerTests {
11 |
12 | val testClass = LoopBreakpointClass::class.java
13 | val breakpoint = BreakpointUtil.findBreakLocation(testClass, 0)
14 |
15 | @Test
16 | fun `test a single breakpoint in for loop with a single debugger`() = runTest(testClass) { jvm, debugger ->
17 | var count = 0;
18 | val breakpoint = debugger.breakAt(breakpoint) { breakpoint ->
19 | if (count == 0) {
20 | jvm.outputDeque.assertAddedOutput(LoopBreakpointClass.BEFORE_MESSAGE, LoopBreakpointClass.getBreakpointMessage(0))
21 | }
22 | else {
23 | jvm.outputDeque.assertAddedOutput(LoopBreakpointClass.getBreakpointMessage(count))
24 | }
25 | count++;
26 | } thenResume {}
27 |
28 | debugger.allBreakpointSet()
29 |
30 | breakpoint.joinAndTest()
31 | jvm.waitForExit()
32 |
33 | jvm.outputDeque.assertAddedOutput(LoopBreakpointClass.AFTER_MESSAGE)
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/integration-tests/src/test/kotlin/ee/veikokaap/debugproxy/tests/singledebugger/SimpleSingleDebuggerTests.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests.singledebugger
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil
4 | import ee.veikokaap.debugproxy.tests.SimpleBreakpointClass
5 | import ee.veikokaap.debugproxy.tests.assertAddedOutput
6 | import ee.veikokaap.debugproxy.tests.runTest
7 | import org.junit.Test
8 |
9 | open class SimpleSingleDebuggerTests {
10 |
11 | val testClass = SimpleBreakpointClass::class.java
12 | val firstBreakpoint = BreakpointUtil.findBreakLocation(testClass, 0)
13 | val secondBreakpoint = BreakpointUtil.findBreakLocation(testClass, 1)
14 |
15 | @Test
16 | fun `test a single breakpoint with a single debugger`() = runTest(testClass) { jvm, debugger ->
17 | val breakpoint = debugger.breakAt(firstBreakpoint) { breakpoint ->
18 | jvm.outputDeque.assertAddedOutput("Before breakpoints")
19 | } thenResume {}
20 |
21 | debugger.allBreakpointSet()
22 |
23 | breakpoint.joinAndTest()
24 | jvm.waitForExit()
25 |
26 | jvm.outputDeque.assertAddedOutput("After breakpoint 0", "After breakpoint 1")
27 | }
28 |
29 | @Test
30 | fun `test 2 breakpoints with a single debugger`() = runTest(testClass) { jvm, debugger ->
31 | val firstBreak = debugger.breakAt(firstBreakpoint) {
32 | jvm.outputDeque.assertAddedOutput("Before breakpoints")
33 | } thenResume {}
34 |
35 | val secondBreak = debugger.breakAt(secondBreakpoint) {
36 | jvm.outputDeque.assertAddedOutput("After breakpoint 0")
37 | } thenResume {}
38 |
39 | debugger.allBreakpointSet()
40 |
41 | firstBreak.joinAndTest()
42 | secondBreak.joinAndTest()
43 | jvm.waitForExit()
44 |
45 | jvm.outputDeque.assertAddedOutput("After breakpoint 1")
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/integration-tests/src/test/kotlin/ee/veikokaap/debugproxy/tests/singledebugger/StepSingleDebuggerTests.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests.singledebugger
2 |
3 | import ee.veikokaap.debugproxy.testframework.utils.BreakpointUtil
4 | import ee.veikokaap.debugproxy.tests.StepBreakpointClass
5 | import ee.veikokaap.debugproxy.tests.assertAddedOutput
6 | import ee.veikokaap.debugproxy.tests.runTest
7 | import org.junit.Test
8 |
9 | open class StepSingleDebuggerTests {
10 |
11 | val testClass = StepBreakpointClass::class.java
12 | val firstBreakpoint = BreakpointUtil.findBreakLocation(testClass, 0)
13 | val secondBreakpoint = BreakpointUtil.findBreakLocation(testClass, 1)
14 |
15 | @Test
16 | fun `test two breakpoints that step to next line with a single debugger`() =
17 | runTest(testClass) { jvm, debugger ->
18 | val firstBreak = debugger.breakAt(firstBreakpoint) {
19 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.BEFORE_MESSAGE)
20 | } thenStepOver {
21 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_0)
22 | } thenResume {}
23 |
24 | val secondBreak = debugger.breakAt(secondBreakpoint) {
25 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER)
26 | } thenStepOver {
27 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_1)
28 | } thenResume {}
29 |
30 | debugger.allBreakpointSet()
31 | firstBreak.joinAndTest()
32 | secondBreak.joinAndTest()
33 | jvm.waitForExit()
34 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.LAST_MESSAGE)
35 | }
36 |
37 | @Test
38 | fun `test stepping onto a existing breakpoint with a single debugger`() = runTest(testClass) { jvm, debugger ->
39 | val firstBreak = debugger.breakAt(firstBreakpoint) {
40 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.BEFORE_MESSAGE)
41 | } thenStepOver {
42 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_0)
43 | } thenStepOver {
44 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER, remove = false)
45 | }
46 |
47 | val secondBreak = debugger.breakAt(secondBreakpoint) {
48 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER, remove = false)
49 | firstBreak.joinAndTest() // wait until first breakpoint and steps have resumed
50 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.STEPPED_OVER)
51 | } thenStepOver {
52 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.AFTER_BREAKPOINT_1)
53 | } thenResume {}
54 |
55 | debugger.allBreakpointSet()
56 |
57 | firstBreak.joinAndTest()
58 | secondBreak.joinAndTest()
59 | jvm.waitForExit()
60 |
61 | jvm.outputDeque.assertAddedOutput(StepBreakpointClass.LAST_MESSAGE)
62 | }
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/integration-tests/src/test/kotlin/ee/veikokaap/debugproxy/tests/testFunctions.kt:
--------------------------------------------------------------------------------
1 | package ee.veikokaap.debugproxy.tests
2 |
3 | import ee.veikokaap.debugproxy.testframework.AsyncTester
4 | import ee.veikokaap.debugproxy.testframework.DebuggerProcess
5 | import ee.veikokaap.debugproxy.testframework.JvmProcess
6 | import java.util.*
7 | import java.util.concurrent.TimeUnit
8 | import java.util.function.Consumer
9 | import kotlin.test.assertEquals
10 |
11 | fun Deque.assertAddedOutput(vararg lines: String, remove: Boolean = true) {
12 | val expectedList = lines.toList()
13 |
14 | synchronized(this) {
15 | val actualPolledList = this.toList();
16 | if (remove) {
17 | this.clear()
18 | }
19 | assertEquals(expectedList, actualPolledList)
20 | }
21 | }
22 |
23 | fun runTest(testClass: Class<*>, timeout: Long = 10, timeUnit: TimeUnit = TimeUnit.SECONDS, test: (JvmProcess, DebuggerProcess) -> Unit) {
24 | JvmProcess.runClass(testClass).use { jvm ->
25 | DebuggerProcess.attach().use { debugger ->
26 | val tester = asyncTester {
27 | assertEquals("Listening for transport dt_socket at address: ${JvmProcess.DEBUGGER_PORT}", jvm.outputDeque.pollLast())
28 | test(jvm, debugger)
29 | }
30 | Thread { tester.accept(null) }.start()
31 | tester.joinAndTest(timeout, timeUnit)
32 | }
33 | }
34 | }
35 |
36 | fun runTest(testClass: Class<*>, timeout: Long = 10, timeUnit: TimeUnit = TimeUnit.SECONDS, test: (JvmProcess, DebuggerProcess, DebuggerProcess) -> Unit) {
37 | JvmProcess.runClass(testClass).use { jvm ->
38 | DebuggerProcess.attach().use { firstDebugger ->
39 | DebuggerProcess.attach().use { secondDebugger ->
40 | val tester = asyncTester {
41 | assertEquals("Listening for transport dt_socket at address: ${JvmProcess.DEBUGGER_PORT}", jvm.outputDeque.pollLast())
42 | test(jvm, firstDebugger, secondDebugger)
43 | }
44 | Thread { tester.accept(null) }.start()
45 | tester.joinAndTest(timeout, timeUnit)
46 | }
47 | }
48 | }
49 | }
50 |
51 | fun asyncTester(f: (T) -> Unit) = AsyncTester(object : Consumer {
52 | override fun accept(t: T) {
53 | f(t)
54 | }
55 | })
56 |
57 | fun toRunnable(f: () -> Unit): Runnable = object : Runnable {
58 | override fun run() {
59 | f()
60 | }
61 | }
--------------------------------------------------------------------------------
/packet/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jvm-debugger-forker
7 | kaap.veiko
8 | 0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | packet
13 |
14 |
15 |
16 | kaap.veiko
17 | types
18 | ${parent.version}
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/CommandPacket.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | import java.util.Arrays;
4 |
5 | import kaap.veiko.debuggerforker.packet.internal.PacketBase;
6 |
7 | public class CommandPacket extends PacketBase {
8 |
9 | private final short commandId;
10 | private final short commandSetId;
11 | private ReplyPacket replyPacket;
12 |
13 | public CommandPacket(int id, short commandSetId, short commandId, byte[] data, PacketSource source) {
14 | super(id, data, source);
15 | this.commandSetId = commandSetId;
16 | this.commandId = commandId;
17 | }
18 |
19 | public short getCommandId() {
20 | return commandId;
21 | }
22 |
23 | public short getCommandSetId() {
24 | return commandSetId;
25 | }
26 |
27 | public ReplyPacket getReplyPacket() {
28 | return replyPacket;
29 | }
30 |
31 | public void setReplyPacket(ReplyPacket replyPacket) {
32 | this.replyPacket = replyPacket;
33 | }
34 |
35 | @Override
36 | public boolean isReply() {
37 | return false;
38 | }
39 |
40 | @Override
41 | public T visit(PacketVisitor visitor) {
42 | return visitor.visit(this);
43 | }
44 |
45 | @Override
46 | public boolean equals(Object o) {
47 | if (this == o) {
48 | return true;
49 | }
50 | if (o == null || getClass() != o.getClass()) {
51 | return false;
52 | }
53 | if (!super.equals(o)) {
54 | return false;
55 | }
56 |
57 | CommandPacket that = (CommandPacket) o;
58 |
59 | if (commandId != that.commandId) {
60 | return false;
61 | }
62 | if (commandSetId != that.commandSetId) {
63 | return false;
64 | }
65 | return replyPacket != null ? replyPacket.equals(that.replyPacket) : that.replyPacket == null;
66 | }
67 |
68 | @Override
69 | public int hashCode() {
70 | int result = super.hashCode();
71 | result = 31 * result + (int) commandId;
72 | result = 31 * result + (int) commandSetId;
73 | return result;
74 | }
75 |
76 | @Override
77 | public String toString() {
78 | return "CommandPacket{" +
79 | "length=" + getLength() +
80 | ", id=" + getId() +
81 | ", flags=" + getFlags() +
82 | ", commandId=" + commandId +
83 | ", commandSetId=" + commandSetId +
84 | ", data=" + Arrays.toString(getData()) +
85 | ", source=" + getSource() +
86 | '}';
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/DebuggerPacketStream.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | import static kaap.veiko.debuggerforker.packet.PacketSource.SourceType.DEBUGGER;
4 |
5 | import java.io.IOException;
6 | import java.nio.channels.SocketChannel;
7 |
8 | import kaap.veiko.debuggerforker.packet.internal.PacketTransformer;
9 | import kaap.veiko.debuggerforker.packet.internal.PacketStreamBase;
10 |
11 | public class DebuggerPacketStream extends PacketStreamBase {
12 |
13 | public DebuggerPacketStream(SocketChannel socketChannel, PacketTransformer packetTransformer) throws IOException {
14 | super(socketChannel, DEBUGGER, packetTransformer);
15 | }
16 |
17 | @Override
18 | public String toString() {
19 | return "DebuggerPacketStream{" +
20 | "socketChannel=" + getSocketChannel() +
21 | '}';
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/Packet.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | public interface Packet {
4 | int HEADER_LENGTH = 11;
5 |
6 | int getLength();
7 |
8 | int getId();
9 |
10 | short getFlags();
11 |
12 | byte[] getData();
13 |
14 | boolean isReply();
15 |
16 | default boolean hasData() {
17 | return getLength() > HEADER_LENGTH;
18 | }
19 |
20 | PacketSource getSource();
21 |
22 | boolean isSynthetic();
23 |
24 | T visit(PacketVisitor visitor);
25 | }
26 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/PacketSource.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | import java.nio.channels.SocketChannel;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | import kaap.veiko.debuggerforker.packet.internal.PacketTransformer;
7 |
8 | public class PacketSource {
9 |
10 | private final static AtomicInteger counter = new AtomicInteger(0);
11 |
12 | private final int id;
13 |
14 | private final SocketChannel socketChannel;
15 | private final SourceType sourceType;
16 | private final PacketTransformer packetTransformer;
17 |
18 | private boolean holdEvents;
19 |
20 | public PacketSource(SocketChannel socketChannel, SourceType sourceType, PacketTransformer packetTransformer) {
21 | this.socketChannel = socketChannel;
22 | this.sourceType = sourceType;
23 | this.packetTransformer = packetTransformer;
24 | id = counter.getAndIncrement();
25 | }
26 |
27 | public int createNewOutputId() {
28 | return packetTransformer.createNewId();
29 | }
30 |
31 | public boolean isDebugger() {
32 | return sourceType == SourceType.DEBUGGER;
33 | }
34 |
35 | public boolean isVirtualMachine() {
36 | return sourceType == SourceType.VIRTUAL_MACHINE;
37 | }
38 |
39 | @Override
40 | public boolean equals(Object o) {
41 | if (this == o) {
42 | return true;
43 | }
44 | if (o == null || getClass() != o.getClass()) {
45 | return false;
46 | }
47 |
48 | PacketSource that = (PacketSource) o;
49 |
50 | return socketChannel != null ? socketChannel.equals(that.socketChannel) : that.socketChannel == null;
51 | }
52 |
53 | @Override
54 | public int hashCode() {
55 | return socketChannel != null ? socketChannel.hashCode() : 0;
56 | }
57 |
58 | @Override
59 | public String toString() {
60 | return sourceType.toString() + "_" + id;
61 |
62 | }
63 |
64 | public void setHoldEvents(boolean holdEvents) {
65 | this.holdEvents = holdEvents;
66 | }
67 |
68 | public boolean isHoldEvents() {
69 | return holdEvents;
70 | }
71 |
72 | public enum SourceType {
73 | DEBUGGER,
74 | VIRTUAL_MACHINE
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/PacketStream.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.SocketChannel;
5 |
6 | public interface PacketStream {
7 | Packet read() throws IOException;
8 |
9 | void write(Packet packet) throws IOException;
10 |
11 | SocketChannel getSocketChannel();
12 |
13 | PacketSource getSource();
14 |
15 | void close();
16 |
17 | boolean isClosed();
18 | }
19 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/PacketVisitor.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | public interface PacketVisitor {
4 | T visit(ReplyPacket replyPacket);
5 |
6 | T visit(CommandPacket commandPacket);
7 | }
8 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/ReplyPacket.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | import java.util.Arrays;
4 |
5 | import kaap.veiko.debuggerforker.packet.internal.PacketBase;
6 |
7 | public class ReplyPacket extends PacketBase {
8 |
9 | private final short errorCode;
10 | private CommandPacket commandPacket;
11 |
12 | public ReplyPacket(int id, short errorCode, byte[] data, PacketSource source) {
13 | super(id, data, source);
14 | this.errorCode = errorCode;
15 | }
16 |
17 | public short getErrorCode() {
18 | return errorCode;
19 | }
20 |
21 | public CommandPacket getCommandPacket() {
22 | return commandPacket;
23 | }
24 |
25 | public void setCommandPacket(CommandPacket commandPacket) {
26 | this.commandPacket = commandPacket;
27 | }
28 |
29 | @Override
30 | public boolean isReply() {
31 | return true;
32 | }
33 |
34 | @Override
35 | public T visit(PacketVisitor visitor) {
36 | return visitor.visit(this);
37 | }
38 |
39 | @Override
40 | public boolean equals(Object o) {
41 | if (this == o) {
42 | return true;
43 | }
44 | if (o == null || getClass() != o.getClass()) {
45 | return false;
46 | }
47 | if (!super.equals(o)) {
48 | return false;
49 | }
50 |
51 | ReplyPacket that = (ReplyPacket) o;
52 |
53 | if (errorCode != that.errorCode) {
54 | return false;
55 | }
56 | return commandPacket != null ? commandPacket.equals(that.commandPacket) : that.commandPacket == null;
57 | }
58 |
59 | @Override
60 | public int hashCode() {
61 | int result = super.hashCode();
62 | result = 31 * result + (int) errorCode;
63 | return result;
64 | }
65 |
66 | @Override
67 | public String toString() {
68 | return "ReplyPacket{" +
69 | "length=" + getLength() +
70 | ", id=" + getId() +
71 | ", flags=" + getFlags() +
72 | ", errorCode=" + errorCode +
73 | ", data=" + Arrays.toString(getData()) +
74 | ", source=" + getSource() +
75 | '}';
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/VirtualMachinePacketStream.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet;
2 |
3 | import static kaap.veiko.debuggerforker.packet.PacketSource.SourceType.VIRTUAL_MACHINE;
4 |
5 | import java.io.IOException;
6 | import java.nio.channels.SocketChannel;
7 | import java.util.concurrent.ConcurrentHashMap;
8 | import java.util.concurrent.ConcurrentMap;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import kaap.veiko.debuggerforker.packet.internal.PacketStreamBase;
14 | import kaap.veiko.debuggerforker.packet.internal.VmPacketTransformer;
15 |
16 | public class VirtualMachinePacketStream extends PacketStreamBase {
17 |
18 | private final Logger log = LoggerFactory.getLogger(VirtualMachinePacketStream.class);
19 |
20 | private final ConcurrentMap writtenCommands = new ConcurrentHashMap<>();
21 | private final ReplyPacketVisitor replyPacketVisitor = new ReplyPacketVisitor();
22 |
23 | public VirtualMachinePacketStream(SocketChannel socketChannel) throws IOException {
24 | super(socketChannel, VIRTUAL_MACHINE, new VmPacketTransformer());
25 | }
26 |
27 | @Override
28 | public Packet read() throws IOException {
29 | Packet packet = super.read();
30 | if (packet == null) {
31 | return null;
32 | }
33 |
34 | return packet.visit(replyPacketVisitor);
35 | }
36 |
37 | @Override
38 | public void write(Packet packet) throws IOException {
39 | if (!packet.isReply() && packet instanceof CommandPacket) {
40 | writtenCommands.put(packet.getId(), (CommandPacket) packet);
41 | super.write(packet);
42 | }
43 | else {
44 | log.error("VirtualMachine can't receive replies. Tried to write packet {}", packet);
45 | }
46 | }
47 |
48 | private class ReplyPacketVisitor implements PacketVisitor {
49 | @Override
50 | public Packet visit(ReplyPacket replyPacket) {
51 | CommandPacket commandPacket = writtenCommands.get(replyPacket.getId());
52 | commandPacket.setReplyPacket(replyPacket);
53 | replyPacket.setCommandPacket(commandPacket);
54 |
55 | return replyPacket;
56 | }
57 |
58 | @Override
59 | public Packet visit(CommandPacket packet) {
60 | return packet;
61 | }
62 | }
63 |
64 | @Override
65 | public String toString() {
66 | return "VirtualMachinePacketStream{" +
67 | "socketChannel=" + getSocketChannel() +
68 | '}';
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/ByteBufferDataReader.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import kaap.veiko.debuggerforker.packet.utils.ByteBufferUtil;
9 | import kaap.veiko.debuggerforker.types.DataReader;
10 |
11 | import kaap.veiko.debuggerforker.types.VMInformation;
12 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
13 |
14 | public class ByteBufferDataReader implements DataReader {
15 |
16 | private final static Logger log = LoggerFactory.getLogger(ByteBufferDataReader.class);
17 |
18 | private final ByteBuffer byteBuffer;
19 | private final VMInformation vmInformation;
20 |
21 | public ByteBufferDataReader(ByteBuffer packetByteBuffer, VMInformation vmInformation) {
22 | this.byteBuffer = packetByteBuffer;
23 | this.vmInformation = vmInformation;
24 | }
25 |
26 | @Override
27 | public byte readByte() {
28 | return byteBuffer.get();
29 | }
30 |
31 | @Override
32 | public short readShort() {
33 | return byteBuffer.getShort();
34 | }
35 |
36 | @Override
37 | public int readInt() {
38 | return byteBuffer.getInt();
39 | }
40 |
41 | @Override
42 | public long readLong() {
43 | return byteBuffer.getLong();
44 | }
45 |
46 | @Override
47 | public float readFloat() {
48 | return byteBuffer.getFloat();
49 | }
50 |
51 | @Override
52 | public double readDouble() {
53 | return byteBuffer.getDouble();
54 | }
55 |
56 | @Override
57 | public long readLongOfSize(IdSizes.SizeType sizeType) {
58 | IdSizes idSizes = vmInformation.getIdSizes();
59 | int size;
60 | if (idSizes == null) {
61 | log.warn("Parsing value without knowing its size in bytes. Assuming size is 8 bytes.");
62 | size = 8;
63 | }
64 | else {
65 | size = idSizes.getSizeOfType(sizeType);
66 | }
67 | return ByteBufferUtil.getLong(byteBuffer, size);
68 | }
69 |
70 | @Override
71 | public boolean readBoolean() {
72 | return byteBuffer.get() != 0;
73 | }
74 |
75 | @Override
76 | public String readString() {
77 | return ByteBufferUtil.getString(byteBuffer);
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/ByteBufferDataWriter.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import kaap.veiko.debuggerforker.packet.utils.ByteBufferUtil;
9 | import kaap.veiko.debuggerforker.types.DataType;
10 | import kaap.veiko.debuggerforker.types.DataWriter;
11 | import kaap.veiko.debuggerforker.types.VMInformation;
12 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
13 |
14 | public class ByteBufferDataWriter implements DataWriter {
15 |
16 | private final static Logger log = LoggerFactory.getLogger(ByteBufferDataWriter.class);
17 |
18 | private final ByteBuffer byteBuffer;
19 | private final VMInformation vmInformation;
20 |
21 | public ByteBufferDataWriter(ByteBuffer byteBuffer, VMInformation vmInformation) {
22 | this.byteBuffer = byteBuffer;
23 | this.vmInformation = vmInformation;
24 | }
25 |
26 | @Override
27 | public void writeBoolean(boolean bool) {
28 | if (bool) {
29 | byteBuffer.put((byte) 1);
30 | }
31 | else {
32 | byteBuffer.put((byte) 0);
33 | }
34 | }
35 |
36 | @Override
37 | public void writeByte(byte b) {
38 | byteBuffer.put(b);
39 | }
40 |
41 | @Override
42 | public void writeShort(short s) {
43 | byteBuffer.putShort(s);
44 | }
45 |
46 | @Override
47 | public void writeInt(int i) {
48 | byteBuffer.putInt(i);
49 | }
50 |
51 | @Override
52 | public void writeLong(long l) {
53 | byteBuffer.putLong(l);
54 | }
55 |
56 | @Override
57 | public void writeFloat(float f) {
58 | byteBuffer.putFloat(f);
59 | }
60 |
61 | @Override
62 | public void writeDouble(double d) {
63 | byteBuffer.putDouble(d);
64 | }
65 |
66 | @Override
67 | public void writeLongOfSize(long l, IdSizes.SizeType sizeType) {
68 | IdSizes idSizes = vmInformation.getIdSizes();
69 | int size;
70 | if (idSizes == null) {
71 | log.warn("Writing value without knowing its size in bytes. Assuming size is 8 bytes.");
72 | size = 8;
73 | }
74 | else {
75 | size = idSizes.getSizeOfType(sizeType);
76 | }
77 |
78 | ByteBufferUtil.putLong(byteBuffer, l, size);
79 | }
80 |
81 | @Override
82 | public void writeString(String string) {
83 | ByteBufferUtil.putString(byteBuffer, string);
84 | }
85 |
86 | @Override
87 | public void writeType(DataType type) {
88 | type.write(this);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/DebuggerPacketTransformer.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 | import java.util.concurrent.ConcurrentMap;
5 | import java.util.concurrent.atomic.AtomicInteger;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import kaap.veiko.debuggerforker.packet.CommandPacket;
11 | import kaap.veiko.debuggerforker.packet.Packet;
12 | import kaap.veiko.debuggerforker.packet.PacketVisitor;
13 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
14 |
15 | public class DebuggerPacketTransformer implements PacketTransformer {
16 |
17 | private static final Logger log = LoggerFactory.getLogger(DebuggerPacketTransformer.class);
18 |
19 | private final ConcurrentMap idMap = new ConcurrentHashMap<>();
20 | private final AtomicInteger idCounter = new AtomicInteger(0);
21 |
22 | private final OutputPacketVisitor outputPacketVisitor = new OutputPacketVisitor();
23 | private final InputPacketVisitor inputPacketVisitor = new InputPacketVisitor();
24 |
25 | @Override
26 | public Packet transformReadPacket(Packet packet) {
27 | return packet.visit(outputPacketVisitor);
28 | }
29 |
30 | @Override
31 | public Packet transformWritePacket(Packet packet) {
32 | return packet.visit(inputPacketVisitor);
33 | }
34 |
35 | @Override
36 | public int createNewId() {
37 | return idCounter.getAndIncrement();
38 | }
39 |
40 | private int getNewId(int originalId) {
41 | int newId = idCounter.getAndIncrement();
42 | idMap.put(newId, originalId);
43 | return newId;
44 | }
45 |
46 | private int getOriginalId(int newId) {
47 | return idMap.get(newId);
48 | }
49 |
50 | private class OutputPacketVisitor implements PacketVisitor {
51 | @Override
52 | public Packet visit(ReplyPacket packet) {
53 | log.error("Debugger shouldn't output reply packets");
54 | return packet;
55 | }
56 |
57 | @Override
58 | public Packet visit(CommandPacket packet) {
59 | // Generate new id to ensure every packet reaching vm has a unique id
60 | // This also makes it easy to later connect reply and command packets and avoid collision
61 | int newId = getNewId(packet.getId());
62 | return new CommandPacket(
63 | newId,
64 | packet.getCommandSetId(),
65 | packet.getCommandId(),
66 | packet.getData(),
67 | packet.getSource()
68 | );
69 | }
70 | }
71 |
72 | private class InputPacketVisitor implements PacketVisitor {
73 | @Override
74 | public Packet visit(ReplyPacket packet) {
75 | // Restore original id
76 | int originalId = getOriginalId(packet.getId());
77 | return new ReplyPacket(
78 | originalId,
79 | packet.getErrorCode(),
80 | packet.getData(),
81 | packet.getSource()
82 | );
83 | }
84 |
85 | @Override
86 | public Packet visit(CommandPacket packet) {
87 | // id of this packet should already be changed by the vm packet transformer
88 | return packet;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/PacketBase.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.util.Arrays;
4 | import java.util.Objects;
5 |
6 | import kaap.veiko.debuggerforker.packet.Packet;
7 | import kaap.veiko.debuggerforker.packet.PacketSource;
8 | import kaap.veiko.debuggerforker.packet.PacketStream;
9 |
10 | public abstract class PacketBase implements Packet {
11 |
12 | private final int id;
13 | private final byte[] data;
14 | private final PacketSource source;
15 |
16 | public PacketBase(int id, byte[] data, PacketSource source) {
17 | this.id = id;
18 | this.data = data;
19 | this.source = source;
20 | }
21 |
22 | @Override
23 | public int getLength() {
24 | return Packet.HEADER_LENGTH + getData().length;
25 | }
26 |
27 | @Override
28 | public int getId() {
29 | return id;
30 | }
31 |
32 | @Override
33 | public short getFlags() {
34 | return (short) (isReply() ? -128 : 0);
35 | }
36 |
37 | @Override
38 | public byte[] getData() {
39 | return data;
40 | }
41 |
42 | @Override
43 | public PacketSource getSource() {
44 | return source;
45 | }
46 |
47 | @Override
48 | public boolean isSynthetic() {
49 | return false;
50 | }
51 |
52 | @Override
53 | public boolean equals(Object o) {
54 | if (this == o) {
55 | return true;
56 | }
57 | if (!(o instanceof PacketBase)) {
58 | return false;
59 | }
60 | PacketBase that = (PacketBase) o;
61 | return getId() == that.getId() &&
62 | isReply() == that.isReply() &&
63 | Arrays.equals(getData(), that.getData()) &&
64 | Objects.equals(getSource(), that.getSource());
65 | }
66 |
67 | @Override
68 | public int hashCode() {
69 | int result = Objects.hash(getId(), isReply(), getSource());
70 | result = 31 * result + Arrays.hashCode(getData());
71 | return result;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/PacketParser.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.util.function.Function;
5 |
6 | import kaap.veiko.debuggerforker.packet.CommandPacket;
7 | import kaap.veiko.debuggerforker.packet.Packet;
8 | import kaap.veiko.debuggerforker.packet.PacketSource;
9 | import kaap.veiko.debuggerforker.packet.PacketStream;
10 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
11 |
12 | class PacketParser {
13 |
14 | private final int length;
15 | private final byte[] packetBytes;
16 | private int index = 0;
17 |
18 | private PacketParser(int length, byte[] packetBytes) {
19 | this.length = length;
20 | this.packetBytes = packetBytes;
21 | }
22 |
23 | static Packet parse(int length, byte[] packetBytes, PacketSource source) {
24 | return new PacketParser(length, packetBytes).internalParse(source);
25 | }
26 |
27 | private Packet internalParse(PacketSource source) {
28 | int id = readInt();
29 | short flags = readByte();
30 |
31 | if (flags == -128) {
32 | short errorCode = readShort();
33 | byte[] data = readData();
34 | return new ReplyPacket(id, errorCode, data, source);
35 | }
36 | else {
37 | short commandSetId = readByte();
38 | short commandId = readByte();
39 | byte[] data = readData();
40 |
41 | return new CommandPacket(id, commandSetId, commandId, data, source);
42 | }
43 | }
44 |
45 | private int readInt() {
46 | return readBytesAndApply(4, ByteBuffer::getInt);
47 | }
48 |
49 | private short readShort() {
50 | return readBytesAndApply(2, ByteBuffer::getShort);
51 | }
52 |
53 | private short readByte() {
54 | return (short) readBytesAndApply(1, ByteBuffer::get);
55 | }
56 |
57 | private byte[] readData() {
58 | if (length > Packet.HEADER_LENGTH) {
59 | return readBytesAndApply(length - Packet.HEADER_LENGTH, bf -> {
60 | byte[] data = new byte[length - Packet.HEADER_LENGTH];
61 | bf.get(data);
62 | return data;
63 | });
64 | } else {
65 | return new byte[0];
66 | }
67 | }
68 |
69 | private T readBytesAndApply(int nrOfBytes, Function function) {
70 | ByteBuffer buf = ByteBuffer.wrap(packetBytes, index, nrOfBytes);
71 | index += nrOfBytes;
72 | return function.apply(buf);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/PacketReader.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.io.IOException;
4 | import java.nio.ByteBuffer;
5 | import java.nio.channels.SocketChannel;
6 |
7 | import kaap.veiko.debuggerforker.packet.Packet;
8 | import kaap.veiko.debuggerforker.packet.PacketSource;
9 | import kaap.veiko.debuggerforker.packet.PacketStream;
10 |
11 | class PacketReader {
12 |
13 | private final SocketChannel socketChannel;
14 | private final PacketSource source;
15 |
16 | private boolean readingLength = true;
17 | private boolean readingData = false;
18 | private boolean doneReading = false;
19 | private int length;
20 | private ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
21 | private ByteBuffer dataBuffer = null;
22 |
23 | PacketReader(SocketChannel socketChannel, PacketSource source) {
24 | this.socketChannel = socketChannel;
25 | this.source = source;
26 | }
27 |
28 | public Packet read() throws IOException {
29 | if (readingLength) {
30 | readLength();
31 | }
32 | if (readingData) {
33 | readData();
34 | }
35 |
36 | if (doneReading) {
37 | doneReading = false;
38 | readingLength = true;
39 | dataBuffer.flip();
40 | byte[] array;
41 | if (dataBuffer.hasArray()) {
42 | array = dataBuffer.array();
43 | } else {
44 | array = new byte[length];
45 | dataBuffer.get(array);
46 | }
47 |
48 | return PacketParser.parse(length, array, source);
49 | }
50 | return null;
51 | }
52 |
53 | private void readLength() throws IOException {
54 | while (lengthBuffer.hasRemaining()) {
55 | int read = socketChannel.read(lengthBuffer);
56 | if (read == 0) {
57 | break;
58 | }
59 | }
60 |
61 | if (!lengthBuffer.hasRemaining()) {
62 | lengthBuffer.flip();
63 | length = lengthBuffer.getInt();
64 | dataBuffer = ByteBuffer.allocate(length - 4);
65 | lengthBuffer.clear();
66 | readingLength = false;
67 | readingData = true;
68 | }
69 | }
70 |
71 | private void readData() throws IOException {
72 | while (dataBuffer.hasRemaining()) {
73 | int read = socketChannel.read(dataBuffer);
74 | if (read == 0) {
75 | break;
76 | }
77 | }
78 |
79 | if (!dataBuffer.hasRemaining()) {
80 | readingData = false;
81 | doneReading = true;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/PacketTransformer.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import kaap.veiko.debuggerforker.packet.Packet;
4 |
5 | public interface PacketTransformer {
6 | Packet transformReadPacket(Packet packet);
7 |
8 | Packet transformWritePacket(Packet packet);
9 |
10 | int createNewId();
11 | }
12 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/PacketWriter.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.io.IOException;
4 | import java.nio.ByteBuffer;
5 | import java.nio.channels.SocketChannel;
6 |
7 | import kaap.veiko.debuggerforker.packet.CommandPacket;
8 | import kaap.veiko.debuggerforker.packet.Packet;
9 | import kaap.veiko.debuggerforker.packet.PacketVisitor;
10 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
11 |
12 | class PacketWriter {
13 |
14 | private final SocketChannel socketChannel;
15 | private final PacketByteBufferConverter packetByteBufferConverter = new PacketByteBufferConverter();
16 |
17 | PacketWriter(SocketChannel socketChannel) {
18 | this.socketChannel = socketChannel;
19 | }
20 |
21 | void write(Packet packet) throws IOException {
22 | ByteBuffer buffer = packet.visit(packetByteBufferConverter);
23 | while (buffer.hasRemaining()) {
24 | socketChannel.write(buffer);
25 | }
26 | }
27 |
28 | private class PacketByteBufferConverter implements PacketVisitor {
29 |
30 | private void writeHeader(Packet packet, ByteBuffer byteBuffer) {
31 | byteBuffer.putInt(packet.getLength());
32 | byteBuffer.putInt(packet.getId());
33 | byteBuffer.put((byte) packet.getFlags());
34 | }
35 |
36 | private void writeData(Packet packet, ByteBuffer byteBuffer) {
37 | if (packet.hasData()) {
38 | byteBuffer.put(packet.getData());
39 | }
40 | }
41 |
42 | @Override
43 | public ByteBuffer visit(ReplyPacket packet) {
44 | ByteBuffer byteBuffer = ByteBuffer.allocate(packet.getLength());
45 |
46 | writeHeader(packet, byteBuffer);
47 | byteBuffer.putShort(packet.getErrorCode());
48 |
49 | writeData(packet, byteBuffer);
50 |
51 | byteBuffer.flip();
52 | return byteBuffer;
53 | }
54 |
55 | @Override
56 | public ByteBuffer visit(CommandPacket packet) {
57 | ByteBuffer byteBuffer = ByteBuffer.allocate(packet.getLength());
58 | writeHeader(packet, byteBuffer);
59 |
60 | byteBuffer.put((byte) packet.getCommandSetId());
61 | byteBuffer.put((byte) packet.getCommandId());
62 |
63 | writeData(packet, byteBuffer);
64 |
65 | byteBuffer.flip();
66 | return byteBuffer;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/internal/VmPacketTransformer.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.internal;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 | import java.util.concurrent.ConcurrentMap;
5 | import java.util.concurrent.atomic.AtomicInteger;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import kaap.veiko.debuggerforker.packet.CommandPacket;
10 | import kaap.veiko.debuggerforker.packet.Packet;
11 | import kaap.veiko.debuggerforker.packet.PacketVisitor;
12 | import kaap.veiko.debuggerforker.packet.ReplyPacket;
13 |
14 | public class VmPacketTransformer implements PacketTransformer {
15 |
16 | private static final Logger log = LoggerFactory.getLogger(VmPacketTransformer.class);
17 |
18 | private final ConcurrentMap idMap = new ConcurrentHashMap<>();
19 | private final AtomicInteger idCounter = new AtomicInteger(0);
20 |
21 | private final OutputPacketVisitor outputPacketVisitor = new OutputPacketVisitor();
22 | private final InputPacketVisitor inputPacketVisitor = new InputPacketVisitor();
23 |
24 | @Override
25 | public Packet transformReadPacket(Packet packet) {
26 | return packet.visit(outputPacketVisitor);
27 | }
28 |
29 | @Override
30 | public Packet transformWritePacket(Packet packet) {
31 | return packet.visit(inputPacketVisitor);
32 | }
33 |
34 | @Override
35 | public int createNewId() {
36 | return idCounter.getAndIncrement();
37 | }
38 |
39 | private int getNewId(int originalId) {
40 | int newId = idCounter.getAndIncrement();
41 | idMap.put(newId, originalId);
42 | return newId;
43 | }
44 |
45 | private int getOriginalId(int newId) {
46 | return idMap.get(newId);
47 | }
48 |
49 | private class OutputPacketVisitor implements PacketVisitor {
50 | @Override
51 | public Packet visit(ReplyPacket packet) {
52 | // Changing this id is the task of DebuggerPacketTransformer
53 | return packet;
54 | }
55 |
56 | @Override
57 | public Packet visit(CommandPacket packet) {
58 | // Generate new id to allow creating artificial packets later without id collision
59 | int newId = getNewId(packet.getId());
60 | return new CommandPacket(
61 | newId,
62 | packet.getCommandSetId(),
63 | packet.getCommandId(),
64 | packet.getData(),
65 | packet.getSource()
66 | );
67 | }
68 | }
69 |
70 | private class InputPacketVisitor implements PacketVisitor {
71 | @Override
72 | public Packet visit(ReplyPacket packet) {
73 | log.error("Virtual Machine shouldn't receive replies");
74 | return packet;
75 | }
76 |
77 | @Override
78 | public Packet visit(CommandPacket packet) {
79 | // Changing this id is the task of DebuggerPacketTransformer
80 | return packet;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/packet/src/main/java/kaap/veiko/debuggerforker/packet/utils/ByteBufferUtil.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.packet.utils;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.nio.charset.StandardCharsets;
5 |
6 | public class ByteBufferUtil {
7 | public static Long getLong(ByteBuffer buffer, int size) {
8 | if (size > 8 || size < 0) {
9 | throw new UnsupportedOperationException("malformed input");
10 | }
11 | int offset = 8 - size;
12 | byte[] bytes = new byte[]{0, 0, 0, 0, 0, 0, 0, 0};
13 | buffer.get(bytes, offset, size);
14 | return ByteBuffer.wrap(bytes).getLong();
15 | }
16 |
17 | public static void putLong(ByteBuffer buffer, long value, int size) {
18 | ByteBuffer tmpBuffer = ByteBuffer.allocate(8);
19 | tmpBuffer.putLong(value);
20 | tmpBuffer.flip();
21 |
22 | byte[] bytes = new byte[size];
23 | for (int i = 0; i < (8 - size); i++) {
24 | tmpBuffer.get();
25 | }
26 | tmpBuffer.get(bytes, 0, size);
27 |
28 | buffer.put(bytes);
29 | }
30 |
31 | public static Integer getInt(ByteBuffer buffer, int size) {
32 | if (size > 4 || size < 0) {
33 | throw new UnsupportedOperationException("malformed input");
34 | }
35 | int offset = 4 - size;
36 | byte[] bytes = new byte[]{0, 0, 0, 0};
37 | buffer.get(bytes, offset, size);
38 | return ByteBuffer.wrap(bytes).getInt();
39 | }
40 |
41 | public static Short getShort(ByteBuffer buffer, int size) {
42 | if (size > 2 || size < 0) {
43 | throw new UnsupportedOperationException("malformed input");
44 | }
45 | int offset = 2 - size;
46 | byte[] bytes = new byte[]{0, 0};
47 | buffer.get(bytes, offset, size);
48 | return ByteBuffer.wrap(bytes).getShort();
49 | }
50 |
51 | public static String getString(ByteBuffer buffer) {
52 | int length = buffer.getInt();
53 | byte[] bytes = new byte[length];
54 | buffer.get(bytes, 0, length);
55 |
56 | return new String(bytes, StandardCharsets.UTF_8);
57 | }
58 |
59 | public static void putString(ByteBuffer buffer, String string) {
60 | byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
61 |
62 | buffer.putInt(bytes.length);
63 | buffer.put(bytes);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/server-logic/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jvm-debugger-forker
7 | kaap.veiko
8 | 0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | server-logic
13 |
14 |
15 |
16 |
17 | org.apache.maven.plugins
18 | maven-shade-plugin
19 | 3.1.0
20 |
21 |
22 | package
23 |
24 | shade
25 |
26 |
27 |
28 |
29 |
30 | org.apache.maven.plugins
31 | maven-jar-plugin
32 | 3.0.2
33 |
34 |
35 |
36 | kaap.veiko.debuggerforker.Main
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | kaap.veiko
47 | commands
48 | ${parent.version}
49 |
50 |
51 | kaap.veiko
52 | packet
53 | ${parent.version}
54 |
55 |
56 | kaap.veiko
57 | connections
58 | ${parent.version}
59 |
60 |
61 | kaap.veiko
62 | types
63 | ${parent.version}
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/server-logic/src/main/java/kaap/veiko/debuggerforker/DebuggerProxy.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import kaap.veiko.debuggerforker.commands.Command;
10 | import kaap.veiko.debuggerforker.handlers.CommandHandler;
11 |
12 | public class DebuggerProxy {
13 |
14 | private final static Logger log = LoggerFactory.getLogger(DebuggerProxy.class);
15 |
16 | private final CommandHandler commandHandler;
17 | public final DebugProxyServer proxyServer;
18 | private AtomicBoolean debuggerConnected = new AtomicBoolean(false);
19 | private final AtomicBoolean vmConnected = new AtomicBoolean(false);
20 |
21 | public DebuggerProxy(InetSocketAddress vmAddress, int debuggerPort) throws IOException {
22 | proxyServer = new DebugProxyServer(vmAddress, debuggerPort);
23 | commandHandler = new CommandHandler(proxyServer.getVmInformation(), proxyServer.getProxyCommandStream());
24 | }
25 |
26 | public void start() {
27 | proxyServer.addVirtualMachineConnectedListener(vmStream -> vmConnected.set(true));
28 | proxyServer.addDebuggerConnectedListener(debuggerStream -> debuggerConnected.set(true));
29 |
30 | proxyServer.start();
31 | waitUntilConnected();
32 |
33 | while (proxyServer.getProxyCommandStream().isOpen()) {
34 | Command command = proxyServer.getProxyCommandStream().read();
35 | if (command != null) {
36 | command.visit(commandHandler);
37 | }
38 | }
39 | }
40 |
41 | private void waitUntilConnected() {
42 | while (!vmConnected.get() || !debuggerConnected.get()) {
43 | try {
44 | Thread.sleep(10);
45 | }
46 | catch (InterruptedException e) {
47 | e.printStackTrace();
48 | }
49 | }
50 | }
51 |
52 | public void stop() {
53 | proxyServer.close();
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/server-logic/src/main/java/kaap/veiko/debuggerforker/Main.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.util.Arrays;
6 | import java.util.List;
7 | import java.util.Optional;
8 |
9 | public class Main {
10 |
11 | private static final String JVM_HOST_ARG = "jvm.host=";
12 | private static final String JVM_PORT_ARG = "jvm.port=";
13 | private static final String PROXY_PORT_ARG = "proxy.port=";
14 |
15 | public static void main(String[] args) throws IOException {
16 | List arguments = Arrays.asList(args);
17 |
18 | InetSocketAddress virtualMachineAddress = getJvmAddress(arguments);
19 | Integer proxyPort = getProxyPort(arguments);
20 |
21 | if (virtualMachineAddress == null || proxyPort == null) {
22 | return;
23 | }
24 |
25 | DebuggerProxy proxy = new DebuggerProxy(virtualMachineAddress, proxyPort);
26 | proxy.start();
27 | }
28 |
29 | private static InetSocketAddress getJvmAddress(List args) {
30 | String host = args.stream()
31 | .filter(s -> s.startsWith(JVM_HOST_ARG))
32 | .map(s -> s.substring(JVM_HOST_ARG.length()))
33 | .findFirst()
34 | .orElse("127.0.0.1");
35 |
36 | Optional port = args.stream()
37 | .filter(s -> s.startsWith(JVM_PORT_ARG))
38 | .map(s -> s.substring(JVM_PORT_ARG.length()))
39 | .findFirst();
40 |
41 | if (port.isPresent()) {
42 | try {
43 | int jvmPort = Integer.parseInt(port.get());
44 | return new InetSocketAddress(host, jvmPort);
45 | }
46 | catch (NumberFormatException e) {
47 | System.err.println("JVM debug port is not a valid number");
48 | return null;
49 | }
50 | }
51 | else {
52 | System.err.println("No JVM debug port specified. Please add " + JVM_PORT_ARG + " argument.");
53 | return null;
54 | }
55 | }
56 |
57 | private static Integer getProxyPort(List args) {
58 | Optional port = args.stream()
59 | .filter(s -> s.startsWith(PROXY_PORT_ARG))
60 | .map(s -> s.substring(PROXY_PORT_ARG.length()))
61 | .findFirst();
62 |
63 | if (port.isPresent()) {
64 | try {
65 | return Integer.parseInt(port.get());
66 | }
67 | catch (NumberFormatException e) {
68 | System.err.println("Proxy server port is not a valid number");
69 | return null;
70 | }
71 | }
72 | else {
73 | System.err.println("No proxy server port specified. Please add -D" + PROXY_PORT_ARG + " JVM argument.");
74 | return null;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/server-logic/src/main/java/kaap/veiko/debuggerforker/ProxyCommandStream.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.Selector;
5 | import java.util.Deque;
6 | import java.util.List;
7 |
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import kaap.veiko.debuggerforker.commands.Command;
12 | import kaap.veiko.debuggerforker.commands.CommandStream;
13 | import kaap.veiko.debuggerforker.managers.CommandStreamInputOutputManager;
14 | import kaap.veiko.debuggerforker.packet.PacketSource;
15 |
16 | public class ProxyCommandStream {
17 |
18 | private final Logger log = LoggerFactory.getLogger(ProxyCommandStream.class);
19 |
20 | private final CommandStreamInputOutputManager commandStreamManager;
21 | private final Thread managerThread;
22 |
23 | public static ProxyCommandStream create() throws IOException {
24 | return new ProxyCommandStream(Selector.open());
25 | }
26 |
27 | private ProxyCommandStream(Selector selector) {
28 | commandStreamManager = new CommandStreamInputOutputManager(selector);
29 | this.managerThread = new Thread(commandStreamManager);
30 | }
31 |
32 | void registerCommandStream(CommandStream commandStream) throws Exception {
33 | commandStreamManager.addCommandStream(commandStream);
34 | }
35 |
36 | public void markForClosingAfterAllPacketsWritten(PacketSource source) {
37 | commandStreamManager.markForClosing(source);
38 | }
39 |
40 | public Command read() {
41 | Command readCommand = commandStreamManager.getReadQueue().pollFirst();
42 | if (readCommand != null) {
43 | log.info("Command from readQueue: {}", readCommand);
44 | }
45 | return readCommand;
46 | }
47 |
48 | public void writeToVm(Command command) {
49 | PacketSource vmSource = commandStreamManager.getVmSource();
50 | if (vmSource != null) {
51 | write(vmSource, command);
52 | }
53 | }
54 |
55 | public void writeToAllDebuggers(Command command) {
56 | commandStreamManager.getAllDebuggers().forEach(s -> write(s, command));
57 | }
58 |
59 | public void write(PacketSource source, Command command) {
60 | Deque writeQueue = commandStreamManager.getWriteQueue(source);
61 | if (writeQueue != null) {
62 | log.info("Adding command '{}' to writeQueue for source {}", command, source);
63 | writeQueue.addLast(command);
64 | } else {
65 | log.warn("Trying to write to a packet source which isn't registered: {}", source);
66 | }
67 | }
68 |
69 | public PacketSource getVmSource() {
70 | return commandStreamManager.getVmSource();
71 | }
72 |
73 | public List getAllDebuggers() {
74 | return commandStreamManager.getAllDebuggers();
75 | }
76 |
77 | void start() {
78 | managerThread.start();
79 | }
80 |
81 | boolean isOpen() {
82 | return commandStreamManager.isOpen();
83 | }
84 |
85 | void close() {
86 | commandStreamManager.close();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/server-logic/src/main/java/kaap/veiko/debuggerforker/handlers/RequestIdentifier.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.handlers;
2 |
3 | import kaap.veiko.debuggerforker.types.jdwp.EventKind;
4 |
5 | final public class RequestIdentifier {
6 | private final EventKind eventKind;
7 | private final int requestId;
8 |
9 | public RequestIdentifier(EventKind eventKind, int requestId) {
10 | this.eventKind = eventKind;
11 | this.requestId = requestId;
12 | }
13 |
14 | public EventKind getEventKind() {
15 | return eventKind;
16 | }
17 |
18 | public int getRequestId() {
19 | return requestId;
20 | }
21 |
22 | @Override
23 | public boolean equals(Object o) {
24 | if (this == o) {
25 | return true;
26 | }
27 | if (o == null || getClass() != o.getClass()) {
28 | return false;
29 | }
30 |
31 | RequestIdentifier requestIdentifier = (RequestIdentifier) o;
32 |
33 | if (requestId != requestIdentifier.requestId) {
34 | return false;
35 | }
36 | return eventKind == requestIdentifier.eventKind;
37 | }
38 |
39 | @Override
40 | public int hashCode() {
41 | int result = eventKind != null ? eventKind.hashCode() : 0;
42 | result = 31 * result + requestId;
43 | return result;
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return "RequestIdentifier{" +
49 | "eventKind=" + eventKind +
50 | ", requestId=" + requestId +
51 | '}';
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/server-logic/src/main/java/kaap/veiko/debuggerforker/managers/ChannelInputOutputManager.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.managers;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.ClosedChannelException;
5 | import java.nio.channels.SelectionKey;
6 | import java.nio.channels.Selector;
7 | import java.util.concurrent.CountDownLatch;
8 | import java.util.concurrent.atomic.AtomicBoolean;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | abstract class ChannelInputOutputManager implements Runnable, AutoCloseable {
13 | private final Logger log = LoggerFactory.getLogger(ChannelInputOutputManager.class);
14 |
15 | private final Object selectLock = new Object();
16 | private final Object registerLock = new Object();
17 | private final Selector selector;
18 |
19 | private final CountDownLatch startLatch = new CountDownLatch(1);
20 |
21 | private final AtomicBoolean open = new AtomicBoolean(true);
22 |
23 | ChannelInputOutputManager(Selector selector) {
24 | this.selector = selector;
25 | }
26 |
27 | abstract void internalRegister(T object, Selector selector) throws ClosedChannelException;
28 |
29 | abstract void handleKey(SelectionKey key);
30 |
31 | void register(T object) throws Exception {
32 | if (!open.get()) {
33 | throw new IOException("Can't register object to closed runnable.");
34 | }
35 |
36 | try {
37 | synchronizedRegister(object);
38 | }
39 | catch (Exception registerException) {
40 | try {
41 | object.close();
42 | }
43 | catch (Exception closeException) {
44 | registerException.addSuppressed(closeException);
45 | throw registerException;
46 | }
47 | }
48 | }
49 |
50 | private void synchronizedRegister(T object) throws ClosedChannelException {
51 | synchronized (registerLock) {
52 | selector.wakeup();
53 | synchronized (selectLock) { // Wait until select has woken.
54 | internalRegister(object, selector);
55 | log.info("Registered new channel: {}", object);
56 | }
57 | }
58 | }
59 |
60 | @Override
61 | public void run() {
62 | try {
63 | while (isOpen() && !Thread.currentThread().isInterrupted()) {
64 | int selected = synchronizedSelect();
65 | if (selected == 0) {
66 | continue;
67 | }
68 | selector.selectedKeys().forEach(this::handleKey);
69 | selector.selectedKeys().clear();
70 | }
71 | }
72 | catch (Exception e) {
73 | close();
74 | log.error("Stopping {} due to exception.", this, e);
75 | }
76 | }
77 |
78 | private int synchronizedSelect() throws IOException {
79 | int selected;
80 | synchronized (selectLock) {
81 | selected = selector.select();
82 | }
83 | synchronized (registerLock) {
84 | } // Wait until new channel is registered
85 |
86 | return selected;
87 | }
88 |
89 | public boolean isOpen() {
90 | return open.get();
91 | }
92 |
93 | public void close() {
94 | open.set(false);
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/server-logic/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/types/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | jvm-debugger-forker
7 | kaap.veiko
8 | 0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | types
13 |
14 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/DataReader.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types;
2 |
3 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
4 |
5 | public interface DataReader {
6 | byte readByte();
7 |
8 | short readShort();
9 |
10 | int readInt();
11 |
12 | long readLong();
13 |
14 | long readLongOfSize(IdSizes.SizeType sizeType);
15 |
16 | boolean readBoolean();
17 |
18 | float readFloat();
19 |
20 | double readDouble();
21 |
22 | String readString();
23 | }
24 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/DataType.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types;
2 |
3 | public interface DataType {
4 | void write(DataWriter writer);
5 | }
6 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/DataWriter.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types;
2 |
3 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
4 |
5 | public interface DataWriter {
6 | void writeBoolean(boolean bool);
7 |
8 | void writeByte(byte b);
9 |
10 | void writeShort(short s);
11 |
12 | void writeInt(int i);
13 |
14 | void writeLong(long l);
15 |
16 | void writeFloat(float f);
17 |
18 | void writeDouble(double d);
19 |
20 | void writeLongOfSize(long l, IdSizes.SizeType sizeType);
21 |
22 | void writeString(String string);
23 |
24 | void writeType(DataType type);
25 | }
26 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/VMInformation.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types;
2 |
3 | import kaap.veiko.debuggerforker.types.jdwp.IdSizes;
4 |
5 | public class VMInformation {
6 | private IdSizes idSizes;
7 |
8 | public IdSizes getIdSizes() {
9 | return idSizes;
10 | }
11 |
12 | public void setIdSizes(IdSizes idSizes) {
13 | this.idSizes = idSizes;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ArrayId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ArrayId extends ObjectId {
6 | public static ArrayId read(DataReader reader) {
7 | return new ArrayId(reader);
8 | }
9 |
10 | ArrayId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ArrayId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ArrayTypeId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ArrayTypeId extends ReferenceTypeId {
6 | public static ArrayTypeId read(DataReader reader) {
7 | return new ArrayTypeId(reader);
8 | }
9 |
10 | ArrayTypeId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ArrayTypeId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ClassId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ClassId extends ReferenceTypeId {
6 | public static ClassId read(DataReader reader) {
7 | return new ClassId(reader);
8 | }
9 |
10 | ClassId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ClassId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ClassLoaderId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ClassLoaderId extends ObjectId {
6 | public static ClassLoaderId read(DataReader reader) {
7 | return new ClassLoaderId(reader);
8 | }
9 |
10 | ClassLoaderId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ClassLoaderId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ClassObjectId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ClassObjectId extends ObjectId {
6 | public static ClassObjectId read(DataReader reader) {
7 | return new ClassObjectId(reader);
8 | }
9 |
10 | ClassObjectId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ClassObjectId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/DataTypeBase.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import kaap.veiko.debuggerforker.types.DataReader;
7 | import kaap.veiko.debuggerforker.types.DataType;
8 | import kaap.veiko.debuggerforker.types.DataWriter;
9 |
10 | abstract class DataTypeBase implements DataType {
11 |
12 | private final static Logger log = LoggerFactory.getLogger(DataTypeBase.class);
13 | private final long value;
14 | private final IdSizes.SizeType sizeType;
15 |
16 | DataTypeBase(DataReader reader, IdSizes.SizeType sizeType) {
17 | this.sizeType = sizeType;
18 | this.value = reader.readLongOfSize(sizeType);
19 | }
20 |
21 | DataTypeBase(long value, IdSizes.SizeType sizeType) {
22 | this.value = value;
23 | this.sizeType = sizeType;
24 | }
25 |
26 | @Override
27 | public void write(DataWriter writer) {
28 | writer.writeLongOfSize(value, sizeType);
29 | }
30 |
31 | @Override
32 | public boolean equals(Object o) {
33 | if (this == o) {
34 | return true;
35 | }
36 | if (o == null || getClass() != o.getClass()) {
37 | return false;
38 | }
39 |
40 | DataTypeBase that = (DataTypeBase) o;
41 |
42 | return value == that.value;
43 | }
44 |
45 | @Override
46 | public int hashCode() {
47 | return (int) (value ^ (value >>> 32));
48 | }
49 |
50 | public long asLong() {
51 | return value;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return this.getClass().getSimpleName() + "{" +
57 | "value=" + value +
58 | '}';
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/EventKind.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import java.util.Arrays;
4 |
5 | import kaap.veiko.debuggerforker.types.DataReader;
6 | import kaap.veiko.debuggerforker.types.DataType;
7 | import kaap.veiko.debuggerforker.types.DataWriter;
8 |
9 | public enum EventKind implements DataType {
10 | SINGLE_STEP(1),
11 | BREAKPOINT(2),
12 | FRAME_POP(3),
13 | EXCEPTION(4),
14 | USER_DEFINED(5),
15 | THREAD_START(6),
16 | THREAD_DEATH(7),
17 | CLASS_PREPARE(8),
18 | CLASS_UNLOAD(9),
19 | CLASS_LOAD(10),
20 | FIELD_ACCESS(20),
21 | FIELD_MODIFICATION(21),
22 | EXCEPTION_CATCH(30),
23 | METHOD_ENTRY(40),
24 | METHOD_EXIT(41),
25 | METHOD_EXIT_WITH_RETURN_VALUE(42),
26 | MONITOR_CONTENDED_ENTER(43),
27 | MONITOR_CONTENDED_ENTERED(44),
28 | MONITOR_WAIT(45),
29 | MONITOR_WAITED(46),
30 | VM_START(90),
31 | VM_DEATH(99),
32 | VM_DISCONNECTED(100);
33 |
34 | public final byte id;
35 |
36 | EventKind(int id) {
37 | this.id = (byte) id;
38 | }
39 |
40 | public static EventKind read(DataReader reader) {
41 | return findByValue(reader.readByte());
42 | }
43 |
44 | private static EventKind findByValue(byte value) {
45 | return Arrays.stream(EventKind.values())
46 | .filter(eventKind -> eventKind.id == value)
47 | .findFirst().get();
48 | }
49 |
50 | public final byte getId() {
51 | return id;
52 | }
53 |
54 | @Override
55 | public void write(DataWriter writer) {
56 | writer.writeByte(id);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/FieldId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class FieldId extends DataTypeBase {
6 | public static FieldId read(DataReader reader) {
7 | return new FieldId(reader);
8 | }
9 |
10 | FieldId(DataReader reader) {
11 | super(reader, IdSizes.SizeType.FIELD_ID_SIZE);
12 | }
13 |
14 | public FieldId(long value) {
15 | super(value, IdSizes.SizeType.FIELD_ID_SIZE);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/FrameId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class FrameId extends DataTypeBase {
6 | public static FrameId read(DataReader reader) {
7 | return new FrameId(reader);
8 | }
9 |
10 | FrameId(DataReader reader) {
11 | super(reader, IdSizes.SizeType.FRAME_ID_SIZE);
12 | }
13 |
14 | public FrameId(long value) {
15 | super(value, IdSizes.SizeType.FRAME_ID_SIZE);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/InterfaceId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class InterfaceId extends ReferenceTypeId {
6 | public static InterfaceId read(DataReader reader) {
7 | return new InterfaceId(reader);
8 | }
9 |
10 | InterfaceId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public InterfaceId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/Location.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 | import kaap.veiko.debuggerforker.types.DataType;
5 | import kaap.veiko.debuggerforker.types.DataWriter;
6 |
7 | public class Location implements DataType {
8 | private final byte typeTag;
9 | private final ClassId classId;
10 | private final MethodId methodId;
11 | private final long index;
12 |
13 | public static Location read(DataReader reader) {
14 | return new Location(reader);
15 | }
16 |
17 | Location(DataReader reader) {
18 | typeTag = reader.readByte();
19 | classId = ClassId.read(reader);
20 | methodId = MethodId.read(reader);
21 | index = reader.readLong();
22 | }
23 |
24 | public Location(byte typeTag, ClassId classId, MethodId methodId, long index) {
25 | this.typeTag = typeTag;
26 | this.classId = classId;
27 | this.methodId = methodId;
28 | this.index = index;
29 | }
30 |
31 | public byte getTypeTag() {
32 | return typeTag;
33 | }
34 |
35 | public ClassId getClassId() {
36 | return classId;
37 | }
38 |
39 | public MethodId getMethodId() {
40 | return methodId;
41 | }
42 |
43 | public long getIndex() {
44 | return index;
45 | }
46 |
47 | @Override
48 | public void write(DataWriter writer) {
49 | writer.writeByte(typeTag);
50 | writer.writeType(classId);
51 | writer.writeType(methodId);
52 | writer.writeLong(index);
53 | }
54 |
55 | @Override
56 | public boolean equals(Object o) {
57 | if (this == o) {
58 | return true;
59 | }
60 | if (o == null || getClass() != o.getClass()) {
61 | return false;
62 | }
63 |
64 | Location location = (Location) o;
65 |
66 | if (typeTag != location.typeTag) {
67 | return false;
68 | }
69 | if (index != location.index) {
70 | return false;
71 | }
72 | if (classId != null ? !classId.equals(location.classId) : location.classId != null) {
73 | return false;
74 | }
75 | return methodId != null ? methodId.equals(location.methodId) : location.methodId == null;
76 | }
77 |
78 | @Override
79 | public int hashCode() {
80 | int result = (int) typeTag;
81 | result = 31 * result + (classId != null ? classId.hashCode() : 0);
82 | result = 31 * result + (methodId != null ? methodId.hashCode() : 0);
83 | result = 31 * result + (int) (index ^ (index >>> 32));
84 | return result;
85 | }
86 |
87 | @Override
88 | public String toString() {
89 | return "Location{" +
90 | "typeTag=" + typeTag +
91 | ", classId=" + classId +
92 | ", methodId=" + methodId +
93 | ", index=" + index +
94 | '}';
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/MethodId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class MethodId extends DataTypeBase {
6 | public static MethodId read(DataReader reader) {
7 | return new MethodId(reader);
8 | }
9 |
10 | MethodId(DataReader reader) {
11 | super(reader, IdSizes.SizeType.METHOD_ID_SIZE);
12 | }
13 |
14 | public MethodId(long value) {
15 | super(value, IdSizes.SizeType.METHOD_ID_SIZE);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ObjectId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ObjectId extends DataTypeBase {
6 | public static ObjectId read(DataReader reader) {
7 | return new ObjectId(reader);
8 | }
9 |
10 | ObjectId(DataReader reader) {
11 | super(reader, IdSizes.SizeType.OBJECT_ID_SIZE);
12 | }
13 |
14 | public ObjectId(long value) {
15 | super(value, IdSizes.SizeType.OBJECT_ID_SIZE);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ReferenceTypeId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ReferenceTypeId extends ObjectId {
6 | public static ReferenceTypeId read(DataReader reader) {
7 | return new ReferenceTypeId(reader);
8 | }
9 |
10 | ReferenceTypeId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ReferenceTypeId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/StringId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class StringId extends ObjectId {
6 | public static StringId read(DataReader reader) {
7 | return new StringId(reader);
8 | }
9 |
10 | StringId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public StringId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/TaggedObjectId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 | import kaap.veiko.debuggerforker.types.DataType;
5 | import kaap.veiko.debuggerforker.types.DataWriter;
6 |
7 | public class TaggedObjectId implements DataType {
8 |
9 | private final byte tag;
10 | private final ObjectId objectId;
11 |
12 | public static TaggedObjectId read(DataReader reader) {
13 | return new TaggedObjectId(reader);
14 | }
15 |
16 | TaggedObjectId(DataReader reader) {
17 | tag = reader.readByte();
18 | objectId = new ObjectId(reader);
19 | }
20 |
21 | public TaggedObjectId(byte tag, ObjectId objectId) {
22 | this.tag = tag;
23 | this.objectId = objectId;
24 | }
25 |
26 | public byte getTag() {
27 | return tag;
28 | }
29 |
30 | public ObjectId getObjectId() {
31 | return objectId;
32 | }
33 |
34 | public long asLong() {
35 | return getObjectId().asLong();
36 | }
37 |
38 | @Override
39 | public void write(DataWriter writer) {
40 | writer.writeByte(tag);
41 | writer.writeType(objectId);
42 | }
43 |
44 | @Override
45 | public boolean equals(Object o) {
46 | if (this == o) {
47 | return true;
48 | }
49 | if (o == null || getClass() != o.getClass()) {
50 | return false;
51 | }
52 |
53 | TaggedObjectId that = (TaggedObjectId) o;
54 |
55 | if (tag != that.tag) {
56 | return false;
57 | }
58 | return objectId != null ? objectId.equals(that.objectId) : that.objectId == null;
59 | }
60 |
61 | @Override
62 | public int hashCode() {
63 | int result = (int) tag;
64 | result = 31 * result + (objectId != null ? objectId.hashCode() : 0);
65 | return result;
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | return "TaggedObjectId{" +
71 | "tag=" + tag +
72 | ", objectId=" + asLong() +
73 | '}';
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ThreadGroupId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ThreadGroupId extends ObjectId {
6 | public static ThreadGroupId read(DataReader reader) {
7 | return new ThreadGroupId(reader);
8 | }
9 |
10 | ThreadGroupId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ThreadGroupId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/ThreadId.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class ThreadId extends ObjectId {
6 | public static ThreadId read(DataReader reader) {
7 | return new ThreadId(reader);
8 | }
9 |
10 | ThreadId(DataReader reader) {
11 | super(reader);
12 | }
13 |
14 | public ThreadId(long value) {
15 | super(value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/Type.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import java.util.Arrays;
4 | import java.util.function.BiConsumer;
5 | import java.util.function.Function;
6 |
7 | import kaap.veiko.debuggerforker.types.DataReader;
8 | import kaap.veiko.debuggerforker.types.DataWriter;
9 |
10 | public enum Type {
11 | ARRAY(91, ObjectId::read, DataWriter::writeType),
12 | BYTE(66, DataReader::readByte, DataWriter::writeByte),
13 | CHAR(67, DataReader::readShort, DataWriter::writeShort),
14 | OBJECT(76, ObjectId::read, DataWriter::writeType),
15 | FLOAT(70, DataReader::readFloat, DataWriter::writeFloat),
16 | DOUBLE(68, DataReader::readDouble, DataWriter::writeDouble),
17 | INT(73, DataReader::readInt, DataWriter::writeInt),
18 | LONG(74, DataReader::readLong, DataWriter::writeLong),
19 | SHORT(83, DataReader::readShort, DataWriter::writeShort),
20 | VOID(86, reader -> null, (writer, o) -> {}),
21 | BOOLEAN(90, DataReader::readBoolean, DataWriter::writeBoolean),
22 | STRING(115, ObjectId::read, DataWriter::writeType),
23 | THREAD(116, ObjectId::read, DataWriter::writeType),
24 | THREAD_GROUP(103, ObjectId::read, DataWriter::writeType),
25 | CLASS_LOADER(108, ObjectId::read, DataWriter::writeType),
26 | CLASS_OBJECT(99, ObjectId::read, DataWriter::writeType);
27 |
28 | private final byte id;
29 | private final Function readFunction;
30 | private final BiConsumer writeFunction;
31 |
32 | Type(int value, Function readFunction, BiConsumer writeConsumer) {
33 | this.id = (byte) value;
34 | this.readFunction = (Function) readFunction;
35 | this.writeFunction = (BiConsumer) writeConsumer;
36 | }
37 |
38 | public static Type findByValue(byte value) {
39 | return Arrays.stream(Type.values())
40 | .filter(type -> type.id == value)
41 | .findFirst().get();
42 | }
43 |
44 | public Object read(DataReader reader) {
45 | return readFunction.apply(reader);
46 | }
47 |
48 | public void write(DataWriter writer, Object value) {
49 | writeFunction.accept(writer, value);
50 | }
51 |
52 | public byte getId() {
53 | return id;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/UntaggedValue.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 |
5 | public class UntaggedValue extends Value {
6 | public static UntaggedValue read(DataReader reader, byte typeTag) {
7 | return new UntaggedValue(reader, typeTag);
8 | }
9 |
10 | UntaggedValue(DataReader reader, byte typeTag) {
11 | super(reader, typeTag);
12 | }
13 |
14 | public UntaggedValue(Type type, Object value) {
15 | super(type, value);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/types/src/main/java/kaap/veiko/debuggerforker/types/jdwp/Value.java:
--------------------------------------------------------------------------------
1 | package kaap.veiko.debuggerforker.types.jdwp;
2 |
3 | import kaap.veiko.debuggerforker.types.DataReader;
4 | import kaap.veiko.debuggerforker.types.DataType;
5 | import kaap.veiko.debuggerforker.types.DataWriter;
6 |
7 | public class Value implements DataType {
8 | private final Type type;
9 | private final Object value;
10 |
11 | public static Value read(DataReader reader) {
12 | return new Value(reader);
13 | }
14 |
15 | private Value(DataReader reader) {
16 | this(reader, reader.readByte());
17 | }
18 |
19 | protected Value(DataReader reader, byte typeTag) {
20 | this.type = Type.findByValue(typeTag);
21 | value = type.read(reader);
22 | }
23 |
24 | public Value(Type type, Object value) {
25 | this.type = type;
26 | this.value = value;
27 | }
28 |
29 | public Type getType() {
30 | return type;
31 | }
32 |
33 | public Object getValue() {
34 | return value;
35 | }
36 |
37 | @Override
38 | public void write(DataWriter writer) {
39 | writer.writeByte(type.getId());
40 | type.write(writer, value);
41 | }
42 |
43 | @Override
44 | public boolean equals(Object o) {
45 | if (this == o) {
46 | return true;
47 | }
48 | if (o == null || getClass() != o.getClass()) {
49 | return false;
50 | }
51 |
52 | Value value1 = (Value) o;
53 |
54 | if (type != value1.type) {
55 | return false;
56 | }
57 | return value != null ? value.equals(value1.value) : value1.value == null;
58 | }
59 |
60 | @Override
61 | public int hashCode() {
62 | int result = type != null ? type.hashCode() : 0;
63 | result = 31 * result + (value != null ? value.hashCode() : 0);
64 | return result;
65 | }
66 |
67 | @Override
68 | public String toString() {
69 | return "Value{" +
70 | "type=" + type +
71 | ", value=" + value +
72 | '}';
73 | }
74 | }
75 |
--------------------------------------------------------------------------------