Basic debugger networking.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
src/Xenia.Debug/Proto/xe/debug/proto/AddBreakpointRequest.cs
Normal file
22
src/Xenia.Debug/Proto/xe/debug/proto/AddBreakpointRequest.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
22
src/Xenia.Debug/Proto/xe/debug/proto/AttachRequest.cs
Normal file
22
src/Xenia.Debug/Proto/xe/debug/proto/AttachRequest.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
22
src/Xenia.Debug/Proto/xe/debug/proto/AttachResponse.cs
Normal file
22
src/Xenia.Debug/Proto/xe/debug/proto/AttachResponse.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
13
src/Xenia.Debug/Proto/xe/debug/proto/Foo.cs
Normal file
13
src/Xenia.Debug/Proto/xe/debug/proto/Foo.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// automatically generated, do not modify
|
||||
|
||||
namespace xe.debug.proto
|
||||
{
|
||||
|
||||
public enum Foo : sbyte
|
||||
{
|
||||
A = 1,
|
||||
B = 2,
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
39
src/Xenia.Debug/Proto/xe/debug/proto/Request.cs
Normal file
39
src/Xenia.Debug/Proto/xe/debug/proto/Request.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
17
src/Xenia.Debug/Proto/xe/debug/proto/RequestData.cs
Normal file
17
src/Xenia.Debug/Proto/xe/debug/proto/RequestData.cs
Normal 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,
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
39
src/Xenia.Debug/Proto/xe/debug/proto/Response.cs
Normal file
39
src/Xenia.Debug/Proto/xe/debug/proto/Response.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
17
src/Xenia.Debug/Proto/xe/debug/proto/ResponseData.cs
Normal file
17
src/Xenia.Debug/Proto/xe/debug/proto/ResponseData.cs
Normal 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,
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
25
src/Xenia.Debug/Proto/xe/debug/proto/StructTest.cs
Normal file
25
src/Xenia.Debug/Proto/xe/debug/proto/StructTest.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
35
src/Xenia.Debug/Proto/xe/debug/proto/TableTest.cs
Normal file
35
src/Xenia.Debug/Proto/xe/debug/proto/TableTest.cs
Normal 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
src/Xenia.Debug/Utilities/Dispatch.cs
Normal file
20
src/Xenia.Debug/Utilities/Dispatch.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/Xenia.Debug/Utilities/TaskExtensions.cs
Normal file
40
src/Xenia.Debug/Utilities/TaskExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user