mirror of
https://github.com/pleonex/NitroDebugger.git
synced 2025-06-18 21:25:42 -04:00
185 lines
4.3 KiB
C#
185 lines
4.3 KiB
C#
//
|
|
// GdbClient.cs
|
|
//
|
|
// Author:
|
|
// Benito Palacios <benito356@gmail.com>
|
|
//
|
|
// Copyright (c) 2014 Benito Palacios
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
using System;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading.Tasks;
|
|
using NitroDebugger.RSP.Packets;
|
|
using System.IO;
|
|
|
|
namespace NitroDebugger.RSP
|
|
{
|
|
public delegate void BreakExecutionEventHandle(object sender, StopSignal signal);
|
|
|
|
/// <summary>
|
|
/// GDB Client. Direct connection to emulator.
|
|
/// Application layer, only packets supported by DeSmuME implemented.
|
|
/// </summary>
|
|
public class GdbClient
|
|
{
|
|
private Task currentTask;
|
|
|
|
public GdbClient()
|
|
{
|
|
this.Error = ErrorCode.NoError;
|
|
this.Connection = new ConnectionManager(this);
|
|
this.Execution = new ExecutionManager(this);
|
|
this.Stream = new GdbStream(this);
|
|
this.Registers = new RegisterManager(this);
|
|
}
|
|
|
|
public ConnectionManager Connection {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public ExecutionManager Execution {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public GdbStream Stream {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public RegisterManager Registers {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public ErrorCode Error {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
internal Presentation Presentation {
|
|
get;
|
|
set;
|
|
}
|
|
|
|
internal void CancelPendingTask()
|
|
{
|
|
if (this.currentTask != null) {
|
|
this.Presentation.CancelRead(this.currentTask);
|
|
this.currentTask = null;
|
|
}
|
|
}
|
|
|
|
internal T SendCommandWithoutErrorReply<T>(CommandPacket command)
|
|
where T : ReplyPacket
|
|
{
|
|
ReplyPacket reply = this.SafeSending(command, typeof(T), typeof(ErrorReply));
|
|
if (reply == null)
|
|
return null;
|
|
|
|
ErrorReply error = reply as ErrorReply;
|
|
if (error != null) {
|
|
this.Error = error.Error;
|
|
return null;
|
|
}
|
|
|
|
return reply as T;
|
|
}
|
|
|
|
internal void SendCommandWithSignalAsync(CommandPacket cmd)
|
|
{
|
|
this.currentTask = Task.Run(() => {
|
|
StopSignal signal = SendCommandWithSignal(cmd);
|
|
this.Execution.OnBreakExecution(signal);
|
|
});
|
|
}
|
|
|
|
internal StopSignal SendCommandWithSignal(CommandPacket cmd)
|
|
{
|
|
ReplyPacket response = this.SafeSending(cmd, typeof(StopSignalReply));
|
|
if (response == null)
|
|
return StopSignal.Unknown;
|
|
|
|
return ((StopSignalReply)response).Signal;
|
|
}
|
|
|
|
internal ReplyPacket SafeInterruption()
|
|
{
|
|
this.Error = ErrorCode.NoError;
|
|
ReplyPacket response = null;
|
|
|
|
try {
|
|
response = this.Presentation.SendInterrupt();
|
|
} catch (SocketException) {
|
|
this.Error = ErrorCode.NetworkError;
|
|
} catch (ProtocolViolationException) {
|
|
this.Error = ErrorCode.ProtocolError;
|
|
}
|
|
|
|
if (response != null && !(response is StopSignalReply))
|
|
this.Error = ErrorCode.ProtocolError;
|
|
|
|
if (this.Error != ErrorCode.NoError) {
|
|
NetworkError();
|
|
response = null;
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
private ReplyPacket SafeSending(CommandPacket command, params Type[] validReplyTypes)
|
|
{
|
|
this.Error = ErrorCode.NoError;
|
|
ReplyPacket response = null;
|
|
|
|
try {
|
|
this.Presentation.SendCommand(command);
|
|
|
|
if (validReplyTypes.Length > 0)
|
|
response = this.Presentation.ReceiveReply();
|
|
} catch (SocketException) {
|
|
this.Error = ErrorCode.NetworkError;
|
|
} catch (ProtocolViolationException) {
|
|
this.Error = ErrorCode.ProtocolError;
|
|
}
|
|
|
|
if (response != null && !ValidateType(response, validReplyTypes))
|
|
this.Error = ErrorCode.ProtocolError;
|
|
|
|
if (this.Error != ErrorCode.NoError) {
|
|
NetworkError();
|
|
response = null;
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
private bool ValidateType(ReplyPacket reply, Type[] validReplyTypes)
|
|
{
|
|
return validReplyTypes.Contains(reply.GetType());
|
|
}
|
|
|
|
private void NetworkError()
|
|
{
|
|
this.Connection.Disconnect();
|
|
this.Connection.OnLostConnection(EventArgs.Empty);
|
|
}
|
|
}
|
|
}
|
|
|