aboutsummaryrefslogtreecommitdiff
path: root/src/debug/GdbStub.h
blob: ace07bf6064f531790195da3293fdbf7b0dd61d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#ifndef GDBSTUB_H_
#define GDBSTUB_H_

#include <stddef.h>
#include <map>
#include <vector>

#include "../types.h"

#include "GdbArch.h"

namespace Gdb
{

using namespace melonDS;
enum class TgtStatus
{
	NoEvent,

	None,
	Running,
	SingleStep,
	BreakReq, // "break" command from gdb client
	Bkpt,
	Watchpt,
	BkptInsn, // "bkpt" instruction
	FaultData, // data abort
	FaultIAcc, // instruction fetch abort
	FaultInsn, // illegal instruction
};

class StubCallbacks
{
public:
	StubCallbacks(){}
	virtual ~StubCallbacks(){};

	virtual int GetCPU() const = 0; // 7 or 9 (currently, maybe also xtensa in the future?)

	// 0..14: as usual
	// 15: pc *pipeline-corrected*
	// 16: cpsr
	virtual u32  ReadReg (Register reg) = 0;
	virtual void WriteReg(Register reg, u32 value) = 0;

	virtual u32  ReadMem (u32 addr, int len) = 0;
	virtual void WriteMem(u32 addr, int len, u32 value) = 0;

	virtual void ResetGdb() = 0;
	virtual int RemoteCmd(const u8* cmd, size_t len) = 0;
};

enum class StubState
{
	NoConn,
	None,
	Break,
	Continue,
	Step,
	Disconnect,
	Attach,
	CheckNoHit
};

enum class ReadResult
{
	NoPacket,
	Eof,
	CksumErr,
	CmdRecvd,
	Wut,
	Break
};

enum class ExecResult
{
	Ok,
	UnkCmd,
	NetErr,
	InitialBreak,
	MustBreak,
	Detached,
	Step,
	Continue
};

class GdbStub;

typedef ExecResult (*GdbProtoCmd)(GdbStub* stub, const u8* cmd, ssize_t len);

struct SubcmdHandler
{
	char MainCmd;
	const char* SubStr;
	GdbProtoCmd Handler;
};

struct CmdHandler
{
	char Cmd;
	GdbProtoCmd Handler;
};

class GdbStub
{
public:
	struct BpWp
	{
	public:
		u32 addr, len;
		int kind;
	};

	GdbStub(StubCallbacks* cb, int port);
	~GdbStub();

	bool Init();
	void Close();

	StubState Poll(bool wait = false);
	void SignalStatus(TgtStatus stat, u32 arg);
	StubState Enter(bool stay, TgtStatus stat=TgtStatus::NoEvent, u32 arg=~(u32)0u, bool wait_for_conn=false);

	// kind: 2=thumb, 3=thumb2 (not relevant), 4=arm
	void AddBkpt(u32 addr, int kind);
	void DelBkpt(u32 addr, int kind);
	// kind: 2=read, 3=write, 4=rdwr
	void AddWatchpt(u32 addr, u32 len, int kind);
	void DelWatchpt(u32 addr, u32 len, int kind);

	void DelAllBpWp();

	StubState CheckBkpt(u32 addr, bool enter, bool stay);
	StubState CheckWatchpt(u32 addr, int kind, bool enter, bool stay);

#include "GdbCmds.h"

	Gdb::ExecResult SubcmdExec(const u8* cmd, ssize_t len, const SubcmdHandler* handlers);
	Gdb::ExecResult CmdExec(const CmdHandler* handlers);

public:
	int SendAck();
	int SendNak();

	int Resp(const u8* data1, size_t len1, const u8* data2 = NULL, size_t len2 = 0);
	int RespC(const char* data1, size_t len1, const u8* data2 = NULL, size_t len2 = 0);
#if defined(__GCC__) || defined(__clang__)
	__attribute__((__format__(printf, 2, 3)))
#endif
	int RespFmt(const char* fmt, ...);

	int RespStr(const char* str);

private:
	void Disconnect();
	StubState HandlePacket();

private:
	StubCallbacks* Cb;

	//struct sockaddr_in server, client;
	void *ServerSA, *ClientSA;
	int Port;
	int SockFd;
	int ConnFd;

	TgtStatus Stat;
	u32 CurBkpt, CurWatchpt;
	bool StatFlag;
	bool NoAck;

	std::map<u32, BpWp> BpList;
	std::vector<BpWp> WpList;

	static SubcmdHandler Handlers_v[];
	static SubcmdHandler Handlers_q[];
	static SubcmdHandler Handlers_Q[];
	static CmdHandler Handlers_top[];
};

}

#endif