From 291c09421594a1d11965866406e6a95c8f46fedd Mon Sep 17 00:00:00 2001 From: smallsql Date: Sun, 22 Feb 2009 09:09:41 +0000 Subject: [PATCH] handling the first debuggee event (ThreadStart) --- debugger/Debugger.cs | 2 +- debugger/EventRequest.cs | 66 +++++++++++++++++++++++--------------- debugger/JdwpConnection.cs | 15 +++++++-- debugger/JdwpHandler.cs | 3 +- debugger/Packet.cs | 50 +++++++++++++++++++++++------ debugger/debugger.csproj | 1 + debugger/win/TargetVM.cs | 48 ++++++++++++++++++++++++--- 7 files changed, 139 insertions(+), 46 deletions(-) diff --git a/debugger/Debugger.cs b/debugger/Debugger.cs index 8630cf80..8ccea406 100644 --- a/debugger/Debugger.cs +++ b/debugger/Debugger.cs @@ -66,7 +66,7 @@ namespace ikvm.debugger JdwpConnection conn = new JdwpConnection(parameters); conn.Connect(); Console.Error.WriteLine("Started"); - TargetVM target = new TargetVM(pid); + TargetVM target = new TargetVM(pid, new JdwpEventHandler(conn)); JdwpHandler handler = new JdwpHandler(conn, target); handler.Run(); //System.Threading.Thread.Sleep(5000); diff --git a/debugger/EventRequest.cs b/debugger/EventRequest.cs index 8fb7ba34..dc76c55c 100644 --- a/debugger/EventRequest.cs +++ b/debugger/EventRequest.cs @@ -36,15 +36,19 @@ namespace ikvm.debugger.requests internal const int CmdClear = 2; internal const int CmdClearAllBreakpoints = 3; - private byte eventKind; - private byte suspendPolicy; - private List modifiers; + private static int eventRequestCounter; + + private readonly byte eventKind; + private readonly byte suspendPolicy; + private readonly List modifiers; + private readonly int requestId; private EventRequest(byte eventKind, byte suspendPolicy, List modifiers) { this.eventKind = eventKind; this.suspendPolicy = suspendPolicy; this.modifiers = modifiers; + this.requestId = ++eventRequestCounter; } /// @@ -57,29 +61,29 @@ namespace ikvm.debugger.requests byte eventKind = packet.ReadByte(); // class EventKind switch (eventKind) { - case EventKind.SINGLE_STEP: - case EventKind.BREAKPOINT: - case EventKind.FRAME_POP: - case EventKind.EXCEPTION: - case EventKind.USER_DEFINED: - case EventKind.THREAD_START: - case EventKind.THREAD_DEATH: - case EventKind.CLASS_PREPARE: - case EventKind.CLASS_UNLOAD: - case EventKind.CLASS_LOAD: - case EventKind.FIELD_ACCESS: - case EventKind.FIELD_MODIFICATION: - case EventKind.EXCEPTION_CATCH: - case EventKind.METHOD_ENTRY: - case EventKind.METHOD_EXIT: - case EventKind.METHOD_EXIT_WITH_RETURN_VALUE: - case EventKind.MONITOR_CONTENDED_ENTER: - case EventKind.MONITOR_CONTENDED_ENTERED: - case EventKind.MONITOR_WAIT: - case EventKind.MONITOR_WAITED: - case EventKind.VM_START: - case EventKind.VM_DEATH: - case EventKind.VM_DISCONNECTED: + case ikvm.debugger.EventKind.SINGLE_STEP: + case ikvm.debugger.EventKind.BREAKPOINT: + case ikvm.debugger.EventKind.FRAME_POP: + case ikvm.debugger.EventKind.EXCEPTION: + case ikvm.debugger.EventKind.USER_DEFINED: + case ikvm.debugger.EventKind.THREAD_START: + case ikvm.debugger.EventKind.THREAD_DEATH: + case ikvm.debugger.EventKind.CLASS_PREPARE: + case ikvm.debugger.EventKind.CLASS_UNLOAD: + case ikvm.debugger.EventKind.CLASS_LOAD: + case ikvm.debugger.EventKind.FIELD_ACCESS: + case ikvm.debugger.EventKind.FIELD_MODIFICATION: + case ikvm.debugger.EventKind.EXCEPTION_CATCH: + case ikvm.debugger.EventKind.METHOD_ENTRY: + case ikvm.debugger.EventKind.METHOD_EXIT: + case ikvm.debugger.EventKind.METHOD_EXIT_WITH_RETURN_VALUE: + case ikvm.debugger.EventKind.MONITOR_CONTENDED_ENTER: + case ikvm.debugger.EventKind.MONITOR_CONTENDED_ENTERED: + case ikvm.debugger.EventKind.MONITOR_WAIT: + case ikvm.debugger.EventKind.MONITOR_WAITED: + case ikvm.debugger.EventKind.VM_START: + case ikvm.debugger.EventKind.VM_DEATH: + case ikvm.debugger.EventKind.VM_DISCONNECTED: break; default: return null; //Invalid or not supported EventKind @@ -139,6 +143,16 @@ namespace ikvm.debugger.requests return new EventRequest(eventKind, suspendPolicy, modifiers); } + internal int RequestId + { + get { return requestId; } + } + + internal int EventKind + { + get { return eventKind; } + } + public override String ToString() { //for debugging diff --git a/debugger/JdwpConnection.cs b/debugger/JdwpConnection.cs index 028f86ba..822fa43e 100644 --- a/debugger/JdwpConnection.cs +++ b/debugger/JdwpConnection.cs @@ -36,10 +36,15 @@ namespace ikvm.debugger private TcpClient client; - BufferedStream stream; + Stream stream; + /// + /// Shared buffer for reading and monitor for reading + /// private readonly byte[] readHeader = new byte[11]; + private readonly Object writeMonitor = new Object(); + internal JdwpConnection(JdwpParameters parameters) { this.parameters = parameters; @@ -59,7 +64,8 @@ namespace ikvm.debugger { client = new TcpClient(parameters.Host, parameters.Port); } - stream = new BufferedStream(client.GetStream()); + stream = client.GetStream(); //TODO Bug in BufferedStream, work not asynchron + //stream = new BufferedStream(client.GetStream()); System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] hello = encoding.GetBytes("JDWP-Handshake"); stream.Write(hello, 0, hello.Length); @@ -98,7 +104,10 @@ namespace ikvm.debugger internal void SendPacket(Packet packet) { - packet.Send(stream); + lock (writeMonitor) + { + packet.Send(stream); + } } } } diff --git a/debugger/JdwpHandler.cs b/debugger/JdwpHandler.cs index 40f2130d..49879811 100644 --- a/debugger/JdwpHandler.cs +++ b/debugger/JdwpHandler.cs @@ -233,7 +233,8 @@ namespace ikvm.debugger } else { - packet.WriteInt(packet.Id); // TODO should be EventID and not PacketID + target.AddEventRequest(eventRequest); + packet.WriteInt(eventRequest.RequestId); } break; default: diff --git a/debugger/Packet.cs b/debugger/Packet.cs index 9fd93e86..b5079303 100644 --- a/debugger/Packet.cs +++ b/debugger/Packet.cs @@ -36,21 +36,25 @@ namespace ikvm.debugger /// class Packet { - public const byte NoFlags = 0x0; - public const byte Reply = 0x80; - public const byte ReplyNoError = 0x0; + private static int packetCounter; + + private const byte NoFlags = 0x0; + private const byte Reply = 0x80; private byte[] data; private int offset; private int id; - private byte flags; private byte cmdSet; private byte cmd; private short errorCode; + private bool isEvent; private Stream output = new MemoryStream(); + /// + /// Private constructor, use the factory methods + /// private Packet() { } /// @@ -65,13 +69,13 @@ namespace ikvm.debugger Packet packet = new Packet(); packet.data = header; int len = packet.ReadInt(); - if (len < 0) + if (len < 11) { throw new IOException("protocol error - invalid length"); } packet.id = packet.ReadInt(); - packet.flags = packet.ReadByte(); - if ((packet.flags & Packet.Reply) == 0) + int flags = packet.ReadByte(); + if ((flags & Reply) == 0) { packet.cmdSet = packet.ReadByte(); packet.cmd = packet.ReadByte(); @@ -81,12 +85,29 @@ namespace ikvm.debugger packet.errorCode = packet.ReadShort(); } packet.data = new byte[len - 11]; -Console.Error.WriteLine("Data Size:" + packet.data.Length); DebuggerUtils.ReadFully(stream, packet.data); packet.offset = 0; return packet; } + /// + /// Create a empty packet to send an Event from the target VM (debuggee) to the debugger. + /// + /// a new packet + internal static Packet CreateEventPacket() + { + Packet packet = new Packet(); + packet.id = ++packetCounter; + packet.cmdSet = ikvm.debugger.CommandSet.Event; + packet.cmd = 100; + packet.isEvent = true; + return packet; + } + + /// + /// Is used from JdwpConnection. You should use jdwpConnection.Send(Packet). + /// + /// internal void Send(Stream stream) { MemoryStream ms = (MemoryStream)output; @@ -95,8 +116,17 @@ Console.Error.WriteLine("Data Size:" + packet.data.Length); output = stream; WriteInt((int)ms.Length + 11); WriteInt(id); - WriteByte(Reply); - WriteShort(errorCode); + if (!isEvent) + { + WriteByte(Reply); + WriteShort(errorCode); + } + else + { + WriteByte(NoFlags); + WriteByte(cmdSet); + WriteByte(cmd); + } ms.WriteTo(stream); } finally diff --git a/debugger/debugger.csproj b/debugger/debugger.csproj index c81e22b1..02ef4950 100644 --- a/debugger/debugger.csproj +++ b/debugger/debugger.csproj @@ -69,6 +69,7 @@ + diff --git a/debugger/win/TargetVM.cs b/debugger/win/TargetVM.cs index 4249242d..30c83086 100644 --- a/debugger/win/TargetVM.cs +++ b/debugger/win/TargetVM.cs @@ -30,6 +30,7 @@ using System.Collections; using Debugger.MetaData; using System.Windows.Forms; using Debugger.Wrappers.MetaData; +using ikvm.debugger.requests; namespace ikvm.debugger.win @@ -46,12 +47,18 @@ namespace ikvm.debugger.win private readonly Dictionary> nameTypeMap = new Dictionary>(); + private readonly JdwpEventHandler jdwpEventHandler = null; + + + private EventRequest threadStartEventRequest; + /// /// Create a new target VM for the giveb process id. /// /// Process ID of the IKVM - internal TargetVM(int pid) + internal TargetVM(int pid, JdwpEventHandler jdwpEventHandler) { + this.jdwpEventHandler = jdwpEventHandler; debugger = new NDebugger(); System.Diagnostics.Process sysProcess = System.Diagnostics.Process.GetProcessById(pid); process = debugger.Attach(sysProcess); @@ -60,7 +67,7 @@ namespace ikvm.debugger.win process.ModuleLoaded += new EventHandler(ModuleLoaded); process.Paused += new EventHandler(Paused); process.Resumed += new EventHandler(Resumed); - + process.ThreadStarted += new EventHandler(ThreadStarted); } /// @@ -171,16 +178,35 @@ namespace ikvm.debugger.win } } - void Paused(object sender, ProcessEventArgs ev) + private void Paused(object sender, ProcessEventArgs ev) { Console.Error.WriteLine("Paused:" + ev); } - void Resumed(object sender, ProcessEventArgs ev) + private void Resumed(object sender, ProcessEventArgs ev) { Console.Error.WriteLine("Resumed:" + ev); } + private void ThreadStarted(object sender, ThreadEventArgs ev) + { + EventRequest eventRequest = threadStartEventRequest; + if (eventRequest != null) + { + Thread th = ev.Thread; + jdwpEventHandler.Send(SuspendPolicy.EVENT_THREAD, EventKind.THREAD_START, eventRequest.RequestId, (int)th.ID); + ev.Thread.Exited += new EventHandler(ThreadExited); + } + Console.Error.WriteLine("ThreadStarted:" + ev.Thread.ID+ " " + eventRequest); + } + + private void ThreadExited(object sender, ThreadEventArgs ev) + { + Console.Error.WriteLine("ThreadExited:" + ev.Thread.ID); + } + + + private IList FindTypesInModules(String name) { List result = new List(); @@ -207,6 +233,18 @@ namespace ikvm.debugger.win return result; } - + /// + /// Set an EventRequest received from debugger. + /// + /// the new EventRequest + internal void AddEventRequest(ikvm.debugger.requests.EventRequest eventRequest) + { + switch (eventRequest.EventKind) + { + case EventKind.THREAD_START: + threadStartEventRequest = eventRequest; + break; + } + } } }