source: git/Singular/cntrlc.cc @ 942305

spielwiese
Last change on this file since 942305 was 942305, checked in by Hans Schoenemann <hannes@…>, 3 years ago
doc: automaticallay call gdb with debug version
  • Property mode set to 100644
File size: 14.0 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT - interupt handling
6*/
7
8#ifndef _GNU_SOURCE
9#define _GNU_SOURCE
10#endif
11
12#include "kernel/mod2.h"
13
14#include "reporter/si_signals.h"
15#include "Singular/fevoices.h"
16
17#include "misc/options.h"
18#include "Singular/tok.h"
19#include "Singular/ipshell.h"
20#include "Singular/cntrlc.h"
21#include "Singular/feOpt.h"
22#include "Singular/misc_ip.h"
23#include "Singular/links/silink.h"
24#include "Singular/links/ssiLink.h"
25
26#ifdef HAVE_NTL
27#include <NTL/version.h>
28#include <NTL/tools.h>
29#ifdef NTL_CLIENT
30NTL_CLIENT
31#endif
32#endif
33
34/* undef, if you don't want GDB to come up on error */
35
36#define CALL_GDB
37
38#if defined(__OPTIMIZE__) && defined(CALL_GDB)
39#undef CALL_GDB
40#endif
41
42 #ifdef TIME_WITH_SYS_TIME
43   #include <time.h>
44   #ifdef HAVE_SYS_TIME_H
45     #include <sys/time.h>
46   #endif
47 #else
48   #ifdef HAVE_SYS_TIME_H
49     #include <sys/time.h>
50   #else
51     #include <time.h>
52   #endif
53 #endif
54 #ifdef HAVE_SYS_TIMES_H
55   #include <sys/times.h>
56 #endif
57
58 #define INTERACTIVE 0
59 #define STACK_TRACE 1
60
61 #ifdef CALL_GDB
62   static void debug (int);
63   static void debug_stop (char *const*args);
64 #endif
65 #ifndef __OPTIMIZE__
66   static void stack_trace (char *const*args);
67 #endif
68
69VAR si_link pipeLastLink=NULL;
70VAR BOOLEAN singular_in_batchmode=FALSE;
71
72void sig_pipe_hdl(int /*sig*/)
73{
74 if (pipeLastLink!=NULL)
75 {
76   slClose(pipeLastLink);
77   pipeLastLink=NULL;
78   WerrorS("pipe failed");
79 }
80}
81
82VAR volatile BOOLEAN do_shutdown = FALSE;
83VAR volatile int defer_shutdown = 0;
84
85void sig_term_hdl(int /*sig*/)
86{
87  do_shutdown = TRUE;
88  if (!defer_shutdown)
89  {
90    m2_end(1);
91  }
92}
93
94/*---------------------------------------------------------------------*
95 * File scope Variables (Variables shared by several functions in
96 *                       the same file )
97 *
98 *---------------------------------------------------------------------*/
99/* data */
100VAR jmp_buf si_start_jmpbuf;
101VAR int siRandomStart;
102VAR short si_restart=0;
103
104typedef void (*si_hdl_typ)(int);
105
106
107/*0 implementation*/
108/*---------------------------------------------------------------------*
109 * Functions declarations
110 *
111 *---------------------------------------------------------------------*/
112void sigint_handler(int /*sig*/);
113
114si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler);
115
116/*---------------------------------------------------------------------*/
117/**
118 * @brief meta function for binding a signal to an handler
119
120 @param[in] sig             Signal number
121 @param[in] signal_handler  Pointer to signal handler
122
123 @return value of signal()
124**/
125/*---------------------------------------------------------------------*/
126si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler)
127{
128#if 0
129  si_hdl_typ retval=signal (sig, (si_hdl_typ)signal_handler);
130  if (retval == SIG_ERR)
131  {
132     fprintf(stderr, "Unable to init signal %d ... exiting...\n", sig);
133  }
134  si_siginterrupt(sig, 0);
135  /*system calls will be restarted if interrupted by  the  specified
136   * signal sig.  This is the default behavior in Linux.
137   */
138#else
139  struct sigaction new_action,old_action;
140  memset(&new_action, 0, sizeof(struct sigaction));
141
142  /* Set up the structure to specify the new action. */
143  new_action.sa_handler = signal_handler;
144  if (sig==SIGINT)
145    sigemptyset (&new_action.sa_mask);
146  else
147    new_action.sa_flags = SA_RESTART;
148
149  int r=si_sigaction (sig, &new_action, &old_action);
150  si_hdl_typ retval=(si_hdl_typ)old_action.sa_handler;
151  if (r == -1)
152  {
153     fprintf(stderr, "Unable to init signal %d ... exiting...\n", sig);
154     retval=SIG_ERR;
155  }
156#endif
157  return retval;
158}                               /* si_set_signal */
159
160
161/*---------------------------------------------------------------------*/
162#if defined(__linux__) && (defined(__i386) || defined(__amd64))
163/*2---------------------------------------------------------------------*/
164/**
165 * @brief signal handler for run time errors, linux/i386, x86_64 version
166
167 @param[in] sig
168 @param[in] s
169**/
170/*---------------------------------------------------------------------*/
171void sigsegv_handler(int sig, sigcontext s)
172{
173  fprintf(stderr,"Singular : signal %d (v: %d):\n",sig,SINGULAR_VERSION);
174  if (sig!=SIGINT)
175  {
176    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
177    fprintf(stderr,"Segment fault/Bus error occurred at %lx because of %lx (r:%d)\n"
178                   "please inform the authors\n",
179                   #ifdef __i386__
180                   (long)s.eip,
181                   #else /* x86_64*/
182                   (long)s.rip,
183                   #endif
184                   (long)s.cr2,siRandomStart);
185  }
186#ifdef __OPTIMIZE__
187  if(si_restart<3)
188  {
189    si_restart++;
190    fputs("trying to restart...\n",stderr);
191    init_signals();
192    longjmp(si_start_jmpbuf,1);
193  }
194#endif /* __OPTIMIZE__ */
195#ifdef CALL_GDB
196  if (sig!=SIGINT)
197  {
198    if (singular_in_batchmode) debug(STACK_TRACE);
199    else                       debug(INTERACTIVE);
200  }
201#endif /* CALL_GDB */
202  exit(0);
203}
204
205/*---------------------------------------------------------------------*/
206#elif defined(SunOS) /*SPARC_SUNOS*/
207/*2
208* signal handler for run time errors, sparc sunos 4 version
209*/
210void sigsegv_handler(int sig, int code, struct sigcontext *scp, char *addr)
211{
212  fprintf(stderr,"Singular : signal %d, code %d (v: %d):\n",
213    sig,code,SINGULAR_VERSION);
214  if ((sig!=SIGINT)&&(sig!=SIGABRT))
215  {
216    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
217    fprintf(stderr,"Segment fault/Bus error occurred at %x (r:%d)\n"
218                   "please inform the authors\n",
219                   (int)addr,siRandomStart);
220  }
221#ifdef __OPTIMIZE__
222  if(si_restart<3)
223  {
224    si_restart++;
225    fputs("trying to restart...\n",stderr);
226    init_signals();
227    longjmp(si_start_jmpbuf,1);
228  }
229#endif /* __OPTIMIZE__ */
230#ifdef CALL_GDB
231  if (sig!=SIGINT) debug(STACK_TRACE);
232#endif /* CALL_GDB */
233  exit(0);
234}
235
236#else
237
238/*---------------------------------------------------------------------*/
239/*2
240* signal handler for run time errors, general version
241*/
242void sigsegv_handler(int sig)
243{
244  fprintf(stderr,"Singular : signal %d (v: %d):\n",
245    sig,SINGULAR_VERSION);
246  if (sig!=SIGINT)
247  {
248    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
249    fprintf(stderr,"Segment fault/Bus error occurred (r:%d)\n"
250                   "please inform the authors\n",
251                   siRandomStart);
252  }
253  #ifdef __OPTIMIZE__
254  if(si_restart<3)
255  {
256    si_restart++;
257    fputs("trying to restart...\n",stderr);
258    init_signals();
259    longjmp(si_start_jmpbuf,1);
260  }
261  #endif /* __OPTIMIZE__ */
262  #ifdef CALL_GDB
263  if (sig!=SIGINT) debug(STACK_TRACE);
264  #endif /* CALL_GDB */
265  exit(0);
266}
267#endif
268
269
270/*2
271* signal handler for SIGINT
272*/
273VAR int sigint_handler_cnt=0;
274void sigint_handler(int /*sig*/)
275{
276  mflush();
277  #ifdef HAVE_FEREAD
278  if (fe_is_raw_tty) fe_temp_reset();
279  #endif /* HAVE_FEREAD */
280  char default_opt=' ';
281  if ((feOptSpec[FE_OPT_CNTRLC].value!=NULL)
282      && ((char*)(feOptSpec[FE_OPT_CNTRLC].value))[0])
283  { default_opt=((char*)(feOptSpec[FE_OPT_CNTRLC].value))[0]; }
284  loop
285  {
286    int cnt=0;
287    int c;
288
289    if (singular_in_batchmode)
290    {
291      c = 'q';
292    }
293    else if (default_opt!=' ')
294    {
295      c = default_opt;
296    }
297    else
298    {
299      fprintf(stderr,"// ** Interrupt at cmd:`%s` in line:'%s'\n",
300        Tok2Cmdname(iiOp),my_yylinebuf);
301      if (feOptValue(FE_OPT_EMACS) == NULL)
302      {
303        fputs("abort after this command(a), abort immediately(r), print backtrace(b), continue(c) or quit Singular(q) ?",stderr);
304        fflush(stderr);fflush(stdin);
305        c = fgetc(stdin);
306      }
307      else
308      {
309        c = 'a';
310      }
311    }
312
313    switch(c)
314    {
315      case 'q': case EOF:
316                m2_end(2);
317      case 'r':
318                if (sigint_handler_cnt<3)
319                {
320                  sigint_handler_cnt++;
321                  fputs("** Warning: Singular should be restarted as soon as possible **\n",stderr);
322                  fflush(stderr);
323                  extern void my_yy_flush();
324                  my_yy_flush();
325                  currentVoice=feInitStdin(NULL);
326                  longjmp(si_start_jmpbuf,1);
327                }
328                else
329                {
330                  fputs("** tried too often, try another possibility **\n",stderr);
331                  fflush(stderr);
332                }
333                break;
334      case 'b':
335                VoiceBackTrack();
336                break;
337      case 'a':
338                siCntrlc++;
339      case 'c':
340                if ((feOptValue(FE_OPT_EMACS) == NULL) && (default_opt!=' '))
341                {
342                  /* Read until a newline or EOF */
343                  while (c != EOF && c != '\n') c = fgetc(stdin);
344                }
345                si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler);
346                return;
347                //siCntrlc ++;
348                //if (siCntrlc>2) si_set_signal(SIGINT,(si_hdl_typ) sigsegv_handler);
349                //else            si_set_signal(SIGINT,(si_hdl_typ) sigint_handler);
350    }
351    cnt++;
352    if(cnt>5) m2_end(2);
353  }
354}
355
356//void test_int()
357//{
358//  if (siCntrlc!=0)
359//  {
360//    int saveecho = si_echo;
361//    siCntrlc = FALSE;
362//    si_set_signal(SIGINT ,sigint_handler);
363//    iiDebug();
364//    si_echo = saveecho;
365//  }
366//}
367
368#  ifndef __OPTIMIZE__
369VAR volatile int si_stop_stack_trace_x;
370#    ifdef CALL_GDB
371static void debug (int method)
372{
373  if (feOptValue(FE_OPT_NO_TTY))
374  {
375    dReportError("Caught Signal 11");
376    return;
377  }
378  /* REMARK FOR NEWER LINUX SYSTEMS:
379Attaching to a process on Linux with GDB as a normal user may fail with "ptrace:Operation not permitted". By default Linux does not allow attaching to a process which wasn't launched by the debugger (see the Yama security documentation for more details). (https://www.kernel.org/doc/Documentation/security/Yama.txt)
380
381There are ways to workaround this:
382
383    Run the following command as super user: echo 0| sudo tee /proc/sys/kernel/yama/ptrace_scope
384
385    This will set the ptrace level to 0, after this just with user permissions you can attach to processes which are not launched by the debugger.
386
387    On distributions without Yama (such as Raspbian) you can use libcap2-bin to assign ptrace permissions to specific executables: sudo setcap cap_sys_ptrace=eip /usr/bin/gdb
388*/
389  int pid;
390  char buf[16];
391  char * args[4] = { (char*)"gdb", (char*)"Singular", NULL, NULL };
392
393  #ifdef HAVE_FEREAD
394  if (fe_is_raw_tty) fe_temp_reset();
395  #endif /* HAVE_FEREAD */
396
397  sprintf (buf, "%d", getpid ());
398
399  args[2] = buf;
400
401  pid = fork ();
402  if (pid == 0)
403  {
404    switch (method)
405    {
406      case INTERACTIVE:
407        fputs ("\n\nquit with \"p si_stop_stack_trace_x=0\"\n\n\n",stderr);
408        debug_stop (args);
409        break;
410      case STACK_TRACE:
411        fputs ("stack_trace\n",stderr);
412        stack_trace (args);
413        break;
414      default:
415        // should not be reached:
416        exit(1);
417    }
418  }
419  else if (pid == -1)
420  {
421    perror ("could not fork");
422    return;
423  }
424
425  si_stop_stack_trace_x = 1;
426  while (si_stop_stack_trace_x) ;
427}
428
429static void debug_stop (char *const*args)
430{
431  execvp (args[0], args);
432  perror ("exec failed");
433  _exit (0);
434}
435#    endif /* CALL_GDB */
436
437static void stack_trace (char *const*args)
438{
439  int pid;
440  int in_fd[2];
441  int out_fd[2];
442  fd_set fdset;
443  fd_set readset;
444  struct timeval tv;
445  int sel, index, state;
446  char buffer[256];
447  char c;
448
449  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
450  {
451    perror ("could open pipe");
452    m2_end(999);
453  }
454
455  pid = fork ();
456  if (pid == 0)
457  {
458    si_close (0); si_dup2 (in_fd[0],0);   /* set the stdin to the in pipe */
459    si_close (1); si_dup2 (out_fd[1],1);  /* set the stdout to the out pipe */
460    si_close (2); si_dup2 (out_fd[1],2);  /* set the stderr to the out pipe */
461
462    execvp (args[0], args);      /* exec gdb */
463    perror ("exec failed");
464    m2_end(999);
465  }
466  else if (pid == -1)
467  {
468    perror ("could not fork");
469    m2_end(999);
470  }
471
472  FD_ZERO (&fdset);
473  FD_SET (out_fd[0], &fdset);
474
475  si_write (in_fd[1], "backtrace\n", 10);
476  si_write (in_fd[1], "p si_stop_stack_trace_x = 0\n", 28);
477  si_write (in_fd[1], "quit\n", 5);
478
479  index = 0;
480  state = 0;
481
482  loop
483  {
484    readset = fdset;
485    tv.tv_sec = 1;
486    tv.tv_usec = 0;
487
488    sel = si_select (FD_SETSIZE, &readset, NULL, NULL, &tv);
489    if (sel == -1)
490      break;
491
492    if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
493    {
494      if (si_read (out_fd[0], &c, 1))
495      {
496        switch (state)
497        {
498          case 0:
499            if (c == '#')
500            {
501              state = 1;
502              index = 0;
503              buffer[index++] = c;
504            }
505            break;
506          case 1:
507            buffer[index++] = c;
508            if ((c == '\n') || (c == '\r'))
509            {
510              buffer[index] = 0;
511              fputs (buffer,stderr);
512              state = 0;
513              index = 0;
514            }
515            break;
516          default:
517            break;
518        }
519      }
520    }
521    else if (si_stop_stack_trace_x==0)
522      break;
523  }
524
525  si_close (in_fd[0]);
526  si_close (in_fd[1]);
527  si_close (out_fd[0]);
528  si_close (out_fd[1]);
529  m2_end(0);
530}
531
532#  endif /* !__OPTIMIZE__ */
533
534/// init signal handlers and error handling for libraries: NTL, factory
535void init_signals()
536{
537// NTL error handling (>= 9.3.0) ----------------------------------------
538#ifdef HAVE_NTL
539#if (((NTL_MAJOR_VERSION==9)&&(NTL_MINOR_VERSION>=3))||(NTL_MAJOR_VERSION>=10))
540  ErrorMsgCallback=WerrorS;
541  ErrorCallback=HALT;
542#endif
543#endif
544// factory error handling: -----------------------------------------------
545  factoryError=WerrorS;
546
547// signal handler -------------------------------------------------------
548  #ifdef SIGSEGV
549  si_set_signal(SIGSEGV,(si_hdl_typ)sigsegv_handler);
550  #endif
551  #ifdef SIGBUS
552  si_set_signal(SIGBUS, (si_hdl_typ)sigsegv_handler);
553  #endif
554  #ifdef SIGFPE
555  si_set_signal(SIGFPE, (si_hdl_typ)sigsegv_handler);
556  #endif
557  #ifdef SIGILL
558  si_set_signal(SIGILL, (si_hdl_typ)sigsegv_handler);
559  #endif
560  #ifdef SIGIOT
561  si_set_signal(SIGIOT, (si_hdl_typ)sigsegv_handler);
562  #endif
563  si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler);
564  si_set_signal(SIGCHLD, (si_hdl_typ)sig_chld_hdl);
565  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
566  si_set_signal(SIGTERM, (si_hdl_typ)sig_term_hdl);
567}
568
Note: See TracBrowser for help on using the repository browser.