Commits

Anonymous committed d338eaa

added a stripped-down version of the seal signal handler

Comments (0)

Files changed (8)

+2008-10-28  Wim Lavrijsen <WLavrijsen@lbl.gov>
+        * added a stripped-down version of the seal signal handler
+        * tagging CxxUtils-00-00-05
+
 2008-10-22  scott s snyder  <snyder@bnl.gov>
 
 	* Tagging CxxUtils-00-00-04.

CxxUtils/SealCommon.h

+/**
+ * @file CxxUtils/SealCommon.h
+ * @author Wim Lavrijsen <WLavrijsen@lbl.gov>
+ * @date Oct, 2008
+ * @brief Collecting a few shared bits and pieces from SEAL headers.
+ */
+
+#ifndef CXXUTILS_SEAL_COMMON_H
+#define CXXUTILS_SEAL_COMMON_H
+
+// start copy from "SealBase/sysapi/IOTypes.h"
+/** Invalid channel descriptor constant.  */
+#ifdef _WIN32
+#define IOFD_INVALID (void *)-1
+#else
+#define IOFD_INVALID -1
+#endif
+
+/** Type the system uses for channel descriptors.  */
+#ifdef _WIN32
+typedef void *IOFD;
+#else
+typedef int   IOFD;
+#endif
+// end copy from IOTypes
+
+
+// platform specific defines from SealPlatform/config.h
+#ifdef __linux
+
+/* C++ features --------------------------------------------------------- */
+
+/* Define if you have standard C++ C headers like <cstdlib>. */
+#define HAVE_CXX_STDC_HEADERS 1
+
+/* Signals -------------------------------------------------------------- */
+
+/* Define if you have POSIX signal stuff.  */
+#define HAVE_POSIX_SIGNALS 1
+
+/* Define if you have POSIX real-time signal stuff.  */
+#define HAVE_POSIX_RT_SIGNALS 1
+
+/* Define if you have the strsignal function.  */
+#define HAVE_STRSIGNAL 1
+#define HAVE_STRSIGNAL_DECL 1
+
+/* Define if you have raise. */
+#define HAVE_RAISE 1
+#define HAVE_RAISE_DECL 1
+
+/* Define if you have sys_siglist in <signal.h>.  */
+#define HAVE_SYS_SIGLIST 1
+
+/* Resource information ------------------------------------------------- */
+
+/* Define if you have program_invocation_name.  */
+#define HAVE_PROGRAM_INVOCATION_NAME 1
+
+/* Stack tracing -------------------------------------------------------- */
+
+/* Define if you have pstack (usually in /usr/proc/bin) to the full
+   path of that program.  */
+#define PROG_PSTACK "/usr/bin/pstack"
+
+/* Define if you have c++filt to the full path of that program.  */
+#define PROG_CXXFILT "/usr/bin/c++filt"
+
+/* Define if you have backtrace and backtrace_symbols_fd (glibc 2.1).  */
+#define HAVE_BACKTRACE_SYMBOLS_FD 1
+
+/* Dynamic linker ------------------------------------------------------- */
+
+/* Define if `dlopen' exists. */
+#define HAVE_DLOPEN 1
+#define HAVE_DLOPEN_DECL 1
+
+/* Define if you have the <link.h> header file.  */
+#define HAVE_LINK_H 1
+
+/* Define if `dladdr' exists. */
+#define HAVE_DLADDR 1
+#define HAVE_DLADDR_DECL 1
+
+/* Define if `_r_debug' exists. */
+#define HAVE_R_DEBUG 1
+
+/* Define if you have the <elf.h> header file.  */
+#define HAVE_ELF_H 1
+
+#endif
+
+
+#if HAVE_LOAD
+# define PATH		"LIBPATH"
+#elif HAVE_DLOPEN
+# if defined __APPLE__ && defined __MACH__
+#  define PATH		"DYLD_LIBRARY_PATH"
+# else
+#  define PATH		"LD_LIBRARY_PATH"
+# endif
+#elif HAVE_SHL_LOAD
+# define PATH		"SHLIB_PATH"
+#elif defined _WIN32
+# define PATH		"PATH"
+#else
+# define PATH		0
+#endif
+// end copy from SealBase/sysapi/SharedLibrary.h
+
+
+// start copy from SealPlatform/system.h
+#if HAVE_CXX_STDC_HEADERS
+# define STDC std
+#else
+# define STDC
+#endif
+// end copy from SealPlatform/system.h
+
+
+// start copy from SealBase/sysapi/ElfAbi.h
+# ifndef _WIN32
+#  if HAVE_LOADER_H
+#   include <loader.h>
+#  endif
+#  if HAVE_LINK_H
+#   include <link.h>
+#   include <limits.h>
+#   include <sys/stat.h>
+#   include <unistd.h>
+#  endif
+#  if HAVE_SGIDEFS_H    // irix n32, 64
+#   include <sgidefs.h>
+#   include <objlist.h>
+#   include <obj_list.h>
+#   include <obj.h>
+#  endif
+#  if HAVE_ELF_H
+#   include <elf.h>
+#  endif
+# endif // ! _WIN32
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+
+#if /* irix */       (defined ABI64 || defined _ABI64 ||                \
+                      (defined _MIPS_SIM && _MIPS_SIM == _MIPS_SIM_ABI64)) \
+    /* solaris */ || (defined sparcv9 || defined _sparcv9               \
+                      || defined __sparcv9 || defined __sparcv9__)      \
+    /* tru64 */   || (defined arch64 || defined _arch64 ||              \
+                      defined __arch64 || defined __arch64__)
+# define ELF_ABI 64
+#else
+# define ELF_ABI 32
+#endif
+#ifndef ElfW
+# define ElfW(type)   ElfW1(Elf,ELF_ABI,type)
+# define ElfW1(e,w,t) ElfW2(Elf,w,_##t)
+# define ElfW2(e,w,t) e ## w ## t
+#endif
+// end copy from SealBase/sysapi/ElfAbi.h
+
+#endif // CXXUTILS_SEAL_COMMON_H

CxxUtils/SealDebug.h

+/**
+ * @file CxxUtils/SealDebug.h
+ * @author Lassi Tuura (original author)
+ * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS)
+ * @date Oct, 2008
+ * @brief This are the SEAL debug aids, adapted to build in Atlas,
+ *        after the drop of that project.
+ *
+ *        Search for `wlav' to find changes from the SEAL version. I
+ *        also dropped all ASSERT macro's in favor of assert. Removed
+ *        logstream references.
+ */
+
+#ifndef CXXUTILS_SEAL_DEBUG_H // wlav SEAL_BASE_DEBUG_H
+#define CXXUTILS_SEAL_DEBUG_H // wlav SEAL_BASE_DEBUG_H
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+//# include "SealBase/Macros.h"                   wlav
+//# include "SealBase/sysapi/IOTypes.h"           wlav
+# include <cstddef>
+
+// wlav copied from SealBase/sysapi/DebugAids.h
+// Windows doesn't have this, so fake a suitable substitute
+# ifdef _WIN32
+#  define STDERR_HANDLE GetStdHandle (STD_ERROR_HANDLE)
+# else
+#  define STDERR_HANDLE STDERR_FILENO
+# endif
+
+// Define a suitable wrapper to write to system file descriptors.
+// This is needed because on Windows we are using HANDLEs, not the
+// compiler's crippled posixy interface.
+# ifdef _WIN32
+#  define MYWRITE(fd,data,n)    do { DWORD written; WriteFile(fd,data,n,\
+                                        &written,0); } while (0)
+# else
+#  define MYWRITE(fd,data,n)    write(fd,data,n)
+# endif
+
+
+//namespace seal {                                wlav
+namespace Athena {                             // wlav
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+/** Utilities for debugging support.  */
+class DebugAids
+{
+public:
+    // Miscellaneous functions
+    static IOFD			stacktraceFd (IOFD fd = IOFD_INVALID);
+    static void			stacktrace (IOFD fd = IOFD_INVALID);
+    static void			coredump (int sig, ...);
+
+private:
+    static IOFD			s_stackTraceFd;
+};
+
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+
+//} // namespace seal                             wlav
+} // namespace Athena                             wlav
+#endif // CXXUTILS_SEAL_DEBUG_H wlav SEAL_BASE_DEBUG_H

CxxUtils/SealSharedLib.h

