1 /*
2
3 This file is part of the Maude 2 interpreter.
4
5 Copyright 1997-2003 SRI International, Menlo Park, CA 94025, USA.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21 */
22
23 //
24 // Code for handling user interaction.
25 //
26 #include <signal.h>
27
28 bool UserLevelRewritingContext::interactiveFlag = true;
29 bool UserLevelRewritingContext::ctrlC_Flag = false;
30 bool UserLevelRewritingContext::stepFlag = false;
31 bool UserLevelRewritingContext::abortFlag = false;
32 int UserLevelRewritingContext::debugLevel = 0;
33
34 int yyparse(UserLevelRewritingContext::ParseResult*);
35 void cleanUpParser();
36 void cleanUpLexer();
37
38 void
clearDebug()39 UserLevelRewritingContext::clearDebug()
40 {
41 setTraceStatus(interpreter.getFlag(Interpreter::EXCEPTION_FLAGS));
42 stepFlag = false;
43 abortFlag = false;
44 }
45
46 void
clearInterrupt()47 UserLevelRewritingContext::clearInterrupt()
48 {
49 setTraceStatus(interpreter.getFlag(Interpreter::EXCEPTION_FLAGS));
50 ctrlC_Flag = false;
51 }
52
53 void
setHandlers(bool handleCtrlC)54 UserLevelRewritingContext::setHandlers(bool handleCtrlC)
55 {
56 if (interactiveFlag && handleCtrlC)
57 {
58 static struct sigaction ctrlC_Handler;
59 ctrlC_Handler.sa_handler = interruptHandler;
60 #ifdef SA_INTERRUPT
61 //
62 // Avoid old BSD semantics which automatically restarts
63 // interrupted system calls.
64 //
65 ctrlC_Handler.sa_flags = SA_INTERRUPT;
66 #endif
67 sigaction(SIGINT, &ctrlC_Handler, 0);
68 }
69
70 #ifdef NO_ASSERT
71 //
72 // If we're not debugging we handle internal errors and stack overflows.
73 //
74 BddUser::setErrorHandler(internalErrorHandler); // BuDDy detects misuse of BDDs
75 signal(SIGBUS, internalErrorHandler); // misaligned memory access or nonexistent real memeory
76 signal(SIGILL, internalErrorHandler); // illegal instruction
77
78 #ifdef USE_LIBSIGSEGV
79 //
80 // Stack overflows are reported as SIGSEGV signals and so we need to use the
81 // libsigsegv library to heuristically distinguish the two conditions.
82 //
83 static char altStack[SIGSTKSZ];
84 sigsegv_install_handler(sigsegvHandler); // illegal memory access or stack overflow
85 stackoverflow_install_handler(stackOverflowHandler, altStack, sizeof(altStack));
86 #else
87 //
88 // If we can't use the library we will will catch SIGSEGVs but not install
89 // an alternative stack so that that stack overflows will show up as
90 // segmentation faults.
91 //
92 signal(SIGSEGV, internalErrorHandler);
93 #endif
94 #endif
95 //
96 // HACK: this should go somewhere else.
97 //
98 changePrompt();
99 ioManager.setContPrompt("> ");
100 }
101
102 #ifdef USE_LIBSIGSEGV
103
104 void
stackOverflowHandler(int emergency,stackoverflow_context_t scp)105 UserLevelRewritingContext::stackOverflowHandler(int emergency, stackoverflow_context_t scp)
106 {
107 //
108 // Assume machine state is bad - so use a system call.
109 //
110 static char message[] = "\nFatal error: stack overflow.\n\
111 This can happen because you have an infinite computation, say a runaway\n\
112 recursion, or model checking an infinite model. It can also happen because\n\
113 the stacksize limit in your environment is set too low for the computation\n\
114 you are trying to do. You can find the value of your stacksize with the\n\
115 tcsh command 'limit stacksize' or the bash command 'ulimit -s'.\n\
116 \n\
117 Depending on your operating system configuration you may be able to\n\
118 increase your stacksize with the tcsh command 'unlimit stacksize'\n\
119 or the bash command 'ulimit -s unlimited'.\n\n";
120 (void) write(STDERR_FILENO, message, sizeof(message) - 1);
121 _exit(1); // don't call atexit() functions with a bad machine state
122 }
123
124 int
sigsegvHandler(void * fault_address,int serious)125 UserLevelRewritingContext::sigsegvHandler(void *fault_address, int serious)
126 {
127 if (serious) // real segmentation fault
128 internalErrorHandler(SIGSEGV); // doesn't return
129 return 0; // must have been a stack overflow
130 }
131
132 #endif
133
134 void
internalErrorHandler(int)135 UserLevelRewritingContext::internalErrorHandler(int /* signalNr */)
136 {
137 //
138 // Assume machine state is bad - so use system calls.
139 //
140 static char message1[] = "\nMaude internal error.\nPlease submit a bug report to: ";
141 static char message2[] = PACKAGE_BUGREPORT;
142 static char message3[] = "\nPlease include the platform details, Maude version, and a file\n\
143 `crash.maude' that can be loaded to reproduce the crash (it may load\n\
144 other files). Do not bother trying to simplify your example unless the\n\
145 runtime to the bug being visible is greater than 10 seconds.\n\n";
146 (void) write(STDERR_FILENO, message1, sizeof(message1) - 1);
147 (void) write(STDERR_FILENO, message2, sizeof(message2) - 1);
148 (void) write(STDERR_FILENO, message3, sizeof(message3) - 1);
149 _exit(1); // don't call atexit() functions with a bad machine state
150 }
151
152 void
interruptHandler(int)153 UserLevelRewritingContext::interruptHandler(int)
154 {
155 ctrlC_Flag = true;
156 setTraceStatus(true);
157 }
158
159 void
interruptHandler2(...)160 UserLevelRewritingContext::interruptHandler2(...)
161 {
162 // windowChangedFlag = true;
163 }
164
165 void
changePrompt()166 UserLevelRewritingContext::changePrompt()
167 {
168 if (debugLevel == 0)
169 ioManager.setPrompt("Maude> ");
170 else
171 {
172 string prompt = "Debug(";
173 prompt += int64ToString(debugLevel); // HACK: fix when we have decent stdc++ lib
174 prompt += ")> ";
175 ioManager.setPrompt(prompt);
176 }
177 }
178
179 UserLevelRewritingContext::ParseResult
commandLoop()180 UserLevelRewritingContext::commandLoop()
181 {
182 ParseResult parseResult;
183 for(;;)
184 {
185
186 //cerr << "start of command\n"; RootContainer::dump(cerr);
187 cout.flush();
188 parseResult = NORMAL;
189 ioManager.startCommand();
190 bool parseError = yyparse(&parseResult);
191 //cout << "parser result is: " << parseError << endl;
192 if (parseError || ctrlC_Flag)
193 {
194 cout << '\n'; // terminate any partially typed in line
195 setTraceStatus(interpreter.getFlag(Interpreter::EXCEPTION_FLAGS));
196 cleanUpParser();
197 cleanUpLexer();
198 ctrlC_Flag = false;
199 }
200 else
201 {
202 switch (parseResult)
203 {
204 case NORMAL:
205 break;
206 case RESUME:
207 case ABORT:
208 case STEP:
209 case WHERE:
210 {
211 if (debugLevel > 0)
212 return parseResult;
213 IssueWarning("not in debugger.");
214 break;
215 }
216 case QUIT:
217 {
218 //
219 // This is the only normal exit() that can be taken.
220 //
221 cout << "Bye.\n";
222 #ifndef NO_ASSERT
223 //
224 // Look for memory bugs.
225 //
226 delete &interpreter;
227 #else
228 //
229 // If we are not going to delete the interpreter
230 // in the interests of a quick exit, at least clean
231 // up any XML log we may have started.
232 //
233 interpreter.endXmlLog();
234 #endif
235 exit(0);
236 }
237 }
238 }
239 }
240 }
241
242 void
setInteractive(bool status)243 UserLevelRewritingContext::setInteractive(bool status)
244 {
245 interactiveFlag = status;
246 }
247
248 void
beginCommand()249 UserLevelRewritingContext::beginCommand()
250 {
251 if (!interactiveFlag)
252 cout << "==========================================\n";
253 }
254
255 bool
handleDebug(const DagNode * subject,const PreEquation * pe)256 UserLevelRewritingContext::handleDebug(const DagNode* subject, const PreEquation* pe)
257 {
258 if (abortFlag)
259 return true;
260 bool broken = 0;
261 Symbol* brokenSymbol = 0;
262 if (interpreter.getFlag(Interpreter::BREAK))
263 {
264 Symbol* s = subject->symbol();
265 if (interpreter.breakId(s->id()))
266 {
267 broken = true;
268 brokenSymbol = s;
269 }
270 else
271 {
272 if (pe != 0 && interpreter.breakId(pe->getLabel().id()))
273 broken = true;
274 }
275 }
276 if (!(ctrlC_Flag || stepFlag || broken))
277 return !(interpreter.getFlag(Interpreter::TRACE)); // normal tracing
278 ++debugLevel;
279 changePrompt();
280 if (ctrlC_Flag)
281 {
282 if (!interactiveFlag)
283 {
284 cout << '\n';
285 cleanUpLexer();
286 }
287 ctrlC_Flag = false;
288 }
289 else if (broken)
290 {
291 if (brokenSymbol != 0)
292 cout << "break on symbol: " << brokenSymbol << '\n';
293 else
294 {
295 if (const SortConstraint* mb = dynamic_cast<const SortConstraint*>(pe))
296 cout << "break on labeled membership axiom:\n" << mb << '\n';
297 else if (const Equation* eq = dynamic_cast<const Equation*>(pe))
298 cout << "break on labeled equation:\n" << eq << '\n';
299 else if (const Rule* rl = dynamic_cast<const Rule*>(pe))
300 cout << "break on labeled rule:\n" << rl << '\n';
301 else
302 CantHappen("unidentified statement");
303 }
304 }
305 stepFlag = false;
306 setTraceStatus(interpreter.getFlag(Interpreter::EXCEPTION_FLAGS));
307 for(;;)
308 {
309 switch (commandLoop())
310 {
311 case RESUME:
312 {
313 --debugLevel;
314 changePrompt();
315 return !(interpreter.getFlag(Interpreter::TRACE));
316 }
317 case ABORT:
318 {
319 --debugLevel;
320 changePrompt();
321 abortFlag = true;
322 setTraceStatus(true);
323 return true;
324 }
325 case STEP:
326 {
327 --debugLevel;
328 changePrompt();
329 stepFlag = true;
330 setTraceStatus(true);
331 return false;
332 }
333 case WHERE:
334 {
335 where();
336 break;
337 }
338 default:
339 CantHappen("bad value in case");
340 }
341 }
342 return true; // never executed
343 }
344
345 void
where()346 UserLevelRewritingContext::where()
347 {
348 static const char* purposeString[] =
349 {
350 "which arose while checking a condition during the evaluation of:",
351 "which arose while doing a sort computation during the evaluation of:",
352 "which arose in some unknown manner during the evaluation of:",
353 "which arose while executing a top level command.",
354 "which arose while doing a meta-evaluation requested by:"
355 };
356 cout << "Current term is:\n";
357 for (UserLevelRewritingContext* p = this; p != 0; p = p->parent)
358 {
359 cout << p->root() << '\n';
360 if (ctrlC_Flag)
361 {
362 ctrlC_Flag = false;
363 return;
364 }
365 cout << purposeString[p->purpose] << '\n';
366 }
367 }
368
369 bool
traceAbort()370 UserLevelRewritingContext::traceAbort()
371 {
372 return abortFlag;
373 }
374