diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 14:52:31 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 14:52:31 +0300 |
commit | 3ba50a15ebd976f7a88393e2e45dc14b6478b9a9 (patch) | |
tree | 6a6bbe6bed1141051fefe94b2d39eacd4854235a /libsigsegv/src | |
parent | 6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f (diff) | |
download | egawk-3ba50a15ebd976f7a88393e2e45dc14b6478b9a9.tar.gz egawk-3ba50a15ebd976f7a88393e2e45dc14b6478b9a9.tar.bz2 egawk-3ba50a15ebd976f7a88393e2e45dc14b6478b9a9.zip |
Move to gawk-3.1.7.
Diffstat (limited to 'libsigsegv/src')
83 files changed, 5746 insertions, 0 deletions
diff --git a/libsigsegv/src/Makefile.am b/libsigsegv/src/Makefile.am new file mode 100644 index 00000000..7e57dad2 --- /dev/null +++ b/libsigsegv/src/Makefile.am @@ -0,0 +1,104 @@ +## Makefile for libsigsegv/src. +## Copyright (C) 2002-2006, 2008-2009 Bruno Haible <bruno@clisp.org> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +## USA. + +## Process this file with automake to produce Makefile.in. + +AUTOMAKE_OPTIONS = 1.5 gnits no-dependencies + +RM = rm -f + +lib_LTLIBRARIES = libsigsegv.la + +noinst_HEADERS = \ + fault.h fault-aix3.h fault-aix3-powerpc.h fault-aix5.h fault-aix5-powerpc.h \ + fault-beos.h fault-beos-i386.h \ + fault-bsd.h fault-freebsd-i386.h \ + fault-hpux.h fault-hpux-hppa.h fault-hurd.h fault-irix.h fault-irix-mips.h \ + fault-linux.h fault-linux-alpha.h fault-linux-arm.h fault-linux-cris.h \ + fault-linux-hppa.h fault-linux-i386.h fault-linux-i386-old.h \ + fault-linux-ia64.h fault-linux-m68k.h fault-linux-m68k.c fault-linux-mips.h \ + fault-linux-powerpc.h fault-linux-s390.h fault-linux-sh.h \ + fault-linux-sparc.h fault-linux-x86_64.h \ + fault-macos-i386.h \ + fault-macosdarwin5-powerpc.h fault-macosdarwin5-powerpc.c \ + fault-macosdarwin7-powerpc.h fault-macosdarwin7-powerpc.c \ + fault-netbsd.h fault-netbsd-alpha.h fault-netbsd-alpha.c \ + fault-none.h \ + fault-openbsd.h fault-openbsd-i386.h \ + fault-osf.h fault-osf-alpha.h \ + fault-posix.h fault-posix-ucontext.h \ + fault-solaris.h fault-solaris-i386.h fault-solaris-sparc.h \ + machfault.h machfault-macos.h \ + signals.h signals-bsd.h signals-hpux.h signals-hurd.h signals-macos.h \ + leave.h \ + stackvma.h + +EXTRA_DIST = \ + handler-none.c handler-unix.c handler-macos.c handler-win32.c \ + stackvma-none.c stackvma-simple.c stackvma-linux.c stackvma-freebsd.c \ + stackvma-procfs.c stackvma-beos.c stackvma-mach.c stackvma-mincore.c \ + stackvma-rofile.c \ + leave-none.c leave-nop.c leave-sigaltstack.c leave-setcontext.c \ + sigsegv.h.msvc + +INCLUDES = -I. -I$(srcdir) +DEFS = @DEFS@ + +libsigsegv_la_SOURCES = handler.c stackvma.c leave.c dispatcher.c version.c + +libsigsegv_la_LDFLAGS = \ + -rpath $(libdir) \ + -version-info $(LIBSIGSEGV_VERSION_INFO) \ + -lc -no-undefined + +# Before making a release, change this according to the libtool documentation, +# section "Library interface versions". +LIBSIGSEGV_VERSION_INFO = 1:0:0 + +# Dependencies. +handler.$(OBJEXT) : ../config.h sigsegv.h @CFG_HANDLER@ $(noinst_HEADERS) +stackvma.$(OBJEXT) : ../config.h @CFG_STACKVMA@ stackvma.h +leave.$(OBJEXT) : ../config.h @CFG_LEAVE@ +dispatcher.$(OBJEXT) : sigsegv.h + + +# Special rules for installing sigsegv.h. + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(includedir) + $(INSTALL_DATA) sigsegv.h $(DESTDIR)$(includedir)/sigsegv.h + +installdirs-local: + $(mkinstalldirs) $(DESTDIR)$(includedir) + +uninstall-local: + $(RM) $(DESTDIR)$(includedir)/sigsegv.h + + +DISTCLEANFILES = sigsegv.h + + +# Rules for "make dist". + +sigsegv.h.msvc : sigsegv.h.in + sed -e 's/@''FAULT_CONTEXT_INCLUDE''@/#include <windows.h>/' \ + -e 's/@''FAULT_CONTEXT''@/CONTEXT/' \ + -e 's/@''HAVE_SIGSEGV_RECOVERY''@/1/' \ + -e 's/@''HAVE_STACK_OVERFLOW_RECOVERY''@/1/' \ + < $(srcdir)/sigsegv.h.in > $@ + diff --git a/libsigsegv/src/Makefile.in b/libsigsegv/src/Makefile.in new file mode 100644 index 00000000..8f18748d --- /dev/null +++ b/libsigsegv/src/Makefile.in @@ -0,0 +1,591 @@ +# Makefile.in generated by automake 1.11 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/sigsegv.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/bold.m4 \ + $(top_srcdir)/m4/fault.m4 $(top_srcdir)/m4/getpagesize.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap-anon.m4 \ + $(top_srcdir)/m4/relocatable.m4 \ + $(top_srcdir)/m4/sigaltstack-longjmp.m4 \ + $(top_srcdir)/m4/sigaltstack-siglongjmp.m4 \ + $(top_srcdir)/m4/sigaltstack.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = sigsegv.h +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libsigsegv_la_LIBADD = +am_libsigsegv_la_OBJECTS = handler.lo stackvma.lo leave.lo \ + dispatcher.lo version.lo +libsigsegv_la_OBJECTS = $(am_libsigsegv_la_OBJECTS) +libsigsegv_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libsigsegv_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libsigsegv_la_SOURCES) +DIST_SOURCES = $(libsigsegv_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFG_HANDLER = @CFG_HANDLER@ +CFG_LEAVE = @CFG_LEAVE@ +CFG_STACKVMA = @CFG_STACKVMA@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FAULT_CONTEXT = @FAULT_CONTEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SIGSEGV_RECOVERY = @HAVE_SIGSEGV_RECOVERY@ +HAVE_STACK_OVERFLOW_RECOVERY = @HAVE_STACK_OVERFLOW_RECOVERY@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PLATFORM = @PLATFORM@ +RANLIB = @RANLIB@ +RELOCATABLE = @RELOCATABLE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = 1.5 gnits no-dependencies +RM = rm -f +lib_LTLIBRARIES = libsigsegv.la +noinst_HEADERS = \ + fault.h fault-aix3.h fault-aix3-powerpc.h fault-aix5.h fault-aix5-powerpc.h \ + fault-beos.h fault-beos-i386.h \ + fault-bsd.h fault-freebsd-i386.h \ + fault-hpux.h fault-hpux-hppa.h fault-hurd.h fault-irix.h fault-irix-mips.h \ + fault-linux.h fault-linux-alpha.h fault-linux-arm.h fault-linux-cris.h \ + fault-linux-hppa.h fault-linux-i386.h fault-linux-i386-old.h \ + fault-linux-ia64.h fault-linux-m68k.h fault-linux-m68k.c fault-linux-mips.h \ + fault-linux-powerpc.h fault-linux-s390.h fault-linux-sh.h \ + fault-linux-sparc.h fault-linux-x86_64.h \ + fault-macos-i386.h \ + fault-macosdarwin5-powerpc.h fault-macosdarwin5-powerpc.c \ + fault-macosdarwin7-powerpc.h fault-macosdarwin7-powerpc.c \ + fault-netbsd.h fault-netbsd-alpha.h fault-netbsd-alpha.c \ + fault-none.h \ + fault-openbsd.h fault-openbsd-i386.h \ + fault-osf.h fault-osf-alpha.h \ + fault-posix.h fault-posix-ucontext.h \ + fault-solaris.h fault-solaris-i386.h fault-solaris-sparc.h \ + machfault.h machfault-macos.h \ + signals.h signals-bsd.h signals-hpux.h signals-hurd.h signals-macos.h \ + leave.h \ + stackvma.h + +EXTRA_DIST = \ + handler-none.c handler-unix.c handler-macos.c handler-win32.c \ + stackvma-none.c stackvma-simple.c stackvma-linux.c stackvma-freebsd.c \ + stackvma-procfs.c stackvma-beos.c stackvma-mach.c stackvma-mincore.c \ + stackvma-rofile.c \ + leave-none.c leave-nop.c leave-sigaltstack.c leave-setcontext.c \ + sigsegv.h.msvc + +INCLUDES = -I. -I$(srcdir) +libsigsegv_la_SOURCES = handler.c stackvma.c leave.c dispatcher.c version.c +libsigsegv_la_LDFLAGS = \ + -rpath $(libdir) \ + -version-info $(LIBSIGSEGV_VERSION_INFO) \ + -lc -no-undefined + + +# Before making a release, change this according to the libtool documentation, +# section "Library interface versions". +LIBSIGSEGV_VERSION_INFO = 1:0:0 +DISTCLEANFILES = sigsegv.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +sigsegv.h: $(top_builddir)/config.status $(srcdir)/sigsegv.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libsigsegv.la: $(libsigsegv_la_OBJECTS) $(libsigsegv_la_DEPENDENCIES) + $(libsigsegv_la_LINK) -rpath $(libdir) $(libsigsegv_la_OBJECTS) $(libsigsegv_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-local + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES uninstall-local + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-data-local install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-local \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-libLTLIBRARIES uninstall-local + + +# Dependencies. +handler.$(OBJEXT) : ../config.h sigsegv.h @CFG_HANDLER@ $(noinst_HEADERS) +stackvma.$(OBJEXT) : ../config.h @CFG_STACKVMA@ stackvma.h +leave.$(OBJEXT) : ../config.h @CFG_LEAVE@ +dispatcher.$(OBJEXT) : sigsegv.h + +# Special rules for installing sigsegv.h. + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(includedir) + $(INSTALL_DATA) sigsegv.h $(DESTDIR)$(includedir)/sigsegv.h + +installdirs-local: + $(mkinstalldirs) $(DESTDIR)$(includedir) + +uninstall-local: + $(RM) $(DESTDIR)$(includedir)/sigsegv.h + +# Rules for "make dist". + +sigsegv.h.msvc : sigsegv.h.in + sed -e 's/@''FAULT_CONTEXT_INCLUDE''@/#include <windows.h>/' \ + -e 's/@''FAULT_CONTEXT''@/CONTEXT/' \ + -e 's/@''HAVE_SIGSEGV_RECOVERY''@/1/' \ + -e 's/@''HAVE_STACK_OVERFLOW_RECOVERY''@/1/' \ + < $(srcdir)/sigsegv.h.in > $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libsigsegv/src/dispatcher.c b/libsigsegv/src/dispatcher.c new file mode 100644 index 00000000..2619e65d --- /dev/null +++ b/libsigsegv/src/dispatcher.c @@ -0,0 +1,255 @@ +/* Dispatch signal to right virtual memory area. + Copyright (C) 1993-1999, 2002-2003 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sigsegv.h" + +#include <stddef.h> /* needed for NULL on SunOS4 */ +#include <stdlib.h> +#ifdef _WIN32 +#include <malloc.h> +#endif + +/* + * A dispatcher contains an AVL tree of non-empty intervals, sorted according + * to their starting address. + */ +typedef +struct node_t +{ + /* AVL tree management. */ + struct node_t *left; + struct node_t *right; + unsigned int height; + /* Representation of interval. */ + unsigned long address; + unsigned long len; + /* User handler. */ + sigsegv_area_handler_t handler; + void *handler_arg; +} +node_t; + +#define empty ((node_t *) 0) +#define heightof(tree) ((tree) == empty ? 0 : (tree)->height) +#define MAXHEIGHT 41 + +static void +rebalance (node_t ***nodeplaces_ptr, unsigned int count) +{ + if (count > 0) + do + { + node_t **nodeplace = *--nodeplaces_ptr; + node_t *node = *nodeplace; + node_t *nodeleft = node->left; + node_t *noderight = node->right; + unsigned int heightleft = heightof (nodeleft); + unsigned int heightright = heightof (noderight); + if (heightright + 1 < heightleft) + { + node_t *nodeleftleft = nodeleft->left; + node_t *nodeleftright = nodeleft->right; + unsigned int heightleftright = heightof (nodeleftright); + if (heightof (nodeleftleft) >= heightleftright) + { + node->left = nodeleftright; nodeleft->right = node; + nodeleft->height = 1 + (node->height = 1 + heightleftright); + *nodeplace = nodeleft; + } + else + { + nodeleft->right = nodeleftright->left; + node->left = nodeleftright->right; + nodeleftright->left = nodeleft; + nodeleftright->right = node; + nodeleft->height = node->height = heightleftright; + nodeleftright->height = heightleft; + *nodeplace = nodeleftright; + } + } + else if (heightleft + 1 < heightright) + { + node_t *noderightright = noderight->right; + node_t *noderightleft = noderight->left; + unsigned int heightrightleft = heightof (noderightleft); + if (heightof (noderightright) >= heightrightleft) + { + node->right = noderightleft; noderight->left = node; + noderight->height = 1 + (node->height = 1 + heightrightleft); + *nodeplace = noderight; + } + else + { + noderight->left = noderightleft->right; + node->right = noderightleft->left; + noderightleft->right = noderight; + noderightleft->left = node; + noderight->height = node->height = heightrightleft; + noderightleft->height = heightright; + *nodeplace = noderightleft; + } + } + else + { + unsigned int height = + (heightleft<heightright ? heightright : heightleft) + 1; + if (height == node->height) + break; + node->height = height; + } + } + while (--count > 0); +} + +static node_t * +insert (node_t *new_node, node_t *tree) +{ + unsigned long key = new_node->address; + node_t **nodeplace = &tree; + node_t **stack[MAXHEIGHT]; + unsigned int stack_count = 0; + node_t ***stack_ptr = &stack[0]; + for (;;) + { + node_t *node = *nodeplace; + if (node == empty) + break; + *stack_ptr++ = nodeplace; stack_count++; + if (key < node->address) + nodeplace = &node->left; + else + nodeplace = &node->right; + } + new_node->left = empty; + new_node->right = empty; + new_node->height = 1; + *nodeplace = new_node; + rebalance (stack_ptr, stack_count); + return tree; +} + +static node_t * +delete (node_t *node_to_delete, node_t *tree) +{ + unsigned long key = node_to_delete->address; + node_t **nodeplace = &tree; + node_t **stack[MAXHEIGHT]; + unsigned int stack_count = 0; + node_t ***stack_ptr = &stack[0]; + for (;;) + { + node_t *node = *nodeplace; + if (node == empty) + return tree; + *stack_ptr++ = nodeplace; stack_count++; + if (key == node->address) + { + if (node != node_to_delete) + abort (); + break; + } + if (key < node->address) + nodeplace = &node->left; + else + nodeplace = &node->right; + } + { + node_t **nodeplace_to_delete = nodeplace; + if (node_to_delete->left == empty) + { + *nodeplace_to_delete = node_to_delete->right; + stack_ptr--; stack_count--; + } + else + { + node_t ***stack_ptr_to_delete = stack_ptr; + node_t **nodeplace = &node_to_delete->left; + node_t *node; + for (;;) + { + node = *nodeplace; + if (node->right == empty) + break; + *stack_ptr++ = nodeplace; stack_count++; + nodeplace = &node->right; + } + *nodeplace = node->left; + node->left = node_to_delete->left; + node->right = node_to_delete->right; + node->height = node_to_delete->height; + *nodeplace_to_delete = node; + *stack_ptr_to_delete = &node->left; + } + } + rebalance (stack_ptr, stack_count); + return tree; +} + +void +sigsegv_init (sigsegv_dispatcher *dispatcher) +{ + dispatcher->tree = empty; +} + +void * +sigsegv_register (sigsegv_dispatcher *dispatcher, + void *address, unsigned long len, + sigsegv_area_handler_t handler, void *handler_arg) +{ + if (len == 0) + return NULL; + else + { + node_t *new_node = (node_t *) malloc (sizeof (node_t)); + new_node->address = (unsigned long) address; + new_node->len = len; + new_node->handler = handler; + new_node->handler_arg = handler_arg; + dispatcher->tree = insert (new_node, (node_t *) dispatcher->tree); + return new_node; + } +} + +void +sigsegv_unregister (sigsegv_dispatcher *dispatcher, void *ticket) +{ + if (ticket != NULL) + { + node_t *node_to_delete = (node_t *) ticket; + dispatcher->tree = delete (node_to_delete, (node_t *) dispatcher->tree); + free (node_to_delete); + } +} + +int +sigsegv_dispatch (sigsegv_dispatcher *dispatcher, void *fault_address) +{ + unsigned long key = (unsigned long) fault_address; + node_t *tree = (node_t *) dispatcher->tree; + for (;;) + { + if (tree == empty) + return 0; + if (key < tree->address) + tree = tree->left; + else if (key - tree->address >= tree->len) + tree = tree->right; + else + break; + } + return (*tree->handler) (fault_address, tree->handler_arg); +} diff --git a/libsigsegv/src/fault-aix3-powerpc.h b/libsigsegv/src/fault-aix3-powerpc.h new file mode 100644 index 00000000..057846ce --- /dev/null +++ b/libsigsegv/src/fault-aix3-powerpc.h @@ -0,0 +1,20 @@ +/* Fault handler information. AIX3/PowerPC and AIX4/PowerPC version. + Copyright (C) 2002-2005 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-aix3.h" + +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_jmpbuf.jmp_context.gpr[1] diff --git a/libsigsegv/src/fault-aix3.h b/libsigsegv/src/fault-aix3.h new file mode 100644 index 00000000..2c91bc99 --- /dev/null +++ b/libsigsegv/src/fault-aix3.h @@ -0,0 +1,20 @@ +/* Fault handler information. AIX 3 and AIX 4 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr +#define SIGSEGV_FAULT_CONTEXT scp diff --git a/libsigsegv/src/fault-aix5-powerpc.h b/libsigsegv/src/fault-aix5-powerpc.h new file mode 100644 index 00000000..bfc1a905 --- /dev/null +++ b/libsigsegv/src/fault-aix5-powerpc.h @@ -0,0 +1,20 @@ +/* Fault handler information. AIX5/PowerPC version. + Copyright (C) 2005 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-aix5.h" + +#define SIGSEGV_FAULT_STACKPOINTER ((ucontext_t *) ucp)->uc_mcontext.jmp_context.gpr[1] diff --git a/libsigsegv/src/fault-aix5.h b/libsigsegv/src/fault-aix5.h new file mode 100644 index 00000000..a915a852 --- /dev/null +++ b/libsigsegv/src/fault-aix5.h @@ -0,0 +1,18 @@ +/* Fault handler information. AIX 5 version. + Copyright (C) 2005, 2009 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-posix-ucontext.h" diff --git a/libsigsegv/src/fault-beos-i386.h b/libsigsegv/src/fault-beos-i386.h new file mode 100644 index 00000000..af030db4 --- /dev/null +++ b/libsigsegv/src/fault-beos-i386.h @@ -0,0 +1,22 @@ +/* Fault handler information. BeOS/i386 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <OS.h> + +#include "fault-beos.h" + +#define SIGSEGV_FAULT_STACKPOINTER vrp->esp diff --git a/libsigsegv/src/fault-beos.h b/libsigsegv/src/fault-beos.h new file mode 100644 index 00000000..29e27daf --- /dev/null +++ b/libsigsegv/src/fault-beos.h @@ -0,0 +1,19 @@ +/* Fault handler information. BeOS version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, void *userdata, struct vregs *vrp +#define SIGSEGV_FAULT_CONTEXT vrp diff --git a/libsigsegv/src/fault-bsd.h b/libsigsegv/src/fault-bsd.h new file mode 100644 index 00000000..5e91845c --- /dev/null +++ b/libsigsegv/src/fault-bsd.h @@ -0,0 +1,19 @@ +/* Fault handler information. BSD Unix version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, void *scp, void *addr +#define SIGSEGV_FAULT_ADDRESS addr diff --git a/libsigsegv/src/fault-freebsd-i386.h b/libsigsegv/src/fault-freebsd-i386.h new file mode 100644 index 00000000..ffc1b6af --- /dev/null +++ b/libsigsegv/src/fault-freebsd-i386.h @@ -0,0 +1,27 @@ +/* Fault handler information. FreeBSD/i386 version. + Copyright (C) 2002, 2007 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, void *addr +#define SIGSEGV_FAULT_ADDRESS addr +#define SIGSEGV_FAULT_CONTEXT scp +#if defined __x86_64__ +/* 64 bit registers */ +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_rsp +#else +/* 32 bit registers */ +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_esp +#endif diff --git a/libsigsegv/src/fault-hpux-hppa.h b/libsigsegv/src/fault-hpux-hppa.h new file mode 100644 index 00000000..cbdf5a8b --- /dev/null +++ b/libsigsegv/src/fault-hpux-hppa.h @@ -0,0 +1,46 @@ +/* Fault handler information. HP-UX HPPA version. + Copyright (C) 2002 Paolo Bonzini <bonzini@gnu.org> + Copyright (C) 2002-2003, 2009 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define USE_64BIT_REGS(mc) \ + (((mc).ss_flags & SS_WIDEREGS) && ((mc).ss_flags & SS_NARROWISINVALID)) + +/* Extract the cr21 register from an mcontext_t. + See the comments in /usr/include/machine/save_state.h. */ +#define GET_CR21(mc) \ + (USE_64BIT_REGS(mc) ? (mc).ss_wide.ss_64.ss_cr21 : (mc).ss_narrow.ss_cr21) + +/* Extract the stack pointer from an mcontext_t. + See the comments in /usr/include/machine/save_state.h. */ +#define GET_SP(mc) \ + (USE_64BIT_REGS(mc) ? (mc).ss_wide.ss_64.ss_sp : (mc).ss_narrow.ss_sp) + +/* Both of these alternatives work on HP-UX 10.20 and HP-UX 11.00. */ +#if 1 + +#include "fault-hpux.h" + +#define SIGSEGV_FAULT_ADDRESS GET_CR21 (scp->sc_sl.sl_ss) +#define SIGSEGV_FAULT_STACKPOINTER GET_SP (scp->sc_ctxt.sl.sl_ss) + +#else + +#include "fault-posix-ucontext.h" + +#define SIGSEGV_FAULT_STACKPOINTER GET_SP (((ucontext_t *) ucp)->uc_mcontext) + +#endif diff --git a/libsigsegv/src/fault-hpux.h b/libsigsegv/src/fault-hpux.h new file mode 100644 index 00000000..632e0de3 --- /dev/null +++ b/libsigsegv/src/fault-hpux.h @@ -0,0 +1,19 @@ +/* Fault handler information. HP-UX version. + Copyright (C) 2002 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_CONTEXT scp diff --git a/libsigsegv/src/fault-hurd.h b/libsigsegv/src/fault-hurd.h new file mode 100644 index 00000000..d0272218 --- /dev/null +++ b/libsigsegv/src/fault-hurd.h @@ -0,0 +1,20 @@ +/* Fault handler information. Hurd version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS (unsigned long) code +#define SIGSEGV_FAULT_CONTEXT scp diff --git a/libsigsegv/src/fault-irix-mips.h b/libsigsegv/src/fault-irix-mips.h new file mode 100644 index 00000000..2051e6e8 --- /dev/null +++ b/libsigsegv/src/fault-irix-mips.h @@ -0,0 +1,20 @@ +/* Fault handler information. IRIX MIPS version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-irix.h" + +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_regs[29] diff --git a/libsigsegv/src/fault-irix.h b/libsigsegv/src/fault-irix.h new file mode 100644 index 00000000..239a8604 --- /dev/null +++ b/libsigsegv/src/fault-irix.h @@ -0,0 +1,20 @@ +/* Fault handler information. IRIX version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS (unsigned long) scp->sc_badvaddr +#define SIGSEGV_FAULT_CONTEXT scp diff --git a/libsigsegv/src/fault-linux-alpha.h b/libsigsegv/src/fault-linux-alpha.h new file mode 100644 index 00000000..0b49da0c --- /dev/null +++ b/libsigsegv/src/fault-linux-alpha.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux/Alpha version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_regs[30] diff --git a/libsigsegv/src/fault-linux-arm.h b/libsigsegv/src/fault-linux-arm.h new file mode 100644 index 00000000..08c92c1f --- /dev/null +++ b/libsigsegv/src/fault-linux-arm.h @@ -0,0 +1,26 @@ +/* Fault handler information. Linux/ARM version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This file supports only kernels >= 2.2.14 or >= 2.3.35. Support for older + kernels would be more complicated, see file + glibc/sysdeps/unix/sysv/linux/arm/bits/armsigctx.h. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc +#define SIGSEGV_FAULT_CONTEXT &sc +#define SIGSEGV_FAULT_STACKPOINTER sc.arm_sp diff --git a/libsigsegv/src/fault-linux-cris.h b/libsigsegv/src/fault-linux-cris.h new file mode 100644 index 00000000..b12b046c --- /dev/null +++ b/libsigsegv/src/fault-linux-cris.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux/cris version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r11, int r12, int r13, struct sigcontext sc +#define SIGSEGV_FAULT_CONTEXT (&sc) +#define SIGSEGV_FAULT_STACKPOINTER sc.usp diff --git a/libsigsegv/src/fault-linux-hppa.h b/libsigsegv/src/fault-linux-hppa.h new file mode 100644 index 00000000..4b83a0d0 --- /dev/null +++ b/libsigsegv/src/fault-linux-hppa.h @@ -0,0 +1,27 @@ +/* Fault handler information. Linux/HPPA version. + Copyright (C) 2002-2003 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <ucontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *ucp +#define SIGSEGV_FAULT_ADDRESS sip->si_ptr +#define SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO + +#if 0 +#define SIGSEGV_FAULT_CONTEXT ((ucontext_t *) ucp) +#define SIGSEGV_FAULT_STACKPOINTER ((ucontext_t *) ucp)->uc_mcontext.gregs.g_regs[30] +#endif diff --git a/libsigsegv/src/fault-linux-i386-old.h b/libsigsegv/src/fault-linux-i386-old.h new file mode 100644 index 00000000..fc949860 --- /dev/null +++ b/libsigsegv/src/fault-linux-i386-old.h @@ -0,0 +1,23 @@ +/* Fault handler information. Linux/i386 version, supports old kernels. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Don't include <asm/sigcontext.h> here, because some older kernels don't + have it or don't define `struct sigcontext' in it. */ +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, unsigned long more +#define SIGSEGV_FAULT_ADDRESS ((unsigned long *) &more) [21] +#define SIGSEGV_FAULT_CONTEXT ((struct sigcontext *) &more) +#define SIGSEGV_FAULT_STACKPOINTER ((unsigned long *) &more) [7] diff --git a/libsigsegv/src/fault-linux-i386.h b/libsigsegv/src/fault-linux-i386.h new file mode 100644 index 00000000..709ca3a1 --- /dev/null +++ b/libsigsegv/src/fault-linux-i386.h @@ -0,0 +1,21 @@ +/* Fault handler information. Linux/i386 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext sc +#define SIGSEGV_FAULT_ADDRESS sc.cr2 +#define SIGSEGV_FAULT_CONTEXT (&sc) +#define SIGSEGV_FAULT_STACKPOINTER sc.esp /* same value as sc.esp_at_signal */ diff --git a/libsigsegv/src/fault-linux-ia64.h b/libsigsegv/src/fault-linux-ia64.h new file mode 100644 index 00000000..f9cf6b12 --- /dev/null +++ b/libsigsegv/src/fault-linux-ia64.h @@ -0,0 +1,29 @@ +/* Fault handler information. Linux/IA-64 version. + Copyright (C) 2002-2003 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS sip->si_addr +#define SIGSEGV_FAULT_CONTEXT scp + +/* IA-64 has two stack pointers, one that grows down, called $r12, and one + that grows up, called $bsp/$bspstore. */ +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_gr[12] + +/* It would be better to access $bspstore instead of $bsp but I don't know + where to find it in 'struct sigcontext'. Anyway, it doesn't matter + because $bsp and $bspstore never differ by more than ca. 1 KB. */ +#define SIGSEGV_FAULT_BSP_POINTER scp->sc_ar_bsp diff --git a/libsigsegv/src/fault-linux-m68k.c b/libsigsegv/src/fault-linux-m68k.c new file mode 100644 index 00000000..8562e30e --- /dev/null +++ b/libsigsegv/src/fault-linux-m68k.c @@ -0,0 +1,44 @@ +/* Fault handler information subroutine. Linux/m68k version. + * Taken from gcc-3.2/boehm-gc/os_dep.c. + * + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +static void * +get_fault_addr (struct sigcontext *scp) +{ + int format = (scp->sc_formatvec >> 12) & 0xf; + unsigned long *framedata = (unsigned long *) (scp + 1); + unsigned long ea; + + switch (format) + { + case 10: case 11: /* 68020/030 */ + ea = framedata[2]; + return (void *) ea; + case 7: /* 68040 */ + ea = framedata[3]; + break; + case 4: /* 68060 */ + ea = framedata[0]; + break; + default: + return (void *) 0; + } + if (framedata[1] & 0x08000000) + /* Correct addr on misaligned access. */ + ea = (ea + 4095) & ~4095; + return (void *) ea; +} diff --git a/libsigsegv/src/fault-linux-m68k.h b/libsigsegv/src/fault-linux-m68k.h new file mode 100644 index 00000000..4623d902 --- /dev/null +++ b/libsigsegv/src/fault-linux-m68k.h @@ -0,0 +1,24 @@ +/* Fault handler information. Linux/m68k version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> +#include "fault-linux-m68k.c" + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS (unsigned long) get_fault_addr (scp) +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_usp diff --git a/libsigsegv/src/fault-linux-mips.h b/libsigsegv/src/fault-linux-mips.h new file mode 100644 index 00000000..fa80dc3e --- /dev/null +++ b/libsigsegv/src/fault-linux-mips.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux/MIPS version + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_regs[29] diff --git a/libsigsegv/src/fault-linux-powerpc.h b/libsigsegv/src/fault-linux-powerpc.h new file mode 100644 index 00000000..ea398f00 --- /dev/null +++ b/libsigsegv/src/fault-linux-powerpc.h @@ -0,0 +1,23 @@ +/* Fault handler information. Linux/PowerPC version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS scp->regs->dar +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->regs->gpr[1] diff --git a/libsigsegv/src/fault-linux-s390.h b/libsigsegv/src/fault-linux-s390.h new file mode 100644 index 00000000..29056ffc --- /dev/null +++ b/libsigsegv/src/fault-linux-s390.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux/S390 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->sregs->regs.gprs[15] diff --git a/libsigsegv/src/fault-linux-sh.h b/libsigsegv/src/fault-linux-sh.h new file mode 100644 index 00000000..3db1aee1 --- /dev/null +++ b/libsigsegv/src/fault-linux-sh.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux/SH version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc +#define SIGSEGV_FAULT_CONTEXT (&sc) +#define SIGSEGV_FAULT_STACKPOINTER sc.sc_regs[15] diff --git a/libsigsegv/src/fault-linux-sparc.h b/libsigsegv/src/fault-linux-sparc.h new file mode 100644 index 00000000..fcc77933 --- /dev/null +++ b/libsigsegv/src/fault-linux-sparc.h @@ -0,0 +1,23 @@ +/* Fault handler information. Linux/SPARC version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, void *addr /* FIXME */ +#define SIGSEGV_FAULT_ADDRESS addr /* in case of SunOS4 signal frames */ +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->sigc_sp /* FIXME: not scp->si_regs.u_regs[14] ? */ diff --git a/libsigsegv/src/fault-linux-x86_64.h b/libsigsegv/src/fault-linux-x86_64.h new file mode 100644 index 00000000..70b08f08 --- /dev/null +++ b/libsigsegv/src/fault-linux-x86_64.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux/x86_64 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <asm/sigcontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext sc +#define SIGSEGV_FAULT_CONTEXT (&sc) +#define SIGSEGV_FAULT_STACKPOINTER sc.rsp diff --git a/libsigsegv/src/fault-linux.h b/libsigsegv/src/fault-linux.h new file mode 100644 index 00000000..b7cf9dbc --- /dev/null +++ b/libsigsegv/src/fault-linux.h @@ -0,0 +1,22 @@ +/* Fault handler information. Linux stub version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* For SIGSEGV_FAULT_HANDLER_ARGLIST, see the definition of SIGCONTEXT in + glibc/sysdeps/unix/sysv/linux/<cpu>/sigcontextinfo.h. */ + +/* For SIGSEGV_FAULT_STACKPOINTER, see the definition of GET_STACK in + glibc/sysdeps/unix/sysv/linux/<cpu>/sigcontextinfo.h. */ diff --git a/libsigsegv/src/fault-macos-i386.h b/libsigsegv/src/fault-macos-i386.h new file mode 100644 index 00000000..83d40cb5 --- /dev/null +++ b/libsigsegv/src/fault-macos-i386.h @@ -0,0 +1,20 @@ +/* Fault handler information. MacOSX/i386 version. + Copyright (C) 2003 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_esp diff --git a/libsigsegv/src/fault-macosdarwin5-powerpc.c b/libsigsegv/src/fault-macosdarwin5-powerpc.c new file mode 100644 index 00000000..a2f59d8f --- /dev/null +++ b/libsigsegv/src/fault-macosdarwin5-powerpc.c @@ -0,0 +1,124 @@ +/* Fault handler information subroutine. MacOSX/Darwin5/PowerPC version. + * Taken from gcc-3.2/boehm-gc/os_dep.c. + * + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* Decodes the machine instruction which was responsible for the sending of the + SIGBUS signal. Sadly this is the only way to find the faulting address + because the signal handler doesn't get it directly from the kernel (although + it is available on the Mach level, but dropped by the BSD personality before + it calls our signal handler...) + This code should be able to deal correctly with all PPCs starting from the + 601 up to and including the G4s (including Velocity Engine). */ +#define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26) +#define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1) +#define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16) +#define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21) +#define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11) +#define EXTRACT_DISP(iw) ((short *) &(iw))[1] + +static void * +get_fault_addr (struct sigcontext *scp) +{ + unsigned int instr = *((unsigned int *) scp->sc_ir); + unsigned int *regs = &((unsigned int *) scp->sc_regs)[2]; + int disp = 0; + int tmp; + unsigned int baseA = 0; + unsigned int baseB = 0; + unsigned int addr; + unsigned int alignmask = 0xFFFFFFFF; + + switch (EXTRACT_OP1 (instr)) + { + case 38: /* stb */ + case 39: /* stbu */ + case 54: /* stfd */ + case 55: /* stfdu */ + case 52: /* stfs */ + case 53: /* stfsu */ + case 44: /* sth */ + case 45: /* sthu */ + case 47: /* stmw */ + case 36: /* stw */ + case 37: /* stwu */ + tmp = EXTRACT_REGA (instr); + if (tmp > 0) + baseA = regs[tmp]; + disp = EXTRACT_DISP (instr); + break; + case 31: + switch (EXTRACT_OP2 (instr)) + { + case 86: /* dcbf */ + case 54: /* dcbst */ + case 1014: /* dcbz */ + case 247: /* stbux */ + case 215: /* stbx */ + case 759: /* stfdux */ + case 727: /* stfdx */ + case 983: /* stfiwx */ + case 695: /* stfsux */ + case 663: /* stfsx */ + case 918: /* sthbrx */ + case 439: /* sthux */ + case 407: /* sthx */ + case 661: /* stswx */ + case 662: /* stwbrx */ + case 150: /* stwcx. */ + case 183: /* stwux */ + case 151: /* stwx */ + case 135: /* stvebx */ + case 167: /* stvehx */ + case 199: /* stvewx */ + case 231: /* stvx */ + case 487: /* stvxl */ + tmp = EXTRACT_REGA (instr); + if (tmp > 0) + baseA = regs[tmp]; + baseB = regs[EXTRACT_REGC (instr)]; + /* Determine Altivec alignment mask. */ + switch (EXTRACT_OP2 (instr)) + { + case 167: /* stvehx */ + alignmask = 0xFFFFFFFE; + break; + case 199: /* stvewx */ + alignmask = 0xFFFFFFFC; + break; + case 231: /* stvx */ + case 487: /* stvxl */ + alignmask = 0xFFFFFFF0; + break; + } + break; + case 725: /* stswi */ + tmp = EXTRACT_REGA (instr); + if (tmp > 0) + baseA = regs[tmp]; + break; + default: /* ignore instruction */ + return (void *) 0; + } + break; + default: /* ignore instruction */ + return (void *) 0; + } + + addr = (baseA + baseB) + disp; + addr &= alignmask; + return (void *) addr; +} diff --git a/libsigsegv/src/fault-macosdarwin5-powerpc.h b/libsigsegv/src/fault-macosdarwin5-powerpc.h new file mode 100644 index 00000000..9998061c --- /dev/null +++ b/libsigsegv/src/fault-macosdarwin5-powerpc.h @@ -0,0 +1,26 @@ +/* Fault handler information. MacOSX/Darwin5/PowerPC version. + Copyright (C) 2002-2004 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-macosdarwin5-powerpc.c" + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS (unsigned long) get_fault_addr (scp) +#define SIGSEGV_FAULT_CONTEXT scp +#if 0 +#define SIGSEGV_FAULT_STACKPOINTER (&((unsigned int *) scp->sc_regs)[2])[1] +#endif +#define SIGSEGV_FAULT_STACKPOINTER (scp->sc_regs ? ((unsigned int *) scp->sc_regs)[3] : scp->sc_sp) diff --git a/libsigsegv/src/fault-macosdarwin7-powerpc.c b/libsigsegv/src/fault-macosdarwin7-powerpc.c new file mode 100644 index 00000000..e8e9337a --- /dev/null +++ b/libsigsegv/src/fault-macosdarwin7-powerpc.c @@ -0,0 +1,131 @@ +/* Fault handler information subroutine. MacOSX/Darwin7/PowerPC version. + * Taken from gcc-3.2/boehm-gc/os_dep.c. + * + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +#include <ucontext.h> + +/* Decodes the machine instruction which was responsible for the sending of the + SIGBUS signal. Sadly this is the only way to find the faulting address + because the signal handler doesn't get it directly from the kernel (although + it is available on the Mach level, but dropped by the BSD personality before + it calls our signal handler...) + This code should be able to deal correctly with all PPCs starting from the + 601 up to and including the G4s (including Velocity Engine). */ +#define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26) +#define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1) +#define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16) +#define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21) +#define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11) +#define EXTRACT_DISP(iw) ((short *) &(iw))[1] + +static void * +get_fault_addr (siginfo_t *sip, ucontext_t *ucp) +{ + unsigned int instr = *(unsigned int *) sip->si_addr; + unsigned int *regs = +#if __DARWIN_UNIX03 + &ucp->uc_mcontext->ss.__r0; /* r0..r31 */ +#else + &ucp->uc_mcontext->ss.r0; /* r0..r31 */ +#endif + int disp = 0; + int tmp; + unsigned int baseA = 0; + unsigned int baseB = 0; + unsigned int addr; + unsigned int alignmask = 0xFFFFFFFF; + + switch (EXTRACT_OP1 (instr)) + { + case 38: /* stb */ + case 39: /* stbu */ + case 54: /* stfd */ + case 55: /* stfdu */ + case 52: /* stfs */ + case 53: /* stfsu */ + case 44: /* sth */ + case 45: /* sthu */ + case 47: /* stmw */ + case 36: /* stw */ + case 37: /* stwu */ + tmp = EXTRACT_REGA (instr); + if (tmp > 0) + baseA = regs[tmp]; + disp = EXTRACT_DISP (instr); + break; + case 31: + switch (EXTRACT_OP2 (instr)) + { + case 86: /* dcbf */ + case 54: /* dcbst */ + case 1014: /* dcbz */ + case 247: /* stbux */ + case 215: /* stbx */ + case 759: /* stfdux */ + case 727: /* stfdx */ + case 983: /* stfiwx */ + case 695: /* stfsux */ + case 663: /* stfsx */ + case 918: /* sthbrx */ + case 439: /* sthux */ + case 407: /* sthx */ + case 661: /* stswx */ + case 662: /* stwbrx */ + case 150: /* stwcx. */ + case 183: /* stwux */ + case 151: /* stwx */ + case 135: /* stvebx */ + case 167: /* stvehx */ + case 199: /* stvewx */ + case 231: /* stvx */ + case 487: /* stvxl */ + tmp = EXTRACT_REGA (instr); + if (tmp > 0) + baseA = regs[tmp]; + baseB = regs[EXTRACT_REGC (instr)]; + /* Determine Altivec alignment mask. */ + switch (EXTRACT_OP2 (instr)) + { + case 167: /* stvehx */ + alignmask = 0xFFFFFFFE; + break; + case 199: /* stvewx */ + alignmask = 0xFFFFFFFC; + break; + case 231: /* stvx */ + case 487: /* stvxl */ + alignmask = 0xFFFFFFF0; + break; + } + break; + case 725: /* stswi */ + tmp = EXTRACT_REGA (instr); + if (tmp > 0) + baseA = regs[tmp]; + break; + default: /* ignore instruction */ + return (void *) 0; + } + break; + default: /* ignore instruction */ + return (void *) 0; + } + + addr = (baseA + baseB) + disp; + addr &= alignmask; + return (void *) addr; +} diff --git a/libsigsegv/src/fault-macosdarwin7-powerpc.h b/libsigsegv/src/fault-macosdarwin7-powerpc.h new file mode 100644 index 00000000..02a26bd8 --- /dev/null +++ b/libsigsegv/src/fault-macosdarwin7-powerpc.h @@ -0,0 +1,28 @@ +/* Fault handler information. MacOSX/Darwin7/PowerPC version. + Copyright (C) 2002-2004, 2007 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-macosdarwin7-powerpc.c" + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, ucontext_t *ucp +#define SIGSEGV_FAULT_ADDRESS (unsigned long) get_fault_addr (sip, ucp) +#define SIGSEGV_FAULT_CONTEXT ucp +#define SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO +#if __DARWIN_UNIX03 +#define SIGSEGV_FAULT_STACKPOINTER ucp->uc_mcontext->ss.__r1 +#else +#define SIGSEGV_FAULT_STACKPOINTER ucp->uc_mcontext->ss.r1 +#endif diff --git a/libsigsegv/src/fault-netbsd-alpha.c b/libsigsegv/src/fault-netbsd-alpha.c new file mode 100644 index 00000000..6ca67bc1 --- /dev/null +++ b/libsigsegv/src/fault-netbsd-alpha.c @@ -0,0 +1,39 @@ +/* Fault handler information subroutine. NetBSD/Alpha version. + * Taken from gcc-3.3/boehm-gc/os_dep.c. + * + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers + * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +/* Decodes the machine instruction which was responsible for the sending of the + SIGBUS signal. Luckily this is much easier than, say, on the PowerPC. */ + +static void * +get_fault_addr (struct sigcontext *scp) +{ + unsigned int instr = *((unsigned int *)(scp->sc_pc)); + unsigned long faultaddr; + + /* Instructions which access memory have operands of the form ARG_MEM or + ARG_FMEM, consisting of + - a base register specification (PRB) in bits 20..16, + - a memory displacement (MDISP) in bits 15..0, + - an general register specification (RA) or a floating-point register + specification (FA) in bits 25..21. + See binutils-2.13.90.0.16/opcodes/alpha-opc.c. */ + + faultaddr = scp->sc_regs[(instr >> 16) & 0x1f]; + faultaddr += (unsigned long) (long) (((int)instr << 16) >> 16); + return (void *) faultaddr; +} diff --git a/libsigsegv/src/fault-netbsd-alpha.h b/libsigsegv/src/fault-netbsd-alpha.h new file mode 100644 index 00000000..595faf57 --- /dev/null +++ b/libsigsegv/src/fault-netbsd-alpha.h @@ -0,0 +1,26 @@ +/* Fault handler information. NetBSD/Alpha version. + Copyright (C) 2003 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* NetBSD's sc_sp field depends on machine/reg.h's definition of R_SP. */ +#include <machine/reg.h> + +#include "fault-netbsd-alpha.c" + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS ((unsigned long) get_fault_addr (scp)) +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_STACKPOINTER ((unsigned int *) scp->sc_sp) diff --git a/libsigsegv/src/fault-netbsd.h b/libsigsegv/src/fault-netbsd.h new file mode 100644 index 00000000..a9f2b17c --- /dev/null +++ b/libsigsegv/src/fault-netbsd.h @@ -0,0 +1,29 @@ +/* Fault handler information. NetBSD version. + Copyright (C) 2006, 2009 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-posix-ucontext.h" + +/* _UC_MACHINE_SP is a platform independent macro. + Defined in <machine/mcontext.h>, see + http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/$arch/include/mcontext.h + Supported on alpha, amd64, i386, ia64, m68k, mips, powerpc, sparc since + NetBSD 2.0. + On i386, _UC_MACHINE_SP is the same as ->uc_mcontext.__gregs[_REG_UESP], + and apparently the same value as ->uc_mcontext.__gregs[_REG_ESP]. */ +#ifdef _UC_MACHINE_SP +#define SIGSEGV_FAULT_STACKPOINTER _UC_MACHINE_SP ((ucontext_t *) ucp) +#endif diff --git a/libsigsegv/src/fault-none.h b/libsigsegv/src/fault-none.h new file mode 100644 index 00000000..064a3f0c --- /dev/null +++ b/libsigsegv/src/fault-none.h @@ -0,0 +1,17 @@ +/* Fault handler information. Version for platforms lacking support, + or with a self-contained handler.c. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/libsigsegv/src/fault-openbsd-i386.h b/libsigsegv/src/fault-openbsd-i386.h new file mode 100644 index 00000000..23339eda --- /dev/null +++ b/libsigsegv/src/fault-openbsd-i386.h @@ -0,0 +1,20 @@ +/* Fault handler information. OpenBSD/i386 version. + Copyright (C) 2003 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-openbsd.h" + +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_esp diff --git a/libsigsegv/src/fault-openbsd.h b/libsigsegv/src/fault-openbsd.h new file mode 100644 index 00000000..c784023e --- /dev/null +++ b/libsigsegv/src/fault-openbsd.h @@ -0,0 +1,21 @@ +/* Fault handler information. OpenBSD version. + Copyright (C) 2003 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, struct sigcontext *scp +#define SIGSEGV_FAULT_ADDRESS sip->si_addr +#define SIGSEGV_FAULT_CONTEXT scp +#define SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO diff --git a/libsigsegv/src/fault-osf-alpha.h b/libsigsegv/src/fault-osf-alpha.h new file mode 100644 index 00000000..e56a6539 --- /dev/null +++ b/libsigsegv/src/fault-osf-alpha.h @@ -0,0 +1,21 @@ +/* Fault handler information. OSF/1 Alpha version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-osf.h" + +#define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0 +#define SIGSEGV_FAULT_STACKPOINTER scp->sc_regs[30] diff --git a/libsigsegv/src/fault-osf.h b/libsigsegv/src/fault-osf.h new file mode 100644 index 00000000..8b939578 --- /dev/null +++ b/libsigsegv/src/fault-osf.h @@ -0,0 +1,19 @@ +/* Fault handler information. OSF/1 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp +#define SIGSEGV_FAULT_CONTEXT scp diff --git a/libsigsegv/src/fault-posix-ucontext.h b/libsigsegv/src/fault-posix-ucontext.h new file mode 100644 index 00000000..78bdd976 --- /dev/null +++ b/libsigsegv/src/fault-posix-ucontext.h @@ -0,0 +1,23 @@ +/* Fault handler information. POSIX:2001 (= SUSV3 = XPG 6) version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <ucontext.h> + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *ucp +#define SIGSEGV_FAULT_ADDRESS sip->si_addr +#define SIGSEGV_FAULT_CONTEXT ((ucontext_t *) ucp) +#define SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO diff --git a/libsigsegv/src/fault-posix.h b/libsigsegv/src/fault-posix.h new file mode 100644 index 00000000..85cd7df5 --- /dev/null +++ b/libsigsegv/src/fault-posix.h @@ -0,0 +1,21 @@ +/* Fault handler information. POSIX:2008 (XPG 7) version. + Copyright (C) 2002, 2009 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *context +#define SIGSEGV_FAULT_ADDRESS sip->si_addr +#define SIGSEGV_FAULT_CONTEXT context +#define SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO diff --git a/libsigsegv/src/fault-solaris-i386.h b/libsigsegv/src/fault-solaris-i386.h new file mode 100644 index 00000000..40035c70 --- /dev/null +++ b/libsigsegv/src/fault-solaris-i386.h @@ -0,0 +1,20 @@ +/* Fault handler information. Solaris/i386 version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-solaris.h" + +#define SIGSEGV_FAULT_STACKPOINTER ((ucontext_t *) ucp)->uc_mcontext.gregs[ESP] diff --git a/libsigsegv/src/fault-solaris-sparc.h b/libsigsegv/src/fault-solaris-sparc.h new file mode 100644 index 00000000..878fe849 --- /dev/null +++ b/libsigsegv/src/fault-solaris-sparc.h @@ -0,0 +1,20 @@ +/* Fault handler information. Solaris/SPARC version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-solaris.h" + +#define SIGSEGV_FAULT_STACKPOINTER ((ucontext_t *) ucp)->uc_mcontext.gregs[REG_O6] diff --git a/libsigsegv/src/fault-solaris.h b/libsigsegv/src/fault-solaris.h new file mode 100644 index 00000000..76135671 --- /dev/null +++ b/libsigsegv/src/fault-solaris.h @@ -0,0 +1,18 @@ +/* Fault handler information. Solaris version. + Copyright (C) 2002, 2009 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "fault-posix-ucontext.h" diff --git a/libsigsegv/src/fault.h b/libsigsegv/src/fault.h new file mode 100644 index 00000000..060c83c4 --- /dev/null +++ b/libsigsegv/src/fault.h @@ -0,0 +1,37 @@ +/* Fault handler information. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* The included file defines: + + SIGSEGV_FAULT_HANDLER_ARGLIST + is the argument list for the actual fault handler. + + SIGSEGV_FAULT_ADDRESS + is a macro for fetching the fault address. + + and if available (optional): + + SIGSEGV_FAULT_CONTEXT + is a macro giving a pointer to the entire fault context (i.e. + the register set etc.). + + SIGSEGV_FAULT_STACKPOINTER + is a macro for fetching the stackpointer at the moment the fault + occurred. + */ + +#include CFG_FAULT diff --git a/libsigsegv/src/handler-macos.c b/libsigsegv/src/handler-macos.c new file mode 100644 index 00000000..3a39e727 --- /dev/null +++ b/libsigsegv/src/handler-macos.c @@ -0,0 +1,563 @@ +/* Fault handler information. MacOSX version. + Copyright (C) 1993-1999, 2002-2003, 2007-2008 Bruno Haible <bruno@clisp.org> + Copyright (C) 2003 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sigsegv.h" + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <signal.h> +#if HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +#endif + +#include <mach/mach.h> +#include <mach/mach_error.h> +#include <mach/thread_status.h> +#include <mach/exception.h> +#include <mach/task.h> +#include <pthread.h> + +/* For MacOSX. */ +#ifndef SS_DISABLE +#define SS_DISABLE SA_DISABLE +#endif + +/* In the header files of MacOS X >= 10.5, when compiling with flags that lead + to __DARWIN_UNIX03=1 (see <sys/cdefs.h>), the register names are prefixed + with '__'. To test for MacOS X >= 10.5 versus < 10.5, we cannot use a + predefined macro such as __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ + because that does not change when a cross-compile via -isysroot is + activated. Instead use some macro defined inside the header files and which + changed in 10.5, such as + File Macro 10.4 10.5 + <mach/machine/exception.h> EXC_TYPES_COUNT 10 11 + <mach/exception_types.h> EXC_CRASH -- 10 + <mach/mach_vm.h> mach_vm_MSG_COUNT 18 19 + <mach/machine.h> CPU_TYPE_ARM -- ... + <mach/memory_object_control.h> memory_object_control_MSG_COUNT 11 12 + <mach/memory_object_types.h> UPL_ABORT_REFERENCE -- 0x80 + <mach/message.h> MACH_RCV_TRAILER_AV -- 8 + <mach/port.h> MACH_PORT_RIGHT_LABELH -- ... + <mach/thread_policy.h> THREAD_AFFINITY_POLICY -- 4 + <mach/vm_region.h> VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 ... + */ +#if EXC_TYPES_COUNT >= 11 +# define MacOS_X_10_5_HEADERS 1 +#endif + +#include "machfault.h" + +/* The following sources were used as a *reference* for this exception handling + code: + 1. Apple's mach/xnu documentation + 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the + omnigroup's macosx-dev list. + www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html */ + +/* This is not defined in any header, although documented. */ + +/* http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/exc_server.html says: + The exc_server function is the MIG generated server handling function + to handle messages from the kernel relating to the occurrence of an + exception in a thread. Such messages are delivered to the exception port + set via thread_set_exception_ports or task_set_exception_ports. When an + exception occurs in a thread, the thread sends an exception message to its + exception port, blocking in the kernel waiting for the receipt of a reply. + The exc_server function performs all necessary argument handling for this + kernel message and calls catch_exception_raise, catch_exception_raise_state + or catch_exception_raise_state_identity, which should handle the exception. + If the called routine returns KERN_SUCCESS, a reply message will be sent, + allowing the thread to continue from the point of the exception; otherwise, + no reply message is sent and the called routine must have dealt with the + exception thread directly. */ +extern boolean_t + exc_server (mach_msg_header_t *request_msg, + mach_msg_header_t *reply_msg); + + +/* http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/catch_exception_raise.html + These functions are defined in this file, and called by exc_server. + FIXME: What needs to be done when this code is put into a shared library? */ +kern_return_t +catch_exception_raise (mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t code_count); +kern_return_t +catch_exception_raise_state (mach_port_t exception_port, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t code_count, + thread_state_flavor_t *flavor, + thread_state_t in_state, + mach_msg_type_number_t in_state_count, + thread_state_t out_state, + mach_msg_type_number_t *out_state_count); +kern_return_t +catch_exception_raise_state_identity (mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t codeCnt, + thread_state_flavor_t *flavor, + thread_state_t in_state, + mach_msg_type_number_t in_state_count, + thread_state_t out_state, + mach_msg_type_number_t *out_state_count); + + +/* Our exception thread. */ +static mach_port_t our_exception_thread; + +/* The exception port on which our thread listens. */ +static mach_port_t our_exception_port; + + +/* mach_initialize() status: + 0: not yet called + 1: called and succeeded + -1: called and failed */ +static int mach_initialized = 0; + +/* Communication area for the exception state and thread state. */ +static SIGSEGV_THREAD_STATE_TYPE save_thread_state; + +/* Check for reentrant signals. */ +static int emergency = -1; + +/* User's stack overflow handler. */ +static stackoverflow_handler_t stk_user_handler = (stackoverflow_handler_t)NULL; +static unsigned long stk_extra_stack; +static unsigned long stk_extra_stack_size; + +/* User's fault handler. */ +static sigsegv_handler_t user_handler = (sigsegv_handler_t)NULL; + +/* Thread that signalled the exception. Only set while user_handler is being + invoked. */ +static mach_port_t signalled_thread = (mach_port_t) 0; + +/* A handler that is called in the faulting thread. It terminates the thread. */ +static void +terminating_handler () +{ + /* Dump core. */ + raise (SIGSEGV); + + /* Seriously. */ + abort (); +} + +/* A handler that is called in the faulting thread, on an alternate stack. + It calls the user installed stack overflow handler. */ +static void +altstack_handler () +{ + /* We arrive here when the user refused to handle a fault. */ + + /* Check if it is plausibly a stack overflow, and the user installed + a stack overflow handler. */ + if (stk_user_handler) + { + emergency++; + /* Call user's handler. */ + (*stk_user_handler) (emergency, &save_thread_state); + } + + /* Else, terminate the thread. */ + terminating_handler (); +} + + +/* Handle an exception by invoking the user's fault handler and/or forwarding + the duty to the previously installed handlers. */ +kern_return_t +catch_exception_raise (mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + exception_data_t code, + mach_msg_type_number_t code_count) +{ +#ifdef SIGSEGV_EXC_STATE_TYPE + SIGSEGV_EXC_STATE_TYPE exc_state; +#endif + SIGSEGV_THREAD_STATE_TYPE thread_state; + mach_msg_type_number_t state_count; + unsigned long addr; + unsigned long sp; + +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Exception: 0x%x Code: 0x%x 0x%x in catch....\n", + exception, + code_count > 0 ? code[0] : -1, + code_count > 1 ? code[1] : -1); +#endif + + /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html. */ +#ifdef SIGSEGV_EXC_STATE_TYPE + state_count = SIGSEGV_EXC_STATE_COUNT; + if (thread_get_state (thread, SIGSEGV_EXC_STATE_FLAVOR, + (void *) &exc_state, &state_count) + != KERN_SUCCESS) + { + /* The thread is supposed to be suspended while the exception handler + is called. This shouldn't fail. */ +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "thread_get_state failed for exception state\n"); +#endif + return KERN_FAILURE; + } +#endif + + state_count = SIGSEGV_THREAD_STATE_COUNT; + if (thread_get_state (thread, SIGSEGV_THREAD_STATE_FLAVOR, + (void *) &thread_state, &state_count) + != KERN_SUCCESS) + { + /* The thread is supposed to be suspended while the exception handler + is called. This shouldn't fail. */ +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "thread_get_state failed for thread state\n"); +#endif + return KERN_FAILURE; + } + + addr = (unsigned long) (SIGSEGV_FAULT_ADDRESS (thread_state, exc_state)); + sp = (unsigned long) (SIGSEGV_STACK_POINTER (thread_state)); + + /* Got the thread's state. Now extract the address that caused the + fault and invoke the user's handler. */ + save_thread_state = thread_state; + + /* If the fault address is near the stack pointer, it's a stack overflow. + Otherwise, treat it like a normal SIGSEGV. */ + if (addr <= sp + 4096 && sp <= addr + 4096) + { + unsigned long new_safe_esp; +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Treating as stack overflow, sp = 0x%lx\n", (char *) sp); +#endif + new_safe_esp = +#if STACK_DIRECTION < 0 + stk_extra_stack + stk_extra_stack_size - 256; +#else + stk_extra_stack + 256; +#endif +#if defined __x86_64__ || defined __i386__ + new_safe_esp &= -16; /* align */ + new_safe_esp -= sizeof (void *); /* make room for (unused) return address slot */ +#endif + SIGSEGV_STACK_POINTER (thread_state) = new_safe_esp; + /* Continue handling this fault in the faulting thread. (We cannot longjmp while + in the exception handling thread, so we need to mimic what signals do!) */ + SIGSEGV_PROGRAM_COUNTER (thread_state) = (unsigned long) altstack_handler; + } + else + { + if (user_handler) + { + int done; +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Calling user handler, addr = 0x%lx\n", (char *) addr); +#endif + signalled_thread = thread; + done = (*user_handler) ((void *) addr, 1); + signalled_thread = (mach_port_t) 0; +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Back from user handler\n"); +#endif + if (done) + return KERN_SUCCESS; + } + SIGSEGV_PROGRAM_COUNTER (thread_state) = (unsigned long) terminating_handler; + } + + /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_state.html. */ + if (thread_set_state (thread, SIGSEGV_THREAD_STATE_FLAVOR, + (void *) &thread_state, state_count) + != KERN_SUCCESS) + { +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "thread_set_state failed for altstack state\n"); +#endif + return KERN_FAILURE; + } + return KERN_SUCCESS; +} + + +/* The main function of the thread listening for exceptions. */ +static void * +mach_exception_thread (void *arg) +{ + /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_thread_self.html. */ + our_exception_thread = mach_thread_self (); + + for (;;) + { + /* These two structures contain some private kernel data. We don't need + to access any of it so we don't bother defining a proper struct. The + correct definitions are in the xnu source code. */ + /* Buffer for a message to be received. */ + struct + { + mach_msg_header_t head; + mach_msg_body_t msgh_body; + char data[1024]; + } + msg; + /* Buffer for a reply message. */ + struct + { + mach_msg_header_t head; + char data[1024]; + } + reply; + + mach_msg_return_t retval; + +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Exception thread going to sleep\n"); +#endif + + /* Wait for a message on the exception port. */ + retval = mach_msg (&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, + sizeof (msg), our_exception_port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Exception thread woke up\n"); +#endif + if (retval != MACH_MSG_SUCCESS) + { +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "mach_msg receive failed with %d %s\n", + (int) retval, mach_error_string (retval)); +#endif + abort (); + } + + /* Handle the message: Call exc_server, which will call + catch_exception_raise and produce a reply message. */ +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Calling exc_server\n"); +#endif + exc_server (&msg.head, &reply.head); +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Finished exc_server\n"); +#endif + + /* Send the reply. */ + if (mach_msg (&reply.head, MACH_SEND_MSG, reply.head.msgh_size, + 0, MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) + != MACH_MSG_SUCCESS) + { +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "mach_msg send failed\n"); +#endif + abort (); + } +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "Reply successful\n"); +#endif + } +} + + +/* Initialize the Mach exception handler thread. + Return 0 if OK, -1 on error. */ +static int +mach_initialize () +{ + mach_port_t self; + exception_mask_t mask; + pthread_attr_t attr; + pthread_t thread; + + self = mach_task_self (); + + /* Allocate a port on which the thread shall listen for exceptions. */ + if (mach_port_allocate (self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port) + != KERN_SUCCESS) + return -1; + + /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html. */ + if (mach_port_insert_right (self, our_exception_port, our_exception_port, + MACH_MSG_TYPE_MAKE_SEND) + != KERN_SUCCESS) + return -1; + + /* The exceptions we want to catch. Only EXC_BAD_ACCESS is interesting + for us (see above in function catch_exception_raise). */ + mask = EXC_MASK_BAD_ACCESS; + + /* Create the thread listening on the exception port. */ + if (pthread_attr_init (&attr) != 0) + return -1; + if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) != 0) + return -1; + if (pthread_create (&thread, &attr, mach_exception_thread, NULL) != 0) + return -1; + pthread_attr_destroy (&attr); + + /* Replace the exception port info for these exceptions with our own. + Note that we replace the exception port for the entire task, not only + for a particular thread. This has the effect that when our exception + port gets the message, the thread specific exception port has already + been asked, and we don't need to bother about it. + See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html. */ + if (task_set_exception_ports (self, mask, our_exception_port, + EXCEPTION_DEFAULT, MACHINE_THREAD_STATE) + != KERN_SUCCESS) + return -1; + + return 0; +} + + +int +sigsegv_install_handler (sigsegv_handler_t handler) +{ + if (!mach_initialized) + mach_initialized = (mach_initialize () >= 0 ? 1 : -1); + if (mach_initialized < 0) + return -1; + + user_handler = handler; + + return 0; +} + +void +sigsegv_deinstall_handler (void) +{ + user_handler = (sigsegv_handler_t)NULL; +} + +int +sigsegv_leave_handler (void (*continuation) (void*, void*, void*), + void* cont_arg1, void* cont_arg2, void* cont_arg3) +{ + emergency--; + if (mach_thread_self () == our_exception_thread) + { + /* Inside user_handler invocation. */ + mach_port_t thread; + SIGSEGV_THREAD_STATE_TYPE thread_state; + mach_msg_type_number_t state_count; + + thread = signalled_thread; + if (thread == (mach_port_t) 0) + { + /* The variable signalled_thread was supposed to be set! */ +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "sigsegv_leave_handler: signalled_thread not set\n"); +#endif + return 0; + } + + /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html. */ + state_count = SIGSEGV_THREAD_STATE_COUNT; + if (thread_get_state (thread, SIGSEGV_THREAD_STATE_FLAVOR, + (void *) &thread_state, &state_count) + != KERN_SUCCESS) + { + /* The thread was supposed to be suspended! */ +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "sigsegv_leave_handler: thread_get_state failed for thread state\n"); +#endif + return 0; + } + +#if defined __ppc64__ || defined __ppc__ || defined __x86_64__ + /* Store arguments in registers. */ + SIGSEGV_INTEGER_ARGUMENT_1 (thread_state) = (unsigned long) cont_arg1; + SIGSEGV_INTEGER_ARGUMENT_2 (thread_state) = (unsigned long) cont_arg2; + SIGSEGV_INTEGER_ARGUMENT_3 (thread_state) = (unsigned long) cont_arg3; +#endif +#if defined __x86_64__ + /* Align stack. */ + { + unsigned long new_esp = SIGSEGV_STACK_POINTER (thread_state); + new_esp &= -16; /* align */ + new_esp -= sizeof (void *); *(void **)new_esp = SIGSEGV_FRAME_POINTER (thread_state); /* push %rbp */ + SIGSEGV_STACK_POINTER (thread_state) = new_esp; + SIGSEGV_FRAME_POINTER (thread_state) = new_esp; /* mov %rsp,%rbp */ + } +#elif defined __i386__ + /* Push arguments onto the stack. */ + { + unsigned long new_esp = SIGSEGV_STACK_POINTER (thread_state); + new_esp &= -16; /* align */ + new_esp -= sizeof (void *); /* unused room, alignment */ + new_esp -= sizeof (void *); *(void **)new_esp = cont_arg3; + new_esp -= sizeof (void *); *(void **)new_esp = cont_arg2; + new_esp -= sizeof (void *); *(void **)new_esp = cont_arg1; + new_esp -= sizeof (void *); /* make room for (unused) return address slot */ + SIGSEGV_STACK_POINTER (thread_state) = new_esp; + } +#endif + /* Point program counter to continuation to be executed. */ + SIGSEGV_PROGRAM_COUNTER (thread_state) = (unsigned long) continuation; + + /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_state.html. */ + if (thread_set_state (thread, SIGSEGV_THREAD_STATE_FLAVOR, + (void *) &thread_state, state_count) + != KERN_SUCCESS) + { +#ifdef DEBUG_EXCEPTION_HANDLING + fprintf (stderr, "sigsegv_leave_handler: thread_set_state failed\n"); +#endif + return 0; + } + + return 1; + } + else + { + /* Inside stk_user_handler invocation. Stay in the same thread. */ + (*continuation) (cont_arg1, cont_arg2, cont_arg3); + return 1; + } +} + +int +stackoverflow_install_handler (stackoverflow_handler_t handler, + void *extra_stack, unsigned long extra_stack_size) +{ + if (!mach_initialized) + mach_initialized = (mach_initialize () >= 0 ? 1 : -1); + if (mach_initialized < 0) + return -1; + + stk_user_handler = handler; + stk_extra_stack = (unsigned long) extra_stack; + stk_extra_stack_size = extra_stack_size; + return 0; +} + +void +stackoverflow_deinstall_handler (void) +{ + stk_user_handler = (stackoverflow_handler_t) NULL; +} diff --git a/libsigsegv/src/handler-none.c b/libsigsegv/src/handler-none.c new file mode 100644 index 00000000..51a13f6f --- /dev/null +++ b/libsigsegv/src/handler-none.c @@ -0,0 +1,49 @@ +/* Fault handler information. + Copyright (C) 1993-1999, 2002, 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sigsegv.h" + +int +sigsegv_install_handler (sigsegv_handler_t handler) +{ + return -1; +} + +void +sigsegv_deinstall_handler (void) +{ +} + +int +sigsegv_leave_handler (void (*continuation) (void*, void*, void*), + void* cont_arg1, void* cont_arg2, void* cont_arg3) +{ + (*continuation) (cont_arg1, cont_arg2, cont_arg3); + return 1; +} + +int +stackoverflow_install_handler (stackoverflow_handler_t handler, + void *extra_stack, unsigned long extra_stack_size) +{ + return -1; +} + +void +stackoverflow_deinstall_handler (void) +{ +} diff --git a/libsigsegv/src/handler-unix.c b/libsigsegv/src/handler-unix.c new file mode 100644 index 00000000..3718eb98 --- /dev/null +++ b/libsigsegv/src/handler-unix.c @@ -0,0 +1,542 @@ +/* Fault handler information. Unix version. + Copyright (C) 1993-1999, 2002-2003, 2006, 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sigsegv.h" + +/* On the average Unix platform, we define + + HAVE_SIGSEGV_RECOVERY + if there is a fault-*.h include file which defines + SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS. + + HAVE_STACK_OVERFLOW_RECOVERY + if HAVE_SIGALTSTACK is set and + at least two of the following are true: + A) There is a fault-*.h include file which defines + SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_ADDRESS. + B) There is a fault-*.h include file which defines + SIGSEGV_FAULT_HANDLER_ARGLIST and SIGSEGV_FAULT_STACKPOINTER. + C) There is a stackvma-*.c, other than stackvma-none.c, which + defines sigsegv_get_vma. + + Why? Obviously, to catch stack overflow, we need an alternate signal + stack; this requires kernel support. But we also need to distinguish + (with a reasonable confidence) a stack overflow from a regular SIGSEGV. + If we have A) and B), we use the + Heuristic AB: If the fault address is near the stack pointer, it's a + stack overflow. + If we have A) and C), we use the + Heuristic AC: If the fault address is near and beyond the bottom of + the stack's virtual memory area, it's a stack overflow. + If we have B) and C), we use the + Heuristic BC: If the stack pointer is near the bottom of the stack's + virtual memory area, it's a stack overflow. + This heuristic comes in two flavours: On OSes which let the stack's + VMA grow continuously, we determine the bottom by use of getrlimit(). + On OSes which preallocate the stack's VMA with its maximum size + (like BeOS), we use the stack's VMA directly. + */ + +#include <stddef.h> /* needed for NULL on SunOS4 */ +#include <stdlib.h> +#include <signal.h> +#if HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +#endif +#include <errno.h> + +/* For MacOSX. */ +#ifndef SS_DISABLE +#define SS_DISABLE SA_DISABLE +#endif + +#include "fault.h" +#include CFG_SIGNALS + +#if HAVE_STACK_OVERFLOW_RECOVERY + +#include <stdio.h> /* perror */ + +#if HAVE_GETRLIMIT +# include <sys/types.h> +# include <sys/time.h> +# include <sys/resource.h> /* declares struct rlimit */ +#endif + +/* Platform dependent: + Determine the virtual memory area of a given address. */ +#include "stackvma.h" + +/* Platform dependent: + Leaving a signal handler executing on the alternate stack. */ +#include "leave.h" + +#if HAVE_STACKVMA + +/* Address of the last byte belonging to the stack vma. */ +static unsigned long stack_top = 0; + +/* Needs to be called once only. */ +static void +remember_stack_top (void *some_variable_on_stack) +{ + struct vma_struct vma; + + if (sigsegv_get_vma ((unsigned long) some_variable_on_stack, &vma) >= 0) + stack_top = vma.end - 1; +} + +#endif /* HAVE_STACKVMA */ + +static stackoverflow_handler_t stk_user_handler = (stackoverflow_handler_t)NULL; +static unsigned long stk_extra_stack; +static unsigned long stk_extra_stack_size; + +#endif /* HAVE_STACK_OVERFLOW_RECOVERY */ + +#if HAVE_SIGSEGV_RECOVERY + +/* User's SIGSEGV handler. */ +static sigsegv_handler_t user_handler = (sigsegv_handler_t)NULL; + +#endif /* HAVE_SIGSEGV_RECOVERY */ + + +/* Our SIGSEGV handler, with OS dependent argument list. */ + +#if HAVE_SIGSEGV_RECOVERY + +static void +sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST) +{ + void *address = (void *) (SIGSEGV_FAULT_ADDRESS); + +#if HAVE_STACK_OVERFLOW_RECOVERY +#if !(HAVE_STACKVMA || defined SIGSEGV_FAULT_STACKPOINTER) +#error "Insufficient heuristics for detecting a stack overflow. Either define CFG_STACKVMA and HAVE_STACKVMA correctly, or define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!" +#endif + + /* Call user's handler. */ + if (user_handler && (*user_handler) (address, 0)) + { + /* Handler successful. */ + } + else + { + /* Handler declined responsibility. */ + + /* Did the user install a stack overflow handler? */ + if (stk_user_handler) + { + /* See whether it was a stack overflow. If so, longjump away. */ +#ifdef SIGSEGV_FAULT_STACKPOINTER + unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER); +#ifdef __ia64 + unsigned long old_bsp = (unsigned long) (SIGSEGV_FAULT_BSP_POINTER); +#endif +#endif + +#if HAVE_STACKVMA + /* Were we able to determine the stack top? */ + if (stack_top) + { + /* Determine stack bounds. */ + int saved_errno; + struct vma_struct vma; + int ret; + + saved_errno = errno; + ret = sigsegv_get_vma (stack_top, &vma); + errno = saved_errno; + if (ret >= 0) + { + /* Heuristic AC: If the fault_address is nearer to the stack + segment's [start,end] than to the previous segment, we + consider it a stack overflow. + In the case of IA-64, we know that the previous segment + is the up-growing bsp segment, and either of the two + stacks can overflow. */ + unsigned long addr = (unsigned long) address; + +#ifdef __ia64 + if (addr >= vma.prev_end && addr <= vma.end - 1) +#else +#if STACK_DIRECTION < 0 + if (addr >= vma.start + ? (addr <= vma.end - 1) + : vma.is_near_this (addr, &vma)) +#else + if (addr <= vma.end - 1 + ? (addr >= vma.start) + : vma.is_near_this (addr, &vma)) +#endif +#endif +#else + /* Heuristic AB: If the fault address is near the stack pointer, + it's a stack overflow. */ + unsigned long addr = (unsigned long) address; + + if ((addr <= old_sp + 4096 && old_sp <= addr + 4096) +#ifdef __ia64 + || (addr <= old_bsp + 4096 && old_bsp <= addr + 4096) +#endif + ) + { + { +#endif + { +#ifdef SIGSEGV_FAULT_STACKPOINTER + int emergency = + (old_sp >= stk_extra_stack + && old_sp <= stk_extra_stack + stk_extra_stack_size); + stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT); +#else + int emergency = 0; + stackoverflow_context_t context = (void *) 0; +#endif + /* Call user's handler. */ + (*stk_user_handler) (emergency, context); + } + } + } + } +#endif /* HAVE_STACK_OVERFLOW_RECOVERY */ + + if (user_handler && (*user_handler) (address, 1)) + { + /* Handler successful. */ + } + else + { + /* Handler declined responsibility for real. */ + + /* Remove ourselves and dump core. */ + SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);) + } + +#if HAVE_STACK_OVERFLOW_RECOVERY + } +#endif /* HAVE_STACK_OVERFLOW_RECOVERY */ +} + +#elif HAVE_STACK_OVERFLOW_RECOVERY + +static void +#ifdef SIGSEGV_FAULT_STACKPOINTER +sigsegv_handler (SIGSEGV_FAULT_HANDLER_ARGLIST) +#else +sigsegv_handler (int sig) +#endif +{ +#if !((HAVE_GETRLIMIT && defined RLIMIT_STACK) || defined SIGSEGV_FAULT_STACKPOINTER) +#error "Insufficient heuristics for detecting a stack overflow. Either define SIGSEGV_FAULT_STACKPOINTER correctly, or undefine HAVE_STACK_OVERFLOW_RECOVERY!" +#endif + + /* Did the user install a handler? */ + if (stk_user_handler) + { + /* See whether it was a stack overflow. If so, longjump away. */ +#ifdef SIGSEGV_FAULT_STACKPOINTER + unsigned long old_sp = (unsigned long) (SIGSEGV_FAULT_STACKPOINTER); +#endif + + /* Were we able to determine the stack top? */ + if (stack_top) + { + /* Determine stack bounds. */ + int saved_errno; + struct vma_struct vma; + + saved_errno = errno; + if (sigsegv_get_vma (stack_top, &vma) >= 0) + { +#if HAVE_GETRLIMIT && defined RLIMIT_STACK + /* Heuristic BC: If the stack size has reached its maximal size, + and old_sp is near the low end, we consider it a stack + overflow. */ + struct rlimit rl; + + if (getrlimit (RLIMIT_STACK, &rl) >= 0) + { + unsigned long current_stack_size = vma.end - vma.start; + unsigned long max_stack_size = rl.rlim_cur; + if (current_stack_size <= max_stack_size + 4096 + && max_stack_size <= current_stack_size + 4096 +#else + { + if (1 +#endif +#ifdef SIGSEGV_FAULT_STACKPOINTER + /* Heuristic BC: If we know old_sp, and it is neither + near the low end, nor in the alternate stack, then + it's probably not a stack overflow. */ + && ((old_sp >= stk_extra_stack + && old_sp <= stk_extra_stack + stk_extra_stack_size) +#if STACK_DIRECTION < 0 + || (old_sp <= vma.start + 4096 + && vma.start <= old_sp + 4096)) +#else + || (old_sp <= vma.end + 4096 + && vma.end <= old_sp + 4096)) +#endif +#endif + ) + { +#ifdef SIGSEGV_FAULT_STACKPOINTER + int emergency = + (old_sp >= stk_extra_stack + && old_sp <= stk_extra_stack + stk_extra_stack_size); + stackoverflow_context_t context = (SIGSEGV_FAULT_CONTEXT); +#else + int emergency = 0; + stackoverflow_context_t context = (void *) 0; +#endif + /* Call user's handler. */ + (*stk_user_handler)(emergency,context); + } + } + } + errno = saved_errno; + } + } + + /* Remove ourselves and dump core. */ + SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);) +} + +#endif + + +static void +install_for (int sig) +{ + struct sigaction action; + +#ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO + action.sa_sigaction = &sigsegv_handler; +#else + action.sa_handler = (void (*) (int)) &sigsegv_handler; +#endif + /* Block most signals while SIGSEGV is being handled. */ + /* Signals SIGKILL, SIGSTOP cannot be blocked. */ + /* Signals SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU are not blocked because + dealing with these signals seems dangerous. */ + /* Signals SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTRAP, SIGIOT, SIGEMT, SIGBUS, + SIGSYS, SIGSTKFLT are not blocked because these are synchronous signals, + which may require immediate intervention, otherwise the process may + starve. */ + sigemptyset (&action.sa_mask); +#ifdef SIGHUP + sigaddset (&action.sa_mask,SIGHUP); +#endif +#ifdef SIGINT + sigaddset (&action.sa_mask,SIGINT); +#endif +#ifdef SIGQUIT + sigaddset (&action.sa_mask,SIGQUIT); +#endif +#ifdef SIGPIPE + sigaddset (&action.sa_mask,SIGPIPE); +#endif +#ifdef SIGALRM + sigaddset (&action.sa_mask,SIGALRM); +#endif +#ifdef SIGTERM + sigaddset (&action.sa_mask,SIGTERM); +#endif +#ifdef SIGUSR1 + sigaddset (&action.sa_mask,SIGUSR1); +#endif +#ifdef SIGUSR2 + sigaddset (&action.sa_mask,SIGUSR2); +#endif +#ifdef SIGCHLD + sigaddset (&action.sa_mask,SIGCHLD); +#endif +#ifdef SIGCLD + sigaddset (&action.sa_mask,SIGCLD); +#endif +#ifdef SIGURG + sigaddset (&action.sa_mask,SIGURG); +#endif +#ifdef SIGIO + sigaddset (&action.sa_mask,SIGIO); +#endif +#ifdef SIGPOLL + sigaddset (&action.sa_mask,SIGPOLL); +#endif +#ifdef SIGXCPU + sigaddset (&action.sa_mask,SIGXCPU); +#endif +#ifdef SIGXFSZ + sigaddset (&action.sa_mask,SIGXFSZ); +#endif +#ifdef SIGVTALRM + sigaddset (&action.sa_mask,SIGVTALRM); +#endif +#ifdef SIGPROF + sigaddset (&action.sa_mask,SIGPROF); +#endif +#ifdef SIGPWR + sigaddset (&action.sa_mask,SIGPWR); +#endif +#ifdef SIGLOST + sigaddset (&action.sa_mask,SIGLOST); +#endif +#ifdef SIGWINCH + sigaddset (&action.sa_mask,SIGWINCH); +#endif + /* Note that sigaction() implicitly adds sig itself to action.sa_mask. */ + /* Ask the OS to provide a structure siginfo_t to the handler. */ +#ifdef SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO + action.sa_flags = SA_SIGINFO; +#else + action.sa_flags = 0; +#endif +#if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGALTSTACK /* not BeOS */ + /* Work around Linux 2.2.5 bug: If SA_ONSTACK is specified but sigaltstack() + has not been called, the kernel will busy loop, eating CPU time. So + avoid setting SA_ONSTACK until the user has requested stack overflow + handling. */ + if (stk_user_handler) + action.sa_flags |= SA_ONSTACK; +#endif + sigaction (sig, &action, (struct sigaction *) NULL); +} + +int +sigsegv_install_handler (sigsegv_handler_t handler) +{ +#if HAVE_SIGSEGV_RECOVERY + user_handler = handler; + + SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);) + + return 0; +#else + return -1; +#endif +} + +void +sigsegv_deinstall_handler (void) +{ +#if HAVE_SIGSEGV_RECOVERY + user_handler = (sigsegv_handler_t)NULL; + +#if HAVE_STACK_OVERFLOW_RECOVERY + if (!stk_user_handler) +#endif + { + SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);) + } +#endif +} + +int +sigsegv_leave_handler (void (*continuation) (void*, void*, void*), + void* cont_arg1, void* cont_arg2, void* cont_arg3) +{ +#if HAVE_STACK_OVERFLOW_RECOVERY + /* + * Reset the system's knowledge that we are executing on the alternate + * stack. If we didn't do that, siglongjmp would be needed instead of + * longjmp to leave the signal handler. + */ + sigsegv_reset_onstack_flag (); +#endif + (*continuation) (cont_arg1, cont_arg2, cont_arg3); + return 1; +} + +int +stackoverflow_install_handler (stackoverflow_handler_t handler, + void *extra_stack, unsigned long extra_stack_size) +{ +#if HAVE_STACK_OVERFLOW_RECOVERY +#if HAVE_STACKVMA + if (!stack_top) + { + int dummy; + remember_stack_top (&dummy); + if (!stack_top) + return -1; + } +#endif + + stk_user_handler = handler; + stk_extra_stack = (unsigned long) extra_stack; + stk_extra_stack_size = extra_stack_size; +#ifdef __BEOS__ + set_signal_stack (extra_stack, extra_stack_size); +#else /* HAVE_SIGALTSTACK */ + { + stack_t ss; +#if SIGALTSTACK_SS_REVERSED + ss.ss_sp = (char *) extra_stack + extra_stack_size - sizeof (void *); + ss.ss_size = extra_stack_size - sizeof (void *); +#else + ss.ss_sp = extra_stack; + ss.ss_size = extra_stack_size; +#endif + ss.ss_flags = 0; /* no SS_DISABLE */ + if (sigaltstack (&ss, (stack_t*)0) < 0) + return -1; + } +#endif + + /* Install the signal handlers with SA_ONSTACK. */ + SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);) + return 0; +#else + return -1; +#endif +} + +void +stackoverflow_deinstall_handler (void) +{ +#if HAVE_STACK_OVERFLOW_RECOVERY + stk_user_handler = (stackoverflow_handler_t) NULL; + +#if HAVE_SIGSEGV_RECOVERY + if (user_handler) + { + /* Reinstall the signal handlers without SA_ONSTACK, to avoid Linux + bug. */ + SIGSEGV_FOR_ALL_SIGNALS (sig, install_for (sig);) + } + else +#endif + { + SIGSEGV_FOR_ALL_SIGNALS (sig, signal (sig, SIG_DFL);) + } + +#ifdef __BEOS__ + /* We cannot undo the effect of set_signal_stack. */ + fprintf (stderr, "libsigsegv (stackoverflow_deinstall_handler): not supported on this platform\n"); +#else /* HAVE_SIGALTSTACK */ + { + stack_t ss; + ss.ss_flags = SS_DISABLE; + if (sigaltstack (&ss, (stack_t *) 0) < 0) + perror ("libsigsegv (stackoverflow_deinstall_handler)"); + } +#endif + +#endif +} diff --git a/libsigsegv/src/handler-win32.c b/libsigsegv/src/handler-win32.c new file mode 100644 index 00000000..479bd030 --- /dev/null +++ b/libsigsegv/src/handler-win32.c @@ -0,0 +1,317 @@ +/* Fault handler information. Woe32 version. + Copyright (C) 1993-1999, 2002-2003, 2007-2008 Bruno Haible <bruno@clisp.org> + Copyright (C) 2003 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sigsegv.h" + +#define WIN32_LEAN_AND_MEAN /* avoid including junk */ +#include <windows.h> +#include <winerror.h> +/* + * extern LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER TopLevelExceptionFilter); + * extern DWORD VirtualQuery (LPCVOID Address, PMEMORY_BASIC_INFORMATION Buffer, DWORD Length); + * extern BOOL VirtualProtect (LPVOID Address, DWORD Size, DWORD NewProtect, PDWORD OldProtect); + * extern DWORD GetLastError (void); + */ + +/* User's SIGSEGV handler. */ +static sigsegv_handler_t user_handler = (sigsegv_handler_t) NULL; + +/* Stack overflow handling is tricky: + First, we must catch a STATUS_STACK_OVERFLOW exception. This is signalled + when the guard page at the end of the stack has been touched. The operating + system remaps the page with protection PAGE_READWRITE and only then calls + our exception handler. Actually, it's even more complicated: The stack has + the following layout: + + | |guard|----------stack-----------| + + and when the guard page is touched, the system maps it PAGE_READWRITE and + allocates a new guard page below it: + + | |guard|-------------stack--------------| + + Only when no new guard page can be allocated (because the maximum stack + size has been reached), will we see an exception. + + |guard|-------------------------stack--------------------------| + + Second, we must reinstall the guard page. Otherwise, on the next stack + overflow, the application will simply crash (on WinNT: silently, on Win95: + with an error message box and freezing the system). + But since we don't know where %esp points to during the exception handling, + we must first leave the exception handler, before we can restore the guard + page. And %esp must be made to point to a reasonable value before we do + this. + + Note: On WinNT, the guard page has protection PAGE_READWRITE|PAGE_GUARD. + On Win95, which doesn't know PAGE_GUARD, it has protection PAGE_NOACCESS. + */ + +static stackoverflow_handler_t stk_user_handler = + (stackoverflow_handler_t) NULL; +static unsigned long stk_extra_stack; +static unsigned long stk_extra_stack_size; + +static void +stack_overflow_handler (unsigned long faulting_page_address, stackoverflow_context_t context) +{ + MEMORY_BASIC_INFORMATION info; + DWORD oldprot; + unsigned long base; + unsigned long address; + + /* First get stack's base address. */ + if (VirtualQuery ((void*) faulting_page_address, &info, sizeof (info)) + != sizeof (info)) + goto failed; + base = (unsigned long) info.AllocationBase; + + /* Now search for the first existing page. */ + address = base; + for (;;) + { + if (VirtualQuery ((void*) address, &info, sizeof (info)) != sizeof (info)) + goto failed; + if (address != (unsigned long) info.BaseAddress) + goto failed; + if (info.State != MEM_FREE) + { + if ((unsigned long) info.AllocationBase != base) + goto failed; + if (info.State == MEM_COMMIT) + break; + } + address = (unsigned long) info.BaseAddress + info.RegionSize; + } + + /* Now add the PAGE_GUARD bit to the first existing page. */ + /* On WinNT this works... */ + if (VirtualProtect (info.BaseAddress, 0x1000, info.Protect | PAGE_GUARD, + &oldprot)) + goto ok; + if (GetLastError () == ERROR_INVALID_PARAMETER) + /* ... but on Win95 we need this: */ + if (VirtualProtect (info.BaseAddress, 0x1000, PAGE_NOACCESS, &oldprot)) + goto ok; + failed: + for (;;) + (*stk_user_handler) (1, context); + ok: + for (;;) + (*stk_user_handler) (0, context); +} + +/* This is the stack overflow and page fault handler. */ +static LONG WINAPI +main_exception_filter (EXCEPTION_POINTERS *ExceptionInfo) +{ + if ((stk_user_handler + && ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW + ) + || + (user_handler != (sigsegv_handler_t)NULL + && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION + )) + { +#if 0 /* for debugging only */ + printf ("Exception!\n"); + printf ("Code = 0x%x\n", + ExceptionInfo->ExceptionRecord->ExceptionCode); + printf ("Flags = 0x%x\n", + ExceptionInfo->ExceptionRecord->ExceptionFlags); + printf ("Address = 0x%x\n", + ExceptionInfo->ExceptionRecord->ExceptionAddress); + printf ("Params:"); + { + DWORD i; + for (i = 0; i < ExceptionInfo->ExceptionRecord->NumberParameters; i++) + printf (" 0x%x,", + ExceptionInfo->ExceptionRecord->ExceptionInformation[i]); + } + printf ("\n"); + printf ("Registers:\n"); + printf ("eip = 0x%x\n", ExceptionInfo->ContextRecord->Eip); + printf ("eax = 0x%x, ", ExceptionInfo->ContextRecord->Eax); + printf ("ebx = 0x%x, ", ExceptionInfo->ContextRecord->Ebx); + printf ("ecx = 0x%x, ", ExceptionInfo->ContextRecord->Ecx); + printf ("edx = 0x%x\n", ExceptionInfo->ContextRecord->Edx); + printf ("esi = 0x%x, ", ExceptionInfo->ContextRecord->Esi); + printf ("edi = 0x%x, ", ExceptionInfo->ContextRecord->Edi); + printf ("ebp = 0x%x, ", ExceptionInfo->ContextRecord->Ebp); + printf ("esp = 0x%x\n", ExceptionInfo->ContextRecord->Esp); +#endif + if (ExceptionInfo->ExceptionRecord->NumberParameters == 2) + { + if (stk_user_handler + && ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + { + char *address = (char *) ExceptionInfo->ExceptionRecord->ExceptionInformation[1]; + /* Restart the program, giving it a sane value for %esp. + At the same time, copy the contents of + ExceptionInfo->ContextRecord (which, on Windows XP, happens + to be allocated in the guard page, where it will be + inaccessible as soon as we restore the PAGE_GUARD bit!) to + this new stack. */ + unsigned long faulting_page_address = (unsigned long)address & -0x1000; + unsigned long new_safe_esp = ((stk_extra_stack + stk_extra_stack_size) & -16); + CONTEXT *orig_context = ExceptionInfo->ContextRecord; + CONTEXT *safe_context = (CONTEXT *) (new_safe_esp -= sizeof (CONTEXT)); /* make room */ + memcpy (safe_context, orig_context, sizeof (CONTEXT)); + new_safe_esp -= 8; /* make room for arguments */ + new_safe_esp &= -16; /* align */ + new_safe_esp -= 4; /* make room for (unused) return address slot */ + ExceptionInfo->ContextRecord->Esp = new_safe_esp; + /* Call stack_overflow_handler(faulting_page_address,safe_context). */ + ExceptionInfo->ContextRecord->Eip = (unsigned long)&stack_overflow_handler; + *(unsigned long *)(new_safe_esp + 4) = faulting_page_address; + *(unsigned long *)(new_safe_esp + 8) = (unsigned long) safe_context; + return EXCEPTION_CONTINUE_EXECUTION; + } + if (user_handler != (sigsegv_handler_t) NULL + && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + { + /* ExceptionInfo->ExceptionRecord->ExceptionInformation[0] is 1 + if it's a write access, 0 if it's a read access. But we don't + need this info because we don't have it on Unix either. */ + void *address = (void *) ExceptionInfo->ExceptionRecord->ExceptionInformation[1]; + if ((*user_handler) (address, 1)) + return EXCEPTION_CONTINUE_EXECUTION; + } + } + } + return EXCEPTION_CONTINUE_SEARCH; +} + +#if defined __CYGWIN__ && defined __i386__ + +/* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin + installs a global exception handler. We have to dig deep in order to install + our main_exception_filter. */ + +/* Data structures for the current thread's exception handler chain. + On the x86 Windows uses register fs, offset 0 to point to the current + exception handler; Cygwin mucks with it, so we must do the same... :-/ */ + +/* Magic taken from winsup/cygwin/include/exceptions.h. */ + +struct exception_list + { + struct exception_list *prev; + int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *); + }; +typedef struct exception_list exception_list; + +/* Magic taken from winsup/cygwin/exceptions.cc. */ + +__asm__ (".equ __except_list,0"); + +extern exception_list *_except_list __asm__ ("%fs:__except_list"); + +/* For debugging. _except_list is not otherwise accessible from gdb. */ +static exception_list * +debug_get_except_list () +{ + return _except_list; +} + +/* Cygwin's original exception handler. */ +static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *); + +/* Our exception handler. */ +static int +libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch) +{ + EXCEPTION_POINTERS ExceptionInfo; + ExceptionInfo.ExceptionRecord = exception; + ExceptionInfo.ContextRecord = context; + if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH) + return cygwin_exception_handler (exception, frame, context, dispatch); + else + return 0; +} + +static void +do_install_main_exception_filter () +{ + /* We cannot insert any handler into the chain, because such handlers + must lie on the stack (?). Instead, we have to replace(!) Cygwin's + global exception handler. */ + cygwin_exception_handler = _except_list->handler; + _except_list->handler = libsigsegv_exception_handler; +} + +#else + +static void +do_install_main_exception_filter () +{ + SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter); +} + +#endif + +static void +install_main_exception_filter () +{ + static int main_exception_filter_installed = 0; + + if (!main_exception_filter_installed) + { + do_install_main_exception_filter (); + main_exception_filter_installed = 1; + } +} + +int +sigsegv_install_handler (sigsegv_handler_t handler) +{ + user_handler = handler; + install_main_exception_filter (); + return 0; +} + +void +sigsegv_deinstall_handler (void) +{ + user_handler = (sigsegv_handler_t) NULL; +} + +int +sigsegv_leave_handler (void (*continuation) (void*, void*, void*), + void* cont_arg1, void* cont_arg2, void* cont_arg3) +{ + (*continuation) (cont_arg1, cont_arg2, cont_arg3); + return 1; +} + +int +stackoverflow_install_handler (stackoverflow_handler_t handler, + void *extra_stack, unsigned long extra_stack_size) +{ + stk_user_handler = handler; + stk_extra_stack = (unsigned long) extra_stack; + stk_extra_stack_size = extra_stack_size; + install_main_exception_filter (); + return 0; +} + +void +stackoverflow_deinstall_handler (void) +{ + stk_user_handler = (stackoverflow_handler_t) NULL; +} diff --git a/libsigsegv/src/handler.c b/libsigsegv/src/handler.c new file mode 100644 index 00000000..4fd1cbac --- /dev/null +++ b/libsigsegv/src/handler.c @@ -0,0 +1,20 @@ +/* Fault handler information. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" + +#include CFG_HANDLER diff --git a/libsigsegv/src/leave-none.c b/libsigsegv/src/leave-none.c new file mode 100644 index 00000000..deeb7b89 --- /dev/null +++ b/libsigsegv/src/leave-none.c @@ -0,0 +1,18 @@ +/* Leaving a signal handler executing on the alternate stack. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* No need to define sigsegv_reset_onstack_flag() on this platform. */ diff --git a/libsigsegv/src/leave-nop.c b/libsigsegv/src/leave-nop.c new file mode 100644 index 00000000..88674bda --- /dev/null +++ b/libsigsegv/src/leave-nop.c @@ -0,0 +1,23 @@ +/* Leaving a signal handler executing on the alternate stack. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +void +sigsegv_reset_onstack_flag (void) +{ + /* Nothing to do. sigaltstack() simply looks at the stack pointer, + therefore SS_ONSTACK is not sticky. */ +} diff --git a/libsigsegv/src/leave-setcontext.c b/libsigsegv/src/leave-setcontext.c new file mode 100644 index 00000000..e383cf96 --- /dev/null +++ b/libsigsegv/src/leave-setcontext.c @@ -0,0 +1,38 @@ +/* Leaving a signal handler executing on the alternate stack. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <signal.h> +#include <ucontext.h> + +void +sigsegv_reset_onstack_flag (void) +{ + ucontext_t uc; + + if (getcontext (&uc) >= 0) + /* getcontext returns twice. We are interested in the returned context + only the first time, i.e. when the SS_ONSTACK bit is set. */ + if (uc.uc_stack.ss_flags & SS_ONSTACK) + { + uc.uc_stack.ss_flags &= ~SS_ONSTACK; + /* Note that setcontext() does not refill uc. Therefore if + setcontext() keeps SS_ONSTACK set in the kernel, either + setcontext() will return -1 or getcontext() will return a + second time, with the SS_ONSTACK bit being cleared. */ + setcontext (&uc); + } +} diff --git a/libsigsegv/src/leave-sigaltstack.c b/libsigsegv/src/leave-sigaltstack.c new file mode 100644 index 00000000..39749a55 --- /dev/null +++ b/libsigsegv/src/leave-sigaltstack.c @@ -0,0 +1,39 @@ +/* Leaving a signal handler executing on the alternate stack. + Copyright (C) 2002-2003 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <stddef.h> +#include <signal.h> +#if HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +#endif + +/* For MacOSX. */ +#ifndef SS_ONSTACK +#define SS_ONSTACK SA_ONSTACK +#endif + +void +sigsegv_reset_onstack_flag (void) +{ + stack_t ss; + + if (sigaltstack (NULL, &ss) >= 0) + { + ss.ss_flags &= ~SS_ONSTACK; + sigaltstack (&ss, NULL); + } +} diff --git a/libsigsegv/src/leave.c b/libsigsegv/src/leave.c new file mode 100644 index 00000000..e7d7024a --- /dev/null +++ b/libsigsegv/src/leave.c @@ -0,0 +1,20 @@ +/* Leaving a signal handler executing on the alternate stack. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" + +#include CFG_LEAVE diff --git a/libsigsegv/src/leave.h b/libsigsegv/src/leave.h new file mode 100644 index 00000000..9a279c76 --- /dev/null +++ b/libsigsegv/src/leave.h @@ -0,0 +1,18 @@ +/* Leaving a signal handler executing on the alternate stack. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +extern void sigsegv_reset_onstack_flag (void); diff --git a/libsigsegv/src/machfault-macos.h b/libsigsegv/src/machfault-macos.h new file mode 100644 index 00000000..3fb49d7b --- /dev/null +++ b/libsigsegv/src/machfault-macos.h @@ -0,0 +1,120 @@ +/* Fault handler information. MacOSX version (both PowerPC and i386). + Copyright (C) 2003-2004, 2006-2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#if defined __ppc__ || defined __ppc64__ + +#if defined __ppc64__ +/* 64 bit registers */ + +#define SIGSEGV_EXC_STATE_TYPE ppc_exception_state64_t +#define SIGSEGV_EXC_STATE_FLAVOR PPC_EXCEPTION_STATE64 +#define SIGSEGV_EXC_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT +#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t +#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64 +#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT + +#else +/* 32 bit registers */ + +#define SIGSEGV_EXC_STATE_TYPE ppc_exception_state_t +#define SIGSEGV_EXC_STATE_FLAVOR PPC_EXCEPTION_STATE +#define SIGSEGV_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT +#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t +#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE +#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT + +#endif + +#if MacOS_X_10_5_HEADERS && __DARWIN_UNIX03 +#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).__dar +#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).__r1 +#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).__srr0 +#define SIGSEGV_INTEGER_ARGUMENT_1(thr_state) (thr_state).__r3 +#define SIGSEGV_INTEGER_ARGUMENT_2(thr_state) (thr_state).__r4 +#define SIGSEGV_INTEGER_ARGUMENT_3(thr_state) (thr_state).__r5 +#else +#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).dar +#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).r1 +#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).srr0 +#define SIGSEGV_INTEGER_ARGUMENT_1(thr_state) (thr_state).r3 +#define SIGSEGV_INTEGER_ARGUMENT_2(thr_state) (thr_state).r4 +#define SIGSEGV_INTEGER_ARGUMENT_3(thr_state) (thr_state).r5 +#endif + +#endif + +#if defined __i386__ || defined __x86_64__ + +#if defined __x86_64__ +/* 64 bit registers */ + +#define SIGSEGV_THREAD_STATE_TYPE x86_thread_state64_t +#define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64 +#define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT +#define SIGSEGV_EXC_STATE_TYPE x86_exception_state64_t +#define SIGSEGV_EXC_STATE_FLAVOR x86_EXCEPTION_STATE64 +#define SIGSEGV_EXC_STATE_COUNT x86_EXCEPTION_STATE64_COUNT +#if MacOS_X_10_5_HEADERS && __DARWIN_UNIX03 +#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).__faultvaddr +#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).__rsp +#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).__rip +#define SIGSEGV_FRAME_POINTER(thr_state) (thr_state).__rbp +#define SIGSEGV_INTEGER_ARGUMENT_1(thr_state) (thr_state).__rdi +#define SIGSEGV_INTEGER_ARGUMENT_2(thr_state) (thr_state).__rsi +#define SIGSEGV_INTEGER_ARGUMENT_3(thr_state) (thr_state).__rdx +#else +#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).faultvaddr +#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).rsp +#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).rip +#define SIGSEGV_FRAME_POINTER(thr_state) (thr_state).rbp +#define SIGSEGV_INTEGER_ARGUMENT_1(thr_state) (thr_state).rdi +#define SIGSEGV_INTEGER_ARGUMENT_2(thr_state) (thr_state).rsi +#define SIGSEGV_INTEGER_ARGUMENT_3(thr_state) (thr_state).rdx +#endif + +#else +/* 32 bit registers */ + +#if defined x86_THREAD_STATE32 +/* MacOS X 10.5 or newer introduces the new names and deprecates the old ones */ +#define SIGSEGV_THREAD_STATE_TYPE x86_thread_state32_t +#define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE32 +#define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT +#define SIGSEGV_EXC_STATE_TYPE x86_exception_state32_t +#define SIGSEGV_EXC_STATE_FLAVOR x86_EXCEPTION_STATE32 +#define SIGSEGV_EXC_STATE_COUNT x86_EXCEPTION_STATE32_COUNT +#else +#define SIGSEGV_THREAD_STATE_TYPE i386_thread_state_t +#define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE +#define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT +#define SIGSEGV_EXC_STATE_TYPE i386_exception_state_t +#define SIGSEGV_EXC_STATE_FLAVOR i386_EXCEPTION_STATE +#define SIGSEGV_EXC_STATE_COUNT i386_EXCEPTION_STATE_COUNT +#endif +#if MacOS_X_10_5_HEADERS && __DARWIN_UNIX03 +#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).__faultvaddr +#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).__esp +#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).__eip +#else +#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).faultvaddr +#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).esp +#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).eip +#endif + +#endif + +#endif diff --git a/libsigsegv/src/machfault.h b/libsigsegv/src/machfault.h new file mode 100644 index 00000000..fd182a05 --- /dev/null +++ b/libsigsegv/src/machfault.h @@ -0,0 +1,54 @@ +/* Fault handler information. + Copyright (C) 2004 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* The included file defines: + + SIGSEGV_EXC_STATE_TYPE + is a type containing state describing details of an exception, + excluding the thread state. + SIGSEGV_EXC_STATE_FLAVOR + is a macro expanding to a constant int value denoting the + SIGSEGV_EXC_STATE_TYPE type. + SIGSEGV_EXC_STATE_COUNT + is a macro expanding to the number of words of the + SIGSEGV_EXC_STATE_TYPE type. + + SIGSEGV_THREAD_STATE_TYPE + is a type containing the state of a (stopped or interrupted) thread. + SIGSEGV_THREAD_STATE_FLAVOR + is a macro expanding to a constant int value denoting the + SIGSEGV_THREAD_STATE_TYPE type. + SIGSEGV_THREAD_STATE_COUNT + is a macro expanding to the number of words of the + SIGSEGV_THREAD_STATE_TYPE type. + + SIGSEGV_FAULT_ADDRESS(thr_state, exc_state) + is a macro for fetching the fault address. + + SIGSEGV_STACK_POINTER(thr_state) + is a macro, expanding to an lvalue, for fetching the stackpointer at + the moment the fault occurred, and for setting the stackpointer in + effect when the thread continues. + + SIGSEGV_PROGRAM_COUNTER(thr_state) + is a macro, expanding to an lvalue, for fetching the program counter + (= instruction pointer) at the moment the fault occurred, and for + setting the program counter before letting the thread continue. + + */ + +#include CFG_MACHFAULT diff --git a/libsigsegv/src/signals-bsd.h b/libsigsegv/src/signals-bsd.h new file mode 100644 index 00000000..4b57f069 --- /dev/null +++ b/libsigsegv/src/signals-bsd.h @@ -0,0 +1,21 @@ +/* List of signals. BSD version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* List of signals that are sent when an invalid virtual memory address + is accessed, or when the stack overflows. */ +#define SIGSEGV_FOR_ALL_SIGNALS(var,body) \ + { int var; var = SIGSEGV; { body } var = SIGBUS; { body } } diff --git a/libsigsegv/src/signals-hpux.h b/libsigsegv/src/signals-hpux.h new file mode 100644 index 00000000..0061d21c --- /dev/null +++ b/libsigsegv/src/signals-hpux.h @@ -0,0 +1,21 @@ +/* List of signals. HP-UX version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* List of signals that are sent when an invalid virtual memory address + is accessed, or when the stack overflows. */ +#define SIGSEGV_FOR_ALL_SIGNALS(var,body) \ + { int var; var = SIGSEGV; { body } var = SIGBUS; { body } } diff --git a/libsigsegv/src/signals-hurd.h b/libsigsegv/src/signals-hurd.h new file mode 100644 index 00000000..b191fe4d --- /dev/null +++ b/libsigsegv/src/signals-hurd.h @@ -0,0 +1,21 @@ +/* List of signals. Hurd version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* List of signals that are sent when an invalid virtual memory address + is accessed, or when the stack overflows. */ +#define SIGSEGV_FOR_ALL_SIGNALS(var,body) \ + { int var; var = SIGSEGV; { body } var = SIGBUS; { body } } diff --git a/libsigsegv/src/signals-macos.h b/libsigsegv/src/signals-macos.h new file mode 100644 index 00000000..a9fc9a81 --- /dev/null +++ b/libsigsegv/src/signals-macos.h @@ -0,0 +1,24 @@ +/* List of signals. MacOSX version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + Copyright (C) 2003 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* List of signals that are sent when an invalid virtual memory address + is accessed, or when the stack overflows. + On MacOS X, accessing an invalid memory address gives a SIGBUS, but a + stack overflow gives a SIGSEGV. */ +#define SIGSEGV_FOR_ALL_SIGNALS(var,body) \ + { int var; var = SIGSEGV; { body } var = SIGBUS; { body } } diff --git a/libsigsegv/src/signals.h b/libsigsegv/src/signals.h new file mode 100644 index 00000000..b6203ee5 --- /dev/null +++ b/libsigsegv/src/signals.h @@ -0,0 +1,21 @@ +/* List of signals. Generic Unix version. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* List of signals that are sent when an invalid virtual memory address + is accessed, or when the stack overflows. */ +#define SIGSEGV_FOR_ALL_SIGNALS(var,body) \ + { int var; var = SIGSEGV; { body } } diff --git a/libsigsegv/src/sigsegv.h.in b/libsigsegv/src/sigsegv.h.in new file mode 100644 index 00000000..e6689d28 --- /dev/null +++ b/libsigsegv/src/sigsegv.h.in @@ -0,0 +1,201 @@ +/* Page fault handling library. + Copyright (C) 1998-1999, 2002, 2004-2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _SIGSEGV_H +#define _SIGSEGV_H + +@FAULT_CONTEXT_INCLUDE@ + +/* HAVE_SIGSEGV_RECOVERY + is defined if the system supports catching SIGSEGV. */ +#if @HAVE_SIGSEGV_RECOVERY@ +# define HAVE_SIGSEGV_RECOVERY 1 +#endif + +/* HAVE_STACK_OVERFLOW_RECOVERY + is defined if stack overflow can be caught. */ +#if @HAVE_STACK_OVERFLOW_RECOVERY@ +# define HAVE_STACK_OVERFLOW_RECOVERY 1 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBSIGSEGV_VERSION 0x0206 /* version number: (major<<8) + minor */ +extern int libsigsegv_version; /* Likewise */ + +/* -------------------------------------------------------------------------- */ + +/* + * The type of a global SIGSEGV handler. + * The fault address is passed as argument. + * The access type (read access or write access) is not passed; your handler + * has to know itself how to distinguish these two cases. + * The second argument is 0, meaning it could also be a stack overflow, or 1, + * meaning the handler should seriously try to fix the fault. + * The return value should be nonzero if the handler has done its job + * and no other handler should be called, or 0 if the handler declines + * responsibility for the given address. + * + * The handler is run at a moment when nothing about the global state of the + * program is known. Therefore it cannot use facilities that manipulate global + * variables or locks. In particular, it cannot use malloc(); use mmap() + * instead. It cannot use fopen(); use open() instead. Etc. All global + * variables that are accessed by the handler should be marked 'volatile'. + */ +typedef int (*sigsegv_handler_t) (void* fault_address, int serious); + +/* + * Installs a global SIGSEGV handler. + * This should be called once only, and it ignores any previously installed + * SIGSEGV handler. + * Returns 0 on success, or -1 if the system doesn't support catching SIGSEGV. + */ +extern int sigsegv_install_handler (sigsegv_handler_t handler); + +/* + * Deinstalls the global SIGSEGV handler. + * This goes back to the state where no SIGSEGV handler is installed. + */ +extern void sigsegv_deinstall_handler (void); + +#if LIBSIGSEGV_VERSION >= 0x0206 +/* + * Prepares leaving a SIGSEGV handler (through longjmp or similar means). + * Control is transferred by calling CONTINUATION with CONT_ARG1, CONT_ARG2, + * CONT_ARG3 as arguments. + * CONTINUATION must not return. + * The sigsegv_leave_handler function may return if called from a SIGSEGV + * handler; its return value should be used as the handler's return value. + * The sigsegv_leave_handler function does not return if called from a + * stack overflow handler. + */ +extern int sigsegv_leave_handler (void (*continuation) (void*, void*, void*), void* cont_arg1, void* cont_arg2, void* cont_arg3); +#else /* older versions of libsigsegv */ +/* + * Prepares leaving a SIGSEGV handler (through longjmp or similar means). + * Limitation: This function could only be called once on MacOS X. + */ +extern void sigsegv_leave_handler (void); +#endif + +/* + * The type of a context passed to a stack overflow handler. + * This type is system dependent; on some platforms it is an 'ucontext_t *', + * on some platforms it is a 'struct sigcontext *', on others merely an + * opaque 'void *'. + */ +typedef @FAULT_CONTEXT@ *stackoverflow_context_t; + +/* + * The type of a stack overflow handler. + * Such a handler should perform a longjmp call in order to reduce the amount + * of stack needed. It must not return. + * The emergency argument is 0 when the stack could be repared, or 1 if the + * application should better save its state and exit now. + * + * The handler is run at a moment when nothing about the global state of the + * program is known. Therefore it cannot use facilities that manipulate global + * variables or locks. In particular, it cannot use malloc(); use mmap() + * instead. It cannot use fopen(); use open() instead. Etc. All global + * variables that are accessed by the handler should be marked 'volatile'. + */ +typedef void (*stackoverflow_handler_t) (int emergency, stackoverflow_context_t scp); + +/* + * Installs a stack overflow handler. + * The extra_stack argument is a pointer to a pre-allocated area used as a + * stack for executing the handler. It is typically allocated by use of + * `alloca' during `main'. Its size should be sufficiently large. + * The following code determines an appropriate size: + * #include <signal.h> + * #ifndef SIGSTKSZ / * glibc defines SIGSTKSZ for this purpose * / + * # define SIGSTKSZ 16384 / * on most platforms, 16 KB are sufficient * / + * #endif + * Returns 0 on success, or -1 if the system doesn't support catching stack + * overflow. + */ +extern int stackoverflow_install_handler (stackoverflow_handler_t handler, + void* extra_stack, unsigned long extra_stack_size); + +/* + * Deinstalls the stack overflow handler. + */ +extern void stackoverflow_deinstall_handler (void); + +/* -------------------------------------------------------------------------- */ + +/* + * The following structure and functions permit to define different SIGSEGV + * policies on different address ranges. + */ + +/* + * The type of a local SIGSEGV handler. + * The fault address is passed as argument. + * The second argument is fixed arbitrary user data. + * The return value should be nonzero if the handler has done its job + * and no other handler should be called, or 0 if the handler declines + * responsibility for the given address. + */ +typedef int (*sigsegv_area_handler_t) (void* fault_address, void* user_arg); + +/* + * This structure represents a table of memory areas (address range intervals), + * with an local SIGSEGV handler for each. + */ +typedef +struct sigsegv_dispatcher { + void* tree; +} +sigsegv_dispatcher; + +/* + * Initializes a sigsegv_dispatcher structure. + */ +extern void sigsegv_init (sigsegv_dispatcher* dispatcher); + +/* + * Adds a local SIGSEGV handler to a sigsegv_dispatcher structure. + * It will cover the interval [address..address+len-1]. + * Returns a "ticket" that can be used to remove the handler later. + */ +extern void* sigsegv_register (sigsegv_dispatcher* dispatcher, + void* address, unsigned long len, + sigsegv_area_handler_t handler, void* handler_arg); + +/* + * Removes a local SIGSEGV handler. + */ +extern void sigsegv_unregister (sigsegv_dispatcher* dispatcher, void* ticket); + +/* + * Call the local SIGSEGV handler responsible for the given fault address. + * Return the handler's return value. 0 means that no handler has been found, + * or that a handler was found but declined responsibility. + */ +extern int sigsegv_dispatch (sigsegv_dispatcher* dispatcher, void* fault_address); + +/* -------------------------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SIGSEGV_H */ diff --git a/libsigsegv/src/sigsegv.h.msvc b/libsigsegv/src/sigsegv.h.msvc new file mode 100644 index 00000000..a586b48a --- /dev/null +++ b/libsigsegv/src/sigsegv.h.msvc @@ -0,0 +1,201 @@ +/* Page fault handling library. + Copyright (C) 1998-1999, 2002, 2004-2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _SIGSEGV_H +#define _SIGSEGV_H + +#include <windows.h> + +/* HAVE_SIGSEGV_RECOVERY + is defined if the system supports catching SIGSEGV. */ +#if 1 +# define HAVE_SIGSEGV_RECOVERY 1 +#endif + +/* HAVE_STACK_OVERFLOW_RECOVERY + is defined if stack overflow can be caught. */ +#if 1 +# define HAVE_STACK_OVERFLOW_RECOVERY 1 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBSIGSEGV_VERSION 0x0206 /* version number: (major<<8) + minor */ +extern int libsigsegv_version; /* Likewise */ + +/* -------------------------------------------------------------------------- */ + +/* + * The type of a global SIGSEGV handler. + * The fault address is passed as argument. + * The access type (read access or write access) is not passed; your handler + * has to know itself how to distinguish these two cases. + * The second argument is 0, meaning it could also be a stack overflow, or 1, + * meaning the handler should seriously try to fix the fault. + * The return value should be nonzero if the handler has done its job + * and no other handler should be called, or 0 if the handler declines + * responsibility for the given address. + * + * The handler is run at a moment when nothing about the global state of the + * program is known. Therefore it cannot use facilities that manipulate global + * variables or locks. In particular, it cannot use malloc(); use mmap() + * instead. It cannot use fopen(); use open() instead. Etc. All global + * variables that are accessed by the handler should be marked 'volatile'. + */ +typedef int (*sigsegv_handler_t) (void* fault_address, int serious); + +/* + * Installs a global SIGSEGV handler. + * This should be called once only, and it ignores any previously installed + * SIGSEGV handler. + * Returns 0 on success, or -1 if the system doesn't support catching SIGSEGV. + */ +extern int sigsegv_install_handler (sigsegv_handler_t handler); + +/* + * Deinstalls the global SIGSEGV handler. + * This goes back to the state where no SIGSEGV handler is installed. + */ +extern void sigsegv_deinstall_handler (void); + +#if LIBSIGSEGV_VERSION >= 0x0206 +/* + * Prepares leaving a SIGSEGV handler (through longjmp or similar means). + * Control is transferred by calling CONTINUATION with CONT_ARG1, CONT_ARG2, + * CONT_ARG3 as arguments. + * CONTINUATION must not return. + * The sigsegv_leave_handler function may return if called from a SIGSEGV + * handler; its return value should be used as the handler's return value. + * The sigsegv_leave_handler function does not return if called from a + * stack overflow handler. + */ +extern int sigsegv_leave_handler (void (*continuation) (void*, void*, void*), void* cont_arg1, void* cont_arg2, void* cont_arg3); +#else /* older versions of libsigsegv */ +/* + * Prepares leaving a SIGSEGV handler (through longjmp or similar means). + * Limitation: This function could only be called once on MacOS X. + */ +extern void sigsegv_leave_handler (void); +#endif + +/* + * The type of a context passed to a stack overflow handler. + * This type is system dependent; on some platforms it is an 'ucontext_t *', + * on some platforms it is a 'struct sigcontext *', on others merely an + * opaque 'void *'. + */ +typedef CONTEXT *stackoverflow_context_t; + +/* + * The type of a stack overflow handler. + * Such a handler should perform a longjmp call in order to reduce the amount + * of stack needed. It must not return. + * The emergency argument is 0 when the stack could be repared, or 1 if the + * application should better save its state and exit now. + * + * The handler is run at a moment when nothing about the global state of the + * program is known. Therefore it cannot use facilities that manipulate global + * variables or locks. In particular, it cannot use malloc(); use mmap() + * instead. It cannot use fopen(); use open() instead. Etc. All global + * variables that are accessed by the handler should be marked 'volatile'. + */ +typedef void (*stackoverflow_handler_t) (int emergency, stackoverflow_context_t scp); + +/* + * Installs a stack overflow handler. + * The extra_stack argument is a pointer to a pre-allocated area used as a + * stack for executing the handler. It is typically allocated by use of + * `alloca' during `main'. Its size should be sufficiently large. + * The following code determines an appropriate size: + * #include <signal.h> + * #ifndef SIGSTKSZ / * glibc defines SIGSTKSZ for this purpose * / + * # define SIGSTKSZ 16384 / * on most platforms, 16 KB are sufficient * / + * #endif + * Returns 0 on success, or -1 if the system doesn't support catching stack + * overflow. + */ +extern int stackoverflow_install_handler (stackoverflow_handler_t handler, + void* extra_stack, unsigned long extra_stack_size); + +/* + * Deinstalls the stack overflow handler. + */ +extern void stackoverflow_deinstall_handler (void); + +/* -------------------------------------------------------------------------- */ + +/* + * The following structure and functions permit to define different SIGSEGV + * policies on different address ranges. + */ + +/* + * The type of a local SIGSEGV handler. + * The fault address is passed as argument. + * The second argument is fixed arbitrary user data. + * The return value should be nonzero if the handler has done its job + * and no other handler should be called, or 0 if the handler declines + * responsibility for the given address. + */ +typedef int (*sigsegv_area_handler_t) (void* fault_address, void* user_arg); + +/* + * This structure represents a table of memory areas (address range intervals), + * with an local SIGSEGV handler for each. + */ +typedef +struct sigsegv_dispatcher { + void* tree; +} +sigsegv_dispatcher; + +/* + * Initializes a sigsegv_dispatcher structure. + */ +extern void sigsegv_init (sigsegv_dispatcher* dispatcher); + +/* + * Adds a local SIGSEGV handler to a sigsegv_dispatcher structure. + * It will cover the interval [address..address+len-1]. + * Returns a "ticket" that can be used to remove the handler later. + */ +extern void* sigsegv_register (sigsegv_dispatcher* dispatcher, + void* address, unsigned long len, + sigsegv_area_handler_t handler, void* handler_arg); + +/* + * Removes a local SIGSEGV handler. + */ +extern void sigsegv_unregister (sigsegv_dispatcher* dispatcher, void* ticket); + +/* + * Call the local SIGSEGV handler responsible for the given fault address. + * Return the handler's return value. 0 means that no handler has been found, + * or that a handler was found but declined responsibility. + */ +extern int sigsegv_dispatch (sigsegv_dispatcher* dispatcher, void* fault_address); + +/* -------------------------------------------------------------------------- */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SIGSEGV_H */ diff --git a/libsigsegv/src/stackvma-beos.c b/libsigsegv/src/stackvma-beos.c new file mode 100644 index 00000000..3bcebac2 --- /dev/null +++ b/libsigsegv/src/stackvma-beos.c @@ -0,0 +1,62 @@ +/* Determine the virtual memory area of a given address. BeOS version. + Copyright (C) 2002, 2006 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "stackvma.h" +#include <OS.h> + +#include "stackvma-simple.c" + +int +sigsegv_get_vma (unsigned long address, struct vma_struct *vma) +{ + area_info info; + int32 cookie; + unsigned long start, end; +#if STACK_DIRECTION < 0 + unsigned long prev; +#endif + +#if STACK_DIRECTION < 0 + prev = 0; +#endif + cookie = 0; + while (get_next_area_info (0, &cookie, &info) == B_OK) + { + start = (unsigned long) info.address; + end = start + info.size; + if (address >= start && address <= end - 1) + { + vma->start = start; + vma->end = end; +#if STACK_DIRECTION < 0 + vma->prev_end = prev; +#else + if (get_next_area_info (0, &cookie, &info) == B_OK) + vma->next_start = (unsigned long) info.address; + else + vma->next_start = 0; +#endif + vma->is_near_this = simple_is_near_this; + return 0; + } +#if STACK_DIRECTION < 0 + prev = end; +#endif + } + + return -1; +} diff --git a/libsigsegv/src/stackvma-freebsd.c b/libsigsegv/src/stackvma-freebsd.c new file mode 100644 index 00000000..fd04ba85 --- /dev/null +++ b/libsigsegv/src/stackvma-freebsd.c @@ -0,0 +1,118 @@ +/* Determine the virtual memory area of a given address. FreeBSD version. + Copyright (C) 2002-2003, 2006, 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "stackvma.h" +#include <stdio.h> + +#include "stackvma-simple.c" +#include "stackvma-rofile.c" + +#if HAVE_MINCORE +# define sigsegv_get_vma mincore_get_vma +# define STATIC static +# include "stackvma-mincore.c" +# undef sigsegv_get_vma +#endif + +int +sigsegv_get_vma (unsigned long address, struct vma_struct *vma) +{ + struct rofile rof; + int c; + /* The stack appears as multiple adjacents segments, therefore we + merge adjacent segments. */ + unsigned long next_start, next_end, curr_start, curr_end; +#if STACK_DIRECTION < 0 + unsigned long prev_end; +#endif + + /* Open the current process' maps file. It describes one VMA per line. */ + if (rof_open (&rof, "/proc/curproc/map") < 0) + goto failed; + +#if STACK_DIRECTION < 0 + prev_end = 0; +#endif + for (curr_start = curr_end = 0; ;) + { + if (!(rof_getchar (&rof) == '0' + && rof_getchar (&rof) == 'x' + && rof_scanf_lx (&rof, &next_start) >= 0)) + break; + while (c = rof_peekchar (&rof), c == ' ' || c == '\t') + rof_getchar (&rof); + if (!(rof_getchar (&rof) == '0' + && rof_getchar (&rof) == 'x' + && rof_scanf_lx (&rof, &next_end) >= 0)) + break; + while (c = rof_getchar (&rof), c != -1 && c != '\n') + continue; + if (next_start == curr_end) + { + /* Merge adjacent segments. */ + curr_end = next_end; + } + else + { + if (curr_start < curr_end + && address >= curr_start && address <= curr_end-1) + goto found; +#if STACK_DIRECTION < 0 + prev_end = curr_end; +#endif + curr_start = next_start; curr_end = next_end; + } + } + if (address >= curr_start && address <= curr_end-1) + found: + { + vma->start = curr_start; + vma->end = curr_end; +#if STACK_DIRECTION < 0 + vma->prev_end = prev_end; +#else + if (rof_getchar (&rof) == '0' + && rof_getchar (&rof) == 'x' + && rof_scanf_lx (&rof, &vma->next_start) >= 0) + { + while (c = rof_peekchar (&rof), c == ' ' || c == '\t') + rof_getchar (&rof); + if (rof_getchar (&rof) == '0' + && rof_getchar (&rof) == 'x' + && rof_scanf_lx (&rof, &next_end) >= 0) + ; + else + vma->next_start = 0; + } + else + vma->next_start = 0; +#endif + rof_close (&rof); + vma->is_near_this = simple_is_near_this; + return 0; + } + rof_close (&rof); + failed: +#if HAVE_MINCORE + /* FreeBSD 6.[01] doesn't allow to distinguish unmapped pages from + mapped but swapped-out pages. See whether it's fixed. */ + if (!is_mapped (0)) + /* OK, mincore() appears to work as expected. */ + return mincore_get_vma (address, vma); +#endif + return -1; +} diff --git a/libsigsegv/src/stackvma-linux.c b/libsigsegv/src/stackvma-linux.c new file mode 100644 index 00000000..33842287 --- /dev/null +++ b/libsigsegv/src/stackvma-linux.c @@ -0,0 +1,83 @@ +/* Determine the virtual memory area of a given address. Linux version. + Copyright (C) 2002, 2006, 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "stackvma.h" +#include <stdio.h> + +#include "stackvma-simple.c" +#include "stackvma-rofile.c" + +#if HAVE_MINCORE +# define sigsegv_get_vma mincore_get_vma +# define STATIC static +# include "stackvma-mincore.c" +# undef sigsegv_get_vma +#endif + +int +sigsegv_get_vma (unsigned long address, struct vma_struct *vma) +{ + struct rofile rof; + int c; + unsigned long start, end; +#if STACK_DIRECTION < 0 + unsigned long prev; +#endif + + /* Open the current process' maps file. It describes one VMA per line. */ + if (rof_open (&rof, "/proc/self/maps") < 0) + goto failed; + +#if STACK_DIRECTION < 0 + prev = 0; +#endif + for (;;) + { + if (!(rof_scanf_lx (&rof, &start) >= 0 + && rof_getchar (&rof) == '-' + && rof_scanf_lx (&rof, &end) >= 0)) + break; + while (c = rof_getchar (&rof), c != -1 && c != '\n') + continue; + if (address >= start && address <= end - 1) + { + vma->start = start; + vma->end = end; +#if STACK_DIRECTION < 0 + vma->prev_end = prev; +#else + if (!(rof_scanf_lx (&rof, &vma->next_start) >= 0 + && rof_getchar (&rof) == '-' + && rof_scanf_lx (&rof, &end) >= 0)) + vma->next_start = 0; +#endif + rof_close (&rof); + vma->is_near_this = simple_is_near_this; + return 0; + } +#if STACK_DIRECTION < 0 + prev = end; +#endif + } + rof_close (&rof); + failed: +#if HAVE_MINCORE + return mincore_get_vma (address, vma); +#else + return -1; +#endif +} diff --git a/libsigsegv/src/stackvma-mach.c b/libsigsegv/src/stackvma-mach.c new file mode 100644 index 00000000..ae309a60 --- /dev/null +++ b/libsigsegv/src/stackvma-mach.c @@ -0,0 +1,119 @@ +/* Determine the virtual memory area of a given address. Mach version. + Copyright (C) 2003, 2006 Paolo Bonzini <bonzini@gnu.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "stackvma.h" +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <libc.h> +#include <nlist.h> +#include <mach/mach.h> +#ifndef NeXT +#include <mach/machine/vm_param.h> +#endif + +#include "stackvma-simple.c" + +int +sigsegv_get_vma (unsigned long req_address, struct vma_struct *vma) +{ + unsigned long prev_address = 0, prev_size = 0; + unsigned long join_address = 0, join_size = 0; + int more = 1; + vm_address_t address; + vm_size_t size; + mach_port_t object_name; +#ifdef VM_REGION_BASIC_INFO + task_t task = mach_task_self (); + struct vm_region_basic_info info; + mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; +#else + task_t task = task_self (); + vm_prot_t protection, max_protection; + vm_inherit_t inheritance; + boolean_t shared; + vm_offset_t offset; +#endif + + for (address = VM_MIN_ADDRESS; more; address += size) + { +#ifdef VM_REGION_BASIC_INFO + more = (vm_region (task, &address, &size, VM_REGION_BASIC_INFO, + (vm_region_info_t)&info, &info_count, &object_name) + == KERN_SUCCESS); +#else + more = (vm_region (task, &address, &size, &protection, &max_protection, + &inheritance, &shared, &object_name, &offset) + == KERN_SUCCESS); +#endif + if (!more) + { + address = join_address + join_size; + size = 0; + } + + if ((unsigned long) address == join_address + join_size) + join_size += size; + else + { + prev_address = join_address; + prev_size = join_size; + join_address = (unsigned long) address; + join_size = size; + } + +#ifdef VM_REGION_BASIC_INFO + if (object_name != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), object_name); + info_count = VM_REGION_BASIC_INFO_COUNT; +#endif + +#if STACK_DIRECTION < 0 + if (join_address <= req_address && join_address + join_size > req_address) + { + vma->start = join_address; + vma->end = join_address + join_size; + vma->prev_end = prev_address + prev_size; + vma->is_near_this = simple_is_near_this; + return 0; + } +#else + if (prev_address <= req_address && prev_address + prev_size > req_address) + { + vma->start = prev_address; + vma->end = prev_address + prev_size; + vma->next_start = join_address; + vma->is_near_this = simple_is_near_this; + return 0; + } +#endif + } + +#if STACK_DIRECTION > 0 + if (join_address <= req_address && join_address + size > req_address) + { + vma->start = prev_address; + vma->end = prev_address + prev_size; + vma->next_start = ~0UL; + vma->is_near_this = simple_is_near_this; + return 0; + } +#endif + + return -1; +} diff --git a/libsigsegv/src/stackvma-mincore.c b/libsigsegv/src/stackvma-mincore.c new file mode 100644 index 00000000..1b51ef23 --- /dev/null +++ b/libsigsegv/src/stackvma-mincore.c @@ -0,0 +1,275 @@ +/* Determine the virtual memory area of a given address. + Copyright (C) 2006, 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* mincore() is a system call that allows to inquire the status of a + range of pages of virtual memory. In particular, it allows to inquire + whether a page is mapped at all. + As of 2006, mincore() is supported by: possible bits: + - Linux, since Linux 2.4 and glibc 2.2, 1 + - Solaris, since Solaris 9, 1 + - MacOS X, since MacOS X 10.3 (at least), 1 + - FreeBSD, since FreeBSD 6.0, MINCORE_{INCORE,REFERENCED,MODIFIED} + - NetBSD, since NetBSD 3.0 (at least), 1 + - OpenBSD, since OpenBSD 2.6 (at least), 1 + However, while the API allows to easily determine the bounds of mapped + virtual memory, it does not make it easy the bounds of _unmapped_ virtual + memory ranges. We try to work around this, but it may still be slow. */ + +#include "stackvma.h" +#include <limits.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <sys/types.h> +#include <sys/mman.h> + +/* Cache for getpagesize(). */ +static unsigned long pagesize; + +/* Initialize pagesize. */ +static void +init_pagesize (void) +{ +#if HAVE_GETPAGESIZE + pagesize = getpagesize (); +#elif HAVE_SYSCONF_PAGESIZE + pagesize = sysconf (_SC_PAGESIZE); +#else + pagesize = PAGESIZE; +#endif +} + +/* Test whether the page starting at ADDR is among the address range. + ADDR must be a multiple of pagesize. */ +static int +is_mapped (unsigned long addr) +{ + char vec[1]; + return mincore ((void *) addr, pagesize, vec) >= 0; +} + +/* Assuming that the page starting at ADDR is among the address range, + return the start of its virtual memory range. + ADDR must be a multiple of pagesize. */ +static unsigned long +mapped_range_start (unsigned long addr) +{ + /* Use a moderately sized VEC here, small enough that it fits on the stack + (without requiring malloc). */ + char vec[2048]; + unsigned long stepsize = sizeof (vec); + + for (;;) + { + unsigned long max_remaining; + + if (addr == 0) + return addr; + + max_remaining = addr / pagesize; + if (stepsize > max_remaining) + stepsize = max_remaining; + if (mincore ((void *) (addr - stepsize * pagesize), + stepsize * pagesize, vec) < 0) + /* Time to search in smaller steps. */ + break; + /* The entire range exists. Continue searching in large steps. */ + addr -= stepsize * pagesize; + } + for (;;) + { + unsigned long halfstepsize1; + unsigned long halfstepsize2; + + if (stepsize == 1) + return addr; + + /* Here we know that less than stepsize pages exist starting at addr. */ + halfstepsize1 = (stepsize + 1) / 2; + halfstepsize2 = stepsize / 2; + /* halfstepsize1 + halfstepsize2 = stepsize. */ + + if (mincore ((void *) (addr - halfstepsize1 * pagesize), + halfstepsize1 * pagesize, vec) < 0) + stepsize = halfstepsize1; + else + { + addr -= halfstepsize1 * pagesize; + stepsize = halfstepsize2; + } + } +} + +/* Assuming that the page starting at ADDR is among the address range, + return the end of its virtual memory range + 1. + ADDR must be a multiple of pagesize. */ +static unsigned long +mapped_range_end (unsigned long addr) +{ + /* Use a moderately sized VEC here, small enough that it fits on the stack + (without requiring malloc). */ + char vec[2048]; + unsigned long stepsize = sizeof (vec); + + addr += pagesize; + for (;;) + { + unsigned long max_remaining; + + if (addr == 0) /* wrapped around? */ + return addr; + + max_remaining = (- addr) / pagesize; + if (stepsize > max_remaining) + stepsize = max_remaining; + if (mincore ((void *) addr, stepsize * pagesize, vec) < 0) + /* Time to search in smaller steps. */ + break; + /* The entire range exists. Continue searching in large steps. */ + addr += stepsize * pagesize; + } + for (;;) + { + unsigned long halfstepsize1; + unsigned long halfstepsize2; + + if (stepsize == 1) + return addr; + + /* Here we know that less than stepsize pages exist starting at addr. */ + halfstepsize1 = (stepsize + 1) / 2; + halfstepsize2 = stepsize / 2; + /* halfstepsize1 + halfstepsize2 = stepsize. */ + + if (mincore ((void *) addr, halfstepsize1 * pagesize, vec) < 0) + stepsize = halfstepsize1; + else + { + addr += halfstepsize1 * pagesize; + stepsize = halfstepsize2; + } + } +} + +/* Determine whether an address range [ADDR1..ADDR2] is completely unmapped. + ADDR1 must be <= ADDR2. */ +static int +is_unmapped (unsigned long addr1, unsigned long addr2) +{ + unsigned long count; + unsigned long stepsize; + + /* Round addr1 down. */ + addr1 = (addr1 / pagesize) * pagesize; + /* Round addr2 up and turn it into an exclusive bound. */ + addr2 = ((addr2 / pagesize) + 1) * pagesize; + + /* This is slow: mincore() does not provide a way to determine the bounds + of the gaps directly. So we have to use mincore() on individual pages + over and over again. Only after we've verified that all pages are + unmapped, we know that the range is completely unmapped. + If we were to traverse the pages from bottom to top or from top to bottom, + it would be slow even in the average case. To speed up the search, we + exploit the fact that mapped memory ranges are larger than one page on + average, therefore we have good chances of hitting a mapped area if we + traverse only every second, or only fourth page, etc. This doesn't + decrease the worst-case runtime, only the average runtime. */ + count = (addr2 - addr1) / pagesize; + /* We have to test is_mapped (addr1 + i * pagesize) for 0 <= i < count. */ + for (stepsize = 1; stepsize < count; ) + stepsize = 2 * stepsize; + for (;;) + { + unsigned long addr_stepsize; + unsigned long i; + unsigned long addr; + + stepsize = stepsize / 2; + if (stepsize == 0) + break; + addr_stepsize = stepsize * pagesize; + for (i = stepsize, addr = addr1 + addr_stepsize; + i < count; + i += 2 * stepsize, addr += 2 * addr_stepsize) + /* Here addr = addr1 + i * pagesize. */ + if (is_mapped (addr)) + return 0; + } + return 1; +} + +#if STACK_DIRECTION < 0 + +/* Info about the gap between this VMA and the previous one. + addr must be < vma->start. */ +static int +mincore_is_near_this (unsigned long addr, struct vma_struct *vma) +{ + /* vma->start - addr <= (vma->start - vma->prev_end) / 2 + is mathematically equivalent to + vma->prev_end <= 2 * addr - vma->start + <==> is_unmapped (2 * addr - vma->start, vma->start - 1). + But be careful about overflow: if 2 * addr - vma->start is negative, + we consider a tiny "guard page" mapping [0, 0] to be present around + NULL; it intersects the range (2 * addr - vma->start, vma->start - 1), + therefore return false. */ + unsigned long testaddr = addr - (vma->start - addr); + if (testaddr > addr) /* overflow? */ + return 0; + /* Here testaddr <= addr < vma->start. */ + return is_unmapped (testaddr, vma->start - 1); +} + +#endif +#if STACK_DIRECTION > 0 + +/* Info about the gap between this VMA and the next one. + addr must be > vma->end - 1. */ +static int +mincore_is_near_this (unsigned long addr, struct vma_struct *vma) +{ + /* addr - vma->end < (vma->next_start - vma->end) / 2 + is mathematically equivalent to + vma->next_start > 2 * addr - vma->end + <==> is_unmapped (vma->end, 2 * addr - vma->end). + But be careful about overflow: if 2 * addr - vma->end is > ~0UL, + we consider a tiny "guard page" mapping [0, 0] to be present around + NULL; it intersects the range (vma->end, 2 * addr - vma->end), + therefore return false. */ + unsigned long testaddr = addr + (addr - vma->end); + if (testaddr < addr) /* overflow? */ + return 0; + /* Here vma->end - 1 < addr <= testaddr. */ + return is_unmapped (vma->end, testaddr); +} + +#endif + +#ifdef STATIC +STATIC +#endif +int +sigsegv_get_vma (unsigned long address, struct vma_struct *vma) +{ + if (pagesize == 0) + init_pagesize (); + address = (address / pagesize) * pagesize; + vma->start = mapped_range_start (address); + vma->end = mapped_range_end (address); + vma->is_near_this = mincore_is_near_this; + return 0; +} diff --git a/libsigsegv/src/stackvma-none.c b/libsigsegv/src/stackvma-none.c new file mode 100644 index 00000000..3ffeb8e3 --- /dev/null +++ b/libsigsegv/src/stackvma-none.c @@ -0,0 +1,25 @@ +/* Determine the virtual memory area of a given address. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "stackvma.h" + +int +sigsegv_get_vma (unsigned long address, struct vma_struct *vma) +{ + /* No way. */ + return -1; +} diff --git a/libsigsegv/src/stackvma-procfs.c b/libsigsegv/src/stackvma-procfs.c new file mode 100644 index 00000000..24c90a1a --- /dev/null +++ b/libsigsegv/src/stackvma-procfs.c @@ -0,0 +1,188 @@ +/* Determine the virtual memory area of a given address. + Copyright (C) 2002, 2006, 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "stackvma.h" +#include <unistd.h> /* open, close */ +#include <fcntl.h> /* open */ +#include <sys/types.h> +#include <sys/mman.h> /* mmap, munmap */ +#include <sys/procfs.h> /* PIOC*, prmap_t */ + +#include "stackvma-simple.c" + +#if HAVE_MINCORE +# define sigsegv_get_vma mincore_get_vma +# define STATIC static +# include "stackvma-mincore.c" +# undef sigsegv_get_vma +#else +/* Cache for getpagesize(). */ +static unsigned long pagesize; +/* Initialize pagesize. */ +static void +init_pagesize (void) +{ + pagesize = getpagesize (); +} +#endif + +int +sigsegv_get_vma (unsigned long address, struct vma_struct *vma) +{ + char fnamebuf[6+10+1]; + char *fname; + int fd; + int nmaps; + size_t memneed; +#if HAVE_MMAP_ANON +# define zero_fd -1 +# define map_flags MAP_ANON +#elif HAVE_MMAP_ANONYMOUS +# define zero_fd -1 +# define map_flags MAP_ANONYMOUS +#else + int zero_fd; +# define map_flags 0 +#endif + void *auxmap; + unsigned long auxmap_start; + unsigned long auxmap_end; + prmap_t* maps; + prmap_t* mp; + unsigned long start, end; +#if STACK_DIRECTION < 0 + unsigned long prev; +#endif + + if (pagesize == 0) + init_pagesize (); + + /* Construct fname = sprintf (fnamebuf+i, "/proc/%u", getpid ()). */ + fname = fnamebuf + sizeof (fnamebuf) - 1; + *fname = '\0'; + { + unsigned int value = getpid (); + do + *--fname = (value % 10) + '0'; + while ((value = value / 10) > 0); + } + fname -= 6; + memcpy (fname, "/proc/", 6); + + fd = open (fname, O_RDONLY); + if (fd < 0) + goto failed; + + if (ioctl (fd, PIOCNMAP, &nmaps) < 0) + goto fail2; + + memneed = (nmaps + 10) * sizeof (prmap_t); + /* Allocate memneed bytes of memory. + We cannot use alloca here, because we are low on stack space. + We also cannot use malloc here, because a malloc() call may have been + interrupted. + So use mmap(), and ignore the resulting VMA. */ + memneed = ((memneed - 1) / pagesize + 1) * pagesize; +#if !(HAVE_MMAP_ANON || HAVE_MMAP_ANONYMOUS) + zero_fd = open ("/dev/zero", O_RDONLY, 0644); + if (zero_fd < 0) + goto fail2; +#endif + auxmap = (void *) mmap ((void *) 0, memneed, PROT_READ | PROT_WRITE, map_flags | MAP_PRIVATE, zero_fd, 0); +#if !(HAVE_MMAP_ANON || HAVE_MMAP_ANONYMOUS) + close (zero_fd); +#endif + if (auxmap == (void *) -1) + goto fail2; + auxmap_start = (unsigned long) auxmap; + auxmap_end = auxmap_start + memneed; + maps = (prmap_t *) auxmap; + + if (ioctl (fd, PIOCMAP, maps) < 0) + goto fail1; + +#if STACK_DIRECTION < 0 + prev = 0; +#endif + for (mp = maps;;) + { + start = (unsigned long) mp->pr_vaddr; + end = start + mp->pr_size; + if (start == 0 && end == 0) + break; + mp++; + if (start <= auxmap_start && auxmap_end - 1 <= end - 1) + { + /* Consider [start,end-1] \ [auxmap_start,auxmap_end-1] + = [start,auxmap_start-1] u [auxmap_end,end-1]. */ + if (start != auxmap_start) + { + if (address >= start && address <= auxmap_start - 1) + { + end = auxmap_start; + goto found; + } +#if STACK_DIRECTION < 0 + prev = auxmap_start; +#endif + } + if (end != auxmap_end) + { + if (address >= auxmap_end && address <= end - 1) + { + start = auxmap_end; + goto found; + } +#if STACK_DIRECTION < 0 + prev = end; +#endif + } + } + else + { + if (address >= start && address <= end - 1) + goto found; +#if STACK_DIRECTION < 0 + prev = end; +#endif + } + } + + fail1: + munmap (auxmap, memneed); + fail2: + close (fd); + failed: +#if HAVE_MINCORE + return mincore_get_vma (address, vma); +#else + return -1; +#endif + + found: + vma->start = start; + vma->end = end; +#if STACK_DIRECTION < 0 + vma->prev_end = prev; +#else + vma->next_start = (unsigned long) mp->pr_vaddr; +#endif + munmap (auxmap, memneed); + close (fd); + vma->is_near_this = simple_is_near_this; + return 0; +} diff --git a/libsigsegv/src/stackvma-rofile.c b/libsigsegv/src/stackvma-rofile.c new file mode 100644 index 00000000..d6d19394 --- /dev/null +++ b/libsigsegv/src/stackvma-rofile.c @@ -0,0 +1,121 @@ +/* Buffered read-only streams. + Copyright (C) 2008 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <errno.h> /* errno, EINTR */ +#include <fcntl.h> /* O_RDONLY */ +#include <stddef.h> /* size_t */ +#include <unistd.h> /* read, close */ + +/* Buffered read-only streams. + We cannot use <stdio.h> here, because fopen() calls malloc(), and a malloc() + call may have been interrupted. */ + +struct rofile + { + int fd; + size_t position; + size_t filled; + int eof_seen; + char buffer[4096]; + }; + +/* Open a read-only file stream. */ +static int +rof_open (struct rofile *rof, const char *filename) +{ + int fd = open (filename, O_RDONLY); + if (fd < 0) + return -1; + rof->fd = fd; + rof->position = 0; + rof->filled = 0; + rof->eof_seen = 0; + return 0; +} + +/* Return the next byte from a read-only file stream without consuming it, + or -1 at EOF. */ +static int +rof_peekchar (struct rofile *rof) +{ + if (rof->position == rof->filled) + { + if (rof->eof_seen) + return -1; + else + for (;;) + { + int n = read (rof->fd, rof->buffer, sizeof (rof->buffer)); +#ifdef EINTR + if (n < 0 && errno == EINTR) + continue; +#endif + if (n <= 0) + { + rof->eof_seen = 1; + return -1; + } + rof->filled = n; + rof->position = 0; + break; + } + } + return (unsigned char) rof->buffer[rof->position]; +} + +/* Return the next byte from a read-only file stream, or -1 at EOF. */ +static int +rof_getchar (struct rofile *rof) +{ + int c = rof_peekchar (rof); + if (c >= 0) + rof->position++; + return c; +} + +/* Parse an unsigned hexadecimal number from a read-only file stream. */ +static int +rof_scanf_lx (struct rofile *rof, unsigned long *valuep) +{ + unsigned long value = 0; + unsigned int numdigits = 0; + for (;;) + { + int c = rof_peekchar (rof); + if (c >= '0' && c <= '9') + value = (value << 4) + (c - '0'); + else if (c >= 'A' && c <= 'F') + value = (value << 4) + (c - 'A' + 10); + else if (c >= 'a' && c <= 'f') + value = (value << 4) + (c - 'a' + 10); + else + break; + rof_getchar (rof); + numdigits++; + } + if (numdigits == 0) + return -1; + *valuep = value; + return 0; +} + +/* Close a read-only file stream. */ +static void +rof_close (struct rofile *rof) +{ + close (rof->fd); +} diff --git a/libsigsegv/src/stackvma-simple.c b/libsigsegv/src/stackvma-simple.c new file mode 100644 index 00000000..3e800373 --- /dev/null +++ b/libsigsegv/src/stackvma-simple.c @@ -0,0 +1,42 @@ +/* Determine the virtual memory area of a given address. + Copyright (C) 2006 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This file contains the proximity test function for the simple cases, where + the OS has an API for enumerating the mapped ranges of virtual memory. */ + +#if STACK_DIRECTION < 0 + +/* Info about the gap between this VMA and the previous one. + addr must be < vma->start. */ +static int +simple_is_near_this (unsigned long addr, struct vma_struct *vma) +{ + return (vma->start - addr <= (vma->start - vma->prev_end) / 2); +} + +#endif +#if STACK_DIRECTION > 0 + +/* Info about the gap between this VMA and the next one. + addr must be > vma->end - 1. */ +static int +simple_is_near_this (unsigned long addr, struct vma_struct *vma) +{ + return (addr - vma->end < (vma->next_start - vma->end) / 2); +} + +#endif diff --git a/libsigsegv/src/stackvma.c b/libsigsegv/src/stackvma.c new file mode 100644 index 00000000..17fd8e51 --- /dev/null +++ b/libsigsegv/src/stackvma.c @@ -0,0 +1,20 @@ +/* Determine the virtual memory area of a given address. + Copyright (C) 2002 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "config.h" + +#include CFG_STACKVMA diff --git a/libsigsegv/src/stackvma.h b/libsigsegv/src/stackvma.h new file mode 100644 index 00000000..cc475d51 --- /dev/null +++ b/libsigsegv/src/stackvma.h @@ -0,0 +1,48 @@ +/* Determine the virtual memory area of a given address. + Copyright (C) 2002, 2006 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _STACKVMA_H +#define _STACKVMA_H + +/* Describes a virtual memory area, with some info about the gap between + it and the next or previous virtual memory area. */ +struct vma_struct +{ + unsigned long start; + unsigned long end; +#if STACK_DIRECTION < 0 + /* Info about the gap between this VMA and the previous one. + addr must be < vma->start. */ + int (*is_near_this) (unsigned long addr, struct vma_struct *vma); + /* Private field, not provided by all sigsegv_get_vma implementations. */ + unsigned long prev_end; +#endif +#if STACK_DIRECTION > 0 + /* Info about the gap between this VMA and the next one. + addr must be > vma->end - 1. */ + int (*is_near_this) (unsigned long addr, struct vma_struct *vma); + /* Private field, not provided by all sigsegv_get_vma implementations. */ + unsigned long next_start; +#endif +}; + +/* Determines the virtual memory area to which a given address belongs, + and returns 0. Returns -1 if it cannot be determined. + This function is used to determine the stack extent when a fault occurs. */ +extern int sigsegv_get_vma (unsigned long address, struct vma_struct *vma); + +#endif /* _STACKVMA_H */ diff --git a/libsigsegv/src/version.c b/libsigsegv/src/version.c new file mode 100644 index 00000000..80bffce2 --- /dev/null +++ b/libsigsegv/src/version.c @@ -0,0 +1,20 @@ +/* Version number. + Copyright (C) 2005 Bruno Haible <bruno@clisp.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "sigsegv.h" + +int libsigsegv_version = LIBSIGSEGV_VERSION; |