+/**
+ * @file CxxUtils/SealSharedLib.h
+ * @author Lassi Tuura (original author)
+ * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS)
+ * @date Oct, 2008
+ *
+ *        Search for `wlav' to find changes from the SEAL version. I
+ *        also dropped all ASSERT macro's in favor of assert.
+ */
+
+#ifndef CXXUTILS_SEAL_SHAREDLIB_H // wlav SEAL_BASE_SHARED_LIBRARY_H
+#define CXXUTILS_SEAL_SHAREDLIB_H // wlav SEAL_BASE_SHARED_LIBRARY_H
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+//# include "SealBase/SharedLibraryError.h"       wlav
+//# include "SealBase/Callback.h"                 wlav
+# include <string>
+# include <list>
+# include <exception>                          // wlav
+
+//namespace seal {                                wlav
+namespace Athena {                             // wlav
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+
+// wlav from SealBase/Callback.h
+template <class T1>
+class Callback1Rep
+{
+public:
+    Callback1Rep (void) : m_refs (0) { }
+    virtual ~Callback1Rep (void) { }
+
+    virtual void	call (T1) = 0;
+    virtual bool	equal (const Callback1Rep *x) const = 0;
+
+    void		ref (void)	{ ++m_refs; }
+    void		unref (void)	{ if (--m_refs == 0) delete this; }
+
+private:
+    int			m_refs;
+};
+
+template <class T1>
+class Callback1
+{
+public:
+    Callback1 (Callback1Rep<T1> *implementation = 0);
+    Callback1 (const Callback1 &x);
+    ~Callback1 (void);
+    Callback1 &	operator= (const Callback1 &x);
+
+    bool		operator== (const Callback1 &x) const;
+    /**/		operator bool (void) const;
+    void		operator() (T1) const;
+
+private:
+    Callback1Rep<T1>	*m_rep;
+};
+
+template <class T1, class T2>
+class CallbackImpF11 : public Callback1Rep<T1>
+{
+    typedef CallbackImpF11 self;
+public:
+    CallbackImpF11 (void (*function) (T1, T2),
+		    const T2 &fill_2)
+	: m_function (function),
+	  m_fill_2 (fill_2)
+    { }
+
+    virtual void call (T1 a)
+    { (*m_function) (a, m_fill_2); }
+
+    virtual bool equal (const Callback1Rep<T1> *other) const
+	{ const self *x = dynamic_cast<const self *> (other);
+	  return x && x->m_function == m_function && x->m_fill_2 == m_fill_2; }
+
+private:
+    void	(*m_function) (T1, T2);
+    T2		m_fill_2;
+};
+
+template <class T1>
+inline
+Callback1<T1>::Callback1 (Callback1Rep<T1> *implementation /* = 0 */)
+    : m_rep (implementation)
+{ if (m_rep) m_rep->ref (); }
+
+template <class T1>
+inline
+Callback1<T1>::Callback1 (const Callback1<T1> &x)
+    : m_rep (x.m_rep)
+{ if (m_rep) m_rep->ref (); }
+
+template <class T1>
+inline
+Callback1<T1>::~Callback1 (void)
+{ if (m_rep) m_rep->unref (); }
+
+template <class T1>
+inline Callback1<T1> &
+Callback1<T1>::operator= (const Callback1<T1> &x)
+{
+    if (m_rep != x.m_rep)
+    {
+	if (m_rep) m_rep->unref ();
+	m_rep = x.m_rep;
+	if (m_rep) m_rep->ref ();
+    }
+    return *this;
+}
+
+template <class T1>
+inline bool
+Callback1<T1>::operator== (const Callback1<T1> &x) const
+{ return m_rep == x.m_rep || (m_rep && x.m_rep && m_rep->equal (x.m_rep)); }
+
+template <class T1>
+inline
+Callback1<T1>::operator bool (void) const
+{ return m_rep ? true : false; } // FIXME: for Sun CC 4.2 (no bool)
+
+template <class T1>
+inline void
+Callback1<T1>::operator() (T1 a) const
+{ m_rep->call (a); }
+
+template <class T1, class T2>
+inline Callback1Rep<T1> *
+CreateCallback (void (*function) (T1, T2),
+		const T2 &fill_2)
+{ return new CallbackImpF11<T1,T2> (function, fill_2); }
+
+
+// wlav modiefied from SealBase/SharedLibraryError.h
+/** Error in a shared library operation. */
+class SharedLibraryError : public std::exception
+{
+public:
+    SharedLibraryError( const char *context, const std::string &cause );
+    virtual ~SharedLibraryError() throw() {}
+
+    virtual const char* what() const throw();
+
+private:
+    std::string		m_context;
+    std::string		m_cause;
+};
+
+
+/** Shared library services.  */
+class SharedLibrary
+{
+public:
+    typedef void *		Data;
+    typedef void		(*Function) (void);
+
+    /** Information about a currently loaded shared library.  */
+    struct LibraryInfo
+    {
+	unsigned long		m_text_start;	//< Start of text segment
+	unsigned long		m_text_end;	//< End of text segment
+	unsigned long		m_data_start;	//< Start of data segment
+	unsigned long		m_data_end;	//< End of data segment
+	unsigned long		m_bss_start;	//< Start of common
+	unsigned long		m_bss_end;	//< End of common
+	const char		*m_filename;	//< Filename
+    };
+
+    typedef Callback1<const LibraryInfo &> InfoHandler;
+
+    static std::string		path (void);
+    static void			path (const std::string &path);
+    static std::string		libname (const std::string &name);
+    static std::string		symname (const std::string &name);
+
+    static SharedLibrary *	self (void);
+    static SharedLibrary *	load (const std::string &name);
+    static void			loaded (const InfoHandler &handler);
+
+    void			release (void);
+    void			abandon (void);
+
+    Data			data (const std::string &name, bool mangle = true) const;
+    Function			function (const std::string &name, bool mangle = true) const;
+
+protected:
+    SharedLibrary (void *handle);
+    ~SharedLibrary (void);
+
+private:
+    void			*m_handle;
+
+    // undefined semantics
+    SharedLibrary (const SharedLibrary &);
+    SharedLibrary &operator= (const SharedLibrary &);
+};
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+
+//} // namespace seal                             wlav
+} // namespace Athena                             wlav
+#endif // CXXUTILS_SEAL_SHAREDLIB_H wlav SEAL_BASE_SHARED_LIBRARY_H

CxxUtils/SealSignal.h

+/**
+ * @file CxxUtils/SealSignal.h
+ * @author Lassi Tuura (original author)
+ * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS)
+ * @date Oct, 2008
+ * @brief This is the signal handler from SEAL, adapted to build in Atlas,
+ *        after the drop of that project.
+ *
+ *        Search for `wlav' to find changes from the SEAL version. I
+ *        also dropped all ASSERT macro's in favor of assert.
+ */
+
+#ifndef CXXUTILS_SEAL_SIGNAL_H // wlav SEAL_BASE_SIGNAL_H
+#define CXXUTILS_SEAL_SIGNAL_H // wlav SEAL_BASE_SIGNAL_H
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+//# include "SealBase/sysapi/IOTypes.h"           wlav
+
+// These should be hidden, but we can't do that for now: the clients
+// must be able to operate on sigset_t and pid_t.  Note that we do not
+// want to have <csignal> -- we need all the extra POSIX stuff.
+# include <signal.h>
+# include <sys/types.h>
+
+//<<<<<< PUBLIC DEFINES                                                 >>>>>>
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+//<<<<<< PUBLIC FUNCTIONS                                               >>>>>>
+//<<<<<< CLASS DECLARATIONS                                             >>>>>>
+
+# if !HAVE_POSIX_SIGNALS
+// Forward declare POSIX signal handling stuff for platforms that
+// don't have them.  This allows them to be mentioned in the Signal
+// interface and minimally used in the clients.  Special kludge for
+// Windows.
+#  ifdef _WIN32
+typedef struct _EXCEPTION_RECORD siginfo_t;
+#define SIGHUP          1       /* Hangup (POSIX).  */
+#define SIGQUIT         3       /* Quit (POSIX).  */
+#define SIGTRAP         5       /* Trace trap (POSIX).  */
+#define SIGKILL         9       /* Kill, unblockable (POSIX).  */
+#define SIGUSR1         10      /* User-defined signal 1 (POSIX).  */
+#define SIGUSR2         12      /* User-defined signal 2 (POSIX).  */
+#define SIGPIPE         13      /* Broken pipe (POSIX).  */
+#define SIGALRM         14      /* Alarm clock (POSIX).  */
+#define SIGCHLD         17      /* Child status has changed (POSIX).  */
+#define SIGCONT         18      /* Continue (POSIX).  */
+#define SIGSTOP         19      /* Stop, unblockable (POSIX).  */
+#define SIGTSTP         20      /* Keyboard stop (POSIX).  */
+#define SIGTTIN         21      /* Background read from tty (POSIX).  */
+#define SIGTTOU         22      /* Background write to tty (POSIX).  */
+#  else
+struct siginfo_t {};
+#  endif
+
+typedef int sigset_t;
+
+#  define sigemptyset(x) 	 (0)
+#  define sigfillset(x)  	 (0)
+#  define sigaddset(x,y) 	 (0)
+#  define sigdelset(x,y) 	 (0)
+#  define sigismember(x,y) (0)
+# endif
+
+//namespace seal {                                wlav
+namespace Athena {                             // wlav
+
+// wlav copied from SealBase/BitTraits.h
+/** Describe the bit features of an integral type @c T. */
+template <class T>
+struct BitTraits
+{
+    /// Number of bits in @c T.
+    enum { Bits		= sizeof (T) * CHAR_BIT };
+
+    /// Number of 8-bit bytes in @c T.
+    enum { Bytes	= Bits / 8 + ((Bits % 8) > 0) };
+
+    /// Number of base-10 digits in @c T (without leading sign).
+    enum { Digits	= (Bits * 30103) / 100000 + 1 };
+    // 30103 =~ M_LN2 / M_LN10 * 100000
+
+    /// Number of base-16 digits in @c T (without leading sign).
+    enum { HexDigits	= Bits / 4 + ((Bits % 4) > 0) };
+};
+
+
+/** Utilities for handling signals and fatal errors.
+
+    FIXME: POSIX single-threaded vs. multi-threaded signals?
+         - all threads should block all the signals
+         - one thread should do sigwait.
+
+    The fatal error handling is largely inspired by code in DDD, the
+    Data Display Debugger, and by the examples in GNU libc manual. */
+class Signal
+{
+public:
+    /** Option that instructs #fatal() to call #coredump() on SIGUSR1.
+	This is merely a request to drop a @c core; no attempt is made
+	to guarantee success.  Failure may result for example for lack
+	of permissions, for lack of disk space, or due to low resource
+	limits.  Please note that @c core files can only be created on
+	unixen.  Note also that dropping a core is a security risk and
+	should never be enabled in setuid or setgid programs or for
+	production applications.  */
+    static const int USR1_DUMP_CORE	= 1;
+
+    /** Option to make SIGHUP, SIGTERM and SIGQUIT fatal instead of
+	just #quit() signals.  */
+    static const int FATAL_ON_QUIT	= 2;
+
+    /** Option to make SIGINT fatal.  It will still just quit, not
+        crash.  */
+    static const int FATAL_ON_INT	= 4;
+
+    /** Option to make #fatal() dump a core file before crashing.  */
+    static const int FATAL_DUMP_CORE	= 8;
+
+    /** Option to make #fataldump() (invoked by #fatal()) to dump the
+	signal name (as reported by #name()).  */
+    static const int FATAL_DUMP_SIG	= 16;
+
+    /** Option to make #fataldump() (invoked by #fatal()) to dump
+	stack backtrace for the offending code location.  */
+    static const int FATAL_DUMP_STACK	= 32;
+
+    /** Option to make #fataldump() (invoked by #fatal()) to dump the
+	list of currently loaded shared libraries.  */
+    static const int FATAL_DUMP_LIBS	= 64;
+
+    /** Option to make #fataldump() (invoked by #fatal()) to dump the
+	machine context (registers etc.) from the fault position.  */
+    static const int FATAL_DUMP_CONTEXT	= 128;
+
+    /** Option to make #fatal() exit via #quit().  This will cause all
+	the appliction clean-up hook to run.  */
+    static const int FATAL_AUTO_EXIT	= 256;
+
+    /** Default options to #handleFatal().  */
+    static const int FATAL_DEFAULT  = (USR1_DUMP_CORE
+				       | FATAL_ON_INT
+				       | FATAL_DUMP_CORE
+				       | FATAL_DUMP_SIG
+				       | FATAL_DUMP_STACK
+				       | FATAL_DUMP_LIBS
+				       | FATAL_DUMP_CONTEXT
+				       | FATAL_AUTO_EXIT);
+
+    /** Application clean-up hook invoked before #quit() exits from
+	program termination signals (SIGHUP, SIGTERM or SIGQUIT).
+
+	The handler should return @c true if the signal handler should
+	proceed to exit the application.  Note that certain options to
+	#handlFatal() cause this hook to be invoked for fatal signals.
+	If such behaviour is enabled, be sure to check the #crashed()
+	status before deciding to let the application to continue.
+
+	The quit hook should take care of resetting terminal modes,
+	killing child processes, removing lock files, and so forth.  */
+    typedef bool		(*QuitHook) (int sig, siginfo_t *info, void *x);
+
+    /** Application hook to run in fatal().  The hook should return @c
+	true if the signal handler should proceed to die.  @a sig is
+	the signal number, or its negative if core was dumped and, as
+	far as can determined, successfully produced.
+
+	The fatal hooks should, if possible, perform clean-ups similar
+	to #QuitHook.  The application may achieve this by actually
+	using the quit by setting #FATAL_AUTO_EXIT for #handleFatal(),
+	or it could reuse an internal function in both handlers.  */
+    typedef bool		(*FatalHook) (int sig, siginfo_t *info, void *x);
+
+    /** Application hook to jump back to the main program from a fatal
+	signal, for example using #siglongjmp.  It must never return.
+	@a sig is the signal number, or its negative if core was
+	dumped and, as far as can determined, successfully produced.  */
+    typedef void		(*FatalReturn) (int sig, siginfo_t *info, void *x);
+
+    /** Signal handler type.  This is defined explicitly and does not
+	necessarily match the system's concept of signal handler type.
+	If necessary, suitable trampolines are used internally to make
+	sure the arguments make sense.
+
+	@param sig	The signal number.
+	@param info	Pointer to signal info.  This pointer will
+			be null on platforms that do not support
+			POSIX signals.
+	@param extra	Extra argument, e.g. the fault address.
+			This pointer will be null on platforms
+			that do not support POSIX signals.  */
+    typedef void (*HandlerType) (int sig, siginfo_t *info, void *extra);
+
+
+    // Generic signal operations
+    // - Signal names
+    static const char *		name (int sig);
+
+    // - Signal handlers and masks
+    static HandlerType		handler (int sig, sigset_t *mask = 0);
+    static HandlerType		handle (int sig, HandlerType handler,
+					const sigset_t *blockMask = 0);
+    static void			revert (int sig);
+    static void			ignore (int sig);
+
+    static void			block (int sig, bool sense);
+    static void			block (const sigset_t *mask, bool sense);
+    static void			mask (const sigset_t *mask, sigset_t *old = 0);
+
+    // - Sending and receiving signals
+    static int			raise (int sig);
+    static int			kill (pid_t process, int sig);
+    static int			queue (int sig, int value = 0);
+    static int			queue (int sig, void *value);
+    static int			queue (pid_t process, int sig, int value = 0);
+    static int			queue (pid_t process, int sig, void *value);
+
+    static bool			pending (int sig);
+    static void			pending (sigset_t *mask);
+    static void			suspend (const sigset_t *mask);
+    static bool			wait (int		sig,
+				      siginfo_t		*info = 0,
+				      long		msecs = -1);
+    static int			wait (const sigset_t	*mask,
+				      siginfo_t		*info = 0,
+				      long		msecs = -1);
+
+    // Assisted handling of program termination signals
+    static void			handleQuit (QuitHook hook = 0);
+    static QuitHook		handleQuitHook (void);
+
+    static void			quit (int sig, siginfo_t *info, void *x);
+
+    // Assisted handling of fatal signals
+    static void			handleFatal (const char *applicationName = 0,
+					     IOFD fd = IOFD_INVALID,
+					     FatalHook hook = 0,
+					     FatalReturn mainreturn = 0,
+					     unsigned options = FATAL_DEFAULT);
+    static IOFD			handleFatalFd (void);
+    static FatalHook		handleFatalHook (void);
+    static FatalReturn		handleFatalReturn (void);
+    static unsigned		handleFatalOptions (void);
+
+    static void			fatal (int sig, siginfo_t *info, void *x);
+    static bool			fatalDump (int sig, siginfo_t *info, void *x);
+    static int			fatalLevel (void);
+    static bool			crashed (void);
+
+    static void			dumpInfo    (IOFD fd, char *buf, int sig,
+					     const siginfo_t *info);
+    static void			dumpMemory  (IOFD fd, char *buf,
+					     const void *data, size_t n);
+    static void			dumpContext (IOFD fd, char *buf,
+					     const void *context);
+
+private:
+    static void			trampoline (int sig);
+    static const char *		describe (int sig, int code);
+
+    static bool			s_crashed;
+    static int			s_inFatal;
+    static const char		*s_applicationName;
+    static IOFD			s_fatalFd;
+    static FatalHook		s_fatalHook;
+    static FatalReturn		s_fatalReturn;
+    static unsigned		s_fatalOptions;
+    static QuitHook		s_quitHook;
+#if !HAVE_POSIX_SIGNALS
+    static HandlerType		s_trampolines [NSIG];
+#endif
+};
+
+//<<<<<< INLINE PUBLIC FUNCTIONS                                        >>>>>>
+//<<<<<< INLINE MEMBER FUNCTIONS                                        >>>>>>
+
+//} // namespace seal                             wlav
+} // namespace Athena                             wlav
+#endif // CXXUTILS_SEAL_SIGNAL_H wlav SEAL_BASE_SIGNAL_H

