diff --git a/docbook/release-notes.adoc b/docbook/release-notes.adoc index fe48a7ccab..2137290591 100644 --- a/docbook/release-notes.adoc +++ b/docbook/release-notes.adoc @@ -61,6 +61,7 @@ OBSAI UDP-based Communication Protocol (UDPCP) AudioCodes Debug Recording (ACDR) Tunnel Extensible Authentication Protocol (TEAP) USB Printer (USBPRINTER) +Java Debug Wire Protocol (JDWP) -- === Updated Protocol Support diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index 92d946d9ca..b656aa57da 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -1280,6 +1280,7 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-ixiatrailer.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-ixveriwave.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-j1939.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-jdwp.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-jmirror.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-jpeg.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-json.c 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 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include +#include + +#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: + */