Basic debugger networking.

This commit is contained in:
Ben Vanik
2015-05-23 22:27:43 -07:00
parent 969badd8c3
commit 576d6492dc
51 changed files with 1745 additions and 162 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,16 +7,26 @@ using System.Threading.Tasks;
using Xenia.Debug.Utilities;
namespace Xenia.Debug {
public class BreakpointList : Changeable {
public class BreakpointList : Changeable, IReadOnlyCollection<Breakpoint> {
private readonly Debugger debugger;
private readonly List<Breakpoint> breakpoints = new List<Breakpoint>();
public void Add(Breakpoint breakpoint) {
public BreakpointList(Debugger debugger) {
this.debugger = debugger;
}
public void Remove(Breakpoint breakpoint) {
public int Count {
get {
return breakpoints.Count;
}
}
public void Clear() {
public IEnumerator<Breakpoint> GetEnumerator() {
return breakpoints.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return breakpoints.GetEnumerator();
}
}
}

View File

@@ -1,10 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Xenia.Debug {
public class DebugClient {
}
}

View File

@@ -1,15 +1,47 @@
using System;
using FlatBuffers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using xe.debug.proto;
using Xenia.Debug.Utilities;
namespace Xenia.Debug {
public class Debugger {
public DebugClient DebugClient {
get;
private readonly static string kServerHostname = "";
private readonly static int kServerPort = 19000;
public enum State {
Idle,
Attaching,
Attached,
Detached,
}
private class PendingRequest {
public uint requestId;
public ByteBuffer byteBuffer;
public TaskCompletionSource<Response> responseTask;
}
private Socket socket;
private readonly ConcurrentDictionary<uint, PendingRequest>
pendingRequests = new ConcurrentDictionary<uint, PendingRequest>();
private uint nextRequestId = 1;
public event EventHandler<State> StateChanged;
public State CurrentState {
get; private set;
}
= State.Idle;
public BreakpointList BreakpointList {
get;
}
@@ -25,28 +57,187 @@ namespace Xenia.Debug {
public ThreadList ThreadList {
get;
}
public Debugger() {
this.DebugClient = new DebugClient();
this.BreakpointList = new BreakpointList();
this.FunctionList = new FunctionList();
this.Memory = new Memory();
this.ModuleList = new ModuleList();
this.ThreadList = new ThreadList();
public Debugger(AsyncTaskRunner asyncTaskRunner) {
Dispatch.AsyncTaskRunner = asyncTaskRunner;
this.BreakpointList = new BreakpointList(this);
this.FunctionList = new FunctionList(this);
this.Memory = new Memory(this);
this.ModuleList = new ModuleList(this);
this.ThreadList = new ThreadList(this);
}
public bool Open() {
return true;
public Task Attach() {
return Attach(CancellationToken.None);
}
public delegate void ChangedEventHandler(EventArgs e);
public async Task Attach(CancellationToken cancellationToken) {
System.Diagnostics.Debug.Assert(CurrentState == State.Idle);
public event ChangedEventHandler Changed;
SocketPermission permission = new SocketPermission(
NetworkAccess.Connect,
TransportType.Tcp,
kServerHostname,
kServerPort
);
permission.Demand();
private void OnChanged(EventArgs e) {
if (Changed != null) {
Changed(e);
IPAddress ipAddress = new IPAddress(new byte[] { 127, 0, 0, 1 });
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, kServerPort);
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
socket.Blocking = false;
socket.NoDelay = true;
socket.ReceiveBufferSize = 1024 * 1024;
socket.SendBufferSize = 1024 * 1024;
socket.ReceiveTimeout = 0;
socket.SendTimeout = 0;
OnStateChanged(State.Attaching);
while (true) {
Task task = Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, ipEndPoint, null);
try {
await task.WithCancellation(cancellationToken);
} catch (OperationCanceledException) {
socket.Close();
socket = null;
OnStateChanged(State.Idle);
return;
} catch (SocketException e) {
if (e.SocketErrorCode == SocketError.ConnectionRefused) {
// Not found - emulator may still be starting.
System.Diagnostics.Debug.WriteLine("Connection refused; trying again...");
continue;
}
OnStateChanged(State.Idle);
return;
}
break;
}
// Start recv pump.
Dispatch.Issue(() => ReceivePump());
var fbb = BeginRequest();
AttachRequest.StartAttachRequest(fbb);
int requestDataOffset = AttachRequest.EndAttachRequest(fbb);
var response = await CommitRequest(fbb, RequestData.AttachRequest, requestDataOffset);
OnStateChanged(State.Attached);
}
public void Detach() {
if (CurrentState == State.Idle || CurrentState == State.Detached) {
return;
}
socket.Close();
socket = null;
OnStateChanged(State.Detached);
}
private async void ReceivePump() {
// Read length.
var lengthBuffer = new byte[4];
int receiveLength;
try {
receiveLength = await Task.Factory.FromAsync(
(callback, state) => socket.BeginReceive(lengthBuffer, 0, lengthBuffer.Length,
SocketFlags.None, callback, state),
asyncResult => socket.EndReceive(asyncResult), null);
} catch (SocketException) {
System.Diagnostics.Debug.WriteLine("Socket read error; detaching");
Detach();
return;
}
if (receiveLength == 0 || receiveLength != 4) {
// Failed?
ReceivePump();
return;
}
var length = BitConverter.ToInt32(lengthBuffer, 0);
// Read body.
var bodyBuffer = new byte[length];
receiveLength = await Task.Factory.FromAsync(
(callback, state) => socket.BeginReceive(bodyBuffer, 0, bodyBuffer.Length, SocketFlags.None, callback, state),
asyncResult => socket.EndReceive(asyncResult),
null);
if (receiveLength == 0 || receiveLength != bodyBuffer.Length) {
// Failed?
ReceivePump();
return;
}
// Emit message.
OnMessageReceived(bodyBuffer);
// Continue pumping.
Dispatch.Issue(() => ReceivePump());
}
private void OnMessageReceived(byte[] buffer) {
ByteBuffer byteBuffer = new ByteBuffer(buffer);
var response = Response.GetRootAsResponse(byteBuffer);
if (response.Id != 0) {
// Response.
PendingRequest pendingRequest;
if (!pendingRequests.TryRemove(response.Id, out pendingRequest)) {
System.Diagnostics.Debug.WriteLine("Unexpected message from debug server?");
return;
}
pendingRequest.byteBuffer = byteBuffer;
pendingRequest.responseTask.SetResult(response);
} else {
// Event.
// TODO(benvanik): events.
}
}
public FlatBufferBuilder BeginRequest() {
var fbb = new FlatBufferBuilder(32 * 1024);
return fbb;
}
public async Task<Response> CommitRequest(FlatBufferBuilder fbb,
RequestData requestDataType,
int requestDataOffset) {
PendingRequest request = new PendingRequest();
request.requestId = nextRequestId++;
request.responseTask = new TaskCompletionSource<Response>();
pendingRequests.TryAdd(request.requestId, request);
int requestOffset =
Request.CreateRequest(fbb, request.requestId,
requestDataType, requestDataOffset);
fbb.Finish(requestOffset);
// Update the placeholder size.
int bufferOffset = fbb.DataBuffer.Position;
int bufferLength = fbb.DataBuffer.Length - fbb.DataBuffer.Position;
fbb.DataBuffer.PutInt(bufferOffset - 4, bufferLength);
// Send request.
await socket.SendTaskAsync(fbb.DataBuffer.Data, bufferOffset - 4,
bufferLength + 4, SocketFlags.None);
// Await response.
var response = await request.responseTask.Task;
return response;
}
private void OnStateChanged(State newState) {
if (newState == CurrentState) {
return;
}
CurrentState = newState;
if (StateChanged != null) {
StateChanged(this, newState);
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,6 +7,26 @@ using System.Threading.Tasks;
using Xenia.Debug.Utilities;
namespace Xenia.Debug {
public class FunctionList : Changeable {
public class FunctionList : Changeable, IReadOnlyCollection<Function> {
private readonly Debugger debugger;
private readonly List<Function> functions = new List<Function>();
public FunctionList(Debugger debugger) {
this.debugger = debugger;
}
public int Count {
get {
return functions.Count;
}
}
public IEnumerator<Function> GetEnumerator() {
return functions.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return functions.GetEnumerator();
}
}
}

View File

@@ -7,6 +7,12 @@ using Xenia.Debug.Utilities;
namespace Xenia.Debug {
public class Memory : Changeable {
private readonly Debugger debugger;
public Memory(Debugger debugger) {
this.debugger = debugger;
}
public MemoryView CreateView() {
return new MemoryView(this);
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,6 +7,26 @@ using System.Threading.Tasks;
using Xenia.Debug.Utilities;
namespace Xenia.Debug {
public class ModuleList : Changeable {
public class ModuleList : Changeable, IReadOnlyCollection<Module> {
private readonly Debugger debugger;
private readonly List<Module> modules = new List<Module>();
public ModuleList(Debugger debugger) {
this.debugger = debugger;
}
public int Count {
get {
return modules.Count;
}
}
public IEnumerator<Module> GetEnumerator() {
return modules.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return modules.GetEnumerator();
}
}
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class AddBreakpointRequest : Table {
public static AddBreakpointRequest GetRootAsAddBreakpointRequest(ByteBuffer _bb) { return GetRootAsAddBreakpointRequest(_bb, new AddBreakpointRequest()); }
public static AddBreakpointRequest GetRootAsAddBreakpointRequest(ByteBuffer _bb, AddBreakpointRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public AddBreakpointRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartAddBreakpointRequest(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndAddBreakpointRequest(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class AddBreakpointResponse : Table {
public static AddBreakpointResponse GetRootAsAddBreakpointResponse(ByteBuffer _bb) { return GetRootAsAddBreakpointResponse(_bb, new AddBreakpointResponse()); }
public static AddBreakpointResponse GetRootAsAddBreakpointResponse(ByteBuffer _bb, AddBreakpointResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public AddBreakpointResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartAddBreakpointResponse(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndAddBreakpointResponse(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class AttachRequest : Table {
public static AttachRequest GetRootAsAttachRequest(ByteBuffer _bb) { return GetRootAsAttachRequest(_bb, new AttachRequest()); }
public static AttachRequest GetRootAsAttachRequest(ByteBuffer _bb, AttachRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public AttachRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartAttachRequest(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndAttachRequest(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class AttachResponse : Table {
public static AttachResponse GetRootAsAttachResponse(ByteBuffer _bb) { return GetRootAsAttachResponse(_bb, new AttachResponse()); }
public static AttachResponse GetRootAsAttachResponse(ByteBuffer _bb, AttachResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public AttachResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartAttachResponse(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndAttachResponse(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,13 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
public enum Foo : sbyte
{
A = 1,
B = 2,
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class ListBreakpointsRequest : Table {
public static ListBreakpointsRequest GetRootAsListBreakpointsRequest(ByteBuffer _bb) { return GetRootAsListBreakpointsRequest(_bb, new ListBreakpointsRequest()); }
public static ListBreakpointsRequest GetRootAsListBreakpointsRequest(ByteBuffer _bb, ListBreakpointsRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public ListBreakpointsRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartListBreakpointsRequest(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndListBreakpointsRequest(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class ListBreakpointsResponse : Table {
public static ListBreakpointsResponse GetRootAsListBreakpointsResponse(ByteBuffer _bb) { return GetRootAsListBreakpointsResponse(_bb, new ListBreakpointsResponse()); }
public static ListBreakpointsResponse GetRootAsListBreakpointsResponse(ByteBuffer _bb, ListBreakpointsResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public ListBreakpointsResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartListBreakpointsResponse(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndListBreakpointsResponse(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class RemoveBreakpointRequest : Table {
public static RemoveBreakpointRequest GetRootAsRemoveBreakpointRequest(ByteBuffer _bb) { return GetRootAsRemoveBreakpointRequest(_bb, new RemoveBreakpointRequest()); }
public static RemoveBreakpointRequest GetRootAsRemoveBreakpointRequest(ByteBuffer _bb, RemoveBreakpointRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public RemoveBreakpointRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartRemoveBreakpointRequest(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndRemoveBreakpointRequest(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class RemoveBreakpointResponse : Table {
public static RemoveBreakpointResponse GetRootAsRemoveBreakpointResponse(ByteBuffer _bb) { return GetRootAsRemoveBreakpointResponse(_bb, new RemoveBreakpointResponse()); }
public static RemoveBreakpointResponse GetRootAsRemoveBreakpointResponse(ByteBuffer _bb, RemoveBreakpointResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public RemoveBreakpointResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartRemoveBreakpointResponse(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndRemoveBreakpointResponse(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,39 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class Request : Table {
public static Request GetRootAsRequest(ByteBuffer _bb) { return GetRootAsRequest(_bb, new Request()); }
public static Request GetRootAsRequest(ByteBuffer _bb, Request obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public Request __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public uint Id { get { int o = __offset(4); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
public RequestData RequestDataType { get { int o = __offset(6); return o != 0 ? (RequestData)bb.Get(o + bb_pos) : (RequestData)0; } }
public Table GetRequestData(Table obj) { int o = __offset(8); return o != 0 ? __union(obj, o) : null; }
public static int CreateRequest(FlatBufferBuilder builder,
uint id = 0,
RequestData request_data_type = 0,
int request_data = 0) {
builder.StartObject(3);
Request.AddRequestData(builder, request_data);
Request.AddId(builder, id);
Request.AddRequestDataType(builder, request_data_type);
return Request.EndRequest(builder);
}
public static void StartRequest(FlatBufferBuilder builder) { builder.StartObject(3); }
public static void AddId(FlatBufferBuilder builder, uint id) { builder.AddUint(0, id, 0); }
public static void AddRequestDataType(FlatBufferBuilder builder, RequestData requestDataType) { builder.AddByte(1, (byte)(requestDataType), 0); }
public static void AddRequestData(FlatBufferBuilder builder, int requestDataOffset) { builder.AddOffset(2, requestDataOffset, 0); }
public static int EndRequest(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,17 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
public enum RequestData : byte
{
NONE = 0,
AttachRequest = 1,
ListBreakpointsRequest = 2,
AddBreakpointRequest = 3,
UpdateBreakpointRequest = 4,
RemoveBreakpointRequest = 5,
};
}

View File

@@ -0,0 +1,39 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class Response : Table {
public static Response GetRootAsResponse(ByteBuffer _bb) { return GetRootAsResponse(_bb, new Response()); }
public static Response GetRootAsResponse(ByteBuffer _bb, Response obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public Response __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public uint Id { get { int o = __offset(4); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
public ResponseData ResponseDataType { get { int o = __offset(6); return o != 0 ? (ResponseData)bb.Get(o + bb_pos) : (ResponseData)0; } }
public Table GetResponseData(Table obj) { int o = __offset(8); return o != 0 ? __union(obj, o) : null; }
public static int CreateResponse(FlatBufferBuilder builder,
uint id = 0,
ResponseData response_data_type = 0,
int response_data = 0) {
builder.StartObject(3);
Response.AddResponseData(builder, response_data);
Response.AddId(builder, id);
Response.AddResponseDataType(builder, response_data_type);
return Response.EndResponse(builder);
}
public static void StartResponse(FlatBufferBuilder builder) { builder.StartObject(3); }
public static void AddId(FlatBufferBuilder builder, uint id) { builder.AddUint(0, id, 0); }
public static void AddResponseDataType(FlatBufferBuilder builder, ResponseData responseDataType) { builder.AddByte(1, (byte)(responseDataType), 0); }
public static void AddResponseData(FlatBufferBuilder builder, int responseDataOffset) { builder.AddOffset(2, responseDataOffset, 0); }
public static int EndResponse(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,17 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
public enum ResponseData : byte
{
NONE = 0,
AttachResponse = 1,
ListBreakpointsResponse = 2,
AddBreakpointResponse = 3,
UpdateBreakpointResponse = 4,
RemoveBreakpointResponse = 5,
};
}

View File

@@ -0,0 +1,25 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class StructTest : Struct {
public StructTest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public short A { get { return bb.GetShort(bb_pos + 0); } }
public sbyte B { get { return bb.GetSbyte(bb_pos + 2); } }
public Foo C { get { return (Foo)bb.GetSbyte(bb_pos + 3); } }
public static int CreateStructTest(FlatBufferBuilder builder, short A, sbyte B, Foo C) {
builder.Prep(2, 4);
builder.PutSbyte((sbyte)(C));
builder.PutSbyte(B);
builder.PutShort(A);
return builder.Offset;
}
};
}

View File

@@ -0,0 +1,35 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class TableTest : Table {
public static TableTest GetRootAsTableTest(ByteBuffer _bb) { return GetRootAsTableTest(_bb, new TableTest()); }
public static TableTest GetRootAsTableTest(ByteBuffer _bb, TableTest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public TableTest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public StructTest St { get { return GetSt(new StructTest()); } }
public StructTest GetSt(StructTest obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
public byte GetIv(int j) { int o = __offset(6); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
public int IvLength { get { int o = __offset(6); return o != 0 ? __vector_len(o) : 0; } }
public string Name { get { int o = __offset(8); return o != 0 ? __string(o + bb_pos) : null; } }
public uint Id { get { int o = __offset(10); return o != 0 ? bb.GetUint(o + bb_pos) : (uint)0; } }
public static void StartTableTest(FlatBufferBuilder builder) { builder.StartObject(4); }
public static void AddSt(FlatBufferBuilder builder, int stOffset) { builder.AddStruct(0, stOffset, 0); }
public static void AddIv(FlatBufferBuilder builder, int ivOffset) { builder.AddOffset(1, ivOffset, 0); }
public static int CreateIvVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
public static void StartIvVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
public static void AddName(FlatBufferBuilder builder, int nameOffset) { builder.AddOffset(2, nameOffset, 0); }
public static void AddId(FlatBufferBuilder builder, uint id) { builder.AddUint(3, id, 0); }
public static int EndTableTest(FlatBufferBuilder builder) {
int o = builder.EndObject();
builder.Required(o, 8); // name
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class UpdateBreakpointRequest : Table {
public static UpdateBreakpointRequest GetRootAsUpdateBreakpointRequest(ByteBuffer _bb) { return GetRootAsUpdateBreakpointRequest(_bb, new UpdateBreakpointRequest()); }
public static UpdateBreakpointRequest GetRootAsUpdateBreakpointRequest(ByteBuffer _bb, UpdateBreakpointRequest obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public UpdateBreakpointRequest __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartUpdateBreakpointRequest(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndUpdateBreakpointRequest(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -0,0 +1,22 @@
// automatically generated, do not modify
namespace xe.debug.proto
{
using FlatBuffers;
public sealed class UpdateBreakpointResponse : Table {
public static UpdateBreakpointResponse GetRootAsUpdateBreakpointResponse(ByteBuffer _bb) { return GetRootAsUpdateBreakpointResponse(_bb, new UpdateBreakpointResponse()); }
public static UpdateBreakpointResponse GetRootAsUpdateBreakpointResponse(ByteBuffer _bb, UpdateBreakpointResponse obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public UpdateBreakpointResponse __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartUpdateBreakpointResponse(FlatBufferBuilder builder) { builder.StartObject(0); }
public static int EndUpdateBreakpointResponse(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
}
};
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,6 +7,26 @@ using System.Threading.Tasks;
using Xenia.Debug.Utilities;
namespace Xenia.Debug {
public class ThreadList : Changeable {
public class ThreadList : Changeable, IReadOnlyCollection<Thread> {
private readonly Debugger debugger;
private readonly List<Thread> threads = new List<Thread>();
public ThreadList(Debugger debugger) {
this.debugger = debugger;
}
public int Count {
get {
return threads.Count;
}
}
public IEnumerator<Thread> GetEnumerator() {
return threads.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return threads.GetEnumerator();
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Xenia.Debug.Utilities {
public delegate void AsyncTask();
public delegate void AsyncTaskRunner(AsyncTask task);
public static class Dispatch {
public static AsyncTaskRunner AsyncTaskRunner {
get; set;
}
public static void Issue(AsyncTask task) {
AsyncTaskRunner(task);
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Xenia.Debug.Utilities {
public static class TaskExtensions {
public static async Task
WithCancellation(this Task task, CancellationToken cancellationToken) {
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs)) {
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
}
await task;
}
public static async Task<T> WithCancellation<T>(
this Task<T> task, CancellationToken cancellationToken) {
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs)) {
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
}
return await task;
}
public static Task<int> SendTaskAsync(this Socket socket, byte[] buffer,
int offset, int size, SocketFlags flags) {
IAsyncResult result =
socket.BeginSend(buffer, offset, size, flags, null, null);
return Task.Factory.FromAsync(result, socket.EndSend);
}
}
}

View File

@@ -43,10 +43,24 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\third_party\flatbuffers\net\FlatBuffers\ByteBuffer.cs">
<Link>Flatbuffers\ByteBuffer.cs</Link>
</Compile>
<Compile Include="..\..\third_party\flatbuffers\net\FlatBuffers\FlatBufferBuilder.cs">
<Link>Flatbuffers\FlatBufferBuilder.cs</Link>
</Compile>
<Compile Include="..\..\third_party\flatbuffers\net\FlatBuffers\FlatBufferConstants.cs">
<Link>Flatbuffers\FlatBufferConstants.cs</Link>
</Compile>
<Compile Include="..\..\third_party\flatbuffers\net\FlatBuffers\Struct.cs">
<Link>Flatbuffers\Struct.cs</Link>
</Compile>
<Compile Include="..\..\third_party\flatbuffers\net\FlatBuffers\Table.cs">
<Link>Flatbuffers\Table.cs</Link>
</Compile>
<Compile Include="Breakpoint.cs" />
<Compile Include="BreakpointList.cs" />
<Compile Include="Callstack.cs" />
<Compile Include="DebugClient.cs" />
<Compile Include="Debugger.cs" />
<Compile Include="Function.cs" />
<Compile Include="FunctionList.cs" />
@@ -55,9 +69,26 @@
<Compile Include="Module.cs" />
<Compile Include="ModuleList.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Proto\xe\debug\proto\AddBreakpointRequest.cs" />
<Compile Include="Proto\xe\debug\proto\AddBreakpointResponse.cs" />
<Compile Include="Proto\xe\debug\proto\AttachRequest.cs" />
<Compile Include="Proto\xe\debug\proto\AttachResponse.cs" />
<Compile Include="Proto\xe\debug\proto\Foo.cs" />
<Compile Include="Proto\xe\debug\proto\ListBreakpointsRequest.cs" />
<Compile Include="Proto\xe\debug\proto\ListBreakpointsResponse.cs" />
<Compile Include="Proto\xe\debug\proto\RemoveBreakpointRequest.cs" />
<Compile Include="Proto\xe\debug\proto\RemoveBreakpointResponse.cs" />
<Compile Include="Proto\xe\debug\proto\Request.cs" />
<Compile Include="Proto\xe\debug\proto\RequestData.cs" />
<Compile Include="Proto\xe\debug\proto\Response.cs" />
<Compile Include="Proto\xe\debug\proto\ResponseData.cs" />
<Compile Include="Proto\xe\debug\proto\StructTest.cs" />
<Compile Include="Proto\xe\debug\proto\TableTest.cs" />
<Compile Include="Thread.cs" />
<Compile Include="ThreadList.cs" />
<Compile Include="Utilities\Changeable.cs" />
<Compile Include="Utilities\Dispatch.cs" />
<Compile Include="Utilities\TaskExtensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.