src/SealDebug.cxx

+/**
+ * @file CxxUtils/src/SealDebug.cxx
+ * @author Lassi Tuura (original author)
+ * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS)
+ * @date Oct, 2008
+ *
+ *        Search for `wlav' to find changes from the SEAL version. All
+ *        includes were modified, all ASSERT macro's were dropped in
+ *        favor of assert, only stack trace functionality was kept.
+ */
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "CxxUtils/SealCommon.h"               // wlav
+#include "CxxUtils/SealDebug.h"                // wlav
+#include "CxxUtils/SealSignal.h"               // wlav
+#include "CxxUtils/SealSharedLib.h"            // wlav
+
+// wlav copied from SealBase/sysapi/DebugAids.h
+# include <cctype>
+# include <cstdio>
+# include <cstdlib>
+# include <iostream>
+# include <iomanip>
+
+# ifdef _WIN32
+#  include <windows.h>
+#  include <winnt.h>
+#  include <imagehlp.h>
+//#  include <io.h>
+# else
+#  include <unistd.h>
+#  include <sys/wait.h>
+#  if HAVE_BACKTRACE_SYMBOLS_FD		// GNU
+#   include <execinfo.h>
+#   include <sys/uio.h>
+#  endif
+#  if HAVE_DLADDR			// Linux, Solaris
+#   include <dlfcn.h>
+#  endif
+# if HAVE_EXCEPTION_H
+    // This is yucky.  KCC's <exception.h> that has nothing to do with the
+    // header we are looking for (it redirect to <exception>).  This ugly
+    // workaround allows us to find the (IRIX) header we are looking for.
+#   if defined __KCC && defined __sgi
+#     include </usr/include/exception.h>
+#    elif defined __sgi
+#     include <exception.h>
+#    endif
+#  endif
+#  if HAVE_EXCPT_H			// IRIX
+#   include <excpt.h>
+#   undef try	  // Defined on SGI to structured exception handling goop
+#   undef catch   // Defined on SGI to structured exception handling goop
+#  endif
+#  if HAVE_RLD_INTERFACE_H		// Tru64 (IRIX)
+#   include <rld_interface.h>
+#  endif
+#  if HAVE_PDSC_H			// Tru64
+#   include <pdsc.h>
+#  endif
+#  if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) // GCC 3.4+ C++ ABI
+#   include <sys/uio.h>
+#  endif
+# endif
+
+// Windows doesn't have this, so fake a suitable substitute
+# ifdef _WIN32
+#  define STDERR_HANDLE GetStdHandle (STD_ERROR_HANDLE)
+# else
+#  define STDERR_HANDLE STDERR_FILENO
+# endif
+
+// Define a suitable wrapper to write to system file descriptors.
+// This is needed because on Windows we are using HANDLEs, not the
+// compiler's crippled posixy interface.
+# ifdef _WIN32
+#  define MYWRITE(fd,data,n)	do { DWORD written; WriteFile(fd,data,n,\
+					&written,0); } while (0)
+# else
+#  define MYWRITE(fd,data,n)	write(fd,data,n)
+# endif
+
+// Helper to write literals
+# define MYWRITELIT(fd,str) MYWRITE(fd,str,sizeof(str)-1)
+
+//<<<<<< PUBLIC CONSTANTS                                               >>>>>>
+//<<<<<< PUBLIC TYPES                                                   >>>>>>
+//<<<<<< PUBLIC VARIABLES                                               >>>>>>
+
+#if HAVE_BACKTRACE_SYMBOLS_FD
+/** The maximum stack trace depth for systems where we request the
+    stack depth separately (GNU libc-based systems).  */
+static const int MAX_BACKTRACE_DEPTH = 128;
+#endif
+
+
+//namespace seal {                                wlav
+namespace Athena {                             // wlav
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+
+/** The default output file descriptor for #stacktrace().  */
+IOFD			DebugAids::s_stackTraceFd = IOFD_INVALID;
+
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+
+#ifdef _WIN32
+// /** WIN32 function to grab the current PC address from the SEH context.
+//     We need this to grab the exception context so we can walk the stack
+//     in #Debug::stacktrace().  We use SEH (as compiler-independently as
+//     we can) as only XP 64-bit has RtlGetContext() function.  */
+// static LONG CALLBACK
+// GrabExceptionContext (PEXCEPTION_POINTERS info)
+// {
+//     *((CONTEXT *) info->ExceptionRecord->ExceptionInformation[0])
+// 	= *info->ContextRecord;
+//     return EXCEPTION_EXECUTE_HANDLER;
+// }
+
+/** Helper function to translate the virtual PC address @a addr into a
+    logical address.  If the address translates to a known module (DLL
+    or executable) memory mapping range, fills @a name (of maximum
+    length @a length) with the name of the module, sets @a section to
+    the index of the memory mapping section within the module, @a
+    offset to a @a addr's relative offset within @a section, and
+    returns @c true.  Otherwise returns @a false and @a name, @a
+    section and @a offset will have undefined values.  Used to
+    translate PC addresses to module addresses during the stack walk.  */
+bool
+GetLogicalAddress (PVOID addr, PTSTR name, DWORD length,
+		   DWORD &section, DWORD &offset)
+{
+    MEMORY_BASIC_INFORMATION info;
+
+    if (! VirtualQuery (addr, &info, sizeof (info)))
+	return false;
+
+    DWORD module = (DWORD) info.AllocationBase;
+    if (! GetModuleFileName ((HMODULE) module, name, length))
+	return false;
+
+    PIMAGE_DOS_HEADER		dosheader = (PIMAGE_DOS_HEADER) module;
+    PIMAGE_NT_HEADERS		ntheader
+	= (PIMAGE_NT_HEADERS) (module + dosheader->e_lfanew);
+    PIMAGE_SECTION_HEADER	sect = IMAGE_FIRST_SECTION (ntheader);
+    DWORD			rva = (DWORD) addr - module;
+
+    for (unsigned i = 0; i < ntheader->FileHeader.NumberOfSections; ++i,++sect)
+    {
+	DWORD sect_start = sect->VirtualAddress;
+	DWORD sect_end = sect_start + std::max (sect->SizeOfRawData,
+					        sect->Misc.VirtualSize);
+
+	if ((rva >= sect_start) && (rva <= sect_end))
+	{
+	    section = i+1;
+	    offset = rva - sect_start;
+	    return true;
+	}
+    }
+
+    assert (false);
+    return false;
+}
+#endif
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) // FIXME: Check
+extern "C" {
+    typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+    struct _Unwind_Context;
+    typedef enum
+    {
+      _URC_NO_REASON = 0,
+      _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+      _URC_FATAL_PHASE2_ERROR = 2,
+      _URC_FATAL_PHASE1_ERROR = 3,
+      _URC_NORMAL_STOP = 4,
+      _URC_END_OF_STACK = 5,
+      _URC_HANDLER_FOUND = 6,
+      _URC_INSTALL_CONTEXT = 7,
+      _URC_CONTINUE_UNWIND = 8
+    } _Unwind_Reason_Code;
+    typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
+    extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+    extern _Unwind_Ptr _Unwind_GetIP (_Unwind_Context *);
+    extern _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
+}
+
+/** IA64-ABI specific stack walking routine.  This is mostly available
+    on platforms with GCC 3.4+, but also with other compilers that have
+    adpoted the same ABI standard.  This walker seems to be limited to
+    walking only through frames with DWARF2 exception data, so it may
+    not be able to go through all C libraries.  It does seem to be
+    able to signal frames on a number of platforms however.  */
+_Unwind_Reason_Code
+unwindWalkStack (_Unwind_Context *ctx, void *data)
+{
+    IOFD		fd = *(IOFD *) data;
+    iovec		bufs [5];
+    int			nbufs = 0;
+    char		addrbuf [5 + BitTraits<unsigned long>::HexDigits];
+    char		diffbuf [10 + 2 * BitTraits<unsigned long>::HexDigits];
+    static const char	trailer [] = "]\n";
+    unsigned long	ip = _Unwind_GetIP (ctx);
+    unsigned long	ir = _Unwind_GetRegionStart (ctx);
+# if HAVE_DLADDR
+    Dl_info		info;
+    if (dladdr ((void *) ir, &info) && info.dli_fname && info.dli_fname[0])
+    {
+	const char	*libname = info.dli_fname;
+	const char	*symname = (info.dli_sname && info.dli_sname[0]
+				    ? info.dli_sname : "?");
+	unsigned long	symaddr = (unsigned long) info.dli_saddr;
+	bool		gte = (ip >= symaddr);
+	unsigned long	diff = (gte ? ip - symaddr : symaddr - ip);
+
+	bufs [nbufs].iov_base = addrbuf;
+	bufs [nbufs].iov_len  = sprintf (addrbuf, " 0x%08lx ", ip);
+	++nbufs;
+
+	bufs [nbufs].iov_base = (char *) symname; // discard const
+	bufs [nbufs].iov_len  = strlen (symname);
+	++nbufs;
+
+	bufs [nbufs].iov_base = diffbuf;
+	bufs [nbufs].iov_len  = sprintf (diffbuf, " %s 0x%lx [",
+					 gte ? "+" : "-", diff);
+	++nbufs;
+
+	bufs [nbufs].iov_base = (char *) libname; // discard const
+	bufs [nbufs].iov_len  = strlen (libname);
+	++nbufs;
+
+	bufs [nbufs].iov_base = (char *) trailer; // discard const
+	bufs [nbufs].iov_len  = 2;
+	++nbufs;
+    }
+    else
+# endif // HAVE_DLADDR
+    {
+	bufs [nbufs].iov_base = addrbuf;
+	bufs [nbufs].iov_len  = sprintf (addrbuf, " 0x%08lx ", ip);
+	++nbufs;
+
+	bufs [nbufs].iov_base = diffbuf;
+	bufs [nbufs].iov_len  = sprintf (diffbuf, " <?%08lx> + 0x%lx\n",
+					 ir, ip - ir);
+        ++nbufs;
+    }
+
+    writev (fd, bufs, nbufs);
+    return _URC_NO_REASON;
+}
+#endif // GCC 3.4+
+
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+
+#if HAVE_U_STACK_TRACE
+// HP-UX stack walker (http://devresource.hp.com/STK/partner/unwind.pdf)
+extern "C" void U_STACK_TRACE (void);
+#endif
+
+#if HAVE_XL_TRBK
+// AIX stack walker (from xlf FORTRAN 90 runtime).
+extern "C" void xl__trbk (void);
+#endif
+
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+/** Set and return the file descriptor for stack trace output.
+
+    If @a fd is the default invalid descriptor value, returns the
+    current value without changing the setting.  This value is only
+    effective for #stacktrace(), but can be overridden by the
+    argument given to that function.  */
+IOFD
+DebugAids::stacktraceFd (IOFD fd /* = IOFD_INVALID */)
+{
+    if (s_stackTraceFd == IOFD_INVALID)
+	s_stackTraceFd = STDERR_HANDLE;
+
+    IOFD old = s_stackTraceFd;
+    if (fd != IOFD_INVALID)
+	s_stackTraceFd = fd;
+    return old;
+}
+
+/** Produce a stack trace.
+
+    Prints the current stack trace to file descriptor @a fd or if the
+    default invalid descriptor, the currently registered stack trace
+    descriptor as registered with #stacktraceFd().  Avoids unnecessary
+    memory allocation so it should be safe to call this function even
+    in dire situations.  On some systems the implementation always
+    outputs to the standard error and has no means for redirection.
+    On these systems an attempt is made to redirect standard error
+    momentarily elsewhere and then redirect standard error to the
+    desired file descriptor, invoke the output, and redirect standard
+    error back to its original location.  If the redirection fails or
+    the system has no stack tracing support, no stack trace is
+    produced.  */
+void
+DebugAids::stacktrace (IOFD fd /* = IOFD_INVALID */)
+{
+    if (s_stackTraceFd == IOFD_INVALID)
+	s_stackTraceFd = STDERR_HANDLE;
+
+    if (fd == IOFD_INVALID)
+	fd = s_stackTraceFd;
+
+    std::cerr.flush ();
+    fflush (stderr);
+
+#ifdef _WIN32
+    // FIXME: Autoload all these functions so users don't need to
+    // link in imagehlp.dll.
+    if (! SymInitialize (GetCurrentProcess (), NULL, TRUE))
+    {
+	MYWRITELIT (fd, ("failed to dump stack trace:"
+			 " cannot get symbolic information\n"));
+	return;
+    }
+
+    union SYMBUFFER {
+	IMAGEHLP_SYMBOL	sym;
+	BYTE		buffer [ sizeof (IMAGEHLP_SYMBOL) + 512 ];
+    };
+
+    unsigned		level = 0;
+    CONTEXT		context;
+    STACKFRAME		frame;
+    SYMBUFFER		symbol;
+    IMAGEHLP_MODULE	module;
+    char		modulename [MAX_PATH];
+    DWORD		section;
+    DWORD		offset;
+    char		buf [2*40+6];  // ample for two 128+ bit numbers
+    // DWORD		exceptargs [] = { (DWORD) &context };
+
+    // FIXME: XP 64-bit adds: RtlCaptureContext (&context);
+    // This is documented to *not* work, but apparently it does.
+    context.ContextFlags = CONTEXT_FULL;
+    if (! GetThreadContext (GetCurrentThread (), &context))
+	return;
+
+    // LPTOP_LEVEL_EXCEPTION_FILTER oldseh
+    //	= SetUnhandledExceptionFilter (&GrabExceptionContext);
+    // RaiseException (0, 0, 1, exceptargs);
+    // SetUnhandledExceptionFilter (oldseh);
+
+    memset (&module, 0, sizeof (module));
+    memset (&frame, 0, sizeof (frame));
+
+    module.SizeOfStruct		= sizeof (module);
+
+    frame.AddrPC.Offset		= context.Eip;
+    frame.AddrPC.Mode		= AddrModeFlat;
+    frame.AddrStack.Offset	= context.Esp;
+    frame.AddrStack.Mode	= AddrModeFlat;
+    frame.AddrFrame.Offset	= context.Ebp;
+    frame.AddrFrame.Mode	= AddrModeFlat;
+
+    while (true)
+    {
+	if (! StackWalk (IMAGE_FILE_MACHINE_I386,
+			 GetCurrentProcess (),
+			 GetCurrentThread (),
+			 &frame,
+			 &context,
+			 NULL,
+			 SymFunctionTableAccess,
+			 SymGetModuleBase,
+			 NULL)
+	    || frame.AddrFrame.Offset == 0)
+	    break;
+
+	// FIXME: Throw away everything above stacktrace?  Keep looping
+	// below until the name includes something we understand?
+
+	// Print stack frame too?  If we know how many arguments there
+	// are (from demangling function name -- see below, could count
+	// commas), args are: *((ULONG *)frame.AddrFrame.Offset+2+ARG).
+	MYWRITE (fd, buf, sprintf (buf, "(%2u) 0x%08lx 0x%08lx   ",
+				   level, frame.AddrPC.Offset,
+				   frame.AddrFrame.Offset));
+
+	memset (&symbol, 0, sizeof (symbol));
+	symbol.sym.SizeOfStruct = sizeof (symbol);
+	symbol.sym.MaxNameLength = sizeof (symbol) - sizeof (symbol.sym);
+
+	offset = 0;
+	if (SymGetSymFromAddr (GetCurrentProcess (), frame.AddrPC.Offset,
+			       &offset, &symbol.sym))
+	{
+	    // FIXME: Demangle name with:
+	    //   UnDecorateSymbolName (name, undecname, sizeof (undecname),
+	    //				UNDNAME_COMPLETE
+	    //				| UNDNAME_NO_THISTYPE
+	    // 				| UNDNAME_NO_SPECIAL_SYMS
+	    // 				| UNDNAME_NO_MEMBER_TYPE
+	    // 				| UNDNAME_NO_MS_KEYWORDS
+	    // 				| UNDNAME_NO_ACCESS_SPECIFIERS);
+	    MYWRITE (fd, symbol.sym.Name, STDC::strlen (symbol.sym.Name));
+	    MYWRITE (fd, buf, sprintf (buf, " + %lx", offset));
+
+	    if (SymGetModuleInfo (GetCurrentProcess(), frame.AddrPC.Offset,
+				  &module))
+	    {
+		MYWRITELIT (fd, " [");
+		MYWRITE (fd, module.ImageName,
+			 STDC::strlen (module.ImageName));
+		MYWRITELIT (fd, "]");
+	    }
+	}
+	else
+	{
+	    GetLogicalAddress ((PVOID) frame.AddrPC.Offset,
+			       modulename, sizeof (modulename),
+			       section, offset);
+	    MYWRITE (fd, buf, sprintf (buf, "%04lx:%08lx [", section, offset));
+	    MYWRITE (fd, modulename, STDC::strlen (modulename));
+	    MYWRITELIT (fd, "]");
+	}
+	MYWRITELIT (fd, "\n");
+	++level;
+    }
+    SymCleanup (GetCurrentProcess ());
+
+#elif (HAVE_U_STACK_TRACE || HAVE_XL_TRBK)		// hp-ux, aix
+    // FIXME: deal with inability to duplicate the file handle
+    int stderrfd = dup (STDERR_FILENO);
+    if (stderrfd == -1)
+	return;
+
+    int newfd    = dup2 (fd, STDERR_FILENO);
+    if (newfd == -1)
+    {
+	close (stderrfd);
+	return;
+    }
+
+# if HAVE_U_STACK_TRACE		// hp-ux
+    U_STACK_TRACE ();
+# elif HAVE_XL_TRBK		// aix
+    xl__trbk ();
+# else
+#  error "oops, you shouldn't have gotten here!"
+# endif
+
+    fflush (stderr);
+    dup2 (stderrfd, STDERR_FILENO);
+    close (newfd);
+#elif HAVE_BACKTRACE_SYMBOLS_FD && HAVE_DLADDR		// linux
+    // we could have used backtrace_symbols_fd, except its output
+    // format is pretty bad, so recode that here :-(
+    void		*trace [MAX_BACKTRACE_DEPTH];
+    int			depth = backtrace (trace, MAX_BACKTRACE_DEPTH);
+
+    iovec		bufs [5];
+    int			nbufs = 0;
+    char		addrbuf [5 + BitTraits<unsigned long>::HexDigits];
+    char		diffbuf [7 + BitTraits<unsigned long>::HexDigits];
+    static const char	trailer [] = "]\n";
+
+    for (int n = 0; n < depth; ++n, nbufs = 0)
+    {
+	unsigned long	addr = (unsigned long) trace [n];
+	Dl_info		info;
+
+	if (dladdr (trace[n], &info) && info.dli_fname && info.dli_fname[0])
+	{
+	    const char		*libname = info.dli_fname;
+	    const char		*symname = (info.dli_sname && info.dli_sname[0]
+					    ? info.dli_sname : "?");
+	    unsigned long	symaddr = (unsigned long) info.dli_saddr;
+	    bool		gte = (addr >= symaddr);
+	    unsigned long	diff = (gte ? addr - symaddr : symaddr - addr);
+
+	    bufs [nbufs].iov_base = addrbuf;
+	    bufs [nbufs].iov_len  = sprintf (addrbuf, " 0x%08lx ", addr);
+	    ++nbufs;
+
+	    bufs [nbufs].iov_base = (void *) symname; // discard const
+	    bufs [nbufs].iov_len  = strlen (symname);
+	    ++nbufs;
+
+	    bufs [nbufs].iov_base = diffbuf;
+	    bufs [nbufs].iov_len  = sprintf (diffbuf, " %s 0x%lx [",
+					     gte ? "+" : "-", diff);
+	    ++nbufs;
+
+	    bufs [nbufs].iov_base = (void *) libname; // discard const
+	    bufs [nbufs].iov_len  = strlen (libname);
+	    ++nbufs;
+
+	    bufs [nbufs].iov_base = (void *) trailer; // discard const
+	    bufs [nbufs].iov_len  = 2;
+	    ++nbufs;
+
+	}
+	else
+	{
+	    bufs [nbufs].iov_base = addrbuf;
+	    bufs [nbufs].iov_len  = sprintf (addrbuf, " 0x%08lx ", addr);
+	    ++nbufs;
+
+	    bufs [nbufs].iov_base = (void *) "<unknown function>\n"; //no const
+	    bufs [nbufs].iov_len  = 19;
+	    ++nbufs;
+	}
+
+	writev (fd, bufs, nbufs);
+    }
+
+#elif HAVE_EXCPT_H && HAVE_PDSC_H && HAVE_RLD_INTERFACE_H // tru64
+    // Tru64 stack walk.  Uses the exception handling library and the
+    // run-time linker's core functions (loader(5)).  FIXME: Tru64
+    // should have _RLD_DLADDR like IRIX below.  Verify and update.
+
+    char	buffer [100 + BitTraits<unsigned long>::HexDigits * 2 + 11];
+    sigcontext	context;
+    int		rc = 0;
+
+    exc_capture_context (&context);
+    while (!rc && context.sc_pc)
+    {
+	// FIXME: Elf32?
+	pdsc_crd *func, *base, *crd
+	  = exc_remote_lookup_function_entry(0, 0, context.sc_pc, 0, &func, &base);
+	Elf32_Addr addr = PDSC_CRD_BEGIN_ADDRESS(base, func);
+	// const char *name = _rld_address_to_name(addr);
+	const char *name = "<unknown function>";
+	sprintf (buffer, " 0x%012lx %.100s + 0x%lx\n",
+		 context.sc_pc, name, context.sc_pc - addr);
+	write (fd, buffer, STDC::strlen(buffer));
+	rc = exc_virtual_unwind(0, &context);
+    }
+
+#elif HAVE_EXCEPTION_H && defined __sgi			// irix
+    // IRIX stack walk -- like Tru64 but with a little different names.
+    // NB: The guard above is to protect against unrelated <exception.h>
+    //   provided by some compilers (e.g. KCC 4.0f).
+    // NB: libexc.h has trace_back_stack and trace_back_stack_and_print
+    //   but their output isn't pretty and nowhere as complete as ours.
+    char       buffer [340];
+    sigcontext context;
+
+    exc_setjmp (&context);
+    while (context.sc_pc >= 4)
+    {
+	// Do two lookups, one using exception handling tables and
+	// another using _RLD_DLADDR, and use the one with a smaller
+	// offset.  For signal handlers we seem to get things wrong:
+	// _sigtramp's exception range is huge while based on Dl_info
+	// the offset is small -- but both supposedly describe the
+	// same thing.  Go figure.
+	char            *name = 0;
+	const char      *libname = 0;
+	const char      *symname = 0;
+	Elf32_Addr      offset = ~0L;
+
+	// Do the exception/dwarf lookup
+	Elf32_Addr      pc = context.sc_pc;
+	Dwarf_Fde       fde = find_fde_name (&pc, &name);
+	Dwarf_Addr      low_pc = context.sc_pc;
+	Dwarf_Unsigned  udummy;
+	Dwarf_Signed    sdummy;
+	Dwarf_Ptr       pdummy;
+	Dwarf_Off       odummy;
+	Dwarf_Error     err;
+
+	symname = name;
+
+	// Determine offset using exception descriptor range information.
+	if (dwarf_get_fde_range (fde, &low_pc, &udummy, &pdummy, &udummy,
+				 &odummy, &sdummy, &odummy, &err) == DW_DLV_OK)
+	    offset = context.sc_pc - low_pc;
+
+       // Now do a dladdr() lookup.  If the found symbol has the same
+       // address, trust the more accurate offset from dladdr();
+       // ignore the looked up mangled symbol name and prefer the
+       // demangled name produced by find_fde_name().  If we find a
+       // smaller offset, trust the dynamic symbol as well.  Always
+       // trust the library name even if we can't match it with an
+       // exact symbol.
+	Elf32_Addr      addr = context.sc_pc;
+	Dl_info         info;
+
+	if (_rld_new_interface (_RLD_DLADDR, addr, &info))
+	{
+	    if (info.dli_fname && info.dli_fname [0])
+		libname = info.dli_fname;
+
+	    Elf32_Addr symaddr = (Elf32_Addr) info.dli_saddr;
+	    if (symaddr == low_pc)
+		offset = addr - symaddr;
+	    else if (info.dli_sname
+		     && info.dli_sname [0]
+		     && addr - symaddr < offset)
+	    {
+		offset = addr - symaddr;
+		symname = info.dli_sname;
+	    }
+	}
+
+	// Print out the result
+	if (libname && symname)
+            write (fd, buffer, sprintf
+		   (buffer, " 0x%012lx %.100s + 0x%lx [%.200s]\n",
+		    addr, symname, offset, libname));
+	else if (symname)
+	    write (fd, buffer, sprintf
+		   (buffer, " 0x%012lx %.100s + 0x%lx\n",
+		    addr, symname, offset));
+	else
+	    write (fd, buffer, sprintf
+		   (buffer, " 0x%012lx <unknown function>\n", addr));
+
+	// Free name from find_fde_name().
+	free (name);
+
+	// Check for termination.  exc_unwind() sets context.sc_pc to
+	// 0 or an error (< 4).  However it seems we can't unwind
+	// through signal stack frames though this is not mentioned in
+	// the docs; it seems that for those we need to check for
+	// changed pc after find_fde_name().  That seems to indicate
+	// end of the post-signal stack frame.  (FIXME: Figure out how
+	// to unwind through signal stack frame, e.g. perhaps using
+	// sigcontext_t's old pc?  Or perhaps we can keep on going
+	// down without doing the symbol lookup?)
+	if (pc != context.sc_pc)
+	    break;
+
+	exc_unwind (&context, fde);
+    }
+
+#elif defined PROG_PSTACK				// solaris
+# ifdef PROG_CXXFILT
+#  define CXXFILTER " | " PROG_CXXFILT
+# else
+#  define CXXFILTER
+# endif
+    // 64 should more than plenty for a space and a pid.
+    char buffer [sizeof(PROG_PSTACK) + 1 + BitTraits<unsigned long>::Digits
+		 + 3 + sizeof(PROG_CXXFILT) + BitTraits<int>::Digits + 1];
+    sprintf (buffer, "%s %lu%s 1>&%d", PROG_PSTACK, (unsigned long) getpid (),
+	     "" CXXFILTER, fd);
+    system (buffer);
+# undef CXXFILTER
+
+#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+    // FIXME: Check for _Unwind*, compilers other than GCC support this API
+    _Unwind_Backtrace (unwindWalkStack, &fd);
+#endif
+
+    // FIXME: mpatrol has some generic unix unwind code.
+    // FIXME: from unix faq: ask debugger to dump stack trace
+    // with something like:
+    //   - gdb: echo "thread apply all where\nwhere\ndetach" | gdb $prog $pid
+    //   - dbx: echo "where\ndetach" | dbx -a $program_path $pid
+    //   - dbx (aix): echo "where\ndetach" | dbx -p $program_path $pid
+}
+
+/** Drop a core dump and continue.
+
+    Creates a core file for the current program state and continues
+    execution.  @a sig should be the number of the signal from which
+    the program should appear to have died; this should a fatal signal
+    that does cause a core file to be created (or @c SIGUSR1).
+
+    This works by forking the process and then killing the child with
+    the given signal; the signal is automatically unblocked in the
+    child to make sure the sure the signal is delivered.  Thus the
+    function returns only once, in the parent process.
+
+    This function can be safely installed directly as a signal
+    handler.  #Signal::handleFatal() will do so for @c SIGUSR1 with
+    suitable options.
+
+    Note that this function does not change core dump resource limits,
+    not even for the forked child process.  If core files are disabled
+    through resource limits, no core file will be created despite your
+    explicit request to create one.
+
+    This concept was taken from DDD, the Data Display Debugger. */
+void
+DebugAids::coredump (int sig, ...)
+{
+#ifndef _WIN32
+    // FIXME: Forking vs. threads -- need to sort out what is safe.
+    // FIXME: Provide a resource limits interface so that core
+    // resource limits can be raised?
+
+    pid_t	corepid;
+    int		status;
+
+    ::unlink ("core");
+    if ((corepid = ::fork ()) == 0)
+    {
+	// In child: re-raise the signal, thus killing the process and
+	// producing a core dump.  Make sure 1) the signal is not
+	// blocked so that we won't return to the caller, 2) we have a
+	// signal that is fatal, 3) the signal falls to its default
+	// handler to produce the dump.
+
+#ifdef SIGUSR1
+	// SIGUSR1 does not cause a core dump; use abort() instead
+	if (sig == SIGUSR1)
+	    sig = SIGABRT;	// Could be SIGIOT if SIGABRT is not defined
+#endif
+	Signal::handle (sig, (Signal::HandlerType) SIG_DFL);
+	Signal::block (sig, false);
+	Signal::raise (sig);
+
+	// Yikes, this shouldn't happen.  ASSERT isn't right here.  If
+	// raise() failed to deliver the signal, abort() is unlikely
+	// to work any better, but try it anyway.  Then make sure we
+	// die so that we won't return to the caller from the child.
+	abort ();
+	_exit (255);
+    }
+    else if (corepid > 0)
+	::waitpid (corepid, &status, 0);
+#endif // !_WIN32
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+//} // namespace seal                             wlav
+} // namespace Athena                             wlav

