handling the first debuggee event (ThreadStart)

This commit is contained in:
smallsql 2009-02-22 09:09:41 +00:00
Родитель 8ffc7143ee
Коммит 291c094215
7 изменённых файлов: 139 добавлений и 46 удалений

Просмотреть файл

@ -66,7 +66,7 @@ namespace ikvm.debugger
JdwpConnection conn = new JdwpConnection(parameters); JdwpConnection conn = new JdwpConnection(parameters);
conn.Connect(); conn.Connect();
Console.Error.WriteLine("Started"); Console.Error.WriteLine("Started");
TargetVM target = new TargetVM(pid); TargetVM target = new TargetVM(pid, new JdwpEventHandler(conn));
JdwpHandler handler = new JdwpHandler(conn, target); JdwpHandler handler = new JdwpHandler(conn, target);
handler.Run(); handler.Run();
//System.Threading.Thread.Sleep(5000); //System.Threading.Thread.Sleep(5000);

Просмотреть файл

@ -36,15 +36,19 @@ namespace ikvm.debugger.requests
internal const int CmdClear = 2; internal const int CmdClear = 2;
internal const int CmdClearAllBreakpoints = 3; internal const int CmdClearAllBreakpoints = 3;
private byte eventKind; private static int eventRequestCounter;
private byte suspendPolicy;
private List<EventModifier> modifiers; private readonly byte eventKind;
private readonly byte suspendPolicy;
private readonly List<EventModifier> modifiers;
private readonly int requestId;
private EventRequest(byte eventKind, byte suspendPolicy, List<EventModifier> modifiers) private EventRequest(byte eventKind, byte suspendPolicy, List<EventModifier> modifiers)
{ {
this.eventKind = eventKind; this.eventKind = eventKind;
this.suspendPolicy = suspendPolicy; this.suspendPolicy = suspendPolicy;
this.modifiers = modifiers; this.modifiers = modifiers;
this.requestId = ++eventRequestCounter;
} }
/// <summary> /// <summary>
@ -57,29 +61,29 @@ namespace ikvm.debugger.requests
byte eventKind = packet.ReadByte(); // class EventKind byte eventKind = packet.ReadByte(); // class EventKind
switch (eventKind) switch (eventKind)
{ {
case EventKind.SINGLE_STEP: case ikvm.debugger.EventKind.SINGLE_STEP:
case EventKind.BREAKPOINT: case ikvm.debugger.EventKind.BREAKPOINT:
case EventKind.FRAME_POP: case ikvm.debugger.EventKind.FRAME_POP:
case EventKind.EXCEPTION: case ikvm.debugger.EventKind.EXCEPTION:
case EventKind.USER_DEFINED: case ikvm.debugger.EventKind.USER_DEFINED:
case EventKind.THREAD_START: case ikvm.debugger.EventKind.THREAD_START:
case EventKind.THREAD_DEATH: case ikvm.debugger.EventKind.THREAD_DEATH:
case EventKind.CLASS_PREPARE: case ikvm.debugger.EventKind.CLASS_PREPARE:
case EventKind.CLASS_UNLOAD: case ikvm.debugger.EventKind.CLASS_UNLOAD:
case EventKind.CLASS_LOAD: case ikvm.debugger.EventKind.CLASS_LOAD:
case EventKind.FIELD_ACCESS: case ikvm.debugger.EventKind.FIELD_ACCESS:
case EventKind.FIELD_MODIFICATION: case ikvm.debugger.EventKind.FIELD_MODIFICATION:
case EventKind.EXCEPTION_CATCH: case ikvm.debugger.EventKind.EXCEPTION_CATCH:
case EventKind.METHOD_ENTRY: case ikvm.debugger.EventKind.METHOD_ENTRY:
case EventKind.METHOD_EXIT: case ikvm.debugger.EventKind.METHOD_EXIT:
case EventKind.METHOD_EXIT_WITH_RETURN_VALUE: case ikvm.debugger.EventKind.METHOD_EXIT_WITH_RETURN_VALUE:
case EventKind.MONITOR_CONTENDED_ENTER: case ikvm.debugger.EventKind.MONITOR_CONTENDED_ENTER:
case EventKind.MONITOR_CONTENDED_ENTERED: case ikvm.debugger.EventKind.MONITOR_CONTENDED_ENTERED:
case EventKind.MONITOR_WAIT: case ikvm.debugger.EventKind.MONITOR_WAIT:
case EventKind.MONITOR_WAITED: case ikvm.debugger.EventKind.MONITOR_WAITED:
case EventKind.VM_START: case ikvm.debugger.EventKind.VM_START:
case EventKind.VM_DEATH: case ikvm.debugger.EventKind.VM_DEATH:
case EventKind.VM_DISCONNECTED: case ikvm.debugger.EventKind.VM_DISCONNECTED:
break; break;
default: default:
return null; //Invalid or not supported EventKind return null; //Invalid or not supported EventKind
@ -139,6 +143,16 @@ namespace ikvm.debugger.requests
return new EventRequest(eventKind, suspendPolicy, modifiers); return new EventRequest(eventKind, suspendPolicy, modifiers);
} }
internal int RequestId
{
get { return requestId; }
}
internal int EventKind
{
get { return eventKind; }
}
public override String ToString() public override String ToString()
{ {
//for debugging //for debugging

Просмотреть файл

@ -36,10 +36,15 @@ namespace ikvm.debugger
private TcpClient client; private TcpClient client;
BufferedStream stream; Stream stream;
/// <summary>
/// Shared buffer for reading and monitor for reading
/// </summary>
private readonly byte[] readHeader = new byte[11]; private readonly byte[] readHeader = new byte[11];
private readonly Object writeMonitor = new Object();
internal JdwpConnection(JdwpParameters parameters) internal JdwpConnection(JdwpParameters parameters)
{ {
this.parameters = parameters; this.parameters = parameters;
@ -59,7 +64,8 @@ namespace ikvm.debugger
{ {
client = new TcpClient(parameters.Host, parameters.Port); 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(); System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] hello = encoding.GetBytes("JDWP-Handshake"); byte[] hello = encoding.GetBytes("JDWP-Handshake");
stream.Write(hello, 0, hello.Length); stream.Write(hello, 0, hello.Length);
@ -98,7 +104,10 @@ namespace ikvm.debugger
internal void SendPacket(Packet packet) internal void SendPacket(Packet packet)
{ {
packet.Send(stream); lock (writeMonitor)
{
packet.Send(stream);
}
} }
} }
} }

Просмотреть файл

@ -233,7 +233,8 @@ namespace ikvm.debugger
} }
else else
{ {
packet.WriteInt(packet.Id); // TODO should be EventID and not PacketID target.AddEventRequest(eventRequest);
packet.WriteInt(eventRequest.RequestId);
} }
break; break;
default: default:

