1 /* nl-debug.c --- debugging functions, and functions to trap signals and timers
2
3 Copyright (C) 2016 Lutz Mueller
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20
21 #include "newlisp.h"
22 #include "protos.h"
23
24 #ifdef WINDOWS
25 #define fgets win_fgets
26 #endif
27
28 extern FILE * IOchannel;
29 extern int evalSilent;
30
31 int matchString(char * buffer, char * string, int * length);
32 int stringComp(char * buffer, char * string);
33 int debugPrintFunction(CELL * cell);
34 void getDebuggerInput(char * msg);
35
36 extern SYMBOL * currentFunc;
37 extern SYMBOL * timerEvent;
38 extern SYMBOL * cilkEvent;
39 extern SYMBOL * symHandler[];
40 extern int currentSignal;
41
42 int currentLevel = 0;
43 int debugStackIdx = 0;
44 UINT * debugStack;
45 UINT tracePrintDevice;
46
47 char debugPreStr[8] = "#";
48 char debugPostStr[8] = "#";
49 CELL * debugPrintCell = NULL;
50
51 char headerStr[16] = "\n-----\n\n";
52 char footerStr[32] = " s|tep n|ext c|ont q|uit > ";
53
54 #define pushDebugStack(A) (*(debugStack + debugStackIdx++) = (UINT)(A))
55 #define popDebugStack() (*(debugStack + --debugStackIdx))
56
57 #define DEBUG_ENTRY "->"
58 #define DEBUG_EXIT "<-"
59
openTrace(void)60 void openTrace(void)
61 {
62 if(traceFlag) return;
63 traceFlag = TRACE_TRUE;
64 currentFunc = nilSymbol;
65 debugStackIdx = 0;
66 debugStack = (UINT *)allocMemory(MAX_CPU_STACK * 2 * sizeof(UINT));
67 }
68
closeTrace(void)69 void closeTrace(void)
70 {
71 if(traceFlag & TRACE_PRINT_EVAL)
72 close(tracePrintDevice);
73 traceFlag = 0;
74 if(debugStack) free(debugStack);
75 debugStack = NULL;
76 }
77
78 #ifdef DEBUGGER
p_debug(CELL * params)79 CELL * p_debug(CELL * params)
80 {
81 CELL * result;
82
83 openTrace();
84 traceFlag |= TRACE_IN_DEBUG;
85 result = copyCell(evaluateExpression(params));
86 closeTrace();
87
88 return(result);
89 }
90 #endif
91
92
p_trace(CELL * params)93 CELL * p_trace(CELL * params)
94 {
95 if(params != nilCell)
96 {
97 params = evaluateExpression(params);
98 if(isNumber(params->type))
99 {
100 traceFlag |= TRACE_PRINT_EVAL;
101 getIntegerExt(params, &tracePrintDevice, FALSE);
102 return(stuffInteger(tracePrintDevice));
103 }
104 if(!isNil(params))
105 {
106 openTrace();
107 traceFlag |= TRACE_IN_DEBUG;
108 }
109 else
110 closeTrace();
111 }
112
113 if(traceFlag & TRACE_IN_DEBUG) return(trueCell);
114 if(traceFlag & TRACE_PRINT_EVAL) return(stuffInteger(tracePrintDevice));
115 return(nilCell);
116 }
117
118 #ifdef DEBUGGER
p_traceHighlight(CELL * params)119 CELL * p_traceHighlight(CELL * params)
120 {
121 char * pre, * post, * header, * footer;
122
123 params = getString(params, &pre);
124 params = getString(params, &post);
125
126 strncpy(debugPreStr, pre, 8);
127 strncpy(debugPostStr, post, 8);
128 *(debugPreStr + 7) = 0;
129 *(debugPostStr + 7) = 0;
130
131 if(params != nilCell)
132 {
133 params = getString(params, &header);
134 strncpy(headerStr, header, 16);
135 }
136
137 if(params != nilCell)
138 {
139 getString(params, &footer);
140 strncpy(footerStr, footer, 32);
141 }
142
143 *(headerStr + 15) = 0;
144 *(footerStr + 31) = 0;
145
146 return(trueCell);
147 }
148 #endif /* DEBUGGER */
149
tracePrint(char * label,CELL * expr)150 void tracePrint(char * label, CELL * expr)
151 {
152 UINT printDeviceSave = printDevice;
153
154 printDevice = tracePrintDevice;
155 varPrintf(OUT_DEVICE, "%d %s: ", recursionCount, label);
156 if(expr) printCell(expr, TRUE, OUT_DEVICE);
157 varPrintf(OUT_DEVICE, "%s", "\n");
158 printDevice = printDeviceSave;
159 }
160
traceEntry(CELL * cell,CELL * pCell,CELL * args)161 void traceEntry(CELL * cell, CELL * pCell, CELL * args)
162 {
163 if(traceFlag & (TRACE_IN_ENTRY | TRACE_IN_EXIT | TRACE_DEBUG_NEXT)) return;
164 traceFlag |= TRACE_IN_ENTRY;
165
166 #ifdef DEBUGGER
167 int defaultFuncFlag = FALSE;
168 #endif
169
170 if(traceFlag & TRACE_SIGNAL)
171 {
172 traceFlag &= ~TRACE_SIGNAL;
173 executeSymbol(symHandler[currentSignal - 1], stuffInteger(currentSignal), NULL);
174 traceFlag &= ~TRACE_IN_ENTRY;
175 return;
176 }
177
178 if(traceFlag & TRACE_SIGINT)
179 {
180 traceFlag &= ~TRACE_SIGINT;
181 longjmp(errorJump, ERR_USER_RESET);
182 }
183
184 if(traceFlag & TRACE_TIMER)
185 {
186 traceFlag &= ~TRACE_TIMER;
187 executeSymbol(timerEvent, NULL, NULL);
188 traceFlag &= ~TRACE_IN_ENTRY;
189 return;
190 }
191
192 if(traceFlag & TRACE_PRINT_EVAL)
193 {
194 if(cell->type == CELL_EXPRESSION) tracePrint("entry", cell);
195 traceFlag &= ~TRACE_IN_ENTRY;
196 return;
197 }
198
199 #ifdef DEBUGGER
200 if(debugStackIdx > 1)
201 {
202 if(debugPrintFunction(cell))
203 getDebuggerInput(DEBUG_ENTRY);
204 if(!traceFlag) return;
205 }
206
207 if(traceFlag & TRACE_DEBUG_NEXT)
208 {
209 traceFlag &= ~TRACE_IN_ENTRY;
210 return;
211 }
212
213 if(pCell->type == CELL_CONTEXT)
214 {
215 defaultFuncFlag = TRUE;
216 currentFunc = translateCreateSymbol(
217 ((SYMBOL*)pCell->contents)->name,
218 CELL_NIL,
219 (SYMBOL*)pCell->contents,
220 TRUE);
221
222 pCell = (CELL *)currentFunc->contents;
223 }
224
225 if((pCell->type == CELL_LAMBDA || pCell->type == CELL_FEXPR)
226 && args->type == CELL_SYMBOL)
227 {
228 if(debugStackIdx == 0) /* startup */
229 traceFlag &= ~TRACE_DEBUG_NEXT;
230
231 if(!defaultFuncFlag)
232 currentFunc = (SYMBOL *)args->contents;
233 pushDebugStack(recursionCount);
234 pushDebugStack(currentFunc);
235 }
236 #endif /* no_DEBUG */
237
238 traceFlag &= ~TRACE_IN_ENTRY;
239 }
240
241
traceExit(CELL * result,CELL * cell,CELL * pCell,CELL * args)242 void traceExit(CELL * result, CELL * cell, CELL * pCell, CELL * args)
243 {
244 if(traceFlag & (TRACE_IN_ENTRY | TRACE_IN_EXIT | TRACE_SIGNAL | TRACE_SIGINT | TRACE_TIMER)) return;
245
246 if(traceFlag == TRACE_PRINT_EVAL)
247 {
248 tracePrint("exit", result);
249 return;
250 }
251
252 traceFlag |= TRACE_IN_EXIT;
253
254 #ifdef DEBUGGER
255 if(traceFlag & TRACE_DEBUG_NEXT)
256 {
257 if(currentLevel >= recursionCount)
258 traceFlag &= ~TRACE_DEBUG_NEXT;
259 else
260 {
261 traceFlag &= ~TRACE_IN_EXIT;
262 return;
263 }
264 }
265
266 if( (pCell->type == CELL_LAMBDA || pCell->type == CELL_FEXPR)
267 && args->type == CELL_SYMBOL)
268 {
269 if((UINT)recursionCount == *(debugStack + debugStackIdx - 2) )
270 {
271 debugStackIdx -= 2;
272 if(debugStackIdx > 0)
273 currentFunc = (SYMBOL *)*(debugStack + debugStackIdx - 1);
274 if(debugStackIdx == 0)
275 traceFlag &= ~TRACE_DEBUG_NEXT;
276 }
277 }
278
279 if(debugPrintFunction(cell))
280 {
281 varPrintf(OUT_CONSOLE, "\nRESULT: ");
282 printCell(result, TRUE, OUT_CONSOLE);
283 varPrintf(OUT_CONSOLE, "\n");
284
285 if(debugStackIdx > 0)
286 {
287 getDebuggerInput(DEBUG_EXIT);
288 if(!traceFlag) return;
289 }
290 }
291
292 if(traceFlag & TRACE_DEBUG_NEXT)
293 currentLevel = recursionCount;
294 #endif /* DEBUGGER */
295
296 traceFlag &= ~TRACE_IN_EXIT;
297 }
298
299 #ifdef DEBUGGER
getDebuggerInput(char * msg)300 void getDebuggerInput(char * msg)
301 {
302 char command[MAX_LINE];
303 char * context;
304 jmp_buf errorJumpSave;
305 UINT * resultStackIdxSave;
306 SYMBOL * contextSave;
307
308 while(TRUE)
309 {
310
311 if(currentContext != mainContext)
312 context = currentContext->name;
313 else context = "";
314
315
316 if(!evalSilent)
317 varPrintf(OUT_CONSOLE, "\n[%s %d %s]%s", msg, recursionCount, context, footerStr);
318 else evalSilent = FALSE;
319
320 if(fgets(command, MAX_LINE - 1, IOchannel) == NULL)
321 fatalError(ERR_IO_ERROR, 0, 0);
322
323 /* client and server could have different line-termination */
324 if(*(command + 1) == '\n' || *(command + 1) == '\r')
325 {
326 if(*command == 'n')
327 {
328 traceFlag |= TRACE_DEBUG_NEXT;
329 currentLevel = recursionCount;
330 break;
331 }
332 if(*command == 's')
333 {
334 traceFlag &= ~TRACE_DEBUG_NEXT;
335 break;
336 }
337 if(*command == 'q')
338 {
339 closeTrace();
340 longjmp(errorJump, ERR_USER_RESET);
341 }
342 if(*command == 'c')
343 {
344 closeTrace();
345 break;
346 }
347 }
348
349 resultStackIdxSave = resultStackIdx;
350 memcpy(errorJumpSave, errorJump, sizeof(jmp_buf));
351 contextSave = currentContext;
352 currentContext = currentFunc->context;
353 if(setjmp(errorJump))
354 {
355 cleanupResults(resultStackIdxSave);
356 goto DEBUG_EVAL_END;
357 }
358
359 executeCommandLine(command, OUT_CONSOLE, NULL);
360
361 DEBUG_EVAL_END:
362 currentContext = contextSave;
363 memcpy(errorJump, errorJumpSave, sizeof(jmp_buf));
364 }
365 }
366
367
debugPrintFunction(CELL * cell)368 int debugPrintFunction(CELL * cell)
369 {
370 int preLen, pos = 0;
371 char * strPos;
372
373 STREAM strStream = {NULL, NULL, 0, 0, 0};
374
375 if(currentFunc == nilSymbol) return FALSE;
376
377 debugPrintCell = cell;
378 openStrStream(&strStream, MAX_STRING, 0);
379 printSymbol(currentFunc, (UINT)&strStream);
380 debugPrintCell = NULL;
381
382 strPos = strstr(strStream.buffer, debugPreStr);
383 if(strPos != NULL)
384 {
385 preLen = strlen(debugPreStr);
386 while(*(strPos + preLen + pos) <= ' ' && *(strPos + preLen + pos) != 0) ++pos;
387 if(pos) /* if there is white space */
388 {
389 /* swap whitespace and debugPreStr */
390 strncpy(strPos, strPos + preLen, pos);
391 strncpy(strPos + pos, debugPreStr, preLen);
392 }
393 varPrintf(OUT_CONSOLE, "%s", headerStr);
394 varPrintf(OUT_CONSOLE, "%s", strStream.buffer);
395 }
396
397 closeStrStream(&strStream);
398 return (strPos != NULL);
399 }
400
401 #endif /* DEBUGGER */
402 /* eof */
403
404
405