src/SealSharedLib.cxx

+/**
+ * @file CxxUtils/src/SealSharedLib.cxx
+ * @author Lassi Tuura (original author)
+ * @author Wim Lavrijsen <WLavrijsen@lbl.gov> (responsible in ATLAS)
+ * @date Oct, 2008
+ *
+ *        Search for `wlav' to find changes from the SEAL version. All
+ *        includes were modified, all ASSERT macro's were dropped in
+ *        favor of assert.
+ */
+
+//<<<<<< INCLUDES                                                       >>>>>>
+
+#include "CxxUtils/SealCommon.h"               // wlav
+#include "CxxUtils/SealSharedLib.h"            // wlav
+#include "CxxUtils/SealDebug.h"                // wlav
+// wlav copied from SealBase/sysapi/SharedLibrary.h
+# ifdef _WIN32
+#  include <windows.h>
+#  include <winnt.h>
+#  include <imagehlp.h>
+# else
+#  if HAVE_DLOPEN 
+#   include <dlfcn.h>
+#  elif HAVE_SHL_LOAD
+#   include <dl.h>
+#  elif HAVE_LOAD
+#   include "utils/dlfcn.h"
+#  endif
+#  if HAVE_LOADER_H
+#   include <loader.h>
+#  endif
+#  if HAVE_LINK_H
+#   include <link.h>
+#   include <limits.h>
+#   include <sys/stat.h>
+#   include <unistd.h>
+#  endif
+#  if HAVE_ELF_H
+#   include <elf.h>
+#  endif
+#  if HAVE_SGIDEFS_H	// irix n32, 64
+#   include <sgidefs.h>
+#   include <objlist.h>
+#   include <obj_list.h>
+#   include <obj.h>
+#  endif
+#  if HAVE_MACH_O_DYLD_H // darwin
+#   include <mach-o/dyld.h>
+#   include <mach-o/getsect.h>
+#  endif
+# endif // _WIN32
+# include <cstdio>
+# include <cstdlib>
+# include <errno.h>
+
+#include <assert.h>                            // wlav
+
+//namespace seal {                                wlav
+namespace Athena {                             // wlav
+//<<<<<< PRIVATE DEFINES                                                >>>>>>
+
+#ifndef SHLIB_UNSUPPORTED
+# define  SHLIB_UNSUPPORTED \
+	throw SharedLibraryError ("", "unsupported operation")
+#endif
+
+//<<<<<< PRIVATE CONSTANTS                                              >>>>>>
+//<<<<<< PRIVATE TYPES                                                  >>>>>>
+//<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
+//<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
+//<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
+//<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
+
+// wlav modified from SealBase/src/SharedLibraryError.cpp
+SharedLibraryError::SharedLibraryError (const char *context,
+					const std::string &cause)
+    : m_context (context ? context : ""),
+      m_cause (cause)
+{}
+
+const char*
+SharedLibraryError::what() const throw()
+{
+    static std::string message = "Shared library operation";
+    if (! m_context.empty ())
+    {
+	message += " ";
+	message += m_context;
+    }
+
+    message += " failed";
+
+    if (! m_cause.empty ())
+    {
+	message += " because: ";
+	message += m_cause;
+    }
+
+    return message.c_str();
+}
+
+
+// wlav continued from SealBase/src/SharedLibrary.cpp
+#ifdef _WIN32
+static BOOL CALLBACK
+enumModules (LPSTR name, ULONG base_address, PVOID context)
+{
+    IMAGEHLP_MODULE			 moduleinfo;
+    const SharedLibrary::InfoHandler	*handler
+	= static_cast<SharedLibrary::InfoHandler *> (context);
+
+    memset (&moduleinfo, 0, sizeof (moduleinfo));
+    moduleinfo.SizeOfStruct = sizeof (moduleinfo);
+
+    SharedLibrary::LibraryInfo info;
+
+    if (SymGetModuleInfo (GetCurrentProcess (), base_address, &moduleinfo))
+    {
+	info.m_filename   = moduleinfo.LoadedImageName;
+	info.m_text_start = moduleinfo.BaseOfImage;
+	info.m_text_end   = moduleinfo.BaseOfImage + moduleinfo.ImageSize;
+	info.m_data_start = 0;
+	info.m_data_end   = 0;
+	info.m_bss_start  = 0;
+	info.m_bss_end    = 0;
+    }
+    else
+    {
+	info.m_filename   = name;
+	info.m_text_start = base_address;
+	info.m_text_end   = 0;
+	info.m_data_start = 0;
+	info.m_data_end   = 0;
+	info.m_bss_start  = 0;
+	info.m_bss_end    = 0;
+    }
+    (*handler) (info);
+    return TRUE;
+}
+#endif
+
+//<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
+//<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+
+std::string
+SharedLibrary::path (void)
+{
+    const char *pathvar = PATH;
+    const char *path = pathvar ? getenv (pathvar) : 0;
+    return path ? path : "";
+}
+
+void
+SharedLibrary::path (const std::string &path)
+{
+    /* Do not free `var'; most implementations of `putenv' use the
+       string without copying it.  On systems where `putenv' copies,
+       you'll see leaks from this routine.  It would be possible to
+       check for this, but only by killing cross-compilation.
+
+       NB: `HAVE_COPYING_PUTENV' will never be set as we are not
+       checking for it :-)  */
+
+    const char *pathvar = PATH;
+    if (pathvar) {
+	char *var = (char *) malloc (strlen(pathvar) + 1 + path.length () + 1);
+	sprintf (var, "%s=%s", pathvar, path.c_str ());
+	putenv (var);
+#if HAVE_COPYING_PUTENV
+	free (var);
+#endif
+    }
+}
+
+/** Return a shared library name that follows the system conventions
+    for naming shared library.  @a name is the basic name of the
+    shared library, without the name prefix ("lib" on unix) or the
+    extension (".so", ".sl", ".dylib" or ".dll").  @a name must not
+    have any directory components. */
+std::string
+SharedLibrary::libname (const std::string &name)
+{
+#ifdef _WIN32
+    return name + ".dll";
+#elif defined __hpux
+    return "lib" + name + ".sl";
+#else
+    return "lib" + name + ".so";
+#endif
+}
+
+/** Transform 'extern "C"' symbol @a name into a name suitable for
+    lookup in a shared library, e.g. with #data() or #function().
+    Normally the latter two automatically perform the necessary
+    mangling by calling this function, but the clients can also
+    do the mangling themselves.  The @a name should be in the
+    form it is spelled in C source code.  */
+std::string
+SharedLibrary::symname (const std::string &name)
+{ return name; }
+
+//////////////////////////////////////////////////////////////////////
+/** Return a shared library object representing the application itself.
+    The returned object is allocated with @c new.  The caller must
+    release the object with either #release() or #abandon().  The
+    method throws a #SharedLibraryError if the operation is not
+    supported or some failure occurs.  */
+SharedLibrary *
+SharedLibrary::self (void)
+{
+#if HAVE_DLOPEN || HAVE_LOAD
+    // NB: Linux (at least RH 7.x) dynamic loader is severly broken
+    // when it comes to reporting error messages.  The error messages
+    // are frequently garbled or null.  If you see a crash in a call
+    // to dlerror(), sorry, there's nothing we can do about that.
+    // Our attempts have only produced even more undesirable crashes.
+    // Waiting for a better version of the linux dynamic laoder.
+    void *handle = ::dlopen (0, RTLD_LAZY);
+    if (! handle)
+    {
+	const char *msg = ::dlerror ();
+	msg = msg ? msg : "dynamic linker error message lost!";
+	throw SharedLibraryError ("dlopen()", msg);
+    }
+
+    return new SharedLibrary (handle);
+#elif HAVE_SHL_LOAD
+    return new SharedLibrary (PROG_HANDLE);
+#elif defined _WIN32
+    return new SharedLibrary (::GetModuleHandle (0));
+#else
+    SHLIB_UNSUPPORTED;
+#endif
+}
+
+/** Load a shared library and return an object representing it.  The
+    returned object is allocated with @c new.  The caller must release
+    the object with either #release() or #abandon().  The method throws
+    a #SharedLibraryError if the operation is not supported or some
+    failure occurs.  Please note that on several systems failure to
+    properly load a library, e.g. due to missing symbols, is effectively
+    fatal.  */
+SharedLibrary *
+SharedLibrary::load (const std::string &name)
+{
+    assert(! name.empty ());
+
+    void *handle = 0;
+
+#if HAVE_DLOPEN || HAVE_LOAD
+# ifndef RTLD_GLOBAL
+#  define RTLD_GLOBAL 0
+# endif
+    // See comments in "self()" about crashes in dlerror().
+    if (! (handle = ::dlopen (name.c_str (), RTLD_LAZY | RTLD_GLOBAL)))
+    {
+	const char *msg = ::dlerror ();
+	msg = msg ? msg : "dynamic linker error message lost!";
+	throw SharedLibraryError ("dlopen()", msg);
+    }
+
+#elif HAVE_SHL_LOAD
+    if (! (handle = ::shl_load (name.c_str (), BIND_DEFERRED, 0L)))
+	throw SharedLibraryError ("shl_load()", errno);
+
+#elif defined _WIN32
+    if (! (handle = ::LoadLibrary (name.c_str ())))
+	throw SharedLibraryError ("LoadLibrary()", GetLastError ());
+#else
+    SHLIB_UNSUPPORTED;
+#endif
+
+    return new SharedLibrary (handle);
+}
+
+/** Iterate and provide information about all currently loaded
+    shared libraries.  */
+void
+SharedLibrary::loaded (const InfoHandler &handler)
+{
+    // Dynamic linker characteristics:
+    //   AIX, Windows, SVR4 (DG/UX, DRS/NX, DYNIX/ptx, Linux, SINIX,
+    //   Solaris, UnixWare, {Free,Open,Net}BSD if __ELF__), BSD,
+    //   HP-UX, IRIX, Tru64
+
+    // Object file formats:
+    //   XCOFF (AIX), ELF32/64 (DG/UX, DRS/NX, DYNIX/ptx, IRIX, SINIX,
+    //   Solaris, UnixWare, {Free,Open,Net}BSD: if __ELF__), a.out
+    //   ({Free,Open,Net}BSD if ! __ELF__, SunOS), BFD (Cygwin, HP-UX,
+    //   Linux, LynxOS, Tru64, Windows if GCC), PE (Windows), COFF (?)
+
+#if HAVE_SHL_LOAD					// hp-ux
+    shl_descriptor desc;
+
+    for (int index = -1; shl_get_r (index, &desc) == 0; ++index)
+    {
+	LibraryInfo info;
+	info.m_filename   = desc.filename;
+	info.m_text_start = desc.tstart;
+	info.m_text_end   = desc.tend;
+	info.m_data_start = desc.dstart;
+	info.m_data_end   = desc.dend;
+	info.m_bss_start  = 0;
+	info.m_bss_end    = 0;
+
+	handler (info);
+    }
+
+#elif HAVE_LINK_H					// bsd/svr4/elf
+# if !HAVE_LINK_MAP_L_MAP_START
+#  define l_map_start l_addr
+#  define l_map_end   l_addr
+# endif
+# if !HAVE_PROGRAM_INVOCATION_NAME
+    static const char *program_invocation_name = "(unknown program name)";
+# endif
+# if HAVE_R_DEBUG					// linux/glibc
+    link_map *p = _r_debug.r_map;
+# else
+    // Dynamic linker root:
+    //   BSD (SunOS):
+    //     #include <sys/types.h>
+    //     #include <link.h>
+    //     extern struct link_dynamic _DYNAMIC;
+    //     link_dynamic *d = &_DYNAMIC;
+    //     if ((d->ld_version > 1) && (d->ld_version <= 3) && (d->ld_un.ld_1 != 0))
+    //       --> link_map *l = d->ld_un.ld_1->ld_loaded
+    //          l->lm_name, l->lm_addr, l->lm_next
+    //
+    //   BSD ({Free,Open,Net}BSD):
+    //     #include <sys/types.h>
+    //     #include <link.h>
+    //     extern struct _dynamic _DYNAMIC
+    //     _dynamic *d = &_DYNAMIC;
+    //     if ((d->version == LD_VERSION_BSD) && d->d_un.d_sdt != 0))
+    //       --> so_map *l = d->d_un.d_sdt->sdt_loaded
+    //           l->som_path, l->som_addr, l->som_next
+    //
+    //   SVR4 (DG/UX, DRS/NX, DYNIX/ptx, SINIX, UnixWare)
+    //     ElfW(Dyn) _DYNAMIC[]  // Linux
+    //     void _DYNAMIC (void)  // weak, really is data, but not
+    //                           // all compilers allow weak data
+    //
+    //   Solaris:
+    //     dlinfo (self, RTLD_DI_LINKMAP, &p);
+
+    extern ElfW(Dyn) _DYNAMIC []; // #pragma weak?
+    link_map *p = 0;
+    for (ElfW(Dyn) *dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
+	if (dyn->d_tag == DT_DEBUG && dyn->d_un.d_ptr)
+	    // linux: p = ((r_debug *) dyn->d_un_d.ptr)->r_map;
+	    p = (link_map *) *((unsigned long *) dyn->d_un.d_ptr + 1);
+# endif
+
+    if (! p)
+       throw SharedLibraryError ("loaded", "no shared library load map");
+
+    // Get executable name; linux has a symlink in /proc/self/exe.
+    // Linux path names are arbitrarily long, so we just have create
+    // some random-sized buffer.  We allocate this on stack to avoid
+    // dynamic memory allocation.  If this is a problem, report a bug.
+    struct stat	sbuf;
+    char	exe [4096];
+
+    memset (exe, 0, sizeof (exe));
+    if (::stat ("/proc/self/exe", &sbuf) == 0)
+	::readlink ("/proc/self/exe", exe, sizeof (exe)-1);
+    else
+       STDC::strncpy (exe, program_invocation_name, sizeof (exe)-1);
+
+    // Get shared libraries
+    for ( ; p; p = p->l_next)
+    {
+	LibraryInfo info;
+
+	/* FIXME: Does this work with prelinked shared libraries?
+	   From a mail to GCC mailing list ("fde-glibc.c bug"):
+
+	     There is a bug in gcc/config/ia64/fde-glibc.c:
+	     ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr,
+	     							   ^^^^^^^^^^^
+				     segment_base, gp);
+
+	     this will work only as long as the shared library in
+	     question has first PT_LOAD segment's p_vaddr == 0.
+	     E.g. with ELF prelinking this is almost never true
+	     though, so what you really want is map->l_map_start
+	     (map->l_addr will be almost always 0) or even better
+	     map->l_phdr/map->l_phnum pair.  */
+
+	// FIXME: use the map address (= ElfW(Ehdr)) to scan over
+	// the different ElfW(Phdr)s to find the various sections.
+	info.m_filename   = (p->l_name && p->l_name[0] ? p->l_name : exe);
+	info.m_text_start = p->l_addr ? p->l_addr : p->l_map_start;
+	info.m_text_end   = p->l_addr ? p->l_addr : p->l_map_end;
+	info.m_data_start = 0;
+	info.m_data_end   = 0;
+	info.m_bss_start  = 0;
+	info.m_bss_end    = 0;
+
+	handler (info);
+    }
+
+#elif HAVE_SGIDEFS_H					// irix
+    /* From rld(1) man page:
+
+       rld keeps a doubly linked list of structures and crt1.o
+       contains a pointer to the head of the list of obj structures
+       called __rld_obj_head. In an o32 executable, this points to a
+       linked list of objList structures (/usr/include/obj_list.h),
+       each of which has a `data' element which is a pointer to a
+       `struct obj' (/usr/include/obj.h) (even though the field is not
+       declared as a pointer). In an n32 executable, __rld_obj_head
+       points to a linked list of Elf32_Obj_Info structures
+       (/usr/include/objlist.h).  In a 64-bit executable,
+       __rld_obj_head points to a linked list of Elf64_Obj_Info
+       structures (/usr/include/objlist.h).  The `oi_magic' element of
+       each Elf32_Obj_Info or Elf64_Obj_Info is all-bits-on
+       (0xffffffff) to make it easier to determine which list type is
+       in use a 32-bit executable.  */
+
+    // To get more details by reading the ELF files:
+    // http://reality.sgi.com/davea/software.html
+    extern ElfW(Obj_Info)	*__rld_obj_head;
+    ElfW(Obj_Info)		*p = __rld_obj_head;
+
+    for ( ; p; p = (ElfW(Obj_Info) *) p->oi_next)
+    {
+	LibraryInfo info;
+
+# if defined _MIPS_SIM_ABI32 && _MIPS_SIM == _MIPS_SIM_ABI32
+	info.m_filename   = (const char *) p->o_path;
+	info.m_text_start = p->o_praw;  // base address: o_base_address
+	info.m_text_end   = p->o_praw;
+# elif (defined _MIPS_SIM_NABI32 && _MIPS_SIM == _MIPS_SIM_NABI32) \
+    || (defined _MIPS_SIM_ABI64  && _MIPS_SIM == _MIPS_SIM_ABI64)
+	info.m_filename   = (const char *) p->oi_pathname;
+	info.m_text_start = p->oi_ehdr; // base address: oi_orig_ehdr
+	info.m_text_end   = p->oi_ehdr;
+# else
+#  error "Unsupported ABI: not o32, n32 or 64"
+# endif
+	info.m_data_start = 0;
+	info.m_data_end   = 0;
+	info.m_bss_start  = 0;
+	info.m_bss_end    = 0;
+
+	handler (info);
+    }
+
+#elif HAVE_LOADER_H && HAVE_LDR_NEXT_MODULE_DECL	// tru64
+    ldr_process_t	proc = ldr_my_process ();
+    ldr_module_t	mod  = LDR_NULL_MODULE;
+    int			ret  = ldr_next_module (proc, &mod);
+
+    for (; ret == 0 && mod != LDR_NULL_MODULE; ret = ldr_next_module (proc, &mod))
+    {
+	ldr_module_info_t	info;
+	size_t			size = 0;
+	LibraryInfo		libinfo;
+
+	if (ldr_inq_module(proc, mod, &info, sizeof(info), &size) < 0)
+	    throw SharedLibraryError ("ldr_inq_module()", errno);
+
+	libinfo.m_filename   = info.lmi_name;
+	libinfo.m_text_start = 0;
+	libinfo.m_text_end   = 0;
+	libinfo.m_data_start = 0;
+	libinfo.m_data_end   = 0;
+	libinfo.m_bss_start  = 0;
+	libinfo.m_bss_end    = 0;
+
+	for (int i = 0; i < info.lmi_nregion; ++i)
+	{
+	    ldr_region_info_t	rinfo;
+	    unsigned long	low;
+	    unsigned long	high;
+
+	    if (ldr_inq_region(proc, mod, i, &rinfo, sizeof(rinfo), &size) < 0)
+	        throw SharedLibraryError ("ldr_inq_region()", errno);
+
+	    low  = (unsigned long) rinfo.lri_mapaddr;
+	    high = ((unsigned long) rinfo.lri_mapaddr) + rinfo.lri_size;
+
+	    if (!strcmp(rinfo.lri_name, ".text")) {
+		libinfo.m_text_start = low;
+		libinfo.m_text_end   = high;
+	    } else if (!strcmp(rinfo.lri_name, ".data")) {
+		libinfo.m_data_start = low;
+		libinfo.m_data_end   = high;
+	    } else if (!strcmp(rinfo.lri_name, ".bss")) {
+		libinfo.m_bss_start  = low;
+		libinfo.m_bss_end    = high;
+	    }
+	}
+
+	handler (libinfo);
+    }
+
+    if (ret < 0)
+	throw SharedLibraryError ("ldr_next_module()", errno);
+
+#elif HAVE_LOAD && HAVE_LOAD_DECL			// aix
+    int		size = 16;
+    void	*buffer = new ld_info [size];
+    int		error = ::loadquery (L_GETINFO, buffer, size);
+    int		offset = 0;
+
+    while (error == -1 && errno == ENOMEM)
+    {
+	delete [] (ld_info *) buffer;
+	buffer = new ld_info [size *= 2];
+	error = ::loadquery (L_GETINFO, buffer, size);
+    }
+
+    if (error == -1)
+	throw SharedLibraryError ("loadquery()", errno);
+
+    while (true)
+    {
+	LibraryInfo	info;
+	ld_info		*ld = (ld_info *) ((char *) buffer + offset);
+	const char	*path = ld->ldinfo_filename;
+	const char	*member = path + strlen (path) + 1;
+	std::string	filename;	// FIXME: Use alloca instead?
+
+	filename = path;
+	if (*member)
+	{
+	    filename += '(';
+	    filename += member;
+	    filename += ')';
+	}
+
+	info.m_filename   = filename.c_str ();
+	info.m_text_start = (unsigned long) ld->ldinfo_textorg;
+	info.m_text_end   = info.m_text_start + ld->ldinfo_textsize;
+	info.m_data_start = (unsigned long) ld->ldinfo_dataorg;
+	info.m_data_end   = info.m_data_start + ld->ldinfo_datasize;
+	info.m_bss_start  = 0;
+	info.m_bss_end    = 0;
+
+	handler (info);
+
+	if (ld->ldinfo_next)
+	    offset += ld->ldinfo_next;
+	else
+	    break;
+    }
+
+    delete [] (ld_info *) buffer;
+
+#elif HAVE_MACH_O_DYLD_H				// darwin
+    unsigned long images = _dyld_image_count ();
+    for (unsigned long i = 0; i < images; ++i)
+    {
+	const mach_header *hdr = _dyld_get_image_header (i);
+	unsigned long	 slide = _dyld_get_image_vmaddr_slide (i);
+	unsigned int	size;
+	char		*sect;
+	LibraryInfo	info;
+
+	info.m_filename   = _dyld_get_image_name (i);
+
+	sect = getsectdatafromheader (hdr, SEG_TEXT, SECT_TEXT, &size);
+	info.m_text_start = sect ? (unsigned long) sect + slide : 0;
+	info.m_text_end   = sect ? (unsigned long) sect + slide + size : 0;
+	sect = getsectdatafromheader (hdr, SEG_DATA, SECT_DATA, &size);
+	info.m_data_start = sect ? (unsigned long) sect + slide : 0;
+	info.m_data_end   = sect ? (unsigned long) sect + slide + size : 0;
+	sect = getsectdatafromheader (hdr, SEG_DATA, SECT_BSS, &size);
+	info.m_bss_start  = sect ? (unsigned long) sect + slide : 0;
+	info.m_bss_end    = sect ? (unsigned long) sect + slide + size : 0;
+
+	handler (info);
+    }
+
+#elif defined _WIN32					// windows
+    if (! SymInitialize (GetCurrentProcess (), NULL, TRUE)
+	|| ! SymEnumerateModules (GetCurrentProcess (), &enumModules, (void *) &handler)
+	|| ! SymCleanup (GetCurrentProcess ()))
+	throw SharedLibraryError ("SymEnumerateModules()", GetLastError());
+#else
+    SHLIB_UNSUPPORTED;
+#endif
+}
+
+/** Protected constructor for initialising a library object.  The real
+    initialisation happens in #load() or #self().   */
+SharedLibrary::SharedLibrary (void *handle)
+    : m_handle (handle)
+{ assert (m_handle); }
+
+/** Protected destructor for cleaning up a library object.  The real
+    destruction happens in #release() or #abadon().   */
+SharedLibrary::~SharedLibrary (void)
+{ assert (! m_handle); }
+
+/** Release a shared library.  This unloads any library the object
+    currently refers to, then deletes @c this.  Note that releasing
+    the library does not guarantee that it will actually be unloaded.
+    If there are outstanding references to the library, explicit or
+    implicit, the library will remain in memory.  */
+void
+SharedLibrary::release (void)
+{
+    assert (m_handle);
+
+#if HAVE_DLOPEN || HAVE_LOAD
+    ::dlclose (m_handle);
+#elif HAVE_SHL_LOAD
+    ::shl_unload ((shl_t) m_handle);
+#elif defined _WIN32
+    ::FreeLibrary ((HINSTANCE) m_handle);
+#else
+    // cannot get here---`load' and `self' should take care of it.
+    assert (false);
+#endif
+
+    m_handle = 0;
+    delete this;
+}
+
+/** Abandon a library.  This simply destroys the shared library
+    object (@c this) without releasing the underlying dynamic
+    object.  */
+void
+SharedLibrary::abandon (void)
+{
+    assert (m_handle);
+    m_handle = 0;
+    delete this;
+}
+
+/** Locate and return a reference to a data symbol called @a name.
+    If no such symbol exists, returns a null pointer.  If @a mangle
+    is the default @c true, the symbol is mangled to the platform
+    convention, typically prepending an underscore if required.  The
+    mangling does not refer to C++ name mangling, but to the mangling
+    required to convert C identifiers to run-time symbol names; see
+    #symname() for details.  */
+SharedLibrary::Data
+SharedLibrary::data (const std::string &name, bool mangle /* = true */) const
+{
+    assert (! name.empty ());
+    assert (m_handle);
+    std::string	mangled = mangle ? symname (name) : name;
+    Data	symbol = 0;
+
+#if HAVE_DLOPEN || HAVE_LOAD
+    // See comments in "self()" about crashes in dlerror().
+    const char *error = 0;
+    symbol = ::dlsym (m_handle, mangled.c_str ());
+    if (! symbol && (error = ::dlerror ()) != 0)
+	throw SharedLibraryError ("dlsym()", error);
+
+#elif HAVE_SHL_LOAD
+    shl_t handle = (shl_t) m_handle;
+    if (::shl_findsym (&handle, mangled.c_str (), TYPE_DATA, &symbol) != 0)
+	throw SharedLibraryError ("shl_findsym()", errno);
+    assert (handle == (shl_t) m_handle);
+
+#elif defined _WIN32
+    if (! (symbol = (Data)::GetProcAddress((HINSTANCE)m_handle, mangled.c_str())))
+	throw SharedLibraryError ("GetProcAddress()", GetLastError ());
+#else
+    // cannot get here---`load' and `self' should take care of it.
+    assert (false);
+#endif
+    return symbol;
+}
+
+/** Locate and return a reference to a function symbol called @a name.
+    If no such symbol exists, returns a null pointer.  If @a mangle
+    is the default @c true, the symbol is mangled to the platform
+    convention, typically prepending an underscore if required.  The
+    mangling does not refer to C++ name mangling, but to the mangling
+    required to convert C identifiers to run-time symbol names; see
+    #symname() for details.  */
+SharedLibrary::Function
+SharedLibrary::function (const std::string &name, bool mangle /* = true */) const
+{
+    assert (! name.empty ());
+    assert (m_handle);
+    std::string	mangled = mangle ? symname (name) : name;
+    Function	symbol = 0;
+
+#if HAVE_DLOPEN || HAVE_LOAD
+    // See comments in "self()" about crashes in dlerror().
+    const char *error = 0;
+    union { Function func; Data data; } sym;
+    sym.data = ::dlsym (m_handle, mangled.c_str ());
+    if (! sym.data && (error