Logo Search packages:      
Sourcecode: lcrash version File versions  Download package

kl_signal.c

/*
 * $Id: kl_signal.c,v 1.1 2004/12/21 23:26:20 tjm Exp $
 *
 * This file is part of libklib.
 * A library which provides access to Linux system kernel dumps.
 *
 * Created by Silicon Graphics, Inc.
 * Contributions by IBM, NEC, and others
 *
 * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 * Copyright 2000 Junichi Nomura, NEC Solutions <j-nomura@ce.jp.nec.com>
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */

#include <klib.h>
#include <signal.h>

jmp_buf klib_jbuf;
static struct sigaction klib_sigact;

/* Global flag which forces the klib_sig_handler() function to generate 
 * a core file (off by default).
 */
static int generate_core = 0;

/* Global flag to control the printing of KLIB ERROR TRAP message
 * (off by default).
 */
static int klib_trap_msg = 1;

/* Global flag to tell the KLIB ERROR TRAP handler if it should exit
 * after a trap or do a longjmp() to continue execution (off by
 * default).
 */
static int klib_longjmp = 0;

/*
 * klib_sigon()
 */
void
klib_sigon(void)
{
      if (sigaction(SIGINT, &klib_sigact, NULL) < 0) {
            KL_ERROR = KLE_SIG_ERROR;
            return;
      }
      if (sigaction(SIGPIPE, &klib_sigact, NULL) < 0) {
            KL_ERROR = KLE_SIG_ERROR;
            return;
      }     
      if (sigaction(SIGABRT, &klib_sigact, NULL) < 0) {
            KL_ERROR = KLE_SIG_ERROR;
            return;              
      }
      if (sigaction(SIGSEGV, &klib_sigact, NULL) < 0) {
            KL_ERROR = KLE_SIG_ERROR;
            return;              
      }
      if (sigaction(SIGBUS, &klib_sigact, NULL) < 0) {
            KL_ERROR = KLE_SIG_ERROR;
            return;
      }
}

/*
 * klib_sig_handler() -- Handle signals
 */
__sighandler_t
klib_sig_handler(int sig, siginfo_t *sip, void *p)
{
      int fatal = 0;

      if (klib_trap_msg) {
            switch (sig) {

                  case SIGABRT:           
                        /* abort called (assert() failed)
                         */
                        fprintf(KL_ERRORFP, "KLIB ERROR TRAP: ABORT\n");
                        fatal = 1;
                        break;

                  case SIGSEGV:           
                        /* out-of-range access 
                         */
                        fprintf(KL_ERRORFP, "KLIB ERROR TRAP: SEGV ");
                        switch (sip->si_code) {

                              case SEGV_MAPERR:
                                    fprintf(KL_ERRORFP, "(address "
                                          "not mapped to "
                                          "object)\n");
                                    break;

                              case SEGV_ACCERR:
                                    fprintf(KL_ERRORFP, "(invalid "
                                          "permissions for "
                                          "mapped object)\n");
                                    break;

                              case SI_USER:
                                    fprintf(KL_ERRORFP, "(sent by "
                                          "kill or sigsend, pid "
                                          "%d, uid %d)\n", 
                                          sip->si_pid, 
                                          sip->si_uid);
                                    break;

                              case SI_QUEUE:
                                    fprintf(KL_ERRORFP, "(sent by "
                                          "sigqueue, pid %d, "
                                          "uid %d)\n", 
                                          sip->si_pid, 
                                          sip->si_uid);
                                    break;

                              default:
                                    fprintf(KL_ERRORFP, "(unknown "
                                          "si_code = %d)\n", 
                                          sip->si_code);
                        }
                        fatal = 1;
                        break;

                  case SIGBUS:
                        fprintf(KL_ERRORFP, "KLIB ERROR TRAP: BUSERR ");
                        switch (sip->si_code) {
                              case BUS_ADRALN:
                                    fprintf(KL_ERRORFP, "(invalid "
                                          "address alignment)\n");
                                    break;

                              case BUS_ADRERR:
                                    fprintf(KL_ERRORFP, "(non-"
                                          "existent physical "
                                          "address)\n");
                                    break;

                              case BUS_OBJERR:
                                    fprintf(KL_ERRORFP, "(object "
                                          "specific hardware "
                                          "error)\n");
                                    break;

                              case SI_USER:
                                    fprintf(KL_ERRORFP, "(sent by "
                                          "kill or sigsend, pid "
                                          "%d, uid %d)\n", 
                                          sip->si_pid, 
                                          sip->si_uid);
                                    break;

                              case SI_QUEUE:
                                    fprintf(KL_ERRORFP, "(sent by "
                                          "sigqueue, pid %d, "
                                          "uid %d)\n", 
                                          sip->si_pid, 
                                          sip->si_uid);
                                    break;

                              default:
                                    fprintf(KL_ERRORFP, "(unknown "
                                          "si_code = %d)\n", 
                                          sip->si_code);
                        }
                        break;

                  case SIGINT:
                        fprintf(KL_ERRORFP, "Received SIGINT signal\n");
                        break;

                  case SIGPIPE:
                        fprintf(KL_ERRORFP, "Received SIGPIPE "
                              "signal\n");
                        break;

                  default:
                        fprintf(KL_ERRORFP, "Error:  unexpectedly got "
                              "signal %d\n",sig);
                        break;
            }
      }

      if (fatal && generate_core) {
            fprintf(KL_ERRORFP, "Please wait, dumping core...\n");
            switch (sig) {
                  case SIGABRT:
                  case SIGSEGV:
                  case SIGBUS:
                        klib_sigact.sa_flags = 0;
                        klib_sigact.sa_handler = SIG_DFL;
                        if (sigaction(SIGABRT, 
                                    &klib_sigact, NULL) < 0) {
                              fprintf(KL_ERRORFP, "Could not set "
                                    "SIGABRT disposition to "
                                    "SIG_DFL!\n");
                        }
                        abort();
            }
      }

      /* If so configured, go back to where we left off...
       */
      if (klib_longjmp) {
            /* Make sure we get ready to trap signals again
             */
            klib_sigon();
            longjmp(klib_jbuf, 0);
      }
      fprintf(KL_ERRORFP, "Exiting after receiving signal %d\n", sig);
      exit(sig);
}

/*
 * kl_sig_setup() -- initialize the sigactions struct
 */
int
kl_sig_setup(int flags) 
{
      /* If any flags are set, set up the appropriate global variable
       */
      if (flags) {
            if (flags & KL_SIGFLG_CORE) {
                  generate_core = 1;
            }
            if (flags & KL_SIGFLG_SILENT) {
                  klib_trap_msg = 0;
            }
            if (flags & KL_SIGFLG_LNGJMP) {
                  /* Make a call to setjmp() to set a default jump
                   * location -- just in case we catch a signal
                   * before the application can set one.
                   */
                  if (setjmp(klib_jbuf)) {
                        fprintf(KL_ERRORFP, "Default longjmp!\n");
                        exit(1);
                  }
                  klib_longjmp = 1;
            }
      }

      /* Don't block the signal, return verbose info, and reset the
       * signal disposition to default.
       */
      klib_sigact.sa_flags = (SA_NODEFER | SA_SIGINFO | SA_RESETHAND);
      klib_sigact.sa_handler = (__sighandler_t)klib_sig_handler; 
      if (sigemptyset(&klib_sigact.sa_mask) < 0) {
            return(1);
      }
      klib_sigon();
      if (KL_ERROR) {
            return(1);
      }
      return(0);
}

Generated by  Doxygen 1.6.0   Back to index