Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Debugger/Breakpoints.h
3186 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#pragma once
19
20
#include <vector>
21
#include <atomic>
22
#include <mutex>
23
24
#include "Core/MIPS/MIPSDebugInterface.h"
25
#include "Common/Math/expression_parser.h"
26
27
enum BreakAction : u32 {
28
BREAK_ACTION_IGNORE = 0x00,
29
BREAK_ACTION_LOG = 0x01,
30
BREAK_ACTION_PAUSE = 0x02,
31
};
32
33
static inline BreakAction &operator |= (BreakAction &lhs, const BreakAction &rhs) {
34
lhs = BreakAction(lhs | rhs);
35
return lhs;
36
}
37
38
static inline BreakAction operator | (const BreakAction &lhs, const BreakAction &rhs) {
39
return BreakAction((u32)lhs | (u32)rhs);
40
}
41
42
struct BreakPointCond {
43
DebugInterface *debug = nullptr;
44
PostfixExpression expression;
45
std::string expressionString;
46
47
u32 Evaluate() {
48
u32 result;
49
if (parseExpression(debug, expression, result) == false)
50
return 0;
51
return result;
52
}
53
};
54
55
struct BreakPoint {
56
u32 addr;
57
bool temporary;
58
59
BreakAction result = BREAK_ACTION_IGNORE;
60
std::string logFormat;
61
62
bool hasCond = false;
63
BreakPointCond cond;
64
65
bool IsEnabled() const {
66
return (result & BREAK_ACTION_PAUSE) != 0;
67
}
68
69
bool operator == (const BreakPoint &other) const {
70
return addr == other.addr;
71
}
72
bool operator < (const BreakPoint &other) const {
73
return addr < other.addr;
74
}
75
};
76
77
enum MemCheckCondition {
78
MEMCHECK_READ = 0x01,
79
MEMCHECK_WRITE = 0x02,
80
MEMCHECK_WRITE_ONCHANGE = 0x04,
81
82
MEMCHECK_READWRITE = 0x03,
83
};
84
85
struct MemCheck {
86
u32 start;
87
u32 end;
88
89
MemCheckCondition cond = MEMCHECK_READ;
90
BreakAction result = BREAK_ACTION_IGNORE;
91
std::string logFormat;
92
93
bool hasCondition = false;
94
BreakPointCond condition;
95
96
u32 numHits = 0;
97
98
u32 lastPC = 0;
99
u32 lastAddr = 0;
100
int lastSize = 0;
101
102
// Called on the stored memcheck (affects numHits, etc.)
103
BreakAction Apply(u32 addr, bool write, int size, u32 pc);
104
// Called on a copy.
105
BreakAction Action(u32 addr, bool write, int size, u32 pc, const char *reason);
106
107
void Log(u32 addr, bool write, int size, u32 pc, const char *reason) const;
108
109
bool IsEnabled() const {
110
return (result & BREAK_ACTION_PAUSE) != 0;
111
}
112
113
bool operator == (const MemCheck &other) const {
114
return start == other.start && end == other.end;
115
}
116
};
117
118
// BreakPoints cannot overlap, only one is allowed per address.
119
// MemChecks can overlap, as long as their ends are different.
120
// WARNING: MemChecks are not always tracked in HLE currently.
121
class BreakpointManager {
122
public:
123
static const size_t INVALID_BREAKPOINT = -1;
124
static const size_t INVALID_MEMCHECK = -1;
125
126
bool IsAddressBreakPoint(u32 addr);
127
bool IsAddressBreakPoint(u32 addr, bool* enabled);
128
bool IsTempBreakPoint(u32 addr);
129
bool RangeContainsBreakPoint(u32 addr, u32 size);
130
int AddBreakPoint(u32 addr, bool temp = false); // Returns the breakpoint index.
131
void RemoveBreakPoint(u32 addr);
132
void ChangeBreakPoint(u32 addr, bool enable);
133
void ChangeBreakPoint(u32 addr, BreakAction result);
134
void ClearAllBreakPoints();
135
void ClearTemporaryBreakPoints();
136
137
// Makes a copy of the condition.
138
void ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond);
139
void ChangeBreakPointRemoveCond(u32 addr);
140
BreakPointCond *GetBreakPointCondition(u32 addr);
141
142
void ChangeBreakPointLogFormat(u32 addr, const std::string &fmt);
143
144
BreakAction ExecBreakPoint(u32 addr);
145
146
int AddMemCheck(u32 start, u32 end, MemCheckCondition cond, BreakAction result);
147
void RemoveMemCheck(u32 start, u32 end);
148
void ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, BreakAction result);
149
void ClearAllMemChecks();
150
151
void ChangeMemCheckAddCond(u32 start, u32 end, const BreakPointCond &cond);
152
void ChangeMemCheckRemoveCond(u32 start, u32 end);
153
BreakPointCond *GetMemCheckCondition(u32 start, u32 end);
154
155
void ChangeMemCheckLogFormat(u32 start, u32 end, const std::string &fmt);
156
157
bool GetMemCheck(u32 start, u32 end, MemCheck *check);
158
bool GetMemCheckInRange(u32 address, int size, MemCheck *check);
159
BreakAction ExecMemCheck(u32 address, bool write, int size, u32 pc, const char *reason);
160
BreakAction ExecOpMemCheck(u32 address, u32 pc);
161
162
void SetSkipFirst(u32 pc);
163
u32 CheckSkipFirst();
164
165
// Includes uncached addresses.
166
std::vector<MemCheck> GetMemCheckRanges(bool write);
167
168
std::vector<MemCheck> GetMemChecks();
169
std::vector<BreakPoint> GetBreakpoints();
170
171
// For editing through the imdebugger.
172
// Since it's on the main thread, we don't need to fear threading clashes.
173
std::vector<BreakPoint> &GetBreakpointRefs() {
174
return breakPoints_;
175
}
176
std::vector<MemCheck> &GetMemCheckRefs() {
177
return memChecks_;
178
}
179
180
bool HasBreakPoints() const {
181
return anyBreakPoints_;
182
}
183
bool HasMemChecks() const {
184
return anyMemChecks_;
185
}
186
187
void Frame();
188
189
bool ValidateLogFormat(MIPSDebugInterface *cpu, const std::string &fmt);
190
bool EvaluateLogFormat(MIPSDebugInterface *cpu, const std::string &fmt, std::string &result);
191
192
private:
193
// Should be called under lock.
194
void Update(u32 addr = 0) {
195
needsUpdate_ = true;
196
updateAddr_ = addr;
197
}
198
size_t FindBreakpoint(u32 addr, bool matchTemp = false, bool temp = false);
199
// Finds exactly, not using a range check.
200
size_t FindMemCheck(u32 start, u32 end);
201
MemCheck *GetMemCheckLocked(u32 address, int size);
202
void UpdateCachedMemCheckRanges();
203
204
std::atomic<bool> anyBreakPoints_;
205
std::atomic<bool> anyMemChecks_;
206
207
std::mutex breakPointsMutex_;
208
std::mutex memCheckMutex_;
209
210
std::vector<BreakPoint> breakPoints_;
211
u32 breakSkipFirstAt_ = 0;
212
u64 breakSkipFirstTicks_ = 0;
213
214
std::vector<MemCheck> memChecks_;
215
std::vector<MemCheck> memCheckRangesRead_;
216
std::vector<MemCheck> memCheckRangesWrite_;
217
218
bool needsUpdate_ = true;
219
u32 updateAddr_ = 0;
220
};
221
222
extern BreakpointManager g_breakpoints;
223
224
225