2020-09-01 21:28:46 +02:00
/*
Copyright ( c ) 2012 , Samsung R & D Institute Russia
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
1. Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
/*! @file death_handler.h
* @ brief Declaration of the SIGSEGV / SIGABRT handler which prints the debug stack
* trace .
* @ author Markovtsev Vadim < gmarkhor @ gmail . com >
* @ version 1.0
* @ license Simplified BSD License
* @ copyright 2012 Samsung R & D Institute Russia , 2016 Moscow Institute of Physics and Technology
*/
/*! @mainpage SIGSEGV/SIGABRT handler which prints the debug stack trace.
* Example
* = = = = = = =
* ~ ~ ~ ~ { . cc }
* # include " death_handler.h "
*
* int main ( ) {
* Debug : : DeathHandler dh ;
* int * p = NULL ;
* * p = 0 ;
* return 0 ;
* }
* ~ ~ ~ ~
*
* Underlying code style is very similar to [ Google C + + Style Guide ] ( http : //google-styleguide.googlecode.com/svn/trunk/cppguide.xml). It is checked with cpplint.py.
*/
# ifndef DEATH_HANDLER_H_
# define DEATH_HANDLER_H_
# include <stddef.h>
# include <unistd.h>
// We have to override malloc() and free()
extern " C " {
void * __malloc_impl ( size_t size ) ;
# ifdef __linux__
void * malloc ( size_t size ) throw ( ) ;
void free ( void * ptr ) throw ( ) ;
# elif defined(__APPLE__)
void * __malloc_zone ( struct _malloc_zone_t * zone , size_t size ) ;
void __free_zone ( struct _malloc_zone_t * zone , void * ptr ) ;
# endif
}
# ifdef __linux__
// Comment this out on systems without quick_exit()
# define QUICK_EXIT
# endif
namespace Debug {
/// @brief This class installs a SEGFAULT signal handler to print
/// a nice stack trace and (if requested) generate a core dump.
/// @details In DeathHandler's constructor, a SEGFAULT signal handler
/// is installed via sigaction(). If your program encounters a segmentation
/// fault, the call stack is unwinded with backtrace(), converted into
/// function names with line numbers via addr2line (fork() + execlp()).
/// Addresses from shared libraries are also converted thanks to dladdr().
/// All C++ symbols are demangled. Printed stack trace includes the faulty
/// thread id obtained with pthread_self() and each line contains the process
/// id to distinguish several stack traces printed by different processes at
/// the same time.
class DeathHandler {
public :
typedef ssize_t ( * OutputCallback ) ( const char * , size_t ) ;
/// @brief Installs the SIGSEGV/etc. signal handler.
/// @param altstack If true, allocate and use a dedicated signal handler stack.
/// backtrace() will report nothing then, but the handler will survive a stack
/// overflow.
DeathHandler ( bool altstack = false ) ;
/// @brief This is called on normal program termination. Previously installed
/// SIGSEGV and SIGABRT signal handlers are removed.
~ DeathHandler ( ) ;
/// @brief Sets the value of cleanup property.
/// @details If cleanup is set to true, program attempts to run all static
/// destructors and atexit() callbacks before terminating. If
/// generate_core_dump is set to true, this property is ignored.
/// @note Default value of this property is true.
bool cleanup ( ) const ;
/// @brief Returns the value of cleanup property.
/// @details If cleanup is set to true, program attempts to run all static
/// destructors and atexit() callbacks before terminating. If
/// generate_core_dump is set to true, this property is ignored.
/// @note Default value of this property is true.
void set_cleanup ( bool value ) ;
/// @brief Returns the current value of generate_core_dump property.
/// @details If generate_core_dump is set to true, a core dump will
/// be generated when the program terminates. This behavior
/// is implemented using abort(). cleanup property is ignored.
/// @note You need to set ulimit to a value different from the default 0
/// (for example, "ulimit -c unlimited") to enable core dumps generation
/// on your system.
/// @note Default value of this property is true.
bool generate_core_dump ( ) const ;
/// @brief Sets the value of generate_core_dump property.
/// @details If generate_core_dump is set to true, a core dump will
/// be generated when the program terminates. This behavior
/// is implemented using abort(). cleanup property is ignored.
/// @note You need to set ulimit to a value different from the default 0
/// (for example, "ulimit -c unlimited") to enable core dumps generation
/// on your system.
/// @note Default value of this property is true.
void set_generate_core_dump ( bool value ) ;
# ifdef QUICK_EXIT
/// @brief Returns the value of quick_exit property.
/// @details If quick_exit is set to true, program will be terminated with
/// quick_exit() call. generate_core_dump and cleanup properties are
/// ignored.
/// @note Default value is false.
bool quick_exit ( ) const ;
/// @brief Sets the value of quick_exit property.
/// @details If quick_exit is set to true, program will be terminated with
/// quick_exit() call. generate_core_dump and cleanup properties are
/// ignored.
/// @note Default value is false.
void set_quick_exit ( bool value ) ;
# endif
/// @brief Returns the depth of the stack trace.
/// @note Default value is 16.
int frames_count ( ) const ;
/// @brief Sets the depth of the stack trace. Accepted range is 1..100.
/// @note Default value is 16.
void set_frames_count ( int value ) ;
/// @brief Returns the value indicating whether to shorten stack trace paths
/// by cutting off the common root between each path and the current working
/// directory.
/// @note Default value is true.
bool cut_common_path_root ( ) const ;
/// @brief Sets the value indicating whether to shorten stack trace paths
/// by cutting off the common root between each path and the current working
/// directory.
/// @note Default value is true.
void set_cut_common_path_root ( bool value ) ;
/// @brief Returns the value indicating whether to shorten stack trace paths
/// by cutting off the relative part (e.g., "../../..").
/// @note Default value is true.
bool cut_relative_paths ( ) const ;
/// @brief Sets the value indicating whether to shorten stack trace paths
/// by cutting off the relative part (e.g., "../../..").
/// @note Default value is true.
void set_cut_relative_paths ( bool value ) ;
/// @brief Returns the value indicating whether to append the process id
/// to each stack trace line.
/// @note Default value is false.
bool append_pid ( ) const ;
/// @brief Sets the value indicating whether to append the process id
/// to each stack trace line.
/// @note Default value is false.
void set_append_pid ( bool value ) ;
/// @brief Returns the value indicating whether to color the output
/// with ANSI escape sequences.
/// @note Default value is true.
bool color_output ( ) const ;
/// @brief Sets the value indicating whether to color the output
/// with ANSI escape sequences.
/// @note Default value is true.
void set_color_output ( bool value ) ;
/// @brief Returns the value indicating whether to do a thread-safe
/// stack trace printing, stopping all running threads by forking.
/// @note Default value is true.
bool thread_safe ( ) const ;
/// @brief Sets the value indicating whether to do a thread-safe stack trace
/// printing, stopping all running threads by forking.
/// @note Default value is true.
void set_thread_safe ( bool value ) ;
/// @brief Returns the current output callback.
/// @note Default value is write to stderr.
OutputCallback output_callback ( ) const ;
/// @brief Changes output callback (that is, how to write the trace, etc.).
/// @note Default value is write to stderr.
void set_output_callback ( OutputCallback value ) ;
2020-09-02 01:11:38 +02:00
static void HandleSignal ( int sig , void * info , void * secret ) ;
2020-09-01 21:28:46 +02:00
private :
friend void * : : __malloc_impl ( size_t ) ;
# ifdef __linux__
friend void * : : malloc ( size_t ) throw ( ) ;
friend void : : free ( void * ) throw ( ) ;
# elif defined(__APPLE__)
friend void * : : __malloc_zone ( struct _malloc_zone_t * , size_t ) ;
friend void : : __free_zone ( struct _malloc_zone_t * , void * ) ;
# endif
/// @brief Reentrant printing to stderr.
inline static void print ( const char * msg , size_t len = 0 ) ;
/// @brief The size of the preallocated memory to use in the signal handler.
static const size_t kNeededMemory ;
/// @brief Used to workaround backtrace() usage of malloc().
static void * malloc_ ;
static void * free_ ;
static bool heap_trap_active_ ;
static bool generate_core_dump_ ;
static bool cleanup_ ;
# ifdef QUICK_EXIT
static bool quick_exit_ ;
# endif
static int frames_count_ ;
static bool cut_common_path_root_ ;
static bool cut_relative_paths_ ;
static bool append_pid_ ;
static bool color_output_ ;
static bool thread_safe_ ;
static OutputCallback output_callback_ ;
/// @brief The preallocated memory to use in the signal handler.
static char * memory_ ;
} ;
} // namespace Debug
# endif // DEATH_HANDLER_H_