-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathdebugger.h
More file actions
321 lines (226 loc) Β· 8.5 KB
/
debugger.h
File metadata and controls
321 lines (226 loc) Β· 8.5 KB
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#pragma once
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <mutex>
#include <optional>
#include <queue> // std::queue
#include <set>
#include <thread>
#include <unordered_map>
#include <vector>
#include "../Edward/proxy.h"
#include "../Edward/proxy_supervisor.h"
#include "../Threading/warduino-thread.h"
#include "../Utils/sockets.h"
struct Module;
struct Block;
struct StackValue;
enum operation {
STORE = 0,
LOAD = 1,
};
enum RunningState {
WARDUINOinit,
WARDUINOrun,
WARDUINOpause,
WARDUINOstep,
PROXYrun, // Running state used when executing a proxy call. During
// this state the call is set up and executed by the main
// loop. After execution, the state is restored to
// PROXYhalt
PROXYhalt // Do not run the program (program runs on computer, which
// sends messages for primitives, do forward interrupts)
};
enum ExecutionState {
pcState = 0x01,
breakpointsState = 0x02,
callstackState = 0x03,
globalsState = 0x04,
tableState = 0x05,
memoryState = 0x06,
branchingTableState = 0x07,
stackState = 0x08,
callbacksState = 0x09,
eventsState = 0x0A,
ioState = 0x0B,
overridesState = 0x0C,
};
enum InterruptTypes {
// Remote Debugging
interruptRUN = 0x01,
interruptHALT = 0x02,
interruptPAUSE = 0x03,
interruptSTEP = 0x04,
interruptSTEPOver = 0x05,
interruptBPAdd = 0x06,
interruptBPRem = 0x07,
interruptContinueFor = 0x08,
interruptInspect = 0x09,
interruptDUMP = 0x10,
interruptDUMPLocals = 0x11,
interruptDUMPFull = 0x12,
interruptReset = 0x13,
interruptUPDATEFun = 0x20,
interruptUPDATELocal = 0x21,
interruptUPDATEModule = 0x22,
interruptUPDATEGlobal = 0x23,
interruptUPDATEStackValue = 0x24,
// Remote REPL
interruptINVOKE = 0x40,
// Pull Debugging
interruptSnapshot = 0x60,
interruptSetSnapshotPolicy = 0x61,
interruptLoadSnapshot = 0x62,
interruptMonitorProxies = 0x63,
interruptProxyCall = 0x64,
interruptProxify = 0x65, // wifi SSID \0 wifi PASS \0
// Push Debugging
interruptDUMPAllEvents = 0x70,
interruptDUMPEvents = 0x71,
interruptPOPEvent = 0x72,
interruptPUSHEvent = 0x73,
interruptDUMPCallbackmapping = 0x74,
interruptRecvCallbackmapping = 0x75,
// Primitive overrides
interruptSetOverridePinValue = 0x80,
interruptUnsetOverridePinValue = 0x81,
// Operations
interruptStore = 0xa0,
interruptStored = 0xa1,
};
enum class SnapshotPolicy : int {
none, // Don't automatically take snapshots.
atEveryInstruction, // Take a snapshot after every instruction.
checkpointing, // Take a snapshot every x instructions or at specific
// points where primitives are used.
};
class Debugger {
private:
std::deque<uint8_t *> debugMessages = {};
// Help variables
volatile bool interruptWrite{};
volatile bool interruptRead{};
bool interruptEven = true;
uint8_t interruptLastChar{};
std::vector<uint8_t> interruptBuffer;
std::queue<uint8_t *> parsedInterrupts{};
long interruptSize{};
bool receivingData = false;
Proxy *proxy = nullptr; // proxy module for debugger
bool connected_to_proxy = false;
warduino::mutex *supervisor_mutex;
// Mocking
std::unordered_map<uint32_t, std::unordered_map<uint32_t, uint32_t>>
overrides;
// Checkpointing
SnapshotPolicy snapshotPolicy;
uint32_t checkpointInterval; // #instructions between checkpoints
uint32_t instructions_executed; // #instructions since last checkpoint
std::optional<uint32_t> fidx_called; // The primitive that was executed
uint32_t prim_args[8]; // The arguments of the executed prim
uint32_t min_return_values;
uint32_t checkpoint_state_size;
uint8_t *checkpoint_state;
// Continue for
int32_t remaining_instructions;
// Private methods
void printValue(const StackValue *v, uint32_t idx, bool end) const;
// TODO Move parsing to WARDuino class?
void parseDebugBuffer(size_t len, const uint8_t *buff);
void pushMessage(uint8_t *msg);
//// Handle REPL interrupts
void handleInvoke(Module *m, uint8_t *interruptData) const;
//// Handle Interrupt Types
void handleInterruptRUN(const Module *m, RunningState *program_state);
void handleSTEP(const Module *m, RunningState *program_state);
void handleSTEPOver(const Module *m, RunningState *program_state);
void handleInterruptBP(Module *m, uint8_t *interruptData);
//// Information dumps
void dump(Module *m, bool full = false) const;
void dumpStack(const Module *m) const;
void dumpLocals(const Module *m) const;
void dumpBreakpoints(Module *m) const;
void dumpFunctions(Module *m) const;
void dumpCallstack(Module *m) const;
void dumpEvents(long start, long size) const;
void dumpCallbackmapping() const;
void inspect(Module *m, uint16_t sizeStateArray,
const uint8_t *state) const;
//// Handle live code update
static bool handleChangedFunction(const Module *m, uint8_t *bytes);
bool handleChangedLocal(const Module *m, uint8_t *bytes) const;
static bool handleUpdateModule(Module *m, uint8_t *data);
bool handleUpdateGlobalValue(const Module *m, uint8_t *data) const;
bool handleUpdateStackValue(const Module *m, uint8_t *bytes) const;
bool reset(Module *m) const;
//// Handle out-of-place debugging
void freeState(Module *m, uint8_t *interruptData);
static uint8_t *findOpcode(Module *m, const Block *block);
bool saveState(Module *m, uint8_t *interruptData);
static uintptr_t readPointer(uint8_t **data);
static void updateCallbackmapping(Module *m, const char *interruptData);
bool operation(Module *m, operation op);
public:
// Public fields
warduino::mutex messageQueueMutex; // mutual exclude debugMessages
warduino::condition_variable messageQueueConditionVariable;
bool freshMessages = false;
Channel *channel;
ProxySupervisor *supervisor = nullptr;
std::set<uint8_t *> breakpoints = {}; // Vector, we expect few breakpoints
uint8_t *mark = 0; // a unique temporary breakpoint that gets removed
// whenever a breakpoint is hit
uint8_t *skipBreakpoint =
nullptr; // Breakpoint to skip in the next interpretation step
// Constructor
explicit Debugger(Channel *duplex);
~Debugger();
void setChannel(Channel *duplex);
// Public methods
void stop();
void pauseRuntime(const Module *m); // pause runtime for given module
void notifyCompleteStep(
Module *m) const; // notify the debugger frontend that a step was taken
// Interrupts
void addDebugMessage(size_t len, const uint8_t *buff);
uint8_t *getDebugMessage();
bool checkDebugMessages(Module *m, RunningState *program_state);
// Breakpoints
void addBreakpoint(uint8_t *loc);
void deleteBreakpoint(uint8_t *loc);
bool isBreakpoint(uint8_t *loc);
void notifyBreakpoint(Module *m, uint8_t *pc_ptr);
// Out-of-place debugging: EDWARD
void snapshot(Module *m) const;
void setSnapshotPolicy(Module *m, uint8_t *interruptData);
void handleSnapshotPolicy(Module *m);
bool handleContinueFor(Module *m);
void proxify();
void handleProxyCall(Module *m, RunningState *program_state,
uint8_t *interruptData) const;
RFC *topProxyCall() const;
void sendProxyCallResult(Module *m) const;
bool isProxy() const;
bool isProxied(uint32_t fidx) const;
void startProxySupervisor(Channel *socket);
bool proxy_connected() const;
void disconnect_proxy() const;
// Pull-based
void handleMonitorProxies(const Module *m, uint8_t *interruptData) const;
// Push-based
void notifyPushedEvent() const;
bool handlePushedEvent(char *bytes) const;
// Concolic Multiverse Debugging
inline bool isMocked(uint32_t fidx, uint32_t argument) {
return overrides.count(fidx) > 0 && overrides[fidx].count(argument) > 0;
}
inline uint32_t getMockedValue(uint32_t fidx, uint32_t argument) {
return overrides[fidx][argument];
}
void addOverride(Module *m, uint8_t *interruptData);
void removeOverride(Module *m, uint8_t *interruptData);
// Checkpointing
void checkpoint(Module *m, bool force = false);
inline SnapshotPolicy getSnapshotPolicy() { return snapshotPolicy; }
};