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