aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-jdwp.c
diff options
context:
space:
mode:
authorEugene Adell <eugene.adell@gmail.com>2020-03-30 22:03:27 +0200
committerAnders Broman <a.broman58@gmail.com>2020-04-22 07:23:37 +0000
commit3a42f536ed7dff6bf04cbb2b6fbf9c69f4267f59 (patch)
tree536e921ec0c7baa016ce7b0d169522ba05edd271 /epan/dissectors/packet-jdwp.c
parent9132feb4a4da8453b490f863caaeb260bc31cb27 (diff)
JDWP dissector for TCP transport
Bug: 16479 Change-Id: I2618bb4b664c1dd7b4663c368b6ca99ec0533dd5 Reviewed-on: https://code.wireshark.org/review/36636 Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com> Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/dissectors/packet-jdwp.c')
-rw-r--r--epan/dissectors/packet-jdwp.c730
1 files changed, 730 insertions, 0 deletions
diff --git a/epan/dissectors/packet-jdwp.c b/epan/dissectors/packet-jdwp.c
new file mode 100644
index 0000000000..85f8d2bb92
--- /dev/null
+++ b/epan/dissectors/packet-jdwp.c
@@ -0,0 +1,730 @@
+/* packet-jdwp.c
+ * Routines for JDWP (Java Debug Wire Protocol) dissection
+ * Copyright 2020, Eugene Adell <eugene.adell@gmail.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+#include <epan/expert.h>
+#include <epan/to_str.h>
+#include <epan/conversation.h>
+#include <epan/wmem/wmem.h>
+
+#include "packet-tcp.h"
+
+void proto_register_jdwp(void);
+void proto_reg_handoff_jdwp(void);
+
+/* IMPORTANT IMPLEMENTATION NOTES
+ *
+ * You need to be looking at:
+ *
+ * https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/jdwp-spec.html
+ *
+ *
+ */
+
+#define JDWP_PORT 9009 /* Not IANA registered */
+#define FRAME_HEADER_LEN 11
+#define JDWP_MIN_LENGTH 11
+#define JDWP_HANDSHAKE_LENGTH 14
+#define JDWP_HANDSHAKE_MSG "JDWP-Handshake"
+
+#define PACKET_TYPE_COMMAND 0
+#define PACKET_TYPE_REPLY 128
+
+#define COMMAND_SET_VIRTUALMACHINE 1
+#define COMMAND_SET_REFERENCETYPE 2
+#define COMMAND_SET_CLASSTYPE 3
+#define COMMAND_SET_ARRAYTYPE 4
+#define COMMAND_SET_INTERFACETYPE 5
+#define COMMAND_SET_METHOD 6
+#define COMMAND_SET_FIELD 8
+#define COMMAND_SET_OBJECTREFERENCE 9
+#define COMMAND_SET_STRINGREFERENCE 10
+#define COMMAND_SET_THREADREFERENCE 11
+#define COMMAND_SET_THREADGROUPREFERENCE 12
+#define COMMAND_SET_ARRAYREFERENCE 13
+#define COMMAND_SET_CLASSLOADERREFERENCE 14
+#define COMMAND_SET_EVENTREQUEST 15
+#define COMMAND_SET_STACKFRAME 16
+#define COMMAND_SET_CLASSOBJECTREFERENCE 17
+#define COMMAND_SET_EVENT 64
+
+static int proto_jdwp = -1;
+
+static int hf_jdwp_type = -1;
+static int hf_jdwp_length = -1;
+static int hf_jdwp_id = -1;
+static int hf_jdwp_flags = -1;
+static int hf_jdwp_commandset = -1;
+static int hf_jdwp_commandset_virtualmachine = -1;
+static int hf_jdwp_commandset_referencetype = -1;
+static int hf_jdwp_commandset_classtype = -1;
+static int hf_jdwp_commandset_arraytype = -1;
+static int hf_jdwp_commandset_interfacetype = -1;
+static int hf_jdwp_commandset_method = -1;
+static int hf_jdwp_commandset_field = -1;
+static int hf_jdwp_commandset_objectreference = -1;
+static int hf_jdwp_commandset_stringreference = -1;
+static int hf_jdwp_commandset_threadreference = -1;
+static int hf_jdwp_commandset_threadgroupreference = -1;
+static int hf_jdwp_commandset_arrayreference = -1;
+static int hf_jdwp_commandset_classloaderreference = -1;
+static int hf_jdwp_commandset_eventrequest = -1;
+static int hf_jdwp_commandset_stackframe = -1;
+static int hf_jdwp_commandset_classobjectreference = -1;
+static int hf_jdwp_commandset_event = -1;
+static int hf_jdwp_errorcode = -1;
+static int hf_jdwp_data = -1;
+
+static gint ett_jdwp = -1;
+
+static expert_field ei_jdwp_hlen_invalid = EI_INIT;
+static expert_field ei_jdwp_flags_invalid = EI_INIT;
+
+// contains the command set names
+static const value_string commandsetnames[] = {
+ {1, "VirtualMachine"},
+ {2, "ReferenceType"},
+ {3, "ClassType"},
+ {4, "ArrayType"},
+ {5, "InterfaceType"},
+ {6, "Method"},
+ {8, "Field"},
+ {9, "ObjectReference"},
+ {10, "StringReference"},
+ {11, "ThreadReference"},
+ {12, "ThreadGroupReference"},
+ {13, "ArrayReference"},
+ {14, "ClassLoaderReference"},
+ {15, "EventRequest"},
+ {16, "StackFrame"},
+ {17, "ClassObjectReference"},
+ {64, "Event"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Virtual Machine
+static const value_string commandset_virtualmachine[] = {
+ {1, "Version"},
+ {2, "ClassesBySignature"},
+ {3, "AllClasses"},
+ {4, "AllThreads"},
+ {5, "TopLevelThreadGroups"},
+ {6, "Dispose"},
+ {7, "IDSizes"},
+ {8, "Suspend"},
+ {9, "Resume"},
+ {10, "Exit"},
+ {11, "CreateString"},
+ {12, "Capabilities"},
+ {13, "ClassPaths"},
+ {14, "DisposeObjects"},
+ {15, "HoldEvents"},
+ {16, "ReleaseEvents"},
+ {17, "CapabilitiesNew"},
+ {18, "RedefineClasses"},
+ {19, "SetDefaultStratum"},
+ {20, "AllClassesWithGeneric"},
+ {21, "InstanceCounts"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Reference
+static const value_string commandset_referencetype[] = {
+ {1, "Signature"},
+ {2, "ClassLoader"},
+ {3, "Modifiers"},
+ {4, "Fields"},
+ {5, "Methods"},
+ {6, "GetValues"},
+ {7, "SourceFile"},
+ {8, "NestedTypes"},
+ {9, "Status"},
+ {10, "Interfaces"},
+ {11, "ClassObject"},
+ {12, "SourceDebugExtension"},
+ {13, "SignatureWithGeneric"},
+ {14, "FieldsWithGeneric"},
+ {15, "MethodsWithGeneric"},
+ {16, "Instances"},
+ {17, "ClassFileVersion"},
+ {18, "ConstantPool"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Class
+static const value_string commandset_classtype[] = {
+ {1, "Superclass"},
+ {2, "SetValues"},
+ {3, "InvokeMethod"},
+ {4, "NewInstance"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Array
+static const value_string commandset_arraytype[] = {
+ {1, "NewInstance"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Interface
+static const value_string commandset_interfacetype[] = {
+ {1, "InvokeMethod"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Method
+static const value_string commandset_method[] = {
+ {1, "LineTable"},
+ {2, "VariableTable"},
+ {3, "Bytecodes"},
+ {4, "IsObsolete"},
+ {5, "VariableTableWithGeneric"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Field
+static const value_string commandset_field[] = {
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Object Reference
+static const value_string commandset_objectreference[] = {
+ {1, "ReferenceType"},
+ {2, "GetValues"},
+ {3, "SetValues"},
+ {5, "MonitorInfo"},
+ {6, "InvokeMethod"},
+ {7, "DisableCollection"},
+ {8, "EnableCollection"},
+ {9, "IsCollected"},
+ {10, "ReferringObjects"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type String Reference
+static const value_string commandset_stringreference[] = {
+ {1, "Value"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Thread Reference
+static const value_string commandset_threadreference[] = {
+ {1, "Name"},
+ {2, "Suspend"},
+ {3, "Resume"},
+ {4, "Status"},
+ {5, "ThreadGroup"},
+ {6, "Frames"},
+ {7, "FrameCount"},
+ {8, "OwnedMonitors"},
+ {9, "CurrentContentedMonitor"},
+ {10, "Stop"},
+ {11, "Interrupt"},
+ {12, "SuspendCount"},
+ {13, "OwnedMonitorsStackDepthInfo"},
+ {14, "ForceEearlyReturn"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type ThreadGroup Reference
+static const value_string commandset_threadgroupreference[] = {
+ {1, "Name"},
+ {2, "Parent"},
+ {3, "Children"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Array Reference
+static const value_string commandset_arrayreference[] = {
+ {1, "Length"},
+ {2, "GetValues"},
+ {3, "SetValues"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type ClassLoader Reference
+static const value_string commandset_classloaderreference[] = {
+ {1, "VisibleClasses"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type EventRequest
+static const value_string commandset_eventrequest[] = {
+ {1, "Set"},
+ {2, "Clear"},
+ {3, "ClearAllBreakpoints"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type StackFrame
+static const value_string commandset_stackframe[] = {
+ {1, "GetValues"},
+ {2, "SetValues"},
+ {3, "ThisObject"},
+ {4, "PopFrames"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type ClassObject Reference
+static const value_string commandset_classobjectreference[] = {
+ {1, "ReflectedType"},
+ {0, NULL}
+};
+
+// contains the commands for the command set of type Event
+static const value_string commandset_event[] = {
+ {100, "Composite"},
+ {0, NULL}
+};
+
+/* translates the error code to human readable value
+ * value 0 ("NONE") means SUCCESS, all other values mean FAILURE
+ */
+static const value_string error_codes[] = {
+ {0, "NONE"},
+ {10, "INVALID_THREAD"},
+ {11, "INVALID_THREAD_GROUP"},
+ {12, "INVALID_PRIORITY"},
+ {13, "THREAD_NOT_SUSPENDED"},
+ {14, "THREAD_SUSPENDED"},
+ {20, "INVALID_OBJECT"},
+ {21, "INVALID_CLASS"},
+ {22, "CLASS_NOT_PREPARED"},
+ {23, "INVALID_METHODID"},
+ {24, "INVALID_LOCATION"},
+ {25, "INVALID_FIELDID"},
+ {30, "INVALID_FRAMEID"},
+ {31, "NO_MORE_FRAMES"},
+ {32, "OPAQUE_FRAME"},
+ {33, "NOT_CURRENT_FRAME"},
+ {34, "TYPE_MISMATCH"},
+ {35, "INVALID_SLOT"},
+ {40, "DUPLICATE"},
+ {41, "NOT_FOUND"},
+ {50, "INVALID_MONITOR"},
+ {51, "NOT_MONITOR_OWNER"},
+ {52, "INTERRUPT"},
+ {60, "INVALID_CLASS_FORMAT"},
+ {61, "CIRCULAR_CLASS_DEFINITION"},
+ {62, "FAILS_VERIFICATION"},
+ {63, "ADD_METHOD_NOT_IMPLEMENTED"},
+ {64, "SCHEMA_CHANGE_NOT_IMPLEMENTED"},
+ {65, "INVALID_TYPESTATE"},
+ {66, "HIERARCHY_CHANGE_NOT_IMPLEMENTED"},
+ {67, "DELETE_METHOD_NOT_IMPLEMENTED"},
+ {68, "UNSUPPORTED_VERSION"},
+ {69, "NAMES_DONT_MATCH"},
+ {70, "CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED"},
+ {71, "METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED"},
+ {99, "NOT_IMPLEMENTED"},
+ {100, "NULL_POINTER"},
+ {101, "ABSENT_INFORMATION"},
+ {102, "INVALID_EVENT_TYPE"},
+ {103, "ILLEGAL_ARGUMENT"},
+ {110, "OUT_OF_MEMORY"},
+ {111, "ACCESS_DENIED"},
+ {112, "VM_DEAD"},
+ {113, "INTERNAL"},
+ {115, "UNATTACHED_THREAD"},
+ {500, "INVALID_TAG"},
+ {502, "ALREADY_INVOKING"},
+ {503, "INVALID_INDEX"},
+ {504, "INVALID_LENGTH"},
+ {506, "INVALID_STRING"},
+ {507, "INVALID_CLASS_LOADER"},
+ {508, "INVALID_ARRAY"},
+ {509, "TRANSPORT_LOAD"},
+ {510, "TRANSPORT_INIT"},
+ {511, "NATIVE_METHOD"},
+ {512, "INVALID_COUNT"},
+ {0, NULL}
+};
+
+/* determine PDU length of protocol JDWP */
+static guint
+get_jdwp_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
+{
+ /* Handshake messages don't contain the length field and
+ * they all are strictly identical in length and content
+ */
+ if (tvb_reported_length(tvb) == JDWP_HANDSHAKE_LENGTH) {
+ if (tvb_strneql(tvb, offset, JDWP_HANDSHAKE_MSG, JDWP_HANDSHAKE_LENGTH) == 0) {
+ return JDWP_HANDSHAKE_LENGTH;
+ }
+ }
+
+ /* All other packets are either a Command or a Reply, of different lengths
+ * and this length is indicated on the 4 first bytes
+ */
+ return (guint)tvb_get_ntohl(tvb, offset);
+}
+
+static int
+dissect_jdwp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ int offset = 0;
+
+ /* packet type can take 3 values (handshake, command, reply) */
+ gint packet_type;
+
+ /* length */
+ gint32 hlen = 0;
+
+ /* flag can take 2 values (0, 128) */
+ guint32 flags;
+
+ /* fields that need to be remembered */
+ guint32 mem_commandset = -1;
+ guint32 mem_errorcode = -1;
+
+ /* Check that there's enough data */
+ if (tvb_reported_length(tvb) < JDWP_MIN_LENGTH)
+ return 0;
+
+ /* Set the Protocol Column */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "JDWP");
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ proto_item *ti, *hlen_item, *flags_item;
+ proto_tree *jdwp_tree;
+
+ /* Clear out stuff in the info column */
+ col_clear(pinfo->cinfo,COL_INFO);
+
+ ti = proto_tree_add_item(tree, proto_jdwp, tvb, 0, -1, ENC_NA);
+ jdwp_tree = proto_item_add_subtree(ti, ett_jdwp);
+
+ /* The two first packets are Handshake packets and
+ * their content is always "JDWP-Handshake"
+ * All other packets are either a Command or a Reply
+ */
+ packet_type = 1;
+ if (tvb_reported_length(tvb) == JDWP_HANDSHAKE_LENGTH) {
+ if (tvb_strneql(tvb, offset, JDWP_HANDSHAKE_MSG, JDWP_HANDSHAKE_LENGTH) == 0) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "JDWP Handshake");
+ packet_type = 0;
+ }
+ }
+
+ if (packet_type == 0) {
+ proto_tree_add_item(jdwp_tree, hf_jdwp_type, tvb, offset, 14, ENC_ASCII|ENC_NA);
+ return tvb_captured_length(tvb);
+ }
+
+ /* LENGTH
+ */
+ hlen_item = proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_length, tvb, offset, 4, ENC_BIG_ENDIAN, &hlen);
+ offset += 4;
+
+ /* ID
+ */
+ proto_tree_add_item(jdwp_tree, hf_jdwp_id, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ /* FLAGS
+ */
+ flags_item = proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_flags, tvb, offset, 1, ENC_BIG_ENDIAN, &flags);
+ offset += 1;
+
+ /* COMMAND
+ */
+ switch (flags) {
+ case PACKET_TYPE_COMMAND:
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Command");
+ proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_commandset, tvb, offset, 1, ENC_BIG_ENDIAN, &mem_commandset);
+ offset += 1;
+
+ switch (mem_commandset) {
+
+ case COMMAND_SET_VIRTUALMACHINE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_virtualmachine, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_REFERENCETYPE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_referencetype, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_CLASSTYPE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classtype, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_ARRAYTYPE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_arraytype, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_INTERFACETYPE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_interfacetype, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_METHOD:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_method, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_FIELD:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_field, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_OBJECTREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_objectreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_STRINGREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_stringreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_THREADREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_threadreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_THREADGROUPREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_threadgroupreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_ARRAYREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_arrayreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_CLASSLOADERREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classloaderreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_EVENTREQUEST:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_eventrequest, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_STACKFRAME:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_stackframe, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_CLASSOBJECTREFERENCE:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_classobjectreference, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ case COMMAND_SET_EVENT:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_event, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ default:
+ proto_tree_add_item(jdwp_tree, hf_jdwp_commandset_virtualmachine, tvb, offset, 1, ENC_BIG_ENDIAN);
+ offset += 1;
+ break;
+
+ }
+
+ /* command comes with data when the minimal length is 12 */
+ if (hlen > 11) {
+ proto_tree_add_item(jdwp_tree, hf_jdwp_data, tvb, offset, hlen - 11, ENC_NA);
+ } else if (hlen < 11) {
+ expert_add_info(pinfo, hlen_item, &ei_jdwp_hlen_invalid);
+ }
+
+ break;
+
+ case PACKET_TYPE_REPLY:
+ proto_tree_add_item_ret_uint(jdwp_tree, hf_jdwp_errorcode, tvb, offset, 2, ENC_BIG_ENDIAN, &mem_errorcode);
+ offset += 2;
+
+ if(mem_errorcode == 0) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Reply (Success)");
+ } else {
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Reply (Failure)");
+ }
+
+ /* reply comes with data when the minimal length is 12 */
+ if (hlen > 11) {
+ proto_tree_add_item(jdwp_tree, hf_jdwp_data, tvb, offset, hlen - 11, ENC_NA);
+ } else if (hlen < 11) {
+ expert_add_info(pinfo, hlen_item, &ei_jdwp_hlen_invalid);
+ }
+
+ break;
+
+ default:
+ expert_add_info(pinfo, flags_item, &ei_jdwp_flags_invalid);
+ break;
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_jdwp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ tcp_dissect_pdus(tvb, pinfo, tree, TRUE, FRAME_HEADER_LEN,
+ get_jdwp_message_len, dissect_jdwp_message, data);
+ return tvb_captured_length(tvb);
+}
+
+void
+proto_register_jdwp(void)
+{
+
+ expert_module_t* expert_jdwp;
+
+ static hf_register_info hf[] = {
+ { &hf_jdwp_type,
+ { "Packet Type", "jdwp.type", FT_STRING, BASE_NONE, NULL, 0x0, "Type",
+ HFILL }
+ },
+ { &hf_jdwp_length,
+ { "Length", "jdwp.length", FT_UINT32, BASE_DEC, NULL, 0x0, "Data Length",
+ HFILL }
+ },
+ { &hf_jdwp_id,
+ { "id", "jdwp.id", FT_UINT32, BASE_DEC, NULL, 0x0, "unique identifier",
+ HFILL }
+ },
+ { &hf_jdwp_flags,
+ { "flags", "jdwp.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "tag packets as a command or reply",
+ HFILL }
+ },
+ { &hf_jdwp_commandset,
+ { "command set", "jdwp.commandset", FT_UINT8, BASE_DEC, VALS(commandsetnames), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_virtualmachine,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_virtualmachine), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_referencetype,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_referencetype), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_classtype,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classtype), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_arraytype,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_arraytype), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_interfacetype,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_interfacetype), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_method,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_method), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_field,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_field), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_objectreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_objectreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_stringreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_stringreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_threadreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_threadreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_threadgroupreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_threadgroupreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_arrayreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_arrayreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_classloaderreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classloaderreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_eventrequest,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_eventrequest), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_stackframe,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_stackframe), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_classobjectreference,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_classobjectreference), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_commandset_event,
+ { "command", "jdwp.command", FT_UINT8, BASE_DEC, VALS(commandset_event), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_errorcode,
+ { "error code", "jdwp.errorcode", FT_UINT8, BASE_DEC, VALS(error_codes), 0x0, NULL,
+ HFILL }
+ },
+ { &hf_jdwp_data,
+ { "data", "jdwp.data", FT_BYTES, BASE_NONE, NULL, 0x0, "details of the command or reply",
+ HFILL }
+ }
+ };
+
+ static ei_register_info ei[] = {
+ { &ei_jdwp_hlen_invalid, { "jdwp.hlen.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid packet length", EXPFILL }},
+ { &ei_jdwp_flags_invalid, { "jdwp.flags.invalid", PI_MALFORMED, PI_ERROR, "Decode aborted: invalid flags value", EXPFILL }}
+ };
+
+ static gint *ett[] = {
+ &ett_jdwp
+ };
+
+ proto_jdwp = proto_register_protocol("Java Debug Wire Protocol", "JDWP", "jdwp");
+ proto_register_field_array(proto_jdwp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_jdwp = expert_register_protocol(proto_jdwp);
+ expert_register_field_array(expert_jdwp, ei, array_length(ei));
+
+}
+
+void
+proto_reg_handoff_jdwp(void)
+{
+ dissector_handle_t jdwp_handle;
+
+ jdwp_handle = create_dissector_handle(dissect_jdwp, proto_jdwp);
+ dissector_add_uint_with_preference("tcp.port", JDWP_PORT, jdwp_handle);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=2 tabstop=8 expandtab:
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */