1 /*
2 csdebug.c:
3
4 Copyright (C) 2013 Andres Cabrera
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include <assert.h>
25
26 #include "csdebug.h"
27
28 debug_instr_t *csoundDebugGetCurrentInstrInstance(CSOUND *csound);
29 debug_opcode_t *csoundDebugGetCurrentOpcodeList(CSOUND *csound);
30 void csoundDebugFreeOpcodeList(CSOUND *csound, debug_opcode_t *opcode_list);
31
csoundDebuggerBreakpointReached(CSOUND * csound)32 void csoundDebuggerBreakpointReached(CSOUND *csound)
33 {
34 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
35 debug_bkpt_info_t bkpt_info;
36 bkpt_info.breakpointInstr = csoundDebugGetCurrentInstrInstance(csound);
37 bkpt_info.instrListHead = csoundDebugGetInstrInstances(csound);
38 bkpt_info.currentOpcode = csoundDebugGetCurrentOpcodeList(csound);
39 bkpt_info.instrVarList = csoundDebugGetVariables(csound,
40 bkpt_info.breakpointInstr);
41 if (data->bkpt_cb) {
42 data->bkpt_cb(csound, &bkpt_info, data->cb_data);
43 } else {
44 csoundMessage(csound, Str("Breakpoint callback not set. Breakpoint Reached."));
45 }
46 // TODO: These free operations could be moved to a low priority context
47 csoundDebugFreeInstrInstances(csound, bkpt_info.breakpointInstr);
48 csoundDebugFreeInstrInstances(csound, bkpt_info.instrListHead);
49 if (bkpt_info.currentOpcode) {
50 csoundDebugFreeOpcodeList(csound, bkpt_info.currentOpcode);
51 }
52 csoundDebugFreeVariables(csound, bkpt_info.instrVarList);
53 }
54
csoundDebuggerInit(CSOUND * csound)55 PUBLIC void csoundDebuggerInit(CSOUND *csound)
56 {
57 csdebug_data_t *data =
58 (csdebug_data_t *) csound->Malloc(csound, sizeof(csdebug_data_t));
59 data->bkpt_anchor = (bkpt_node_t *) csound->Malloc(csound, sizeof(bkpt_node_t));
60 data->bkpt_anchor->line = -1;
61 data->bkpt_anchor->next = NULL;
62 data->debug_instr_ptr = NULL;
63 data->debug_opcode_ptr = NULL;
64 data->bkpt_cb = NULL;
65 data->status = CSDEBUG_STATUS_RUNNING;
66 data->bkpt_buffer = csoundCreateCircularBuffer(csound,
67 64, sizeof(bkpt_node_t **));
68 data->cmd_buffer = csoundCreateCircularBuffer(csound,
69 64, sizeof(debug_command_t));
70 csound->csdebug_data = data;
71 csound->kperf = kperf_debug;
72 }
73
csoundDebuggerClean(CSOUND * csound)74 PUBLIC void csoundDebuggerClean(CSOUND *csound)
75 {
76 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
77 assert(data);
78 bkpt_node_t *node = data->bkpt_anchor;
79 csoundDestroyCircularBuffer(csound, data->bkpt_buffer);
80 csoundDestroyCircularBuffer(csound, data->cmd_buffer);
81 while (node) {
82 bkpt_node_t *oldnode = node;
83 node = node->next;
84 csound->Free(csound, oldnode);
85 }
86 csound->Free(csound, data);
87 csound->csdebug_data = NULL;
88 csound->kperf = kperf_nodebug;
89 }
90
csoundDebugStart(CSOUND * csound)91 PUBLIC void csoundDebugStart(CSOUND *csound)
92 {
93 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
94 data->status = CSDEBUG_STATUS_RUNNING;
95 }
96
csoundSetBreakpoint(CSOUND * csound,int line,int instr,int skip)97 PUBLIC void csoundSetBreakpoint(CSOUND *csound, int line, int instr, int skip)
98 {
99 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
100 if (!data) {
101 csound->Warning(csound,
102 Str("csoundSetBreakpoint: cannot set breakpoint. "
103 "Debugger is not initialised."));
104 return;
105 }
106 if (line <= 0) {
107 csound->Warning(csound, Str("csoundSetBreakpoint: line > 0 for breakpoint."));
108 return;
109 }
110 bkpt_node_t *newpoint =
111 (bkpt_node_t *) csound->Malloc(csound, sizeof(bkpt_node_t));
112 newpoint->line = line;
113 newpoint->instr = instr;
114 newpoint->skip = skip;
115 newpoint->count = skip;
116 newpoint->mode = CSDEBUG_BKPT_LINE;
117 csoundWriteCircularBuffer(csound, data->bkpt_buffer, &newpoint, 1);
118 }
119
csoundRemoveBreakpoint(CSOUND * csound,int line,int instr)120 PUBLIC void csoundRemoveBreakpoint(CSOUND *csound, int line, int instr)
121 {
122 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
123 if (!data) {
124 csound->Warning(csound,
125 Str("csoundRemoveBreakpoint: cannot remove breakpoint. "
126 "Debugger is not initialised."));
127 return;
128 }
129 if (line < 0) {
130 csound->Warning(csound, Str ("Negative line for breakpoint invalid."));
131 }
132 bkpt_node_t *newpoint =
133 (bkpt_node_t *) csound->Malloc(csound, sizeof(bkpt_node_t));
134 newpoint->line = line;
135 newpoint->instr = instr;
136 newpoint->mode = CSDEBUG_BKPT_DELETE;
137 csoundWriteCircularBuffer(csound, data->bkpt_buffer, &newpoint, 1);
138 }
139
csoundSetInstrumentBreakpoint(CSOUND * csound,MYFLT instr,int skip)140 PUBLIC void csoundSetInstrumentBreakpoint(CSOUND *csound, MYFLT instr, int skip)
141 {
142 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
143 if (!data) {
144 csound->Warning(csound,
145 Str("csoundRemoveBreakpoint: cannot remove breakpoint. "
146 "Debugger is not initialised."));
147 return;
148 }
149 assert(data);
150 bkpt_node_t *newpoint =
151 (bkpt_node_t *) csound->Malloc(csound, sizeof(bkpt_node_t));
152 newpoint->line = -1;
153 newpoint->instr = instr;
154 newpoint->skip = skip;
155 newpoint->count = skip;
156 newpoint->mode = CSDEBUG_BKPT_INSTR;
157 csoundWriteCircularBuffer(csound, data->bkpt_buffer, &newpoint, 1);
158 }
159
csoundRemoveInstrumentBreakpoint(CSOUND * csound,MYFLT instr)160 PUBLIC void csoundRemoveInstrumentBreakpoint(CSOUND *csound, MYFLT instr)
161 {
162 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
163 assert(data);
164 bkpt_node_t *newpoint =
165 (bkpt_node_t *) csound->Malloc(csound, sizeof(bkpt_node_t));
166 newpoint->line = -1;
167 newpoint->instr = instr;
168 newpoint->mode = CSDEBUG_BKPT_DELETE;
169 csoundWriteCircularBuffer(csound, data->bkpt_buffer, &newpoint, 1);
170 }
171
csoundClearBreakpoints(CSOUND * csound)172 PUBLIC void csoundClearBreakpoints(CSOUND *csound)
173 {
174 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
175 assert(data);
176 bkpt_node_t *newpoint =
177 (bkpt_node_t *) csound->Malloc(csound, sizeof(bkpt_node_t));
178 newpoint->line = -1;
179 newpoint->instr = -1;
180 newpoint->mode = CSDEBUG_BKPT_CLEAR_ALL;
181 csoundWriteCircularBuffer(csound, data->bkpt_buffer, &newpoint, 1);
182 }
183
csoundSetBreakpointCallback(CSOUND * csound,breakpoint_cb_t bkpt_cb,void * userdata)184 PUBLIC void csoundSetBreakpointCallback(CSOUND *csound,
185 breakpoint_cb_t bkpt_cb, void *userdata)
186 {
187
188 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
189 assert(data);
190 data->bkpt_cb = bkpt_cb;
191 data->cb_data = userdata;
192 }
193
csoundDebugStepOver(CSOUND * csound)194 PUBLIC void csoundDebugStepOver(CSOUND *csound)
195 {
196 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
197 assert(data);
198 debug_command_t command = CSDEBUG_CMD_STEPOVER;
199 csoundWriteCircularBuffer(csound, data->cmd_buffer, &command, 1);
200 }
201
csoundDebugStepInto(CSOUND * csound)202 PUBLIC void csoundDebugStepInto(CSOUND *csound)
203 {
204 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
205 assert(data);
206 debug_command_t command = CSDEBUG_CMD_STEPINTO;
207 csoundWriteCircularBuffer(csound, data->cmd_buffer, &command, 1);
208 }
209
csoundDebugNext(CSOUND * csound)210 PUBLIC void csoundDebugNext(CSOUND *csound)
211 {
212 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
213 assert(data);
214 debug_command_t command = CSDEBUG_CMD_NEXT;
215 csoundWriteCircularBuffer(csound, data->cmd_buffer, &command, 1);
216 }
217
csoundDebugContinue(CSOUND * csound)218 PUBLIC void csoundDebugContinue(CSOUND *csound)
219 {
220 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
221 assert(data);
222 debug_command_t command = CSDEBUG_CMD_CONTINUE;
223 csoundWriteCircularBuffer(csound, data->cmd_buffer, &command, 1);
224 }
225
csoundDebugStop(CSOUND * csound)226 PUBLIC void csoundDebugStop(CSOUND *csound)
227 {
228 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
229 assert(data);
230 debug_command_t command = CSDEBUG_CMD_STOP;
231 csoundWriteCircularBuffer(csound, data->cmd_buffer, &command, 1);
232 }
233
csoundDebugGetInstrInstances(CSOUND * csound)234 PUBLIC debug_instr_t *csoundDebugGetInstrInstances(CSOUND *csound)
235 {
236 debug_instr_t *instrhead = NULL;
237 debug_instr_t *debug_instr = NULL;
238 INSDS *insds = csound->actanchor.nxtact;
239
240 while (insds) {
241 if (!instrhead) {
242 instrhead = csound->Malloc(csound, sizeof(debug_instr_t));
243 debug_instr = instrhead;
244 } else {
245 debug_instr->next = csound->Malloc(csound, sizeof(debug_instr_t));
246 debug_instr = debug_instr->next;
247 }
248 debug_instr->lclbas = insds->lclbas;
249 debug_instr->varPoolHead = insds->instr->varPool->head;
250 debug_instr->instrptr = (void *) insds;
251 debug_instr->p1 = insds->p1.value;
252 debug_instr->p2 = insds->p2.value;
253 debug_instr->p3 = insds->p3.value;
254 debug_instr->kcounter = insds->kcounter;
255 debug_instr->next = NULL;
256 insds = insds->nxtact;
257 }
258 return instrhead;
259 }
260
csoundDebugGetCurrentInstrInstance(CSOUND * csound)261 debug_instr_t *csoundDebugGetCurrentInstrInstance(CSOUND *csound)
262 {
263 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
264 assert(data);
265 if (!data->debug_instr_ptr) {
266 return NULL;
267 }
268 debug_instr_t *debug_instr = csound->Malloc(csound, sizeof(debug_instr_t));
269 INSDS *insds = (INSDS *)data->debug_instr_ptr;
270 debug_instr->lclbas = insds->lclbas;
271 debug_instr->varPoolHead = insds->instr->varPool->head;
272 debug_instr->instrptr = data->debug_instr_ptr;
273 debug_instr->p1 = insds->p1.value;
274 debug_instr->p2 = insds->p2.value;
275 debug_instr->p3 = insds->p3.value;
276 debug_instr->kcounter = insds->kcounter;
277 debug_instr->next = NULL;
278 OPDS* opstart = (OPDS*) data->debug_instr_ptr;
279 if (opstart->nxtp) {
280 debug_instr->line = opstart->nxtp->optext->t.linenum;
281 } else {
282 debug_instr->line = 0;
283 }
284 return debug_instr;
285 }
286
287
csoundDebugGetCurrentOpcodeList(CSOUND * csound)288 debug_opcode_t *csoundDebugGetCurrentOpcodeList(CSOUND *csound)
289 {
290 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
291 assert(data);
292 if (!data->debug_instr_ptr) {
293 return NULL;
294 }
295 OPDS *op = (OPDS *)data->debug_opcode_ptr;
296
297 if (!op) {
298 return NULL;
299 }
300 debug_opcode_t *opcode_list = csound->Malloc(csound, sizeof(debug_opcode_t));
301 strNcpy(opcode_list->opname, op->optext->t.opcod, 16);
302 //opcode_list->opname[15] = '\0';
303 opcode_list->line = op->optext->t.linenum;
304 return opcode_list;
305 }
306
csoundDebugFreeOpcodeList(CSOUND * csound,debug_opcode_t * opcode_list)307 void csoundDebugFreeOpcodeList(CSOUND *csound, debug_opcode_t *opcode_list)
308 {
309 csound->Free(csound, opcode_list);
310 }
311
csoundDebugFreeInstrInstances(CSOUND * csound,debug_instr_t * instr)312 PUBLIC void csoundDebugFreeInstrInstances(CSOUND *csound, debug_instr_t *instr)
313 {
314 while (instr) {
315 debug_instr_t *oldinstr = instr;
316 instr = instr->next;
317 csound->Free(csound, oldinstr);
318 }
319 }
320
csoundDebugGetVariables(CSOUND * csound,debug_instr_t * instr)321 PUBLIC debug_variable_t *csoundDebugGetVariables(CSOUND *csound,
322 debug_instr_t *instr)
323 {
324 debug_variable_t *head = NULL;
325 debug_variable_t *debug_var = head;
326 CS_VARIABLE * var = instr->varPoolHead;
327 while (var) {
328 void * varmem = NULL;
329 if (!head) {
330 head = csound->Malloc(csound, sizeof(debug_variable_t));
331 debug_var = head;
332 } else {
333 debug_var->next = csound->Malloc(csound, sizeof(debug_variable_t));
334 debug_var = debug_var->next;
335 }
336 debug_var->next = NULL;
337 debug_var->name = var->varName;
338 debug_var->typeName = var->varType->varTypeName;
339 if (strcmp(debug_var->typeName, "i") == 0
340 || strcmp(debug_var->typeName, "k") == 0
341 || strcmp(debug_var->typeName, "a") == 0
342 || strcmp(debug_var->typeName, "r") == 0
343 ) {
344 varmem = instr->lclbas + var->memBlockIndex;
345 } else if (strcmp(debug_var->typeName, "S") == 0) {
346 STRINGDAT *strdata = (STRINGDAT *) (instr->lclbas + var->memBlockIndex);
347 varmem = &strdata->data[0];
348 } else {
349 csound->Message(csound, "csoundDebugGetVarData() unknown data type.\n");
350 }
351 debug_var->data = varmem;
352 var = var->next;
353 }
354 return head;
355 }
356
357
csoundDebugFreeVariables(CSOUND * csound,debug_variable_t * varHead)358 PUBLIC void csoundDebugFreeVariables(CSOUND *csound, debug_variable_t *varHead)
359 {
360 while (varHead) {
361 debug_variable_t *oldvar = varHead;
362 varHead = varHead->next;
363 csound->Free(csound, oldvar);
364 }
365 }
366
367