Просмотреть файл

@ -36,21 +36,25 @@ namespace ikvm.debugger
/// </summary> /// </summary>
class Packet class Packet
{ {
public const byte NoFlags = 0x0; private static int packetCounter;
public const byte Reply = 0x80;
public const byte ReplyNoError = 0x0; private const byte NoFlags = 0x0;
private const byte Reply = 0x80;
private byte[] data; private byte[] data;
private int offset; private int offset;
private int id; private int id;
private byte flags;
private byte cmdSet; private byte cmdSet;
private byte cmd; private byte cmd;
private short errorCode; private short errorCode;
private bool isEvent;
private Stream output = new MemoryStream(); private Stream output = new MemoryStream();
/// <summary>
/// Private constructor, use the factory methods
/// </summary>
private Packet() { } private Packet() { }
/// <summary> /// <summary>
@ -65,13 +69,13 @@ namespace ikvm.debugger
Packet packet = new Packet(); Packet packet = new Packet();
packet.data = header; packet.data = header;
int len = packet.ReadInt(); int len = packet.ReadInt();
if (len < 0) if (len < 11)
{ {
throw new IOException("protocol error - invalid length"); throw new IOException("protocol error - invalid length");
} }
packet.id = packet.ReadInt(); packet.id = packet.ReadInt();
packet.flags = packet.ReadByte(); int flags = packet.ReadByte();
if ((packet.flags & Packet.Reply) == 0) if ((flags & Reply) == 0)
{ {
packet.cmdSet = packet.ReadByte(); packet.cmdSet = packet.ReadByte();
packet.cmd = packet.ReadByte(); packet.cmd = packet.ReadByte();
@ -81,12 +85,29 @@ namespace ikvm.debugger
packet.errorCode = packet.ReadShort(); packet.errorCode = packet.ReadShort();
} }
packet.data = new byte[len - 11]; packet.data = new byte[len - 11];
Console.Error.WriteLine("Data Size:" + packet.data.Length);
DebuggerUtils.ReadFully(stream, packet.data); DebuggerUtils.ReadFully(stream, packet.data);
packet.offset = 0; packet.offset = 0;
return packet; return packet;
} }
/// <summary>
/// Create a empty packet to send an Event from the target VM (debuggee) to the debugger.
/// </summary>
/// <returns>a new packet</returns>
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;
}
/// <summary>
/// Is used from JdwpConnection. You should use jdwpConnection.Send(Packet).
/// </summary>
/// <param name="stream"></param>
internal void Send(Stream stream) internal void Send(Stream stream)
{ {
MemoryStream ms = (MemoryStream)output; MemoryStream ms = (MemoryStream)output;
@ -95,8 +116,17 @@ Console.Error.WriteLine("Data Size:" + packet.data.Length);
output = stream; output = stream;
WriteInt((int)ms.Length + 11); WriteInt((int)ms.Length + 11);
WriteInt(id); WriteInt(id);
WriteByte(Reply); if (!isEvent)
WriteShort(errorCode); {
WriteByte(Reply);
WriteShort(errorCode);
}
else
{
WriteByte(NoFlags);
WriteByte(cmdSet);
WriteByte(cmd);
}
ms.WriteTo(stream); ms.WriteTo(stream);
} }
finally finally

