Fix for issue 242, plus a redo of how old exception handlers are tracked, and called.
R=Craig.Schlenter, luly81 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@315 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
4af5fe0b59
commit
02c244f1b2
@ -1,7 +1,7 @@
|
|||||||
CXX=g++
|
CXX=g++
|
||||||
CC=gcc
|
CC=gcc
|
||||||
|
|
||||||
CXXFLAGS=-gstabs -I../../.. -Wall -D_REENTRANT
|
CXXFLAGS=-gstabs+ -I../../.. -Wall -D_REENTRANT
|
||||||
LDFLAGS=-lpthread
|
LDFLAGS=-lpthread
|
||||||
|
|
||||||
OBJ_DIR=.
|
OBJ_DIR=.
|
||||||
|
@ -81,6 +81,15 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
|
|||||||
installed_handler_(install_handler) {
|
installed_handler_(install_handler) {
|
||||||
set_dump_path(dump_path);
|
set_dump_path(dump_path);
|
||||||
|
|
||||||
|
act_.sa_handler = HandleException;
|
||||||
|
act_.sa_flags = SA_ONSTACK;
|
||||||
|
sigemptyset(&act_.sa_mask);
|
||||||
|
// now, make sure we're blocking all the signals we are handling
|
||||||
|
// when we're handling any of them
|
||||||
|
for ( size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) {
|
||||||
|
sigaddset(&act_.sa_mask, SigTable[i]);
|
||||||
|
}
|
||||||
|
|
||||||
if (install_handler) {
|
if (install_handler) {
|
||||||
SetupHandler();
|
SetupHandler();
|
||||||
pthread_mutex_lock(&handler_stack_mutex_);
|
pthread_mutex_lock(&handler_stack_mutex_);
|
||||||
@ -149,20 +158,26 @@ void ExceptionHandler::SetupHandler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionHandler::SetupHandler(int signo) {
|
void ExceptionHandler::SetupHandler(int signo) {
|
||||||
struct sigaction act, old_act;
|
|
||||||
act.sa_handler = HandleException;
|
// We're storing pointers to the old signal action
|
||||||
act.sa_flags = SA_ONSTACK;
|
// structure, rather than copying the structure
|
||||||
if (sigaction(signo, &act, &old_act) < 0)
|
// because we can't count on the sa_mask field to
|
||||||
return;
|
// be scalar.
|
||||||
old_handlers_[signo] = old_act.sa_handler;
|
struct sigaction *old_act = &old_actions_[signo];
|
||||||
|
|
||||||
|
if (sigaction(signo, &act_, old_act) < 0)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionHandler::TeardownHandler(int signo) {
|
void ExceptionHandler::TeardownHandler(int signo) {
|
||||||
if (old_handlers_.find(signo) != old_handlers_.end()) {
|
TeardownHandler(signo, NULL);
|
||||||
struct sigaction act;
|
}
|
||||||
act.sa_handler = old_handlers_[signo];
|
|
||||||
act.sa_flags = 0;
|
void ExceptionHandler::TeardownHandler(int signo, struct sigaction *final_handler) {
|
||||||
sigaction(signo, &act, 0);
|
if (old_actions_[signo].sa_handler) {
|
||||||
|
struct sigaction *act = &old_actions_[signo];
|
||||||
|
sigaction(signo, act, final_handler);
|
||||||
|
memset(&old_actions_[signo], 0x0, sizeof(struct sigaction));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +208,8 @@ void ExceptionHandler::HandleException(int signo) {
|
|||||||
pthread_mutex_unlock(&handler_stack_mutex_);
|
pthread_mutex_unlock(&handler_stack_mutex_);
|
||||||
|
|
||||||
// Restore original handler.
|
// Restore original handler.
|
||||||
current_handler->TeardownHandler(signo);
|
struct sigaction old_action;
|
||||||
|
current_handler->TeardownHandler(signo, &old_action);
|
||||||
|
|
||||||
struct sigcontext *sig_ctx = NULL;
|
struct sigcontext *sig_ctx = NULL;
|
||||||
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
|
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
|
||||||
@ -202,11 +218,23 @@ void ExceptionHandler::HandleException(int signo) {
|
|||||||
} else {
|
} else {
|
||||||
// Exception not fully handled, will call the next handler in stack to
|
// Exception not fully handled, will call the next handler in stack to
|
||||||
// process it.
|
// process it.
|
||||||
typedef void (*SignalHandler)(int signo, struct sigcontext);
|
if (old_action.sa_handler != NULL && sig_ctx != NULL) {
|
||||||
SignalHandler old_handler =
|
|
||||||
reinterpret_cast<SignalHandler>(current_handler->old_handlers_[signo]);
|
// Have our own typedef, because of the comment above w.r.t signal
|
||||||
if (old_handler != NULL && sig_ctx != NULL)
|
// context on the stack
|
||||||
|
typedef void (*SignalHandler)(int signo, struct sigcontext);
|
||||||
|
|
||||||
|
SignalHandler old_handler =
|
||||||
|
reinterpret_cast<SignalHandler>(old_action.sa_handler);
|
||||||
|
|
||||||
|
sigset_t old_set;
|
||||||
|
// Use SIG_BLOCK here because we don't want to unblock a signal
|
||||||
|
// that the signal handler we're currently in needs to block
|
||||||
|
sigprocmask(SIG_BLOCK, &old_action.sa_mask, &old_set);
|
||||||
old_handler(signo, *sig_ctx);
|
old_handler(signo, *sig_ctx);
|
||||||
|
sigprocmask(SIG_SETMASK, &old_set, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&handler_stack_mutex_);
|
pthread_mutex_lock(&handler_stack_mutex_);
|
||||||
@ -247,7 +275,7 @@ bool ExceptionHandler::InternalWriteMinidump(int signo,
|
|||||||
|
|
||||||
// Unblock the signals.
|
// Unblock the signals.
|
||||||
if (blocked) {
|
if (blocked) {
|
||||||
sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
|
sigprocmask(SIG_SETMASK, &sig_old, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback_)
|
if (callback_)
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <signal.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "client/linux/handler/minidump_generator.h"
|
#include "client/linux/handler/minidump_generator.h"
|
||||||
@ -146,6 +147,8 @@ class ExceptionHandler {
|
|||||||
void SetupHandler(int signo);
|
void SetupHandler(int signo);
|
||||||
// Teardown the handler for a signal.
|
// Teardown the handler for a signal.
|
||||||
void TeardownHandler(int signo);
|
void TeardownHandler(int signo);
|
||||||
|
// Teardown the handler for a signal.
|
||||||
|
void TeardownHandler(int signo, struct sigaction *old);
|
||||||
// Teardown all handlers.
|
// Teardown all handlers.
|
||||||
void TeardownAllHandler();
|
void TeardownAllHandler();
|
||||||
|
|
||||||
@ -192,10 +195,6 @@ class ExceptionHandler {
|
|||||||
// when created (with an install_handler parameter set to true).
|
// when created (with an install_handler parameter set to true).
|
||||||
bool installed_handler_;
|
bool installed_handler_;
|
||||||
|
|
||||||
// Keep the previous handlers for the signal.
|
|
||||||
typedef void (*sighandler_t)(int);
|
|
||||||
std::map<int, sighandler_t> old_handlers_;
|
|
||||||
|
|
||||||
// The global exception handler stack. This is need becuase there may exist
|
// The global exception handler stack. This is need becuase there may exist
|
||||||
// multiple ExceptionHandler instances in a process. Each will have itself
|
// multiple ExceptionHandler instances in a process. Each will have itself
|
||||||
// registered in this stack.
|
// registered in this stack.
|
||||||
@ -210,6 +209,16 @@ class ExceptionHandler {
|
|||||||
// disallow copy ctor and operator=
|
// disallow copy ctor and operator=
|
||||||
explicit ExceptionHandler(const ExceptionHandler &);
|
explicit ExceptionHandler(const ExceptionHandler &);
|
||||||
void operator=(const ExceptionHandler &);
|
void operator=(const ExceptionHandler &);
|
||||||
|
|
||||||
|
// The sigactions structure we use for each signal
|
||||||
|
struct sigaction act_;
|
||||||
|
|
||||||
|
|
||||||
|
// Keep the previous handlers for the signal.
|
||||||
|
// We're wasting a bit of memory here since we only change
|
||||||
|
// the handler for some signals but i want to avoid allocating
|
||||||
|
// memory in the signal handler
|
||||||
|
struct sigaction old_actions_[NSIG];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
Loading…
x
Reference in New Issue
Block a user