using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Collections.Generic; using System.Text; using Mono.Cecil.Metadata; namespace Mono.Debugger.Soft { class VersionInfo { public string VMVersion { get; set; } public int MajorVersion { get; set; } public int MinorVersion { get; set; } } class DebugInfo { public int max_il_offset; public string filename; public int[] il_offsets; public int[] line_numbers; } struct FrameInfo { public long id; public long method; public int il_offset; public StackFrameFlags flags; } class TypeInfo { public string ns, name, full_name; public long assembly, module, base_type, element_type; public int token, rank, attributes; public bool is_byref, is_pointer, is_primitive, is_valuetype, is_enum; public long[] nested; } class MethodInfo { public int attributes, iattributes, token; } class MethodBodyInfo { public byte[] il; } struct ParamInfo { public int call_conv; public int param_count; public int generic_param_count; public long ret_type; public long[] param_types; public string[] param_names; } struct LocalsInfo { public long[] types; public string[] names; public int[] live_range_start; public int[] live_range_end; } struct PropInfo { public long id; public string name; public long get_method, set_method; public int attrs; } class CattrNamedArgInfo { public bool is_property; public long id; public ValueImpl value; } class CattrInfo { public long ctor_id; public ValueImpl[] ctor_args; public CattrNamedArgInfo[] named_args; } class ThreadInfo { public bool is_thread_pool; } enum ValueTypeId { VALUE_TYPE_ID_NULL = 0xf0, VALUE_TYPE_ID_TYPE = 0xf1 } enum InvokeFlags { NONE = 0x0, DISABLE_BREAKPOINTS = 0x1, SINGLE_THREADED = 0x2 } class ValueImpl { public ElementType Type; /* or one of the VALUE_TYPE_ID constants */ public long Objid; public object Value; public long Klass; // For ElementType.ValueType public ValueImpl[] Fields; // for ElementType.ValueType public bool IsEnum; // For ElementType.ValueType public long Id; /* For VALUE_TYPE_ID_TYPE */ } class ModuleInfo { public string Name, ScopeName, FQName, Guid; public long Assembly; } enum TokenType { STRING = 0, TYPE = 1, FIELD = 2, METHOD = 3, UNKNOWN = 4 } enum StackFrameFlags { DEBUGGER_INVOKE = 1 } class ResolvedToken { public TokenType Type; public string Str; public long Id; } class Modifier { } class CountModifier : Modifier { public int Count { get; set; } } class LocationModifier : Modifier { public long Method { get; set; } public long Location { get; set; } } class StepModifier : Modifier { public long Thread { get; set; } public int Depth { get; set; } public int Size { get; set; } } class ThreadModifier : Modifier { public long Thread { get; set; } } class ExceptionModifier : Modifier { public long Type { get; set; } public bool Caught { get; set; } public bool Uncaught { get; set; } } class AssemblyModifier : Modifier { public long[] Assemblies { get; set; } } public enum ErrorCode { NONE = 0, INVALID_OBJECT = 20, INVALID_FIELDID = 25, INVALID_FRAMEID = 30, NOT_IMPLEMENTED = 100, NOT_SUSPENDED = 101, INVALID_ARGUMENT = 102 } public class ErrorHandlerEventArgs : EventArgs { public ErrorCode ErrorCode { get; set; } } /* * Represents the connection to the debuggee */ class Connection { /* * The protocol and the packet format is based on JDWP, the differences * are in the set of supported events, and the commands. */ public const string HANDSHAKE_STRING = "DWP-Handshake"; public const int HEADER_LENGTH = 11; /* * Th version of the wire-protocol implemented by the library. The library * and the debuggee can communicate if they implement the same major version. * If they implement a different minor version, they can communicate, but some * features might not be available. This allows older clients to communicate * with newer runtimes, and vice versa. */ public const int MAJOR_VERSION = 2; public const int MINOR_VERSION = 1; enum WPSuspendPolicy { NONE = 0, EVENT_THREAD = 1, ALL = 2 } enum CommandSet { VM = 1, OBJECT_REF = 9, STRING_REF = 10, THREAD = 11, ARRAY_REF = 13, EVENT_REQUEST = 15, STACK_FRAME = 16, APPDOMAIN = 20, ASSEMBLY = 21, METHOD = 22, TYPE = 23, MODULE = 24, EVENT = 64 } enum EventKind { VM_START = 0, VM_DEATH = 1, THREAD_START = 2, THREAD_DEATH = 3, APPDOMAIN_CREATE = 4, // Not in JDI APPDOMAIN_UNLOAD = 5, // Not in JDI METHOD_ENTRY = 6, METHOD_EXIT = 7, ASSEMBLY_LOAD = 8, ASSEMBLY_UNLOAD = 9, BREAKPOINT = 10, STEP = 11, TYPE_LOAD = 12, EXCEPTION = 13 } enum ModifierKind { COUNT = 1, THREAD_ONLY = 3, LOCATION_ONLY = 7, EXCEPTION_ONLY = 8, STEP = 10, ASSEMBLY_ONLY = 11 } enum CmdVM { VERSION = 1, ALL_THREADS = 2, SUSPEND = 3, RESUME = 4, EXIT = 5, DISPOSE = 6, INVOKE_METHOD = 7, SET_PROTOCOL_VERSION = 8 } enum CmdEvent { COMPOSITE = 100 } enum CmdThread { GET_FRAME_INFO = 1, GET_NAME = 2, GET_STATE = 3, GET_INFO = 4 } enum CmdEventRequest { SET = 1, CLEAR = 2, CLEAR_ALL_BREAKPOINTS = 3 } enum CmdAppDomain { GET_ROOT_DOMAIN = 1, GET_FRIENDLY_NAME = 2, GET_ASSEMBLIES = 3, GET_ENTRY_ASSEMBLY = 4, CREATE_STRING = 5, GET_CORLIB = 6, CREATE_BOXED_VALUE = 7 } enum CmdAssembly { GET_LOCATION = 1, GET_ENTRY_POINT = 2, GET_MANIFEST_MODULE = 3, GET_OBJECT = 4, GET_TYPE = 5, GET_NAME = 6 } enum CmdModule { GET_INFO = 1, } enum CmdMethod { GET_NAME = 1, GET_DECLARING_TYPE = 2, GET_DEBUG_INFO = 3, GET_PARAM_INFO = 4, GET_LOCALS_INFO = 5, GET_INFO = 6, GET_BODY = 7, RESOLVE_TOKEN = 8 } enum CmdType { GET_INFO = 1, GET_METHODS = 2, GET_FIELDS = 3, GET_VALUES = 4, GET_OBJECT = 5, GET_SOURCE_FILES = 6, SET_VALUES = 7, IS_ASSIGNABLE_FROM = 8, GET_PROPERTIES = 9, GET_CATTRS = 10, GET_FIELD_CATTRS = 11, GET_PROPERTY_CATTRS = 12 } enum CmdStackFrame { GET_VALUES = 1, GET_THIS = 2, SET_VALUES = 3 } enum CmdArrayRef { GET_LENGTH = 1, GET_VALUES = 2, SET_VALUES = 3 } enum CmdStringRef { GET_VALUE = 1 } enum CmdObjectRef { GET_TYPE = 1, GET_VALUES = 2, IS_COLLECTED = 3, GET_ADDRESS = 4, GET_DOMAIN = 5, SET_VALUES = 6 } class Header { public int id; public int command_set; public int command; public int flags; } public static int GetPacketLength (byte[] header) { int offset = 0; return decode_int (header, ref offset); } public static bool IsReplyPacket (byte[] packet) { int offset = 8; return decode_byte (packet, ref offset) == 0x80; } public static int GetPacketId (byte[] packet) { int offset = 4; return decode_int (packet, ref offset); } static int decode_byte (byte[] packet, ref int offset) { return packet [offset++]; } static int decode_short (byte[] packet, ref int offset) { int res = ((int)packet [offset] << 8) | (int)packet [offset + 1]; offset += 2; return res; } static int decode_int (byte[] packet, ref int offset) { int res = ((int)packet [offset] << 24) | ((int)packet [offset + 1] << 16) | ((int)packet [offset + 2] << 8) | (int)packet [offset + 3]; offset += 4; return res; } static long decode_id (byte[] packet, ref int offset) { return decode_int (packet, ref offset); } static long decode_long (byte[] packet, ref int offset) { uint high = (uint)decode_int (packet, ref offset); uint low = (uint)decode_int (packet, ref offset); return (long)(((ulong)high << 32) | (ulong)low); } public static SuspendPolicy decode_suspend_policy (int suspend_policy) { switch ((WPSuspendPolicy)suspend_policy) { case WPSuspendPolicy.NONE: return SuspendPolicy.None; case WPSuspendPolicy.EVENT_THREAD: return SuspendPolicy.EventThread; case WPSuspendPolicy.ALL: return SuspendPolicy.All; default: throw new NotImplementedException (); } } static Header decode_command_header (byte[] packet) { int offset = 0; Header res = new Header (); decode_int (packet, ref offset); res.id = decode_int (packet, ref offset); res.flags = decode_byte (packet, ref offset); res.command_set = decode_byte (packet, ref offset); res.command = decode_byte (packet, ref offset); return res; } static void encode_byte (byte[] buf, int b, ref int offset) { buf [offset] = (byte)b; offset ++; } static void encode_int (byte[] buf, int i, ref int offset) { buf [offset] = (byte)((i >> 24) & 0xff); buf [offset + 1] = (byte)((i >> 16) & 0xff); buf [offset + 2] = (byte)((i >> 8) & 0xff); buf [offset + 3] = (byte)((i >> 0) & 0xff); offset += 4; } static void encode_id (byte[] buf, long id, ref int offset) { encode_int (buf, (int)id, ref offset); } static void encode_long (byte[] buf, long l, ref int offset) { encode_int (buf, (int)((l >> 32) & 0xffffffff), ref offset); encode_int (buf, (int)(l & 0xffffffff), ref offset); } public static byte[] EncodePacket (int id, int commandSet, int command, byte[] data, int dataLen) { byte[] buf = new byte [dataLen + 11]; int offset = 0; encode_int (buf, buf.Length, ref offset); encode_int (buf, id, ref offset); encode_byte (buf, 0, ref offset); encode_byte (buf, commandSet, ref offset); encode_byte (buf, command, ref offset); for (int i = 0; i < dataLen; ++i) buf [offset + i] = data [i]; return buf; } class PacketReader { byte[] packet; int offset; public PacketReader (byte[] packet) { this.packet = packet; // For event packets Header header = decode_command_header (packet); CommandSet = (CommandSet)header.command_set; Command = header.command; // For reply packets offset = 0; ReadInt (); // length ReadInt (); // id ReadByte (); // flags ErrorCode = ReadShort (); } public CommandSet CommandSet { get; set; } public int Command { get; set; } public int ErrorCode { get; set; } public int Offset { get { return offset; } } public int ReadByte () { return decode_byte (packet, ref offset); } public int ReadShort () { return decode_short (packet, ref offset); } public int ReadInt () { return decode_int (packet, ref offset); } public long ReadId () { return decode_id (packet, ref offset); } public long ReadLong () { return decode_long (packet, ref offset); } public float ReadFloat () { float f = DataConverter.FloatFromBE (packet, offset); offset += 4; return f; } public double ReadDouble () { double d = DataConverter.DoubleFromBE (packet, offset); offset += 8; return d; } public string ReadString () { int len = decode_int (packet, ref offset); string res = new String (Encoding.UTF8.GetChars (packet, offset, len)); offset += len; return res; } public ValueImpl ReadValue () { ElementType etype = (ElementType)ReadByte (); switch (etype) { case ElementType.Void: return new ValueImpl { Type = etype }; case ElementType.I1: return new ValueImpl { Type = etype, Value = (sbyte)ReadInt () }; case ElementType.U1: return new ValueImpl { Type = etype, Value = (byte)ReadInt () }; case ElementType.Boolean: return new ValueImpl { Type = etype, Value = ReadInt () != 0 }; case ElementType.I2: return new ValueImpl { Type = etype, Value = (short)ReadInt () }; case ElementType.U2: return new ValueImpl { Type = etype, Value = (ushort)ReadInt () }; case ElementType.Char: return new ValueImpl { Type = etype, Value = (char)ReadInt () }; case ElementType.I4: return new ValueImpl { Type = etype, Value = ReadInt () }; case ElementType.U4: return new ValueImpl { Type = etype, Value = (uint)ReadInt () }; case ElementType.I8: return new ValueImpl { Type = etype, Value = ReadLong () }; case ElementType.U8: return new ValueImpl { Type = etype, Value = (ulong)ReadLong () }; case ElementType.R4: return new ValueImpl { Type = etype, Value = ReadFloat () }; case ElementType.R8: return new ValueImpl { Type = etype, Value = ReadDouble () }; case ElementType.I: case ElementType.U: case ElementType.Ptr: // FIXME: The client and the debuggee might have different word sizes return new ValueImpl { Type = etype, Value = ReadLong () }; case ElementType.String: case ElementType.SzArray: case ElementType.Class: case ElementType.Array: case ElementType.Object: long objid = ReadId (); return new ValueImpl () { Type = etype, Objid = objid }; case ElementType.ValueType: bool is_enum = ReadByte () == 1; long klass = ReadId (); long nfields = ReadInt (); ValueImpl[] fields = new ValueImpl [nfields]; for (int i = 0; i < nfields; ++i) fields [i] = ReadValue (); return new ValueImpl () { Type = etype, Klass = klass, Fields = fields, IsEnum = is_enum }; case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: return new ValueImpl { Type = etype }; case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE: return new ValueImpl () { Type = etype, Id = ReadId () }; default: throw new NotImplementedException ("Unable to handle type " + etype); } } } class PacketWriter { byte[] data; int offset; public PacketWriter () { // FIXME: data = new byte [1024]; offset = 0; } public PacketWriter WriteByte (byte val) { encode_byte (data, val, ref offset); return this; } public PacketWriter WriteInt (int val) { encode_int (data, val, ref offset); return this; } public PacketWriter WriteId (long id) { encode_id (data, id, ref offset); return this; } public PacketWriter WriteLong (long val) { encode_long (data, val, ref offset); return this; } public PacketWriter WriteFloat (float f) { byte[] b = DataConverter.GetBytesBE (f); for (int i = 0; i < 4; ++i) data [offset + i] = b [i]; offset += 4; return this; } public PacketWriter WriteDouble (double d) { byte[] b = DataConverter.GetBytesBE (d); for (int i = 0; i < 8; ++i) data [offset + i] = b [i]; offset += 8; return this; } public PacketWriter WriteInts (int[] ids) { for (int i = 0; i < ids.Length; ++i) WriteInt (ids [i]); return this; } public PacketWriter WriteIds (long[] ids) { for (int i = 0; i < ids.Length; ++i) WriteId (ids [i]); return this; } public PacketWriter WriteString (string s) { encode_int (data, s.Length, ref offset); byte[] b = Encoding.UTF8.GetBytes (s); Buffer.BlockCopy (b, 0, data, offset, b.Length); offset += b.Length; return this; } public PacketWriter WriteBool (bool val) { WriteByte (val ? (byte)1 : (byte)0); return this; } public PacketWriter WriteValue (ValueImpl v) { ElementType t; if (v.Value != null) t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ())); else t = v.Type; WriteByte ((byte)t); switch (t) { case ElementType.Boolean: WriteInt ((bool)v.Value ? 1 : 0); break; case ElementType.Char: WriteInt ((int)(char)v.Value); break; case ElementType.I1: WriteInt ((int)(sbyte)v.Value); break; case ElementType.U1: WriteInt ((int)(byte)v.Value); break; case ElementType.I2: WriteInt ((int)(short)v.Value); break; case ElementType.U2: WriteInt ((int)(ushort)v.Value); break; case ElementType.I4: WriteInt ((int)(int)v.Value); break; case ElementType.U4: WriteInt ((int)(uint)v.Value); break; case ElementType.I8: WriteLong ((long)(long)v.Value); break; case ElementType.U8: WriteLong ((long)(ulong)v.Value); break; case ElementType.R4: WriteFloat ((float)v.Value); break; case ElementType.R8: WriteDouble ((double)v.Value); break; case ElementType.String: case ElementType.SzArray: case ElementType.Class: case ElementType.Array: case ElementType.Object: WriteId (v.Objid); break; case ElementType.ValueType: // FIXME: if (v.IsEnum) throw new NotImplementedException (); WriteByte (0); WriteId (v.Klass); WriteInt (v.Fields.Length); for (int i = 0; i < v.Fields.Length; ++i) WriteValue (v.Fields [i]); break; case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL: break; default: throw new NotImplementedException (); } return this; } public PacketWriter WriteValues (ValueImpl[] values) { for (int i = 0; i < values.Length; ++i) WriteValue (values [i]); return this; } public byte[] Data { get { return data; } } public int Offset { get { return offset; } } } delegate void ReplyCallback (int packet_id, byte[] packet); Socket socket; bool closed; Thread receiver_thread; Dictionary reply_packets; Dictionary reply_cbs; object reply_packets_monitor; public event EventHandler ErrorHandler; public Connection (Socket socket) { this.socket = socket; //socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.NoDelay, 1); closed = false; reply_packets = new Dictionary (); reply_cbs = new Dictionary (); reply_packets_monitor = new Object (); } int Receive (byte[] buf, int buf_offset, int len) { int offset = 0; while (offset < len) { int n = socket.Receive (buf, buf_offset + offset, len - offset, SocketFlags.None); if (n == 0) return offset; offset += n; } return offset; } public VersionInfo Version; // Do the wire protocol handshake public void Connect () { byte[] buf = new byte [HANDSHAKE_STRING.Length]; char[] cbuf = new char [buf.Length]; // FIXME: Add a timeout int n = Receive (buf, 0, buf.Length); if (n == 0) throw new IOException ("DWP Handshake failed."); for (int i = 0; i < buf.Length; ++i) cbuf [i] = (char)buf [i]; if (new String (cbuf) != HANDSHAKE_STRING) throw new IOException ("DWP Handshake failed."); socket.Send (buf); receiver_thread = new Thread (new ThreadStart (receiver_thread_main)); receiver_thread.Start (); Version = VM_GetVersion (); // // Tell the debuggee our protocol version, so newer debuggees can work // with older clients // // // Older debuggees might not support this request EventHandler OrigErrorHandler = ErrorHandler; ErrorHandler = null; ErrorHandler += delegate (object sender, ErrorHandlerEventArgs args) { throw new NotSupportedException (); }; try { VM_SetProtocolVersion (MAJOR_VERSION, MINOR_VERSION); } catch (NotSupportedException) { } ErrorHandler = OrigErrorHandler; } public EndPoint EndPoint { get { return socket.RemoteEndPoint; } } public byte[] ReadPacket () { // FIXME: Throw ClosedConnectionException () if the connection is closed // FIXME: Throw ClosedConnectionException () if another thread closes the connection // FIXME: Locking byte[] header = new byte [HEADER_LENGTH]; int len = Receive (header, 0, header.Length); if (len == 0) return new byte [0]; if (len != HEADER_LENGTH) { // FIXME: throw new IOException ("Packet of length " + len + " is read."); } int packetLength = GetPacketLength (header); if (packetLength < 11) throw new IOException ("Invalid packet length."); if (packetLength == 11) { return header; } else { byte[] buf = new byte [packetLength]; for (int i = 0; i < header.Length; ++i) buf [i] = header [i]; len = Receive (buf, header.Length, packetLength - header.Length); if (len != packetLength - header.Length) throw new IOException (); return buf; } } public void WritePacket (byte[] packet) { // FIXME: Throw ClosedConnectionException () if the connection is closed // FIXME: Throw ClosedConnectionException () if another thread closes the connection // FIXME: Locking socket.Send (packet); } public void Close () { closed = true; } public bool IsClosed { get { return closed; } } bool disconnected; void receiver_thread_main () { while (true) { try { bool res = ReceivePacket (); if (!res) break; } catch (Exception ex) { Console.WriteLine (ex); break; } } lock (reply_packets_monitor) { disconnected = true; Monitor.PulseAll (reply_packets_monitor); } EventHandler.VMDisconnect (0, 0, null); } bool ReceivePacket () { byte[] packet = ReadPacket (); if (packet.Length == 0) { return false; } if (IsReplyPacket (packet)) { int id = GetPacketId (packet); ReplyCallback cb = null; lock (reply_packets_monitor) { reply_cbs.TryGetValue (id, out cb); if (cb == null) { reply_packets [id] = packet; Monitor.PulseAll (reply_packets_monitor); } } if (cb != null) cb.Invoke (id, packet); } else { PacketReader r = new PacketReader (packet); if (r.CommandSet == CommandSet.EVENT && r.Command == (int)CmdEvent.COMPOSITE) { r.ReadByte (); // suspend_policy int nevents = r.ReadInt (); for (int i = 0; i < nevents; ++i) { EventKind kind = (EventKind)r.ReadByte (); int req_id = r.ReadInt (); if (kind == EventKind.VM_START) { long thread_id = r.ReadId (); EventHandler.VMStart (req_id, thread_id, null); } else if (kind == EventKind.VM_DEATH) { EventHandler.VMDeath (req_id, 0, null); } else if (kind == EventKind.THREAD_START) { long thread_id = r.ReadId (); EventHandler.ThreadStart (req_id, thread_id, thread_id); } else if (kind == EventKind.THREAD_DEATH) { long thread_id = r.ReadId (); EventHandler.ThreadDeath (req_id, thread_id, thread_id); } else if (kind == EventKind.ASSEMBLY_LOAD) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.AssemblyLoad (req_id, thread_id, id); } else if (kind == EventKind.ASSEMBLY_UNLOAD) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.AssemblyUnload (req_id, thread_id, id); } else if (kind == EventKind.TYPE_LOAD) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.TypeLoad (req_id, thread_id, id); } else if (kind == EventKind.METHOD_ENTRY) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.MethodEntry (req_id, thread_id, id); } else if (kind == EventKind.METHOD_EXIT) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.MethodExit (req_id, thread_id, id); } else if (kind == EventKind.BREAKPOINT) { long thread_id = r.ReadId (); long id = r.ReadId (); long loc = r.ReadLong (); EventHandler.Breakpoint (req_id, thread_id, id, loc); } else if (kind == EventKind.STEP) { long thread_id = r.ReadId (); long id = r.ReadId (); long loc = r.ReadLong (); EventHandler.Step (req_id, thread_id, id, loc); } else if (kind == EventKind.EXCEPTION) { long thread_id = r.ReadId (); long id = r.ReadId (); long loc = 0; // FIXME EventHandler.Exception (req_id, thread_id, id, loc); } else if (kind == EventKind.APPDOMAIN_CREATE) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.AppDomainCreate (req_id, thread_id, id); } else if (kind == EventKind.APPDOMAIN_UNLOAD) { long thread_id = r.ReadId (); long id = r.ReadId (); EventHandler.AppDomainUnload (req_id, thread_id, id); } else { throw new NotImplementedException ("Unknown event kind: " + kind); } } } } return true; } public IEventHandler EventHandler { get; set; } /* Send a request and call cb when a result is received */ void Send (CommandSet command_set, int command, PacketWriter packet, Action cb) { int id = IdGenerator; lock (reply_packets_monitor) { reply_cbs [id] = delegate (int packet_id, byte[] p) { /* Run the callback on a tp thread to avoid blocking the receive thread */ PacketReader r = new PacketReader (p); cb.BeginInvoke (r, null, null); }; } if (packet == null) WritePacket (EncodePacket (id, (int)command_set, command, null, 0)); else WritePacket (EncodePacket (id, (int)command_set, command, packet.Data, packet.Offset)); } PacketReader SendReceive (CommandSet command_set, int command, PacketWriter packet) { int id = IdGenerator; if (packet == null) WritePacket (EncodePacket (id, (int)command_set, command, null, 0)); else WritePacket (EncodePacket (id, (int)command_set, command, packet.Data, packet.Offset)); int packetId = id; /* Wait for the reply packet */ while (true) { lock (reply_packets_monitor) { if (reply_packets.ContainsKey (packetId)) { byte[] reply = reply_packets [packetId]; reply_packets.Remove (packetId); PacketReader r = new PacketReader (reply); if (r.ErrorCode != 0) { if (ErrorHandler != null) ErrorHandler (this, new ErrorHandlerEventArgs () { ErrorCode = (ErrorCode)r.ErrorCode }); throw new NotImplementedException ("No error handler set."); } else { return r; } } else { if (disconnected) throw new VMDisconnectedException (); Monitor.Wait (reply_packets_monitor); } } } } PacketReader SendReceive (CommandSet command_set, int command) { return SendReceive (command_set, command, null); } int packet_id_generator; int IdGenerator { get { return Interlocked.Increment (ref packet_id_generator); } } CattrInfo[] ReadCattrs (PacketReader r) { CattrInfo[] res = new CattrInfo [r.ReadInt ()]; for (int i = 0; i < res.Length; ++i) { CattrInfo info = new CattrInfo (); info.ctor_id = r.ReadId (); info.ctor_args = new ValueImpl [r.ReadInt ()]; for (int j = 0; j < info.ctor_args.Length; ++j) { info.ctor_args [j] = r.ReadValue (); } info.named_args = new CattrNamedArgInfo [r.ReadInt ()]; for (int j = 0; j < info.named_args.Length; ++j) { CattrNamedArgInfo arg = new CattrNamedArgInfo (); int arg_type = r.ReadByte (); arg.is_property = arg_type == 0x54; arg.id = r.ReadId (); arg.value = r.ReadValue (); info.named_args [j] = arg; } res [i] = info; } return res; } static ElementType TypeCodeToElementType (TypeCode c) { switch (c) { case TypeCode.Boolean: return ElementType.Boolean; case TypeCode.Char: return ElementType.Char; case TypeCode.SByte: return ElementType.I1; case TypeCode.Byte: return ElementType.U1; case TypeCode.Int16: return ElementType.I2; case TypeCode.UInt16: return ElementType.U2; case TypeCode.Int32: return ElementType.I4; case TypeCode.UInt32: return ElementType.U4; case TypeCode.Int64: return ElementType.I8; case TypeCode.UInt64: return ElementType.U8; case TypeCode.Single: return ElementType.R4; case TypeCode.Double: return ElementType.R8; default: throw new NotImplementedException (); } } /* * Implementation of debugger commands */ public VersionInfo VM_GetVersion () { var res = SendReceive (CommandSet.VM, (int)CmdVM.VERSION, null); VersionInfo info = new VersionInfo (); info.VMVersion = res.ReadString (); info.MajorVersion = res.ReadInt (); info.MinorVersion = res.ReadInt (); return info; } public void VM_SetProtocolVersion (int major, int minor) { SendReceive (CommandSet.VM, (int)CmdVM.SET_PROTOCOL_VERSION, new PacketWriter ().WriteInt (major).WriteInt (minor)); } public long[] VM_GetThreads () { var res = SendReceive (CommandSet.VM, (int)CmdVM.ALL_THREADS, null); int len = res.ReadInt (); long[] arr = new long [len]; for (int i = 0; i < len; ++i) arr [i] = res.ReadId (); return arr; } public void VM_Suspend () { SendReceive (CommandSet.VM, (int)CmdVM.SUSPEND); } public void VM_Resume () { SendReceive (CommandSet.VM, (int)CmdVM.RESUME); } public void VM_Exit (int exitCode) { SendReceive (CommandSet.VM, (int)CmdVM.EXIT, new PacketWriter ().WriteInt (exitCode)); } public void VM_Dispose () { SendReceive (CommandSet.VM, (int)CmdVM.DISPOSE); } public ValueImpl VM_InvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, out ValueImpl exc) { exc = null; PacketReader r = SendReceive (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments)); if (r.ReadByte () == 0) { exc = r.ReadValue (); return null; } else { return r.ReadValue (); } } public delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, ErrorCode error, object state); public void VM_BeginInvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, InvokeMethodCallback callback, object state) { Send (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments), delegate (PacketReader r) { ValueImpl v, exc; if (r.ErrorCode != 0) { callback (null, null, (ErrorCode)r.ErrorCode, state); } else { if (r.ReadByte () == 0) { exc = r.ReadValue (); v = null; } else { v = r.ReadValue (); exc = null; } callback (v, exc, 0, state); } }); } /* * DOMAIN */ public long RootDomain { get { return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ROOT_DOMAIN, null).ReadId (); } } public string Domain_GetName (long id) { return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_FRIENDLY_NAME, new PacketWriter ().WriteId (id)).ReadString (); } public long[] Domain_GetAssemblies (long id) { var res = SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ASSEMBLIES, new PacketWriter ().WriteId (id)); int count = res.ReadInt (); long[] assemblies = new long [count]; for (int i = 0; i < count; ++i) assemblies [i] = res.ReadId (); return assemblies; } public long Domain_GetEntryAssembly (long id) { return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ENTRY_ASSEMBLY, new PacketWriter ().WriteId (id)).ReadId (); } public long Domain_GetCorlib (long id) { return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_CORLIB, new PacketWriter ().WriteId (id)).ReadId (); } public long Domain_CreateString (long id, string s) { return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_STRING, new PacketWriter ().WriteId (id).WriteString (s)).ReadId (); } public long Domain_CreateBoxedValue (long id, long type_id, ValueImpl v) { return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_BOXED_VALUE, new PacketWriter ().WriteId (id).WriteId (type_id).WriteValue (v)).ReadId (); } /* * METHOD */ public string Method_GetName (long id) { return SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_NAME, new PacketWriter ().WriteId (id)).ReadString (); } public long Method_GetDeclaringType (long id) { return SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_DECLARING_TYPE, new PacketWriter ().WriteId (id)).ReadId (); } public DebugInfo Method_GetDebugInfo (long id) { var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_DEBUG_INFO, new PacketWriter ().WriteId (id)); DebugInfo info = new DebugInfo (); info.max_il_offset = res.ReadInt (); info.filename = res.ReadString (); int n_il_offsets = res.ReadInt (); info.il_offsets = new int [n_il_offsets]; info.line_numbers = new int [n_il_offsets]; for (int i = 0; i < n_il_offsets; ++i) { info.il_offsets [i] = res.ReadInt (); info.line_numbers [i] = res.ReadInt (); } return info; } public ParamInfo Method_GetParamInfo (long id) { var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_PARAM_INFO, new PacketWriter ().WriteId (id)); ParamInfo info = new ParamInfo (); info.call_conv = res.ReadInt (); info.param_count = res.ReadInt (); info.generic_param_count = res.ReadInt (); info.ret_type = res.ReadId (); info.param_types = new long [info.param_count]; for (int i = 0; i < info.param_count; ++i) info.param_types [i] = res.ReadId (); info.param_names = new string [info.param_count]; for (int i = 0; i < info.param_count; ++i) info.param_names [i] = res.ReadString (); return info; } public LocalsInfo Method_GetLocalsInfo (long id) { var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_LOCALS_INFO, new PacketWriter ().WriteId (id)); LocalsInfo info = new LocalsInfo (); int nlocals = res.ReadInt (); info.types = new long [nlocals]; for (int i = 0; i < nlocals; ++i) info.types [i] = res.ReadId (); info.names = new string [nlocals]; for (int i = 0; i < nlocals; ++i) info.names [i] = res.ReadString (); info.live_range_start = new int [nlocals]; info.live_range_end = new int [nlocals]; for (int i = 0; i < nlocals; ++i) { info.live_range_start [i] = res.ReadInt (); info.live_range_end [i] = res.ReadInt (); } return info; } public MethodInfo Method_GetInfo (long id) { var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_INFO, new PacketWriter ().WriteId (id)); MethodInfo info = new MethodInfo (); info.attributes = res.ReadInt (); info.iattributes = res.ReadInt (); info.token = res.ReadInt (); return info; } public MethodBodyInfo Method_GetBody (long id) { var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_BODY, new PacketWriter ().WriteId (id)); MethodBodyInfo info = new MethodBodyInfo (); info.il = new byte [res.ReadInt ()]; for (int i = 0; i < info.il.Length; ++i) info.il [i] = (byte)res.ReadByte (); return info; } public ResolvedToken Method_ResolveToken (long id, int token) { var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.RESOLVE_TOKEN, new PacketWriter ().WriteId (id).WriteInt (token)); TokenType type = (TokenType)res.ReadByte (); switch (type) { case TokenType.STRING: return new ResolvedToken () { Type = type, Str = res.ReadString () }; case TokenType.TYPE: case TokenType.METHOD: case TokenType.FIELD: return new ResolvedToken () { Type = type, Id = res.ReadId () }; case TokenType.UNKNOWN: return new ResolvedToken () { Type = type }; default: throw new NotImplementedException (); } } /* * THREAD */ public string Thread_GetName (long id) { return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_NAME, new PacketWriter ().WriteId (id)).ReadString (); } public FrameInfo[] Thread_GetFrameInfo (long id, int start_frame, int length) { var res = SendReceive (CommandSet.THREAD, (int)CmdThread.GET_FRAME_INFO, new PacketWriter ().WriteId (id).WriteInt (start_frame).WriteInt (length)); int count = res.ReadInt (); var frames = new FrameInfo [count]; for (int i = 0; i < count; ++i) { frames [i].id = res.ReadInt (); frames [i].method = res.ReadId (); frames [i].il_offset = res.ReadInt (); frames [i].flags = (StackFrameFlags)res.ReadByte (); } return frames; } public int Thread_GetState (long id) { return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_STATE, new PacketWriter ().WriteId (id)).ReadInt (); } public ThreadInfo Thread_GetInfo (long id) { PacketReader r = SendReceive (CommandSet.THREAD, (int)CmdThread.GET_INFO, new PacketWriter ().WriteId (id)); ThreadInfo res = new ThreadInfo () { is_thread_pool = r.ReadByte () > 0 ? true : false }; return res; } /* * MODULE */ public ModuleInfo Module_GetInfo (long id) { PacketReader r = SendReceive (CommandSet.MODULE, (int)CmdModule.GET_INFO, new PacketWriter ().WriteId (id)); ModuleInfo info = new ModuleInfo { Name = r.ReadString (), ScopeName = r.ReadString (), FQName = r.ReadString (), Guid = r.ReadString (), Assembly = r.ReadId () }; return info; } /* * ASSEMBLY */ public string Assembly_GetLocation (long id) { return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_LOCATION, new PacketWriter ().WriteId (id)).ReadString (); } public long Assembly_GetEntryPoint (long id) { return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_ENTRY_POINT, new PacketWriter ().WriteId (id)).ReadId (); } public long Assembly_GetManifestModule (long id) { return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_MANIFEST_MODULE, new PacketWriter ().WriteId (id)).ReadId (); } public long Assembly_GetObject (long id) { return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_OBJECT, new PacketWriter ().WriteId (id)).ReadId (); } public long Assembly_GetType (long id, string name, bool ignoreCase) { return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_TYPE, new PacketWriter ().WriteId (id).WriteString (name).WriteBool (ignoreCase)).ReadId (); } public string Assembly_GetName (long id) { return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_NAME, new PacketWriter ().WriteId (id)).ReadString (); } /* * TYPE */ public TypeInfo Type_GetInfo (long id) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INFO, new PacketWriter ().WriteId (id)); TypeInfo res = new TypeInfo (); res.ns = r.ReadString (); res.name = r.ReadString (); res.full_name = r.ReadString (); res.assembly = r.ReadId (); res.module = r.ReadId (); res.base_type = r.ReadId (); res.element_type = r.ReadId (); res.token = r.ReadInt (); res.rank = r.ReadByte (); res.attributes = r.ReadInt (); int b = r.ReadByte (); res.is_byref = (b & 1) != 0; res.is_pointer = (b & 2) != 0; res.is_primitive = (b & 4) != 0; res.is_valuetype = (b & 8) != 0; res.is_enum = (b & 16) != 0; int nested_len = r.ReadInt (); res.nested = new long [nested_len]; for (int i = 0; i < nested_len; ++i) res.nested [i] = r.ReadId (); return res; } public long[] Type_GetMethods (long id) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_METHODS, new PacketWriter ().WriteId (id)); int n = r.ReadInt (); long[] res = new long [n]; for (int i = 0; i < n; ++i) res [i] = r.ReadId (); return res; } public long[] Type_GetFields (long id, out string[] names, out long[] types, out int[] attrs) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_FIELDS, new PacketWriter ().WriteId (id)); int n = r.ReadInt (); long[] res = new long [n]; names = new string [n]; types = new long [n]; attrs = new int [n]; for (int i = 0; i < n; ++i) { res [i] = r.ReadId (); names [i] = r.ReadString (); types [i] = r.ReadId (); attrs [i] = r.ReadInt (); } return res; } public PropInfo[] Type_GetProperties (long id) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_PROPERTIES, new PacketWriter ().WriteId (id)); int n = r.ReadInt (); PropInfo[] res = new PropInfo [n]; for (int i = 0; i < n; ++i) { res [i] = new PropInfo (); res [i].id = r.ReadId (); res [i].name = r.ReadString (); res [i].get_method = r.ReadId (); res [i].set_method = r.ReadId (); res [i].attrs = r.ReadInt (); } return res; } public long Type_GetObject (long id) { return SendReceive (CommandSet.TYPE, (int)CmdType.GET_OBJECT, new PacketWriter ().WriteId (id)).ReadId (); } public ValueImpl[] Type_GetValues (long id, long[] fields) { int len = fields.Length; PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (len).WriteIds (fields)); ValueImpl[] res = new ValueImpl [len]; for (int i = 0; i < len; ++i) res [i] = r.ReadValue (); return res; } public void Type_SetValues (long id, long[] fields, ValueImpl[] values) { SendReceive (CommandSet.TYPE, (int)CmdType.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (fields.Length).WriteIds (fields).WriteValues (values)); } public string[] Type_GetSourceFiles (long id) { var r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_SOURCE_FILES, new PacketWriter ().WriteId (id)); int len = r.ReadInt (); string[] res = new string [len]; for (int i = 0; i < len; ++i) res [i] = r.ReadString (); return res; } public bool Type_IsAssignableFrom (long id, long c_id) { return SendReceive (CommandSet.TYPE, (int)CmdType.IS_ASSIGNABLE_FROM, new PacketWriter ().WriteId (id).WriteId (c_id)).ReadByte () > 0; } public CattrInfo[] Type_GetCustomAttributes (long id, long attr_type_id, bool inherit) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_CATTRS, new PacketWriter ().WriteId (id).WriteId (attr_type_id)); return ReadCattrs (r); } public CattrInfo[] Type_GetFieldCustomAttributes (long id, long field_id, long attr_type_id, bool inherit) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_FIELD_CATTRS, new PacketWriter ().WriteId (id).WriteId (field_id).WriteId (attr_type_id)); return ReadCattrs (r); } public CattrInfo[] Type_GetPropertyCustomAttributes (long id, long field_id, long attr_type_id, bool inherit) { PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_PROPERTY_CATTRS, new PacketWriter ().WriteId (id).WriteId (field_id).WriteId (attr_type_id)); return ReadCattrs (r); } /* * EVENTS */ public int EnableEvent (EventType etype, SuspendPolicy suspend_policy, List mods) { var w = new PacketWriter ().WriteByte ((byte)etype).WriteByte ((byte)suspend_policy); if (mods != null) { if (mods.Count > 255) throw new NotImplementedException (); w.WriteByte ((byte)mods.Count); foreach (Modifier mod in mods) { if (mod is CountModifier) { w.WriteByte ((byte)ModifierKind.COUNT); w.WriteInt ((mod as CountModifier).Count); } else if (mod is LocationModifier) { w.WriteByte ((byte)ModifierKind.LOCATION_ONLY); w.WriteId ((mod as LocationModifier).Method); w.WriteLong ((mod as LocationModifier).Location); } else if (mod is StepModifier) { w.WriteByte ((byte)ModifierKind.STEP); w.WriteId ((mod as StepModifier).Thread); w.WriteInt ((mod as StepModifier).Size); w.WriteInt ((mod as StepModifier).Depth); } else if (mod is ThreadModifier) { w.WriteByte ((byte)ModifierKind.THREAD_ONLY); w.WriteId ((mod as ThreadModifier).Thread); } else if (mod is ExceptionModifier) { var em = mod as ExceptionModifier; w.WriteByte ((byte)ModifierKind.EXCEPTION_ONLY); w.WriteId (em.Type); if (Version.MajorVersion > 2 || Version.MinorVersion > 0) { /* This is only supported in protocol version 2.1 */ w.WriteBool (em.Caught); w.WriteBool (em.Uncaught); } else if (!em.Caught || !em.Uncaught) { throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee."); } } else if (mod is AssemblyModifier) { w.WriteByte ((byte)ModifierKind.ASSEMBLY_ONLY); var amod = (mod as AssemblyModifier); w.WriteInt (amod.Assemblies.Length); foreach (var id in amod.Assemblies) w.WriteId (id); } else { throw new NotImplementedException (); } } } else { w.WriteByte (0); } return SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.SET, w).ReadInt (); } public void ClearEventRequest (EventType etype, int req_id) { SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.CLEAR, new PacketWriter ().WriteByte ((byte)etype).WriteInt (req_id)); } public void ClearAllBreakpoints () { SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.CLEAR_ALL_BREAKPOINTS, new PacketWriter ()); } /* * STACK FRAME */ public ValueImpl StackFrame_GetThis (long thread_id, long id) { PacketReader r = SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_THIS, new PacketWriter ().WriteId (thread_id).WriteId (id)); return r.ReadValue (); } public ValueImpl[] StackFrame_GetValues (long thread_id, long id, int[] pos) { /* pos < 0 -> argument at pos (-pos) - 1 */ /* pos >= 0 -> local at pos */ int len = pos.Length; PacketReader r = SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_VALUES, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteInt (len).WriteInts (pos)); ValueImpl[] res = new ValueImpl [len]; for (int i = 0; i < len; ++i) res [i] = r.ReadValue (); return res; } public void StackFrame_SetValues (long thread_id, long id, int[] pos, ValueImpl[] values) { /* pos < 0 -> argument at pos (-pos) - 1 */ /* pos >= 0 -> local at pos */ int len = pos.Length; SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.SET_VALUES, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteInt (len).WriteInts (pos).WriteValues (values)); } /* * ARRAYS */ public int[] Array_GetLength (long id, out int rank, out int[] lower_bounds) { var r = SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.GET_LENGTH, new PacketWriter ().WriteId (id)); rank = r.ReadInt (); int[] res = new int [rank]; lower_bounds = new int [rank]; for (int i = 0; i < rank; ++i) { res [i] = r.ReadInt (); lower_bounds [i] = r.ReadInt (); } return res; } public ValueImpl[] Array_GetValues (long id, int index, int len) { var r = SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (index).WriteInt (len)); ValueImpl[] res = new ValueImpl [len]; for (int i = 0; i < len; ++i) res [i] = r.ReadValue (); return res; } public void Array_SetValues (long id, int index, ValueImpl[] values) { SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (index).WriteInt (values.Length).WriteValues (values)); } /* * STRINGS */ public string String_GetValue (long id) { return SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_VALUE, new PacketWriter ().WriteId (id)).ReadString (); } /* * OBJECTS */ public long Object_GetType (long id) { return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_TYPE, new PacketWriter ().WriteId (id)).ReadId (); } public long Object_GetDomain (long id) { return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_DOMAIN, new PacketWriter ().WriteId (id)).ReadId (); } public ValueImpl[] Object_GetValues (long id, long[] fields) { int len = fields.Length; PacketReader r = SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (len).WriteIds (fields)); ValueImpl[] res = new ValueImpl [len]; for (int i = 0; i < len; ++i) res [i] = r.ReadValue (); return res; } public void Object_SetValues (long id, long[] fields, ValueImpl[] values) { SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (fields.Length).WriteIds (fields).WriteValues (values)); } public bool Object_IsCollected (long id) { return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.IS_COLLECTED, new PacketWriter ().WriteId (id)).ReadInt () == 1; } public long Object_GetAddress (long id) { return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_ADDRESS, new PacketWriter ().WriteId (id)).ReadLong (); } } /* This is the interface exposed by the debugger towards the debugger agent */ interface IEventHandler { void VMStart (int req_id, long thread_id, string vm_uri); void VMDeath (int req_id, long thread_id, string vm_uri); void VMDisconnect (int req_id, long thread_id, string vm_uri); void ThreadStart (int req_id, long thread_id, long id); void ThreadDeath (int req_id, long thread_id, long id); void AssemblyLoad (int req_id, long thread_id, long id); void AssemblyUnload (int req_id, long thread_id, long id); void TypeLoad (int req_id, long thread_id, long id); void MethodEntry (int req_id, long thread_id, long id); void MethodExit (int req_id, long thread_id, long id); void Breakpoint (int req_id, long thread_id, long method_id, long loc); void Step (int req_id, long thread_id, long method_id, long loc); void Exception (int req_id, long thread_id, long exc_id, long loc); void AppDomainCreate (int req_id, long thread_id, long id); void AppDomainUnload (int req_id, long thread_id, long id); } }