Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10618 was 10114, checked in by patrick, 18 years ago

merged network back to trunk

File size: 6.0 KB
RevLine 
[7361]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"
[7461]17#include <assert.h>
[7361]18
[8228]19SignalHandler * SignalHandler::singletonRef = NULL;
20
[7439]21#ifndef __WIN32__
22
[9240]23#include <wait.h>
24
[7361]25SignalHandler::SignalHandler()
26{
27}
28
[9406]29/**
30 * register signal handlers for SIGSEGV and SIGABRT
31 * @param appName path to executable eg argv[0]
32 * @param fileName filename to append backtrace to
33 */
34void SignalHandler::doCatch( const std::string & appName, const std::string & fileName )
[7361]35{
36  this->appName = appName;
[9406]37  this->fileName = fileName;
38 
39  // make sure doCatch is only called once without calling dontCatch
40  assert( sigRecList.size() == 0 );
[7461]41
[7361]42  catchSignal( SIGSEGV );
43  catchSignal( SIGABRT );
[10114]44  catchSignal( SIGILL );
[7361]45}
46
[9406]47/**
48 * restore previous signal handlers
49 */
[7361]50void SignalHandler::dontCatch()
51{
52  for ( SignalRecList::iterator it = sigRecList.begin(); it != sigRecList.end(); it++ )
53  {
54    signal( it->signal, it->handler );
55  }
56
57  sigRecList.clear();
58}
59
[9406]60/**
61 * catch signal sig
62 * @param sig signal to catch
63 */
[7361]64void SignalHandler::catchSignal( int sig )
65{
[8293]66  sig_t handler = signal( sig, SignalHandler::sigHandler );
[7361]67
68  assert( handler != SIG_ERR );
69
70  SignalRec rec;
71  rec.signal = sig;
72  rec.handler = handler;
73
74  sigRecList.push_front( rec );
75}
76
[9406]77/**
78 * sigHandler is called when receiving signals
79 * @param sig
80 */
[7361]81void SignalHandler::sigHandler( int sig )
82{
[8228]83  for ( SignalCallbackList::iterator it = SignalHandler::getInstance()->callbackList.begin(); it != SignalHandler::getInstance()->callbackList.end(); it++  )
84  {
85    (*(it->cb))( it->someData );
86  }
[8293]87
88  std::string sigName = "UNKNOWN";
[8228]89 
[7361]90  switch ( sig )
91  {
92    case SIGSEGV:
93      sigName = "SIGSEGV";
94      break;
95    case SIGABRT:
96      sigName = "SIGABRT";
97      break;
[10114]98    case SIGILL:
99      sigName = "SIGILL";
100      break;
[7361]101  }
102
103  printf( "recieved signal %s\ntry to write backtrace to file orxonox.backtrace\n", sigName.c_str() );
[9240]104 
105  int sigPipe[2];
106  if ( pipe(sigPipe) == -1 )
107  {
108    perror("pipe failed!\n");
109    exit(EXIT_FAILURE);
110  }
111 
112  int sigPid = fork();
[7361]113
[9240]114  if ( sigPid == -1 )
115  {
116    perror("fork failed!\n");
117    exit(EXIT_FAILURE);
118  }
[7361]119
[9240]120  // gdb will be attached to this process
121  if ( sigPid == 0 )
122  {
123    getInstance()->dontCatch();
124    // wait for message from parent when it has attached gdb
125    int someData;
[7461]126
[9240]127    read( sigPipe[0], &someData, sizeof(someData) );
[7361]128
[9240]129    if ( someData != 0x12345678 )
130    {
131      printf("something went wrong :(\n");
132    }
[7361]133
[9240]134    return;
135  }
[8068]136
[9240]137  int gdbIn[2];
138  int gdbOut[2];
139  int gdbErr[2];
140 
141  if ( pipe(gdbIn) == -1 || pipe(gdbOut) == -1 || pipe(gdbErr) == -1 )
[7361]142  {
[9240]143    perror("pipe failed!\n");
144    kill( sigPid, SIGTERM );
145    waitpid( sigPid, NULL, 0 );
146    exit(EXIT_FAILURE);
147  }
[7361]148
[9240]149  int gdbPid = fork();
150  // this process will run gdb
151 
152  if ( gdbPid == -1 )
153  {
154    perror("fork failed\n");
155    kill( sigPid, SIGTERM );
156    waitpid( sigPid, NULL, 0 );
157    exit(EXIT_FAILURE);
[7361]158  }
[9240]159 
160  if ( gdbPid == 0 )
[7361]161  {
[9240]162    // start gdb
163   
164    close(gdbIn[1]);
165    close(gdbOut[0]);
166    close(gdbErr[0]);
167
168    dup2( gdbIn[0], STDIN_FILENO );
169    dup2( gdbOut[1], STDOUT_FILENO );
170    dup2( gdbErr[1], STDERR_FILENO );
171   
172    execlp( "sh", "sh", "-c", "gdb", (void*)NULL);
173  }
174
175  char cmd[256];
176  snprintf( cmd, 256, "file %s\nattach %d\nc\n", getInstance()->appName.c_str(), sigPid );
177  write( gdbIn[1], cmd, strlen(cmd) );
178
179  int charsFound = 0;
180  int promptFound = 0;
181  char byte;
182  while ( read( gdbOut[0], &byte, 1 ) == 1 )
183  {
184    if ( 
185      charsFound == 0 && byte == '(' ||
186      charsFound == 1 && byte == 'g' ||
187      charsFound == 2 && byte == 'd' ||
188      charsFound == 3 && byte == 'b' ||
189      charsFound == 4 && byte == ')' ||
190      charsFound == 5 && byte == ' '
191        )
192          charsFound++;
[9406]193    else
194      charsFound = 0;
[9240]195
196    if ( charsFound == 6 )
[7361]197    {
[9240]198      promptFound++;
199      charsFound = 0;
200    }
[7361]201
[9240]202    if ( promptFound == 3 )
203    {
204      break;
[7361]205    }
[9240]206  }
207 
208  int someData = 0x12345678;
209  write( sigPipe[1], &someData, sizeof(someData) );
[7461]210
[9406]211  write( gdbIn[1], "bt\nk\nq\n", 7 );
[9240]212
213 
214  charsFound = 0;
215  promptFound = 0;
216  std::string bt;
217  while ( read( gdbOut[0], &byte, 1 ) == 1 )
218  {
219    bt += std::string( &byte, 1 );
220
221    if ( 
222      charsFound == 0 && byte == '(' ||
223      charsFound == 1 && byte == 'g' ||
224      charsFound == 2 && byte == 'd' ||
225      charsFound == 3 && byte == 'b' ||
226      charsFound == 4 && byte == ')' ||
227      charsFound == 5 && byte == ' '
228        )
229          charsFound++;
[9406]230    else
231      charsFound = 0;
[9240]232
233    if ( charsFound == 6 )
[7366]234    {
[9240]235      promptFound++;
236      charsFound = 0;
237      bt += "\n";
[7366]238    }
[9240]239
[9406]240    if ( promptFound == 3 )
[9240]241    {
242      break;
243    }
[7361]244  }
[9240]245
246
247  waitpid( sigPid, NULL, 0 );
248  waitpid( gdbPid, NULL, 0 );
249 
250  int wsRemoved = 0;
251
252  while ( wsRemoved < 2 && bt.length() > 0 )
253  {
254    if ( bt[1] == '\n' )
255      wsRemoved++;
256    bt.erase(0, 1);
257  }
258
259  if ( bt.length() > 0 )
260    bt.erase(0, 1);
261
262  time_t now = time(NULL);
263
264  std::string timeString = "\n\n\n\n"
265                           "=======================================================\n"
266                           "= time: " + std::string(ctime(&now)) +
267                           "=======================================================\n";
268  bt.insert(0, timeString);
269 
[9406]270  FILE * f = fopen( getInstance()->fileName.c_str(), "a" );
[9240]271
272  if ( !f )
273  {
[9406]274    perror( ( std::string( "could not append to " ) + getInstance()->fileName ).c_str() );
[9240]275    exit(EXIT_FAILURE);
276  }
277
278  if ( fwrite( bt.c_str(), 1, bt.length(), f ) != bt.length() )
279  {
[9406]280    printf( ( std::string("could not write %d byte to ") + getInstance()->fileName ).c_str(), bt.length());
[9240]281    exit(EXIT_FAILURE);
282  }
283
284  exit(EXIT_FAILURE);
[7361]285}
286
[8228]287void SignalHandler::registerCallback( SignalCallback cb, void * someData )
288{
289  SignalCallbackRec rec;
290  rec.cb = cb;
291  rec.someData = someData;
292 
293  callbackList.push_back(rec);
294}
295
[7439]296#endif /* __WIN32__ */
Note: See TracBrowser for help on using the repository browser.