Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/util/signal_handler.cc @ 9387

Last change on this file since 9387 was 9240, checked in by bensch, 18 years ago

orxonox/trunk: better signal handler.
patched by chrigi

File size: 5.3 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Christoph Renner
13   co-programmer: ...
14*/
15
16#include "signal_handler.h"
17#include <assert.h>
18
19SignalHandler * SignalHandler::singletonRef = NULL;
20
21#ifndef __WIN32__
22
23#include <wait.h>
24
25SignalHandler::SignalHandler()
26{
27}
28
29void SignalHandler::doCatch( std::string appName )
30{
31  this->appName = appName;
32
33  catchSignal( SIGSEGV );
34  catchSignal( SIGABRT );
35}
36
37void SignalHandler::dontCatch()
38{
39  for ( SignalRecList::iterator it = sigRecList.begin(); it != sigRecList.end(); it++ )
40  {
41    signal( it->signal, it->handler );
42  }
43
44  sigRecList.clear();
45}
46
47void SignalHandler::catchSignal( int sig )
48{
49  sig_t handler = signal( sig, SignalHandler::sigHandler );
50
51  assert( handler != SIG_ERR );
52
53  SignalRec rec;
54  rec.signal = sig;
55  rec.handler = handler;
56
57  sigRecList.push_front( rec );
58}
59
60void SignalHandler::sigHandler( int sig )
61{
62  for ( SignalCallbackList::iterator it = SignalHandler::getInstance()->callbackList.begin(); it != SignalHandler::getInstance()->callbackList.end(); it++  )
63  {
64    (*(it->cb))( it->someData );
65  }
66
67  std::string sigName = "UNKNOWN";
68 
69  switch ( sig )
70  {
71    case SIGSEGV:
72      sigName = "SIGSEGV";
73      break;
74    case SIGABRT:
75      sigName = "SIGABRT";
76      break;
77  }
78
79  printf( "recieved signal %s\ntry to write backtrace to file orxonox.backtrace\n", sigName.c_str() );
80 
81  int sigPipe[2];
82  if ( pipe(sigPipe) == -1 )
83  {
84    perror("pipe failed!\n");
85    exit(EXIT_FAILURE);
86  }
87 
88  int sigPid = fork();
89
90  if ( sigPid == -1 )
91  {
92    perror("fork failed!\n");
93    exit(EXIT_FAILURE);
94  }
95
96  // gdb will be attached to this process
97  if ( sigPid == 0 )
98  {
99    getInstance()->dontCatch();
100    // wait for message from parent when it has attached gdb
101    int someData;
102
103    read( sigPipe[0], &someData, sizeof(someData) );
104
105    if ( someData != 0x12345678 )
106    {
107      printf("something went wrong :(\n");
108    }
109
110    return;
111  }
112
113  int gdbIn[2];
114  int gdbOut[2];
115  int gdbErr[2];
116 
117  if ( pipe(gdbIn) == -1 || pipe(gdbOut) == -1 || pipe(gdbErr) == -1 )
118  {
119    perror("pipe failed!\n");
120    kill( sigPid, SIGTERM );
121    waitpid( sigPid, NULL, 0 );
122    exit(EXIT_FAILURE);
123  }
124
125  int gdbPid = fork();
126  // this process will run gdb
127 
128  if ( gdbPid == -1 )
129  {
130    perror("fork failed\n");
131    kill( sigPid, SIGTERM );
132    waitpid( sigPid, NULL, 0 );
133    exit(EXIT_FAILURE);
134  }
135 
136  if ( gdbPid == 0 )
137  {
138    // start gdb
139   
140    close(gdbIn[1]);
141    close(gdbOut[0]);
142    close(gdbErr[0]);
143
144    dup2( gdbIn[0], STDIN_FILENO );
145    dup2( gdbOut[1], STDOUT_FILENO );
146    dup2( gdbErr[1], STDERR_FILENO );
147   
148    execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
149  }
150
151  char cmd[256];
152  snprintf( cmd, 256, "file %s\nattach %d\nc\n", getInstance()->appName.c_str(), sigPid );
153  write( gdbIn[1], cmd, strlen(cmd) );
154
155  int charsFound = 0;
156  int promptFound = 0;
157  char byte;
158  while ( read( gdbOut[0], &byte, 1 ) == 1 )
159  {
160    if ( 
161      charsFound == 0 && byte == '(' ||
162      charsFound == 1 && byte == 'g' ||
163      charsFound == 2 && byte == 'd' ||
164      charsFound == 3 && byte == 'b' ||
165      charsFound == 4 && byte == ')' ||
166      charsFound == 5 && byte == ' '
167        )
168          charsFound++;
169
170    if ( charsFound == 6 )
171    {
172      promptFound++;
173      charsFound = 0;
174    }
175
176    if ( promptFound == 3 )
177    {
178      break;
179    }
180  }
181 
182  int someData = 0x12345678;
183  write( sigPipe[1], &someData, sizeof(someData) );
184
185  write( gdbIn[1], "bt\nq\n", 5 );
186
187 
188  charsFound = 0;
189  promptFound = 0;
190  std::string bt;
191  while ( read( gdbOut[0], &byte, 1 ) == 1 )
192  {
193    bt += std::string( &byte, 1 );
194
195    if ( 
196      charsFound == 0 && byte == '(' ||
197      charsFound == 1 && byte == 'g' ||
198      charsFound == 2 && byte == 'd' ||
199      charsFound == 3 && byte == 'b' ||
200      charsFound == 4 && byte == ')' ||
201      charsFound == 5 && byte == ' '
202        )
203          charsFound++;
204
205    if ( charsFound == 6 )
206    {
207      promptFound++;
208      charsFound = 0;
209      bt += "\n";
210    }
211
212    if ( promptFound == 2 )
213    {
214      break;
215    }
216  }
217
218
219  waitpid( sigPid, NULL, 0 );
220  waitpid( gdbPid, NULL, 0 );
221 
222  int wsRemoved = 0;
223
224  while ( wsRemoved < 2 && bt.length() > 0 )
225  {
226    if ( bt[1] == '\n' )
227      wsRemoved++;
228    bt.erase(0, 1);
229  }
230
231  if ( bt.length() > 0 )
232    bt.erase(0, 1);
233
234  time_t now = time(NULL);
235
236  std::string timeString = "\n\n\n\n"
237                           "=======================================================\n"
238                           "= time: " + std::string(ctime(&now)) +
239                           "=======================================================\n";
240  bt.insert(0, timeString);
241 
242  FILE * f = fopen( GDB_BT_FILE, "a" );
243
244  if ( !f )
245  {
246    perror("could not append to " GDB_BT_FILE);
247    exit(EXIT_FAILURE);
248  }
249
250  if ( fwrite( bt.c_str(), 1, bt.length(), f ) != bt.length() )
251  {
252    printf("could not write %d byte to " GDB_BT_FILE, bt.length());
253    exit(EXIT_FAILURE);
254  }
255
256  exit(EXIT_FAILURE);
257}
258
259void SignalHandler::registerCallback( SignalCallback cb, void * someData )
260{
261  SignalCallbackRec rec;
262  rec.cb = cb;
263  rec.someData = someData;
264 
265  callbackList.push_back(rec);
266}
267
268#endif /* __WIN32__ */
Note: See TracBrowser for help on using the repository browser.