mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 12:30:32 +00:00
Locals window now works! (For primitive types and pointers only.) Exceptions related to unrecognised (i.e. more complex) types should be caught and display as the local variable's value instead of causing VS to crash. Autos window still causes instant VS crash. Cosmos windows works. Call Stack works (sort of...only ever displays current line) Threads works (but there is only ever 1 thread so not very helpful) Watch window is only capable of doing 1 watch result per break - step to next line to be able to run another - will look into why this is.
276 lines
9.5 KiB
C#
276 lines
9.5 KiB
C#
// DO NOT remove the following line. Should you want to get rid of read count tracking comment
|
|
// out the line. Enabling the symbol will handle a thread safe counter that tracks the count
|
|
// of pending reads on the link to the DebugStub.
|
|
// #define TRACK_PENDING
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace Cosmos.Debug.Common
|
|
{
|
|
/// <summary>Use a Stream to implement wire transfer protocol between a Debug Stub hosted in
|
|
/// a debugged Cosmos Kernel and our Debug Engine hosted in Visual Studio. This class is still
|
|
/// abstract and is further refined by sub-classes handling serial communication line or pipe
|
|
/// for example.</summary>
|
|
public abstract class DebugConnectorStream : DebugConnector
|
|
{
|
|
#if TRACK_PENDING
|
|
/// <summary>For debugging purpose we track the number of pending read operations. Should this
|
|
/// counter fail to 0, the connector should be considered stalled.</summary>
|
|
private int _pendingReadsCount = 0;
|
|
#endif
|
|
private Stream mStream;
|
|
|
|
protected class Incoming
|
|
{
|
|
public Stream Stream;
|
|
// Buffer to hold incoming message
|
|
public byte[] Packet;
|
|
// Current # of bytes in mPacket
|
|
public int CurrentPos = 0;
|
|
public Action<byte[]> Completed;
|
|
}
|
|
|
|
internal static string BytesToString(byte[] bytes, int index, int count)
|
|
{
|
|
if (count > 100)
|
|
{
|
|
return String.Empty;
|
|
}
|
|
var xSB = new StringBuilder(2 + (bytes.Length * 2));
|
|
xSB.Append("0x");
|
|
for (int i = index; i < index + count; i++)
|
|
{
|
|
xSB.Append(bytes[i].ToString("X2").ToString());
|
|
}
|
|
return xSB.ToString();
|
|
}
|
|
|
|
protected override bool SendRawData(byte[] aBytes)
|
|
{
|
|
bool OK = false;
|
|
|
|
System.Diagnostics.Debug.WriteLine(String.Format("DC - sending: {0}", BytesToString(aBytes, 0, aBytes.Length)));
|
|
if (mStream != null)
|
|
{
|
|
mStream.Write(aBytes, 0, aBytes.Length);
|
|
OK = true;
|
|
}
|
|
else
|
|
{
|
|
DoDebugMsg("Error! mStream is null! Cannot send data! Is the debugger shutting down?");
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
public override bool IsConnected
|
|
{
|
|
get { return mStream != null; }
|
|
}
|
|
|
|
// Start is not in ctor, because for servers we have to wait for the callback. This
|
|
// however does not prevent other kind of DebugConnectorStream descendants from
|
|
// invoking this method from their constructor.
|
|
protected void Start(Stream aStream)
|
|
{
|
|
DoConnected();
|
|
mStream = aStream;
|
|
Next(1, WaitForSignature);
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
if (mStream != null)
|
|
{
|
|
mStream.Close();
|
|
mStream = null;
|
|
}
|
|
base.Dispose();
|
|
}
|
|
|
|
protected Action<byte[]> mCompletedAfterSize; // Action to call after size received
|
|
protected void SizePacket(byte[] aPacket)
|
|
{
|
|
int xSize = aPacket[0] + (aPacket[1] << 8);
|
|
Next(xSize, mCompletedAfterSize);
|
|
}
|
|
|
|
protected override void Next(int aPacketSize, Action<byte[]> aCompleted)
|
|
{
|
|
var xIncoming = new Incoming();
|
|
if (aPacketSize == 0)
|
|
{
|
|
// Can occur with variable size packets for exampmle.
|
|
// Dont call read, becuase that will close the stream.
|
|
// So we just call the Completed directly
|
|
aCompleted(new byte[0]);
|
|
}
|
|
else if (aPacketSize == -1)
|
|
{
|
|
// Variable size packet, split into two reads
|
|
mCompletedAfterSize = aCompleted;
|
|
aPacketSize = 2;
|
|
xIncoming.Completed = SizePacket;
|
|
}
|
|
else
|
|
{
|
|
xIncoming.Completed = aCompleted;
|
|
}
|
|
xIncoming.Packet = new byte[aPacketSize];
|
|
xIncoming.Stream = mStream;
|
|
|
|
System.Diagnostics.Debug.WriteLine(String.Format("DC - Next: Expecting: {0}", aPacketSize));
|
|
|
|
Read(xIncoming);
|
|
|
|
#if TRACK_PENDING
|
|
try {
|
|
Interlocked.Increment(ref _pendingReadsCount);
|
|
#endif
|
|
//mStream.BeginRead(xIncoming.Packet, 0, aPacketSize, new AsyncCallback(DoRead), xIncoming);
|
|
#if TRACK_PENDING
|
|
}
|
|
catch (Exception e) {
|
|
Interlocked.Decrement(ref _pendingReadsCount);
|
|
throw;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
protected void DoRead(IAsyncResult aResult)
|
|
{
|
|
try
|
|
{
|
|
var xIncoming = (Incoming)aResult.AsyncState;
|
|
int xCount = xIncoming.Stream.EndRead(aResult);
|
|
|
|
System.Diagnostics.Debug.WriteLine(String.Format("DC - Received: {0}", BytesToString(xIncoming.Packet, xIncoming.CurrentPos, xCount)));
|
|
xIncoming.CurrentPos += xCount;
|
|
if (xCount == 0)
|
|
{
|
|
// If 0, end of stream then just exit without calling BeginRead again
|
|
return;
|
|
}
|
|
else if (xIncoming.CurrentPos < xIncoming.Packet.Length)
|
|
{
|
|
// Packet is not full yet, read more data
|
|
#if TRACK_PENDING
|
|
try {
|
|
Interlocked.Increment(ref _pendingReadsCount);
|
|
#endif
|
|
xIncoming.Stream.BeginRead(xIncoming.Packet, xIncoming.CurrentPos
|
|
, xIncoming.Packet.Length - xIncoming.CurrentPos
|
|
, new AsyncCallback(DoRead), xIncoming);
|
|
#if TRACK_PENDING
|
|
}
|
|
catch (Exception e) {
|
|
Interlocked.Decrement(ref _pendingReadsCount);
|
|
throw;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.WriteLine(String.Format("DC - Full packet received - Received: {0}", BytesToString(xIncoming.Packet, 0, xIncoming.Packet.Length)));
|
|
|
|
// Full packet received, process it
|
|
xIncoming.Completed(xIncoming.Packet);
|
|
}
|
|
}
|
|
catch (System.IO.IOException ex)
|
|
{
|
|
ConnectionLost(ex);
|
|
}
|
|
#if TRACK_PENDING
|
|
finally {
|
|
Interlocked.Decrement(ref _pendingReadsCount);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private List<Incoming> ReadQueue = new List<Incoming>();
|
|
private bool reading = false;
|
|
|
|
private void Read(Incoming packet)
|
|
{
|
|
//lock (ReadQueue)
|
|
{
|
|
ReadQueue.Add(packet);
|
|
}
|
|
ContinueRead();
|
|
}
|
|
private void ContinueRead()
|
|
{
|
|
if(ReadQueue.Count > 0 && !reading)
|
|
{
|
|
reading = true;
|
|
|
|
Incoming next = ReadQueue[0];
|
|
if (mStream == null)
|
|
{
|
|
DoDebugMsg("Error! mStream is null! Cannot read data! Is the debugger shutting down?");
|
|
}
|
|
else
|
|
{
|
|
mStream.BeginRead(next.Packet, next.CurrentPos, next.Packet.Length - next.CurrentPos, new AsyncCallback(DoRead2), next);
|
|
}
|
|
}
|
|
}
|
|
private void DoRead2(IAsyncResult result)
|
|
{
|
|
try
|
|
{
|
|
Incoming xIncoming = (Incoming)result.AsyncState;
|
|
int xCount = mStream.EndRead(result);
|
|
|
|
System.Diagnostics.Debug.WriteLine(String.Format("DC DR2 - Received: {0}", BytesToString(xIncoming.Packet, xIncoming.CurrentPos, xCount)));
|
|
xIncoming.CurrentPos += xCount;
|
|
if (xCount == 0)
|
|
{
|
|
// If 0, end of stream then just exit without calling BeginRead again
|
|
reading = false;
|
|
|
|
// lock (ReadQueue)
|
|
{
|
|
ReadQueue.Remove(xIncoming);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if (xIncoming.CurrentPos < xIncoming.Packet.Length)
|
|
{
|
|
// Packet is not full yet, read more data
|
|
//Do nothing
|
|
}
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.WriteLine(String.Format("DC DR2 - Full packet received - Received: {0}", BytesToString(xIncoming.Packet, 0, xIncoming.Packet.Length)));
|
|
|
|
//lock (ReadQueue)
|
|
{
|
|
ReadQueue.Remove(xIncoming);
|
|
}
|
|
|
|
// Full packet received, process it
|
|
xIncoming.Completed.BeginInvoke(xIncoming.Packet, new AsyncCallback((IAsyncResult bResult) =>
|
|
{
|
|
((Incoming)(bResult.AsyncState)).Completed.EndInvoke(bResult);
|
|
}), xIncoming);
|
|
}
|
|
|
|
reading = false;
|
|
|
|
ContinueRead();
|
|
}
|
|
catch (System.IO.IOException ex)
|
|
{
|
|
reading = false;
|
|
|
|
ConnectionLost(ex);
|
|
}
|
|
}
|
|
}
|
|
}
|