Просмотреть файл

@ -69,6 +69,7 @@
<Compile Include="EventRequest.cs" /> <Compile Include="EventRequest.cs" />
<Compile Include="JdwpConnection.cs" /> <Compile Include="JdwpConnection.cs" />
<Compile Include="JdwpConst.cs" /> <Compile Include="JdwpConst.cs" />
<Compile Include="JdwpEventHandler.cs" />
<Compile Include="JdwpHandler.cs" /> <Compile Include="JdwpHandler.cs" />
<Compile Include="JdwpParameters.cs" /> <Compile Include="JdwpParameters.cs" />
<Compile Include="Packet.cs" /> <Compile Include="Packet.cs" />

Просмотреть файл

@ -30,6 +30,7 @@ using System.Collections;
using Debugger.MetaData; using Debugger.MetaData;
using System.Windows.Forms; using System.Windows.Forms;
using Debugger.Wrappers.MetaData; using Debugger.Wrappers.MetaData;
using ikvm.debugger.requests;
namespace ikvm.debugger.win namespace ikvm.debugger.win
@ -46,12 +47,18 @@ namespace ikvm.debugger.win
private readonly Dictionary<String, IList<TargetType>> nameTypeMap = new Dictionary<String, IList<TargetType>>(); private readonly Dictionary<String, IList<TargetType>> nameTypeMap = new Dictionary<String, IList<TargetType>>();
private readonly JdwpEventHandler jdwpEventHandler = null;
private EventRequest threadStartEventRequest;
/// <summary> /// <summary>
/// Create a new target VM for the giveb process id. /// Create a new target VM for the giveb process id.
/// </summary> /// </summary>
/// <param name="pid">Process ID of the IKVM</param> /// <param name="pid">Process ID of the IKVM</param>
internal TargetVM(int pid) internal TargetVM(int pid, JdwpEventHandler jdwpEventHandler)
{ {
this.jdwpEventHandler = jdwpEventHandler;
debugger = new NDebugger(); debugger = new NDebugger();
System.Diagnostics.Process sysProcess = System.Diagnostics.Process.GetProcessById(pid); System.Diagnostics.Process sysProcess = System.Diagnostics.Process.GetProcessById(pid);
process = debugger.Attach(sysProcess); process = debugger.Attach(sysProcess);
@ -60,7 +67,7 @@ namespace ikvm.debugger.win
process.ModuleLoaded += new EventHandler<ModuleEventArgs>(ModuleLoaded); process.ModuleLoaded += new EventHandler<ModuleEventArgs>(ModuleLoaded);
process.Paused += new EventHandler<ProcessEventArgs>(Paused); process.Paused += new EventHandler<ProcessEventArgs>(Paused);
process.Resumed += new EventHandler<ProcessEventArgs>(Resumed); process.Resumed += new EventHandler<ProcessEventArgs>(Resumed);
process.ThreadStarted += new EventHandler<ThreadEventArgs>(ThreadStarted);
} }
/// <summary> /// <summary>
@ -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); Console.Error.WriteLine("Paused:" + ev);
} }
void Resumed(object sender, ProcessEventArgs ev) private void Resumed(object sender, ProcessEventArgs ev)
{ {
Console.Error.WriteLine("Resumed:" + 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<ThreadEventArgs>(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<DebugType> FindTypesInModules(String name) private IList<DebugType> FindTypesInModules(String name)
{ {
List<DebugType> result = new List<DebugType>(); List<DebugType> result = new List<DebugType>();
@ -207,6 +233,18 @@ namespace ikvm.debugger.win
return result; return result;
} }
/// <summary>
/// Set an EventRequest received from debugger.
/// </summary>
/// <param name="eventRequest">the new EventRequest</param>
internal void AddEventRequest(ikvm.debugger.requests.EventRequest eventRequest)
{
switch (eventRequest.EventKind)
{
case EventKind.THREAD_START:
threadStartEventRequest = eventRequest;
break;
}
}
} }
} }