From 00ada6a6c171f5bdab9c4f34e0527f7859373366 Mon Sep 17 00:00:00 2001 From: Stephanie Gawroriski Date: Fri, 26 Jan 2024 10:30:23 +0000 Subject: [PATCH] Add JDWPValue to store read non-host values. --- .../main/java/cc/squirreljme/jdwp/JDWPPacket.java | 107 +++++++++++++++++++++ .../main/java/cc/squirreljme/jdwp/JDWPValue.java | 55 +++++++++++ .../java/cc/squirreljme/jdwp/JDWPValueTag.java | 26 +++++ .../java/cc/squirreljme/debugger/InfoFrame.java | 9 +- 4 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValue.java diff --git a/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPPacket.java b/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPPacket.java index 939301530f..5ef7bb2ac0 100644 --- a/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPPacket.java +++ b/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPPacket.java @@ -587,6 +587,27 @@ public final class JDWPPacket } /** + * Reads a short value. + * + * @return The read value. + * @throws JDWPException If the packet could not be read. + * @since 2024/01/26 + */ + public short readShort() + throws JDWPException + { + synchronized (this) + { + // Ensure this is open + this.__checkOpen(); + + // Read in each byte + return (short)(((this.readByte() & 0xFF) << 8) | + (this.readByte() & 0xFF)); + } + } + + /** * Reads the specified string. * * @return The read string. @@ -623,6 +644,92 @@ public final class JDWPPacket } /** + * Reads a single value. + * + * @return The resultant value. + * @throws JDWPException On read errors. + * @since 2024/01/26 + */ + public JDWPValue readValue() + throws JDWPException + { + synchronized (this) + { + // Ensure this is open + this.__checkOpen(); + + // Read tag + byte rawTag = this.readByte(); + JDWPValueTag tag = JDWPValueTag.fromTag(rawTag); + if (tag == null) + throw new JDWPException("ITAG " + rawTag); + + // Read based on tag value + Object value; + switch (tag) + { + // Void, which is nothing + case VOID: + value = null; + break; + + // Objects + case ARRAY: + case OBJECT: + case STRING: + case CLASS_OBJECT: + case CLASS_LOADER: + case THREAD_GROUP: + value = this.readId(JDWPIdKind.OBJECT_ID); + break; + + case THREAD: + value = this.readId(JDWPIdKind.THREAD_ID); + break; + + case BOOLEAN: + value = (this.readByte() != 0); + break; + + case BYTE: + value = this.readByte(); + break; + + case SHORT: + value = this.readShort(); + break; + + case CHARACTER: + value = (char)this.readShort(); + break; + + case INTEGER: + value = this.readInt(); + break; + + case LONG: + value = this.readLong(); + break; + + case FLOAT: + value = Float.intBitsToFloat(this.readInt()); + break; + + case DOUBLE: + value = Double.longBitsToDouble(this.readLong()); + break; + + // Unknown value + default: + throw new JDWPException("ITAG " + rawTag); + } + + // Return the resultant value + return new JDWPValue(tag, value); + } + } + + /** * Reads a variable width value from the packet * * @param __width The width of the value. diff --git a/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValue.java b/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValue.java new file mode 100644 index 0000000000..d26f7064a4 --- /dev/null +++ b/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValue.java @@ -0,0 +1,55 @@ +// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*- +// --------------------------------------------------------------------------- +// Multi-Phasic Applications: SquirrelJME +// Copyright (C) Stephanie Gawroriski +// --------------------------------------------------------------------------- +// SquirrelJME is under the Mozilla Public License Version 2.0. +// See license.mkd for licensing and copyright information. +// --------------------------------------------------------------------------- + +package cc.squirreljme.jdwp; + +import cc.squirreljme.runtime.cldc.debug.Debugging; + +/** + * Not Described. + * + * @since 2024/01/26 + */ +public class JDWPValue +{ + /** The tag type. */ + public final JDWPValueTag tag; + + /** The value type. */ + public final Object value; + + /** + * Initializes the JDWP value. + * + * @param __tag The tag type. + * @param __value The value used. + * @throws NullPointerException On null arguments. + * @since 2024/01/26 + */ + public JDWPValue(JDWPValueTag __tag, Object __value) + throws NullPointerException + { + if (__tag == null) + throw new NullPointerException("NARG"); + + this.tag = __tag; + this.value = __value; + } + + /** + * {@inheritDoc} + * @since 2024/01/26 + */ + @Override + public String toString() + { + return String.format("%s %s", + this.tag, this.value); + } +} diff --git a/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValueTag.java b/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValueTag.java index c2bc2f0370..5582021244 100644 --- a/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValueTag.java +++ b/modules/debug-jdwp/src/main/java/cc/squirreljme/jdwp/JDWPValueTag.java @@ -98,6 +98,32 @@ public enum JDWPValueTag } /** + * Determines the value tag from the given tag. + * + * @param __tag The tag to parse. + * @return The value tag or {@code null} if not valid. + * @since 2021/04/11 + */ + public static JDWPValueTag fromTag(int __tag) + { + switch (__tag) + { + case '[': return JDWPValueTag.ARRAY; + case 'Z': return JDWPValueTag.BOOLEAN; + case 'B': return JDWPValueTag.BYTE; + case 'S': return JDWPValueTag.SHORT; + case 'C': return JDWPValueTag.CHARACTER; + case 'I': return JDWPValueTag.INTEGER; + case 'F': return JDWPValueTag.FLOAT; + case 'J': return JDWPValueTag.LONG; + case 'D': return JDWPValueTag.DOUBLE; + case 'L': return JDWPValueTag.OBJECT; + } + + return null; + } + + /** * Determines the value tag from the given signature. * * @param __signature The signature to read from. diff --git a/tools/squirreljme-debugger/src/main/java/cc/squirreljme/debugger/InfoFrame.java b/tools/squirreljme-debugger/src/main/java/cc/squirreljme/debugger/InfoFrame.java index 27a90e7b78..2f216b7221 100644 --- a/tools/squirreljme-debugger/src/main/java/cc/squirreljme/debugger/InfoFrame.java +++ b/tools/squirreljme-debugger/src/main/java/cc/squirreljme/debugger/InfoFrame.java @@ -14,6 +14,7 @@ import cc.squirreljme.jdwp.JDWPCommandSetStackFrame; import cc.squirreljme.jdwp.JDWPId; import cc.squirreljme.jdwp.JDWPIdKind; import cc.squirreljme.jdwp.JDWPPacket; +import cc.squirreljme.jdwp.JDWPValue; import cc.squirreljme.jdwp.JDWPValueTag; import java.util.ArrayList; import java.util.List; @@ -141,7 +142,7 @@ public class InfoFrame // directly, like it does not tell us the actual type that is there, so // we have to do some major probing to try to get that information... List result = new ArrayList<>(); - Object[] object = new Object[1]; + JDWPValue[] object = new JDWPValue[1]; for (int i = 0; i < 255; i++) try { @@ -171,7 +172,7 @@ public class InfoFrame * @since 2024/01/26 */ private Object __variableAttempt(DebuggerState __state, JDWPId __threadId, - JDWPId __frameId, int __varIndex, Object[] __object) + JDWPId __frameId, int __varIndex, JDWPValue[] __object) throws NoSuchElementException, NullPointerException { if (__state == null || __threadId == null || __frameId == null || @@ -216,7 +217,7 @@ public class InfoFrame */ private Object __variableAttempt(DebuggerState __state, JDWPId __threadId, JDWPId __frameId, int __varIndex, JDWPValueTag __tag, - Object[] __object) + JDWPValue[] __object) throws NoSuchElementException, NullPointerException { if (__state == null || __threadId == null || __frameId == null || @@ -241,7 +242,7 @@ public class InfoFrame (__ignored, __reply) -> { // The number of read values int numValues = __reply.readInt(); - Object value = __reply.readByte(); + JDWPValue value = __reply.readValue(); // Set value synchronized (__object) -- 2.11.4.GIT