diff options
Diffstat (limited to 'gprofng/libcollector')
38 files changed, 46214 insertions, 0 deletions
diff --git a/gprofng/libcollector/CHK_LIBC_OBJ b/gprofng/libcollector/CHK_LIBC_OBJ new file mode 100755 index 0000000..dbeb9cb --- /dev/null +++ b/gprofng/libcollector/CHK_LIBC_OBJ @@ -0,0 +1,82 @@ +#!/bin/sh +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file 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 3 of the License, 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; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# +# CHK_LIBC_OBJ -- a script to scan the .o's in an output directory, +# which is one of ../{intel-S2,sparc-S2,intel-Linux,sparc-Linux} +# +# usage: cd to the output directory, and invoke ../src/CHK_LIBC_OBJ + + +check_obj() { + logF="nm.`basename $1`.log" + if [ `uname` = 'Linux' ]; then + nm $1 | grep -v GLIBC_ > ${logF} + else + nm $1 > ${logF} + fi + + FUNC_LIST="strcpy strlcpy strncpy strcat strlcat strncat strncmp strlen \ + strerror strchr strrchr strpbrk strstr strtok strtok_r \ + printf fprintf sprintf snprintf asprintf wsprintf \ + vprintf vfprintf vsprintf vsnprintf vasprintf \ + memset memcmp memcpy strtol strtoll strtoul strtoull \ + getcpuid calloc malloc free strdup" + res=0 + echo " -- Checking Object file '$1' for functions from libc" + for j in `echo ${FUNC_LIST}` ; do + grep -w ${j} ${logF} | grep UNDEF> grep.log 2>&1 + if [ $? -eq 0 ]; then + grep -w ${j} ${logF} + res=1 + fi + done + return ${res} +} + +STATUS=0 + +for i in *.o ; do + echo "" + check_obj ${i} + res=$? + if [ ${res} -eq 0 ]; then + echo "Object file ${i} does not reference functions in libc" + else + echo "======Object file: ${i} DOES reference functions in libc" + fi + if [ ${STATUS} -eq 0 ]; then + STATUS=${res} + fi +done + +for i in *.so ; do + echo "" + check_obj ${i} + res=$? + if [ ${res} -eq 0 ]; then + echo "Object file ${i} does not reference functions in libc" + else + echo "======Object file: ${i} DOES reference functions in libc" + fi + if [ ${STATUS} -eq 0 ]; then + STATUS=${res} + fi +done + +exit $STATUS diff --git a/gprofng/libcollector/Makefile.am b/gprofng/libcollector/Makefile.am new file mode 100644 index 0000000..bd86e97 --- /dev/null +++ b/gprofng/libcollector/Makefile.am @@ -0,0 +1,79 @@ +## Process this file with automake to generate Makefile.in +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file 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 3 of the License, 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; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I . -I ../.. + +GPROFNG_VARIANT = @GPROFNG_VARIANT@ + +CSOURCES = \ + gethrtime.c \ + dispatcher.c \ + iolib.c \ + mmaptrace.c \ + memmgr.c \ + tsd.c \ + profile.c \ + envmgmt.c \ + linetrace.c \ + libcol_hwcdrv.c \ + libcol_hwcfuncs.c \ + libcol-i386-dis.c \ + hwprofile.c \ + jprofile.c \ + unwind.c \ + libcol_util.c \ + collector.c \ + $(NULL) + +AM_CFLAGS = $(GPROFNG_CFLAGS) -Wno-nonnull-compare +AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -I.. -I$(srcdir) \ + -I$(srcdir)/../common -I$(srcdir)/../src \ + -I$(srcdir)/../../include +AM_LDFLAGS = -module -avoid-version \ + -Wl,--version-script,$(srcdir)/mapfile.$(GPROFNG_VARIANT) \ + $(LD_NO_AS_NEEDED) -Wl,-lrt -Wl,-ldl + +myincludedir = @includedir@ +myinclude_HEADERS = $(srcdir)/../../include/collectorAPI.h \ + $(srcdir)/../../include/libcollector.h \ + $(srcdir)/../../include/libfcollector.h + +lib_LTLIBRARIES = libgp-collector.la libgp-collectorAPI.la libgp-heap.la \ + libgp-sync.la libgp-iotrace.la + +libgp_collector_la_SOURCES = $(CSOURCES) +libgp_collector_la_CPPFLAGS = $(AM_CPPFLAGS) $(jdk_inc) \ + -I../../bfd -I$(srcdir)/../.. +# Prevent libtool from reordering -Wl,--no-as-needed after -lrt by +# disguising -lrt as a linker flag. +libgp_collector_la_LDFLAGS = $(AM_LDFLAGS) +libgp_collector_la_LIBADD = + +libgp_heap_la_SOURCES = heaptrace.c +libgp_heap_la_LDFLAGS = $(AM_LDFLAGS) + +libgp_sync_la_SOURCES = synctrace.c +libgp_sync_la_LDFLAGS = $(AM_LDFLAGS) + +libgp_iotrace_la_SOURCES = iotrace.c +libgp_iotrace_la_LDFLAGS = $(AM_LDFLAGS) + +libgp_collectorAPI_la_SOURCES = collectorAPI.c +libgp_collectorAPI_la_LIBADD = -lc -ldl + diff --git a/gprofng/libcollector/Makefile.in b/gprofng/libcollector/Makefile.in new file mode 100644 index 0000000..920c7a7 --- /dev/null +++ b/gprofng/libcollector/Makefile.in @@ -0,0 +1,1131 @@ +# Makefile.in generated by automake 1.15.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2017 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@ + +# +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This file 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 3 of the License, 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; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../../config/depstand.m4 \ + $(top_srcdir)/../../config/lead-dot.m4 \ + $(top_srcdir)/../../config/override.m4 \ + $(top_srcdir)/../../libtool.m4 \ + $(top_srcdir)/../../ltoptions.m4 \ + $(top_srcdir)/../../ltsugar.m4 \ + $(top_srcdir)/../../ltversion.m4 \ + $(top_srcdir)/../../lt~obsolete.m4 \ + $(top_srcdir)/../../bfd/version.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(myinclude_HEADERS) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs +CONFIG_HEADER = lib-config.h +CONFIG_CLEAN_FILES = +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(myincludedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libgp_collector_la_DEPENDENCIES = +am__objects_1 = libgp_collector_la-gethrtime.lo \ + libgp_collector_la-dispatcher.lo libgp_collector_la-iolib.lo \ + libgp_collector_la-mmaptrace.lo libgp_collector_la-memmgr.lo \ + libgp_collector_la-tsd.lo libgp_collector_la-profile.lo \ + libgp_collector_la-envmgmt.lo libgp_collector_la-linetrace.lo \ + libgp_collector_la-libcol_hwcdrv.lo \ + libgp_collector_la-libcol_hwcfuncs.lo \ + libgp_collector_la-libcol-i386-dis.lo \ + libgp_collector_la-hwprofile.lo libgp_collector_la-jprofile.lo \ + libgp_collector_la-unwind.lo libgp_collector_la-libcol_util.lo \ + libgp_collector_la-collector.lo +am_libgp_collector_la_OBJECTS = $(am__objects_1) +libgp_collector_la_OBJECTS = $(am_libgp_collector_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libgp_collector_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgp_collector_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +libgp_collectorAPI_la_DEPENDENCIES = +am_libgp_collectorAPI_la_OBJECTS = collectorAPI.lo +libgp_collectorAPI_la_OBJECTS = $(am_libgp_collectorAPI_la_OBJECTS) +libgp_heap_la_LIBADD = +am_libgp_heap_la_OBJECTS = heaptrace.lo +libgp_heap_la_OBJECTS = $(am_libgp_heap_la_OBJECTS) +libgp_heap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgp_heap_la_LDFLAGS) $(LDFLAGS) -o $@ +libgp_iotrace_la_LIBADD = +am_libgp_iotrace_la_OBJECTS = iotrace.lo +libgp_iotrace_la_OBJECTS = $(am_libgp_iotrace_la_OBJECTS) +libgp_iotrace_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libgp_iotrace_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libgp_sync_la_LIBADD = +am_libgp_sync_la_OBJECTS = synctrace.lo +libgp_sync_la_OBJECTS = $(am_libgp_sync_la_OBJECTS) +libgp_sync_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgp_sync_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libgp_collector_la_SOURCES) \ + $(libgp_collectorAPI_la_SOURCES) $(libgp_heap_la_SOURCES) \ + $(libgp_iotrace_la_SOURCES) $(libgp_sync_la_SOURCES) +DIST_SOURCES = $(libgp_collector_la_SOURCES) \ + $(libgp_collectorAPI_la_SOURCES) $(libgp_heap_la_SOURCES) \ + $(libgp_iotrace_la_SOURCES) $(libgp_sync_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(myinclude_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +AM_RECURSIVE_TARGETS = cscope +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../../ar-lib \ + $(top_srcdir)/../../compile $(top_srcdir)/../../config.guess \ + $(top_srcdir)/../../config.sub $(top_srcdir)/../../depcomp \ + $(top_srcdir)/../../install-sh $(top_srcdir)/../../ltmain.sh \ + $(top_srcdir)/../../missing $(top_srcdir)/../../mkinstalldirs \ + $(top_srcdir)/../common/config.h.in ../../COPYING \ + ../../COPYING.LIB ../../ChangeLog ../../README ../../ar-lib \ + ../../compile ../../config.guess ../../config.rpath \ + ../../config.sub ../../depcomp ../../install-sh \ + ../../ltmain.sh ../../missing ../../mkinstalldirs ../../ylwrap +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +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@ +FGREP = @FGREP@ +GPROFNG_VARIANT = @GPROFNG_VARIANT@ +GREP = @GREP@ +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@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +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_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +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_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +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@ +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 = foreign +ACLOCAL_AMFLAGS = -I . -I ../.. +CSOURCES = \ + gethrtime.c \ + dispatcher.c \ + iolib.c \ + mmaptrace.c \ + memmgr.c \ + tsd.c \ + profile.c \ + envmgmt.c \ + linetrace.c \ + libcol_hwcdrv.c \ + libcol_hwcfuncs.c \ + libcol-i386-dis.c \ + hwprofile.c \ + jprofile.c \ + unwind.c \ + libcol_util.c \ + collector.c \ + $(NULL) + +AM_CFLAGS = $(GPROFNG_CFLAGS) -Wno-nonnull-compare +AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -I.. -I$(srcdir) \ + -I$(srcdir)/../common -I$(srcdir)/../src \ + -I$(srcdir)/../../include + +AM_LDFLAGS = -module -avoid-version \ + -Wl,--version-script,$(srcdir)/mapfile.$(GPROFNG_VARIANT) \ + $(LD_NO_AS_NEEDED) -Wl,-lrt -Wl,-ldl + +myincludedir = @includedir@ +myinclude_HEADERS = $(srcdir)/../../include/collectorAPI.h \ + $(srcdir)/../../include/libcollector.h \ + $(srcdir)/../../include/libfcollector.h + +lib_LTLIBRARIES = libgp-collector.la libgp-collectorAPI.la libgp-heap.la \ + libgp-sync.la libgp-iotrace.la + +libgp_collector_la_SOURCES = $(CSOURCES) +libgp_collector_la_CPPFLAGS = $(AM_CPPFLAGS) $(jdk_inc) \ + -I../../bfd -I$(srcdir)/../.. + +# Prevent libtool from reordering -Wl,--no-as-needed after -lrt by +# disguising -lrt as a linker flag. +libgp_collector_la_LDFLAGS = $(AM_LDFLAGS) +libgp_collector_la_LIBADD = +libgp_heap_la_SOURCES = heaptrace.c +libgp_heap_la_LDFLAGS = $(AM_LDFLAGS) +libgp_sync_la_SOURCES = synctrace.c +libgp_sync_la_LDFLAGS = $(AM_LDFLAGS) +libgp_iotrace_la_SOURCES = iotrace.c +libgp_iotrace_la_LDFLAGS = $(AM_LDFLAGS) +libgp_collectorAPI_la_SOURCES = collectorAPI.c +libgp_collectorAPI_la_LIBADD = -lc -ldl +all: lib-config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +lib-config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(top_srcdir)/../common/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status lib-config.h +$(top_srcdir)/../common/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f lib-config.h stamp-h1 + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @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 " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + 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)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libgp-collector.la: $(libgp_collector_la_OBJECTS) $(libgp_collector_la_DEPENDENCIES) $(EXTRA_libgp_collector_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgp_collector_la_LINK) -rpath $(libdir) $(libgp_collector_la_OBJECTS) $(libgp_collector_la_LIBADD) $(LIBS) + +libgp-collectorAPI.la: $(libgp_collectorAPI_la_OBJECTS) $(libgp_collectorAPI_la_DEPENDENCIES) $(EXTRA_libgp_collectorAPI_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libgp_collectorAPI_la_OBJECTS) $(libgp_collectorAPI_la_LIBADD) $(LIBS) + +libgp-heap.la: $(libgp_heap_la_OBJECTS) $(libgp_heap_la_DEPENDENCIES) $(EXTRA_libgp_heap_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgp_heap_la_LINK) -rpath $(libdir) $(libgp_heap_la_OBJECTS) $(libgp_heap_la_LIBADD) $(LIBS) + +libgp-iotrace.la: $(libgp_iotrace_la_OBJECTS) $(libgp_iotrace_la_DEPENDENCIES) $(EXTRA_libgp_iotrace_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgp_iotrace_la_LINK) -rpath $(libdir) $(libgp_iotrace_la_OBJECTS) $(libgp_iotrace_la_LIBADD) $(LIBS) + +libgp-sync.la: $(libgp_sync_la_OBJECTS) $(libgp_sync_la_DEPENDENCIES) $(EXTRA_libgp_sync_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgp_sync_la_LINK) -rpath $(libdir) $(libgp_sync_la_OBJECTS) $(libgp_sync_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/collectorAPI.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heaptrace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iotrace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-collector.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-dispatcher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-envmgmt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-gethrtime.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-hwprofile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-iolib.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-jprofile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol-i386-dis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol_util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-linetrace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-memmgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-mmaptrace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-profile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-tsd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-unwind.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/synctrace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libgp_collector_la-gethrtime.lo: gethrtime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-gethrtime.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-gethrtime.Tpo -c -o libgp_collector_la-gethrtime.lo `test -f 'gethrtime.c' || echo '$(srcdir)/'`gethrtime.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-gethrtime.Tpo $(DEPDIR)/libgp_collector_la-gethrtime.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gethrtime.c' object='libgp_collector_la-gethrtime.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-gethrtime.lo `test -f 'gethrtime.c' || echo '$(srcdir)/'`gethrtime.c + +libgp_collector_la-dispatcher.lo: dispatcher.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-dispatcher.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-dispatcher.Tpo -c -o libgp_collector_la-dispatcher.lo `test -f 'dispatcher.c' || echo '$(srcdir)/'`dispatcher.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-dispatcher.Tpo $(DEPDIR)/libgp_collector_la-dispatcher.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dispatcher.c' object='libgp_collector_la-dispatcher.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-dispatcher.lo `test -f 'dispatcher.c' || echo '$(srcdir)/'`dispatcher.c + +libgp_collector_la-iolib.lo: iolib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-iolib.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-iolib.Tpo -c -o libgp_collector_la-iolib.lo `test -f 'iolib.c' || echo '$(srcdir)/'`iolib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-iolib.Tpo $(DEPDIR)/libgp_collector_la-iolib.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iolib.c' object='libgp_collector_la-iolib.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-iolib.lo `test -f 'iolib.c' || echo '$(srcdir)/'`iolib.c + +libgp_collector_la-mmaptrace.lo: mmaptrace.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-mmaptrace.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-mmaptrace.Tpo -c -o libgp_collector_la-mmaptrace.lo `test -f 'mmaptrace.c' || echo '$(srcdir)/'`mmaptrace.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-mmaptrace.Tpo $(DEPDIR)/libgp_collector_la-mmaptrace.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mmaptrace.c' object='libgp_collector_la-mmaptrace.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-mmaptrace.lo `test -f 'mmaptrace.c' || echo '$(srcdir)/'`mmaptrace.c + +libgp_collector_la-memmgr.lo: memmgr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-memmgr.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-memmgr.Tpo -c -o libgp_collector_la-memmgr.lo `test -f 'memmgr.c' || echo '$(srcdir)/'`memmgr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-memmgr.Tpo $(DEPDIR)/libgp_collector_la-memmgr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='memmgr.c' object='libgp_collector_la-memmgr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-memmgr.lo `test -f 'memmgr.c' || echo '$(srcdir)/'`memmgr.c + +libgp_collector_la-tsd.lo: tsd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-tsd.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-tsd.Tpo -c -o libgp_collector_la-tsd.lo `test -f 'tsd.c' || echo '$(srcdir)/'`tsd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-tsd.Tpo $(DEPDIR)/libgp_collector_la-tsd.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tsd.c' object='libgp_collector_la-tsd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-tsd.lo `test -f 'tsd.c' || echo '$(srcdir)/'`tsd.c + +libgp_collector_la-profile.lo: profile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-profile.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-profile.Tpo -c -o libgp_collector_la-profile.lo `test -f 'profile.c' || echo '$(srcdir)/'`profile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-profile.Tpo $(DEPDIR)/libgp_collector_la-profile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profile.c' object='libgp_collector_la-profile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-profile.lo `test -f 'profile.c' || echo '$(srcdir)/'`profile.c + +libgp_collector_la-envmgmt.lo: envmgmt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-envmgmt.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-envmgmt.Tpo -c -o libgp_collector_la-envmgmt.lo `test -f 'envmgmt.c' || echo '$(srcdir)/'`envmgmt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-envmgmt.Tpo $(DEPDIR)/libgp_collector_la-envmgmt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='envmgmt.c' object='libgp_collector_la-envmgmt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-envmgmt.lo `test -f 'envmgmt.c' || echo '$(srcdir)/'`envmgmt.c + +libgp_collector_la-linetrace.lo: linetrace.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-linetrace.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-linetrace.Tpo -c -o libgp_collector_la-linetrace.lo `test -f 'linetrace.c' || echo '$(srcdir)/'`linetrace.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-linetrace.Tpo $(DEPDIR)/libgp_collector_la-linetrace.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='linetrace.c' object='libgp_collector_la-linetrace.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-linetrace.lo `test -f 'linetrace.c' || echo '$(srcdir)/'`linetrace.c + +libgp_collector_la-libcol_hwcdrv.lo: libcol_hwcdrv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol_hwcdrv.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Tpo -c -o libgp_collector_la-libcol_hwcdrv.lo `test -f 'libcol_hwcdrv.c' || echo '$(srcdir)/'`libcol_hwcdrv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Tpo $(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol_hwcdrv.c' object='libgp_collector_la-libcol_hwcdrv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol_hwcdrv.lo `test -f 'libcol_hwcdrv.c' || echo '$(srcdir)/'`libcol_hwcdrv.c + +libgp_collector_la-libcol_hwcfuncs.lo: libcol_hwcfuncs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol_hwcfuncs.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Tpo -c -o libgp_collector_la-libcol_hwcfuncs.lo `test -f 'libcol_hwcfuncs.c' || echo '$(srcdir)/'`libcol_hwcfuncs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Tpo $(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol_hwcfuncs.c' object='libgp_collector_la-libcol_hwcfuncs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol_hwcfuncs.lo `test -f 'libcol_hwcfuncs.c' || echo '$(srcdir)/'`libcol_hwcfuncs.c + +libgp_collector_la-libcol-i386-dis.lo: libcol-i386-dis.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol-i386-dis.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol-i386-dis.Tpo -c -o libgp_collector_la-libcol-i386-dis.lo `test -f 'libcol-i386-dis.c' || echo '$(srcdir)/'`libcol-i386-dis.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol-i386-dis.Tpo $(DEPDIR)/libgp_collector_la-libcol-i386-dis.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol-i386-dis.c' object='libgp_collector_la-libcol-i386-dis.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol-i386-dis.lo `test -f 'libcol-i386-dis.c' || echo '$(srcdir)/'`libcol-i386-dis.c + +libgp_collector_la-hwprofile.lo: hwprofile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-hwprofile.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-hwprofile.Tpo -c -o libgp_collector_la-hwprofile.lo `test -f 'hwprofile.c' || echo '$(srcdir)/'`hwprofile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-hwprofile.Tpo $(DEPDIR)/libgp_collector_la-hwprofile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hwprofile.c' object='libgp_collector_la-hwprofile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-hwprofile.lo `test -f 'hwprofile.c' || echo '$(srcdir)/'`hwprofile.c + +libgp_collector_la-jprofile.lo: jprofile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-jprofile.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-jprofile.Tpo -c -o libgp_collector_la-jprofile.lo `test -f 'jprofile.c' || echo '$(srcdir)/'`jprofile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-jprofile.Tpo $(DEPDIR)/libgp_collector_la-jprofile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jprofile.c' object='libgp_collector_la-jprofile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-jprofile.lo `test -f 'jprofile.c' || echo '$(srcdir)/'`jprofile.c + +libgp_collector_la-unwind.lo: unwind.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-unwind.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-unwind.Tpo -c -o libgp_collector_la-unwind.lo `test -f 'unwind.c' || echo '$(srcdir)/'`unwind.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-unwind.Tpo $(DEPDIR)/libgp_collector_la-unwind.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unwind.c' object='libgp_collector_la-unwind.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-unwind.lo `test -f 'unwind.c' || echo '$(srcdir)/'`unwind.c + +libgp_collector_la-libcol_util.lo: libcol_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol_util.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol_util.Tpo -c -o libgp_collector_la-libcol_util.lo `test -f 'libcol_util.c' || echo '$(srcdir)/'`libcol_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol_util.Tpo $(DEPDIR)/libgp_collector_la-libcol_util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol_util.c' object='libgp_collector_la-libcol_util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol_util.lo `test -f 'libcol_util.c' || echo '$(srcdir)/'`libcol_util.c + +libgp_collector_la-collector.lo: collector.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-collector.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-collector.Tpo -c -o libgp_collector_la-collector.lo `test -f 'collector.c' || echo '$(srcdir)/'`collector.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-collector.Tpo $(DEPDIR)/libgp_collector_la-collector.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='collector.c' object='libgp_collector_la-collector.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-collector.lo `test -f 'collector.c' || echo '$(srcdir)/'`collector.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-myincludeHEADERS: $(myinclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(myinclude_HEADERS)'; test -n "$(myincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(myincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(myincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(myincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(myincludedir)" || exit $$?; \ + done + +uninstall-myincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(myinclude_HEADERS)'; test -n "$(myincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(myincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + 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-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + 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" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @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 + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) lib-config.h +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(myincludedir)"; 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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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) + +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 $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-myincludeHEADERS + +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 $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -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-myincludeHEADERS + +.MAKE: all install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \ + clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \ + cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ + dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + 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-myincludeHEADERS \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-libLTLIBRARIES uninstall-myincludeHEADERS + +.PRECIOUS: Makefile + + +# 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/gprofng/libcollector/aclocal.m4 b/gprofng/libcollector/aclocal.m4 new file mode 100644 index 0000000..b269c73 --- /dev/null +++ b/gprofng/libcollector/aclocal.m4 @@ -0,0 +1,1237 @@ +# generated automatically by aclocal 1.15.1 -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. + +# This file 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. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.15' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.15.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.15.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Copyright (C) 2011-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_AR([ACT-IF-FAIL]) +# ------------------------- +# Try to determine the archiver interface, and trigger the ar-lib wrapper +# if it is needed. If the detection of archiver interface fails, run +# ACT-IF-FAIL (default is to abort configure with a proper error message). +AC_DEFUN([AM_PROG_AR], +[AC_BEFORE([$0], [LT_INIT])dnl +AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([ar-lib])dnl +AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) +: ${AR=ar} + +AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], + [AC_LANG_PUSH([C]) + am_cv_ar_interface=ar + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], + [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + ]) + AC_LANG_POP([C])]) + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + m4_default([$1], + [AC_MSG_ERROR([could not determine $AR interface])]) + ;; +esac +AC_SUBST([AR])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file 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. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# +# This file 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. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# +# This file 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. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file 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 macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> +# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: <http://www.gnu.org/software/coreutils/>. + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2017 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2017 Free Software Foundation, Inc. +# +# This file 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. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + AM_RUN_LOG([cat conftest.dir/file]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([../../config/depstand.m4]) +m4_include([../../config/lead-dot.m4]) +m4_include([../../config/override.m4]) +m4_include([../../libtool.m4]) +m4_include([../../ltoptions.m4]) +m4_include([../../ltsugar.m4]) +m4_include([../../ltversion.m4]) +m4_include([../../lt~obsolete.m4]) diff --git a/gprofng/libcollector/collector.c b/gprofng/libcollector/collector.c new file mode 100644 index 0000000..93c9d33 --- /dev/null +++ b/gprofng/libcollector/collector.c @@ -0,0 +1,2494 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <alloca.h> +#include <errno.h> +#include <signal.h> +#include <ucontext.h> +#include <stdlib.h> /* exit() */ +#include <sys/param.h> +#include <sys/utsname.h> /* struct utsname */ +#include <sys/resource.h> +#include <sys/syscall.h> /* system call fork() */ + +#include "gp-defs.h" +#include "collector.h" +#include "descendants.h" +#include "gp-experiment.h" +#include "memmgr.h" +#include "cc_libcollector.h" +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +typedef unsigned long ulong_t; + +extern char **environ; +extern void __collector_close_experiment (); +extern int __collector_set_size_limit (char *par); + +/* ------- internal function prototypes ---------- */ +CollectorModule __collector_register_module (ModuleInterface *modint); +static void write_sample (char *name); +static const char *__collector_get_params (); +static const char *__collector_get_expdir (); +static FrameInfo __collector_getUserCtx (CollectorModule modl, HiResTime ts, int mode, void *arg); +static FrameInfo __collector_getUID1 (CM_Array *arg); +static int __collector_writeMetaData (CollectorModule modl, char *format, ...); +static int __collector_writeDataRecord (CollectorModule modl, struct Common_packet *pckt); +static int __collector_writeDataPacket (CollectorModule modl, struct CM_Packet *pckt); +static void *allocCSize (struct Heap*, unsigned, int); +static void freeCSize (struct Heap*, void*, unsigned); +static void *allocVSize (struct Heap*, unsigned); +static void *reallocVSize (struct Heap*, void*, unsigned); + +static int collector_create_expr_dir (const char *new_exp_name); +static int collector_create_expr_dir_lineage (const char *parent_exp_name); +static int collector_exp_dir_append_x (int linenum, const char *parent_exp_name); +static int collector_tail_init (const char *parent_exp_name); +static int log_open (); +static void log_header_write (sp_origin_t origin); +static void log_pause (); +static void log_resume (); +static void fs_warn (); +static void log_close (); +static void get_progspec (char *cmdline, int tmp_sz, char *progname, int sz); +static void sample_handler (int, siginfo_t*, void*); +static int sample_set_interval (char *); +static int set_duration (char *); +static int sample_set_user_sig (char *); +static void pause_handler (int, siginfo_t*, void*); +static int pause_set_user_sig (char *); +static int set_user_sig_action (char*); +static void ovw_open (); +static hrtime_t ovw_write (); + +/* ------- global data controlling the collector's behavior -------- */ + +static CollectorInterface collector_interface ={ + __collector_register_module, /* registerModule */ + __collector_get_params, /* getParams */ + __collector_get_expdir, /* getExpDir */ + __collector_log_write, /* writeLog */ + __collector_getUserCtx, /* getFrameInfo */ + __collector_getUID1, /* getUID */ + __collector_getUID, /* getUID2 */ + __collector_getStackTrace, /* getStackTrace */ + __collector_writeMetaData, /* writeMetaData */ + __collector_writeDataRecord, /* writeDataRecord */ + __collector_writeDataPacket, /* writeDataPacket */ + write_sample, /* write_sample */ + get_progspec, /* get_progspec */ + __collector_open_experiment, /* open_experiment */ + NULL, /* getHiResTime */ + __collector_newHeap, /* newHeap */ + __collector_deleteHeap, /* deleteHeap */ + allocCSize, /* allocCSize */ + freeCSize, /* freeCSize */ + allocVSize, /* allocVSize */ + reallocVSize, /* reallocVSize */ + __collector_tsd_create_key, /* createKey */ + __collector_tsd_get_by_key, /* getKey */ + __collector_dlog /* writeDebugInfo */ +}; + +#define MAX_MODULES 32 +static ModuleInterface *modules[MAX_MODULES]; +static int modules_st[MAX_MODULES]; +static void *modules_hndl[MAX_MODULES]; +static volatile int nmodules = 0; + +/* flag set non-zero, if data collected implies a filesystem warning is appropriate */ +static int fs_matters = 0; +static const char *collector_params = NULL; +static const char *project_home = NULL; +Heap *__collector_heap = NULL; +int __collector_no_threads; +int __collector_libthread_T1 = -1; + +static volatile int collector_paused = 0; + +int __collector_tracelevel = -1; +static int collector_debug_opt = 0; + +hrtime_t __collector_next_sample = 0; +int __collector_sample_period = 0; /* if non-zero, periodic sampling is enabled */ + +hrtime_t __collector_delay_start = 0; /* if non-zero, delay before starting data */ +hrtime_t __collector_terminate_time = 0; /* if non-zero, fixed duration run */ + +static collector_mutex_t __collector_glob_lock = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t __collector_open_guard = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t __collector_close_guard = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t __collector_sample_guard = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t __collector_suspend_guard = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t __collector_resume_guard = COLLECTOR_MUTEX_INITIALIZER; +char __collector_exp_dir_name[MAXPATHLEN + 1] = ""; /* experiment directory */ +int __collector_size_limit = 0; + +static char *archive_mode = NULL; + +volatile sp_state_t __collector_expstate = EXP_INIT; +static int exp_origin = SP_ORIGIN_LIBCOL_INIT; +static int exp_open = 0; +int __collector_exp_active = 0; +static int paused_when_suspended = 0; +static int exp_initted = 0; +static char exp_progspec[_POSIX_ARG_MAX + 1]; /* program cmdline. includes args */ +static char exp_progname[_POSIX_ARG_MAX + 1]; /* program name == argv[0] */ + +hrtime_t __collector_start_time = 0; +static time_t start_sec_time = 0; + +/* Sample related data */ +static int sample_installed = 0; /* 1 if the sample signal handler installed */ +static int sample_mode = 0; /* dynamically turns sample record writing on/off */ +static int sample_number = 0; /* index of the current sample record */ +static struct sigaction old_sample_handler; +int __collector_sample_sig = -1; /* user-specified sample signal */ +int __collector_sample_sig_warn = 0; /* non-zero if warning already given */ + +/* Pause/resume related data */ +static struct sigaction old_pause_handler; +int __collector_pause_sig = -1; /* user-specified pause signal */ +int __collector_pause_sig_warn = 0; /* non-zero if warning already given */ + +static struct sigaction old_close_handler; +static struct sigaction old_exit_handler; + +/* Experiment files */ +static char ovw_name[MAXPATHLEN]; /* Overview data file name */ + +/* macro to convert a timestruc to hrtime_t */ +#define ts2hrt(x) ((hrtime_t)(x).tv_sec*NANOSEC + (hrtime_t)(x).tv_nsec) + +static void +init_tracelevel () +{ +#if DEBUG + char *s = CALL_UTIL (getenv)("SP_COLLECTOR_TRACELEVEL"); + if (s != NULL) + __collector_tracelevel = CALL_UTIL (atoi)(s); + TprintfT (DBG_LT0, "collector: SP_COLLECTOR_TRACELEVEL=%d\n", __collector_tracelevel); + s = CALL_UTIL (getenv)("SP_COLLECTOR_DEBUG"); + if (s != NULL) + collector_debug_opt = CALL_UTIL (atoi)(s) & ~(SP_DUMP_TIME | SP_DUMP_FLAG); +#endif +} + +static CollectorInterface * +get_collector_interface () +{ + if (collector_interface.getHiResTime == NULL) + collector_interface.getHiResTime = __collector_gethrtime; + return &collector_interface; +} + +/* + * __collector_module_init is an alternate method to initialize + * dynamic collector modules (er_heap, er_sync, er_iotrace, er_mpi, tha). + * Every module that needs to register itself with libcollector + * before the experiment is open implements its own global + * __collector_module_init and makes sure the next one is called. + */ +static void +collector_module_init (CollectorInterface *col_intf) +{ + int nmodules = 0; + + ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_DEFAULT, "__collector_module_init"); + if (next_init != NULL) + { + nmodules++; + next_init (col_intf); + } + TprintfT (DBG_LT1, "collector_module_init: %d modules\n", nmodules); +} + +/* Routines concerned with general experiment start and stop */ + +/* initialization -- init section routine -- called when libcollector loaded */ +static void collector_init () __attribute__ ((constructor)); + +static void +collector_init () +{ + if (__collector_util_init () != 0) + /* we can't do anything without various utility functions */ + abort (); + init_tracelevel (); + + /* + * Unconditionally install the SIGPROF handler + * to process signals originated in dtracelets. + */ + __collector_sigprof_install (); + + /* Initialize all preloaded modules */ + collector_module_init (get_collector_interface ()); + + /* determine experiment name */ + char *exp = CALL_UTIL (getenv)("SP_COLLECTOR_EXPNAME"); + if ((exp == NULL) || (CALL_UTIL (strlen)(exp) == 0)) + { + TprintfT (DBG_LT0, "collector_init: SP_COLLECTOR_EXPNAME undefined - no experiment to start\n"); + /* not set -- no experiment to run */ + return; + } + else + TprintfT (DBG_LT1, "collector_init: found SP_COLLECTOR_EXPNAME = %s\n", exp); + + /* determine the data descriptor for the experiment */ + char *params = CALL_UTIL (getenv)("SP_COLLECTOR_PARAMS"); + if (params == NULL) + { + TprintfT (0, "collector_init: SP_COLLECTOR_PARAMS undefined - no experiment to start\n"); + return; + } + + /* now do the real open of the experiment */ + if (__collector_open_experiment (exp, params, SP_ORIGIN_LIBCOL_INIT)) + { + TprintfT (0, "collector_init: __collector_open_experiment failed\n"); + /* experiment open failed, close it */ + __collector_close_experiment (); + return; + } + return; +} + +CollectorModule +__collector_register_module (ModuleInterface *modint) +{ + TprintfT (DBG_LT1, "collector: module %s calls for registration.\n", + modint->description == NULL ? "(null)" : modint->description); + if (modint == NULL) + return COLLECTOR_MODULE_ERR; + if (nmodules >= MAX_MODULES) + return COLLECTOR_MODULE_ERR; + if (modint->initInterface && + modint->initInterface (get_collector_interface ())) + return COLLECTOR_MODULE_ERR; + int idx = nmodules++; + modules[idx] = modint; + modules_st[idx] = 0; + + if (exp_open && modint->openExperiment) + { + modules_st[idx] = modint->openExperiment (__collector_exp_dir_name); + if (modules_st[idx] == COL_ERROR_NONE && modules[idx]->description != NULL) + { + modules_hndl[idx] = __collector_create_handle (modules[idx]->description); + if (modules_hndl[idx] == NULL) + modules_st[idx] = -1; + } + } + if (__collector_exp_active && collector_paused == 0 && + modint->startDataCollection && modules_st[idx] == 0) + modint->startDataCollection (); + TprintfT (DBG_LT1, "collector: module %s (%d) registered.\n", + modint->description == NULL ? "(null)" : modint->description, idx); + return (CollectorModule) idx; +} + +static const char * +__collector_get_params () +{ + return collector_params; +} + +static const char * +__collector_get_expdir () +{ + return __collector_exp_dir_name; +} + +static FrameInfo +__collector_getUserCtx (CollectorModule modl, HiResTime ts, int mode, void *arg) +{ + return __collector_get_frame_info (ts, mode, arg); +} + +static FrameInfo +__collector_getUID1 (CM_Array *arg) +{ + return __collector_getUID (arg, (FrameInfo) 0); +} + +static int +__collector_writeMetaData (CollectorModule modl, char *format, ...) +{ + if (modl < 0 || modl >= nmodules || modules[modl]->description == NULL) + { + TprintfT (DBG_LT0, "__collector_writeMetaData(): bad module: %d\n", modl); + return 1; + } + char fname[MAXPATHLEN + 1]; + CALL_UTIL (strlcpy)(fname, __collector_exp_dir_name, sizeof (fname)); + CALL_UTIL (strlcat)(fname, "/metadata.", sizeof (fname)); + CALL_UTIL (strlcat)(fname, modules[modl]->description, sizeof (fname)); + CALL_UTIL (strlcat)(fname, ".xml", sizeof (fname)); + int fd = CALL_UTIL (open)(fname, O_CREAT | O_WRONLY | O_APPEND, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) + { + TprintfT (DBG_LT0, "__collector_writeMetaData(): can't open file: %s\n", fname); + return 1; + } + char buf[1024]; + char *bufptr = buf; + va_list va; + va_start (va, format); + int sz = __collector_xml_vsnprintf (bufptr, sizeof (buf), format, va); + va_end (va); + + if (sz >= sizeof (buf)) + { + /* Allocate a new buffer */ + sz += 1; /* add the terminating null byte */ + bufptr = (char*) alloca (sz); + + va_start (va, format); + sz = __collector_xml_vsnprintf (bufptr, sz, format, va); + va_end (va); + } + CALL_UTIL (write)(fd, bufptr, sz); + CALL_UTIL (close)(fd); + return COL_ERROR_NONE; +} + +/* check that the header fields are filled-in, and then call __collector_writeDataPacket */ +static int +__collector_writeDataRecord (CollectorModule modl, struct Common_packet *pckt) +{ + return __collector_write_record (modules_hndl[modl], pckt); +} + +static int +__collector_writeDataPacket (CollectorModule modl, struct CM_Packet *pckt) +{ + return __collector_write_packet (modules_hndl[modl], pckt); +} + +static void * +allocCSize (struct Heap *heap, unsigned sz, int log) +{ + return __collector_allocCSize (heap ? heap : __collector_heap, sz, log); +} + +static void +freeCSize (struct Heap *heap, void *ptr, unsigned sz) +{ + __collector_freeCSize (heap ? heap : __collector_heap, ptr, sz); +} + +static void * +allocVSize (struct Heap *heap, unsigned sz) +{ + return __collector_allocVSize (heap ? heap : __collector_heap, sz); +} + +static void * +reallocVSize (struct Heap *heap, void *ptr, unsigned sz) +{ + return __collector_reallocVSize (heap ? heap : __collector_heap, ptr, sz); +} + +static time_t +get_gm_time (struct tm *tp) +{ + /* + Note that glibc contains a function of the same purpose named `timegm'. + But obviously, it is not universally available. + + Some implementations of mktime return -1 for the nonexistent localtime hour + at the beginning of DST. In this event, use 'mktime(tm - 1hr) + 3600'. + nonexistent + tm_isdst is set to 0 to force mktime to introduce a consistent offset + (the non DST offset) since tm and tm+o might be on opposite sides of a DST change. + + Schematically: + mktime(tm) --> t+o + gmtime_r(t+o) --> tm+o + mktime(tm+o) --> t+2o + t = t+o - (t+2o - t+o) + */ + struct tm stm; + time_t tl = CALL_UTIL (mktime)(tp); + if (tl == -1) + { + stm = *tp; + stm.tm_hour--; + tl = CALL_UTIL (mktime)(&stm); + if (tl == -1) + return -1; + tl += 3600; + } + + (void) (CALL_UTIL (gmtime_r)(&tl, &stm)); + stm.tm_isdst = 0; + time_t tb = CALL_UTIL (mktime)(&stm); + if (tb == -1) + { + stm.tm_hour--; + tb = CALL_UTIL (mktime)(&stm); + if (tb == -1) + return -1; + tb += 3600; + } + return (tl - (tb - tl)); +} + +static void +log_write_event_run () +{ + /* get the gm and local time */ + struct tm start_stm; + CALL_UTIL (gmtime_r)(&start_sec_time, &start_stm); + time_t start_gm_time = get_gm_time (&start_stm); + time_t lcl_time = CALL_UTIL (mktime)(&start_stm); + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" time=\"%lld\" tm_zone=\"%lld\"/>\n", + SP_JCMD_RUN, + (unsigned) (__collector_start_time / NANOSEC), + (unsigned) (__collector_start_time % NANOSEC), + (long long) start_gm_time, + (long long) (lcl_time - start_gm_time)); +} + +static void * +m_dlopen (const char *filename, int flag) +{ + void *p = dlopen (filename, flag); + TprintfT (DBG_LT1, "collector.c: dlopen(%s, %d) returns %p\n", filename, flag, p); + return p; +} +/* real routine to open an experiment + * called by collector_init from libcollector init section + * called by __collector_start_experiment when a child is forked */ +int +__collector_open_experiment (const char *exp, const char *params, sp_origin_t origin) +{ + char *s; + char *buf = NULL; + char *duration_string = NULL; + int err; + int is_founder = 1; + int record_this_experiment = 1; + int seen_F_flag = 0; + static char buffer[32]; + if (exp_open) + { + /* experiment already opened */ + TprintfT (0, "collector: ERROR: Attempt to open opened experiment\n"); + return COL_ERROR_EXPOPEN; + } + __collector_start_time = collector_interface.getHiResTime (); + TprintfT (DBG_LT1, "\n\t\t__collector_open_experiment(SP_COLLECTOR_EXPNAME=%s, params=%s, origin=%d); setting start_time\n", + exp, params, origin); + if (environ) + __collector_env_printall ("__collector_open_experiment", environ); + else + TprintfT (DBG_LT1, "collector_open_experiment found environ == NULL)\n"); + + /* + * Recheck sigprof handler + * XXXX Bug 18177509 - additional sigprof signal kills target program + */ + __collector_sigprof_install (); + exp_origin = origin; + collector_params = params; + + /* Determine which of the three possible threading models: + * singlethreaded + * multi-LWP (no threads) + * multithreaded + * is the one the target is actually using. + * + * we really only need to distinguish between first two + * and the third. The thr_main() trick does exactly that. + * is the one the target is actually using. + * + * __collector_no_threads applies to all signal handlers, + * and must be set before signal handlers are installed. + */ + __collector_no_threads = 0; + __collector_exp_dir_name[0] = 0; + sample_mode = 0; + sample_number = 0; + + /* create global heap */ + if (__collector_heap == NULL) + { + __collector_heap = __collector_newHeap (); + if (__collector_heap == NULL) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment COLERROR_NOZMEM 1\n"); + return COL_ERROR_NOZMEM; + } + } + //check whether is origin is collect + char * envar = CALL_UTIL (getenv)("SP_COLLECTOR_ORIGIN_COLLECT"); + TprintfT (DBG_LT1, "__collector_open_experiment SP_COLLECTOR_ORIGIN_COLLECT = '%s'\n", + (envar == NULL) ? "NULL" : envar); + if (envar) + exp_origin = SP_ORIGIN_COLLECT; + + //check if this is the founder process + is_founder = getpid (); + if (origin != SP_ORIGIN_DBX_ATTACH) + { + envar = CALL_UTIL (getenv)("SP_COLLECTOR_FOUNDER"); + if (envar) + is_founder = CALL_UTIL (atoi)(envar); + if (is_founder != 0) + { + if (is_founder != getpid ()) + { + TprintfT (0, "__collector_open_experiment SP_COLLECTOR_FOUNDER=%d != pid(%d)\n", + is_founder, getpid ()); + //CALL_UTIL(fprintf)(stderr, "__collector_open_experiment SP_COLLECTOR_FOUNDER=%d != pid(%d); not recording experiment\n", + //is_founder, getpid() ); + //return COL_ERROR_UNEXP_FOUNDER; + is_founder = 0; // Special case (CR 22917352) + } + /* clear FOUNDER for descendant experiments */ + TprintfT (0, "__collector_open_experiment setting SP_COLLECTOR_FOUNDER=0\n"); + CALL_UTIL (strlcpy)(buffer, "SP_COLLECTOR_FOUNDER=0", sizeof (buffer)); + CALL_UTIL (putenv)(buffer); + } + } + + /* Set up fork/exec interposition (requires __collector_heap). */ + /* Determine if "collect -F" specification enables this subexperiment */ + get_progspec (exp_progspec, sizeof (exp_progspec), exp_progname, sizeof (exp_progname)); + + /* convert the returned exp_progname to a basename */ + const char * base_name = __collector_strrchr (exp_progname, '/'); + if (base_name == NULL) + base_name = exp_progname; + else + base_name = base_name + 1; + err = __collector_ext_line_init (&record_this_experiment, exp_progspec, base_name); + if (err != COL_ERROR_NONE) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment COLERROR: %d\n", err); + return err; + } + + /* Due to the fix of bug 15691122, we need to initialize unwind to make + * the function __collector_ext_return_address() work for dlopen interposition. + * */ + if (!record_this_experiment && !is_founder) + { + TprintfT (DBG_LT0, "__collector_open_experiment: NOT creating experiment. (is_founder=%d, record=%d)\n", + is_founder, record_this_experiment); + return collector_tail_init (exp); + } + TprintfT (DBG_LT0, "__collector_open_experiment: is_founder=%d, record=%d\n", + is_founder, record_this_experiment); + if (is_founder || origin == SP_ORIGIN_FORK) + { + CALL_UTIL (strlcpy)(__collector_exp_dir_name, exp, sizeof (__collector_exp_dir_name)); + if (origin == SP_ORIGIN_FORK) + { /*create exp dir for fork-child*/ + if (collector_create_expr_dir (__collector_exp_dir_name)) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 1: `%s'\n", exp); + return COL_ERROR_BADDIR; + } + } + } + else + {/* founder/fork-child will already have created experiment dir, but exec/combo descendants must do so now */ + if (collector_create_expr_dir_lineage (exp)) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 2: `%s'\n", exp); + return COL_ERROR_BADDIR; + } + static char exp_name_env[MAXPATHLEN + 1]; + TprintfT (DBG_LT1, "collector_open_experiment: setting SP_COLLECTOR_EXPNAME to %s\n", __collector_exp_dir_name); + CALL_UTIL (snprintf)(exp_name_env, sizeof (exp_name_env), "SP_COLLECTOR_EXPNAME=%s", __collector_exp_dir_name); + CALL_UTIL (putenv)(exp_name_env); + } + /* Check that the name is that of a directory (new structure) */ + DIR *expDir = CALL_UTIL (opendir)(__collector_exp_dir_name); + if (expDir == NULL) + { + /* can't open it */ + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 3: `%s'\n", exp); + return COL_ERROR_BADDIR; + } + CALL_UTIL (closedir)(expDir); + + if (CALL_UTIL (access)(__collector_exp_dir_name, W_OK)) + { + TprintfT (0, "collector: ERROR: access error: errno=%d\n", errno); + if ((errno == EACCES) || (errno == EROFS)) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_DIRPERM: `%s'\n", exp); + TprintfT (DBG_LT0, "collector: ERROR: experiment directory `%s' is not writeable\n", + __collector_exp_dir_name); + return COL_ERROR_DIRPERM; + } + else + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 4: `%s'\n", exp); + return COL_ERROR_BADDIR; + } + } + + /* reset the paused flag */ + collector_paused = (origin == SP_ORIGIN_FORK ? paused_when_suspended : 0); + + /* mark the experiment as opened */ + __collector_expstate = EXP_OPEN; + TprintfT (DBG_LT1, "collector: __collector_expstate->EXP_OPEN\n"); + + /* open the log file */ + err = log_open (); + if (err != COL_ERROR_NONE) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_LOG_OPEN\n"); + return COL_ERROR_LOG_OPEN; + } + if (origin != SP_ORIGIN_GENEXP && origin != SP_ORIGIN_KERNEL) + log_header_write (origin); + + /* Make a copy of params so that we can modify the string */ + int paramsz = CALL_UTIL (strlen)(params) + 1; + buf = (char*) alloca (paramsz); + if (buf == NULL) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_ARGS2BIG: %s\n", params); + TprintfT (DBG_LT0, "collector: ERROR: experiment parameter `%s' is too long\n", params); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\"/></event>\n", + SP_JCMD_CERROR, COL_ERROR_ARGS2BIG); + return COL_ERROR_ARGS2BIG; + } + CALL_UTIL (strlcpy)(buf, params, paramsz); + + /* create directory for archives (if founder) */ + char archives[MAXPATHLEN]; + CALL_UTIL (snprintf)(archives, MAXPATHLEN, "%s/%s", __collector_exp_dir_name, + SP_ARCHIVES_DIR); + if (is_founder) + { + mode_t dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + if ((CALL_UTIL (mkdir)(archives, dmode) != 0) && (errno != EEXIST)) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_MKDIR: %s: errno = %d\n", archives, errno); + TprintfT (0, "collector: ERROR: mkdir(%s) failed: errno = %d\n", archives, errno); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">mkdir(%s): errno=%d</event>\n", + SP_JCMD_COMMENT, COL_COMMENT_NONE, archives, errno); + /* this is not a fatal error currently */ + } + else + TprintfT (DBG_LT1, "collector: archive mkdir(%s) succeeded\n", archives); + } + + /* initialize the segments map and mmap interposition */ + if (origin != SP_ORIGIN_GENEXP && origin != SP_ORIGIN_KERNEL) + { + if ((err = __collector_ext_mmap_install (1)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\"/></event>\n", SP_JCMD_CERROR, err); + return err; + } + } + + /* open the overview file for sample data */ + if (origin != SP_ORIGIN_GENEXP) + ovw_open (); + + /* initialize TSD module (note: relies on __collector_heap) */ + if (__collector_tsd_init () != 0) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_TSD_INIT\n"); + __collector_log_write ("<event kind=\"%s\" id=\"%d\">TSD could not be initialized</event>\n", SP_JCMD_CERROR, COL_ERROR_TSD_INIT); + return COL_ERROR_TSD_INIT; + } + + /* experiment is initialized; allow pause/resume/close */ + exp_initted = 1; + + // 24935305 should not use SIGPROF if collect -p -t and -S are all off + /* (check here if -t or -S is on; -p is checked later) */ + if (((params[0] == 't' || params[0] == 'S') && params[1] == ':') + || CALL_UTIL (strstr)(params, ";t:") + || CALL_UTIL (strstr)(params, ";S:")) + { + /* set a default time to 100 ms.; use negative value to force setting */ + TprintfT (DBG_LT1, "collector: open_experiment setting timer to 100000\n"); + __collector_ext_itimer_set (-100000); + } + + /* call open for all dynamic modules */ + int i; + for (i = 0; i < nmodules; i++) + { + if (modules[i]->openExperiment != NULL) + { + modules_st[i] = modules[i]->openExperiment (__collector_exp_dir_name); + if (modules_st[i] == COL_ERROR_NONE && modules[i]->description != NULL) + { + modules_hndl[i] = __collector_create_handle (modules[i]->description); + if (modules_hndl[i] == NULL) + modules_st[i] = -1; + } + } + /* check to see if anyone closed the experiment */ + if (!exp_initted) + { + CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_EXP_OPEN\n"); + __collector_log_write ("<event kind=\"%s\" id=\"%d\">Experiment closed prematurely</event>\n", SP_JCMD_CERROR, COL_ERROR_EXPOPEN); + return COL_ERROR_EXPOPEN; + } + } + + /* initialize for subsequent stack unwinds */ + __collector_ext_unwind_init (1); + TprintfT (DBG_LT0, "__collector_open_experiment(); module init done, params=%s\n", + buf); + + /* now parse the data descriptor */ + /* The parameter string is a series of specifiers, + * each of which is of the form: + * <key>:<param>; + * key is a single letter, the : and ; are mandatory, + * and param is a string which may be zero-length, and + * which contains any character except a null-byte or ; + * param is interpreted by the handler for the particular key + */ + + s = buf; + + while (*s) + { + char *par; + char key = *s++; + /* ensure that it's followed by a colon */ + if (*s++ != ':') + { + TprintfT (0, "collector: ERROR: parameter %c is not followed by a colon\n", key); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, COL_ERROR_ARGS, params); + return COL_ERROR_ARGS; + } + /* find the semicolon terminator */ + par = s; + while (*s && (*s != ';')) + s++; + if (*s != ';') + { + /* not followed by semicolon */ + TprintfT (0, "collector: ERROR: parameter %c:%s is not terminated by a semicolon\n", key, par); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, COL_ERROR_ARGS, params); + return COL_ERROR_ARGS; + } + /* terminate par, and position for next descriptor */ + *s++ = 0; + + /* now process that element of the data descriptor */ + switch (key) + { + case 'g': /* g<sig>; */ + if ((err = sample_set_user_sig (par)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + return err; + } + break; + case 'd': /* d<sig>; -or- d<sig>p; */ + if ((err = pause_set_user_sig (par)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + return err; + } + break; + case 'H': + m_dlopen ("libgp-heap.so", RTLD_LAZY); /* hack to force .so's constructor to be called (?) */ + break; + case 's': + m_dlopen ("libgp-sync.so", RTLD_LAZY); /* hack to force .so's constructor to be called (?) */ + break; + case 'i': + m_dlopen ("libgp-iotrace.so", RTLD_LAZY); /* hack to force .so's constructor to be called (?) */ + break; + case 'F': /* F; */ + seen_F_flag = 1; + TprintfT (DBG_LT0, "__collector_open_experiment: calling __collector_ext_line_install (%s, %s)\n", + par, __collector_exp_dir_name); + if ((err = __collector_ext_line_install (par, __collector_exp_dir_name)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + return err; + } + break; + case 'a': /* a; */ + archive_mode = __collector_strdup (par); + break; + case 't': /* t:<expt-duration>; */ + duration_string = par; + break; + case 'S': /* S:<sample-interval>; */ + if ((err = sample_set_interval (par)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + return err; + } + break; + case 'L': /* L:<experiment-size-limit>; */ + if ((err = __collector_set_size_limit (par)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + return err; + } + break; + case 'P': /* P:PROJECT_HOME; */ + project_home = __collector_strdup (par); + break; + case 'h': + case 'p': + fs_matters = 1; + break; + case 'Y': + err = set_user_sig_action (par); + if (err != COL_ERROR_NONE) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + break; + default: + /* Ignore unknown parameters; allow them to be handled by modules */ + break; + } + } + /* end of data descriptor parsing */ + + if (!seen_F_flag) + { + char * par = "0"; // This will not happen when collect has no -F option + if ((err = __collector_ext_line_install (par, __collector_exp_dir_name)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par); + return err; + } + } + + /* now that we know what data is being collected, we can set the filesystem warning */ + fs_warn (); + + // We have to create all tsd keys before __collector_tsd_allocate(). + // With the pthreads-based implementation, this might no longer be necessary. + // In any case, we still have to create the key before a thread can use it. + __collector_ext_gettid_tsd_create_key (); + __collector_ext_dispatcher_tsd_create_key (); + + /* allocate tsd for the current thread */ + if (__collector_tsd_allocate () != 0) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">TSD allocate failed</event>\n", SP_JCMD_CERROR, COL_ERROR_EXPOPEN); + return COL_ERROR_EXPOPEN; + } + /* init tsd for unwind, called right after __collector_tsd_allocate()*/ + __collector_ext_unwind_key_init (1, NULL); + + /* start java attach if suitable */ + if (exp_origin == SP_ORIGIN_DBX_ATTACH) + __collector_jprofile_start_attach (); + start_sec_time = CALL_UTIL (time)(NULL); + __collector_start_time = collector_interface.getHiResTime (); + TprintfT (DBG_LT0, "\t__collector_open_experiment; resetting start_time\n"); + if (duration_string != NULL && (err = set_duration (duration_string)) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, duration_string); + return err; + } + + /* install the common SIGPROF dispatcher (requires TSD) */ + if ((err = __collector_ext_dispatcher_install ()) != COL_ERROR_NONE) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\"/></event>\n", SP_JCMD_CERROR, err); + return err; + } + + /* mark the experiment open complete */ + exp_open = 1; + if (exp_origin == SP_ORIGIN_DBX_ATTACH) + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" time=\"%lld\" tm_zone=\"%lld\"/>\n", + SP_JCMD_RUN, + (unsigned) (__collector_start_time / NANOSEC), (unsigned) (__collector_start_time % NANOSEC), + (long long) start_sec_time, (long long) 0); + else + log_write_event_run (); + + /* schedule the first sample */ + __collector_next_sample = __collector_start_time + ((hrtime_t) NANOSEC) * __collector_sample_period; + __collector_ext_usage_sample (MASTER_SMPL, "collector_open_experiment"); + + /* start data collection in dynamic modules */ + if (collector_paused == 0) + { + for (i = 0; i < nmodules; i++) + if (modules[i]->startDataCollection != NULL && modules_st[i] == 0) + modules[i]->startDataCollection (); + } + else + { + hrtime_t ts = GETRELTIME (); + (void) __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n", + SP_JCMD_PAUSE, (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC)); + } + + /* mark the experiment active */ + __collector_exp_active = 1; + return COL_ERROR_NONE; +} + +/* prepare directory for new experiment of fork-child */ + +/* return 0 if successful */ +static int +collector_create_expr_dir (const char *new_exp_name) +{ + int ret = -1; + mode_t dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + TprintfT (DBG_LT1, "collector: __collector_create_expr_dir(%s)\n", new_exp_name); + if (CALL_UTIL (mkdir)(new_exp_name, dmode) < 0) + TprintfT (0, "__collector_create_expr_dir(%s) ERROR: errno=%d\n", new_exp_name, errno); + else + ret = 0; + return (ret); +} + +/* append _xN to __collector_exp_dir_name*/ +/* return 0 if successful */ +static int +collector_exp_dir_append_x (int linenum, const char *parent_exp_name) +{ + char buffer[MAXPATHLEN + 1]; + char * p = __collector_strrchr (parent_exp_name, '/'); + if (p == NULL || (*(p + 1) != '_')) + { + size_t sz = CALL_UTIL (strlen)(parent_exp_name); + const char * q = parent_exp_name + sz - 3; + if (sz < 3 || __collector_strncmp (q, ".er", CALL_UTIL (strlen)(q)) != 0 + || CALL_UTIL (access)(parent_exp_name, F_OK) != 0) + { + TprintfT (0, "collector_exp_dir_append_x() ERROR: invalid parent_exp_name %s\n", parent_exp_name); + return -1; + } + CALL_UTIL (strlcpy)(buffer, parent_exp_name, sizeof (buffer)); + CALL_UTIL (snprintf)(__collector_exp_dir_name, sizeof (__collector_exp_dir_name), + "%s/_x%d.er", buffer, linenum); + } + else + { + p = __collector_strrchr (parent_exp_name, '.'); + if (p == NULL || *(p + 1) != 'e' || *(p + 2) != 'r') + { + TprintfT (0, "collector_exp_dir_append_x() ERROR: invalid parent_exp_name %s\n", parent_exp_name); + return -1; + } + CALL_UTIL (strlcpy)(buffer, parent_exp_name, + ((p - parent_exp_name + 1)<sizeof (buffer)) ? (p - parent_exp_name + 1) : sizeof (buffer)); + CALL_UTIL (snprintf)(__collector_exp_dir_name, sizeof (__collector_exp_dir_name), + "%s_x%d.er", buffer, linenum); + } + return 0; +} + +/* prepare directory for new experiment of exec/combo child*/ + +/* return 0 if successful */ +static int +collector_create_expr_dir_lineage (const char *parent_exp_name) +{ + int ret = -1; + mode_t dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + int linenum = 1; + while (linenum < INT_MAX) + { + if (collector_exp_dir_append_x (linenum, parent_exp_name) != 0) + return -1; + if (CALL_UTIL (access)(__collector_exp_dir_name, F_OK) != 0) + { + if (CALL_UTIL (mkdir)(__collector_exp_dir_name, dmode) == 0) + return 0; + } + linenum++; + TprintfT (DBG_LT0, "collector: collector_create_expr_dir_lineage(%s -> %s)\n", parent_exp_name, __collector_exp_dir_name); + } + return (ret); +} + +/* Finish the initializing work if we don't collect data while libcollector.so is preloaded. */ +/* return COL_ERROR_NONE if successful */ +static int +collector_tail_init (const char *parent_exp_name) +{ + int err = COL_ERROR_NONE; + if (exp_origin != SP_ORIGIN_FORK) + { + /* For exec/combo descendants. Don't create dir for this subexp, but update lineage by appending "_x0". */ + /* Different children can have the same _x0 if their name don't match -F exp. + * Assume their fork children inherit the program name, there will be no _x0_fN.er to create. + * So we don't need to worry about the lineage messed up by _x0. + */ + int linenum = 0; + if (collector_exp_dir_append_x (linenum, parent_exp_name) != 0) + return COL_ERROR_BADDIR; + static char exp_name_env[MAXPATHLEN + 1]; + CALL_UTIL (snprintf)(exp_name_env, sizeof (exp_name_env), "SP_COLLECTOR_EXPNAME=%s", __collector_exp_dir_name); + TprintfT (DBG_LT1, "collector_tail_init: setting SP_COLLECTOR_EXPNAME to %s\n", __collector_exp_dir_name); + CALL_UTIL (putenv)(exp_name_env); + } + /* initialize the segments map and mmap interposition */ + if (exp_origin != SP_ORIGIN_GENEXP && exp_origin != SP_ORIGIN_KERNEL) + if ((err = __collector_ext_mmap_install (0)) != COL_ERROR_NONE) + return err; + + /* initialize TSD module (note: relies on __collector_heap) */ + if (__collector_tsd_init () != 0) + return COL_ERROR_EXPOPEN; + + /* initialize for subsequent stack unwinds */ + __collector_ext_unwind_init (0); + + char * buf = NULL; + /* Make a copy of params so that we can modify the string */ + int paramsz = CALL_UTIL (strlen)(collector_params) + 1; + buf = (char*) alloca (paramsz); + CALL_UTIL (strlcpy)(buf, collector_params, paramsz); + + char *par_F = "0"; + char *s; + for (s = buf; *s;) + { + char key = *s++; + /* ensure that it's followed by a colon */ + if (*s++ != ':') + { + TprintfT (DBG_LT0, "collector_tail_init: ERROR: parameter %c is not followed by a colon\n", key); + return COL_ERROR_ARGS; + } + + /* find the semicolon terminator */ + char *par = s; + while (*s && (*s != ';')) + s++; + if (*s != ';') + { + /* not followed by semicolon */ + TprintfT (0, "collector_tail_init: ERROR: parameter %c:%s is not terminated by a semicolon\n", key, par); + return COL_ERROR_ARGS; + } + /* terminate par, and position for next descriptor */ + *s++ = 0; + /* now process that element of the data descriptor */ + if (key == 'F') + { + par_F = par; + break; + } + } + if ((err = __collector_ext_line_install (par_F, __collector_exp_dir_name)) != COL_ERROR_NONE) + return err; + + /* allocate tsd for the current thread */ + if (__collector_tsd_allocate () != 0) + return COL_ERROR_EXPOPEN; + return COL_ERROR_NONE; +} + +/* routines concerning closing the experiment */ +/* close down -- fini section routine */ +static void collector_fini () __attribute__ ((destructor)); +static void +collector_fini () +{ + TprintfT (DBG_LT0, "collector_fini: closing experiment\n"); + __collector_close_experiment (); + +} + +void collector_terminate_expt () __attribute__ ((weak, alias ("__collector_terminate_expt"))); + +/* __collector_terminate_expt called by user, or from dbx */ +void +__collector_terminate_expt () +{ + TprintfT (DBG_LT0, "__collector_terminate_expt: %s; calling close\n", __collector_exp_dir_name); + __collector_close_experiment (); + TprintfT (DBG_LT0, "__collector_terminate_expt done\n\n"); +} + +/* + * We manage the SIGCHLD handler with sigaction and don't worry about signal or sigset(). + * This is in line with the comments in dispatcher.c + * immediately preceding the wrapper function for (Linux) signal(). + */ +static struct sigaction original_sigchld_sigaction; +static pid_t mychild_pid = -1; + +/* __collector_SIGCHLD_signal_handler called when er_archive exits */ +static void +__collector_SIGCHLD_signal_handler (int sig, siginfo_t *si, void *context) +{ + pid_t calling_pid = si->si_pid; + /* Potential race. + * We get mychild_pid from the vfork() return value. + * So there is an outside chance that the child completes and sends SIGCHLD + * before the handler knows the value of mychild_pid. + */ + if (calling_pid == mychild_pid) + // er_archive has exited; so restore the user handler + __collector_sigaction (SIGCHLD, &original_sigchld_sigaction, NULL); + else + { + // if we can't identify the pid, the signal must be for the user's handler + if (original_sigchld_sigaction.sa_handler != SIG_DFL + && original_sigchld_sigaction.sa_handler != SIG_IGN) + original_sigchld_sigaction.sa_sigaction (sig, si, context); + } + TprintfT (DBG_LT1, "__collector_SIGCHLD_signal_handler done\n\n"); +} + +int +collector_sigchld_sigaction (const struct sigaction *nact, + struct sigaction *oact) +{ + // get the current SIGCHLD handler + struct sigaction cur_handler; + __collector_sigaction (SIGCHLD, NULL, &cur_handler); + + // if we have NOT installed our own handler, return an error + // (force the caller to deal with this case) + if (cur_handler.sa_sigaction != __collector_SIGCHLD_signal_handler) + return -1; + + // if we HAVE installed our own handler, act on the user's handler + if (oact) + __collector_memcpy (oact, &original_sigchld_sigaction, sizeof (struct sigaction)); + if (nact) + __collector_memcpy (&original_sigchld_sigaction, nact, sizeof (struct sigaction)); + return 0; +} + +/* + * __collector_close_experiment may be called either from + * __collector_terminate_expt() or the .fini section + */ +void +__collector_close_experiment () +{ + hrtime_t ts; + char *argv[10]; + int status; + TprintfT (DBG_LT1, "collector: __collector_close_experiment(): %s\n", __collector_exp_dir_name); + if (!exp_initted) + return; + /* The experiment may have been previously closed */ + if (!exp_open) + return; + + if (__collector_mutex_trylock (&__collector_close_guard)) + /* someone else is in the middle of closing the experiment */ + return; + + /* record the termination of the experiment */ + ts = GETRELTIME (); + collector_params = NULL; + + /* tell all dynamic modules to stop data collection */ + int i; + for (i = 0; i < nmodules; i++) + if (modules[i]->stopDataCollection != NULL) + modules[i]->stopDataCollection (); + + /* notify all dynamic modules the experiment is being closed */ + for (i = 0; i < nmodules; i++) + { + if (modules[i]->closeExperiment != NULL) + modules[i]->closeExperiment (); + __collector_delete_handle (modules_hndl[i]); + modules_hndl[i] = NULL; + } + + /* acquire the global lock -- only one close at a time */ + __collector_mutex_lock (&__collector_glob_lock); + /* deinstall mmap tracing (with final update) */ + __collector_ext_mmap_deinstall (1); + + /* deinstall common SIGPROF dispatcher */ + __collector_ext_dispatcher_deinstall (); + + /* disable line interposition */ + __collector_ext_line_close (); + + /* Other threads may be reading tsd now. */ + //__collector_tsd_fini(); + + /* delete global heap */ + /* omazur: do not delete the global heap + * to avoid crashes in TSD. Need a better solution. + __collector_deleteHeap( __collector_heap ); + __collector_heap = NULL; + */ + __collector_mutex_unlock (&__collector_glob_lock); + + /* take a final sample */ + __collector_ext_usage_sample (MASTER_SMPL, "collector_close_experiment"); + sample_mode = 0; + + /* close the frameinfo file */ + __collector_ext_unwind_close (); + if (exp_origin != SP_ORIGIN_DBX_ATTACH) + log_write_event_run (); + + /* mark the experiment as closed */ + __collector_expstate = EXP_CLOSED; + TprintfT (DBG_LT1, "collector: __collector_expstate->EXP_CLOSED: project_home=%s\n", + STR (project_home)); + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n", + SP_JCMD_EXIT, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC)); + + /* derive er_archive's absolute path from that of libcollector */ + argv[0] = NULL; + if (project_home && archive_mode && __collector_strcmp (archive_mode, "off")) + { + /* construct a command to launch it */ + char *er_archive_name = "/bin/gp-archive"; + size_t cmdlen = CALL_UTIL (strlen)(project_home) + CALL_UTIL (strlen)(er_archive_name) + 1; + char *command = (char*) alloca (cmdlen); + CALL_UTIL (snprintf)(command, cmdlen, "%s%s", project_home, er_archive_name); + if (CALL_UTIL (access)(command, F_OK) == 0) + { + // build the argument list + int nargs = 0; + argv[nargs++] = command; + argv[nargs++] = "-n"; + argv[nargs++] = "-a"; + argv[nargs++] = archive_mode; + size_t len = CALL_UTIL (strlen)(__collector_exp_dir_name) + 1; + size_t len1 = CALL_UTIL (strlen)(SP_ARCHIVE_LOG_FILE) + 1; + char *str = (char*) alloca (len + len1); + CALL_UTIL (snprintf)(str, len + 15, "%s/%s", __collector_exp_dir_name, SP_ARCHIVE_LOG_FILE); + argv[nargs++] = "--outfile"; + argv[nargs++] = str; + str = (char*) alloca (len); + CALL_UTIL (snprintf)(str, len, "%s", __collector_exp_dir_name); + argv[nargs++] = str; + argv[nargs] = NULL; + } + } + + /* log the archive command to be run */ + if (argv[0] == NULL) + { + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_COMMENT, COL_COMMENT_NONE, "No archive command run"); + TprintfT (DBG_LT1, "collector: No archive command run\n"); + } + else + { + char cmdbuf[4096]; + int bufoffset = 0; + int i; + for (i = 0; argv[i] != NULL; i++) + { + bufoffset += CALL_UTIL (snprintf)(&cmdbuf[bufoffset], (sizeof (cmdbuf) - bufoffset), + " %s", argv[i]); + } + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">Archive command `%s'</event>\n", + SP_JCMD_COMMENT, COL_COMMENT_NONE, cmdbuf); + TprintfT (DBG_LT1, "collector: running `%s'\n", cmdbuf); + } + log_close (); + TprintfT (DBG_LT1, "__collector_close_experiment(%s) done\n", __collector_exp_dir_name); + exp_open = 0; /* mark the experiment as closed */ + __collector_exp_active = 0; /* mark the experiment as inactive */ + + /* reset all experiment parameters */ + sample_mode = 0; + collector_paused = 0; + __collector_pause_sig = -1; + __collector_pause_sig_warn = 0; + __collector_sample_sig = -1; + __collector_sample_sig_warn = 0; + __collector_sample_period = 0; + __collector_exp_dir_name[0] = 0; + + /* uninstall the pause and sample signal handlers */ + /* XXXX -- not yet, because of potential race conditions in libthread */ + if (argv[0] == NULL) + { + /* er_archive command will not be run */ + __collector_mutex_unlock (&__collector_close_guard); + return; + } + + struct sigaction sa; + CALL_UTIL (memset)(&sa, 0, sizeof (struct sigaction)); + sa.sa_sigaction = __collector_SIGCHLD_signal_handler; + sa.sa_flags = SA_SIGINFO; + __collector_sigaction (SIGCHLD, &sa, &original_sigchld_sigaction); + + /* linetrace interposition takes care of unsetting Environment variables */ + /* create a child process to invoke er_archive */ + pid_t pid = CALL_UTIL (vfork)(); + if (pid == 0) + { + /* pid is zero == child process -- invoke er_archive */ + /* Unset LD_PRELOAD environment variables */ + CALL_UTIL (unsetenv)("LD_PRELOAD_32"); + CALL_UTIL (unsetenv)("LD_PRELOAD_64"); + CALL_UTIL (unsetenv)("LD_PRELOAD"); + /* Invoke er_archive */ + CALL_UTIL (execv)(argv[0], argv); + CALL_UTIL (exit)(1); /* exec failed -- child exits with an error */ + } + else if (pid != -1) + { + mychild_pid = pid; // notify our signal handler who the child is + pid_t w; + /* copied from system.c */ + do + { + w = CALL_UTIL (waitpid)(pid, &status, 0); + } + while (w == -1 && errno == EINTR); + TprintfT (DBG_LT1, "collector: creating archive done\n"); + // __collector_SIGCHLD_signal_handler should now be de-installed, but it does so itself + } + else + /* child-process creation failed */ + TprintfT (DBG_LT0, "collector: creating archive process failed\n"); + + __collector_mutex_unlock (&__collector_close_guard); + TprintfT (DBG_LT1, "collector: __collector_close_experiment done\n"); + return; +} + +/* + * void __collector_clean_state() + * Perform all necessary cleanup steps in child process after fork(). + */ +void +__collector_clean_state () +{ + TprintfT (DBG_LT1, "collector: collector_clean_state()\n"); + int i; + /* + * We are in child process after fork(). + * First of all we have to reset all mutex locks in collector's subsystems. + * After that we can reinitialize modules. + */ + __collector_mmgr_init_mutex_locks (__collector_heap); + __collector_mutex_init (&__collector_glob_lock); + __collector_mutex_init (&__collector_open_guard); + __collector_mutex_init (&__collector_close_guard); + __collector_mutex_init (&__collector_sample_guard); + __collector_mutex_init (&__collector_suspend_guard); + __collector_mutex_init (&__collector_resume_guard); + + if (__collector_mutex_trylock (&__collector_close_guard)) + /* someone else is in the middle of closing the experiment */ + return; + + /* Stop data collection in all dynamic modules */ + for (i = 0; i < nmodules; i++) + if (modules[i]->stopDataCollection != NULL) + modules[i]->stopDataCollection (); + + // Now we can reset modules + for (i = 0; i < nmodules; i++) + { + if (modules[i]->detachExperiment != NULL && modules_st[i] == 0) + modules[i]->detachExperiment (); + __collector_delete_handle (modules_hndl[i]); + modules_hndl[i] = NULL; + } + + /* acquire the global lock -- only one suspend at a time */ + __collector_mutex_lock (&__collector_glob_lock); + { + + /* stop any profile data writing */ + paused_when_suspended = collector_paused; + collector_paused = 1; + + /* deinstall common SIGPROF dispatcher */ + __collector_ext_dispatcher_suspend (); + + /* mark the experiment as suspended */ + __collector_exp_active = 0; + + /* XXXX mark the experiment as closed! */ + exp_open = 0; /* This is a hack to allow fork child to call__collector_open_experiment() */ + + /* mark the experiment log closed! */ + log_close (); + } + __collector_mutex_unlock (&__collector_glob_lock); + + // Now we can reset subsystems. + __collector_ext_dispatcher_fork_child_cleanup (); + __collector_mmap_fork_child_cleanup (); + __collector_tsd_fork_child_cleanup (); + paused_when_suspended = 0; + collector_paused = 0; + __collector_expstate = EXP_INIT; + TprintfT (DBG_LT1, "__collector_clean_slate: __collector_expstate->EXP_INIT\n"); + exp_origin = SP_ORIGIN_LIBCOL_INIT; + exp_initted = 0; + __collector_start_time = collector_interface.getHiResTime (); + TprintfT (DBG_LT1, " -->__collector_clean_slate; resetting start_time\n"); + start_sec_time = 0; + + /* Sample related data */ + sample_installed = 0; // 1 if the sample signal handler installed + sample_mode = 0; // dynamically turns sample record writing on/off + sample_number = 0; // index of the current sample record + __collector_sample_sig = -1; // user-specified sample signal + __collector_sample_sig_warn = 0; // non-zero if warning already given + + /* Pause/resume related data */ + __collector_pause_sig = -1; // user-specified pause signal + __collector_pause_sig_warn = 0; // non-zero if warning already given + __collector_mutex_unlock (&__collector_close_guard); + return; +} + +/* modelled on __collector_close_experiment */ +void +__collector_suspend_experiment (char *why) +{ + if (!exp_initted) + return; + /* The experiment may have been previously closed */ + if (!exp_open) + return; + /* The experiment may have been previously suspended */ + if (!__collector_exp_active) + return; + if (__collector_mutex_trylock (&__collector_suspend_guard)) + /* someone else is in the middle of suspending the experiment */ + return; + + /* Stop data collection in all dynamic modules */ + int i; + for (i = 0; i < nmodules; i++) + if (modules[i]->stopDataCollection != NULL) + modules[i]->stopDataCollection (); + + /* take a pre-suspension sample */ + __collector_ext_usage_sample (MASTER_SMPL, why); + + /* acquire the global lock -- only one suspend at a time */ + __collector_mutex_lock (&__collector_glob_lock); + /* stop any profile data writing */ + paused_when_suspended = collector_paused; + collector_paused = 1; + + /* deinstall common SIGPROF dispatcher */ + __collector_ext_dispatcher_suspend (); + + /* mark the experiment as suspended */ + __collector_exp_active = 0; + + /* XXXX mark the experiment as closed! */ + exp_open = 0; // This is a hack to allow fork child to call __collector_open_experiment() + log_pause (); // mark the experiment log closed! + TprintfT (DBG_LT0, "collector: collector_suspend_experiment(%s, %d)\n\n", why, collector_paused); + __collector_mutex_unlock (&__collector_glob_lock); + __collector_mutex_unlock (&__collector_suspend_guard); + return; +} + +void +__collector_resume_experiment () +{ + if (!exp_initted) + return; + + /* The experiment may have been previously resumed */ + if (__collector_exp_active) + return; + if (__collector_mutex_trylock (&__collector_resume_guard)) + /* someone else is in the middle of resuming the experiment */ + return; + + /* acquire the global lock -- only one resume at a time */ + __collector_mutex_lock (&__collector_glob_lock); + /* mark the experiment as re-activated */ + __collector_exp_active = 1; + /* XXXX mark the experiment as open! */ + exp_open = 1; // This is a hack to allow fork child to call__collector_open_experiment() + log_resume (); // mark the experiment log re-opened! + TprintfT (DBG_LT0, "collector: collector_resume_experiment(%d)\n", paused_when_suspended); + /* resume any profile data writing */ + collector_paused = paused_when_suspended; + /* restart common SIGPROF dispatcher */ + __collector_ext_dispatcher_restart (); + __collector_mutex_unlock (&__collector_glob_lock); + + /* take a post-suspension sample */ + __collector_ext_usage_sample (MASTER_SMPL, "collector_resume_experiment"); + + /* Resume data collection in all dynamic modules */ + if (collector_paused == 0) + { + int i; + for (i = 0; i < nmodules; i++) + if (modules[i]->startDataCollection != NULL && modules_st[i] == 0) + modules[i]->startDataCollection (); + } + + if (__collector_sample_period != 0) + { + hrtime_t now = collector_interface.getHiResTime (); + while (__collector_next_sample < now) + __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period; + } + + /* check for experiment past termination time */ + if (__collector_terminate_time != 0) + { + hrtime_t now = collector_interface.getHiResTime (); + if (__collector_terminate_time < now) + { + TprintfT (DBG_LT0, "__collector_resume_experiment: now (%lld) > terminate_time (%lld); closing experiment\n", + (now - __collector_start_time), (__collector_terminate_time - __collector_start_time)); + __collector_close_experiment (); + } + } + __collector_mutex_unlock (&__collector_resume_guard); + return; +} + +/* Code to support Samples and Pause/Resume */ +void collector_sample () __attribute__ ((weak, alias ("__collector_sample"))); +void +__collector_sample (char *name) +{ + __collector_ext_usage_sample (PROGRAM_SMPL, name); +} + +static void +write_sample (char *name) +{ + if (sample_mode == 0) + return; + /* make the sample timestamp relative to the start */ + hrtime_t ts, now = collector_interface.getHiResTime (); + + /* update time for next periodic sample */ + /* since this is common to all LWPs, and only one (the first!) will + update it to the next period, doing the update early will avoid + the overhead/frustration of the other LWPs + */ + if (__collector_sample_period != 0) + { + /* this update should only be done for periodic samples */ + while (__collector_next_sample < now) + __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period; + } + + /* take the sample and record it; use (return - __collector_start_time) for timestamp */ + now = ovw_write (); + ts = now - __collector_start_time; + + /* write sample records to log file */ + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" id=\"%d\" label=\"%s\"/>\n", + SP_JCMD_SAMPLE, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + sample_number, + name); + /* increment the sample number */ + sample_number++; +} + +/* + * __collector_ext_usage_sample + * + * Handle taking a process usage sample and recording it. + * Common to all different types of sample: + * libcollector master samples at initiation and close, + * programmatic samples via libcollector API calls, + * periodic samples originating in the dispatcher, + * manual samples originating in the signal sample handler, + * manual samples originating from the debugger + * Differentiating type and name information is currently not recorded. + */ +void +__collector_ext_usage_sample (Smpl_type type, char *name) +{ + /* name is optional */ + if (name == NULL) + name = ""; + TprintfT (DBG_LT3, "collector: __collector_ext_usage_sample(%d,%s)\n", type, name); + if (!exp_initted) + return; + + /* if paused, don't record periodic samples */ + if ((type == PERIOD_SMPL) && (collector_paused == 1)) + return; + + /* There is a possibility of entering this function + * from sample_handler, dbx direct call to __collector_sample, + * and user called collector_sample. Since we are making a + * new sample anyway just return. + */ + if (__collector_mutex_trylock (&__collector_sample_guard)) + return; + if (type != PERIOD_SMPL || __collector_sample_period != 0) + write_sample (name); + __collector_mutex_unlock (&__collector_sample_guard); +} + +/* set the sample period from the parameter */ +static int +sample_set_interval (char *param) +{ + if (!exp_initted) + return COL_ERROR_SMPLINIT; + __collector_sample_period = CALL_UTIL (strtol)(param, NULL, 0); /* seconds */ + TprintfT (DBG_LT1, "collector: collector_sample period set to %d seconds.\n", + __collector_sample_period); + if (__collector_sample_period > 0) + (void) __collector_log_write ("<setting %s=\"%d\"/>\n", + SP_JCMD_SAMPLE_PERIOD, __collector_sample_period); + return COL_ERROR_NONE; +} + +/* set the experiment duration from the parameter */ + +/* parameter is of the form nnn:mmm, where nnn is the start delay in seconds, + * and mmm is the terminate time in seconds; if nnn is zero, + * data collection starts when the run starts. If mmm is zero, + * data collection terminates when the run terminates. Otherwise, + * nnn must be less than mmm + */ +static int +set_duration (char *param) +{ + if (!exp_initted) + return COL_ERROR_DURATION_INIT; + int delay_start = CALL_UTIL (strtol)(param, ¶m, 0); /* seconds */ + int terminate_duration = 0; + if (*param == 0) + { + /* we only have one parameter, the terminate time */ + terminate_duration = delay_start; + delay_start = 0; + } + else if (*param == ':') + { + param++; + terminate_duration = CALL_UTIL (strtol)(param, ¶m, 0); /* seconds */ + } + else + return COL_ERROR_DURATION_INIT; + TprintfT (DBG_LT1, "collector: collector_delay_start duration set to %d seconds.\n", + delay_start); + TprintfT (DBG_LT1, "collector: collector_terminate duration set to %d seconds.\n", + terminate_duration); + if (terminate_duration > 0) + __collector_log_write ("<setting %s=\"%d\"/>\n<setting %s=\"%d\"/>\n", + SP_JCMD_DELAYSTART, delay_start, + SP_JCMD_TERMINATE, terminate_duration); + __collector_delay_start = (hrtime_t) 0; + if (delay_start != 0) + { + __collector_delay_start = __collector_start_time + ((hrtime_t) NANOSEC) * delay_start; + collector_paused = 1; + } + __collector_terminate_time = terminate_duration == 0 ? (hrtime_t) 0 : + __collector_start_time + ((hrtime_t) NANOSEC) * terminate_duration; + return COL_ERROR_NONE; +} + +static int +sample_set_user_sig (char *par) +{ + int sig = CALL_UTIL (strtol)(par, &par, 0); + TprintfT (DBG_LT1, "collector: sample_set_user_sig(sig=%d,installed=%d)\n", + sig, sample_installed); + /* Installing the sampling signal handler more + * than once is not good. + */ + if (!sample_installed) + { + struct sigaction act; + sigemptyset (&act.sa_mask); + /* XXXX should any signals be blocked? */ + act.sa_sigaction = sample_handler; + act.sa_flags = SA_RESTART | SA_SIGINFO; + if (sigaction (sig, &act, &old_sample_handler) == -1) + { + TprintfT (DBG_LT0, "collector: ERROR: collector_sample_handler install failed (sig=%d).\n", + __collector_sample_sig); + return COL_ERROR_ARGS; + } + if (old_sample_handler.sa_handler == SIG_DFL || + old_sample_handler.sa_sigaction == sample_handler) + old_sample_handler.sa_handler = SIG_IGN; + TprintfT (DBG_LT1, "collector: collector_sample_handler installed (sig=%d,hndlr=0x%p).\n", + sig, sample_handler); + __collector_sample_sig = sig; + sample_installed = 1; + } + (void) __collector_log_write ("<setting %s=\"%u\"/>\n", SP_JCMD_SAMPLE_SIG, __collector_sample_sig); + return COL_ERROR_NONE; +} + +/* signal handler for sample signal */ +static void +sample_handler (int sig, siginfo_t *sip, void *uap) +{ + if (sip && sip->si_code == SI_USER) + { + TprintfT (DBG_LT1, "collector: collector_sample_handler sampling!\n"); + __collector_ext_usage_sample (MANUAL_SMPL, "signal"); + } + else if (old_sample_handler.sa_handler != SIG_IGN) + { + TprintfT (DBG_LT1, "collector: collector_sample_handler forwarding signal.\n"); + (old_sample_handler.sa_sigaction)(sig, sip, uap); + } +} + +void collector_pause () __attribute__ ((weak, alias ("__collector_pause"))); + +void +__collector_pause () +{ + __collector_pause_m ("API"); +} + +void +__collector_pause_m (char *reason) +{ + hrtime_t now; + char xreason[MAXPATHLEN]; + TprintfT (DBG_LT0, "collector: __collector_pause_m(%s)\n", reason); + + /* Stop data collection in all dynamic modules */ + for (int i = 0; i < nmodules; i++) + if (modules[i]->stopDataCollection != NULL) + modules[i]->stopDataCollection (); + + /* Take a pause sample */ + CALL_UTIL (snprintf)(xreason, sizeof (xreason), "collector_pause(%s)", reason); + __collector_ext_usage_sample (MASTER_SMPL, xreason); + + /* Record the event in the log file */ + now = GETRELTIME (); + (void) __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" name=\"%s\"/>\n", SP_JCMD_PAUSE, + (unsigned) (now / NANOSEC), (unsigned) (now % NANOSEC), reason); + __collector_expstate = EXP_PAUSED; + TprintfT (DBG_LT1, "collector: __collector_expstate->EXP_PAUSED\n"); + collector_paused = 1; +} + +void collector_resume () __attribute__ ((weak, alias ("__collector_resume"))); + +void +__collector_resume () +{ + TprintfT (DBG_LT0, "collector: __collector_resume()\n"); + __collector_expstate = EXP_OPEN; + TprintfT (DBG_LT1, "collector: __collector_expstate->EXP_OPEN\n"); + + /* Record the event in the log file */ + hrtime_t now = GETRELTIME (); + (void) __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n", SP_JCMD_RESUME, + (unsigned) (now / NANOSEC), (unsigned) (now % NANOSEC)); + /* Take a resume sample */ + __collector_ext_usage_sample (MASTER_SMPL, "collector_resume"); + + /* Resume data collection in all dynamic modules */ + for (int i = 0; i < nmodules; i++) + if (modules[i]->startDataCollection != NULL && modules_st[i] == 0) + modules[i]->startDataCollection (); + collector_paused = 0; +} + +static int +pause_set_user_sig (char *par) +{ + struct sigaction act; + int sig = CALL_UTIL (strtol)(par, &par, 0); + if (*par) + { + /* not end of the token */ + if (*par != 'p') + { + /* it should be a p */ + TprintfT (DBG_LT0, "collector: ERROR: collector_user_handler bad terminator (par=%p[0]=%d).\n", + par, (int) *par); + return COL_ERROR_ARGS; + + } + else + { + /*, it's a p, make sure next is end of token */ + par++; + if (*par) + { + TprintfT (DBG_LT0, "collector: ERROR: collector_user_handler bad terminator (par=%p[0]=%d).\n", + par, (int) *par); + return COL_ERROR_ARGS; + } + else + /* start off paused */ + collector_paused = 1; + } + } + sigemptyset (&act.sa_mask); + /* XXXX should any signals be blocked? */ + act.sa_sigaction = pause_handler; + act.sa_flags = SA_RESTART | SA_SIGINFO; + if (sigaction (sig, &act, &old_pause_handler) == -1) + { + TprintfT (DBG_LT0, "collector: ERROR: collector_pause_handler install failed (sig=%d).\n", sig); + return COL_ERROR_ARGS; + } + if (old_pause_handler.sa_handler == SIG_DFL || + old_pause_handler.sa_sigaction == pause_handler) + old_pause_handler.sa_handler = SIG_IGN; + TprintfT (DBG_LT1, "collector: collector_pause_handler installed (sig=%d,hndlr=0x%p).\n", + sig, pause_handler); + __collector_pause_sig = sig; + (void) __collector_log_write ("<setting %s=\"%u\"/>\n", SP_JCMD_PAUSE_SIG, + __collector_pause_sig); + return COL_ERROR_NONE; +} + +/* signal handler for pause/resume signal */ +static void +pause_handler (int sig, siginfo_t *sip, void *uap) +{ + if (sip && sip->si_code == SI_USER) + { + if (collector_paused == 1) + { + __collector_resume (); + TprintfT (DBG_LT0, "collector: collector_pause_handler resumed!\n"); + } + else + { + __collector_pause_m ("signal"); + TprintfT (DBG_LT0, "collector: collector_pause_handler paused!\n"); + } + } + else if (old_pause_handler.sa_handler != SIG_IGN) + { + TprintfT (DBG_LT0, "collector: collector_pause_handler forwarding signal.\n"); + (old_pause_handler.sa_sigaction)(sig, sip, uap); + } +} + +static void +get_progspec (char *retstr, int tmp_sz, char *name, int name_sz) +{ + int procfd, count, i; + *retstr = 0; + tmp_sz--; + *name = 0; + name_sz--; + procfd = CALL_UTIL (open)("/proc/self/cmdline", O_RDONLY); + int getting_name = 0; + if (procfd != -1) + { + count = CALL_UTIL (read)(procfd, retstr, tmp_sz); + retstr[count] = '\0'; + for (i = 0; i < count; i++) + { + if (getting_name == 0) + name[i] = retstr[i]; + if (retstr[i] == '\0') + { + getting_name = 1; + if ((i + 1) < count) + retstr[i] = ' '; + } + } + CALL_UTIL (close)(procfd); + } +} + +static void +fs_warn () +{ + /* if data implies we don't care, just return */ + if (fs_matters == 0) + return; +} + +static void +close_handler (int sig, siginfo_t *sip, void *uap) +{ + if (sip && sip->si_code == SI_USER) + { + TprintfT (DBG_LT0, "collector: close_handler: processing signal.\n"); + __collector_close_experiment (); + } + else if (old_close_handler.sa_handler != SIG_IGN) + { + TprintfT (DBG_LT0, "collector: close_handler forwarding signal.\n"); + (old_close_handler.sa_sigaction)(sig, sip, uap); + } +} + +static void +exit_handler (int sig, siginfo_t *sip, void *uap) +{ + if (sip && sip->si_code == SI_USER) + { + TprintfT (DBG_LT0, "collector: exit_handler: processing signal.\n"); + CALL_UTIL (exit)(1); + } + else if (old_exit_handler.sa_handler != SIG_IGN) + { + TprintfT (DBG_LT0, "collector: exit_handler forwarding signal.\n"); + (old_exit_handler.sa_sigaction)(sig, sip, uap); + } +} + +static int +set_user_sig_action (char *par) +{ + int sig = CALL_UTIL (strtol)(par, &par, 0); + if (*par != '=') + { + TprintfT (DBG_LT0, "collector: ERROR: set_user_sig_action bad separator: %s.\n", par); + return COL_ERROR_ARGS; + } + par++; + struct sigaction act; + sigemptyset (&act.sa_mask); + act.sa_flags = SA_RESTART | SA_SIGINFO; + if (__collector_strcmp (par, "exit") == 0) + { + act.sa_sigaction = exit_handler; + if (sigaction (sig, &act, &old_exit_handler) == -1) + { + TprintfT (DBG_LT0, "collector: ERROR: set_user_sig_action failed: %d=%s.\n", sig, par); + return COL_ERROR_ARGS; + } + } + else if (__collector_strcmp (par, "close") == 0) + { + act.sa_sigaction = close_handler; + if (sigaction (sig, &act, &old_close_handler) == -1) + { + TprintfT (DBG_LT0, "collector: ERROR: set_user_sig_action failed: %d=%s.\n", sig, par); + return COL_ERROR_ARGS; + } + } + else + { + TprintfT (DBG_LT0, "collector: ERROR: set_user_sig_action unknown action: %d=%s.\n", sig, par); + return COL_ERROR_ARGS; + } + __collector_log_write ("<setting signal=\"%u\" action=\"%s\"/>\n", sig, par); + return COL_ERROR_NONE; +} + +/*============================================================*/ +/* + * Routines for handling the log file + */ +static struct DataHandle *log_hndl = NULL; +static int log_initted = 0; +static int log_enabled = 0; + +static int +log_open () +{ + log_hndl = __collector_create_handle (SP_LOG_FILE); + if (log_hndl == NULL) + return COL_ERROR_LOG_OPEN; + log_initted = 1; + log_enabled = 1; + TprintfT (DBG_LT1, "log_open()\n"); + return COL_ERROR_NONE; +} + +static void +log_header_write (sp_origin_t origin) +{ + __collector_log_write ("<experiment %s=\"%d.%d\">\n", + SP_JCMD_VERSION, SUNPERF_VERNUM, SUNPERF_VERNUM_MINOR); + __collector_log_write ("<collector>%s</collector>\n", VERSION); + __collector_log_write ("</experiment>\n"); + + struct utsname sysinfo; + if (uname (&sysinfo) < 0) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\"/></event>\n", SP_JCMD_CERROR, COL_ERROR_SYSINFO, errno); + __collector_log_write ("<system>\n"); + } + else + { + long page_size = CALL_UTIL (sysconf)(_SC_PAGESIZE); + long npages = CALL_UTIL (sysconf)(_SC_PHYS_PAGES); + __collector_log_write ("<system hostname=\"%s\" arch=\"%s\" os=\"%s %s\" pagesz=\"%ld\" npages=\"%ld\">\n", + sysinfo.nodename, sysinfo.machine, sysinfo.sysname, sysinfo.release, page_size, npages); + } + + //YXXX Updating this section? Check similar cut/paste code in: + // collctrl.cc::Coll_Ctrl() + // collector.c::log_header_write() + // cpu_frequency.h::get_cpu_frequency() + + FILE *procf = CALL_UTIL (fopen)("/proc/cpuinfo", "r"); + if (procf != NULL) + { + char temp[1024]; + int cpu = -1; + while (CALL_UTIL (fgets)(temp, sizeof (temp), procf) != NULL) + { +#if ARCH(Intel) + if (__collector_strStartWith (temp, "processor") == 0) + { + char *val = CALL_UTIL (strchr)(temp, ':'); + cpu = val ? CALL_UTIL (atoi)(val + 1) : -1; + } + // else if ( __collector_strStartWith(temp, "model") == 0 + // && CALL_UTIL(strstr)(temp, "name") == 0) { + // char *val = CALL_UTIL(strchr)( temp, ':' ); + // int model = val ? CALL_UTIL(atoi)( val + 1 ) : -1; + // } + // else if ( __collector_strStartWith(temp, "cpu family") == 0 ) { + // char *val = CALL_UTIL(strchr)( temp, ':' ); + // int family = val ? CALL_UTIL(atoi)( val + 1 ) : -1; + // } + else if (__collector_strStartWith (temp, "cpu MHz") == 0) + { + char *val = CALL_UTIL (strchr)(temp, ':'); + int mhz = val ? CALL_UTIL (atoi)(val + 1) : 0; /* reading it as int is fine */ + (void) __collector_log_write (" <cpu id=\"%d\" clk=\"%d\"/>\n", cpu, mhz); + } +#elif ARCH(SPARC) + if (__collector_strStartWith (temp, "Cpu") == 0 && + temp[3] != '\0' && + __collector_strStartWith ((CALL_UTIL (strchr)(temp + 1, 'C')) ? CALL_UTIL (strchr)(temp + 1, 'C') : (temp + 4), "ClkTck") == 0) + { // sparc-Linux + char *val = CALL_UTIL (strchr)(temp, ':'); + int mhz = 0; + if (val) + { + unsigned long long freq; + (*__collector_sscanfp) (val + 2, "%llx", &freq); + mhz = (unsigned int) (((double) freq) / 1000000.0 + 0.5); + } + char *numend = CALL_UTIL (strchr)(temp + 1, 'C') ? CALL_UTIL (strchr)(temp + 1, 'C') : (temp + 4); + *numend = '\0'; + cpu = CALL_UTIL (atoi)(temp + 3); + __collector_log_write (" <cpu id=\"%d\" clk=\"%d\"/>\n", cpu, mhz); + } +#elif defined(__aarch64__) + if (__collector_strStartWith (temp, "processor") == 0) + { + char *val = CALL_UTIL (strchr)(temp, ':'); + cpu = val ? CALL_UTIL (atoi)(val + 1) : -1; + if (cpu != -1) + { + unsigned int mhz; + asm volatile("mrs %0, cntfrq_el0" : "=r" (mhz)); + __collector_log_write (" <cpu id=\"%d\" clk=\"%d\"/>\n", cpu, + mhz / 1000000); + } + } +#endif + } + CALL_UTIL (fclose)(procf); + } + __collector_log_write ("</system>\n"); + __collector_log_write ("<process pid=\"%d\"></process>\n", getpid ()); + __collector_log_write ("<process ppid=\"%d\"></process>\n", getppid ()); + __collector_log_write ("<process pgrp=\"%d\"></process>\n", getpgrp ()); + __collector_log_write ("<process sid=\"%d\"></process>\n", getsid (0)); + + /* XXX -- cwd commented out + It would be nice to get the current directory for the experiment, + but neither method below will work--the /proc method returns a + 0-length string, and using getcwd will break collect on /bin/sh + (as cuserid does) because of /bin/sh's private malloc + omazur: readlink seems to work on Linux + */ + /* write the current directory */ + char cwd[MAXPATHLEN + 1]; + int i = readlink ("/proc/self/cwd", cwd, sizeof (cwd)); + if (i >= 0) + { + cwd[i < sizeof (cwd) ? i : sizeof (cwd) - 1] = 0; + (void) __collector_log_write ("<process cwd=\"%s\"></process>\n", cwd); + } + (void) __collector_log_write ("<process wsize=\"%d\"></process>\n", (int) (8 * sizeof (void *))); + + ucontext_t ucp; + ucp.uc_stack.ss_sp = NULL; + ucp.uc_stack.ss_size = 0; + if (getcontext (&ucp) == 0) + { + (void) __collector_log_write ("<process stackbase=\"0x%lx\"></process>\n", + (unsigned long) ucp.uc_stack.ss_sp + ucp.uc_stack.ss_size); + } + + (void) __collector_log_write ("<process>%s</process>\n", + origin == SP_ORIGIN_FORK ? "(fork)" : exp_progspec); + __collector_libthread_T1 = 0; +} + +static void +log_pause (void) +{ + if (log_initted) + log_enabled = 0; +} + +static void +log_resume (void) +{ + if (log_initted) + log_enabled = 1; +} + +/* __collector_log_write -- write a line to the log file + * return value: + * 0 if OK + * 1 if error (in creating or extending the log file) + */ +int +__collector_log_write (char *format, ...) +{ + char buf[4096]; + va_list va; + int rc = 0; + static size_t loglen = 0; + + va_start (va, format); + char *bufptr = buf; + int sz = __collector_xml_vsnprintf (bufptr, sizeof (buf), format, va); + int allocated_sz = 0; + va_end (va); + if (sz >= sizeof (buf)) + { + /* Allocate a new buffer. + * We need this buffer only temporarily and locally. + * But don't use the thread stack + * since it already has buf + * and is unlikely to have additonal room for something even larger than buf. + */ + sz += 1; /* add the terminating null byte */ + bufptr = (char*) __collector_allocCSize (__collector_heap, sz, 0); + if (bufptr) + { + allocated_sz = sz; + va_start (va, format); + sz = __collector_xml_vsnprintf (bufptr, sz, format, va); + va_end (va); + } + } + int newlen = CALL_UTIL (strlen)(bufptr); + if (sz != newlen) + // no need to free bufptr if we're going to abort anyhow + abort (); + bufptr[newlen + 1] = 0; + loglen = loglen + newlen; + TprintfT (DBG_LT2, "__collector_log_write len=%ld, loglen=%ld %s", + (long) newlen, (long) loglen, bufptr); + if (log_enabled <= 0) + { +#if 0 + /* XXX suppress log_write messages with no log file open + * this is reached from SimApp dealing with the clock frequency, which it should + * not be doing. For now, don't write a message. + */ + CALL_UTIL (fprintf)(stderr, "__collector_log_write COL_ERROR_LOG_OPEN: %s", buf); +#endif + } + else + rc = __collector_write_string (log_hndl, bufptr, sz); + if (allocated_sz) + __collector_freeCSize (__collector_heap, (void *) bufptr, allocated_sz); + return rc; +} + +static void +log_close () +{ + log_enabled = 0; + log_initted = 0; + __collector_delete_handle (log_hndl); + log_hndl = NULL; +} + +/*============================================================*/ +/* + * Routines for handling the overview file + */ +static void +ovw_open () +{ + CALL_UTIL (strlcpy)(ovw_name, __collector_exp_dir_name, sizeof (ovw_name)); + CALL_UTIL (strlcat)(ovw_name, "/", sizeof (ovw_name)); + CALL_UTIL (strlcat)(ovw_name, SP_OVERVIEW_FILE, sizeof (ovw_name)); + int fd = CALL_UTIL (open)(ovw_name, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, ovw_name); + return; + } + CALL_UTIL (close)(fd); + sample_mode = 1; +} + +static __inline__ void +timeval_to_timespec(struct timeval *tval, struct timespec *value) +{ + value->tv_nsec = tval->tv_usec * 1000; + value->tv_sec = tval->tv_sec; +} + +/* + * Resource usage. /proc/<pid>/usage /proc/<pid>/lwp/<lwpid>/lwpusage + */ +typedef struct prusage +{ + id_t pr_lwpid; /* lwp id. 0: process or defunct */ + int pr_count; /* number of contributing lwps */ + timestruc_t pr_tstamp; /* current time stamp */ + timestruc_t pr_create; /* process/lwp creation time stamp */ + timestruc_t pr_term; /* process/lwp termination time stamp */ + timestruc_t pr_rtime; /* total lwp real (elapsed) time */ + timestruc_t pr_utime; /* user level cpu time */ + timestruc_t pr_stime; /* system call cpu time */ + timestruc_t pr_ttime; /* other system trap cpu time */ + timestruc_t pr_tftime; /* text page fault sleep time */ + timestruc_t pr_dftime; /* data page fault sleep time */ + timestruc_t pr_kftime; /* kernel page fault sleep time */ + timestruc_t pr_ltime; /* user lock wait sleep time */ + timestruc_t pr_slptime; /* all other sleep time */ + timestruc_t pr_wtime; /* wait-cpu (latency) time */ + timestruc_t pr_stoptime; /* stopped time */ + timestruc_t filltime[6]; /* filler for future expansion */ + ulong_t pr_minf; /* minor page faults */ + ulong_t pr_majf; /* major page faults */ + ulong_t pr_nswap; /* swaps */ + ulong_t pr_inblk; /* input blocks */ + ulong_t pr_oublk; /* output blocks */ + ulong_t pr_msnd; /* messages sent */ + ulong_t pr_mrcv; /* messages received */ + ulong_t pr_sigs; /* signals received */ + ulong_t pr_vctx; /* voluntary context switches */ + ulong_t pr_ictx; /* involuntary context switches */ + ulong_t pr_sysc; /* system calls */ + ulong_t pr_ioch; /* chars read and written */ + ulong_t filler[10]; /* filler for future expansion */ +} prusage_t; + +static hrtime_t starttime = 0; + +static hrtime_t +ovw_write () +{ + if (sample_mode == 0) + return 0; + int fd; + int res; + struct prusage usage; + struct rusage rusage; + hrtime_t hrt, delta; + + /* Fill in the prusage structure with info from getrusage() */ + hrt = collector_interface.getHiResTime (); + if (starttime == 0) + starttime = hrt; + res = getrusage (RUSAGE_SELF, &rusage); + if (res != 0) + { + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_OVWREAD, errno, ovw_name); + return ( hrt); + } + + CALL_UTIL (memset)(&usage, 0, sizeof (struct prusage)); + usage.pr_lwpid = getpid (); + usage.pr_count = 1; + usage.pr_tstamp.tv_sec = hrt / NANOSEC; + usage.pr_tstamp.tv_nsec = hrt % NANOSEC; + usage.pr_create.tv_sec = starttime / NANOSEC; + usage.pr_create.tv_nsec = starttime % NANOSEC; + delta = hrt - starttime; + usage.pr_rtime.tv_sec = delta / NANOSEC; + usage.pr_rtime.tv_nsec = delta % NANOSEC; + timeval_to_timespec (&rusage.ru_utime, &usage.pr_utime); + timeval_to_timespec (&rusage.ru_stime, &usage.pr_stime); + + /* make sure that user- and system cpu time are not negative */ + if (ts2hrt (usage.pr_utime) < 0) + { + usage.pr_utime.tv_sec = 0; + usage.pr_utime.tv_nsec = 0; + } + if (ts2hrt (usage.pr_stime) < 0) + { + usage.pr_stime.tv_sec = 0; + usage.pr_stime.tv_nsec = 0; + } + + /* fill in other fields */ + usage.pr_minf = (ulong_t) rusage.ru_minflt; + usage.pr_majf = (ulong_t) rusage.ru_majflt; + usage.pr_nswap = (ulong_t) rusage.ru_nswap; + usage.pr_inblk = (ulong_t) rusage.ru_inblock; + usage.pr_oublk = (ulong_t) rusage.ru_oublock; + usage.pr_msnd = (ulong_t) rusage.ru_msgsnd; + usage.pr_mrcv = (ulong_t) rusage.ru_msgrcv; + usage.pr_sigs = (ulong_t) rusage.ru_nsignals; + usage.pr_vctx = (ulong_t) rusage.ru_nvcsw; + usage.pr_ictx = (ulong_t) rusage.ru_nivcsw; + + fd = CALL_UTIL (open)(ovw_name, O_WRONLY | O_APPEND); + if (fd < 0) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, ovw_name); + return ( ts2hrt (usage.pr_tstamp)); + } + + CALL_UTIL (lseek)(fd, 0, SEEK_END); + res = CALL_UTIL (write)(fd, &usage, sizeof (usage)); + CALL_UTIL (close)(fd); + if (res != sizeof (usage)) + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_OVWWRITE, errno, ovw_name); + return (hrt); +} + +void +__collector_dlog (int tflag, int level, char *format, ...) +{ + if ((tflag & SP_DUMP_FLAG) == 0) + { + if (level > __collector_tracelevel) + return; + } + else if ((tflag & collector_debug_opt) == 0) + return; + + /* In most cases this allocation should suffice */ + int bufsz = CALL_UTIL (strlen)(format) + 128; + char *buf = (char*) alloca (bufsz); + char *p = buf; + int left = bufsz; + if ((tflag & SP_DUMP_NOHEADER) == 0) + { + p += CALL_UTIL (snprintf)(p, left, "P%d,L%02u,t%02lu", + (int) getpid (), + (unsigned int) __collector_lwp_self (), + __collector_no_threads ? 0 : __collector_thr_self ()); + left = bufsz - (p - buf); + if (tflag) + { + hrtime_t ts = GETRELTIME (); + p += CALL_UTIL (snprintf)(p, left, " %u.%09u ", (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC)); + } + else + p += CALL_UTIL (snprintf)(p, left, ": "); + left = bufsz - (p - buf); + } + + va_list va; + va_start (va, format); + int nbufsz = CALL_UTIL (vsnprintf)(p, left, format, va); + va_end (va); + + if (nbufsz >= left) + { + /* Allocate a new buffer */ + nbufsz += 1; /* add the terminating null byte */ + char *nbuf = (char*) alloca (nbufsz + (p - buf)); + __collector_memcpy (nbuf, buf, p - buf); + p = nbuf + (p - buf); + + va_start (va, format); + nbufsz = CALL_UTIL (vsnprintf)(p, nbufsz, format, va); + va_end (va); + buf = nbuf; + } + CALL_UTIL (write)(2, buf, CALL_UTIL (strlen)(buf)); +} + +/*============================================================*/ +#if ! ARCH(SPARC) /* !sparc-Linux */ +/* + * Routines for handling _exit and _Exit + */ +/*------------------------------------------------------------- _exit */ + +#define CALL_REAL(x) (*(int(*)())__real_##x) +#define NULL_PTR(x) ( __real_##x == NULL ) + +static void *__real__exit = NULL; /* libc only: _exit */ +static void *__real__Exit = NULL; /* libc only: _Exit */ +void _exit () __attribute__ ((weak, alias ("__collector_exit"))); +void _Exit () __attribute__ ((weak, alias ("__collector_Exit"))); + +void +__collector_exit (int status) +{ + if (NULL_PTR (_exit)) + { + __real__exit = dlsym (RTLD_NEXT, "_exit"); + if (__real__exit == NULL) + __real__exit = dlsym (RTLD_DEFAULT, "_exit"); + } + TprintfT (DBG_LT1, "__collector_exit() interposing @0x%p __real__exit\n", __real__exit); + __collector_terminate_expt (); + TprintfT (DBG_LT1, "__collector_exit(): experiment terminated\n"); + CALL_REAL (_exit)(status); // this will exit the process +} + +void +__collector_Exit (int status) +{ + if (NULL_PTR (_Exit)) + { + __real__Exit = dlsym (RTLD_NEXT, "_Exit"); + if (__real__Exit == NULL) + __real__Exit = dlsym (RTLD_DEFAULT, "_exit"); + } + TprintfT (DBG_LT1, "__collector_Exit() interposing @0x%p __real__Exit\n", __real__Exit); + __collector_terminate_expt (); + TprintfT (DBG_LT1, "__collector_Exit(): experiment terminated\n"); + CALL_REAL (_Exit)(status); // this will exit the process +} +#endif /* !sparc-Linux */ diff --git a/gprofng/libcollector/collector.h b/gprofng/libcollector/collector.h new file mode 100644 index 0000000..c54568d --- /dev/null +++ b/gprofng/libcollector/collector.h @@ -0,0 +1,236 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef _COLLECTOR_H +#define _COLLECTOR_H + +#include <ucontext.h> +#include <signal.h> + +#include "gp-defs.h" +#include "data_pckts.h" +#include "libcol_util.h" +#include "collector_module.h" + +#define GETRELTIME() (__collector_gethrtime() - __collector_start_time) + +extern hrtime_t __collector_start_time; + +/* ========================================================== */ +/* ------- internal function prototypes ----------------- */ +/* These will not be exported from libcollector.so */ +struct DataHandle; +struct Heap; +extern struct DataHandle *__collector_create_handle (char*); +extern void __collector_delete_handle (struct DataHandle*); +extern int __collector_write_record (struct DataHandle*, Common_packet*); +extern int __collector_write_packet (struct DataHandle*, CM_Packet*); +extern int __collector_write_string (struct DataHandle*, char*, int); +extern FrameInfo __collector_get_frame_info (hrtime_t, int, void *); +extern FrameInfo __collector_getUID (CM_Array *arg, FrameInfo uid); +extern int __collector_getStackTrace (void *buf, int size, void *bptr, void *eptr, void *arg); +extern void *__collector_ext_return_address (unsigned level); +extern void __collector_mmap_fork_child_cleanup (); + +extern int __collector_ext_mmap_install (int); +extern int __collector_ext_mmap_deinstall (int); +extern int __collector_ext_update_map_segments (void); +extern int __collector_check_segment (unsigned long addr, + unsigned long *base, + unsigned long *end, int maxnretries); +extern int __collector_check_readable_segment (unsigned long addr, + unsigned long *base, + unsigned long *end, int maxnretries); +extern int __collector_ext_line_init (int * pfollow_this_experiment, + const char * progspec, + const char *progname); +extern int __collector_ext_line_install (char *, const char *); +extern void __collector_ext_line_close (); +extern void __collector_ext_unwind_init (int); +extern void __collector_ext_unwind_close (); +extern int __collector_ext_jstack_unwind (char*, int, ucontext_t *); +extern void __collector_ext_dispatcher_fork_child_cleanup (); +extern void __collector_ext_unwind_key_init (int isPthread, void * stack); +extern void __collector_ext_dispatcher_tsd_create_key (); +extern void __collector_ext_dispatcher_thread_timer_suspend (); +extern int __collector_ext_dispatcher_thread_timer_resume (); +extern int __collector_ext_dispatcher_install (); +extern void __collector_ext_dispatcher_suspend (); +extern void __collector_ext_dispatcher_restart (); +extern void __collector_ext_dispatcher_deinstall (); +extern void __collector_ext_usage_sample (Smpl_type type, char *name); +extern void __collector_ext_profile_handler (siginfo_t *, ucontext_t *); +extern int __collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg, + va_list va /* pid_t *ptid, struct user_desc *tlspid_t *" ctid" */); + +/* D-light related functions */ +extern int __collector_sigprof_install (); +extern int __collector_ext_hwc_active (); +extern void __collector_ext_hwc_check (siginfo_t *, ucontext_t *); +extern int __collector_ext_hwc_lwp_init (); +extern void __collector_ext_hwc_lwp_fini (); +extern int __collector_ext_hwc_lwp_suspend (); +extern int __collector_ext_hwc_lwp_resume (); +extern int (*__collector_VM_ReadByteInstruction)(unsigned char *); +extern int (*__collector_omp_stack_trace)(char*, int, hrtime_t, void*); +extern hrtime_t (*__collector_gethrtime)(); +extern int (*__collector_mpi_stack_trace)(char*, int, hrtime_t); +extern int __collector_open_experiment (const char *exp, const char *par, sp_origin_t origin); +extern void __collector_suspend_experiment (char *why); +extern void __collector_resume_experiment (); +extern void __collector_clean_state (); +extern void __collector_close_experiment (); +extern void __collector_terminate_expt (); +extern void __collector_terminate_hook (); +extern void __collector_sample (char *name); +extern void __collector_pause (); +extern void __collector_pause_m (); +extern void __collector_resume (); +extern int collector_sigemt_sigaction (const struct sigaction*, + struct sigaction*); +extern int collector_sigchld_sigaction (const struct sigaction*, + struct sigaction*); + +extern int +__collector_log_write (char *format, ...) __attribute__ ((format (printf, 1, 2))); + +/* ------- internal global data ----------------- */ +/* These will not be exported from libcollector.so */ +extern struct Heap *__collector_heap; + +/* experiment state flag */ +typedef enum +{ + EXP_INIT, EXP_OPEN, EXP_PAUSED, EXP_CLOSED +} sp_state_t; +extern volatile sp_state_t __collector_expstate; + +/* global flag, defines whether target is threaded or not + * if set, put _lwp_self() for thread id instead of thr_self() + * in output packets; should be set before any data packets + * are written, i.e., before signal handlers are installed. + */ +extern int __collector_no_threads; +extern int __collector_libthread_T1; /* T1 or not T1 */ +extern int __collector_sample_sig; /* set to signal used to trigger a sample */ +extern int __collector_sample_sig_warn; /* if 1, warning given on target use */ +extern int __collector_pause_sig; /* set to signal used to toggle pause-resume */ +extern int __collector_pause_sig_warn; /* if 1, warning given on target use */ +extern hrtime_t __collector_delay_start; +extern int __collector_exp_active; + +/* global hrtime_t for next periodic sample */ +extern hrtime_t __collector_next_sample; +extern int __collector_sample_period; + +/* global hrtime_t for experiment termination (-t) */ +extern hrtime_t __collector_terminate_time; +extern int __collector_terminate_duration; +extern char __collector_exp_dir_name[]; +extern int __collector_java_mode; +extern int __collector_java_asyncgetcalltrace_loaded; +extern int __collector_jprofile_start_attach (); + +/* --------- information controlling debug tracing ------------- */ + +/* global flag, defines level of trace information */ +extern void __collector_dlog (int, int, char *, ...) __attribute__ ((format (printf, 3, 4))); + +#define STR(x) ((x) ? (x) : "NULL") + +// To set collector_debug_opt use: +// SP_COLLECTOR_DEBUG=4 ; export SP_COLLECTOR_DEBUG ; collect ... +enum +{ + SP_DUMP_TIME = 1, + SP_DUMP_FLAG = 2, + SP_DUMP_JAVA = 4, + SP_DUMP_NOHEADER = 8, + SP_DUMP_UNWIND = 16, + SP_DUMP_STACK = 32, +}; + +#ifndef DEBUG +#define DprintfT(flag, ...) +#define tprintf(...) +#define Tprintf(...) +#define TprintfT(...) + +#else +#define DprintfT(flag, ...) __collector_dlog(SP_DUMP_FLAG | (flag), 0, __VA_ARGS__ ) +#define tprintf(...) __collector_dlog( SP_DUMP_NOHEADER, __VA_ARGS__ ) +#define Tprintf(...) __collector_dlog( 0, __VA_ARGS__ ) +#define TprintfT(...) __collector_dlog( SP_DUMP_TIME, __VA_ARGS__ ) + +#endif /* DEBUG */ + +// To find the glibc version: +// objdump -T /lib*/*so /lib*/*/*.so | grep popen +// IMPORTANT: The GLIBC_* versions below must match those in mapfile.<variant> + #if ARCH(Aarch64) + #define SYS_LIBC_NAME "libc.so.6" + #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.17" + #define SYS_DLOPEN_VERSION "GLIBC_2.17" + #define SYS_POPEN_VERSION "GLIBC_2.17" + #define SYS_FOPEN_X_VERSION "GLIBC_2.17" + #define SYS_FGETPOS_X_VERSION "GLIBC_2.17" + +#elif ARCH(Intel) + #define SYS_LIBC_NAME "libc.so.6" + #define SYS_POSIX_SPAWN_VERSION "GLIBC_2.15" + #if WSIZE(32) + #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.1" + #define SYS_DLOPEN_VERSION "GLIBC_2.1" + #define SYS_POPEN_VERSION "GLIBC_2.1" + #define SYS_TIMER_X_VERSION "GLIBC_2.2" + #define SYS_FOPEN_X_VERSION "GLIBC_2.1" + #define SYS_FGETPOS_X_VERSION "GLIBC_2.2" + #define SYS_FGETPOS64_X_VERSION "GLIBC_2.2" + #define SYS_OPEN64_X_VERSION "GLIBC_2.2" + #define SYS_PREAD_X_VERSION "GLIBC_2.2" + #define SYS_PWRITE_X_VERSION "GLIBC_2.2" + #define SYS_PWRITE64_X_VERSION "GLIBC_2.2" + #else /* WSIZE(64) */ + #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.2.5" + #define SYS_DLOPEN_VERSION "GLIBC_2.2.5" + #define SYS_POPEN_VERSION "GLIBC_2.2.5" + #define SYS_TIMER_X_VERSION "GLIBC_2.3.3" + #define SYS_FOPEN_X_VERSION "GLIBC_2.2.5" + #define SYS_FGETPOS_X_VERSION "GLIBC_2.2.5" + #endif + + #elif ARCH(SPARC) + #define SYS_LIBC_NAME "libc.so.6" + #define SYS_DLOPEN_VERSION "GLIBC_2.1" + #if WSIZE(32) + #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.1" + #define SYS_POPEN_VERSION "GLIBC_2.1" + #define SYS_FOPEN_X_VERSION "GLIBC_2.1" + #define SYS_FGETPOS_X_VERSION "GLIBC_2.2" + #else /* WSIZE(64) */ + #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.2" + #define SYS_POPEN_VERSION "GLIBC_2.2" + #define SYS_TIMER_X_VERSION "GLIBC_2.3.3" + #define SYS_FOPEN_X_VERSION "GLIBC_2.2" + #define SYS_FGETPOS_X_VERSION "GLIBC_2.2" + #endif + #endif + +#endif diff --git a/gprofng/libcollector/collectorAPI.c b/gprofng/libcollector/collectorAPI.c new file mode 100644 index 0000000..8c9b920 --- /dev/null +++ b/gprofng/libcollector/collectorAPI.c @@ -0,0 +1,140 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* C and Fortran stubs for collector API */ + +#include "config.h" +#include <dlfcn.h> +#include "gp-defs.h" +#include "collectorAPI.h" +#include "gp-experiment.h" + +static void *__real_collector_sample = NULL; +static void *__real_collector_pause = NULL; +static void *__real_collector_resume = NULL; +static void *__real_collector_terminate_expt = NULL; +static void *__real_collector_func_load = NULL; +static void *__real_collector_func_unload = NULL; + +#define INIT_API if (init_API == 0) collectorAPI_initAPI() +#define NULL_PTR(x) (__real_##x == NULL) +#define CALL_REAL(x) (*(void(*)())__real_##x) +#define CALL_IF_REAL(x) INIT_API; if (!NULL_PTR(x)) CALL_REAL(x) + +static int init_API = 0; + +void +collectorAPI_initAPI (void) +{ + void *libcollector = dlopen (SP_LIBCOLLECTOR_NAME, RTLD_NOLOAD); + if (libcollector == NULL) + libcollector = RTLD_DEFAULT; + __real_collector_sample = dlsym (libcollector, "__collector_sample"); + __real_collector_pause = dlsym (libcollector, "__collector_pause"); + __real_collector_resume = dlsym (libcollector, "__collector_resume"); + __real_collector_terminate_expt = dlsym (libcollector, "__collector_terminate_expt"); + __real_collector_func_load = dlsym (libcollector, "__collector_func_load"); + __real_collector_func_unload = dlsym (libcollector, "__collector_func_unload"); + init_API = 1; +} + +/* initialization -- init section routine */ +static void collectorAPI_init () __attribute__ ((constructor)); + +static void +collectorAPI_init (void) +{ + collectorAPI_initAPI (); +} + +/* C API */ +void +collector_pause (void) +{ + CALL_IF_REAL (collector_pause)(); +} + +void +collector_resume (void) +{ + CALL_IF_REAL (collector_resume)(); +} + +void +collector_sample (const char *name) +{ + CALL_IF_REAL (collector_sample)(name); +} + +void +collector_terminate_expt (void) +{ + CALL_IF_REAL (collector_terminate_expt)(); +} + +void +collector_func_load (const char *name, const char *alias, const char *sourcename, + void *vaddr, int size, int lntsize, Lineno *lntable) +{ + CALL_IF_REAL (collector_func_load)(name, alias, sourcename, + vaddr, size, lntsize, lntable); +} + +void +collector_func_unload (void *vaddr) +{ + CALL_IF_REAL (collector_func_unload)(vaddr); +} + +/* Fortran API */ +void +collector_pause_ (void) +{ + CALL_IF_REAL (collector_pause)(); +} + +void +collector_resume_ (void) +{ + CALL_IF_REAL (collector_resume)(); +} + +void +collector_terminate_expt_ (void) +{ + CALL_IF_REAL (collector_terminate_expt)(); +} + +void +collector_sample_ (char *name, long name_length) +{ + INIT_API; + if (!NULL_PTR (collector_sample)) + { + char name_string[256]; + long length = sizeof (name_string) - 1; + if (name_length < length) + length = name_length; + for (long i = 0; i < length; i++) + name_string[i] = name[i]; + name_string[length] = '\0'; + CALL_REAL (collector_sample)(name_string); + } +} diff --git a/gprofng/libcollector/configure b/gprofng/libcollector/configure new file mode 100755 index 0000000..ed23350 --- /dev/null +++ b/gprofng/libcollector/configure @@ -0,0 +1,18081 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for gprofng 2.38.50. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='gprofng' +PACKAGE_TARNAME='gprofng' +PACKAGE_VERSION='2.38.50' +PACKAGE_STRING='gprofng 2.38.50' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="libcol_util.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +GPROFNG_VARIANT +CXXCPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +ac_ct_AR +AR +RANLIB +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +EGREP +GREP +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +CXX +CXXFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures gprofng 2.38.50 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/gprofng] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of gprofng 2.38.50:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +gprofng configure 2.38.50 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by gprofng $as_me 2.38.50, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + +ac_aux_dir= +for ac_dir in ../.. "$srcdir"/../..; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in ../.. \"$srcdir\"/../.." "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +am__api_version='1.15' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='gprofng' + VERSION='2.38.50' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> +# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: <http://www.gnu.org/software/coreutils/>. + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = xyes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if ${ac_cv_safe_to_define___extensions__+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar lib "link -lib" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar lib "link -lib" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 +$as_echo_n "checking the archiver ($AR) interface... " >&6; } +if ${am_cv_ar_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + am_cv_ar_interface=ar + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int some_variable = 0; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 +$as_echo "$am_cv_ar_interface" >&6; } + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + as_fn_error $? "could not determine $AR interface" "$LINENO" 5 + ;; +esac + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.7a' +macro_revision='1.3134' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`print -r -- -n 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the nm to test. + lt_nm_to_check="$NM" + else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + case "$lt_tmp_nm" in + */*|*\\*) tmp_nm="$lt_tmp_nm";; + *) tmp_nm="$ac_dir/$lt_tmp_nm";; + esac + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + case `"$tmp_nm" -B "$tmp_nm" 2>&1 | grep -v '^ *$' | sed '1q'` in + *$tmp_nm*) lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p "$tmp_nm" 2>&1 | grep -v '^ *$' | sed '1q'` in + *$tmp_nm*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +plugin_option= +plugin_names="liblto_plugin.so liblto_plugin-0.dll cyglto_plugin-0.dll" +for plugin in $plugin_names; do + plugin_so=`${CC} ${CFLAGS} --print-prog-name $plugin` + if test x$plugin_so = x$plugin; then + plugin_so=`${CC} ${CFLAGS} --print-file-name $plugin` + fi + if test x$plugin_so != x$plugin; then + plugin_option="--plugin $plugin_so" + break + fi +done + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +if test -n "$plugin_option"; then + if $AR --help 2>&1 | grep -q "\--plugin"; then + touch conftest.c + $AR $plugin_option rc conftest.a conftest.c + if test "$?" != 0; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed: $AR $plugin_option rc" >&5 +$as_echo "$as_me: WARNING: Failed: $AR $plugin_option rc" >&2;} + else + AR="$AR $plugin_option" + fi + rm -f conftest.* + fi +fi +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: +if test -n "$plugin_option" && test "$RANLIB" != ":"; then + if $RANLIB --help 2>&1 | grep -q "\--plugin"; then + RANLIB="$RANLIB $plugin_option" + fi +fi + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BCDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + lt_prog_compiler_pic='-Xcompiler -fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12016 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12122 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + lt_prog_compiler_pic_CXX='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_prog_compiler_pic_CXX" >&6; } + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +# Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=no +fi + + + + + + + +if test "$enable_shared" != "yes"; then + as_fn_error $? "Cannot set --enable-shared for gprofng/libcollector." "$LINENO" 5 +fi + +GPROFNG_VARIANT=unknown +case "${target}" in + x86_64-*-linux*) + GPROFNG_VARIANT=amd64-Linux + ;; + i?86-*-linux*) + GPROFNG_VARIANT=intel-Linux + ;; + aarch64-*-linux*) + GPROFNG_VARIANT=aarch64-Linux + ;; +esac + + +ac_config_files="$ac_config_files Makefile" + +ac_config_headers="$ac_config_headers lib-config.h:../common/config.h.in" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by gprofng $as_me 2.38.50, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +gprofng config.status 2.38.50 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +fix_srcfile_path_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "lib-config.h") CONFIG_HEADERS="$CONFIG_HEADERS lib-config.h:../common/config.h.in" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool 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 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + diff --git a/gprofng/libcollector/configure.ac b/gprofng/libcollector/configure.ac new file mode 100644 index 0000000..8acd66f --- /dev/null +++ b/gprofng/libcollector/configure.ac @@ -0,0 +1,60 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl Copyright (C) 2021 Free Software Foundation, Inc. +dnl +dnl This file is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; see the file COPYING3. If not see +dnl <http://www.gnu.org/licenses/>. + +m4_include([../../bfd/version.m4]) +AC_INIT([gprofng], BFD_VERSION) +AC_CONFIG_MACRO_DIRS([../../config ../..]) +AC_CONFIG_AUX_DIR(../..) +AM_INIT_AUTOMAKE +AM_MAINTAINER_MODE + +AC_CONFIG_SRCDIR(libcol_util.c) + +AC_USE_SYSTEM_EXTENSIONS +AC_PROG_CC +AC_PROG_CXX +AC_PROG_INSTALL +AC_PROG_RANLIB +AM_PROG_AR + +LT_INIT +AC_ENABLE_SHARED +AC_DISABLE_STATIC + +if test "$enable_shared" != "yes"; then + AC_MSG_ERROR([Cannot set --enable-shared for gprofng/libcollector.]) +fi + +GPROFNG_VARIANT=unknown +case "${target}" in + x86_64-*-linux*) + GPROFNG_VARIANT=amd64-Linux + ;; + i?86-*-linux*) + GPROFNG_VARIANT=intel-Linux + ;; + aarch64-*-linux*) + GPROFNG_VARIANT=aarch64-Linux + ;; +esac +AC_SUBST(GPROFNG_VARIANT) + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_HEADERS([lib-config.h:../common/config.h.in]) +AC_OUTPUT + diff --git a/gprofng/libcollector/descendants.h b/gprofng/libcollector/descendants.h new file mode 100644 index 0000000..8fa18c8 --- /dev/null +++ b/gprofng/libcollector/descendants.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* Lineage events for process fork, exec, etc. */ + +#ifndef DESCENDANTS_H +#define DESCENDANTS_H + +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <alloca.h> +#include <assert.h> + +#include "gp-defs.h" +#include "gp-experiment.h" +#include "collector.h" +#include "memmgr.h" +#include "cc_libcollector.h" +#include "tsd.h" + +/* configuration, not changed after init. */ +typedef enum +{ + LM_DORMANT = -2, /* env vars preserved, not recording */ + LM_CLOSED = -1, /* env vars cleared, not recording */ + LM_TRACK_LINEAGE = 1, /* env vars preserved, recording */ +} line_mode_t; + +extern line_mode_t line_mode; +extern int user_follow_mode; +extern int java_mode; +extern int dbg_current_mode; /* for debug only */ +extern unsigned line_key; +extern char **sp_env_backup; + +#define INIT_REENTRANCE(x) ((x) = __collector_tsd_get_by_key (line_key)) +#define CHCK_REENTRANCE(x) (((INIT_REENTRANCE(x)) == NULL) || (*(x) != 0)) +#define PUSH_REENTRANCE(x) ((*(x))++) +#define POP_REENTRANCE(x) ((*(x))--) + +/* environment variables that must be forwarded to descendents */ +#define SP_COLLECTOR_PARAMS "SP_COLLECTOR_PARAMS" +#define SP_COLLECTOR_EXPNAME "SP_COLLECTOR_EXPNAME" +#define SP_COLLECTOR_FOLLOW_SPEC "SP_COLLECTOR_FOLLOW_SPEC" +#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER" +#define SP_PRELOAD_STRINGS "SP_COLLECTOR_PRELOAD" +#define LD_PRELOAD_STRINGS "LD_PRELOAD" +#define SP_LIBPATH_STRINGS "SP_COLLECTOR_LIBRARY_PATH" +#define LD_LIBPATH_STRINGS "LD_LIBRARY_PATH" +#define JAVA_TOOL_OPTIONS "JAVA_TOOL_OPTIONS" +#define COLLECTOR_JVMTI_OPTION "-agentlib:gp-collector" + +extern int __collector_linetrace_shutdown_hwcs_6830763_XXXX; +extern void __collector_env_unset (char *envp[]); +extern void __collector_env_save_preloads (); +extern char ** __collector_env_backup (); +extern void __collector_env_backup_free (); +extern void __collector_env_update (char *envp[]); +extern void __collector_env_print (char *label); +extern void __collector_env_printall (char *label, char *envp[]); +extern char ** __collector_env_allocate (char *const old_env[], int allocate_env); + +#endif diff --git a/gprofng/libcollector/dispatcher.c b/gprofng/libcollector/dispatcher.c new file mode 100644 index 0000000..f9a7de1 --- /dev/null +++ b/gprofng/libcollector/dispatcher.c @@ -0,0 +1,1263 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Central SIGPROF dispatcher to various module event handlers + * (REALPROF profile, HWC check, overview sample, manual sample) + */ + +#include "config.h" +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> +#include <sys/param.h> +#include <sys/signal.h> +#include <sys/syscall.h> +#include <time.h> +#include <signal.h> + +#include "gp-defs.h" +#include "gp-experiment.h" +#include "collector.h" +#include "collector_module.h" +#include "tsd.h" +#include "hwcdrv.h" + + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LTT 0 // for interposition on GLIBC functions +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +static void collector_sigprof_dispatcher (int, siginfo_t*, void*); +static int init_interposition_intf (); +#include "memmgr.h" +static int collector_timer_create (timer_t * ptimerid); +static int collector_timer_settime (int period, timer_t timerid); +static int collector_timer_gettime (timer_t timerid); +static volatile int collector_sigprof_entries = 0; /* counter for SIGPROF signals in DISPATCH_TST mode */ +static timer_t collector_master_thread_timerid = NULL; +static collector_mutex_t collector_clone_libc_lock = COLLECTOR_MUTEX_INITIALIZER; +static unsigned dispatcher_key = COLLECTOR_TSD_INVALID_KEY; + +static void *__real_clone = NULL; +static void *__real_timer_create = NULL; +static void *__real_timer_settime = NULL; +static void *__real_timer_delete = NULL; +static void *__real_timer_gettime = NULL; +#if ARCH(Intel) && WSIZE(32) +static void *__real_pthread_create_2_1 = NULL; +static void *__real_pthread_create_2_0 = NULL; +#elif ARCH(Intel) && WSIZE(64) +static void *__real_timer_create_2_3_3 = NULL; +static void *__real_timer_create_2_2_5 = NULL; +#elif ARCH(SPARC) && WSIZE(64) +static void *__real_timer_create_2_3_3 = NULL; +static void *__real_timer_create_2_2 = NULL; +#endif + +/* Original SIGPROF handler which will be replaced with the dispatcher. Used + * to properly interact with libaio, which uses SIGPROF as its SIGAIOCANCEL. */ +static struct sigaction original_sigprof_handler; + +enum +{ + DISPATCH_NYI = -1, /* dispatcher not yet installed */ + DISPATCH_OFF = 0, /* dispatcher installed, but disabled */ + DISPATCH_ON = 1, /* dispatcher installed, and enabled */ + DISPATCH_TST = 2 /* dispatcher installed, and enabled in testing mode */ +}; + +static int dispatch_mode = DISPATCH_NYI; /* controls SIGPROF dispatching */ +static int itimer_period_requested = 0; /* dispatcher itimer period */ +static int itimer_period_actual = 0; /* actual dispatcher itimer period */ + +#define CALL_REAL(x) (*(int(*)())__real_##x) +#define NULL_PTR(x) ( __real_##x == NULL ) + +static void *__real_sigaction = NULL; +static void *__real_setitimer = NULL; +static void *__real_libc_setitimer = NULL; +static void *__real_sigprocmask = NULL; +static void *__real_thr_sigsetmask = NULL; +static void *__real_pthread_sigmask = NULL; +static void *__real_pthread_create = NULL; + +/* + * void collector_sigprof_dispatcher() + * + * Common SIGPROF event handler which dispatches events to appropriate + * module handlers, if they are active for this collection and due. + * Dispatch sequence, logic and handlers currently hardcoded in dispatcher. + */ +static void +collector_sigprof_dispatcher (int sig, siginfo_t *info, void *context) +{ + if (info == NULL || (info->si_code <= 0 && info->si_code != SI_TIMER)) + { + TprintfT (DBG_LT2, "collector_sigprof_dispatcher signal for %p\n", + original_sigprof_handler.sa_handler); + /* pass signal to previous handler */ + /* watch for recursion, SIG_IGN, and SIG_DFL */ + if (original_sigprof_handler.sa_handler == SIG_DFL) + __collector_SIGDFL_handler (SIGPROF); + else if (original_sigprof_handler.sa_handler != SIG_IGN && + original_sigprof_handler.sa_sigaction != &collector_sigprof_dispatcher) + { + (original_sigprof_handler.sa_sigaction)(sig, info, context); + TprintfT (DBG_LT2, "collector_sigprof_dispatcher handled\n"); + } + } + else if (dispatch_mode == DISPATCH_ON) + { +#if ARCH(SPARC) + ucontext_t uctxmem; + ucontext_t *uctx = &uctxmem; + uctx->uc_link = NULL; + /* 23340823 signal handler third argument should point to a ucontext_t */ + /* Convert sigcontext to ucontext_t on sparc-Linux */ + struct sigcontext *sctx = (struct sigcontext*) context; +#if WSIZE(32) + uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc; + __collector_memcpy (&uctx->uc_mcontext.gregs[3], + sctx->si_regs.u_regs, + sizeof (sctx->si_regs.u_regs)); +#else + uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc; + __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3], + sctx->sigc_regs.u_regs, + sizeof (sctx->sigc_regs.u_regs)); +#endif /* WSIZE() */ + +#else /* not sparc-Linux */ + ucontext_t *uctx = (ucontext_t*) context; +#endif /* ARCH() */ + TprintfT (DBG_LT3, "collector_sigprof_dispatcher dispatching signal\n"); + + /* XXXX the order of these checks/activities may need adjustment */ + /* XXXX should also check (first) for a "cached" manual sample */ + /* HWC check for each LWP: required even if collection is paused */ + /* This should be first, otherwise it's likely to find the counters + * stopped due to an event/overflow during some of the other activities. + */ + /* XXXX HWC check performed every time (skipping if HWC profiling inactive) + * to avoid complexity of maintaining separate check times for each LWP + */ + __collector_ext_hwc_check (info, uctx); + + /* XXXX if sigemtpending, should perhaps skip __collector_ext_usage_sample + * (and get it next time through) + */ + + /* check for experiment past delay start */ + if (__collector_delay_start != 0) + { + hrtime_t now = __collector_gethrtime (); + if (__collector_delay_start < now) + { + TprintfT (0, "__collector_ext_usage_sample: now (%lld) > delay_start (%lld)\n", + (now - __collector_start_time), (__collector_delay_start - __collector_start_time)); + + /* resume the data collection */ + __collector_delay_start = 0; + __collector_resume (); + + /* don't take a periodic sample, just let the resume sample cover it */ + if (__collector_sample_period != 0) + { + /* this update should only be done for periodic samples */ + while (__collector_next_sample < now) + __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period; + } + /* return; */ + } + } + /* check for periodic sampling */ + if (__collector_gethrtime () > __collector_next_sample) + __collector_ext_usage_sample (PERIOD_SMPL, "periodic"); + + /* check for experiment past termination time */ + if (__collector_exp_active && __collector_terminate_time != 0) + { + hrtime_t now = __collector_gethrtime (); + if (__collector_terminate_time < now) + { + TprintfT (0, "__collector_ext_usage_sample: now (%lld) > terminate_time (%lld); closing experiment\n", + (now - __collector_start_time), (__collector_terminate_time - __collector_start_time)); + /* close the experiment */ + __collector_close_experiment (); + } + } + + /* call the code to process the profile data, and generate the packet */ + /* (must always be called, otherwise profile data must be aggregated, + * but can be left till last, as already have the required data) + */ + __collector_ext_profile_handler (info, uctx); + } + else if (dispatch_mode == DISPATCH_TST) + { + collector_sigprof_entries++; + return; + } +} + +/* + * __collector_sigprof_install + */ +int +__collector_sigprof_install () +{ + TprintfT (DBG_LT2, "__collector_sigprof_install\n"); + struct sigaction oact; + if (__collector_sigaction (SIGPROF, NULL, &oact) != 0) + return COL_ERROR_DISPINIT; + if (oact.sa_sigaction == collector_sigprof_dispatcher) + /* signal handler is already in place; we are probably in a fork-child */ + TprintfT (DBG_LT1, "dispatcher: __collector_ext_dispatcher_install() collector_sigprof_dispatcher already installed\n"); + else + { + struct sigaction c_act; + CALL_UTIL (memset)(&c_act, 0, sizeof c_act); + sigemptyset (&c_act.sa_mask); + sigaddset (&c_act.sa_mask, HWCFUNCS_SIGNAL); /* block SIGEMT delivery in handler */ + c_act.sa_sigaction = collector_sigprof_dispatcher; + c_act.sa_flags = SA_RESTART | SA_SIGINFO; + if (__collector_sigaction (SIGPROF, &c_act, &original_sigprof_handler)) + return COL_ERROR_DISPINIT; + } + dispatch_mode = DISPATCH_OFF; /* don't dispatch yet */ + TprintfT (DBG_LT2, "__collector_sigprof_install done\n"); + return COL_ERROR_NONE; +} + +/* + * void __collector_ext_dispatcher_tsd_create_key() + * + * create tsd key for dispatcher + */ +void +__collector_ext_dispatcher_tsd_create_key () +{ + dispatcher_key = __collector_tsd_create_key (sizeof (timer_t), NULL, NULL); +} +/* + * int __collector_ext_dispatcher_install() + * + * installs a common handler/dispatcher (and itimer) for SIGPROF events + */ +int +__collector_ext_dispatcher_install () +{ + int timer_period; + TprintfT (DBG_LT2, "__collector_ext_dispatcher_install\n"); + + /* check period set for interval timer, which will be used as the basis + * for all timed activities: if not set, no role for SIGPROF dispatcher + */ + if (itimer_period_requested <= 0) + { + TprintfT (DBG_LT1, "No interval timer set: skipping dispatcher install!\n"); + return COL_ERROR_NONE; /* no itimer/dispatcher required */ + } + + /* check for an existing interval timer */ + if (collector_master_thread_timerid == NULL) + if (collector_timer_create (&collector_master_thread_timerid) < 0) + return COL_ERROR_ITMRINIT; + timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key); + if (timeridptr != NULL) + *timeridptr = collector_master_thread_timerid; // store for per thread timer stop/start + TprintfT (DBG_LT3, "__collector_ext_dispatcher_install: collector_master_thread_timerid=%p\n", + collector_master_thread_timerid); + timer_period = collector_timer_gettime (collector_master_thread_timerid); + if (timer_period > 0) + { + TprintfT (DBG_LT1, "Overriding app-set interval timer with period %d\n", timer_period); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d->%d</event>\n", + SP_JCMD_CWARN, COL_WARN_ITMRPOVR, timer_period, itimer_period_requested); + } + /* install the interval timer used for all timed activities */ + if (collector_timer_settime (itimer_period_requested, collector_master_thread_timerid) < 0) + return COL_ERROR_ITMRINIT; + TprintfT (DBG_LT2, "__collector_ext_dispatcher_install done\n"); + dispatch_mode = DISPATCH_ON; /* activate SIGPROF dispatch to event handlers */ + return COL_ERROR_NONE; +} + +int +__collector_sigaction (int sig, const struct sigaction *nact, struct sigaction *oact) +{ + TprintfT (DBG_LT1, "__collector_sigaction: %d, %p\n", sig, nact ? nact->sa_sigaction : NULL); + if (NULL_PTR (sigaction)) + init_interposition_intf (); + + /* Whether we change the signal handler in the kernel + * or not make sure the real sigaction is aware about + * our new handler (6227565) + */ + return CALL_REAL (sigaction)(sig, nact, oact); +} + +/* + * We have special dispatchers for SIGPROF and HWCFUNCS_SIGNAL to + * decide whether the signal was intended for us or for the user. + * One special case is SIGDFL, in which case we don't have a + * user-function address to call. If the user did indeed set + * default disposition for one of these signals and sent that + * signal, we honor that action, even though it will lead to + * termination. + */ +void +__collector_SIGDFL_handler (int sig) +{ + /* remove our dispatcher, replacing it with the default disposition */ + struct sigaction act; + CALL_UTIL (memset)(&act, 0, sizeof (act)); + act.sa_handler = SIG_DFL; + if (__collector_sigaction (sig, &act, NULL)) + { + /* XXXXXX what are we supposed to do here? we're committing suicide anyhow */ + } + /* resend the signal we intercepted earlier */ + // XXXX Bug 18177509 - additional sigprof signal kills target program + kill (getpid (), sig); +} + +/* + * suspend/resume timer per thread + */ +void +__collector_ext_dispatcher_thread_timer_suspend () +{ + timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key); + if (timeridptr != NULL && *timeridptr != NULL) + (void) collector_timer_settime (0, *timeridptr); + return; +} + +int +__collector_ext_dispatcher_thread_timer_resume () +{ + timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key); + if (timeridptr == NULL) + return -1; + if (*timeridptr == NULL) + { // timer id not initialized yet + TprintfT (DBG_LT2, "__collector_ext_dispatcher_thread_timer_resume: timer not initialized yet, create it\n"); + if (collector_timer_create (timeridptr) == -1) + { + TprintfT (0, "__collector_ext_dispatcher_thread_timer_resume(): WARNING: No timer created\n"); + return -1; + } + } + return collector_timer_settime (itimer_period_requested, *timeridptr); +} + +void +__collector_ext_dispatcher_suspend () +{ + TprintfT (DBG_LT2, "__collector_ext_dispatcher_suspend\n"); + if (dispatch_mode == DISPATCH_NYI) + { + TprintfT (0, "__collector_ext_dispatcher_suspend(): WARNING: No dispatcher installed\n"); + return; + } + + /* disable SIGPROF dispatching */ + dispatch_mode = DISPATCH_OFF; + + /* disable the interval timer; ignore any failures */ + __collector_ext_dispatcher_thread_timer_suspend (); + return; +} + +void +__collector_ext_dispatcher_restart () +{ + TprintfT (DBG_LT2, "__collector_ext_dispatcher_restart(ip=%d)\n", itimer_period_requested); + if (dispatch_mode == DISPATCH_NYI) + { + TprintfT (0, "__collector_ext_dispatcher_restart(): WARNING: No dispatcher installed\n"); + return; + } + + /* restart the interval timer used for all timed activities */ + if (__collector_ext_dispatcher_thread_timer_resume () == 0) + dispatch_mode = DISPATCH_ON; /* re-activate SIGPROF dispatch to handlers */ + return; +} +/* + * void __collector_ext_dispatcher_deinstall() + * + * If installed, disables SIGPROF dispatch and interval timer. + * Includes checks for last SIGPROF dispatch time, interval timer period, + * and currently installed SIGPROF handler, with appropriate warnings logged. + * The dispatcher remains installed to handle pending collector SIGPROFs and + * forward non-collector SIGPROFs to the application's handler(s). + * If the decision is ever made actually to deinstall the dispatcher, + * consider bug 4183714 and what to do about any possible pending + * SIGPROFs. + */ + +void +__collector_ext_dispatcher_deinstall () +{ + TprintfT (DBG_LT1, "__collector_ext_dispatcher_deinstall()\n"); + if (dispatch_mode == DISPATCH_NYI) + { + TprintfT (0, "__collector_ext_dispatcher_deinstall(): WARNING: No dispatcher installed\n"); + return; + } + dispatch_mode = DISPATCH_OFF; /* disable SIGPROF dispatching */ + + /* verify that interval timer is still installed with expected period */ + int timer_period = collector_timer_gettime (collector_master_thread_timerid); + if (timer_period != itimer_period_actual) + { + TprintfT (DBG_LT2, "dispatcher: Collector interval timer period changed %d -> %d\n", + itimer_period_actual, timer_period); + if ((itimer_period_actual >= (timer_period + timer_period / 10)) || + (itimer_period_actual <= (timer_period - timer_period / 10))) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", + SP_JCMD_CWARN, COL_WARN_ITMRREP, + itimer_period_actual, timer_period); + else + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", + SP_JCMD_COMMENT, COL_WARN_PROFRND, + itimer_period_actual, timer_period); + } + + /* Verify that SIGPROF dispatcher is still installed. + * (still required with sigaction interposition and management, + * since interposition is not done for attach experiments) + */ + struct sigaction curr; + if (__collector_sigaction (SIGPROF, NULL, &curr) == -1) + TprintfT (0, "ERROR: dispatcher sigaction check failed: errno=%d\n", errno); + else if (curr.sa_sigaction != collector_sigprof_dispatcher) + { + TprintfT (0, "ERROR: collector dispatcher replaced by %p!\n", curr.sa_handler); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%p</event>\n", + SP_JCMD_CWARN, COL_WARN_SIGPROF, curr.sa_handler); + } + else + TprintfT (DBG_LT2, "collector dispatcher integrity verified!\n"); + + /* disable the interval timer; ignore any failures */ + if (collector_master_thread_timerid != NULL) + { + (void) CALL_REAL (timer_delete)(collector_master_thread_timerid); + collector_master_thread_timerid = NULL; + } + dispatcher_key = COLLECTOR_TSD_INVALID_KEY; + itimer_period_requested = 0; + itimer_period_actual = 0; +} + +/* + * void __collector_ext_dispatcher_fork_child_cleanup() + * + * delete timer, clear timer interval + */ +void +__collector_ext_dispatcher_fork_child_cleanup () +{ + if (collector_master_thread_timerid != NULL) + { + (void) CALL_REAL (timer_delete)(collector_master_thread_timerid); + collector_master_thread_timerid = NULL; + } + __collector_mutex_init (&collector_clone_libc_lock); + dispatcher_key = COLLECTOR_TSD_INVALID_KEY; + itimer_period_requested = 0; + itimer_period_actual = 0; +} +/* + * int __collector_ext_itimer_set (int rperiod) + * + * set itimer period, if not yet set to a positive number of microseconds, + * (after rounding to sys_resolution if necessary) and return its value + */ +int +__collector_ext_itimer_set (int rperiod) +{ + int period; + /* if rperiod is negative, force setting */ + if (rperiod < 0) + { + itimer_period_actual = 0; + period = -rperiod; + } + else + period = rperiod; + + // ignore SIGPROF while testing itimer interval setting + int saved = dispatch_mode; + dispatch_mode = DISPATCH_OFF; + if (collector_timer_create (&collector_master_thread_timerid) == -1) + { + TprintfT (0, "__collector_ext_itimer_set(): WARNING: No timer created\n"); + return itimer_period_actual; + } + if (collector_timer_settime (period, collector_master_thread_timerid) == 0) + { + itimer_period_actual = collector_timer_gettime (collector_master_thread_timerid); + (void) collector_timer_settime (0, collector_master_thread_timerid); /* XXXX unset for now */ + itimer_period_requested = period; + if (itimer_period_requested != itimer_period_actual) + { + TprintfT (DBG_LT2, " itimer period %d adjusted to %d\n", + itimer_period_requested, itimer_period_actual); + // (void) __collector_log_write("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", + // SP_JCMD_CWARN, COL_WARN_PROFRND, itimer_period_requested, itimer_period_actual); + } + else + TprintfT (DBG_LT2, " itimer period %d accepted\n", period); + } + + // restore dispatching SIGPROF handler + dispatch_mode = saved; + TprintfT (0, "__collector_ext_itimer_set(%d), requested=%d, actual=%d)\n", + rperiod, itimer_period_requested, itimer_period_actual); + return (itimer_period_actual); +} + +static int +collector_timer_gettime (timer_t timerid) +{ + int timer_period; + struct itimerspec itimer; + if (timerid == NULL) + return (0); // timer was not initialized + if (CALL_REAL (timer_gettime)(timerid, &itimer) == -1) + { + /* this should never reasonably fail, so not worth logging */ + TprintfT (DBG_LT1, "WARNING: timer_gettime failed: errno=%d\n", errno); + return (-1); + } + timer_period = ((itimer.it_interval.tv_sec * NANOSEC) + + itimer.it_interval.tv_nsec) / 1000; + TprintfT (DBG_LT2, "collector_timer_gettime (period=%d)\n", timer_period); + return (timer_period); +} + +static int +collector_timer_create (timer_t * ptimerid) +{ + struct sigevent sigev; + if (NULL_PTR (timer_create)) + init_interposition_intf (); + TprintfT (DBG_LT2, "collector_timer_settime(): timer_create is %p\n", __real_timer_create); + sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL; + sigev.sigev_signo = SIGPROF; + sigev.sigev_value.sival_ptr = ptimerid; + sigev._sigev_un._tid = __collector_gettid (); + if (CALL_REAL (timer_create)(CLOCK_THREAD_CPUTIME_ID, &sigev, ptimerid) == -1) + { + TprintfT (DBG_LT2, "collector_timer_settime() failed! errno=%d\n", errno); + return -1; + } + return 0; +} + +static int +collector_timer_settime (int period, timer_t timerid) +{ + struct itimerspec itimer; + if (NULL_PTR (timer_settime)) + init_interposition_intf (); + TprintfT (DBG_LT2, "collector_timer_settime(period=%d)\n", period); + time_t NPM = 1000; + itimer.it_interval.tv_sec = NPM * period / NANOSEC; + itimer.it_interval.tv_nsec = (NPM * period) % NANOSEC; + itimer.it_value = itimer.it_interval; + if (CALL_REAL (timer_settime)(timerid, 0, &itimer, NULL) == -1) + { + TprintfT (DBG_LT2, "collector_timer_settime(%d) failed! errno=%d\n", period, errno); + return -1; + } + return 0; +} + +static void +protect_profiling_signals (sigset_t* lset) +{ + static unsigned int protected_sigprof = 0; + static unsigned int protected_sigemt = 0; + // T1 relies on thread signal masking, so best not to mess with it: + // T1 users have already been warned about the dangers of its use + if (__collector_libthread_T1) + return; + if (sigismember (lset, SIGPROF) && (dispatch_mode == DISPATCH_ON)) + { + TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGPROF"); + if (protected_sigprof == 0) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CWARN, COL_WARN_SIGMASK, "SIGPROF"); + sigdelset (lset, SIGPROF); + protected_sigprof++; + } + if (sigismember (lset, HWCFUNCS_SIGNAL) && __collector_ext_hwc_active ()) + { + TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGEMT"); + if (protected_sigemt == 0) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CWARN, COL_WARN_SIGMASK, HWCFUNCS_SIGNAL_STRING); + sigdelset (lset, HWCFUNCS_SIGNAL); + protected_sigemt++; + } +} + +#define SYS_SETITIMER_NAME "setitimer" +#define SYS_SIGACTION_NAME "sigaction" +#define SYS_SIGPROCMASK_NAME "sigprocmask" +#define SYS_PTHREAD_SIGMASK "pthread_sigmask" +#define SYS_THR_SIGSETMASK "thr_sigsetmask" + +static int +init_interposition_intf () +{ + if (__collector_dlsym_guard) + return 1; + void *dlflag; + /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */ + void *handle = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD); + +#if ARCH(SPARC) && WSIZE(64) + /* dlopen a bogus path to avoid CR 23608692 */ + dlopen ("/bogus_path_for_23608692_workaround/", RTLD_LAZY | RTLD_NOLOAD); +#endif + __real_setitimer = dlsym (RTLD_NEXT, SYS_SETITIMER_NAME); + + if (__real_setitimer == NULL) + { + __real_setitimer = dlsym (RTLD_DEFAULT, SYS_SETITIMER_NAME); + if (__real_setitimer == NULL) + { + TprintfT (DBG_LT2, "init_interposition_intf() setitimer not found\n"); + return 1; + } + dlflag = RTLD_DEFAULT; + } + else + dlflag = RTLD_NEXT; + + TprintfT (DBG_LT2, "init_interposition_intf() using RTLD_%s\n", + (dlflag == RTLD_DEFAULT) ? "DEFAULT" : "NEXT"); + TprintfT (DBG_LT2, "@%p __real_setitimer\n", __real_setitimer); + + __real_sigaction = dlsym (dlflag, SYS_SIGACTION_NAME); + TprintfT (DBG_LT2, "@%p __real_sigaction\n", __real_sigaction); + + /* also explicitly get libc.so/setitimer (as a backup) */ + __real_libc_setitimer = dlsym (handle, SYS_SETITIMER_NAME); + TprintfT (DBG_LT2, "@%p __real_libc_setitimer\n", __real_libc_setitimer); + + __real_sigprocmask = dlsym (dlflag, SYS_SIGPROCMASK_NAME); + TprintfT (DBG_LT2, "@%p __real_sigprocmask\n", __real_sigprocmask); + + __real_thr_sigsetmask = dlsym (dlflag, SYS_THR_SIGSETMASK); + TprintfT (DBG_LT2, "@%p __real_thr_sigsetmask\n", __real_thr_sigsetmask); + + __real_pthread_sigmask = dlsym (dlflag, SYS_PTHREAD_SIGMASK); + TprintfT (DBG_LT2, "@%p __real_pthread_sigmask\n", __real_pthread_sigmask); + +#if ARCH(Aarch64) + __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION); + __real_timer_create = dlsym (dlflag, "timer_create"); + __real_timer_settime = dlsym (dlflag, "timer_settime"); + __real_timer_delete = dlsym (dlflag, "timer_delete"); + __real_timer_gettime = dlsym (dlflag, "timer_gettime"); +#else + __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION); + TprintfT (DBG_LT2, "[%s] @%p __real_pthread_create\n", SYS_PTHREAD_CREATE_VERSION, __real_pthread_create); + __real_timer_create = dlvsym (dlflag, "timer_create", SYS_TIMER_X_VERSION); + TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_create\n", SYS_TIMER_X_VERSION, __real_timer_create); + __real_timer_settime = dlvsym (dlflag, "timer_settime", SYS_TIMER_X_VERSION); + TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_settime\n", SYS_TIMER_X_VERSION, __real_timer_settime); + __real_timer_delete = dlvsym (dlflag, "timer_delete", SYS_TIMER_X_VERSION); + TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_delete\n", SYS_TIMER_X_VERSION, __real_timer_delete); + __real_timer_gettime = dlvsym (dlflag, "timer_gettime", SYS_TIMER_X_VERSION); + TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_gettime\n", SYS_TIMER_X_VERSION, __real_timer_gettime); + __real_clone = dlsym (dlflag, "clone"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone); +#if ARCH(Intel) && WSIZE(32) + __real_pthread_create_2_1 = __real_pthread_create; + __real_pthread_create_2_0 = dlvsym (dlflag, "pthread_create", "GLIBC_2.0"); +#elif ARCH(Intel) && WSIZE(64) + __real_timer_create_2_3_3 = __real_timer_create; + __real_timer_create_2_2_5 = dlvsym (dlflag, "timer_create", "GLIBC_2.2.5"); +#elif ARCH(SPARC) && WSIZE(64) + __real_timer_create_2_3_3 = __real_timer_create; + __real_timer_create_2_2 = dlvsym (dlflag, "timer_create", "GLIBC_2.2"); +#endif /* ARCH() && SIZE() */ +#endif + return 0; +} + + +/*------------------------------------------------------------- sigaction */ + +/* NB: need a global interposing function called "sigaction" */ +int +sigaction (int sig, const struct sigaction *nact, struct sigaction *oact) +{ + int ret = 0; + int err = 0; + if (NULL_PTR (sigaction)) + err = init_interposition_intf (); + if (err) + return -1; + TprintfT (DBG_LT3, "sigaction(sig=%02d, nact=%p) interposing\n", sig, nact); + if (sig == SIGPROF && dispatch_mode != DISPATCH_NYI) + { + if (oact != NULL) + { + oact->sa_handler = original_sigprof_handler.sa_handler; + oact->sa_mask = original_sigprof_handler.sa_mask; + oact->sa_flags = original_sigprof_handler.sa_flags; + } + if (nact != NULL) + { + original_sigprof_handler.sa_handler = nact->sa_handler; + original_sigprof_handler.sa_mask = nact->sa_mask; + original_sigprof_handler.sa_flags = nact->sa_flags; + TprintfT (DBG_LT1, "dispatcher: new sigaction(sig=%02d) set\n", sig); + } + } + else if (sig == HWCFUNCS_SIGNAL) + ret = collector_sigemt_sigaction (nact, oact); + else + { + if (sig != SIGCHLD || collector_sigchld_sigaction (nact, oact)) + ret = CALL_REAL (sigaction)(sig, nact, oact); + TprintfT (DBG_LT3, "Real sigaction(sig=%02d) returned %d (oact=%p)\n", + sig, ret, oact); + /* but check for other important signals */ + /* check for sample and pause/resume signals; give warning once, if need be */ + if ((sig == __collector_sample_sig) && (__collector_sample_sig_warn == 0)) + { + /* give user a warning */ + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n", + SP_JCMD_CWARN, COL_WARN_SAMPSIGUSED, __collector_sample_sig); + __collector_sample_sig_warn = 1; + } + if ((sig == __collector_pause_sig) && (__collector_pause_sig_warn == 0)) + { + /* give user a warning */ + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n", + SP_JCMD_CWARN, COL_WARN_PAUSESIGUSED, __collector_pause_sig); + __collector_pause_sig_warn = 1; + } + } + TprintfT (DBG_LT3, "sigaction() returning %d (oact=%p)\n", ret, oact); + return ret; +} + +/* + * In addition to interposing on sigaction(), should we also interpose + * on other important signal functions like signal() or sigset()? + * - On Solaris, those other functions apparently call sigaction(). + * So, we only have to interpose on it. + * - On Linux, we should perhaps interpose on these other functions, + * but they are less portable than sigaction() and deprecated or even obsolete. + * So, we interpose, but don't overly worry about doing a good job. + */ +sighandler_t +signal (int sig, sighandler_t handler) +{ + struct sigaction nact; + struct sigaction oact; + TprintfT (DBG_LT3, "signal(sig=%02d, handler=%p) interposing\n", sig, handler); + sigemptyset (&nact.sa_mask); + nact.sa_handler = handler; + nact.sa_flags = SA_RESTART; + if (sigaction (sig, &nact, &oact)) + return SIG_ERR; + TprintfT (DBG_LT3, "signal() returning %p\n", oact.sa_handler); + return oact.sa_handler; +} + +sighandler_t +sigset (int sig, sighandler_t handler) +{ + TprintfT (DBG_LT3, "sigset(sig=%02d, handler=%p) interposing\n", sig, handler); + return signal (sig, handler); +} + +/*------------------------------------------------------------- timer_create */ + +// map interposed symbol versions +#if WSIZE(64) +#if ARCH(SPARC) || ARCH(Intel) +static int +__collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid, struct sigevent *sevp, + timer_t *timerid); + +int +__collector_timer_create_2_3_3 (clockid_t clockid, struct sigevent *sevp, + timer_t *timerid) +{ + if (NULL_PTR (timer_create)) + init_interposition_intf (); + TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_3_3@%p\n", CALL_REAL (timer_create_2_3_3)); + return __collector_timer_create_symver (CALL_REAL (timer_create_2_3_3), clockid, sevp, timerid); +} +__asm__(".symver __collector_timer_create_2_3_3,timer_create@@GLIBC_2.3.3"); +#endif /* ARCH(SPARC) || ARCH(Intel)*/ + +#if ARCH(SPARC) + +int +__collector_timer_create_2_2 (clockid_t clockid, struct sigevent *sevp, + timer_t *timerid) +{ + if (NULL_PTR (timer_create)) + init_interposition_intf (); + TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2@%p\n", CALL_REAL (timer_create_2_2)); + return __collector_timer_create_symver (CALL_REAL (timer_create_2_2), clockid, sevp, timerid); +} + +__asm__(".symver __collector_timer_create_2_2,timer_create@GLIBC_2.2"); + +#elif ARCH(Intel) + +int +__collector_timer_create_2_2_5 (clockid_t clockid, struct sigevent *sevp, + timer_t *timerid) +{ + if (NULL_PTR (timer_create)) + init_interposition_intf (); + TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2_5@%p\n", CALL_REAL (timer_create_2_2_5)); + return __collector_timer_create_symver (CALL_REAL (timer_create_2_2_5), clockid, sevp, timerid); +} +__asm__(".symver __collector_timer_create_2_2_5,timer_create@GLIBC_2.2.5"); +#endif /* ARCH() */ +#endif /* WSIZE(64) */ + +#if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32)) +int timer_create (clockid_t clockid, struct sigevent *sevp, timer_t *timerid) +#else +static int +__collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid, + struct sigevent *sevp, timer_t *timerid) +#endif +{ + int ret; + + if (NULL_PTR (timer_create)) + init_interposition_intf (); + + /* collector reserves SIGPROF + */ + if (sevp == NULL || sevp->sigev_notify != SIGEV_SIGNAL + || sevp->sigev_signo != SIGPROF) + { +#if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32)) + ret = CALL_REAL (timer_create)(clockid, sevp, timerid); +#else + ret = (real_timer_create) (clockid, sevp, timerid); +#endif + TprintfT (DBG_LT2, "Real timer_create(%d) returned %d\n", + clockid, ret); + return ret; + } + + /* log that application's timer_create request is overridden */ + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n", + SP_JCMD_CWARN, COL_WARN_ITMROVR, -1); + ret = -1; + errno = EBUSY; + TprintfT (DBG_LT2, "timer_create() returning %d\n", ret); + return ret; +} +/*------------------------------------------------------------- setitimer */ +int +_setitimer (int which, const struct itimerval *nval, + struct itimerval *oval) +{ + int ret; + int period; + + if (NULL_PTR (setitimer)) + init_interposition_intf (); + + if (nval == NULL) + period = -1; + else + period = (nval->it_interval.tv_sec * MICROSEC) + + nval->it_interval.tv_usec; + TprintfT (DBG_LT1, "setitimer(which=%d,nval=%dus) interposing\n", which, period); + + /* collector reserves ITIMER_REALPROF for its own use, and ITIMER_PROF + * uses the same signal (SIGPROF) so it must also be reserved + */ + if (((which != ITIMER_REALPROF) && (which != ITIMER_PROF)) || (nval == NULL)) + { + ret = CALL_REAL (setitimer)(which, nval, oval); + if (oval == NULL) + period = -1; + else + period = (oval->it_interval.tv_sec * MICROSEC) + + oval->it_interval.tv_usec; + TprintfT (DBG_LT2, "Real setitimer(%d) returned %d (oval=%dus)\n", + which, ret, period); + return ret; + } + /* log that application's setitimer request is overridden */ + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n", + SP_JCMD_CWARN, COL_WARN_ITMROVR, period); + if (oval == NULL) + period = -1; + else + { + getitimer (which, oval); /* return current itimer setting */ + period = (oval->it_interval.tv_sec * MICROSEC) + + oval->it_interval.tv_usec; + } + ret = -1; + errno = EBUSY; + TprintfT (DBG_LT2, "setitimer() returning %d (oval=%dus)\n", ret, period); + return ret; +} + +/*--------------------------------------------------------------- sigprocmask */ +int +__collector_sigprocmask (int how, const sigset_t* iset, sigset_t* oset) +{ + int err = 0; + if (NULL_PTR (sigprocmask)) + err = init_interposition_intf (); + if (err) + return -1; + TprintfT (DBG_LT2, "__collector_sigprocmask(%d) interposing\n", how); + sigset_t lsigset; + sigset_t* lset = NULL; + if (iset) + { + lsigset = *iset; + lset = &lsigset; + if ((how == SIG_BLOCK) || (how == SIG_SETMASK)) + protect_profiling_signals (lset); + } + int ret = CALL_REAL (sigprocmask)(how, lset, oset); + TprintfT (DBG_LT2, "__collector_sigprocmask(%d) returning %d\n", how, ret); + return ret; +} + +/*------------------------------------------------------------ thr_sigsetmask */ +int +__collector_thr_sigsetmask (int how, const sigset_t* iset, sigset_t* oset) +{ + if (NULL_PTR (thr_sigsetmask)) + init_interposition_intf (); + TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) interposing\n", how); + sigset_t lsigset; + sigset_t* lset = NULL; + if (iset) + { + lsigset = *iset; + lset = &lsigset; + if ((how == SIG_BLOCK) || (how == SIG_SETMASK)) + protect_profiling_signals (lset); + } + int ret = CALL_REAL (thr_sigsetmask)(how, lset, oset); + TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) returning %d\n", how, ret); + return ret; +} + +/*----------------------------------------------------------- pthread_sigmask */ + +int +pthread_sigmask (int how, const sigset_t* iset, sigset_t* oset) +{ + if (NULL_PTR (pthread_sigmask)) + init_interposition_intf (); + TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) interposing\n", how); + sigset_t lsigset; + sigset_t* lset = NULL; + if (iset) + { + lsigset = *iset; + lset = &lsigset; + if ((how == SIG_BLOCK) || (how == SIG_SETMASK)) + protect_profiling_signals (lset); + } + int ret = CALL_REAL (pthread_sigmask)(how, lset, oset); + TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) returning %d\n", how, ret); + return ret; +} +/*----------------------------------------------------------- pthread_create */ +typedef struct _CollectorArgs +{ + void *(*func)(void*); + void *arg; + void *stack; + int isPthread; +} CollectorArgs; + +static void * +collector_root (void *cargs) +{ + /* save the real arguments and free cargs */ + void *(*func)(void*) = ((CollectorArgs*) cargs)->func; + void *arg = ((CollectorArgs*) cargs)->arg; + void *stack = ((CollectorArgs*) cargs)->stack; + int isPthread = ((CollectorArgs*) cargs)->isPthread; + __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs)); + + /* initialize tsd for this thread */ + if (__collector_tsd_allocate () == 0) + /* init tsd for unwind, called right after __collector_tsd_allocate()*/ + __collector_ext_unwind_key_init (isPthread, stack); + + if (!isPthread) + __collector_mutex_lock (&collector_clone_libc_lock); + + /* set the profile timer */ + timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key); + timer_t timerid = NULL; + if (timeridptr != NULL) + { + collector_timer_create (timeridptr); + if (*timeridptr != NULL) + collector_timer_settime (itimer_period_requested, *timeridptr); + timerid = *timeridptr; + } + int hwc_rc = __collector_ext_hwc_lwp_init (); + + if (!isPthread) + __collector_mutex_unlock (&collector_clone_libc_lock); + /* call the real function */ + void *ret = func (arg); + if (!isPthread) + __collector_mutex_lock (&collector_clone_libc_lock); + if (timerid != NULL) + CALL_REAL (timer_delete)(timerid); + if (!hwc_rc) + /* pthread_kill not handled here */ + __collector_ext_hwc_lwp_fini (); + + if (!isPthread) + __collector_mutex_unlock (&collector_clone_libc_lock); + /* if we have this chance, release tsd */ + __collector_tsd_release (); + + return ret; +} + +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) +static int +__collector_pthread_create_symver (int(real_pthread_create) (), + pthread_t *thread, + const pthread_attr_t *attr, + void *(*func)(void*), + void *arg); + +int +__collector_pthread_create_2_1 (pthread_t *thread, + const pthread_attr_t *attr, + void *(*func)(void*), + void *arg) +{ + if (NULL_PTR (pthread_create)) + init_interposition_intf (); + TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_1@%p\n", CALL_REAL (pthread_create_2_1)); + return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_1), thread, attr, func, arg); +} + +int +__collector_pthread_create_2_0 (pthread_t *thread, + const pthread_attr_t *attr, + void *(*func)(void*), + void *arg) +{ + if (NULL_PTR (pthread_create)) + init_interposition_intf (); + TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_0@%p\n", CALL_REAL (pthread_create_2_0)); + return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_0), thread, attr, func, arg); +} + +__asm__(".symver __collector_pthread_create_2_1,pthread_create@@GLIBC_2.1"); +__asm__(".symver __collector_pthread_create_2_0,pthread_create@GLIBC_2.0"); + +#endif + +#if ARCH(Intel) && WSIZE(32) +static int +__collector_pthread_create_symver (int(real_pthread_create) (), + pthread_t *thread, + const pthread_attr_t *attr, + void *(*func)(void*), + void *arg) +#else +int +pthread_create (pthread_t *thread, const pthread_attr_t *attr, + void *(*func)(void*), void *arg) +#endif +{ + if (NULL_PTR (pthread_create)) + init_interposition_intf (); + + TprintfT (DBG_LT1, "pthread_create interposition called\n"); + + if (dispatch_mode != DISPATCH_ON) + { +#if ARCH(Intel) && WSIZE(32) + return (real_pthread_create) (thread, attr, func, arg); +#else + return CALL_REAL (pthread_create)(thread, attr, func, arg); +#endif + } + CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1); + + if (cargs == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_pthread_create) (thread, attr, func, arg); +#else + return CALL_REAL (pthread_create)(thread, attr, func, arg); +#endif + } + cargs->func = func; + cargs->arg = arg; + cargs->stack = NULL; + cargs->isPthread = 1; + int ret = -1; +#if ARCH(Intel) && WSIZE(32) + ret = (real_pthread_create) (thread, attr, &collector_root, cargs); +#else + ret = CALL_REAL (pthread_create)(thread, attr, &collector_root, cargs); +#endif + if (ret) + __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs)); + TprintfT (DBG_LT1, "pthread_create returning %d\n", ret); + return ret; +} + +int +__collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg, + va_list va /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */) +{ + if (NULL_PTR (clone)) + init_interposition_intf (); + TprintfT (0, "clone thread interposing\n"); + pid_t * ptid = NULL; + struct user_desc * tls = NULL; + pid_t * ctid = NULL; + int num_args = 0; + if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) + { + ptid = va_arg (va, pid_t *); + tls = va_arg (va, struct user_desc*); + ctid = va_arg (va, pid_t *); + num_args = 3; + } + else if (flags & CLONE_SETTLS) + { + ptid = va_arg (va, pid_t *); + tls = va_arg (va, struct user_desc*); + num_args = 2; + } + else if (flags & CLONE_PARENT_SETTID) + { + ptid = va_arg (va, pid_t *); + num_args = 1; + } + int ret = 0; + if (dispatch_mode != DISPATCH_ON) + { + switch (num_args) + { + case 3: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid); + break; + case 2: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls); + break; + case 1: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid); + break; + default: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg); + break; + } + return ret; + } + CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1); + if (cargs == NULL) + { + switch (num_args) + { + case 3: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid); + break; + case 2: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls); + break; + case 1: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid); + break; + default: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg); + break; + } + return ret; + } + + cargs->func = (void *(*)(void*))fn; + cargs->arg = arg; + cargs->stack = child_stack; + cargs->isPthread = 0; + + switch (num_args) + { + case 3: + ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls, ctid); + break; + case 2: + ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls); + break; + case 1: + ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid); + break; + default: + ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs); + break; + } + + if (ret < 0) + __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs)); + TprintfT (DBG_LT1, "clone thread returning %d\n", ret); + return ret; +} + +// weak symbols: +int sigprocmask () __attribute__ ((weak, alias ("__collector_sigprocmask"))); +int thr_sigsetmask () __attribute__ ((weak, alias ("__collector_thr_sigsetmask"))); +int setitimer () __attribute__ ((weak, alias ("_setitimer"))); diff --git a/gprofng/libcollector/envmgmt.c b/gprofng/libcollector/envmgmt.c new file mode 100644 index 0000000..b4418d6 --- /dev/null +++ b/gprofng/libcollector/envmgmt.c @@ -0,0 +1,840 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Routines for managing the target's environment array + */ + +#include "config.h" +#include "descendants.h" + +#define MAX_LD_PRELOADS 2 + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 +#define DBG_LT4 4 + +/* original environment settings to be saved for later restoration */ +static char *sp_preloads[MAX_LD_PRELOADS]; +static char *sp_libpaths[MAX_LD_PRELOADS]; +char **sp_env_backup; + +static const char *SP_ENV[]; +static const char *LD_ENV[]; +static const char *SP_PRELOAD[]; +static const char *LD_PRELOAD[]; +static const char *SP_LIBRARY_PATH[]; +static const char *LD_LIBRARY_PATH[]; +static int NUM_SP_ENV_VARS; +static int NUM_LD_ENV_VARS; +static int NUM_SP_PRELOADS; +static int NUM_LD_PRELOADS; +static int NUM_SP_LIBPATHS; +static int NUM_LD_LIBPATHS; + +static const char *SP_ENV[] = { + SP_COLLECTOR_PARAMS, /* data descriptor */ + SP_COLLECTOR_EXPNAME, /* experiment name */ + SP_COLLECTOR_FOLLOW_SPEC, /* linetrace */ + SP_COLLECTOR_FOUNDER, /* determine founder exp */ + SP_PRELOAD_STRINGS, /* LD_PRELOADs for data collection */ + SP_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs for data collection */ + "SP_COLLECTOR_TRACELEVEL", /* tprintf */ +#if DEBUG + "SP_COLLECTOR_SIGACTION", /* dispatcher, hwprofile */ +#endif + /* JAVA* */ + /* LD_DEBUG=audit,bindings,detail */ + /* LD_ORIGIN=yes */ + NULL +}; + +static const char *LD_ENV[] = { + LD_PRELOAD_STRINGS, /* LD_PRELOADs */ + LD_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs */ + JAVA_TOOL_OPTIONS, /* enable -agentlib:collector for JVMTI */ + NULL +}; + +static const char *SP_PRELOAD[] = { + SP_PRELOAD_STRINGS, + NULL +}; + +static const char *LD_PRELOAD[] = { + LD_PRELOAD_STRINGS, + NULL +}; + +static const char *SP_LIBRARY_PATH[] = { + SP_LIBPATH_STRINGS, + NULL +}; +static const char *LD_LIBRARY_PATH[] = { + LD_LIBPATH_STRINGS, + NULL +}; + +void +__collector_env_save_preloads () +{ + /* save the list of SP_PRELOADs */ + int v; + for (v = 0; SP_PRELOAD[v]; v++) + { + sp_preloads[v] = __collector_strdup (CALL_UTIL (getenv)(SP_PRELOAD[v])); + TprintfT (DBG_LT3, "__collector_env_save_preloads: %s=%s\n", SP_PRELOAD[v], sp_preloads[v]); + } + NUM_SP_PRELOADS = v; + for (v = 0; SP_LIBRARY_PATH[v]; v++) + { + sp_libpaths[v] = __collector_strdup (CALL_UTIL (getenv)(SP_LIBRARY_PATH[v])); + TprintfT (DBG_LT4, "__collector_env_save_preloads: %s=%s\n", SP_LIBRARY_PATH[v], + sp_libpaths[v] ? sp_libpaths[v] : "NULL"); + } + NUM_SP_LIBPATHS = v; + for (v = 0; LD_PRELOAD[v]; v++) + ; + NUM_LD_PRELOADS = v; + for (v = 0; LD_LIBRARY_PATH[v]; v++) + ; + NUM_LD_LIBPATHS = v; + for (v = 0; SP_ENV[v]; v++) + ; + NUM_SP_ENV_VARS = v; + for (v = 0; LD_ENV[v]; v++) + ; + NUM_LD_ENV_VARS = v; +} + +/* free the memory involved in backing up the environment */ +void +__collector_env_backup_free () +{ + int v = 0; + TprintfT (DBG_LT2, "env_backup_free()\n"); + for (v = 0; sp_env_backup[v]; v++) + { + TprintfT (DBG_LT2, "env_backup_free():sp_env_backup[%d]=%s \n", v, sp_env_backup[v]); + __collector_freeCSize (__collector_heap, (char *) sp_env_backup[v], __collector_strlen (sp_env_backup[v]) + 1); + } + __collector_freeCSize (__collector_heap, (char**) sp_env_backup, + (NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1) * sizeof (char*)); +} + +char ** +__collector_env_backup () +{ + TprintfT (DBG_LT2, "env_backup_()\n"); + char **backup = __collector_env_allocate (NULL, 1); + __collector_env_update (backup); + TprintfT (DBG_LT2, "env_backup_()\n"); + return backup; +} + +/* + function: env_prepend() + given an <old_str>, check to see if <str> + is already defined by it. If not, allocate + a new string and concat <envvar>=<str><separator><old_str> + params: + old_str: original string + str: substring to prepend + return: pointer to updated string or NULL if string was not updated. + */ +static char * +env_prepend (const char *envvar, const char *str, const char *separator, + const char *old_str) +{ + if (!envvar || *envvar == 0 || !str || *str == 0) + { + /* nothing to do */ + TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") -- nothing to do\n", + envvar, str, separator, old_str); + + return NULL; + } + TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\")\n", + envvar, str, separator, old_str); + char *ev; + size_t strsz; + if (!old_str || *old_str == 0) + { + strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + 1; + ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1); + if (ev) + { + CALL_UTIL (snprintf)(ev, strsz, "%s=%s", envvar, str); + assert (__collector_strlen (ev) + 1 == strsz); + } + else + TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n"); + } + else + { + char *p = CALL_UTIL (strstr)(old_str, str); + if (p) + { + TprintfT (DBG_LT2, "env_prepend(): %s=%s was already set\n", + envvar, old_str); + return NULL; + } + strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + + __collector_strlen (separator) + __collector_strlen (old_str) + 1; + ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1); + if (ev) + { + CALL_UTIL (snprintf)(ev, strsz, "%s=%s%s%s", envvar, str, separator, old_str); + assert (__collector_strlen (ev) + 1 == strsz); + } + else + TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n"); + } + TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") returns \"%s\"\n", + envvar, str, separator, old_str, (ev == NULL ? "NULL" : ev)); + return ev; +} + +/* + function: putenv_prepend() + get environment variable <envvar>, check to see if <str> + is already defined by it. If not prepend <str> + and put it back to environment. + params: + envvar: environment variable + str: substring to find + return: 0==success, nonzero on failure. + */ +int +putenv_prepend (const char *envvar, const char *str, const char *separator) +{ + if (!envvar || *envvar == 0) + return 1; + const char * old_str = CALL_UTIL (getenv)(envvar); + char * newstr = env_prepend (envvar, str, separator, old_str); + if (newstr) + // now put the new variable into the environment + if (CALL_UTIL (putenv)(newstr) != 0) + { + TprintfT (DBG_LT2, "putenv_prepend(): ERROR %s is not set!\n", newstr); + return 1; + } + return 0; +} + +/* + function: env_strip() + Finds substr in origstr; Removes + all characters from previous ':' or ' ' + up to and including any trailing ':' or ' '. + params: + env: environment variable contents + str: substring to find + return: count of instances removed from env + */ +static int +env_strip (char *origstr, const char *substr) +{ + int removed = 0; + char *p, *q; + if (origstr == NULL || substr == NULL || *substr == 0) + return 0; + while ((p = q = CALL_UTIL (strstr)(origstr, substr))) + { + p += __collector_strlen (substr); + while (*p == ':' || *p == ' ') /* strip trailing separator */ + p++; + while (*q != ':' && *q != ' ' && *q != '=' && q != origstr) /* strip path */ + q--; + if (q != origstr) /* restore leading separator (if any) */ + q++; + __collector_strlcpy (q, p, __collector_strlen (p) + 1); + removed++; + } + return removed; +} + +/* + function: env_ld_preload_strip() + Removes known libcollector shared objects from envv. + params: + var: shared object name (leading characters don't have to match) + return: 0 = so's removed, non-zero = so's not found. + */ +static int +env_ld_preload_strip (char *envv) +{ + if (!envv || *envv == 0) + { + TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - envv is NULL\n"); + return -1; + } + for (int v = 0; SP_PRELOAD[v]; v++) + if (env_strip (envv, sp_preloads[v])) + return 0; + if (line_mode != LM_CLOSED) + TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - could not strip SP_PRELOADS from '%s'\n", + envv); + return -2; +} + +void +__collector_env_print (char * label) +{ +#if DEBUG + TprintfT (DBG_LT2, "__collector_env_print(%s)\n", label); + for (int v = 0; v < MAX_LD_PRELOADS; v++) + TprintfT (DBG_LT2, " %s sp_preloads[%d] (0x%p)=%s\n", label, + v, sp_preloads[v], (sp_preloads[v] == NULL ? "NULL" : sp_preloads[v])); + for (int v = 0; SP_ENV[v]; v++) + { + char *s = CALL_UTIL (getenv)(SP_ENV[v]); + if (s == NULL) + s = "<null>"; + TprintfT (DBG_LT2, " %s SP_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, SP_ENV[v], SP_ENV[v], s); + } + for (int v = 0; LD_ENV[v]; v++) + { + char *s = CALL_UTIL (getenv)(LD_ENV[v]); + if (s == NULL) + s = "<null>"; + TprintfT (DBG_LT2, " %s LD_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, LD_ENV[v], LD_ENV[v], s); + } +#endif +} + +void +__collector_env_printall (char *label, char *envp[]) +{ +#if DEBUG + TprintfT (DBG_LT2, "__collector_env_printall(%s): environment @ 0x%p\n", label, envp); + for (int i = 0; envp[i]; i++) + Tprintf (DBG_LT2, "\tenv[%d]@0x%p == %s\n", i, envp[i], envp[i]); +#endif +} + +/* match collector environment variable */ +int +env_match (char *envp[], const char *envvar) +{ + int match = -1; + if (envp == NULL) + TprintfT (DBG_LT1, "env_match(%s): NULL envp!\n", envvar); + else + { + int i = 0; + while ((envp[i] != NULL) && (__collector_strStartWith (envp[i], envvar))) + i++; + if ((envp[i] == NULL) || (envp[i][__collector_strlen (envvar)] != '=')) + TprintfT (DBG_LT4, "env_match(): @%p []%s not defined in envp\n", envp, envvar); + else + { + TprintfT (DBG_LT4, "env_match(): @%p [%d]%s defined in envp\n", envp, i, envp[i]); + match = i; + } + } + TprintfT (DBG_LT1, "env_match(%s): found in slot %d\n", envvar, match); + return (match); +} + +/* allocate new environment with collector variables */ +/* 1) copy all current envp[] ptrs into a new array, coll_env[] */ +/* 2) if collector-related env ptrs not in envp[], append them to coll_env */ +/* from processes' "environ" (allocate_env==1) */ +/* or from sp_env_backup (allocate_env==0)*/ +/* If they already exist in envp, probably is an error... */ +/* 3) return coll_env */ + +/* __collector__env_update() need be called after this to set LD_ENV*/ +char ** +__collector_env_allocate (char *const old_env[], int allocate_env) +{ + extern char **environ; /* the process' actual environment */ + char **new_env; /* a new environment for collection */ + TprintfT (DBG_LT3, "__collector_env_allocate(old_env=0x%p %s environ=0x%p)\n", + old_env, (old_env == environ) ? "==" : "!=", environ); + /* set up a copy of the provided old_env for collector use */ + int old_env_size = 0; + + /* determine number of (used) slots in old_env */ + if (old_env) + while (old_env[old_env_size] != NULL) + old_env_size++; + /* allocate a new vector with additional slots */ + int new_env_alloc_sz = old_env_size + NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1; + new_env = (char**) __collector_allocCSize (__collector_heap, new_env_alloc_sz * sizeof (char*), 1); + if (new_env == NULL) + return NULL; + TprintfT (DBG_LT4, "__collector_env_allocate(): old_env has %d entries, new_env @ 0x%p\n", old_env_size, new_env); + + /* copy provided old_env pointers to new collector environment */ + int new_env_size = 0; + for (new_env_size = 0; new_env_size < old_env_size; new_env_size++) + new_env[new_env_size] = old_env[new_env_size]; + + /* check each required environment variable, adding as required */ + const char * env_var; + int v; + for (v = 0; (env_var = SP_ENV[v]) != NULL; v++) + { + if (env_match ((char**) old_env, env_var) == -1) + { + int idx; + /* not found in old_env */ + if (allocate_env) + { + if ((idx = env_match (environ, env_var)) != -1) + { + /* found in environ */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, environ[idx]); + int varsz = __collector_strlen (environ[idx]) + 1; + char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1); + if (var == NULL) + return NULL; + __collector_strlcpy (var, environ[idx], varsz); + new_env[new_env_size++] = var; + } + else + { + /* not found in environ */ + if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) || + (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0)) + TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n", + env_var); + } + } + else + { + if ((idx = env_match (sp_env_backup, env_var)) != -1) + { + /* found in backup */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, sp_env_backup[idx]); + new_env[new_env_size++] = sp_env_backup[idx]; + } + else + { + /* not found in environ */ + if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) || + (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0)) + TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n", + env_var); + } + } + } + } + + for (v = 0; (env_var = LD_ENV[v]) != NULL; v++) + { + if (env_match ((char**) old_env, env_var) == -1) + { + int idx; + /* not found in old_env */ + if (allocate_env) + { + if ((idx = env_match (environ, env_var)) != -1) + { + /* found in environ */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, environ[idx]); + + int varsz = __collector_strlen (env_var) + 2; + char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1); + if (var == NULL) + return NULL; + // assume __collector_env_update() will fill content of env_var + CALL_UTIL (snprintf)(var, varsz, "%s=", env_var); + new_env[new_env_size++] = var; + } + } + else + { + if ((idx = env_match (sp_env_backup, env_var)) != -1) + { + /* found in backup */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, sp_env_backup[idx]); + new_env[new_env_size++] = sp_env_backup[idx]; + } + } + } + } + + /* ensure new_env vector ends with NULL */ + new_env[new_env_size] = NULL; + assert (new_env_size <= new_env_alloc_sz); + TprintfT (DBG_LT4, "__collector_env_allocate(): new_env has %d entries (%d added), new_env=0x%p\n", + new_env_size, new_env_size - old_env_size, new_env); + if (new_env_size != old_env_size && !allocate_env) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n", + SP_JCMD_CWARN, COL_WARN_EXECENV, new_env_size - old_env_size); + __collector_env_printall ("__collector_env_allocate", new_env); + return (new_env); +} + +/* unset collection environment variables */ +/* if they exist in env... */ +/* 1) push non-collectorized version to env */ + +/* Not mt safe */ +void +__collector_env_unset (char *envp[]) +{ + int v; + const char * env_name; + TprintfT (DBG_LT3, "env_unset(envp=0x%p)\n", envp); + if (envp == NULL) + { + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + { + const char *env_val = CALL_UTIL (getenv)(env_name); + if (env_val && CALL_UTIL (strstr)(env_val, sp_preloads[v])) + { + size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1; + char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return; + CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val); + assert (__collector_strlen (ev) + 1 == sz); + TprintfT (DBG_LT4, "env_unset(): old %s\n", ev); + env_ld_preload_strip (ev); + CALL_UTIL (putenv)(ev); + TprintfT (DBG_LT4, "env_unset(): new %s\n", ev); + } + } + // unset JAVA_TOOL_OPTIONS + env_name = JAVA_TOOL_OPTIONS; + const char * env_val = CALL_UTIL (getenv)(env_name); + if (env_val && CALL_UTIL (strstr)(env_val, COLLECTOR_JVMTI_OPTION)) + { + size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1; + char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return; + CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val); + assert (__collector_strlen (ev) + 1 == sz); + TprintfT (DBG_LT4, "env_unset(): old %s\n", ev); + env_strip (ev, COLLECTOR_JVMTI_OPTION); + CALL_UTIL (putenv)(ev); + TprintfT (DBG_LT4, "env_unset(): new %s\n", ev); + } + __collector_env_print ("__collector_env_unset"); + } + else + { + __collector_env_printall ("__collector_env_unset, before", envp); + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + { + int idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = envp[idx]; + TprintfT (DBG_LT4, "env_unset(): old %s\n", env_val); + envp[idx] = "junk="; /* xxxx is it ok to use original string? */ + env_ld_preload_strip (env_val); + envp[idx] = env_val; + TprintfT (DBG_LT4, "env_unset(): new %s\n", envp[idx]); + } + } + // unset JAVA_TOOL_OPTIONS + env_name = JAVA_TOOL_OPTIONS; + int idx = env_match(envp, env_name); + if (idx != -1) { + char *env_val = envp[idx]; + TprintfT(DBG_LT4, "env_unset(): old %s\n", env_val); + envp[idx] = "junk="; /* xxxx is it ok to use original string? */ + env_strip(env_val, COLLECTOR_JVMTI_OPTION); + envp[idx] = env_val; + TprintfT(DBG_LT4, "env_unset(): new %s\n", envp[idx]); + } + __collector_env_printall ("__collector_env_unset, after", envp ); + } +} + +/* update collection environment variables */ +/* update LD_PRELOADs and push them */ +/* not mt safe */ +void +__collector_env_update (char *envp[]) +{ + const char *env_name; + TprintfT (DBG_LT1, "__collector_env_update(envp=0x%p)\n", envp); + extern char **environ; + if (envp == NULL) + { + int v; + TprintfT (DBG_LT2, "__collector_env_update(envp=NULL)\n"); + __collector_env_printall (" environ array, before", environ); + __collector_env_print (" env_update at entry "); + + /* SP_ENV */ + for (v = 0; (env_name = SP_ENV[v]) != NULL; v++) + { + if (env_match (environ, env_name) == -1) + { + int idx; + if ((idx = env_match (sp_env_backup, env_name)) != -1) + { + unsigned strsz = __collector_strlen (sp_env_backup[idx]) + 1; + char *ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1); + CALL_UTIL (snprintf)(ev, strsz, "%s", sp_env_backup[idx]); + if (CALL_UTIL (putenv)(ev) != 0) + TprintfT (DBG_LT2, "__collector_env_update(): ERROR %s is not set!\n", + sp_env_backup[idx]); + } + } + } + __collector_env_print (" env_update after SP_ENV settings "); + + /* LD_LIBRARY_PATH */ + for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++) + /* assumes same index used between LD and SP vars */ + if (putenv_prepend (env_name, sp_libpaths[v], ":")) + TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n", + env_name, sp_libpaths[v]); + __collector_env_print (" env_update after LD_LIBRARY_PATH settings "); + + /* LD_PRELOAD */ + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + /* assumes same index used between LD and SP vars */ + if (putenv_prepend (env_name, sp_preloads[v], " ")) + TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n", + env_name, sp_preloads[v]); + __collector_env_print (" env_update after LD_PRELOAD settings "); + + /* JAVA_TOOL_OPTIONS */ + if (java_mode) + if (putenv_prepend (JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION, " ")) + TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n", + JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION); + __collector_env_print (" env_update after JAVA_TOOL settings "); + } + else + { + int v; + int idx; + TprintfT (DBG_LT2, "__collector_env_update(envp=0x%p) not NULL\n", envp); + __collector_env_printall ("__collector_env_update, before", envp); + /* LD_LIBRARY_PATH */ + for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++) + { + int idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = __collector_strchr (envp[idx], '='); + if (env_val) + env_val++; /* skip '=' */ + /* assumes same index used between LD and SP vars */ + char *new_str = env_prepend (env_name, sp_libpaths[v], + ":", env_val); + if (new_str) + envp[idx] = new_str; + } + } + + /* LD_PRELOAD */ + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + { + int idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = __collector_strchr (envp[idx], '='); + if (env_val) + env_val++; /* skip '=' */ + /* assumes same index used between LD and SP vars */ + char *new_str = env_prepend (env_name, sp_preloads[v], + " ", env_val); + if (new_str) + envp[idx] = new_str; + } + } + + /* JAVA_TOOL_OPTIONS */ + if (java_mode) + { + env_name = JAVA_TOOL_OPTIONS; + idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = __collector_strchr (envp[idx], '='); + if (env_val) + env_val++; /* skip '=' */ + char *new_str = env_prepend (env_name, COLLECTOR_JVMTI_OPTION, + " ", env_val); + if (new_str) + envp[idx] = new_str; + } + } + } + __collector_env_printall ("__collector_env_update, after", environ); +} + + +/*------------------------------------------------------------- putenv */ +int putenv () __attribute__ ((weak, alias ("__collector_putenv"))); +int _putenv () __attribute__ ((weak, alias ("__collector_putenv"))); + +int +__collector_putenv (char * string) +{ + if (CALL_UTIL (putenv) == __collector_putenv || + CALL_UTIL (putenv) == NULL) + { // __collector_libc_funcs_init failed + CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_NEXT, "putenv"); + if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv) + CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_DEFAULT, "putenv"); + if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv) + { + TprintfT (DBG_LT2, "__collector_putenv(): ERROR: no pointer found.\n"); + errno = EBUSY; + return -1; + } + } + if (user_follow_mode == FOLLOW_NONE) + return CALL_UTIL (putenv)(string); + char * envp[] = {string, NULL}; + __collector_env_update (envp); + return CALL_UTIL (putenv)(envp[0]); +} + +/*------------------------------------------------------------- setenv */ +int setenv () __attribute__ ((weak, alias ("__collector_setenv"))); +int _setenv () __attribute__ ((weak, alias ("__collector_setenv"))); + +int +__collector_setenv (const char *name, const char *value, int overwrite) +{ + if (CALL_UTIL (setenv) == __collector_setenv || + CALL_UTIL (setenv) == NULL) + { // __collector_libc_funcs_init failed + CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_NEXT, "setenv"); + if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv) + CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_DEFAULT, "setenv"); + if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv) + { + TprintfT (DBG_LT2, "__collector_setenv(): ERROR: no pointer found.\n"); + errno = EBUSY; + return -1; + } + } + if (user_follow_mode == FOLLOW_NONE || !overwrite) + return CALL_UTIL (setenv)(name, value, overwrite); + size_t sz = __collector_strlen (name) + 1 + __collector_strlen (value) + 1; + char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return CALL_UTIL (setenv)(name, value, overwrite); + CALL_UTIL (snprintf)(ev, sz, "%s=%s", name, value); + char * envp[] = {ev, NULL}; + __collector_env_update (envp); + if (envp[0] == ev) + { + __collector_freeCSize (__collector_heap, ev, sz); + return CALL_UTIL (setenv)(name, value, overwrite); + } + else + { + char *env_val = __collector_strchr (envp[0], '='); + if (env_val) + { + *env_val = '\0'; + env_val++; /* skip '=' */ + } + return CALL_UTIL (setenv)(envp[0], env_val, overwrite); + } +} + +/*------------------------------------------------------------- unsetenv */ +int unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv"))); +int _unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv"))); + +int +__collector_unsetenv (const char *name) +{ + if (CALL_UTIL (unsetenv) == __collector_unsetenv || + CALL_UTIL (unsetenv) == NULL) + { // __collector_libc_funcs_init failed + CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_NEXT, "unsetenv"); + if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv) + CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_DEFAULT, "unsetenv"); + if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv) + { + TprintfT (DBG_LT2, "__collector_unsetenv(): ERROR: no pointer found.\n"); + errno = EBUSY; + return -1; + } + } + int ret = CALL_UTIL (unsetenv)(name); + if (user_follow_mode == FOLLOW_NONE) + return ret; + TprintfT (DBG_LT2, "__collector_unsetenv(): %d.\n", user_follow_mode); + size_t sz = __collector_strlen (name) + 1 + 1; + char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return ret; + CALL_UTIL (snprintf)(ev, sz, "%s=", name); + char * envp[] = {ev, NULL}; + __collector_env_update (envp); + if (envp[0] == ev) + __collector_freeCSize (__collector_heap, ev, sz); + else + CALL_UTIL (putenv)(envp[0]); + return ret; +} + +/*------------------------------------------------------------- clearenv */ +int clearenv () __attribute__ ((weak, alias ("__collector_clearenv"))); + +int +__collector_clearenv (void) +{ + if (CALL_UTIL (clearenv) == __collector_clearenv || CALL_UTIL (clearenv) == NULL) + { + /* __collector_libc_funcs_init failed; look up clearenv now */ + CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_NEXT, "clearenv"); + if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv) + /* still not found; try again */ + CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_DEFAULT, "clearenv"); + if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv) + { + /* still not found -- a fatal error */ + TprintfT (DBG_LT2, "__collector_clearenv(): ERROR: %s\n", dlerror ()); + CALL_UTIL (fprintf)(stderr, "__collector_clearenv(): ERROR: %s\n", dlerror ()); + errno = EBUSY; + return -1; + } + } + int ret = CALL_UTIL (clearenv)(); + if (user_follow_mode == FOLLOW_NONE) + return ret; + if (sp_env_backup == NULL) + { + TprintfT (DBG_LT2, "__collector_clearenv: ERROR sp_env_backup is not set!\n"); + return ret; + } + for (int v = 0; v < NUM_SP_ENV_VARS + NUM_LD_ENV_VARS; v++) + if (sp_env_backup[v] && CALL_UTIL (putenv)(sp_env_backup[v]) != 0) + TprintfT (DBG_LT2, "__collector_clearenv: ERROR %s is not set!\n", + sp_env_backup[v]); + return ret; +} diff --git a/gprofng/libcollector/gethrtime.c b/gprofng/libcollector/gethrtime.c new file mode 100644 index 0000000..f369cdc --- /dev/null +++ b/gprofng/libcollector/gethrtime.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <time.h> +#include "gp-time.h" + +/* + * CLOCK_MONOTONIC + * Clock that cannot be set and represents monotonic time since some + * unspecified starting point. + */ +static hrtime_t +linux_gethrtime () +{ + struct timespec tp; + hrtime_t rc = 0; + int r = clock_gettime (CLOCK_MONOTONIC_RAW, &tp); + if (r == 0) + rc = ((hrtime_t) tp.tv_sec)*1000000000 + (hrtime_t) tp.tv_nsec; + return rc; +} + +hrtime_t (*__collector_gethrtime)() = linux_gethrtime; diff --git a/gprofng/libcollector/heaptrace.c b/gprofng/libcollector/heaptrace.c new file mode 100644 index 0000000..470a269 --- /dev/null +++ b/gprofng/libcollector/heaptrace.c @@ -0,0 +1,503 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Heap tracing events + */ + +#include "config.h" +#include <dlfcn.h> + +#include "gp-defs.h" +#include "collector_module.h" +#include "gp-experiment.h" +#include "data_pckts.h" +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 +#define DBG_LT4 4 + +/* define the packets to be written out */ +typedef struct Heap_packet +{ /* Malloc/free tracing packet */ + Common_packet comm; + Heap_type mtype; /* subtype of packet */ + Size_type size; /* size of malloc/realloc request */ + Vaddr_type vaddr; /* vaddr given to free or returned from malloc/realloc */ + Vaddr_type ovaddr; /* Previous vaddr given to realloc */ +} Heap_packet; + +static int init_heap_intf (); +static int open_experiment (const char *); +static int start_data_collection (void); +static int stop_data_collection (void); +static int close_experiment (void); +static int detach_experiment (void); + +static ModuleInterface module_interface = { + SP_HEAPTRACE_FILE, /* description */ + NULL, /* initInterface */ + open_experiment, /* openExperiment */ + start_data_collection, /* startDataCollection */ + stop_data_collection, /* stopDataCollection */ + close_experiment, /* closeExperiment */ + detach_experiment /* detachExperiment (fork child) */ +}; + +static CollectorInterface *collector_interface = NULL; +static int heap_mode = 0; +static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR; +static unsigned heap_key = COLLECTOR_TSD_INVALID_KEY; + +#define CHCK_REENTRANCE(x) ( !heap_mode || ((x) = collector_interface->getKey( heap_key )) == NULL || (*(x) != 0) ) +#define PUSH_REENTRANCE(x) ((*(x))++) +#define POP_REENTRANCE(x) ((*(x))--) +#define CALL_REAL(x) (__real_##x) +#define NULL_PTR(x) (__real_##x == NULL) +#define gethrtime collector_interface->getHiResTime + +#ifdef DEBUG +#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ ) +#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ ) +#else +#define Tprintf(...) +#define TprintfT(...) +#endif + +static void *(*__real_malloc)(size_t) = NULL; +static void (*__real_free)(void *); +static void *(*__real_realloc)(void *, size_t); +static void *(*__real_memalign)(size_t, size_t); +static void *(*__real_calloc)(size_t, size_t); +static void *(*__real_valloc)(size_t); +static char *(*__real_strchr)(const char *, int); + +void *__libc_malloc (size_t); +void __libc_free (void *); +void *__libc_realloc (void *, size_t); + +static void +collector_memset (void *s, int c, size_t n) +{ + unsigned char *s1 = s; + while (n--) + *s1++ = (unsigned char) c; +} + +void +__collector_module_init (CollectorInterface *_collector_interface) +{ + if (_collector_interface == NULL) + return; + collector_interface = _collector_interface; + Tprintf (0, "heaptrace: __collector_module_init\n"); + heap_hndl = collector_interface->registerModule (&module_interface); + + /* Initialize next module */ + ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init"); + if (next_init != NULL) + next_init (_collector_interface); + return; +} + +static int +open_experiment (const char *exp) +{ + if (collector_interface == NULL) + { + Tprintf (0, "heaptrace: collector_interface is null.\n"); + return COL_ERROR_HEAPINIT; + } + if (heap_hndl == COLLECTOR_MODULE_ERR) + { + Tprintf (0, "heaptrace: handle create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_HEAPINIT); + return COL_ERROR_HEAPINIT; + } + TprintfT (0, "heaptrace: open_experiment %s\n", exp); + if (NULL_PTR (malloc)) + init_heap_intf (); + + const char *params = collector_interface->getParams (); + while (params) + { + if ((params[0] == 'H') && (params[1] == ':')) + { + params += 2; + break; + } + params = CALL_REAL (strchr)(params, ';'); + if (params) + params++; + } + if (params == NULL) /* Heap data collection not specified */ + return COL_ERROR_HEAPINIT; + + heap_key = collector_interface->createKey (sizeof ( int), NULL, NULL); + if (heap_key == (unsigned) - 1) + { + Tprintf (0, "heaptrace: TSD key create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_HEAPINIT); + return COL_ERROR_HEAPINIT; + } + collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE); + collector_interface->writeLog (" <profdata fname=\"%s\"/>\n", + module_interface.description); + + /* Record Heap_packet description */ + Heap_packet *pp = NULL; + collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Heap tracing data\">\n", HEAP_PCKT); + collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"HTYPE\" uname=\"Heap trace function type\" offset=\"%d\" type=\"%s\"/>\n", + &pp->mtype, sizeof (pp->mtype) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"HSIZE\" uname=\"Memory size\" offset=\"%d\" type=\"%s\"/>\n", + &pp->size, sizeof (pp->size) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" <field name=\"HVADDR\" uname=\"Memory address\" offset=\"%d\" type=\"%s\"/>\n", + &pp->vaddr, sizeof (pp->vaddr) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" <field name=\"HOVADDR\" uname=\"Previous memory address\" offset=\"%d\" type=\"%s\"/>\n", + &pp->ovaddr, sizeof (pp->ovaddr) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" </profpckt>\n"); + collector_interface->writeLog ("</profile>\n"); + return COL_ERROR_NONE; +} + +static int +start_data_collection (void) +{ + heap_mode = 1; + Tprintf (0, "heaptrace: start_data_collection\n"); + return 0; +} + +static int +stop_data_collection (void) +{ + heap_mode = 0; + Tprintf (0, "heaptrace: stop_data_collection\n"); + return 0; +} + +static int +close_experiment (void) +{ + heap_mode = 0; + heap_key = COLLECTOR_TSD_INVALID_KEY; + Tprintf (0, "heaptrace: close_experiment\n"); + return 0; +} + +static int +detach_experiment (void) +/* fork child. Clean up state but don't write to experiment */ +{ + heap_mode = 0; + heap_key = COLLECTOR_TSD_INVALID_KEY; + Tprintf (0, "heaptrace: detach_experiment\n"); + return 0; +} + +static int in_init_heap_intf = 0; // Flag that we are in init_heap_intf() + +static int +init_heap_intf () +{ + void *dlflag; + in_init_heap_intf = 1; + __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc"); + if (__real_malloc == NULL) + { + /* We are probably dlopened after libthread/libc, + * try to search in the previously loaded objects + */ + __real_malloc = (void*(*)(size_t))dlsym (RTLD_DEFAULT, "malloc"); + if (__real_malloc == NULL) + { + Tprintf (0, "heaptrace: ERROR: real malloc not found\n"); + in_init_heap_intf = 0; + return 1; + } + Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_DEFAULT\n"); + dlflag = RTLD_DEFAULT; + } + else + { + Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_NEXT\n"); + dlflag = RTLD_NEXT; + } + __real_free = (void(*)(void *))dlsym (dlflag, "free"); + __real_realloc = (void*(*)(void *, size_t))dlsym (dlflag, "realloc"); + __real_memalign = (void*(*)(size_t, size_t))dlsym (dlflag, "memalign"); + __real_calloc = (void*(*)(size_t, size_t))dlsym (dlflag, "calloc"); + __real_valloc = (void*(*)(size_t))dlsym (dlflag, "valloc"); + __real_strchr = (char*(*)(const char *, int))dlsym (dlflag, "strchr"); + Tprintf (0, "heaptrace: init_heap_intf done\n"); + in_init_heap_intf = 0; + return 0; +} + +/*------------------------------------------------------------- malloc */ + +void * +malloc (size_t size) +{ + void *ret; + int *guard; + Heap_packet hpacket; + /* Linux startup workaround */ + if (!heap_mode) + { + void *ppp = (void *) __libc_malloc (size); + Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)...\n", (long) size, ppp); + return ppp; + } + if (NULL_PTR (malloc)) + init_heap_intf (); + if (CHCK_REENTRANCE (guard)) + { + ret = (void *) CALL_REAL (malloc)(size); + Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret); + return ret; + } + PUSH_REENTRANCE (guard); + + ret = (void *) CALL_REAL (malloc)(size); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = gethrtime (); + hpacket.mtype = MALLOC_TRACE; + hpacket.size = (Size_type) size; + hpacket.vaddr = (Vaddr_type) ret; + hpacket.ovaddr = (Vaddr_type) 0; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return (void *) ret; +} + +/*------------------------------------------------------------- free */ + +void +free (void *ptr) +{ + int *guard; + Heap_packet hpacket; + /* Linux startup workaround */ + if (!heap_mode) + { + // Tprintf(DBG_LT4,"heaptrace: LINUX free(%p)...\n",ptr); + __libc_free (ptr); + return; + } + if (NULL_PTR (malloc)) + init_heap_intf (); + if (CHCK_REENTRANCE (guard)) + { + CALL_REAL (free)(ptr); + return; + } + if (ptr == NULL) + return; + PUSH_REENTRANCE (guard); + + /* Get a timestamp before 'free' to enforce consistency */ + hrtime_t ts = gethrtime (); + CALL_REAL (free)(ptr); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = ts; + hpacket.mtype = FREE_TRACE; + hpacket.size = (Size_type) 0; + hpacket.vaddr = (Vaddr_type) ptr; + hpacket.ovaddr = (Vaddr_type) 0; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return; +} + +/*------------------------------------------------------------- realloc */ +void * +realloc (void *ptr, size_t size) +{ + void *ret; + int *guard; + Heap_packet hpacket; + + /* Linux startup workaround */ + if (!heap_mode) + { + void * ppp = (void *) __libc_realloc (ptr, size); + Tprintf (DBG_LT4, "heaptrace: LINUX realloc(%ld, %p->%p)...\n", + (long) size, ptr, ppp); + return ppp; + } + if (NULL_PTR (realloc)) + init_heap_intf (); + if (CHCK_REENTRANCE (guard)) + { + ret = (void *) CALL_REAL (realloc)(ptr, size); + return ret; + } + PUSH_REENTRANCE (guard); + hrtime_t ts = gethrtime (); + ret = (void *) CALL_REAL (realloc)(ptr, size); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = ts; + hpacket.mtype = REALLOC_TRACE; + hpacket.size = (Size_type) size; + hpacket.vaddr = (Vaddr_type) ret; + hpacket.ovaddr = (Vaddr_type) ptr; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return (void *) ret; +} + +/*------------------------------------------------------------- memalign */ +void * +memalign (size_t align, size_t size) +{ + void *ret; + int *guard; + Heap_packet hpacket; + if (NULL_PTR (memalign)) + init_heap_intf (); + if (CHCK_REENTRANCE (guard)) + { + ret = (void *) CALL_REAL (memalign)(align, size); + return ret; + } + PUSH_REENTRANCE (guard); + ret = (void *) CALL_REAL (memalign)(align, size); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = gethrtime (); + hpacket.mtype = MALLOC_TRACE; + hpacket.size = (Size_type) size; + hpacket.vaddr = (Vaddr_type) ret; + hpacket.ovaddr = (Vaddr_type) 0; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- valloc */ + +void * +valloc (size_t size) +{ + void *ret; + int *guard; + Heap_packet hpacket; + if (NULL_PTR (memalign)) + init_heap_intf (); + if (CHCK_REENTRANCE (guard)) + { + ret = (void *) CALL_REAL (valloc)(size); + return ret; + } + PUSH_REENTRANCE (guard); + ret = (void *) CALL_REAL (valloc)(size); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = gethrtime (); + hpacket.mtype = MALLOC_TRACE; + hpacket.size = (Size_type) size; + hpacket.vaddr = (Vaddr_type) ret; + hpacket.ovaddr = (Vaddr_type) 0; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- calloc */ +void * +calloc (size_t size, size_t esize) +{ + void *ret; + int *guard; + Heap_packet hpacket; + if (NULL_PTR (calloc)) + { + if (in_init_heap_intf != 0) + return NULL; // Terminate infinite loop + init_heap_intf (); + } + if (CHCK_REENTRANCE (guard)) + { + ret = (void *) CALL_REAL (calloc)(size, esize); + return ret; + } + PUSH_REENTRANCE (guard); + ret = (void *) CALL_REAL (calloc)(size, esize); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = gethrtime (); + hpacket.mtype = MALLOC_TRACE; + hpacket.size = (Size_type) (size * esize); + hpacket.vaddr = (Vaddr_type) ret; + hpacket.ovaddr = (Vaddr_type) 0; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return ret; +} + +/* __collector_heap_record is used to record java allocations/deallocations. + * It uses the same facilities as regular heap tracing for now. + */ +void +__collector_heap_record (int mtype, size_t size, void *vaddr) +{ + int *guard; + Heap_packet hpacket; + if (CHCK_REENTRANCE (guard)) + return; + PUSH_REENTRANCE (guard); + collector_memset (&hpacket, 0, sizeof ( Heap_packet)); + hpacket.comm.tsize = sizeof ( Heap_packet); + hpacket.comm.tstamp = gethrtime (); + hpacket.mtype = mtype; + hpacket.size = (Size_type) size; + hpacket.vaddr = (Vaddr_type) vaddr; + hpacket.ovaddr = (Vaddr_type) 0; + hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket); + collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket); + POP_REENTRANCE (guard); + return; +} diff --git a/gprofng/libcollector/hwprofile.c b/gprofng/libcollector/hwprofile.c new file mode 100644 index 0000000..6fdaf1b --- /dev/null +++ b/gprofng/libcollector/hwprofile.c @@ -0,0 +1,905 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* Hardware counter profiling */ + +#include "config.h" +#include <alloca.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/syscall.h> +#include <signal.h> +#include <ucontext.h> + +#include "gp-defs.h" +#define _STRING_H 1 /* XXX MEZ: temporary workaround */ +#include "hwcdrv.h" +#include "collector_module.h" +#include "gp-experiment.h" +#include "libcol_util.h" +#include "hwprofile.h" +#include "ABS.h" +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 +#define DBG_LT4 4 +#define DBG_LT5 5 + +#define SD_OFF 0 /* before start or after close she shut down process */ +#define SD_PENDING 1 /* before running real_detach_experiment() */ +#define SD_COMPLETE 2 /* after running real_detach_experiment() */ + +static int init_interface (CollectorInterface*); +static int open_experiment (const char *); +static int start_data_collection (void); +static int stop_data_collection (void); +static int close_experiment (void); +static int detach_experiment (void); +static int real_detach_experiment (void); + +static ModuleInterface module_interface ={ + SP_HWCNTR_FILE, /* description */ + init_interface, /* initInterface */ + open_experiment, /* openExperiment */ + start_data_collection, /* startDataCollection */ + stop_data_collection, /* stopDataCollection */ + close_experiment, /* closeExperiment */ + detach_experiment /* detachExperiment (fork child) */ +}; + +static CollectorInterface *collector_interface = NULL; + + +/*---------------------------------------------------------------------------*/ +/* compile options and workarounds */ + +/* Solaris: We set ITIMER_REALPROF to ensure that counters get started on + * LWPs that existed before the collector initialization. + * + * In addition, if the appropriate #define's are set, we check for: + * lost-hw-overflow -- the HW counters rollover, but the overflow + * interrupt is not generated (counters keep running) + * lost-sigemt -- the interrupt is received by the kernel, + * which stops the counters, but the kernel fails + * to deliver the signal. + */ + +/*---------------------------------------------------------------------------*/ +/* typedefs */ + +typedef enum { + HWCMODE_OFF, /* before start or after close */ + HWCMODE_SUSPEND, /* stop_data_collection called */ + HWCMODE_ACTIVE, /* counters are defined and after start_data_collection() */ + HWCMODE_ABORT /* fatal error occured. Log a message, stop recording */ +} hwc_mode_t; + +/*---------------------------------------------------------------------------*/ +/* prototypes */ +static void init_ucontexts (void); +static int hwc_initialize_handlers (void); +static void collector_record_counter (ucontext_t*, + int timecvt, + ABST_type, hrtime_t, + unsigned, uint64_t); +static void collector_hwc_ABORT (int errnum, const char *msg); +static void hwclogwrite0 (); +static void hwclogwrite (Hwcentry *); +static void set_hwc_mode (hwc_mode_t); +static void collector_sigemt_handler (int sig, siginfo_t *si, void *puc); + +/*---------------------------------------------------------------------------*/ +/* static variables */ + +/* --- user counter selections and options */ +static int hwcdef_has_memspace; /* true to indicate use of extened packets */ +static unsigned hwcdef_cnt; /* number of *active* hardware counters */ +static unsigned hwcdef_num_sampling_ctrdefs; /* ctrs that use sampling */ +static unsigned hwcdef_num_overflow_ctrdefs; /* ctrs that use overflow */ +static Hwcentry **hwcdef; /* HWC definitions */ +static int cpcN_cpuver = CPUVER_UNDEFINED; +static int hwcdrv_inited; /* Don't call hwcdrv_init() in fork_child */ +static hwcdrv_api_t *hwc_driver = NULL; +static unsigned hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY; +static int hwprofile_tsd_sz = 0; +static volatile hwc_mode_t hwc_mode = HWCMODE_OFF; +static volatile unsigned int nthreads_in_sighandler = 0; +static volatile unsigned int sd_state = SD_OFF; + +/* --- experiment logging state */ +static CollectorModule expr_hndl = COLLECTOR_MODULE_ERR; +static ucontext_t expr_dummy_uc; // used for hacked "collector" frames +static ucontext_t expr_out_of_range_uc; // used for "out-of-range" frames +static ucontext_t expr_frozen_uc; // used for "frozen" frames +static ucontext_t expr_nopc_uc; // used for not-program-related frames +static ucontext_t expr_lostcounts_uc; // used for lost_counts frames + +/* --- signal handler state */ +static struct sigaction old_sigemt_handler; //overwritten in fork-child + +/*---------------------------------------------------------------------------*/ +/* macros */ +#define COUNTERS_ENABLED() (hwcdef_cnt) +#define gethrtime collector_interface->getHiResTime + +#ifdef DEBUG +#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ ) +#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ ) +#else +#define Tprintf(...) +#define TprintfT(...) +#endif + + +/*---------------------------------------------------------------------------*/ + +/* Initialization routines */ +static hwcdrv_api_t * +get_hwc_driver () +{ + if (hwc_driver == NULL) + hwc_driver = __collector_get_hwcdrv (); + return hwc_driver; +} + +static void init_module () __attribute__ ((constructor)); +static void +init_module () +{ + __collector_dlsym_guard = 1; + RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module"); + __collector_dlsym_guard = 0; + if (reg_module == NULL) + { + TprintfT (0, "hwprofile: init_module FAILED - reg_module = NULL\n"); + return; + } + expr_hndl = reg_module (&module_interface); + if (expr_hndl == COLLECTOR_MODULE_ERR) + { + TprintfT (0, "hwprofile: ERROR: handle not created.\n"); + if (collector_interface) + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCINIT); + } +} + +static int +init_interface (CollectorInterface *_collector_interface) +{ + collector_interface = _collector_interface; + return COL_ERROR_NONE; +} + +static void * +hwprofile_get_tsd () +{ + return collector_interface->getKey (hwprofile_tsd_key); +} + +static int +open_experiment (const char *exp) +{ + if (collector_interface == NULL) + { + TprintfT (0, "hwprofile: ERROR: collector_interface is null.\n"); + return COL_ERROR_HWCINIT; + } + const char *params = collector_interface->getParams (); + while (params) + { + if (__collector_strStartWith (params, "h:*") == 0) + { + /* HWC counters set by default */ + collector_interface->writeLog ("<%s %s=\"1\"/>\n", + SP_TAG_SETTING, SP_JCMD_HWC_DEFAULT); + params += 3; + break; + } + else if (__collector_strStartWith (params, "h:") == 0) + { + params += 2; + break; + } + params = CALL_UTIL (strchr)(params, ';'); + if (params) + params++; + } + if (params == NULL) /* HWC profiling not specified */ + return COL_ERROR_HWCINIT; + char *s = CALL_UTIL (strchr)(params, (int) ';'); + int sz = s ? s - params : CALL_UTIL (strlen)(params); + char *defstring = (char*) alloca (sz + 1); + CALL_UTIL (strlcpy)(defstring, params, sz + 1); + TprintfT (0, "hwprofile: open_experiment %s -- %s\n", exp, defstring); + + int err = COL_ERROR_NONE; + /* init counter library */ + if (!hwcdrv_inited) + { /* do not call hwcdrv_init() from fork-child */ + hwcdrv_inited = 1; + get_hwc_driver (); + if (hwc_driver->hwcdrv_init (collector_hwc_ABORT, &hwprofile_tsd_sz) == 0) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring); + TprintfT (0, "hwprofile: ERROR: hwcfuncs_init() failed\n"); + return COL_ERROR_HWCINIT; + } + + if (hwc_driver->hwcdrv_enable_mt (hwprofile_get_tsd)) + { + // It is OK to call hwcdrv_enable_mt() before tsd key is created + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring); + TprintfT (0, "hwprofile: ERROR: hwcdrv_enable_mt() failed\n"); + return COL_ERROR_HWCINIT; + } + + hwc_driver->hwcdrv_get_info (&cpcN_cpuver, NULL, NULL, NULL, NULL); + if (cpcN_cpuver < 0) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring); + TprintfT (0, "hwprofile: ERROR: hwcdrv_get_info() failed\n"); + return COL_ERROR_HWCINIT; + } + } + + if (hwprofile_tsd_sz) + { + hwprofile_tsd_key = collector_interface->createKey (hwprofile_tsd_sz, NULL, NULL); + if (hwprofile_tsd_key == COLLECTOR_TSD_INVALID_KEY) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring); + TprintfT (0, "hwprofile: ERROR: TSD createKey failed\n"); + return COL_ERROR_HWCINIT; + } + } + hwcdef_cnt = 0; + hwcdef_has_memspace = 0; + + /* create counters based on hwcdef[] */ + err = __collector_hwcfuncs_bind_descriptor (defstring); + if (err) + { + err = err == HWCFUNCS_ERROR_HWCINIT ? COL_ERROR_HWCINIT : COL_ERROR_HWCARGS; + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, err, defstring); + TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err); + return err; + } + + /* generate an array of counter structures for each requested counter */ + hwcdef = __collector_hwcfuncs_get_ctrs (&hwcdef_cnt); + hwcdef_num_sampling_ctrdefs = hwcdef_num_overflow_ctrdefs = 0; + int idx; + for (idx = 0; idx < hwcdef_cnt; idx++) + { + if (HWCENTRY_USES_SAMPLING (hwcdef[idx])) + { + hwcdef_num_sampling_ctrdefs++; + } + else + { + hwcdef_num_overflow_ctrdefs++; + } + } + + init_ucontexts (); + + /* initialize the SIGEMT handler, and the periodic HWC checker */ + err = hwc_initialize_handlers (); + if (err != COL_ERROR_NONE) + { + hwcdef_cnt = 0; + TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err); + /* log written by hwc_initialize_handlers() */ + return err; + } + + for (idx = 0; idx < hwcdef_cnt; idx++) + if (ABST_BACKTRACK_ENABLED (hwcdef[idx]->memop)) + hwcdef_has_memspace = 1; + + /* record the hwc definitions in the log, based on the counter array */ + hwclogwrite0 (); + for (idx = 0; idx < hwcdef_cnt; idx++) + hwclogwrite (hwcdef[idx]); + return COL_ERROR_NONE; +} + +int +__collector_ext_hwc_lwp_init () +{ + return get_hwc_driver ()->hwcdrv_lwp_init (); +} + +void +__collector_ext_hwc_lwp_fini () +{ + get_hwc_driver ()->hwcdrv_lwp_fini (); +} + +int +__collector_ext_hwc_lwp_suspend () +{ + return get_hwc_driver ()->hwcdrv_lwp_suspend (); +} + +int +__collector_ext_hwc_lwp_resume () +{ + return get_hwc_driver ()->hwcdrv_lwp_resume (); +} + +/* Dummy routine, used to provide a context for non-program related profiles */ +void +__collector_not_program_related () { } + +/* Dummy routine, used to provide a context for lost counts (perf_events) */ +void +__collector_hwc_samples_lost () { } + +/* Dummy routine, used to provide a context */ +void +__collector_hwcs_frozen () { } + +/* Dummy routine, used to provide a context */ +void +__collector_hwcs_out_of_range () { } +/* initialize some structures */ +static void +init_ucontexts (void) +{ + /* initialize dummy context for "collector" frames */ + getcontext (&expr_dummy_uc); + SETFUNCTIONCONTEXT (&expr_dummy_uc, NULL); + + /* initialize dummy context for "out-of-range" frames */ + getcontext (&expr_out_of_range_uc); + SETFUNCTIONCONTEXT (&expr_out_of_range_uc, &__collector_hwcs_out_of_range); + + /* initialize dummy context for "frozen" frames */ + getcontext (&expr_frozen_uc); + SETFUNCTIONCONTEXT (&expr_frozen_uc, &__collector_hwcs_frozen); + + /* initialize dummy context for non-program-related frames */ + getcontext (&expr_nopc_uc); + SETFUNCTIONCONTEXT (&expr_nopc_uc, &__collector_not_program_related); + + /* initialize dummy context for lost-counts-related frames */ + getcontext (&expr_lostcounts_uc); + SETFUNCTIONCONTEXT (&expr_lostcounts_uc, &__collector_hwc_samples_lost); +} +/* initialize the signal handler */ +static int +hwc_initialize_handlers (void) +{ + /* install the signal handler for SIGEMT */ + struct sigaction oact; + if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact) != 0) + { + TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to get oact\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT); + return COL_ERROR_HWCINIT; + } + if (oact.sa_sigaction == collector_sigemt_handler) + { + /* signal handler is already in place; we are probably in a fork-child */ + TprintfT (DBG_LT1, "hwc_initialize_handlers(): hwc_initialize_handlers() collector_sigemt_handler already installed\n"); + } + else + { + /* set our signal handler */ + struct sigaction c_act; + CALL_UTIL (memset)(&c_act, 0, sizeof c_act); + sigemptyset (&c_act.sa_mask); + sigaddset (&c_act.sa_mask, SIGPROF); /* block SIGPROF delivery in handler */ + /* XXXX should probably also block sample_sig & pause_sig */ + c_act.sa_sigaction = collector_sigemt_handler; /* note: used to set sa_handler instead */ + c_act.sa_flags = SA_RESTART | SA_SIGINFO; + if (__collector_sigaction (HWCFUNCS_SIGNAL, &c_act, &old_sigemt_handler) != 0) + { + TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to set cact\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">event handler could not be installed</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT); + return COL_ERROR_HWCINIT; + } + } + return COL_ERROR_NONE; +} + +static int +close_experiment (void) +{ + /* note: stop_data_collection() should have already been called by + * collector_close_experiment() + */ + if (!COUNTERS_ENABLED ()) + return COL_ERROR_NONE; + detach_experiment (); + + /* cpc or libperfctr may still generate sigemts for a while */ + /* verify that SIGEMT handler is still installed */ + /* (still required with sigaction interposition and management, + since interposition is not done for attach experiments) + */ + struct sigaction curr; + if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &curr) == -1) + { + TprintfT (0, "hwprofile close_experiment: ERROR: hwc sigaction check failed: errno=%d\n", errno); + } + else if (curr.sa_sigaction != collector_sigemt_handler) + { + TprintfT (DBG_LT1, "hwprofile close_experiment: WARNING: collector sigemt handler replaced by 0x%p!\n", curr.sa_handler); + (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">0x%p</event>\n", + SP_JCMD_CWARN, COL_WARN_SIGEMT, curr.sa_handler); + } + else + TprintfT (DBG_LT1, "hwprofile close_experiment: collector sigemt handler integrity verified!\n"); + TprintfT (0, "hwprofile: close_experiment\n"); + return 0; +} + +static int +detach_experiment (void) +{ + /* fork child. Clean up state but don't write to experiment */ + /* note: stop_data_collection() has already been called by the fork_prologue */ + // detach_experiment() can be called asynchronously + // from anywhere, even from within a sigemt handler + // via DBX detach. + // Important: stop_data_collection() _must_ be called + // before detach_experiment() is called. + if (!COUNTERS_ENABLED ()) + return COL_ERROR_NONE; + TprintfT (0, "hwprofile: detach_experiment()\n"); + if (SD_OFF != __collector_cas_32 (&sd_state, SD_OFF, SD_PENDING)) + return 0; + // one and only one call should ever make it here here. + if (hwc_mode == HWCMODE_ACTIVE) + { + TprintfT (0, "hwprofile: ERROR: stop_data_collection() should have been called before detach_experiment()\n"); + stop_data_collection (); + } + + // Assumption: The only calls to sigemt_handler + // we should see at this point + // will be those that were already in-flight before + // stop_new_sigemts() was called. + if (nthreads_in_sighandler > 0) + { + // sigemt handlers should see + // SD_PENDING and should call real_detach_experiment() + // when the last handler is finished. + TprintfT (DBG_LT1, "hwprofile: detach in the middle of signal handler.\n"); + return 0; + } + + // If we get here, there should be no remaining + // sigemt handlers. However, we don't really know + // if there were ever any in flight, so call + // real_detach_experiment() here: + return real_detach_experiment (); // multiple calls to this OK +} + +static int +real_detach_experiment (void) +{ + /*multiple calls to this routine are OK.*/ + if (SD_PENDING != __collector_cas_32 (&sd_state, SD_PENDING, SD_COMPLETE)) + return 0; + // only the first caller to this routine should get here. + hwcdef_cnt = 0; /* since now deinstalled */ + hwcdef = NULL; + set_hwc_mode (HWCMODE_OFF); + if (SD_COMPLETE != __collector_cas_32 (&sd_state, SD_COMPLETE, SD_OFF)) + { + TprintfT (0, "hwprofile: ERROR: unexpected sd_state in real_detach_experiment()\n"); + sd_state = SD_OFF; + } + hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (DBG_LT0, "hwprofile: real_detach_experiment() detached from experiment.\n"); + return 0; +} + +/*---------------------------------------------------------------------------*/ +/* Record counter values. */ + +/* <value> should already be adjusted to be "zero-based" (counting up from 0).*/ +static void +collector_record_counter_internal (ucontext_t *ucp, int timecvt, + ABST_type ABS_memop, hrtime_t time, + unsigned tag, uint64_t value, uint64_t pc, + uint64_t va, uint64_t latency, + uint64_t data_source) +{ + MHwcntr_packet pckt; + CALL_UTIL (memset)(&pckt, 0, sizeof ( MHwcntr_packet)); + pckt.comm.tstamp = time; + pckt.tag = tag; + if (timecvt > 1) + { + if (HWCVAL_HAS_ERR (value)) + { + value = HWCVAL_CLR_ERR (value); + value *= timecvt; + value = HWCVAL_SET_ERR (value); + } + else + value *= timecvt; + } + pckt.interval = value; + pckt.comm.type = HW_PCKT; + pckt.comm.tsize = sizeof (Hwcntr_packet); + TprintfT (DBG_LT4, "hwprofile: %llu sample %lld tag %u recorded\n", + (unsigned long long) time, (long long) value, tag); + if (ABS_memop == ABST_NOPC) + ucp = &expr_nopc_uc; + pckt.comm.frinfo = collector_interface->getFrameInfo (expr_hndl, pckt.comm.tstamp, FRINFO_FROM_UC, ucp); + collector_interface->writeDataRecord (expr_hndl, (Common_packet*) & pckt); +} + +static void +collector_record_counter (ucontext_t *ucp, int timecvt, ABST_type ABS_memop, + hrtime_t time, unsigned tag, uint64_t value) +{ + collector_record_counter_internal (ucp, timecvt, ABS_memop, time, tag, value, + HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64, + HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64); +} + + +/*---------------------------------------------------------------------------*/ +/* Signal handlers */ + +/* SIGEMT -- relayed from libcpc, when the counter overflows */ + +/* Generates the appropriate event or events, and resets the counters */ +static void +collector_sigemt_handler (int sig, siginfo_t *si, void *puc) +{ + int rc; + hwc_event_t sample, lost_samples; + if (sig != HWCFUNCS_SIGNAL) + { + TprintfT (0, "hwprofile: ERROR: %s: unexpected signal %d\n", "collector_sigemt_handler", sig); + return; + } + if (!COUNTERS_ENABLED ()) + { /* apparently deinstalled */ + TprintfT (0, "hwprofile: WARNING: SIGEMT detected after close_experiment()\n"); + /* kills future sigemts since hwcdrv_sighlr_restart() not called */ + return; + } + + /* Typically, we expect HWC overflow signals to come from the kernel: si_code > 0. + * On Linux, however, dbx might be "forwarding" a signal using tkill()/tgkill(). + * For more information on what si_code values can be expected on Linux, check: + * cmn_components/Collector_Interface/hwcdrv_pcl.c hwcdrv_overflow() + * cmn_components/Collector_Interface/hwcdrv_perfctr.c hdrv_perfctr_overflow() + */ + if (puc == NULL || si == NULL || (si->si_code <= 0 && si->si_code != SI_TKILL)) + { + TprintfT (DBG_LT3, "hwprofile: collector_sigemt_handler SIG%02d\n", sig); + if (old_sigemt_handler.sa_handler == SIG_DFL) + __collector_SIGDFL_handler (HWCFUNCS_SIGNAL); + else if (old_sigemt_handler.sa_handler != SIG_IGN && + old_sigemt_handler.sa_sigaction != &collector_sigemt_handler) + { + /* Redirect the signal to the previous signal handler */ + (old_sigemt_handler.sa_sigaction)(sig, si, puc); + TprintfT (DBG_LT1, "hwprofile: collector_sigemt_handler SIG%02d redirected to original handler\n", sig); + } + return; + } + rc = get_hwc_driver ()->hwcdrv_overflow (si, &sample, &lost_samples); + if (rc) + { + /* hwcdrv_sighlr_restart() should not be called */ + TprintfT (0, "hwprofile: ERROR: collector_sigemt_handler: hwcdrv_overflow() failed\n"); + return; + } + + if (hwc_mode == HWCMODE_ACTIVE) + { + /* record the event only if counters are active */ + /* The following has been copied from dispatcher.c */ +#if ARCH(SPARC) + /* 23340823 signal handler third argument should point to a ucontext_t */ + /* Convert sigcontext to ucontext_t on sparc-Linux */ + ucontext_t uctxmem; + struct sigcontext *sctx = (struct sigcontext*) puc; + ucontext_t *uctx = &uctxmem; + uctx->uc_link = NULL; +#if WSIZE(32) + uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc; + __collector_memcpy (&uctx->uc_mcontext.gregs[3], + sctx->si_regs.u_regs, + sizeof (sctx->si_regs.u_regs)); +#else + uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc; + __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3], + sctx->sigc_regs.u_regs, + sizeof (sctx->sigc_regs.u_regs)); +#endif /* WSIZE() */ +#else + ucontext_t *uctx = (ucontext_t*) puc; +#endif /* ARCH() */ + + for (int ii = 0; ii < hwcdef_cnt; ii++) + if (lost_samples.ce_pic[ii]) + collector_record_counter (&expr_lostcounts_uc, hwcdef[ii]->timecvt, + hwcdef[ii]->memop, lost_samples.ce_hrt, + hwcdef[ii]->sort_order, lost_samples.ce_pic[ii]); + for (int ii = 0; ii < hwcdef_cnt; ii++) + if (sample.ce_pic[ii]) + collector_record_counter (uctx, hwcdef[ii]->timecvt, + hwcdef[ii]->memop, sample.ce_hrt, + hwcdef[ii]->sort_order, sample.ce_pic[ii]); + } + rc = get_hwc_driver ()->hwcdrv_sighlr_restart (NULL); +} +/* SIGPROF -- not installed as handler, but + * __collector_ext_hwc_check: called by (SIGPROF) dispatcher. + * Periodical check of integrity of HWC count/signal mechanism, + * as required for various chip/system bugs/workarounds. + */ +void +__collector_ext_hwc_check (siginfo_t *info, ucontext_t *vcontext) { } + +/*---------------------------------------------------------------------------*/ +int +collector_sigemt_sigaction (const struct sigaction *nact, + struct sigaction *oact) +{ + struct sigaction oact_check; + /* Error codes and messages that refer to HWC are tricky. + * E.g., HWC profiling might not even be on; we might + * encounter an error here simply because the user is + * trying to set a handler for a signal that happens to + * be HWCFUNCS_SIGNAL, which we aren't even using. + */ + if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact_check) != 0) + { + TprintfT (0, "hwprofile: ERROR: collector_sigemt_sigaction(): request to set handler for signal %d, but check on existing handler failed\n", HWCFUNCS_SIGNAL); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler for signal %d could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT, HWCFUNCS_SIGNAL); + return COL_ERROR_HWCINIT; + } + + if (oact_check.sa_sigaction == collector_sigemt_handler) + { + /* dispatcher is in place, so nact/oact apply to old_sigemt_handler */ + if (oact != NULL) + { + oact->sa_handler = old_sigemt_handler.sa_handler; + oact->sa_mask = old_sigemt_handler.sa_mask; + oact->sa_flags = old_sigemt_handler.sa_flags; + } + if (nact != NULL) + { + old_sigemt_handler.sa_handler = nact->sa_handler; + old_sigemt_handler.sa_mask = nact->sa_mask; + old_sigemt_handler.sa_flags = nact->sa_flags; + } + return COL_ERROR_NONE; + } + else /* no dispatcher in place, so just act like normal sigaction() */ + return __collector_sigaction (HWCFUNCS_SIGNAL, nact, oact); +} + +static void +collector_hwc_ABORT (int errnum, const char *msg) +{ + TprintfT (0, "hwprofile: collector_hwc_ABORT: [%d] %s\n", errnum, msg); + if (hwc_mode == HWCMODE_ABORT) /* HWC collection already aborted! */ + return; + set_hwc_mode (HWCMODE_ABORT); /* set global flag to disable handlers and indicate abort */ + + /* Write the error message to the experiment */ + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCFAIL, msg, errnum); + +#ifdef REAL_DEBUG + abort (); +#else + TprintfT (0, "hwprofile: Continuing without HWC collection...\n"); +#endif +} + +static int +start_data_collection (void) +{ + hwc_mode_t old_mode = hwc_mode; + if (!COUNTERS_ENABLED ()) + return COL_ERROR_NONE; + TprintfT (0, "hwprofile: start_data_collection (hwc_mode=%d)\n", old_mode); + switch (old_mode) + { + case HWCMODE_OFF: + if (get_hwc_driver ()->hwcdrv_start ()) + { + TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_start()\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n", + SP_JCMD_CERROR, COL_ERROR_HWCFAIL, + "start_data_collection()", errno); + return COL_ERROR_HWCINIT; + } + set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */ + break; + case HWCMODE_SUSPEND: + if (get_hwc_driver ()->hwcdrv_lwp_resume ()) + { + TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_lwp_resume()\n"); + /* ignore errors from lwp_resume() */ + } + set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */ + break; + default: + TprintfT (0, "hwprofile: ERROR: start_data_collection() invalid mode\n"); + return COL_ERROR_HWCINIT; + } + return COL_ERROR_NONE; +} + +static int +stop_data_collection (void) +{ + hwc_mode_t old_mode = hwc_mode; + if (!COUNTERS_ENABLED ()) + return COL_ERROR_NONE; + TprintfT (0, "hwprofile: stop_data_collection (hwc_mode=%d)\n", old_mode); + switch (old_mode) + { + case HWCMODE_SUSPEND: + return COL_ERROR_NONE; + case HWCMODE_ACTIVE: + set_hwc_mode (HWCMODE_SUSPEND); /* stop handling signals */ + break; + default: + /* Don't change the mode, but attempt to suspend anyway... */ + break; + } + + if (get_hwc_driver ()->hwcdrv_lwp_suspend ()) + /* ignore errors from lwp_suspend() */ + TprintfT (0, "hwprofile: ERROR: stop_data_collection() failed in hwcdrv_lwp_suspend()\n"); + + /* + * hwcdrv_lwp_suspend() cannot guarantee that all SIGEMTs will stop + * but hwc_mode will prevent logging and counters will overflow once + * then stay frozen. + */ + /* There may still be pending SIGEMTs so don't reset the SIG_DFL handler. + */ + /* see comment in dispatcher.c */ + /* ret = __collector_sigaction( SIGEMT, &old_sigemt_handler, NULL ); */ + return COL_ERROR_NONE; +} + +/*---------------------------------------------------------------------------*/ + +/* utilities */ +static void +set_hwc_mode (hwc_mode_t md) +{ + TprintfT (DBG_LT1, "hwprofile: set_hwc_mode(%d)\n", md); + hwc_mode = md; +} + +int +__collector_ext_hwc_active () +{ + return (hwc_mode == HWCMODE_ACTIVE); +} + +static void +hwclogwrite0 () +{ + collector_interface->writeLog ("<profdata fname=\"%s\"/>\n", + module_interface.description); + /* Record Hwcntr_packet description */ + Hwcntr_packet *pp = NULL; + collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", HW_PCKT); + collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n", + &pp->tag, sizeof (pp->tag) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n", + &pp->interval, sizeof (pp->interval) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog ("</profpckt>\n"); + if (hwcdef_has_memspace) + { + /* Record MHwcntr_packet description */ + MHwcntr_packet *xpp = NULL; + collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", MHWC_PCKT); + collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->comm.lwp_id, sizeof (xpp->comm.lwp_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->comm.thr_id, sizeof (xpp->comm.thr_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->comm.cpu_id, sizeof (xpp->comm.cpu_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->comm.tstamp, sizeof (xpp->comm.tstamp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->comm.frinfo, sizeof (xpp->comm.frinfo) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->tag, sizeof (xpp->tag) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->interval, sizeof (xpp->interval) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"VADDR\" uname=\"" STXT ("Virtual address (data)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->ea_vaddr, sizeof (xpp->ea_vaddr) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" <field name=\"PADDR\" uname=\"" STXT ("Physical address (data)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->ea_paddr, sizeof (xpp->ea_paddr) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" <field name=\"VIRTPC\" uname=\"" STXT ("Virtual address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->pc_vaddr, sizeof (xpp->pc_vaddr) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" <field name=\"PHYSPC\" uname=\"" STXT ("Physical address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->pc_paddr, sizeof (xpp->pc_paddr) == 4 ? "UINT32" : "UINT64"); + collector_interface->writeLog (" <field name=\"EA_PAGESIZE\" uname=\"" STXT ("Page size (data)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->ea_pagesz, sizeof (xpp->ea_pagesz) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"PC_PAGESIZE\" uname=\"" STXT ("Page size (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->pc_pagesz, sizeof (xpp->pc_pagesz) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"EA_LGRP\" uname=\"" STXT ("Page locality group (data)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->ea_lgrp, sizeof (xpp->ea_lgrp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"PC_LGRP\" uname=\"" STXT ("Page locality group (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->pc_lgrp, sizeof (xpp->pc_lgrp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"LWP_LGRP_HOME\" uname=\"" STXT ("LWP home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->lgrp_lwp, sizeof (xpp->lgrp_lwp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"PS_LGRP_HOME\" uname=\"" STXT ("Process home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->lgrp_ps, sizeof (xpp->lgrp_ps) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"MEM_LAT\" uname=\"" STXT ("Memory Latency Cycles") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->latency, sizeof (xpp->latency) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"MEM_SRC\" uname=\"" STXT ("Memory Data Source") "\" offset=\"%d\" type=\"%s\"/>\n", + &xpp->data_source, sizeof (xpp->data_source) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog ("</profpckt>\n"); + } +} + +static void +hwclogwrite (Hwcentry * ctr) +{ + TprintfT (DBG_LT1, "hwprofile: writeLog(%s %u %s %d %u %d)\n", + SP_JCMD_HW_COUNTER, cpcN_cpuver, ctr->name ? ctr->name : "NULL", + ctr->val, ctr->sort_order, ctr->memop); + collector_interface->writeLog ("<profile name=\"%s\"", SP_JCMD_HW_COUNTER); + collector_interface->writeLog (" cpuver=\"%u\"", cpcN_cpuver); + collector_interface->writeLog (" hwcname=\"%s\"", ctr->name); + collector_interface->writeLog (" int_name=\"%s\"", ctr->int_name); + collector_interface->writeLog (" interval=\"%d\"", ctr->val); + collector_interface->writeLog (" tag=\"%u\"", ctr->sort_order); + collector_interface->writeLog (" memop=\"%d\"", ctr->memop); + collector_interface->writeLog ("/>\n"); +} diff --git a/gprofng/libcollector/hwprofile.h b/gprofng/libcollector/hwprofile.h new file mode 100644 index 0000000..4d01bf1 --- /dev/null +++ b/gprofng/libcollector/hwprofile.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef _HWPROFILE_H +#define _HWPROFILE_H + +#include <data_pckts.h> + +typedef struct Hwcntr_packet +{ /* HW counter profiling packet */ + Common_packet comm; + uint32_t tag; /* hw counter index, register */ + uint64_t interval; /* overflow value */ +} Hwcntr_packet; + +typedef struct MHwcntr_packet +{ /* extended (superset) Hwcntr_packet */ + Common_packet comm; + uint32_t tag; /* hw counter index, register */ + uint64_t interval; /* overflow value */ + Vaddr_type ea_vaddr; /* virtual addr causing HWC event */ + Vaddr_type pc_vaddr; /* candidate eventPC */ + uint64_t ea_paddr; /* physical address for ea_vaddr */ + uint64_t pc_paddr; /* physical address for pc_vaddr */ + uint64_t ea_pagesz; /* pagesz (bytes) for ea_paddr */ + uint64_t pc_pagesz; /* pagesz (bytes) for pc_paddr */ + uint32_t ea_lgrp; /* latency group of ea_paddr */ + uint32_t pc_lgrp; /* latency group of pc_paddr */ + uint32_t lgrp_lwp; /* locality group of lwp */ + uint32_t lgrp_ps; /* locality group of process */ + uint64_t latency; /* latency in cycles (sampling only) */ + uint64_t data_source; /* data source (sampling only) */ +} MHwcntr_packet; + +#if ARCH(SPARC) +#define CONTEXT_PC MC_PC +#define CONTEXT_SP MC_O6 +#define CONTEXT_FP MC_O7 +#define SETFUNCTIONCONTEXT(ucp,funcp) \ + (ucp)->uc_mcontext.gregs[CONTEXT_PC] = (greg_t)(funcp); \ + (ucp)->uc_mcontext.gregs[CONTEXT_SP] = 0; \ + (ucp)->uc_mcontext.gregs[CONTEXT_FP] = 0; + +#elif ARCH(Intel) +#include <sys/reg.h> + +#if WSIZE(64) +#define CONTEXT_PC REG_RIP +#define CONTEXT_FP REG_RBP +#define CONTEXT_SP REG_RSP + +#elif WSIZE(32) +#define CONTEXT_PC REG_EIP +#define CONTEXT_FP REG_EBP +#define CONTEXT_SP REG_ESP +#endif /* WSIZE() */ +#define SETFUNCTIONCONTEXT(ucp,funcp) \ + (ucp)->uc_mcontext.gregs[CONTEXT_PC] = (greg_t)(funcp); \ + (ucp)->uc_mcontext.gregs[CONTEXT_SP] = 0; \ + (ucp)->uc_mcontext.gregs[CONTEXT_FP] = 0; + +#elif ARCH(Aarch64) +#define CONTEXT_PC 15 +#define CONTEXT_FP 14 +#define CONTEXT_SP 13 +#define SETFUNCTIONCONTEXT(ucp,funcp) \ + (ucp)->uc_mcontext.regs[CONTEXT_PC] = (greg_t)(funcp); \ + (ucp)->uc_mcontext.regs[CONTEXT_SP] = 0; \ + (ucp)->uc_mcontext.regs[CONTEXT_FP] = 0; +#endif /* ARCH() */ + +#endif diff --git a/gprofng/libcollector/iolib.c b/gprofng/libcollector/iolib.c new file mode 100644 index 0000000..6881f02 --- /dev/null +++ b/gprofng/libcollector/iolib.c @@ -0,0 +1,1156 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <dlfcn.h> +#include <pthread.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include "gp-defs.h" +#include "collector.h" +#include "gp-experiment.h" +#include "memmgr.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* ------------- Data and prototypes for block management --------- */ +#define IO_BLK 0 /* Concurrent requests */ +#define IO_SEQ 1 /* All requests are sequential, f.e. JAVA_CLASSES */ +#define IO_TXT 2 /* Sequential requests. Text strings. */ +#define ST_INIT 0 /* Initial state. Not allocated */ +#define ST_FREE 1 /* Available */ +#define ST_BUSY 2 /* Not available */ + +/* IO_BLK, IO_SEQ */ +#define NCHUNKS 64 + +/* IO_TXT */ +#define NBUFS 64 /* Number of text buffers */ +#define CUR_BUSY(x) ((uint32_t) ((x)>>63)) /* bit 63 */ +#define CUR_INDX(x) ((uint32_t) (((x)>>57) & 0x3fULL)) /* bits 62:57 */ +#define CUR_FOFF(x) ((x) & 0x01ffffffffffffffULL) /* bits 56: 0 */ +#define CUR_MAKE(busy, indx, foff) ((((uint64_t)(busy))<<63) | (((uint64_t)(indx))<<57) | ((uint64_t)(foff)) ) + +typedef struct Buffer +{ + uint8_t *vaddr; + uint32_t left; /* bytes left */ + uint32_t state; /* ST_FREE or ST_BUSY */ +} Buffer; + +typedef struct DataHandle +{ + Pckt_type kind; /* obsolete (to be removed) */ + int iotype; /* IO_BLK, IO_SEQ, IO_TXT */ + int active; + char fname[MAXPATHLEN]; /* data file name */ + + /* IO_BLK, IO_SEQ */ + uint32_t nflow; /* number of data flows */ + uint32_t *blkstate; /* block states, nflow*NCHUNKS array */ + uint32_t *blkoff; /* block offset, nflow*NCHUNKS array */ + uint32_t nchnk; /* number of active chunks, probably small for IO_BLK */ + uint8_t *chunks[NCHUNKS]; /* chunks (nflow contiguous blocks in virtual memory) */ + uint32_t chblk[NCHUNKS]; /* number of active blocks in a chunk */ + uint32_t nblk; /* number of blocks in data file */ + int exempt; /* if exempt from experiment size limit */ + + /* IO_TXT */ + Buffer *buffers; /* array of text buffers */ + uint64_t curpos; /* current buffer and file offset */ +} DataHandle; + +#define PROFILE_DATAHNDL_MAX 16 +static DataHandle data_hndls[PROFILE_DATAHNDL_MAX]; +static int initialized = 0; +static long blksz; /* Block size. Multiple of page size. Power of two to make (x%blksz)==(x&(blksz-1)) fast. */ +static long log2blksz; /* log2(blksz) to make (x/blksz)==(x>>log2blksz) fast. */ +static uint32_t size_limit; /* Experiment size limit */ +static uint32_t cur_size; /* Current experiment size */ +static void init (); +static void deleteHandle (DataHandle *hndl); +static int exp_size_ck (int nblocks, char *fname); + +/* IO_BLK, IO_SEQ */ +static int allocateChunk (DataHandle *hndl, unsigned ichunk); +static uint8_t *getBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk); +static int remapBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk); +static int newBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk); +static void deleteBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk); + +/* IO_TXT */ +static int is_not_the_log_file (char *fname); +static int mapBuffer (char *fname, Buffer *buf, off64_t foff); +static int newBuffer (DataHandle *hndl, uint64_t pos); +static void writeBuffer (Buffer *buf, int blk_off, char *src, int len); +static void deleteBuffer (Buffer *buf); + +/* + * Common buffer management routines + */ +static void +init () +{ + /* set the block size */ + long pgsz = CALL_UTIL (sysconf)(_SC_PAGESIZE); + blksz = pgsz; + log2blksz = 16; /* ensure a minimum size */ + while ((1 << log2blksz) < blksz) + log2blksz += 1; + blksz = 1L << log2blksz; /* ensure that blksz is a power of two */ + TprintfT (DBG_LT1, "iolib init: page size=%ld (0x%lx) blksz=%ld (0x%lx) log2blksz=%ld\n", + pgsz, pgsz, (long) blksz, (long) blksz, (long) log2blksz); + size_limit = 0; + cur_size = 0; + initialized = 1; +} + +DataHandle * +__collector_create_handle (char *descp) +{ + int exempt = 0; + char *desc = descp; + if (desc[0] == '*') + { + desc++; + exempt = 1; + } + if (!initialized) + init (); + + /* set up header for file, file name, etc. */ + if (__collector_exp_dir_name == NULL) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">__collector_exp_dir_name==NULL</event>\n", + SP_JCMD_CERROR, COL_ERROR_EXPOPEN); + return NULL; + } + char fname[MAXPATHLEN]; + CALL_UTIL (strlcpy)(fname, __collector_exp_dir_name, sizeof (fname)); + CALL_UTIL (strlcat)(fname, "/", sizeof (fname)); + Pckt_type kind = 0; + int iotype = IO_BLK; + if (__collector_strcmp (desc, SP_HEAPTRACE_FILE) == 0) + kind = HEAP_PCKT; + else if (__collector_strcmp (desc, SP_SYNCTRACE_FILE) == 0) + kind = SYNC_PCKT; + else if (__collector_strcmp (desc, SP_IOTRACE_FILE) == 0) + kind = IOTRACE_PCKT; + else if (__collector_strcmp (desc, SP_RACETRACE_FILE) == 0) + kind = RACE_PCKT; + else if (__collector_strcmp (desc, SP_PROFILE_FILE) == 0) + kind = PROF_PCKT; + else if (__collector_strcmp (desc, SP_OMPTRACE_FILE) == 0) + kind = OMP_PCKT; + else if (__collector_strcmp (desc, SP_HWCNTR_FILE) == 0) + kind = HW_PCKT; + else if (__collector_strcmp (desc, SP_DEADLOCK_FILE) == 0) + kind = DEADLOCK_PCKT; + else if (__collector_strcmp (desc, SP_FRINFO_FILE) == 0) + CALL_UTIL (strlcat)(fname, "data.", sizeof (fname)); + else if (__collector_strcmp (desc, SP_LOG_FILE) == 0) + iotype = IO_TXT; + else if (__collector_strcmp (desc, SP_MAP_FILE) == 0) + iotype = IO_TXT; + else if (__collector_strcmp (desc, SP_JCLASSES_FILE) == 0) + iotype = IO_SEQ; + else + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">iolib unknown file desc %s</event>\n", + SP_JCMD_CERROR, COL_ERROR_EXPOPEN, desc); + return NULL; + } + + CALL_UTIL (strlcat)(fname, desc, sizeof (fname)); + TprintfT (DBG_LT1, "createHandle calling open on fname = `%s', desc = `%s' %s\n", + fname, desc, (exempt == 0 ? "non-exempt" : "exempt")); + + /* allocate a handle -- not mt-safe */ + DataHandle *hndl = NULL; + for (int i = 0; i < PROFILE_DATAHNDL_MAX; ++i) + if (data_hndls[i].active == 0) + { + hndl = &data_hndls[i]; + break; + } + + /* out of handles? */ + if (hndl == NULL) + { + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_NOHNDL, fname); + return NULL; + } + + hndl->kind = kind; + hndl->nblk = 0; + hndl->exempt = exempt; + CALL_UTIL (strlcpy)(hndl->fname, fname, sizeof (hndl->fname)); + int fd = CALL_UTIL (open)(hndl->fname, + O_RDWR | O_CREAT | O_TRUNC | O_EXCL, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) + { + TprintfT (0, "createHandle open failed -- hndl->fname = `%s', SP_LOG_FILE = `%s': %s\n", + hndl->fname, SP_LOG_FILE, CALL_UTIL (strerror)(errno)); + if (is_not_the_log_file (hndl->fname) == 0) + { + char errbuf[4096]; + /* If we are trying to create the handle for the log file, write to stderr, not the experiment */ + CALL_UTIL (snprintf)(errbuf, sizeof (errbuf), + "create_handle: COL_ERROR_LOG_OPEN %s: %s\n", hndl->fname, CALL_UTIL (strerror)(errno)); + CALL_UTIL (write)(2, errbuf, CALL_UTIL (strlen)(errbuf)); + + } + else + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: create_handle</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, hndl->fname); + return NULL; + } + CALL_UTIL (close)(fd); + + hndl->iotype = iotype; + if (hndl->iotype == IO_TXT) + { + /* allocate our buffers in virtual memory */ + /* later, we will remap buffers individually to the file */ + uint8_t *memory = (uint8_t*) CALL_UTIL (mmap64)(0, + (size_t) (NBUFS * blksz), + PROT_READ | PROT_WRITE, +#if ARCH(SPARC) + MAP_SHARED | MAP_ANON, +#else + MAP_PRIVATE | MAP_ANON, +#endif + -1, + (off64_t) 0); + if (memory == MAP_FAILED) + { + TprintfT (0, "create_handle: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror)(errno)); + /* see if this is the log file */ + if (is_not_the_log_file (hndl->fname) == 0) + { + /* If we are trying to map the log file, write to stderr, not to the experiment */ + char errbuf[4096]; + CALL_UTIL (snprintf)(errbuf, sizeof (errbuf), + "create_handle: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror)(errno)); + CALL_UTIL (write)(2, errbuf, CALL_UTIL (strlen)(errbuf)); + } + else /* write the error message into the experiment */ + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">MAP_ANON (for %s); create_handle</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname); + return NULL; + } + TprintfT (DBG_LT2, " create_handle IO_TXT data buffer length=%ld (0x%lx) file='%s' memory=%p -- %p\n", + (long) (NBUFS * blksz), (long) (NBUFS * blksz), hndl->fname, + memory, memory + (NBUFS * blksz) - 1); + + /* set up an array of buffers, pointing them to the virtual addresses */ + TprintfT (DBG_LT2, "create_handle IO_TXT Buffer structures fname = `%s', NBUFS= %d, size = %ld (0x%lx)\n", fname, + NBUFS, (long) NBUFS * sizeof (Buffer), (long) NBUFS * sizeof (Buffer)); + hndl->buffers = (Buffer*) __collector_allocCSize (__collector_heap, NBUFS * sizeof (Buffer), 1); + if (hndl->buffers == NULL) + { + TprintfT (0, "create_handle allocCSize for hndl->buffers failed\n"); + CALL_UTIL (munmap)(memory, NBUFS * blksz); + return NULL; + } + for (int i = 0; i < NBUFS; i++) + { + Buffer *buf = &hndl->buffers[i]; + buf->vaddr = memory + i * blksz; + buf->state = ST_FREE; + } + /* set the file pointer to the beginning of the file */ + hndl->curpos = CUR_MAKE (0, 0, 0); + } + else + { + if (hndl->iotype == IO_BLK) + { + long nflow = CALL_UTIL (sysconf)(_SC_NPROCESSORS_ONLN); + if (nflow < 16) + nflow = 16; + hndl->nflow = (uint32_t) nflow; + } + else if (hndl->iotype == IO_SEQ) + hndl->nflow = 1; + TprintfT (DBG_LT2, "create_handle calling allocCSize blkstate fname=`%s' nflow=%d NCHUNKS=%d size=%ld (0x%lx)\n", + fname, hndl->nflow, NCHUNKS, + (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)), + (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t))); + uint32_t *blkstate = (uint32_t*) __collector_allocCSize (__collector_heap, hndl->nflow * NCHUNKS * sizeof (uint32_t), 1); + if (blkstate == NULL) + return NULL; + for (int j = 0; j < hndl->nflow * NCHUNKS; ++j) + blkstate[j] = ST_INIT; + hndl->blkstate = blkstate; + TprintfT (DBG_LT2, "create_handle calling allocCSize blkoff fname=`%s' nflow=%d NCHUNKS=%d size=%ld (0x%lx)\n", + fname, hndl->nflow, NCHUNKS, + (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)), + (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t))); + hndl->blkoff = (uint32_t*) __collector_allocCSize (__collector_heap, hndl->nflow * NCHUNKS * sizeof (uint32_t), 1); + if (hndl->blkoff == NULL) + return NULL; + hndl->nchnk = 0; + for (int j = 0; j < NCHUNKS; ++j) + { + hndl->chunks[j] = NULL; + hndl->chblk[j] = 0; + } + } + hndl->active = 1; + return hndl; +} + +static void +deleteHandle (DataHandle *hndl) +{ + if (hndl->active == 0) + return; + hndl->active = 0; + + if (hndl->iotype == IO_BLK || hndl->iotype == IO_SEQ) + { + /* Delete all blocks. */ + /* Since access to hndl->active is not synchronized it's still + * possible that we leave some blocks undeleted. + */ + for (int j = 0; j < hndl->nflow * NCHUNKS; ++j) + { + uint32_t oldstate = hndl->blkstate[j]; + if (oldstate != ST_FREE) + continue; + /* Mark as busy */ + uint32_t state = __collector_cas_32 (hndl->blkstate + j, oldstate, ST_BUSY); + if (state != oldstate) + continue; + deleteBlock (hndl, j / NCHUNKS, j % NCHUNKS); + } + } + else if (hndl->iotype == IO_TXT) + { + /* + * First, make sure that buffers are in some "coherent" state: + * + * At this point, the handle is no longer active. But some threads + * might already have passed the active-handle check and are now + * trying to schedule writes. So, set the handle pointer to "busy". + * This will prevent new writes from being scheduled. Threads that + * polling will time out. + */ + hrtime_t timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000); + volatile uint32_t busy = 0; + while (1) + { + uint32_t indx; + uint64_t opos, npos, foff; + int blk_off; + /* read the current pointer */ + opos = hndl->curpos; + busy = CUR_BUSY (opos); + indx = CUR_INDX (opos); + foff = CUR_FOFF (opos); + if (busy == 1) + { + if (__collector_gethrtime () > timeout) + { + TprintfT (0, "deleteHandle ERROR: timeout cleaning up handle for %s\n", hndl->fname); + return; + } + continue; + } + blk_off = foff & (blksz - 1); + if (blk_off > 0) + foff += blksz - blk_off; + npos = CUR_MAKE (1, indx, foff); + + /* try to update the handle position atomically */ + if (__collector_cas_64p (&hndl->curpos, &opos, &npos) != opos) + continue; + + /* + * If the last buffer won't be filled, account for + * the white space at the end so that the buffer will + * be deleted properly. + */ + if (blk_off > 0) + { + Buffer *buf = &hndl->buffers[indx]; + if (__collector_subget_32 (&buf->left, blksz - blk_off) == 0) + deleteBuffer (buf); + } + break; + } + /* wait for buffers to be deleted */ + timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000); + for (int i = 0; i < NBUFS; i++) + { + Buffer *buf = &hndl->buffers[i]; + while (__collector_cas_32 (&buf->state, ST_FREE, ST_INIT) != ST_FREE) + { + if (__collector_gethrtime () > timeout) + { + TprintfT (0, "deleteHandle ERROR: timeout waiting for buffer %d for %s\n", i, hndl->fname); + return; + } + } + CALL_UTIL (munmap)(buf->vaddr, blksz); + } + + /* free buffer array */ + __collector_freeCSize (__collector_heap, hndl->buffers, NBUFS * sizeof (Buffer)); + } +} + +void +__collector_delete_handle (DataHandle *hndl) +{ + if (hndl == NULL) + return; + deleteHandle (hndl); +} + +static int +exp_size_ck (int nblocks, char *fname) +{ + if (size_limit == 0) + return 0; + /* do an atomic add to the cur_size */ + uint32_t old_size = cur_size; + uint32_t new_size; + for (;;) + { + new_size = __collector_cas_32 (&cur_size, old_size, old_size + nblocks); + if (new_size == old_size) + { + new_size = old_size + nblocks; + break; + } + old_size = new_size; + } + TprintfT (DBG_LT2, "exp_size_ck() adding %d block(s); new_size = %d, limit = %d blocks; fname = %s\n", + nblocks, new_size, size_limit, fname); + + /* pause the entire collector if we have exceeded the limit */ + if (old_size < size_limit && new_size >= size_limit) + { + TprintfT (0, "exp_size_ck() experiment size limit exceeded; new_size = %ld, limit = %ld blocks; fname = %s\n", + (long) new_size, (long) size_limit, fname); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%ld blocks (each %ld bytes)</event>\n", + SP_JCMD_CWARN, COL_ERROR_SIZELIM, (long) size_limit, (long) blksz); + __collector_pause_m ("size-limit"); + __collector_terminate_expt (); + return -1; + } + return 0; +} + +int +__collector_set_size_limit (char *par) +{ + if (!initialized) + init (); + + int lim = CALL_UTIL (strtol)(par, &par, 0); + size_limit = (uint32_t) ((uint64_t) lim * 1024 * 1024 / blksz); + TprintfT (DBG_LT0, "collector_size_limit set to %d MB. = %d blocks\n", + lim, size_limit); + (void) __collector_log_write ("<setting limit=\"%d\"/>\n", lim); + return COL_ERROR_NONE; +} + +/* + * IO_BLK and IO_SEQ files + */ + +/* + * Allocate a chunk (nflow blocks) contiguously in virtual memory. + * Its blocks will be mmapped to the file individually. + */ +static int +allocateChunk (DataHandle *hndl, unsigned ichunk) +{ + /* + * hndl->chunks[ichunk] is one of: + * - NULL (initial value) + * - CHUNK_BUSY (transition state when allocating the chunk) + * - some address (the allocated chunk) + */ + uint8_t *CHUNK_BUSY = (uint8_t *) 1; + hrtime_t timeout = 0; + while (1) + { + if (hndl->chunks[ichunk] > CHUNK_BUSY) + return 0; /* the chunk has already been allocated */ + /* try to allocate the chunk (change: NULL => CHUNK_BUSY) */ + if (__collector_cas_ptr (&hndl->chunks[ichunk], NULL, CHUNK_BUSY) == NULL) + { + /* allocate virtual memory */ + uint8_t *newchunk = (uint8_t*) CALL_UTIL (mmap64)(0, + (size_t) (blksz * hndl->nflow), + PROT_READ | PROT_WRITE, +#if ARCH(SPARC) + MAP_SHARED | MAP_ANON, +#else + MAP_PRIVATE | MAP_ANON, +#endif + -1, (off64_t) 0); + if (newchunk == MAP_FAILED) + { + deleteHandle (hndl); + TprintfT (DBG_LT1, " allocateChunk mmap: start=0x%x length=%ld (0x%lx), offset=%d ret=%p\n", + 0, (long) (blksz * hndl->nflow), + (long) (blksz * hndl->nflow), 0, newchunk); + TprintfT (0, "allocateChunk: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror) (errno)); + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">MAP_ANON (for %s)</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname); + return 1; + } + + /* assign allocated address to our chunk */ + if (__collector_cas_ptr (&hndl->chunks[ichunk], CHUNK_BUSY, newchunk) != CHUNK_BUSY) + { + TprintfT (0, "allocateChunk: can't release chunk CAS lock for %s\n", hndl->fname); + __collector_log_write ("<event kind=\"%s\" id=\"%d\">couldn't release chunk CAS lock (%s)</event>\n", + SP_JCMD_CERROR, COL_ERROR_GENERAL, hndl->fname); + } + __collector_inc_32 (&hndl->nchnk); + return 0; + } + + /* check for time out */ + if (timeout == 0) + timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000); + if (__collector_gethrtime () > timeout) + { + TprintfT (0, "allocateChunk: timeout for %s\n", hndl->fname); + __collector_log_write ("<event kind=\"%s\" id=\"%d\">timeout allocating chunk for %s</event>\n", + SP_JCMD_CERROR, COL_ERROR_GENERAL, hndl->fname); + return 1; + } + } +} + +/* + * Get the address for block (iflow,ichunk). + */ +static uint8_t * +getBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk) +{ + return hndl->chunks[ichunk] + iflow * blksz; +} + +/* + * Map block (iflow,ichunk) to the next part of the file. + */ +static int +remapBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk) +{ + int rc = 0; + int fd; + /* Get the old file nblk and increment it atomically. */ + uint32_t oldblk = hndl->nblk; + for (;;) + { + uint32_t newblk = __collector_cas_32 (&hndl->nblk, oldblk, oldblk + 1); + if (newblk == oldblk) + break; + oldblk = newblk; + } + off64_t offset = (off64_t) oldblk * blksz; + + /* 6618470: disable thread cancellation */ + int old_cstate; + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cstate); + + /* Open the file. */ + int iter = 0; + hrtime_t tso = __collector_gethrtime (); + for (;;) + { + fd = CALL_UTIL (open)(hndl->fname, O_RDWR, 0); + if (fd < 0) + { + if (errno == EMFILE) + { + /* too many open files */ + iter++; + if (iter > 1000) + { + /* we've tried 1000 times; kick error back to caller */ + char errmsg[MAXPATHLEN + 50]; + hrtime_t teo = __collector_gethrtime (); + double deltato = (double) (teo - tso) / 1000000.; + (void) CALL_UTIL (snprintf) (errmsg, sizeof (errmsg), " t=%d, %s: open-retries-failed = %d, %3.6f ms.; remap", + __collector_thr_self (), hndl->fname, iter, deltato); + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_COMMENT, COL_COMMENT_NONE, errmsg); + rc = 1; + goto exit; + } + /* keep trying */ + continue; + } + deleteHandle (hndl); + TprintfT (0, "remapBlock: can't open file: %s: %s\n", hndl->fname, STR (CALL_UTIL (strerror)(errno))); + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">t=%llu, %s: remap </event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, + (unsigned long long) __collector_thr_self (), + hndl->fname); + rc = 1; + goto exit; + } + else + break; + } + + /* report number of retries of the open due to too many open fd's */ + if (iter > 0) + { + char errmsg[MAXPATHLEN + 50]; + hrtime_t teo = __collector_gethrtime (); + double deltato = (double) (teo - tso) / 1000000.; + (void) CALL_UTIL (snprintf) (errmsg, sizeof (errmsg), " t=%d, %s: open-retries = %d, %3.6f ms.; remap", + __collector_thr_self (), hndl->fname, iter, deltato); + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_COMMENT, COL_COMMENT_NONE, errmsg); + } + + /* Ensure disk space is allocated and the block offset is 0 */ + uint32_t zero = 0; + int n = CALL_UTIL (pwrite64)(fd, &zero, sizeof (zero), (off64_t) (offset + blksz - sizeof (zero))); + if (n <= 0) + { + deleteHandle (hndl); + TprintfT (0, "remapBlock: can't pwrite file: %s : errno=%d\n", hndl->fname, errno); + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: remap</event>\n", + SP_JCMD_CERROR, COL_ERROR_NOSPACE, errno, hndl->fname); + CALL_UTIL (close)(fd); + rc = 1; + goto exit; + } + hndl->blkoff[iflow * NCHUNKS + ichunk] = 0; + + /* Map block to file */ + uint8_t *bptr = getBlock (hndl, iflow, ichunk); + uint8_t *vaddr = (uint8_t *) CALL_UTIL (mmap64)( + (void*) bptr, + (size_t) blksz, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, + fd, + offset); + + if (vaddr != bptr) + { + deleteHandle (hndl); + TprintfT (DBG_LT1, " remapBlock mmap: start=%p length=%ld (0x%lx) offset=0x%llx ret=%p\n", + bptr, (long) blksz, (long) blksz, (long long) offset, vaddr); + TprintfT (0, "remapBlock: can't mmap file: %s : errno=%d\n", hndl->fname, errno); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: remap</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname); + CALL_UTIL (close)(fd); + rc = 1; + goto exit; + } + CALL_UTIL (close)(fd); + + if (hndl->exempt == 0) + exp_size_ck (1, hndl->fname); + else + Tprintf (DBG_LT1, "exp_size_ck() bypassed for %d block(s); exempt fname = %s\n", + 1, hndl->fname); +exit: + /* Restore the previous cancellation state */ + pthread_setcancelstate (old_cstate, NULL); + + return rc; +} + +static int +newBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk) +{ + if (allocateChunk (hndl, ichunk) != 0) + return 1; + if (remapBlock (hndl, iflow, ichunk) != 0) + return 1; + + /* Update the number of active blocks */ + __collector_inc_32 (hndl->chblk + ichunk); + return 0; +} + +static void +deleteBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk) +{ + uint8_t *bptr = getBlock (hndl, iflow, ichunk); + CALL_UTIL (munmap)((void*) bptr, blksz); + hndl->blkstate[iflow * NCHUNKS + ichunk] = ST_INIT; + + /* Update the number of active blocks */ + __collector_dec_32 (hndl->chblk + ichunk); +} + +int +__collector_write_record (DataHandle *hndl, Common_packet *pckt) +{ + if (hndl == NULL || !hndl->active) + return 1; + /* fill in the fields of the common packet structure */ + if (pckt->type == 0) + pckt->type = hndl->kind; + if (pckt->tstamp == 0) + pckt->tstamp = __collector_gethrtime (); + if (pckt->lwp_id == 0) + pckt->lwp_id = __collector_lwp_self (); + if (pckt->thr_id == 0) + pckt->thr_id = __collector_thr_self (); + if (pckt->cpu_id == 0) + pckt->cpu_id = CALL_UTIL (getcpuid)(); + if (pckt->tsize == 0) + pckt->tsize = sizeof (Common_packet); + TprintfT (DBG_LT3, "collector_write_record to %s, type:%d tsize:%d\n", + hndl->fname, pckt->type, pckt->tsize); + return __collector_write_packet (hndl, (CM_Packet*) pckt); +} + +int +__collector_write_packet (DataHandle *hndl, CM_Packet *pckt) +{ + if (hndl == NULL || !hndl->active) + return 1; + + /* if the experiment is not open, there should be no writes */ + if (__collector_expstate != EXP_OPEN) + { +#ifdef DEBUG + char *xstate; + switch (__collector_expstate) + { + case EXP_INIT: + xstate = "EXP_INIT"; + break; + case EXP_OPEN: + xstate = "EXP_OPEN"; + break; + case EXP_PAUSED: + xstate = "EXP_PAUSED"; + break; + case EXP_CLOSED: + xstate = "EXP_CLOSED"; + break; + default: + xstate = "Unknown"; + break; + } + TprintfT (0, "collector_write_packet: write to %s while experiment state is %s\n", + hndl->fname, xstate); +#endif + return 1; + } + int recsz = pckt->tsize; + if (recsz > blksz) + { + TprintfT (0, "collector_write_packet: packet too long: %d (max %ld)\n", recsz, blksz); + return 1; + } + unsigned tid = (__collector_no_threads ? __collector_lwp_self () : __collector_thr_self ()); + unsigned iflow = tid % hndl->nflow; + + /* Acquire block */ + uint32_t *sptr = &hndl->blkstate[iflow * NCHUNKS]; + uint32_t state = ST_BUSY; + unsigned ichunk; + for (ichunk = 0; ichunk < NCHUNKS; ++ichunk) + { + uint32_t oldstate = sptr[ichunk]; + if (oldstate == ST_BUSY) + continue; + /* Mark as busy */ + state = __collector_cas_32 (sptr + ichunk, oldstate, ST_BUSY); + if (state == oldstate) + break; + if (state == ST_BUSY) + continue; + /* It's possible the state changed from ST_INIT to ST_FREE */ + oldstate = state; + state = __collector_cas_32 (sptr + ichunk, oldstate, ST_BUSY); + if (state == oldstate) + break; + } + + if (state == ST_BUSY || ichunk == NCHUNKS) + { + /* We are out of blocks for this data flow. + * We might switch to another flow but for now report and return. + */ + TprintfT (0, "collector_write_packet: all %d blocks on flow %d for %s are busy\n", + NCHUNKS, iflow, hndl->fname); + return 1; + } + + if (state == ST_INIT && newBlock (hndl, iflow, ichunk) != 0) + return 1; + uint8_t *bptr = getBlock (hndl, iflow, ichunk); + uint32_t blkoff = hndl->blkoff[iflow * NCHUNKS + ichunk]; + if (blkoff + recsz > blksz) + { + /* The record doesn't fit. Close the block */ + if (blkoff < blksz) + { + Common_packet *closed = (Common_packet *) (bptr + blkoff); + closed->type = CLOSED_PCKT; + closed->tsize = blksz - blkoff; /* redundant */ + } + if (remapBlock (hndl, iflow, ichunk) != 0) + return 1; + blkoff = hndl->blkoff[iflow * NCHUNKS + ichunk]; + } + if (blkoff + recsz < blksz) + { + /* Set the empty padding */ + Common_packet *empty = (Common_packet *) (bptr + blkoff + recsz); + empty->type = EMPTY_PCKT; + empty->tsize = blksz - blkoff - recsz; + } + __collector_memcpy (bptr + blkoff, pckt, recsz); + + /* Release block */ + if (hndl->active == 0) + { + deleteBlock (hndl, iflow, ichunk); + return 0; + } + hndl->blkoff[iflow * NCHUNKS + ichunk] += recsz; + sptr[ichunk] = ST_FREE; + return 0; +} + +/* + * IO_TXT files + * + * IO_TXT covers the case where many threads are trying to write text messages + * sequentially (atomically) to a file. Examples include SP_LOG_FILE and SP_MAP_FILE. + * + * The file is not written directly, but by writing to mmapped virtual memory. + * The granularity of the mapping is a "Buffer". There may be as many as + * NBUFS buffers at any one time. + * + * The current position of the file is handled via hndl->curpos. + * + * * It is accessed atomically with 64-bit CAS instructions. + * + * * This 64-bit word encapsulates: + * - busy: a bit to lock access to hndl->curpos + * - indx: an index indicating which Buffer to use for the current position + * - foff: the file offset + * + * * The contents are accessed with: + * - unpack macros: CUR_BUSY CUR_INDX CUR_FOFF + * - pack macro : CUR_MAKE + * + * Conceptually, what happens when a thread wants to write a message is: + * - acquire the hndl->curpos "busy" lock + * . acquire and map new Buffers if needed to complete the message + * . update the file offset + * . release the lock + * - write to the corresponding buffers + * + * Each Buffer has a buf->left field that tracks how many more bytes + * need to be written to the Buffer. After a thread writes to a Buffer, + * it decrements buf->left atomically. When buf->left reaches 0, the + * Buffer (mapping) is deleted, freeing the Buffer for a new mapping. + * + * The actual implementation has some twists: + * + * * If the entire text message fits into the current Buffer -- that is, + * no new Buffers are needed -- the thread does not acquire the lock. + * It simply updates hndl->curpos atomically to the new file offset. + * + * * There are various timeouts to prevent hangs in case of abnormalities. + */ +static int +is_not_the_log_file (char *fname) +{ + if (CALL_UTIL (strstr)(fname, SP_LOG_FILE) == NULL) + return 1; + return 0; +} + +static int +mapBuffer (char *fname, Buffer *buf, off64_t foff) +{ + int rc = 0; + /* open fname */ + int fd = CALL_UTIL (open)(fname, O_RDWR, 0); + if (fd < 0) + { + TprintfT (0, "mapBuffer ERROR: can't open file: %s\n", fname); + if (is_not_the_log_file (fname)) + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, fname); + return 1; + } + TprintfT (DBG_LT2, "mapBuffer pwrite file %s at 0x%llx\n", fname, (long long) foff); + + /* ensure disk space is allocated */ + char nl = '\n'; + int n = CALL_UTIL (pwrite64)(fd, &nl, sizeof (nl), (off64_t) (foff + blksz - sizeof (nl))); + if (n <= 0) + { + TprintfT (0, "mapBuffer ERROR: can't pwrite file %s at 0x%llx\n", fname, + (long long) (foff + blksz - sizeof (nl))); + if (is_not_the_log_file (fname)) + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILETRNC, errno, fname); + rc = 1; + goto exit; + } + /* mmap buf->vaddr to fname at foff */ + uint8_t *vaddr = CALL_UTIL (mmap64)(buf->vaddr, (size_t) blksz, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, foff); + if (vaddr != buf->vaddr) + { + TprintfT (DBG_LT1, " mapBuffer mmap: start=%p length=%ld (0x%lx) offset=0x%llx ret=%p\n", + buf->vaddr, blksz, blksz, (long long) foff, vaddr); + TprintfT (0, "mapBuffer ERROR: can't mmap %s: vaddr=%p size=%ld (0x%lx) ret=%p off=0x%llx errno=%d\n", + fname, buf->vaddr, blksz, blksz, vaddr, (long long) foff, errno); + if (is_not_the_log_file (fname)) + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n", + SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, fname); + rc = 1; + } + else + buf->left = blksz; +exit: + CALL_UTIL (close)(fd); + + /* Should we check buffer size? Let's not since: + * - IO_TXT is typically not going to be that big + * - we want log.xml to be treated specially + */ + /* exp_size_ck( 1, fname ); */ + return rc; +} + +static int +newBuffer (DataHandle *hndl, uint64_t foff) +{ + /* find a ST_FREE buffer and mark it ST_BUSY */ + int ibuf; + for (ibuf = 0; ibuf < NBUFS; ibuf++) + if (__collector_cas_32 (&hndl->buffers[ibuf].state, ST_FREE, ST_BUSY) == ST_FREE) + break; + if (ibuf >= NBUFS) + { + TprintfT (0, "newBuffer ERROR: all buffers busy for %s\n", hndl->fname); + return -1; + } + Buffer *nbuf = hndl->buffers + ibuf; + + /* map buffer */ + if (mapBuffer (hndl->fname, nbuf, foff) != 0) + { + nbuf->state = ST_FREE; + ibuf = -1; + goto exit; + } +exit: + return ibuf; +} + +static void +writeBuffer (Buffer *buf, int blk_off, char *src, int len) +{ + __collector_memcpy (buf->vaddr + blk_off, src, len); + if (__collector_subget_32 (&buf->left, len) == 0) + deleteBuffer (buf); +} + +static void +deleteBuffer (Buffer *buf) +{ + buf->state = ST_FREE; +} + +int +__collector_write_string (DataHandle *hndl, char *src, int len) +{ + if (hndl == NULL || !hndl->active) + return 1; + if (len <= 0) + return 0; + + hrtime_t timeout = __collector_gethrtime () + 20 * ((hrtime_t) 1000000000); + volatile uint32_t busy = 0; + while (1) + { + uint32_t indx; + uint64_t opos, foff, base; + int blk_off, buf_indices[NBUFS], ibuf, nbufs; + + /* read and decode the current pointer */ + opos = hndl->curpos; + busy = CUR_BUSY (opos); + indx = CUR_INDX (opos); + foff = CUR_FOFF (opos); + if (busy == 1) + { + if (__collector_gethrtime () > timeout) + { + /* + * E.g., if another thread deleted the handle + * after we checked hndl->active. + */ + TprintfT (0, "__collector_write_string ERROR: timeout writing length=%d to text file: %s\n", len, hndl->fname); + return 1; + } + continue; + } + + /* initial block offset */ + blk_off = foff & (blksz - 1); + + /* number of new buffers to map */ + int lastbuf = ((foff + len - 1) >> log2blksz); /* last block file index we will write */ + int firstbuf = ((foff - 1) >> log2blksz); /* last block file index we have written */ + nbufs = lastbuf - firstbuf; + TprintfT (DBG_LT2, "__collector_write_string firstbuf = %d, lastbuf = %d, nbufs = %d, log2blksz = %ld\n", + firstbuf, lastbuf, nbufs, log2blksz); + if (nbufs >= NBUFS) + { + Tprintf (0, "__collector_write_string ERROR: string of length %d too long to be written to text file: %s\n", len, hndl->fname); + return 1; + } + + /* things are simple if we don't need new buffers */ + if (nbufs == 0) + { + /* try to update the handle position atomically */ + uint64_t npos = CUR_MAKE (0, indx, foff + len); + if (__collector_cas_64p (&hndl->curpos, &opos, &npos) != opos) + continue; + + /* success! copy our string and we're done */ + TprintfT (DBG_LT2, "__collector_write_string writeBuffer[%d]: vaddr = %p, len = %d, foff = %lld, '%s'\n", + indx, hndl->buffers[indx].vaddr, len, (long long) foff, src); + writeBuffer (&hndl->buffers[indx], foff & (blksz - 1), src, len); + break; + } + + /* initialize the new signal mask */ + sigset_t new_mask; + sigset_t old_mask; + CALL_UTIL (sigfillset)(&new_mask); + + /* 6618470: disable thread cancellation */ + int old_cstate; + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cstate); + /* block all signals */ + CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask); + + /* but if we need new buffers, "lock" the handle pointer */ + uint64_t lpos = CUR_MAKE (1, indx, foff); + if (__collector_cas_64p (&hndl->curpos, &opos, &lpos) != opos) + { + /* restore signal mask */ + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + /* Restore the previous cancellation state */ + pthread_setcancelstate (old_cstate, NULL); + continue; + } + + /* map new buffers */ + base = ((foff - 1) & ~(blksz - 1)); /* last buffer to have been mapped */ + for (ibuf = 0; ibuf < nbufs; ibuf++) + { + base += blksz; + buf_indices[ibuf] = newBuffer (hndl, base); + if (buf_indices[ibuf] < 0) + break; + } + + /* "unlock" the handle pointer */ + uint64_t npos = CUR_MAKE (0, indx, foff); + if (ibuf == nbufs) + npos = CUR_MAKE (0, buf_indices[nbufs - 1], foff + len); + if (__collector_cas_64p (&hndl->curpos, &lpos, &npos) != lpos) + { + TprintfT (0, "__collector_write_string ERROR: file handle corrupted: %s\n", hndl->fname); + /* + * At this point, the handle is apparently corrupted and + * presumably locked. No telling what's going on. Still + * let's proceed and write our data and let a later thread + * raise an error if it encounters one. + */ + } + + /* restore signal mask */ + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + /* Restore the previous cancellation state */ + pthread_setcancelstate (old_cstate, NULL); + + /* if we couldn't map all the buffers we needed, don't write any part of the string */ + if (ibuf < nbufs) + { + TprintfT (0, "__collector_write_string ERROR: can't map new buffer: %s\n", hndl->fname); + return 1; + } + + /* write any data to the old block */ + if (blk_off > 0) + { + TprintfT (DBG_LT2, "__collector_write_string partial writeBuffer[%d]: len=%ld, foff = %d '%s'\n", + indx, blksz - blk_off, blk_off, src); + writeBuffer (&hndl->buffers[indx], blk_off, src, blksz - blk_off); + src += blksz - blk_off; + len -= blksz - blk_off; + } + + /* write data to the new blocks */ + for (ibuf = 0; ibuf < nbufs; ibuf++) + { + int clen = blksz; + if (clen > len) + clen = len; + TprintfT (DBG_LT2, "__collector_write_string continue writeBuffer[%d]: len= %d, %s", + ibuf, clen, src); + writeBuffer (&hndl->buffers[buf_indices[ibuf]], 0, src, clen); + src += clen; + len -= clen; + } + break; + } + return 0; +} + diff --git a/gprofng/libcollector/iotrace.c b/gprofng/libcollector/iotrace.c new file mode 100644 index 0000000..462ccf2 --- /dev/null +++ b/gprofng/libcollector/iotrace.c @@ -0,0 +1,3728 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * IO events + */ +#include "config.h" +#include <dlfcn.h> +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> + +// create() and others are defined in fcntl.h. +// Our 'create' should not have the __nonnull attribute +#undef __nonnull +#define __nonnull(x) +#include <fcntl.h> + +#include "gp-defs.h" +#include "collector_module.h" +#include "gp-experiment.h" +#include "data_pckts.h" +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LTT 0 // for interposition on GLIBC functions +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* define the packet that will be written out */ +typedef struct IOTrace_packet +{ /* IO tracing packet */ + Common_packet comm; + IOTrace_type iotype; /* IO type */ + int32_t fd; /* file descriptor */ + Size_type nbyte; /* number of bytes */ + hrtime_t requested; /* time of IO requested */ + int32_t ofd; /* original file descriptor */ + FileSystem_type fstype; /* file system type */ + char fname; /* file name */ +} IOTrace_packet; + +typedef long long offset_t; + +static int open_experiment (const char *); +static int start_data_collection (void); +static int stop_data_collection (void); +static int close_experiment (void); +static int detach_experiment (void); +static int init_io_intf (); + +static ModuleInterface module_interface ={ + SP_IOTRACE_FILE, /* description */ + NULL, /* initInterface */ + open_experiment, /* openExperiment */ + start_data_collection, /* startDataCollection */ + stop_data_collection, /* stopDataCollection */ + close_experiment, /* closeExperiment */ + detach_experiment /* detachExperiment (fork child) */ +}; + +static CollectorInterface *collector_interface = NULL; +static struct Heap *io_heap = NULL; +static int io_mode = 0; +static CollectorModule io_hndl = COLLECTOR_MODULE_ERR; +static unsigned io_key = COLLECTOR_TSD_INVALID_KEY; + +#define CHCK_REENTRANCE(x) (!io_mode || ((x) = collector_interface->getKey( io_key )) == NULL || (*(x) != 0)) +#define RECHCK_REENTRANCE(x) (!io_mode || ((x) = collector_interface->getKey( io_key )) == NULL || (*(x) == 0)) +#define PUSH_REENTRANCE(x) ((*(x))++) +#define POP_REENTRANCE(x) ((*(x))--) + +#define CALL_REAL(x) (__real_##x) +#define NULL_PTR(x) (__real_##x == NULL) + +#define gethrtime collector_interface->getHiResTime + +#ifdef DEBUG +#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ ) +#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ ) +#else +#define Tprintf(...) +#define TprintfT(...) +#endif + +/* interposition function handles */ +static int (*__real_open)(const char *path, int oflag, ...) = NULL; +static int (*__real_fcntl)(int fildes, int cmd, ...) = NULL; +static int (*__real_openat)(int fildes, const char *path, int oflag, ...) = NULL; +static int (*__real_close)(int fildes) = NULL; +static FILE *(*__real_fopen)(const char *filename, const char *mode) = NULL; +static int (*__real_fclose)(FILE *stream) = NULL; +static int (*__real_dup)(int fildes) = NULL; +static int (*__real_dup2)(int fildes, int fildes2) = NULL; +static int (*__real_pipe)(int fildes[2]) = NULL; +static int (*__real_socket)(int domain, int type, int protocol) = NULL; +static int (*__real_mkstemp)(char *template) = NULL; +static int (*__real_mkstemps)(char *template, int slen) = NULL; +static int (*__real_creat)(const char *path, mode_t mode) = NULL; +static FILE *(*__real_fdopen)(int fildes, const char *mode) = NULL; +static ssize_t (*__real_read)(int fildes, void *buf, size_t nbyte) = NULL; +static ssize_t (*__real_write)(int fildes, const void *buf, size_t nbyte) = NULL; +static ssize_t (*__real_readv)(int fildes, const struct iovec *iov, int iovcnt) = NULL; +static ssize_t (*__real_writev)(int fildes, const struct iovec *iov, int iovcnt) = NULL; +static size_t (*__real_fread)(void *ptr, size_t size, size_t nitems, FILE *stream) = NULL; +static size_t (*__real_fwrite)(const void *ptr, size_t size, size_t nitems, FILE *stream) = NULL; +static ssize_t (*__real_pread)(int fildes, void *buf, size_t nbyte, off_t offset) = NULL; +static ssize_t (*__real_pwrite)(int fildes, const void *buf, size_t nbyte, off_t offset) = NULL; +static ssize_t (*__real_pwrite64)(int fildes, const void *buf, size_t nbyte, off64_t offset) = NULL; +static char *(*__real_fgets)(char *s, int n, FILE *stream) = NULL; +static int (*__real_fputs)(const char *s, FILE *stream) = NULL; +static int (*__real_fputc)(int c, FILE *stream) = NULL; +static int (*__real_fprintf)(FILE *stream, const char *format, ...) = NULL; +static int (*__real_vfprintf)(FILE *stream, const char *format, va_list ap) = NULL; +static off_t (*__real_lseek)(int fildes, off_t offset, int whence) = NULL; +static offset_t (*__real_llseek)(int fildes, offset_t offset, int whence) = NULL; +static int (*__real_chmod)(const char *path, mode_t mode) = NULL; +static int (*__real_access)(const char *path, int amode) = NULL; +static int (*__real_rename)(const char *old, const char *new) = NULL; +static int (*__real_mkdir)(const char *path, mode_t mode) = NULL; +static int (*__real_getdents)(int fildes, struct dirent *buf, size_t nbyte) = NULL; +static int (*__real_unlink)(const char *path) = NULL; +static int (*__real_fseek)(FILE *stream, long offset, int whence) = NULL; +static void (*__real_rewind)(FILE *stream) = NULL; +static long (*__real_ftell)(FILE *stream) = NULL; +static int (*__real_fgetpos)(FILE *stream, fpos_t *pos) = NULL; +static int (*__real_fsetpos)(FILE *stream, const fpos_t *pos) = NULL; +static int (*__real_fsync)(int fildes) = NULL; +static struct dirent *(*__real_readdir)(DIR *dirp) = NULL; +static int (*__real_flock)(int fd, int operation) = NULL; +static int (*__real_lockf)(int fildes, int function, off_t size) = NULL; +static int (*__real_fflush)(FILE *stream) = NULL; + +#if WSIZE(32) +static int (*__real_open64)(const char *path, int oflag, ...) = NULL; +static int (*__real_creat64)(const char *path, mode_t mode) = NULL; +static int (*__real_fgetpos64)(FILE *stream, fpos64_t *pos) = NULL; +static int (*__real_fsetpos64)(FILE *stream, const fpos64_t *pos) = NULL; + +#if ARCH(Intel) +static FILE *(*__real_fopen_2_1)(const char *filename, const char *mode) = NULL; +static int (*__real_fclose_2_1)(FILE *stream) = NULL; +static FILE *(*__real_fdopen_2_1)(int fildes, const char *mode) = NULL; +static int (*__real_fgetpos_2_2)(FILE *stream, fpos_t *pos) = NULL; +static int (*__real_fsetpos_2_2)(FILE *stream, const fpos_t *pos) = NULL; +static int (*__real_fgetpos64_2_2)(FILE *stream, fpos64_t *pos) = NULL; +static int (*__real_fsetpos64_2_2)(FILE *stream, const fpos64_t *pos) = NULL; +static int (*__real_open64_2_2)(const char *path, int oflag, ...) = NULL; +static ssize_t (*__real_pread_2_2)(int fildes, void *buf, size_t nbyte, off_t offset) = NULL; +static ssize_t (*__real_pwrite_2_2)(int fildes, const void *buf, size_t nbyte, off_t offset) = NULL; +static ssize_t (*__real_pwrite64_2_2)(int fildes, const void *buf, size_t nbyte, off64_t offset) = NULL; +static FILE *(*__real_fopen_2_0)(const char *filename, const char *mode) = NULL; +static int (*__real_fclose_2_0)(FILE *stream) = NULL; +static FILE *(*__real_fdopen_2_0)(int fildes, const char *mode) = NULL; +static int (*__real_fgetpos_2_0)(FILE *stream, fpos_t *pos) = NULL; +static int (*__real_fsetpos_2_0)(FILE *stream, const fpos_t *pos) = NULL; +static int (*__real_fgetpos64_2_1)(FILE *stream, fpos64_t *pos) = NULL; +static int (*__real_fsetpos64_2_1)(FILE *stream, const fpos64_t *pos) = NULL; +static int (*__real_open64_2_1)(const char *path, int oflag, ...) = NULL; +static ssize_t (*__real_pread_2_1)(int fildes, void *buf, size_t nbyte, off_t offset) = NULL; +static ssize_t (*__real_pwrite_2_1)(int fildes, const void *buf, size_t nbyte, off_t offset) = NULL; +static ssize_t (*__real_pwrite64_2_1)(int fildes, const void *buf, size_t nbyte, off64_t offset) = NULL; +#endif /* ARCH() */ +#endif /* WSIZE(32) */ + +static int +collector_align_pktsize (int sz) +{ + int pktSize = sz; + if (sz <= 0) + return sz; + if ((sz % 8) != 0) + { + pktSize = (sz / 8) + 1; + pktSize *= 8; + } + return pktSize; +} + +static void +collector_memset (void *s, int c, size_t n) +{ + unsigned char *s1 = s; + while (n--) + *s1++ = (unsigned char) c; +} + +static size_t +collector_strlen (const char *s) +{ + if (s == NULL) + return 0; + int len = -1; + while (s[++len] != '\0') + ; + return len; +} + +static size_t +collector_strncpy (char *dst, const char *src, size_t dstsize) +{ + size_t i; + for (i = 0; i < dstsize; i++) + { + dst[i] = src[i]; + if (src[i] == '\0') + break; + } + return i; +} + +static char * +collector_strchr (const char *s, int c) +{ + do + { + if (*s == (char) c) + return ((char *) s); + } + while (*s++); + return (NULL); +} + +static FileSystem_type +collector_fstype (const char *path) +{ + return UNKNOWNFS_TYPE; +} + +void +__collector_module_init (CollectorInterface *_collector_interface) +{ + if (_collector_interface == NULL) + return; + collector_interface = _collector_interface; + Tprintf (0, "iotrace: __collector_module_init\n"); + io_hndl = collector_interface->registerModule (&module_interface); + /* Initialize next module */ + ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init"); + if (next_init != NULL) + next_init (_collector_interface); + return; +} + +static int +open_experiment (const char *exp) +{ + if (collector_interface == NULL) + { + Tprintf (0, "iotrace: collector_interface is null.\n"); + return COL_ERROR_IOINIT; + } + if (io_hndl == COLLECTOR_MODULE_ERR) + { + Tprintf (0, "iotrace: handle create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_IOINIT); + return COL_ERROR_IOINIT; + } + TprintfT (0, "iotrace: open_experiment %s\n", exp); + if (NULL_PTR (fopen)) + init_io_intf (); + if (io_heap == NULL) + { + io_heap = collector_interface->newHeap (); + if (io_heap == NULL) + { + Tprintf (0, "iotrace: new heap failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">new iotrace heap not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_IOINIT); + return COL_ERROR_IOINIT; + } + } + + const char *params = collector_interface->getParams (); + while (params) + { + if ((params[0] == 'i') && (params[1] == ':')) + { + params += 2; + break; + } + params = collector_strchr (params, ';'); + if (params) + params++; + } + if (params == NULL) /* IO data collection not specified */ + return COL_ERROR_IOINIT; + + io_key = collector_interface->createKey (sizeof ( int), NULL, NULL); + if (io_key == (unsigned) - 1) + { + Tprintf (0, "iotrace: TSD key create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_IOINIT); + return COL_ERROR_IOINIT; + } + + collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_IOTRACE); + collector_interface->writeLog (" <profdata fname=\"%s\"/>\n", + module_interface.description); + /* Record IOTrace_packet description */ + IOTrace_packet *pp = NULL; + collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"IO tracing data\">\n", IOTRACE_PCKT); + collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IOTYPE\" uname=\"IO trace function type\" offset=\"%d\" type=\"%s\"/>\n", + &pp->iotype, sizeof (pp->iotype) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IOFD\" uname=\"File descriptor\" offset=\"%d\" type=\"%s\"/>\n", + &pp->fd, sizeof (pp->fd) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IONBYTE\" uname=\"Number of bytes\" offset=\"%d\" type=\"%s\"/>\n", + &pp->nbyte, sizeof (pp->nbyte) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IORQST\" uname=\"Time of IO requested\" offset=\"%d\" type=\"%s\"/>\n", + &pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IOOFD\" uname=\"Original file descriptor\" offset=\"%d\" type=\"%s\"/>\n", + &pp->ofd, sizeof (pp->ofd) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IOFSTYPE\" uname=\"File system type\" offset=\"%d\" type=\"%s\"/>\n", + &pp->fstype, sizeof (pp->fstype) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"IOFNAME\" uname=\"File name\" offset=\"%d\" type=\"%s\"/>\n", + &pp->fname, "STRING"); + collector_interface->writeLog (" </profpckt>\n"); + collector_interface->writeLog ("</profile>\n"); + return COL_ERROR_NONE; +} + +static int +start_data_collection (void) +{ + io_mode = 1; + Tprintf (0, "iotrace: start_data_collection\n"); + return 0; +} + +static int +stop_data_collection (void) +{ + io_mode = 0; + Tprintf (0, "iotrace: stop_data_collection\n"); + return 0; +} + +static int +close_experiment (void) +{ + io_mode = 0; + io_key = COLLECTOR_TSD_INVALID_KEY; + if (io_heap != NULL) + { + collector_interface->deleteHeap (io_heap); + io_heap = NULL; + } + Tprintf (0, "iotrace: close_experiment\n"); + return 0; +} + +static int +detach_experiment (void) +{ + /* fork child. Clean up state but don't write to experiment */ + io_mode = 0; + io_key = COLLECTOR_TSD_INVALID_KEY; + if (io_heap != NULL) + { + collector_interface->deleteHeap (io_heap); + io_heap = NULL; + } + Tprintf (0, "iotrace: detach_experiment\n"); + return 0; +} + +static int +init_io_intf () +{ + void *dlflag; + int rc = 0; + /* if we detect recursion/reentrance, SEGV so we can get a stack */ + static int init_io_intf_started; + static int init_io_intf_finished; + init_io_intf_started++; + if (!init_io_intf_finished && init_io_intf_started >= 3) + { + /* pull the plug if recursion occurs... */ + abort (); + } + + /* lookup fprint to print fatal error message */ + void *ptr = dlsym (RTLD_NEXT, "fprintf"); + if (ptr) + __real_fprintf = (int (*)(FILE*, const char*, ...)) ptr; + else + abort (); + +#if ARCH(Intel) +#if WSIZE(32) +#define SYS_FOPEN_X_VERSION "GLIBC_2.1" +#define SYS_FGETPOS_X_VERSION "GLIBC_2.2" +#define SYS_FGETPOS64_X_VERSION "GLIBC_2.2" +#define SYS_OPEN64_X_VERSION "GLIBC_2.2" +#define SYS_PREAD_X_VERSION "GLIBC_2.2" +#define SYS_PWRITE_X_VERSION "GLIBC_2.2" +#define SYS_PWRITE64_X_VERSION "GLIBC_2.2" +#else /* WSIZE(64) */ +#define SYS_FOPEN_X_VERSION "GLIBC_2.2.5" +#define SYS_FGETPOS_X_VERSION "GLIBC_2.2.5" +#endif +#elif ARCH(SPARC) +#if WSIZE(32) +#define SYS_FOPEN_X_VERSION "GLIBC_2.1" +#define SYS_FGETPOS_X_VERSION "GLIBC_2.2" +#else /* WSIZE(64) */ +#define SYS_FOPEN_X_VERSION "GLIBC_2.2" +#define SYS_FGETPOS_X_VERSION "GLIBC_2.2" +#endif +#elif ARCH(Aarch64) +#define SYS_FOPEN_X_VERSION "GLIBC_2.17" +#define SYS_FGETPOS_X_VERSION "GLIBC_2.17" +#endif /* ARCH() */ + +#if WSIZE(32) + dlflag = RTLD_NEXT; + __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (dlflag, "fopen", SYS_FOPEN_X_VERSION); + if (__real_fopen == NULL) + { + /* We are probably dlopened after libc, + * try to search in the previously loaded objects + */ + __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (RTLD_DEFAULT, "fopen", SYS_FOPEN_X_VERSION); + if (__real_fopen != NULL) + { + Tprintf (0, "iotrace: WARNING: init_io_intf() using RTLD_DEFAULT for Linux io routines\n"); + dlflag = RTLD_DEFAULT; + } + else + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fopen\n"); + rc = COL_ERROR_IOINIT; + } + } + + __real_fclose = (int (*)(FILE*))dlvsym (dlflag, "fclose", SYS_FOPEN_X_VERSION); + if (__real_fclose == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fclose\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fdopen = (FILE * (*)(int, const char*))dlvsym (dlflag, "fdopen", SYS_FOPEN_X_VERSION); + if (__real_fdopen == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fdopen\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fgetpos = (int (*)(FILE*, fpos_t*))dlvsym (dlflag, "fgetpos", SYS_FGETPOS_X_VERSION); + if (__real_fgetpos == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsetpos = (int (*)(FILE*, const fpos_t*))dlvsym (dlflag, "fsetpos", SYS_FGETPOS_X_VERSION); + if (__real_fsetpos == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos\n"); + rc = COL_ERROR_IOINIT; + } + + +#if ARCH(Intel) + __real_fopen_2_1 = __real_fopen; + __real_fclose_2_1 = __real_fclose; + __real_fdopen_2_1 = __real_fdopen; + __real_fgetpos_2_2 = __real_fgetpos; + __real_fsetpos_2_2 = __real_fsetpos; + + __real_fopen_2_0 = (FILE * (*)(const char*, const char*))dlvsym (dlflag, "fopen", "GLIBC_2.0"); + if (__real_fopen_2_0 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fopen_2_0\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fclose_2_0 = (int (*)(FILE*))dlvsym (dlflag, "fclose", "GLIBC_2.0"); + if (__real_fclose_2_0 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fclose_2_0\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fdopen_2_0 = (FILE * (*)(int, const char*))dlvsym (dlflag, "fdopen", "GLIBC_2.0"); + if (__real_fdopen_2_0 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fdopen_2_0\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fgetpos_2_0 = (int (*)(FILE*, fpos_t*))dlvsym (dlflag, "fgetpos", "GLIBC_2.0"); + if (__real_fgetpos_2_0 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos_2_0\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsetpos_2_0 = (int (*)(FILE*, const fpos_t*))dlvsym (dlflag, "fsetpos", "GLIBC_2.0"); + if (__real_fsetpos_2_0 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos_2_0\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fgetpos64_2_1 = (int (*)(FILE*, fpos64_t*))dlvsym (dlflag, "fgetpos64", "GLIBC_2.1"); + if (__real_fgetpos64_2_1 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos64_2_1\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsetpos64_2_1 = (int (*)(FILE*, const fpos64_t*))dlvsym (dlflag, "fsetpos64", "GLIBC_2.1"); + if (__real_fsetpos64_2_1 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos64_2_1\n"); + rc = COL_ERROR_IOINIT; + } + + __real_open64_2_1 = (int (*)(const char*, int, ...))dlvsym (dlflag, "open64", "GLIBC_2.1"); + if (__real_open64_2_1 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open64_2_1\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pread_2_1 = (int (*)(int fildes, void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pread", "GLIBC_2.1"); + if (__real_pread_2_1 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pread_2_1\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pwrite_2_1 = (int (*)(int fildes, const void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pwrite", "GLIBC_2.1"); + if (__real_pwrite_2_1 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite_2_1\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pwrite64_2_1 = (int (*)(int fildes, const void *buf, size_t nbyte, off64_t offset))dlvsym (dlflag, "pwrite64", "GLIBC_2.1"); + if (__real_pwrite64_2_1 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite64_2_1\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fgetpos64_2_2 = (int (*)(FILE*, fpos64_t*))dlvsym (dlflag, "fgetpos64", SYS_FGETPOS64_X_VERSION); + if (__real_fgetpos64_2_2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos64_2_2\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsetpos64_2_2 = (int (*)(FILE*, const fpos64_t*))dlvsym (dlflag, "fsetpos64", SYS_FGETPOS64_X_VERSION); + if (__real_fsetpos64_2_2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos64_2_2\n"); + rc = COL_ERROR_IOINIT; + } + + __real_open64_2_2 = (int (*)(const char*, int, ...))dlvsym (dlflag, "open64", SYS_OPEN64_X_VERSION); + if (__real_open64_2_2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open64_2_2\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pread_2_2 = (int (*)(int fildes, void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pread", SYS_PREAD_X_VERSION); + if (__real_pread_2_2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pread_2_2\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pwrite_2_2 = (int (*)(int fildes, const void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pwrite", SYS_PWRITE_X_VERSION); + if (__real_pwrite_2_2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite_2_2\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pwrite64_2_2 = (int (*)(int fildes, const void *buf, size_t nbyte, off64_t offset))dlvsym (dlflag, "pwrite64", SYS_PWRITE64_X_VERSION); + if (__real_pwrite64_2_2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite64_2_2\n"); + rc = COL_ERROR_IOINIT; + } + +#endif + +#else /* WSIZE(64) */ + dlflag = RTLD_NEXT; + __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (dlflag, "fopen", SYS_FOPEN_X_VERSION); + if (__real_fopen == NULL) + { + /* We are probably dlopened after libc, + * try to search in the previously loaded objects + */ + __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (RTLD_DEFAULT, "fopen", SYS_FOPEN_X_VERSION); + if (__real_fopen != NULL) + { + Tprintf (0, "iotrace: WARNING: init_io_intf() using RTLD_DEFAULT for Linux io routines\n"); + dlflag = RTLD_DEFAULT; + } + else + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fopen\n"); + rc = COL_ERROR_IOINIT; + } + } + + __real_fclose = (int (*)(FILE*))dlvsym (dlflag, "fclose", SYS_FOPEN_X_VERSION); + if (__real_fclose == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fclose\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fdopen = (FILE * (*)(int, const char*))dlvsym (dlflag, "fdopen", SYS_FOPEN_X_VERSION); + if (__real_fdopen == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fdopen\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fgetpos = (int (*)(FILE*, fpos_t*))dlvsym (dlflag, "fgetpos", SYS_FGETPOS_X_VERSION); + if (__real_fgetpos == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsetpos = (int (*)(FILE*, const fpos_t*))dlvsym (dlflag, "fsetpos", SYS_FGETPOS_X_VERSION); + if (__real_fsetpos == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos\n"); + rc = COL_ERROR_IOINIT; + } +#endif /* WSIZE(32) */ + + __real_open = (int (*)(const char*, int, ...))dlsym (dlflag, "open"); + if (__real_open == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open\n"); + rc = COL_ERROR_IOINIT; + } + +#if WSIZE(32) + __real_open64 = (int (*)(const char*, int, ...))dlsym (dlflag, "open64"); + if (__real_open64 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open64\n"); + rc = COL_ERROR_IOINIT; + } +#endif + + __real_fcntl = (int (*)(int, int, ...))dlsym (dlflag, "fcntl"); + if (__real_fcntl == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fcntl\n"); + rc = COL_ERROR_IOINIT; + } + + __real_openat = (int (*)(int, const char*, int, ...))dlsym (dlflag, "openat"); + if (__real_openat == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT openat\n"); + rc = COL_ERROR_IOINIT; + } + + __real_close = (int (*)(int))dlsym (dlflag, "close"); + if (__real_close == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT close\n"); + rc = COL_ERROR_IOINIT; + } + + __real_dup = (int (*)(int))dlsym (dlflag, "dup"); + if (__real_dup == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT dup\n"); + rc = COL_ERROR_IOINIT; + } + + __real_dup2 = (int (*)(int, int))dlsym (dlflag, "dup2"); + if (__real_dup2 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT dup2\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pipe = (int (*)(int[]))dlsym (dlflag, "pipe"); + if (__real_pipe == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pipe\n"); + rc = COL_ERROR_IOINIT; + } + + __real_socket = (int (*)(int, int, int))dlsym (dlflag, "socket"); + if (__real_socket == NULL) + { + __real_socket = (int (*)(int, int, int))dlsym (RTLD_NEXT, "socket"); + if (__real_socket == NULL) + { +#if 0 + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERXXX_IOINIT socket\n"); + rc = COL_ERROR_IOINIT; +#endif + } + } + + __real_mkstemp = (int (*)(char*))dlsym (dlflag, "mkstemp"); + if (__real_mkstemp == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT mkstemp\n"); + rc = COL_ERROR_IOINIT; + } + + __real_mkstemps = (int (*)(char*, int))dlsym (dlflag, "mkstemps"); + if (__real_mkstemps == NULL) + { +#if 0 + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERXXX_IOINIT mkstemps\n"); + rc = COL_ERROR_IOINIT; +#endif + } + + __real_creat = (int (*)(const char*, mode_t))dlsym (dlflag, "creat"); + if (__real_creat == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT creat\n"); + rc = COL_ERROR_IOINIT; + } + +#if WSIZE(32) + __real_creat64 = (int (*)(const char*, mode_t))dlsym (dlflag, "creat64"); + if (__real_creat64 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT creat64\n"); + rc = COL_ERROR_IOINIT; + } +#endif + + __real_read = (ssize_t (*)(int, void*, size_t))dlsym (dlflag, "read"); + if (__real_read == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT read\n"); + rc = COL_ERROR_IOINIT; + } + + __real_write = (ssize_t (*)(int, const void*, size_t))dlsym (dlflag, "write"); + if (__real_write == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT write\n"); + rc = COL_ERROR_IOINIT; + } + + __real_readv = (ssize_t (*)(int, const struct iovec*, int))dlsym (dlflag, "readv"); + if (__real_readv == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT readv\n"); + rc = COL_ERROR_IOINIT; + } + + __real_writev = (ssize_t (*)(int, const struct iovec*, int))dlsym (dlflag, "writev"); + if (__real_writev == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT writev\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fread = (size_t (*)(void*, size_t, size_t, FILE*))dlsym (dlflag, "fread"); + if (__real_fread == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fread\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fwrite = (size_t (*)(const void*, size_t, size_t, FILE*))dlsym (dlflag, "fwrite"); + if (__real_fwrite == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fwrite\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pread = (ssize_t (*)(int, void*, size_t, off_t))dlsym (dlflag, "pread"); + if (__real_pread == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pread\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pwrite = (ssize_t (*)(int, const void*, size_t, off_t))dlsym (dlflag, "pwrite"); + if (__real_pwrite == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite\n"); + rc = COL_ERROR_IOINIT; + } + + __real_pwrite64 = (ssize_t (*)(int, const void*, size_t, off64_t))dlsym (dlflag, "pwrite64"); + if (__real_pwrite64 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite64\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fgets = (char* (*)(char*, int, FILE*))dlsym (dlflag, "fgets"); + if (__real_fgets == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgets\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fputs = (int (*)(const char*, FILE*))dlsym (dlflag, "fputs"); + if (__real_fputs == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fputs\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fputc = (int (*)(int, FILE*))dlsym (dlflag, "fputc"); + if (__real_fputc == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fputc\n"); + rc = COL_ERROR_IOINIT; + } + + __real_vfprintf = (int (*)(FILE*, const char*, va_list))dlsym (dlflag, "vfprintf"); + if (__real_vfprintf == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT vfprintf\n"); + rc = COL_ERROR_IOINIT; + } + + + __real_lseek = (off_t (*)(int, off_t, int))dlsym (dlflag, "lseek"); + if (__real_lseek == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT lseek\n"); + rc = COL_ERROR_IOINIT; + } + + __real_llseek = (offset_t (*)(int, offset_t, int))dlsym (dlflag, "llseek"); + if (__real_llseek == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT llseek\n"); + rc = COL_ERROR_IOINIT; + } + + __real_chmod = (int (*)(const char*, mode_t))dlsym (dlflag, "chmod"); + if (__real_chmod == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT chmod\n"); + rc = COL_ERROR_IOINIT; + } + + __real_access = (int (*)(const char*, int))dlsym (dlflag, "access"); + if (__real_access == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT access\n"); + rc = COL_ERROR_IOINIT; + } + + __real_rename = (int (*)(const char*, const char*))dlsym (dlflag, "rename"); + if (__real_rename == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT rename\n"); + rc = COL_ERROR_IOINIT; + } + + __real_mkdir = (int (*)(const char*, mode_t))dlsym (dlflag, "mkdir"); + if (__real_mkdir == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT mkdir\n"); + rc = COL_ERROR_IOINIT; + } + + __real_getdents = (int (*)(int, struct dirent*, size_t))dlsym (dlflag, "getdents"); + if (__real_getdents == NULL) + { +#if 0 + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERXXX_IOINIT getdents\n"); + rc = COL_ERROR_IOINIT; +#endif + } + + __real_unlink = (int (*)(const char*))dlsym (dlflag, "unlink"); + if (__real_unlink == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT unlink\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fseek = (int (*)(FILE*, long, int))dlsym (dlflag, "fseek"); + if (__real_fseek == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fseek\n"); + rc = COL_ERROR_IOINIT; + } + + __real_rewind = (void (*)(FILE*))dlsym (dlflag, "rewind"); + if (__real_rewind == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT rewind\n"); + rc = COL_ERROR_IOINIT; + } + + __real_ftell = (long (*)(FILE*))dlsym (dlflag, "ftell"); + if (__real_ftell == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT ftell\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsync = (int (*)(int))dlsym (dlflag, "fsync"); + if (__real_fsync == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsync\n"); + rc = COL_ERROR_IOINIT; + } + + __real_readdir = (struct dirent * (*)(DIR*))dlsym (dlflag, "readdir"); + if (__real_readdir == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT readdir\n"); + rc = COL_ERROR_IOINIT; + } + + __real_flock = (int (*)(int, int))dlsym (dlflag, "flock"); + if (__real_flock == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT flock\n"); + rc = COL_ERROR_IOINIT; + } + + __real_lockf = (int (*)(int, int, off_t))dlsym (dlflag, "lockf"); + if (__real_lockf == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT lockf\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fflush = (int (*)(FILE*))dlsym (dlflag, "fflush"); + if (__real_fflush == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fflush\n"); + rc = COL_ERROR_IOINIT; + } + +#if WSIZE(32) + __real_fgetpos64 = (int (*)(FILE*, fpos64_t*))dlsym (dlflag, "fgetpos64"); + if (__real_fgetpos64 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos64\n"); + rc = COL_ERROR_IOINIT; + } + + __real_fsetpos64 = (int (*)(FILE*, const fpos64_t*))dlsym (dlflag, "fsetpos64"); + if (__real_fsetpos64 == NULL) + { + CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos64\n"); + rc = COL_ERROR_IOINIT; + } +#endif + init_io_intf_finished++; + return rc; +} + +/*------------------------------------------------------------- open */ +int +open (const char *path, int oflag, ...) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + mode_t mode; + va_list ap; + size_t sz; + unsigned pktSize; + + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + va_end (ap); + + if (NULL_PTR (open)) + init_io_intf (); + + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (open)(path, oflag, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (open)(path, oflag, mode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (path); + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: open cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- open64 */ +#if ARCH(Intel) && WSIZE(32) +// map interposed symbol versions +static int +__collector_open64_symver (int(real_open64) (const char *, int, ...), + const char *path, int oflag, mode_t mode); + +int +__collector_open64_2_2 (const char *path, int oflag, ...) +{ + mode_t mode; + va_list ap; + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + va_end (ap); + TprintfT (DBG_LTT, + "iotrace: __collector_open64_2_2@%p(path=%s, oflag=0%o, mode=0%o\n", + CALL_REAL (open64_2_2), path ? path : "NULL", oflag, mode); + if (NULL_PTR (open64)) + init_io_intf (); + return __collector_open64_symver (CALL_REAL (open64_2_2), path, oflag, mode); +} + +int +__collector_open64_2_1 (const char *path, int oflag, ...) +{ + mode_t mode; + va_list ap; + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + va_end (ap); + TprintfT (DBG_LTT, + "iotrace: __collector_open64_2_1@%p(path=%s, oflag=0%o, mode=0%o\n", + CALL_REAL (open64_2_1), path ? path : "NULL", oflag, mode); + if (NULL_PTR (open64)) + init_io_intf (); + return __collector_open64_symver (CALL_REAL (open64_2_1), path, oflag, mode); +} + +__asm__(".symver __collector_open64_2_2,open64@@GLIBC_2.2"); +__asm__(".symver __collector_open64_2_1,open64@GLIBC_2.1"); + +#endif /* ARCH(Intel) && WSIZE(32) */ +#if WSIZE(32) +#if ARCH(Intel) && WSIZE(32) + +static int +__collector_open64_symver (int(real_open64) (const char *, int, ...), + const char *path, int oflag, mode_t mode) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (open64)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return (real_open64) (path, oflag, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = real_open64 (path, oflag, mode); +#else /* ^ARCH(Intel) && WSIZE(32) */ + +int +open64 (const char *path, int oflag, ...) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + mode_t mode; + va_list ap; + size_t sz; + unsigned pktSize; + + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + va_end (ap); + if (NULL_PTR (open64)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (open64)(path, oflag, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (open64)(path, oflag, mode); +#endif /* ^ARCH(Intel) && WSIZE(32) */ + + if (RECHCK_REENTRANCE (guard) || path == NULL) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (path); + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: open64 cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} +#endif + +#define F_ERROR_ARG 0 +#define F_INT_ARG 1 +#define F_LONG_ARG 2 +#define F_VOID_ARG 3 + +/* + * The following macro is not defined in the + * older versions of Linux. + * #define F_DUPFD_CLOEXEC 1030 + * + * Instead use the command that is defined below + * until we start compiling mpmt on the newer + * versions of Linux. + */ +#define TMP_F_DUPFD_CLOEXEC 1030 + +/*------------------------------------------------------------- fcntl */ +int +fcntl (int fildes, int cmd, ...) +{ + int *guard; + int fd = 0; + IOTrace_packet iopkt; + long long_arg = 0; + int int_arg = 0; + int which_arg = F_ERROR_ARG; + va_list ap; + switch (cmd) + { + case F_DUPFD: + case TMP_F_DUPFD_CLOEXEC: + case F_SETFD: + case F_SETFL: + case F_SETOWN: + case F_SETSIG: + case F_SETLEASE: + case F_NOTIFY: + case F_SETLK: + case F_SETLKW: + case F_GETLK: + va_start (ap, cmd); + long_arg = va_arg (ap, long); + va_end (ap); + which_arg = F_LONG_ARG; + break; + case F_GETFD: + case F_GETFL: + case F_GETOWN: + case F_GETLEASE: + case F_GETSIG: + which_arg = F_VOID_ARG; + break; + } + if (NULL_PTR (fcntl)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + { + switch (which_arg) + { + case F_INT_ARG: + return CALL_REAL (fcntl)(fildes, cmd, int_arg); + case F_LONG_ARG: + return CALL_REAL (fcntl)(fildes, cmd, long_arg); + case F_VOID_ARG: + return CALL_REAL (fcntl)(fildes, cmd); + case F_ERROR_ARG: + Tprintf (0, "iotrace: ERROR: Unsupported fcntl command\n"); + return -1; + } + return -1; + } + if (cmd != F_DUPFD && cmd != TMP_F_DUPFD_CLOEXEC) + { + switch (which_arg) + { + case F_INT_ARG: + return CALL_REAL (fcntl)(fildes, cmd, int_arg); + case F_LONG_ARG: + return CALL_REAL (fcntl)(fildes, cmd, long_arg); + case F_VOID_ARG: + return CALL_REAL (fcntl)(fildes, cmd); + case F_ERROR_ARG: + Tprintf (0, "iotrace: ERROR: Unsupported fcntl command\n"); + return -1; + } + return -1; + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + switch (cmd) + { + case F_DUPFD: + case TMP_F_DUPFD_CLOEXEC: + fd = CALL_REAL (fcntl)(fildes, cmd, long_arg); + break; + } + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (fd != -1) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + iopkt.fd = fd; + iopkt.ofd = fildes; + iopkt.fstype = UNKNOWNFS_TYPE; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- openat */ +int +openat (int fildes, const char *path, int oflag, ...) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + mode_t mode; + va_list ap; + size_t sz; + unsigned pktSize; + + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + va_end (ap); + if (NULL_PTR (openat)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (openat)(fildes, path, oflag, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (openat)(fildes, path, oflag, mode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (path); + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: openat cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- creat */ +int +creat (const char *path, mode_t mode) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (creat)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (creat)(path, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (creat)(path, mode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (path); + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: creat cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- creat64 */ +#if WSIZE(32) +int +creat64 (const char *path, mode_t mode) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + + if (NULL_PTR (creat64)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (creat64)(path, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (creat64)(path, mode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (path); + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: creat64 cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} +#endif + +/*------------------------------------------------------------- mkstemp */ +int +mkstemp (char *template) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (mkstemp)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || template == NULL) + return CALL_REAL (mkstemp)(template); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (mkstemp)(template); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (template); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (template); + collector_strncpy (&(iopkt->fname), template, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: mkstemp cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- mkstemps */ +int +mkstemps (char *template, int slen) +{ + int *guard; + int fd; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (mkstemps)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || template == NULL) + return CALL_REAL (mkstemps)(template, slen); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (mkstemps)(template, slen); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (template); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fd != -1) + iopkt->iotype = OPEN_TRACE; + else + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = fd; + iopkt->fstype = collector_fstype (template); + collector_strncpy (&(iopkt->fname), template, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: mkstemps cannot allocate memory\n"); + return -1; + } + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- close */ +int +close (int fildes) +{ + int *guard; + int stat; + IOTrace_packet iopkt; + if (NULL_PTR (close)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (close)(fildes); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + stat = CALL_REAL (close)(fildes); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return stat; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (stat == 0) + iopkt.iotype = CLOSE_TRACE; + else + iopkt.iotype = CLOSE_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return stat; +} + +/*------------------------------------------------------------- fopen */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) + +static FILE* +__collector_fopen_symver (FILE*(real_fopen) (), const char *filename, const char *mode); + +FILE* +__collector_fopen_2_1 (const char *filename, const char *mode) +{ + if (NULL_PTR (fopen)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fopen_2_1@%p\n", CALL_REAL (fopen_2_1)); + return __collector_fopen_symver (CALL_REAL (fopen_2_1), filename, mode); +} + +FILE* +__collector_fopen_2_0 (const char *filename, const char *mode) +{ + if (NULL_PTR (fopen)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fopen_2_0@%p\n", CALL_REAL (fopen_2_0)); + return __collector_fopen_symver (CALL_REAL (fopen_2_0), filename, mode); +} + +__asm__(".symver __collector_fopen_2_1,fopen@@GLIBC_2.1"); +__asm__(".symver __collector_fopen_2_0,fopen@GLIBC_2.0"); + +#endif + +#if ARCH(Intel) && WSIZE(32) + +static FILE* +__collector_fopen_symver (FILE*(real_fopen) (), const char *filename, const char *mode) +{ +#else + +FILE* +fopen (const char *filename, const char *mode) +{ +#endif + int *guard; + FILE *fp = NULL; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (fopen)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || filename == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_fopen) (filename, mode); +#else + return CALL_REAL (fopen)(filename, mode); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + +#if ARCH(Intel) && WSIZE(32) + fp = (real_fopen) (filename, mode); +#else + fp = CALL_REAL (fopen)(filename, mode); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fp; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (filename); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (fp != NULL) + { + iopkt->iotype = OPEN_TRACE; + iopkt->fd = fileno (fp); + } + else + { + iopkt->iotype = OPEN_TRACE_ERROR; + iopkt->fd = -1; + } + iopkt->fstype = collector_fstype (filename); + collector_strncpy (&(iopkt->fname), filename, sz); + +#if ARCH(Intel) && WSIZE(32) + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: fopen cannot allocate memory\n"); + return NULL; + } + POP_REENTRANCE (guard); + return fp; +} + +/*------------------------------------------------------------- fclose */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) + +static int +__collector_fclose_symver (int(real_fclose) (), FILE *stream); + +int +__collector_fclose_2_1 (FILE *stream) +{ + if (NULL_PTR (fclose)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fclose_2_1@%p\n", CALL_REAL (fclose_2_1)); + return __collector_fclose_symver (CALL_REAL (fclose_2_1), stream); +} + +int +__collector_fclose_2_0 (FILE *stream) +{ + if (NULL_PTR (fclose)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fclose_2_0@%p\n", CALL_REAL (fclose_2_0)); + return __collector_fclose_symver (CALL_REAL (fclose_2_0), stream); +} + +__asm__(".symver __collector_fclose_2_1,fclose@@GLIBC_2.1"); +__asm__(".symver __collector_fclose_2_0,fclose@GLIBC_2.0"); + +#endif + +#if ARCH(Intel) && WSIZE(32) + +static int +__collector_fclose_symver (int(real_fclose) (), FILE *stream) +{ +#else + +int +fclose (FILE *stream) +{ +#endif + int *guard; + int stat; + IOTrace_packet iopkt; + if (NULL_PTR (fclose)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_fclose) (stream); +#else + return CALL_REAL (fclose)(stream); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + stat = (real_fclose) (stream); +#else + stat = CALL_REAL (fclose)(stream); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return stat; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (stat == 0) + iopkt.iotype = CLOSE_TRACE; + else + iopkt.iotype = CLOSE_TRACE_ERROR; + iopkt.fd = fileno (stream); + +#if ARCH(Intel) && WSIZE(32) + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return stat; +} + +/*------------------------------------------------------------- fflush */ +int +fflush (FILE *stream) +{ + int *guard; + int stat; + IOTrace_packet iopkt; + if (NULL_PTR (fflush)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (fflush)(stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + stat = CALL_REAL (fflush)(stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return stat; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (stat == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + if (stream != NULL) + iopkt.fd = fileno (stream); + else + iopkt.fd = -1; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return stat; +} + +/*------------------------------------------------------------- fdopen */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) + +static FILE* +__collector_fdopen_symver (FILE*(real_fdopen) (), int fildes, const char *mode); + +FILE* +__collector_fdopen_2_1 (int fildes, const char *mode) +{ + if (NULL_PTR (fdopen)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fdopen_2_1@%p\n", CALL_REAL (fdopen_2_1)); + return __collector_fdopen_symver (CALL_REAL (fdopen_2_1), fildes, mode); +} + +FILE* +__collector_fdopen_2_0 (int fildes, const char *mode) +{ + if (NULL_PTR (fdopen)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fdopen_2_0@%p\n", CALL_REAL (fdopen_2_0)); + return __collector_fdopen_symver (CALL_REAL (fdopen_2_0), fildes, mode); +} + +__asm__(".symver __collector_fdopen_2_1,fdopen@@GLIBC_2.1"); +__asm__(".symver __collector_fdopen_2_0,fdopen@GLIBC_2.0"); + +#endif + +#if ARCH(Intel) && WSIZE(32) +static FILE* +__collector_fdopen_symver (FILE*(real_fdopen) (), int fildes, const char *mode) +{ +#else +FILE* +fdopen (int fildes, const char *mode) +{ +#endif + int *guard; + FILE *fp = NULL; + IOTrace_packet iopkt; + if (NULL_PTR (fdopen)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + { +#if ARCH(Intel) && WSIZE(32) + return (real_fdopen) (fildes, mode); +#else + return CALL_REAL (fdopen)(fildes, mode); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + fp = (real_fdopen) (fildes, mode); +#else + fp = CALL_REAL (fdopen)(fildes, mode); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fp; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (fp != NULL) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.fstype = UNKNOWNFS_TYPE; +#if ARCH(Intel) && WSIZE(32) + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return fp; +} + +/*------------------------------------------------------------- dup */ +int +dup (int fildes) +{ + int *guard; + int fd; + IOTrace_packet iopkt; + if (NULL_PTR (dup)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (dup)(fildes); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (dup)(fildes); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (fd != -1) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + + iopkt.fd = fd; + iopkt.ofd = fildes; + iopkt.fstype = UNKNOWNFS_TYPE; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- dup2 */ +int +dup2 (int fildes, int fildes2) +{ + int *guard; + int fd; + IOTrace_packet iopkt; + if (NULL_PTR (dup2)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (dup2)(fildes, fildes2); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (dup2)(fildes, fildes2); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (fd != -1) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + iopkt.fd = fd; + iopkt.ofd = fildes; + iopkt.fstype = UNKNOWNFS_TYPE; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- pipe */ +int +pipe (int fildes[2]) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (pipe)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (pipe)(fildes); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (pipe)(fildes); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + iopkt.fd = fildes[0]; + iopkt.fstype = UNKNOWNFS_TYPE; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + iopkt.fd = fildes[1]; + iopkt.fstype = UNKNOWNFS_TYPE; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- socket */ +int +socket (int domain, int type, int protocol) +{ + int *guard; + int fd; + IOTrace_packet iopkt; + if (NULL_PTR (socket)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (socket)(domain, type, protocol); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + fd = CALL_REAL (socket)(domain, type, protocol); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return fd; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (fd != -1) + iopkt.iotype = OPEN_TRACE; + else + iopkt.iotype = OPEN_TRACE_ERROR; + iopkt.fd = fd; + iopkt.fstype = UNKNOWNFS_TYPE; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return fd; +} + +/*------------------------------------------------------------- read */ +ssize_t +read (int fildes, void *buf, size_t nbyte) +{ + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (read)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (read)(fildes, buf, nbyte); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (read)(fildes, buf, nbyte); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = READ_TRACE; + else + iopkt.iotype = READ_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- write */ +ssize_t +write (int fildes, const void *buf, size_t nbyte) +{ + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (write)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (write)(fildes, buf, nbyte); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (write)(fildes, buf, nbyte); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = WRITE_TRACE; + else + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- readv */ +ssize_t +readv (int fildes, const struct iovec *iov, int iovcnt) +{ + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (readv)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (readv)(fildes, iov, iovcnt); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (readv)(fildes, iov, iovcnt); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = READ_TRACE; + else + iopkt.iotype = READ_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- writev */ +ssize_t +writev (int fildes, const struct iovec *iov, int iovcnt) +{ + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (writev)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (writev)(fildes, iov, iovcnt); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (writev)(fildes, iov, iovcnt); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = WRITE_TRACE; + else + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fread */ +size_t +fread (void *ptr, size_t size, size_t nitems, FILE *stream) +{ + int *guard; + size_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (fread)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (fread)(ptr, size, nitems, stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (fread)(ptr, size, nitems, stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ferror (stream) == 0) + { + iopkt.iotype = READ_TRACE; + iopkt.nbyte = ret * size; + } + else + { + iopkt.iotype = READ_TRACE_ERROR; + iopkt.nbyte = 0; + } + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fwrite */ +size_t +fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream) +{ + int *guard; + size_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (fwrite)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (fwrite)(ptr, size, nitems, stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (fwrite)(ptr, size, nitems, stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ferror (stream) == 0) + { + iopkt.iotype = WRITE_TRACE; + iopkt.nbyte = ret * size; + } + else + { + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.nbyte = 0; + } + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- pread */ +#if ARCH(Intel) && WSIZE(32) +// map interposed symbol versions +static int +__collector_pread_symver (int(real_pread) (), int fildes, void *buf, size_t nbyte, off_t offset); + +int +__collector_pread_2_2 (int fildes, void *buf, size_t nbyte, off_t offset) +{ + TprintfT (DBG_LTT, "iotrace: __collector_pread_2_2@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n", + CALL_REAL (pread_2_2), fildes, buf, (long long) nbyte, (long long) offset); + if (NULL_PTR (pread)) + init_io_intf (); + return __collector_pread_symver (CALL_REAL (pread_2_2), fildes, buf, nbyte, offset); +} + +int +__collector_pread_2_1 (int fildes, void *buf, size_t nbyte, off_t offset) +{ + TprintfT (DBG_LTT, "iotrace: __collector_pread_2_1@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n", + CALL_REAL (pread_2_1), fildes, buf, (long long) nbyte, (long long) offset); + if (NULL_PTR (pread)) + init_io_intf (); + return __collector_pread_symver (CALL_REAL (pread_2_1), fildes, buf, nbyte, offset); +} + +__asm__(".symver __collector_pread_2_2,pread@@GLIBC_2.2"); +__asm__(".symver __collector_pread_2_1,pread@GLIBC_2.1"); + +static int +__collector_pread_symver (int(real_pread) (), int fildes, void *buf, size_t nbyte, off_t offset) +{ +#else /* ^ARCH(Intel) && WSIZE(32) */ + +ssize_t +pread (int fildes, void *buf, size_t nbyte, off_t offset) +{ +#endif + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (pread)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + { +#if ARCH(Intel) && WSIZE(32) + return (real_pread) (fildes, buf, nbyte, offset); +#else + return CALL_REAL (pread)(fildes, buf, nbyte, offset); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + ret = (real_pread) (fildes, buf, nbyte, offset); +#else + ret = CALL_REAL (pread)(fildes, buf, nbyte, offset); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = READ_TRACE; + else + iopkt.iotype = READ_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- pwrite */ +#if ARCH(Intel) && WSIZE(32) +// map interposed symbol versions +static int +__collector_pwrite_symver (int(real_pwrite) (), int fildes, const void *buf, size_t nbyte, off_t offset); + +int +__collector_pwrite_2_2 (int fildes, const void *buf, size_t nbyte, off_t offset) +{ + TprintfT (DBG_LTT, "iotrace: __collector_pwrite_2_2@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n", + CALL_REAL (pwrite_2_2), fildes, buf, (long long) nbyte, (long long) offset); + if (NULL_PTR (pwrite)) + init_io_intf (); + return __collector_pwrite_symver (CALL_REAL (pwrite_2_2), fildes, buf, nbyte, offset); +} + +int +__collector_pwrite_2_1 (int fildes, const void *buf, size_t nbyte, off_t offset) +{ + TprintfT (DBG_LTT, "iotrace: __collector_pwrite_2_1@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n", + CALL_REAL (pwrite_2_1), fildes, buf, (long long) nbyte, (long long) offset); + if (NULL_PTR (pwrite)) + init_io_intf (); + return __collector_pwrite_symver (CALL_REAL (pwrite_2_1), fildes, buf, nbyte, offset); +} + +__asm__(".symver __collector_pwrite_2_2,pwrite@@GLIBC_2.2"); +__asm__(".symver __collector_pwrite_2_1,pwrite@GLIBC_2.1"); + +static int +__collector_pwrite_symver (int(real_pwrite) (), int fildes, const void *buf, size_t nbyte, off_t offset) +{ +#else /* ^ARCH(Intel) && WSIZE(32) */ + +ssize_t +pwrite (int fildes, const void *buf, size_t nbyte, off_t offset) +{ +#endif /* ^ARCH(Intel) && WSIZE(32) */ + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (pwrite)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + { +#if ARCH(Intel) && WSIZE(32) + return (real_pwrite) (fildes, buf, nbyte, offset); +#else + return CALL_REAL (pwrite)(fildes, buf, nbyte, offset); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + ret = (real_pwrite) (fildes, buf, nbyte, offset); +#else + ret = CALL_REAL (pwrite)(fildes, buf, nbyte, offset); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = WRITE_TRACE; + else + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- pwrite64 */ +#if ARCH(Intel) && WSIZE(32) +// map interposed symbol versions +static int +__collector_pwrite64_symver (int(real_pwrite64) (), int fildes, const void *buf, size_t nbyte, off64_t offset); + +int +__collector_pwrite64_2_2 (int fildes, const void *buf, size_t nbyte, off64_t offset) +{ + TprintfT (DBG_LTT, "iotrace: __collector_pwrite64_2_2@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n", + CALL_REAL (pwrite64_2_2), fildes, buf, (long long) nbyte, (long long) offset); + if (NULL_PTR (pwrite64)) + init_io_intf (); + return __collector_pwrite64_symver (CALL_REAL (pwrite64_2_2), fildes, buf, nbyte, offset); +} + +int +__collector_pwrite64_2_1 (int fildes, const void *buf, size_t nbyte, off64_t offset) +{ + TprintfT (DBG_LTT, "iotrace: __collector_pwrite64_2_1@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n", + CALL_REAL (pwrite64_2_1), fildes, buf, (long long) nbyte, (long long) offset); + if (NULL_PTR (pwrite64)) + init_io_intf (); + return __collector_pwrite64_symver (CALL_REAL (pwrite64_2_1), fildes, buf, nbyte, offset); +} + +__asm__(".symver __collector_pwrite64_2_2,pwrite64@@GLIBC_2.2"); +__asm__(".symver __collector_pwrite64_2_1,pwrite64@GLIBC_2.1"); + +static int +__collector_pwrite64_symver (int(real_pwrite64) (), int fildes, const void *buf, size_t nbyte, off64_t offset) +{ +#else /* ^ARCH(Intel) && WSIZE(32) */ + +ssize_t +pwrite64 (int fildes, const void *buf, size_t nbyte, off64_t offset) +{ +#endif /* ^ARCH(Intel) && WSIZE(32) */ + int *guard; + ssize_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (pwrite64)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + { +#if ARCH(Intel) && WSIZE(32) + return (real_pwrite64) (fildes, buf, nbyte, offset); +#else + return CALL_REAL (pwrite64)(fildes, buf, nbyte, offset); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + ret = (real_pwrite64) (fildes, buf, nbyte, offset); +#else + ret = CALL_REAL (pwrite64)(fildes, buf, nbyte, offset); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = WRITE_TRACE; + else + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fgets */ +char* +fgets (char *s, int n, FILE *stream) +{ + int *guard; + char *ptr; + IOTrace_packet iopkt; + if (NULL_PTR (fgets)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (fgets)(s, n, stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ptr = CALL_REAL (fgets)(s, n, stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ptr; + } + int error = errno; + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ptr != NULL) + { + iopkt.iotype = READ_TRACE; + iopkt.nbyte = collector_strlen (ptr); + } + else if (ptr == NULL && error != EAGAIN && error != EBADF && error != EINTR && + error != EIO && error != EOVERFLOW && error != ENOMEM && error != ENXIO) + { + iopkt.iotype = READ_TRACE; + iopkt.nbyte = 0; + } + else + iopkt.iotype = READ_TRACE_ERROR; + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ptr; +} + +/*------------------------------------------------------------- fputs */ +int +fputs (const char *s, FILE *stream) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fputs)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (fputs)(s, stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (fputs)(s, stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != EOF) + { + iopkt.iotype = WRITE_TRACE; + iopkt.nbyte = ret; + } + else + { + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.nbyte = 0; + } + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fputc */ +int +fputc (int c, FILE *stream) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fputc)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (fputc)(c, stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (fputc)(c, stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != EOF) + { + iopkt.iotype = WRITE_TRACE; + iopkt.nbyte = ret; + } + else + { + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.nbyte = 0; + } + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fprintf */ +int +fprintf (FILE *stream, const char *format, ...) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + va_list ap; + va_start (ap, format); + if (NULL_PTR (fprintf)) + init_io_intf (); + if (NULL_PTR (vfprintf)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (vfprintf)(stream, format, ap); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (vfprintf)(stream, format, ap); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = WRITE_TRACE; + else + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.fd = fileno (stream); + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- vfprintf */ +int +vfprintf (FILE *stream, const char *format, va_list ap) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (vfprintf)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (vfprintf)(stream, format, ap); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (vfprintf)(stream, format, ap); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret >= 0) + iopkt.iotype = WRITE_TRACE; + else + iopkt.iotype = WRITE_TRACE_ERROR; + iopkt.fd = fileno (stream); + iopkt.nbyte = ret; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- lseek */ +off_t +lseek (int fildes, off_t offset, int whence) +{ + int *guard; + off_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (lseek)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (lseek)(fildes, offset, whence); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (lseek)(fildes, offset, whence); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- llseek */ +offset_t +llseek (int fildes, offset_t offset, int whence) +{ + int *guard; + offset_t ret; + IOTrace_packet iopkt; + if (NULL_PTR (llseek)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (llseek)(fildes, offset, whence); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (llseek)(fildes, offset, whence); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- chmod */ +int +chmod (const char *path, mode_t mode) +{ + int *guard; + int ret; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (chmod)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (chmod)(path, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (chmod)(path, mode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (ret != -1) + iopkt->iotype = OTHERIO_TRACE; + else + iopkt->iotype = OTHERIO_TRACE_ERROR; + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: chmod cannot allocate memory\n"); + return 0; + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- access */ +int +access (const char *path, int amode) +{ + int *guard; + int ret; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (access)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (access)(path, amode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (access)(path, amode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (ret != -1) + iopkt->iotype = OTHERIO_TRACE; + else + iopkt->iotype = OTHERIO_TRACE_ERROR; + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: access cannot allocate memory\n"); + return 0; + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- rename */ +int +rename (const char *old, const char *new) +{ + int *guard; + int ret; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (rename)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || new == NULL) + return CALL_REAL (rename)(old, new); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (rename)(old, new); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (new); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (ret != -1) + iopkt->iotype = OTHERIO_TRACE; + else + iopkt->iotype = OTHERIO_TRACE_ERROR; + collector_strncpy (&(iopkt->fname), new, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: rename cannot allocate memory\n"); + return 0; + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- mkdir */ +int +mkdir (const char *path, mode_t mode) +{ + int *guard; + int ret; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (mkdir)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (mkdir)(path, mode); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (mkdir)(path, mode); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (ret != -1) + iopkt->iotype = OTHERIO_TRACE; + else + iopkt->iotype = OTHERIO_TRACE_ERROR; + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: mkdir cannot allocate memory\n"); + return 0; + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- getdents */ +int +getdents (int fildes, struct dirent *buf, size_t nbyte) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (getdents)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (getdents)(fildes, buf, nbyte); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (getdents)(fildes, buf, nbyte); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- unlink */ +int +unlink (const char *path) +{ + int *guard; + int ret; + void *packet; + IOTrace_packet *iopkt; + size_t sz; + unsigned pktSize; + if (NULL_PTR (unlink)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || path == NULL) + return CALL_REAL (unlink)(path); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (unlink)(path); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + sz = collector_strlen (path); + pktSize = sizeof (IOTrace_packet) + sz; + pktSize = collector_align_pktsize (pktSize); + Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize); + packet = collector_interface->allocCSize (io_heap, pktSize, 1); + if (packet != NULL) + { + iopkt = (IOTrace_packet *) packet; + collector_memset (iopkt, 0, pktSize); + iopkt->comm.tsize = pktSize; + iopkt->comm.tstamp = grnt; + iopkt->requested = reqt; + if (ret != -1) + iopkt->iotype = OTHERIO_TRACE; + else + iopkt->iotype = OTHERIO_TRACE_ERROR; + collector_strncpy (&(iopkt->fname), path, sz); + iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt); + collector_interface->freeCSize (io_heap, packet, pktSize); + } + else + { + Tprintf (0, "iotrace: ERROR: unlink cannot allocate memory\n"); + return 0; + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fseek */ +int +fseek (FILE *stream, long offset, int whence) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fseek)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (fseek)(stream, offset, whence); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (fseek)(stream, offset, whence); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- rewind */ +void +rewind (FILE *stream) +{ + int *guard; + IOTrace_packet iopkt; + if (NULL_PTR (rewind)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + { + CALL_REAL (rewind)(stream); + return; + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + CALL_REAL (rewind)(stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + iopkt.iotype = OTHERIO_TRACE; + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); +} + +/*------------------------------------------------------------- ftell */ +long +ftell (FILE *stream) +{ + int *guard; + long ret; + IOTrace_packet iopkt; + if (NULL_PTR (ftell)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + return CALL_REAL (ftell)(stream); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (ftell)(stream); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret != -1) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fileno (stream); + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- fgetpos */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) +static int +__collector_fgetpos_symver (int(real_fgetpos) (), FILE *stream, fpos_t *pos); + +int +__collector_fgetpos_2_2 (FILE *stream, fpos_t *pos) +{ + if (NULL_PTR (fgetpos)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fgetpos_2_2@%p\n", CALL_REAL (fgetpos_2_2)); + return __collector_fgetpos_symver (CALL_REAL (fgetpos_2_2), stream, pos); +} + +int +__collector_fgetpos_2_0 (FILE *stream, fpos_t *pos) +{ + if (NULL_PTR (fgetpos)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fgetpos_2_0@%p\n", CALL_REAL (fgetpos_2_0)); + return __collector_fgetpos_symver (CALL_REAL (fgetpos_2_0), stream, pos); +} + +__asm__(".symver __collector_fgetpos_2_2,fgetpos@@GLIBC_2.2"); +__asm__(".symver __collector_fgetpos_2_0,fgetpos@GLIBC_2.0"); +#endif + +#if ARCH(Intel) && WSIZE(32) + +static int +__collector_fgetpos_symver (int(real_fgetpos) (), FILE *stream, fpos_t *pos) +{ +#else +int +fgetpos (FILE *stream, fpos_t *pos) +{ +#endif + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fgetpos)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_fgetpos) (stream, pos); +#else + return CALL_REAL (fgetpos)(stream, pos); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + ret = (real_fgetpos) (stream, pos); +#else + ret = CALL_REAL (fgetpos)(stream, pos); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fileno (stream); + +#if ARCH(Intel) && WSIZE(32) + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +#if WSIZE(32) +/*------------------------------------------------------------- fgetpos64 */ +#if ARCH(Intel) +// map interposed symbol versions + +static int +__collector_fgetpos64_symver (int(real_fgetpos64) (), FILE *stream, fpos64_t *pos); + +int +__collector_fgetpos64_2_2 (FILE *stream, fpos64_t *pos) +{ + TprintfT (DBG_LTT, "iotrace: __collector_fgetpos64_2_2@%p(stream=%p, pos=%p)\n", + CALL_REAL (fgetpos64_2_2), stream, pos); + if (NULL_PTR (fgetpos64)) + init_io_intf (); + return __collector_fgetpos64_symver (CALL_REAL (fgetpos64_2_2), stream, pos); +} + +int +__collector_fgetpos64_2_1 (FILE *stream, fpos64_t *pos) +{ + TprintfT (DBG_LTT, "iotrace: __collector_fgetpos64_2_1@%p(stream=%p, pos=%p)\n", + CALL_REAL (fgetpos64_2_1), stream, pos); + if (NULL_PTR (fgetpos64)) + init_io_intf (); + return __collector_fgetpos64_symver (CALL_REAL (fgetpos64_2_1), stream, pos); +} + +__asm__(".symver __collector_fgetpos64_2_2,fgetpos64@@GLIBC_2.2"); +__asm__(".symver __collector_fgetpos64_2_1,fgetpos64@GLIBC_2.1"); + +static int +__collector_fgetpos64_symver (int(real_fgetpos64) (), FILE *stream, fpos64_t *pos) +{ +#else +int +fgetpos64 (FILE *stream, fpos64_t *pos) +{ +#endif + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fgetpos64)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + { +#if ARCH(Intel) + return (real_fgetpos64) (stream, pos); +#else + return CALL_REAL (fgetpos64)(stream, pos); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) + ret = (real_fgetpos64) (stream, pos); +#else + ret = CALL_REAL (fgetpos64)(stream, pos); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fileno (stream); +#if ARCH(Intel) + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} +#endif + +/*------------------------------------------------------------- fsetpos */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) +static int +__collector_fsetpos_symver (int(real_fsetpos) (), FILE *stream, const fpos_t *pos); + +int +__collector_fsetpos_2_2 (FILE *stream, const fpos_t *pos) +{ + if (NULL_PTR (fsetpos)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fsetpos_2_2@%p\n", CALL_REAL (fsetpos_2_2)); + return __collector_fsetpos_symver (CALL_REAL (fsetpos_2_2), stream, pos); +} + +int +__collector_fsetpos_2_0 (FILE *stream, const fpos_t *pos) +{ + if (NULL_PTR (fsetpos)) + init_io_intf (); + TprintfT (DBG_LTT, "iotrace: __collector_fsetpos_2_0@%p\n", CALL_REAL (fsetpos_2_0)); + return __collector_fsetpos_symver (CALL_REAL (fsetpos_2_0), stream, pos); +} + +__asm__(".symver __collector_fsetpos_2_2,fsetpos@@GLIBC_2.2"); +__asm__(".symver __collector_fsetpos_2_0,fsetpos@GLIBC_2.0"); +#endif + +#if ARCH(Intel) && WSIZE(32) + +static int +__collector_fsetpos_symver (int(real_fsetpos) (), FILE *stream, const fpos_t *pos) +{ +#else +int +fsetpos (FILE *stream, const fpos_t *pos) +{ +#endif + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fsetpos)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_fsetpos) (stream, pos); +#else + return CALL_REAL (fsetpos)(stream, pos); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + ret = (real_fsetpos) (stream, pos); +#else + ret = CALL_REAL (fsetpos)(stream, pos); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fileno (stream); +#if ARCH(Intel) && WSIZE(32) + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +#if WSIZE(32) +/*------------------------------------------------------------- fsetpos64 */ +#if ARCH(Intel) +// map interposed symbol versions +static int +__collector_fsetpos64_symver (int(real_fsetpos64) (), FILE *stream, const fpos64_t *pos); + +int +__collector_fsetpos64_2_2 (FILE *stream, const fpos64_t *pos) +{ + TprintfT (DBG_LTT, "iotrace: __collector_fsetpos64_2_2@%p(stream=%p, pos=%p)\n", + CALL_REAL (fsetpos64_2_2), stream, pos); + if (NULL_PTR (fsetpos64)) + init_io_intf (); + return __collector_fsetpos64_symver (CALL_REAL (fsetpos64_2_2), stream, pos); +} + +int +__collector_fsetpos64_2_1 (FILE *stream, const fpos64_t *pos) +{ + TprintfT (DBG_LTT, "iotrace: __collector_fsetpos64_2_1@%p(stream=%p, pos=%p)\n", + CALL_REAL (fsetpos64_2_1), stream, pos); + if (NULL_PTR (fsetpos64)) + init_io_intf (); + return __collector_fsetpos64_symver (CALL_REAL (fsetpos64_2_1), stream, pos); +} + +__asm__(".symver __collector_fsetpos64_2_2,fsetpos64@@GLIBC_2.2"); +__asm__(".symver __collector_fsetpos64_2_1,fsetpos64@GLIBC_2.1"); + +static int +__collector_fsetpos64_symver (int(real_fsetpos64) (), FILE *stream, const fpos64_t *pos) +{ +#else +int +fsetpos64 (FILE *stream, const fpos64_t *pos) +{ +#endif + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fsetpos64)) + init_io_intf (); + if (CHCK_REENTRANCE (guard) || stream == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_fsetpos64) (stream, pos); +#else + return CALL_REAL (fsetpos64)(stream, pos); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); +#if ARCH(Intel) && WSIZE(32) + ret = (real_fsetpos64) (stream, pos); +#else + ret = CALL_REAL (fsetpos64)(stream, pos); +#endif + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fileno (stream); +#if ARCH(Intel) + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt); +#else + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); +#endif + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} +#endif + +/*------------------------------------------------------------- fsync */ +int +fsync (int fildes) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (fsync)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (fsync)(fildes); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (fsync)(fildes); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- readdir */ +struct dirent* +readdir (DIR *dirp) +{ + int *guard; + struct dirent *ptr; + IOTrace_packet iopkt; + if (NULL_PTR (readdir)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (readdir)(dirp); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ptr = CALL_REAL (readdir)(dirp); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ptr; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof ( IOTrace_packet)); + iopkt.comm.tsize = sizeof ( IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ptr != NULL) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ptr; +} + +/*------------------------------------------------------------- flock */ +int +flock (int fd, int operation) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (flock)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (flock)(fd, operation); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (flock)(fd, operation); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fd; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- lockf */ +int +lockf (int fildes, int function, off_t size) +{ + int *guard; + int ret; + IOTrace_packet iopkt; + if (NULL_PTR (lockf)) + init_io_intf (); + if (CHCK_REENTRANCE (guard)) + return CALL_REAL (lockf)(fildes, function, size); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + ret = CALL_REAL (lockf)(fildes, function, size); + if (RECHCK_REENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + collector_memset (&iopkt, 0, sizeof (IOTrace_packet)); + iopkt.comm.tsize = sizeof (IOTrace_packet); + iopkt.comm.tstamp = grnt; + iopkt.requested = reqt; + if (ret == 0) + iopkt.iotype = OTHERIO_TRACE; + else + iopkt.iotype = OTHERIO_TRACE_ERROR; + iopkt.fd = fildes; + iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt); + collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt); + POP_REENTRANCE (guard); + return ret; +} diff --git a/gprofng/libcollector/jprofile.c b/gprofng/libcollector/jprofile.c new file mode 100644 index 0000000..9daaa5a --- /dev/null +++ b/gprofng/libcollector/jprofile.c @@ -0,0 +1,1315 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" + +#if defined(GPROFNG_JAVA_PROFILING) +#include <alloca.h> +#include <dlfcn.h> /* dlsym() */ +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/param.h> /* MAXPATHLEN */ + +#include <jni.h> +#include <jvmti.h> + +#include "gp-defs.h" +#include "collector.h" +#include "gp-experiment.h" +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* ARCH_STRLEN is defined in dbe, copied here */ +#define ARCH_STRLEN(s) ((CALL_UTIL(strlen)(s) + 4 ) & ~0x3) + +/* call frame */ +typedef struct +{ + jint lineno; /* line number in the source file */ + jmethodID method_id; /* method executed in this frame */ +} JVMPI_CallFrame; + +/* call trace */ +typedef struct +{ + JNIEnv *env_id; /* Env where trace was recorded */ + jint num_frames; /* number of frames in this trace */ + JVMPI_CallFrame *frames; /* frames */ +} JVMPI_CallTrace; + +extern void __collector_jprofile_enable_synctrace (void); +int __collector_jprofile_start_attach (void); +static int init_interface (CollectorInterface*); +static int open_experiment (const char *); +static int close_experiment (void); +static int detach_experiment (void); +static void jprof_find_asyncgetcalltrace (void); +static char *apistr = NULL; + +static ModuleInterface module_interface = { + "*"SP_JCLASSES_FILE, /* description, exempt from limit */ + init_interface, /* initInterface */ + open_experiment, /* openExperiment */ + NULL, /* startDataCollection */ + NULL, /* stopDataCollection */ + close_experiment, /* closeExperiment */ + detach_experiment /* detachExperiment (fork child) */ +}; + +static CollectorInterface *collector_interface = NULL; +static CollectorModule jprof_hndl = COLLECTOR_MODULE_ERR; +static int __collector_java_attach = 0; +static JavaVM *jvm; +static jmethodID getResource = NULL; +static jmethodID toExternalForm = NULL; + +/* Java profiling thread specific data */ +typedef struct TSD_Entry +{ + JNIEnv *env; + hrtime_t tstamp; +} TSD_Entry; + +static unsigned tsd_key = COLLECTOR_TSD_INVALID_KEY; +static collector_mutex_t jclasses_lock = COLLECTOR_MUTEX_INITIALIZER; +static int java_gc_on = 0; +static int java_mem_mode = 0; +static int java_sync_mode = 0; +static int is_hotspot_vm = 0; +static void get_jvm_settings (); +static void rwrite (int fd, const void *buf, size_t nbyte); +static void addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len); +static void (*AsyncGetCallTrace)(JVMPI_CallTrace*, jint, ucontext_t*) = NULL; +static void (*collector_heap_record)(int, int, void*) = NULL; +static void (*collector_jsync_begin)() = NULL; +static void (*collector_jsync_end)(hrtime_t, void *) = NULL; + +#define gethrtime collector_interface->getHiResTime + +/* + * JVMTI declarations + */ + +static jvmtiEnv *jvmti; +static void jvmti_VMInit (jvmtiEnv*, JNIEnv*, jthread); +static void jvmti_VMDeath (jvmtiEnv*, JNIEnv*); +static void jvmti_ThreadStart (jvmtiEnv*, JNIEnv*, jthread); +static void jvmti_ThreadEnd (jvmtiEnv*, JNIEnv*, jthread); +static void jvmti_CompiledMethodLoad (jvmtiEnv*, jmethodID, jint, const void*, + jint, const jvmtiAddrLocationMap*, const void*); +static void jvmti_CompiledMethodUnload (jvmtiEnv*, jmethodID, const void*); +static void jvmti_DynamicCodeGenerated (jvmtiEnv*, const char*, const void*, jint); +static void jvmti_ClassPrepare (jvmtiEnv*, JNIEnv*, jthread, jclass); +static void jvmti_ClassLoad (jvmtiEnv*, JNIEnv*, jthread, jclass); +//static void jvmti_ClassUnload( jvmtiEnv*, JNIEnv*, jthread, jclass ); +static void jvmti_MonitorEnter (jvmtiEnv *, JNIEnv*, jthread, jobject); +static void jvmti_MonitorEntered (jvmtiEnv *, JNIEnv*, jthread, jobject); +#if 0 +static void jvmti_MonitorWait (jvmtiEnv *, JNIEnv*, jthread, jobject, jlong); +static void jvmti_MonitorWaited (jvmtiEnv *, JNIEnv*, jthread, jobject, jboolean); +#endif +static void jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined, + jobject loader, const char* name, jobject protection_domain, + jint class_data_len, const unsigned char* class_data, + jint* new_class_data_len, unsigned char** new_class_data); +static void jvmti_GarbageCollectionStart (jvmtiEnv *); +static void +jvmti_GarbageCollectionFinish (jvmtiEnv *); +jvmtiEventCallbacks callbacks = { + jvmti_VMInit, // 50 jvmtiEventVMInit; + jvmti_VMDeath, // 51 jvmtiEventVMDeath; + jvmti_ThreadStart, // 52 jvmtiEventThreadStart; + jvmti_ThreadEnd, // 53 jvmtiEventThreadEnd; + jvmti_ClassFileLoadHook, // 54 jvmtiEventClassFileLoadHook; + jvmti_ClassLoad, // 55 jvmtiEventClassLoad; + jvmti_ClassPrepare, // 56 jvmtiEventClassPrepare; + NULL, // 57 reserved57; + NULL, // 58 jvmtiEventException; + NULL, // 59 jvmtiEventExceptionCatch; + NULL, // 60 jvmtiEventSingleStep; + NULL, // 61 jvmtiEventFramePop; + NULL, // 62 jvmtiEventBreakpoint; + NULL, // 63 jvmtiEventFieldAccess; + NULL, // 64 jvmtiEventFieldModification; + NULL, // 65 jvmtiEventMethodEntry; + NULL, // 66 jvmtiEventMethodExit; + NULL, // 67 jvmtiEventNativeMethodBind; + jvmti_CompiledMethodLoad, // 68 jvmtiEventCompiledMethodLoad; + jvmti_CompiledMethodUnload, // 69 jvmtiEventCompiledMethodUnload; + jvmti_DynamicCodeGenerated, // 70 jvmtiEventDynamicCodeGenerated; + NULL, // 71 jvmtiEventDataDumpRequest; + NULL, // 72 jvmtiEventDataResetRequest; + NULL, /*jvmti_MonitorWait,*/ // 73 jvmtiEventMonitorWait; + NULL, /*jvmti_MonitorWaited,*/ // 74 jvmtiEventMonitorWaited; + jvmti_MonitorEnter, // 75 jvmtiEventMonitorContendedEnter; + jvmti_MonitorEntered, // 76 jvmtiEventMonitorContendedEntered; + NULL, // 77 jvmtiEventMonitorContendedExit; + NULL, // 78 jvmtiEventReserved; + NULL, // 79 jvmtiEventReserved; + NULL, // 80 jvmtiEventReserved; + jvmti_GarbageCollectionStart, // 81 jvmtiEventGarbageCollectionStart; + jvmti_GarbageCollectionFinish, // 82 jvmtiEventGarbageCollectionFinish; + NULL, // 83 jvmtiEventObjectFree; + NULL // 84 jvmtiEventVMObjectAlloc; +}; + +typedef jint (JNICALL JNI_GetCreatedJavaVMs_t)(JavaVM **, jsize, jsize *); + +int +init_interface (CollectorInterface *_collector_interface) +{ + collector_interface = _collector_interface; + return COL_ERROR_NONE; +} + +static int +open_experiment (const char *exp) +{ + if (collector_interface == NULL) + return COL_ERROR_JAVAINIT; + TprintfT (0, "jprofile: open_experiment %s\n", exp); + const char *params = collector_interface->getParams (); + const char *args = params; + while (args) + { + if (__collector_strStartWith (args, "j:") == 0) + { + args += 2; + break; + } + args = CALL_UTIL (strchr)(args, ';'); + if (args) + args++; + } + if (args == NULL) /* Java profiling not specified */ + return COL_ERROR_JAVAINIT; + tsd_key = collector_interface->createKey (sizeof ( TSD_Entry), NULL, NULL); + if (tsd_key == (unsigned) - 1) + { + TprintfT (0, "jprofile: TSD key create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_JAVAINIT); + return COL_ERROR_JAVAINIT; + } + else + Tprintf (DBG_LT2, "jprofile: TSD key create succeeded %d.\n", tsd_key); + + args = params; + while (args) + { + if (__collector_strStartWith (args, "H:") == 0) + { + java_mem_mode = 1; + collector_heap_record = (void(*)(int, int, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record"); + } +#if 0 + else if (__collector_strStartWith (args, "s:") == 0) + { + java_sync_mode = 1; + collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin"); + collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end"); + } +#endif + args = CALL_UTIL (strchr)(args, ';'); + if (args) + args++; + } + + /* synchronization tracing is enabled by the synctrace module, later in initialization */ + __collector_java_mode = 1; + java_gc_on = 1; + return COL_ERROR_NONE; +} + +/* routine called from the syntrace module to enable Java-API synctrace */ +void +__collector_jprofile_enable_synctrace () +{ + if (__collector_java_mode == 0) + { + TprintfT (DBG_LT1, "jprofile: not turning on Java synctrace; Java mode not enabled\n"); + return; + } + java_sync_mode = 1; + collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin"); + collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end"); + TprintfT (DBG_LT1, "jprofile: turning on Java synctrace, and requesting events\n"); +} + +int +__collector_jprofile_start_attach (void) +{ + if (!__collector_java_mode || __collector_java_asyncgetcalltrace_loaded) + return 0; + void *g_sHandle = RTLD_DEFAULT; + /* Now get the function addresses */ + JNI_GetCreatedJavaVMs_t *pfnGetCreatedJavaVMs; + pfnGetCreatedJavaVMs = (JNI_GetCreatedJavaVMs_t *) dlsym (g_sHandle, "JNI_GetCreatedJavaVMs"); + if (pfnGetCreatedJavaVMs != NULL) + { + TprintfT (0, "jprofile attach: pfnGetCreatedJavaVMs is detected.\n"); + JavaVM * vmBuf[1]; // XXXX only detect on jvm + jsize nVMs = 0; + (*pfnGetCreatedJavaVMs)(vmBuf, 1, &nVMs); + if (vmBuf[0] != NULL && nVMs > 0) + { + jvm = vmBuf[0]; + JNIEnv* jni_env = NULL; + (*jvm)->AttachCurrentThread (jvm, (void **) &jni_env, NULL); + Agent_OnLoad (jvm, NULL, NULL); + if ((*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2) >= 0 && jni_env && jvmti) + { + jthread thread; + (*jvmti)->GetCurrentThread (jvmti, &thread); +#ifdef DEBUG + collector_thread_t tid; + tid = __collector_thr_self (); + TprintfT (0, "jprofile attach: AttachCurrentThread: thread: %lu jni_env=%p jthread=%p\n", + (unsigned long) tid, jni_env, thread); +#endif /* DEBUG */ + jvmti_VMInit (jvmti, jni_env, thread); + (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD); + (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED); + __collector_java_attach = 1; + (*jvm)->DetachCurrentThread (jvm); + } + } + } + return 0; +} + +static int +close_experiment (void) +{ + /* fixme XXXXX add content here */ + /* see detach_experiment() */ + __collector_java_mode = 0; + __collector_java_asyncgetcalltrace_loaded = 0; + __collector_java_attach = 0; + java_gc_on = 0; + java_mem_mode = 0; + java_sync_mode = 0; + is_hotspot_vm = 0; + __collector_mutex_init (&jclasses_lock); + tsd_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (0, "jprofile: experiment closed.\n"); + return 0; +} + +static int +detach_experiment (void) +/* fork child. Clean up state but don't write to experiment */ +{ + __collector_java_mode = 0; + java_gc_on = 0; + jvm = NULL; + java_mem_mode = 0; + java_sync_mode = 0; + is_hotspot_vm = 0; + jvmti = NULL; + apistr = NULL; + __collector_mutex_init (&jclasses_lock); + tsd_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (0, "jprofile: detached from experiment.\n"); + return 0; +} + +JNIEXPORT jint JNICALL +JVM_OnLoad (JavaVM *vm, char *options, void *reserved) +{ + jvmtiError err; + int use_jvmti = 0; + if (!__collector_java_mode) + { + TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked with java mode disabled\n"); + return JNI_OK; + } + else + TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked\n"); + jvm = vm; + jvmti = NULL; + if ((*jvm)->GetEnv (jvm, (void **) &jvmti, JVMTI_VERSION_1_0) >= 0 && jvmti) + { + TprintfT (DBG_LT1, "jprofile: JVMTI found\n"); + use_jvmti = 1; + } + if (!use_jvmti) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n", + SP_JCMD_CERROR, COL_ERROR_JVMNOTSUPP); + return JNI_ERR; + } + else + { + Tprintf (DBG_LT0, "\tjprofile: Initializing for JVMTI\n"); + apistr = "JVMTI 1.0"; + + // setup JVMTI + jvmtiCapabilities cpblts; + err = (*jvmti)->GetPotentialCapabilities (jvmti, &cpblts); + if (err == JVMTI_ERROR_NONE) + { + jvmtiCapabilities cpblts_set; + CALL_UTIL (memset)(&cpblts_set, 0, sizeof (cpblts_set)); + + /* Add only those capabilities that are among potential ones */ + cpblts_set.can_get_source_file_name = cpblts.can_get_source_file_name; + Tprintf (DBG_LT1, "\tjprofile: adding can_get_source_file_name capability: %u\n", cpblts.can_get_source_file_name); + + cpblts_set.can_generate_compiled_method_load_events = cpblts.can_generate_compiled_method_load_events; + Tprintf (DBG_LT1, "\tjprofile: adding can_generate_compiled_method_load_events capability: %u\n", cpblts.can_generate_compiled_method_load_events); + + if (java_sync_mode) + { + cpblts_set.can_generate_monitor_events = cpblts.can_generate_monitor_events; + Tprintf (DBG_LT1, "\tjprofile: adding can_generate_monitor_events capability: %u\n", cpblts.can_generate_monitor_events); + } + if (java_gc_on) + { + cpblts_set.can_generate_garbage_collection_events = cpblts.can_generate_garbage_collection_events; + Tprintf (DBG_LT1, "\tjprofile: adding can_generate_garbage_collection_events capability: %u\n", cpblts.can_generate_garbage_collection_events); + } + err = (*jvmti)->AddCapabilities (jvmti, &cpblts_set); + Tprintf (DBG_LT1, "\tjprofile: AddCapabilities() returns: %d\n", err); + } + err = (*jvmti)->SetEventCallbacks (jvmti, &callbacks, sizeof ( callbacks)); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); + if (java_gc_on) + { + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL); + } + if (java_mem_mode) + { + // err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, <no event for heap tracing> , NULL ); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n", + SP_JCMD_CWARN, COL_WARN_NO_JAVA_HEAP); + java_mem_mode = 0; + } + if (java_sync_mode) + { + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL); + err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL); + //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL ); + //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL ); + } + Tprintf (DBG_LT0, "\tjprofile: JVMTI initialized\n"); + } + + /* JVM still uses collector API on Solaris to notify us about dynamically generated code. + * If we ask it to generate events we'll end up with duplicate entries in the + * map file. + */ + if (use_jvmti) + { + err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED); + err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD); + } + Tprintf (DBG_LT1, "\tjprofile: JVM_OnLoad ok\n"); + return JNI_OK; +} + +/* This is currently just a placeholder */ +JNIEXPORT jint JNICALL +Agent_OnLoad (JavaVM *vm, char *options, void *reserved) +{ + return JVM_OnLoad (vm, options, reserved); +} + +static void +rwrite (int fd, const void *buf, size_t nbyte) +{ + size_t left = nbyte; + size_t res; + char *ptr = (char*) buf; + while (left > 0) + { + res = CALL_UTIL (write)(fd, ptr, left); + if (res == -1) + { + /* XXX: we can't write this record, we probably + * can't write anything else. Ignore. + */ + return; + } + left -= res; + ptr += res; + } +} + +void +get_jvm_settings () +{ + jint res; + JNIEnv *jni; + jclass jcls; + jmethodID jmid; + jstring jstrin; + jstring jstrout; + const char *str; + res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2); + if (res < 0) + return; + + /* I'm not checking if results are valid as JVM is extremely + * sensitive to exceptions that might occur during these JNI calls + * and will die with a fatal error later anyway. + */ + jcls = (*jni)->FindClass (jni, "java/lang/System"); + jmid = (*jni)->GetStaticMethodID (jni, jcls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); + jstrin = (*jni)->NewStringUTF (jni, "java.class.path"); + jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin); + str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL; + if (str) + { + collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str); + (*jni)->ReleaseStringUTFChars (jni, jstrout, str); + } + jstrin = (*jni)->NewStringUTF (jni, "sun.boot.class.path"); + jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin); + str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL; + if (str) + { + collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str); + (*jni)->ReleaseStringUTFChars (jni, jstrout, str); + } + jstrin = (*jni)->NewStringUTF (jni, "java.home"); + jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin); + str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL; + if (str) + { + collector_interface->writeLog ("<setting %s=\"%s/../src.zip\"/>\n", SP_JCMD_SRCHPATH, str); + (*jni)->ReleaseStringUTFChars (jni, jstrout, str); + } + jstrin = (*jni)->NewStringUTF (jni, "java.vm.version"); + jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin); + str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL; + if (str) + { + (void) collector_interface->writeLog ("<profile name=\"jprofile\" %s=\"%s\" %s=\"%s\"/>\n", + SP_JCMD_JVERSION, str, "api", apistr != NULL ? apistr : "N/A"); + if (__collector_strStartWith (str, "1.4.2_02") < 0) + { + (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n", + SP_JCMD_CWARN, COL_WARN_OLDJAVA); + } + (*jni)->ReleaseStringUTFChars (jni, jstrout, str); + } + is_hotspot_vm = 0; + jstrin = (*jni)->NewStringUTF (jni, "sun.management.compiler"); + jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin); + str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL; + if (str && __collector_strncmp (str, "HotSpot", 7) == 0) + is_hotspot_vm = 1; + + /* Emulate System.setProperty( "collector.init", "true") */ + jmid = (*jni)->GetStaticMethodID (jni, jcls, "setProperty", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); + jstrin = (*jni)->NewStringUTF (jni, "collector.init"); + jstrout = (*jni)->NewStringUTF (jni, "true"); + (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin, jstrout); +} + +/* + * JVMTI code + */ + +static void +jvmti_VMInit (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread) +{ + jint class_count = 0; + jclass *classes = NULL; + int i; + TprintfT (DBG_LT1, "jprofile: jvmti_VMInit called\n"); + get_jvm_settings (); + + /* determine loaded classes */ + (*jvmti_env)->GetLoadedClasses (jvmti_env, &class_count, &classes); + TprintfT (DBG_LT1, "jprofile: jvmti_VMInit initializing %d classes\n", class_count); + for (i = 0; i < class_count; i++) + { + // PushLocalFrame + jvmti_ClassPrepare (jvmti_env, jni_env, NULL, classes[i]); + // PopLocalFrame + // DeleteLocalRef( classes[i] ); + } + (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) classes); + getResource = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/lang/ClassLoader"), "getResource", "(Ljava/lang/String;)Ljava/net/URL;"); + toExternalForm = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/net/URL"), "toExternalForm", "()Ljava/lang/String;"); + + /* find the stack unwind routine */ + jprof_find_asyncgetcalltrace (); +} + +static void +jvmti_VMDeath (jvmtiEnv *jvmti_env, JNIEnv* jni_env) +{ + __collector_java_mode = 0; + TprintfT (DBG_LT1, "jprofile: jvmti_VMDeath event received\n"); +} + +static void +jvmti_ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread) +{ + jvmtiError err; + jvmtiThreadInfo t_info; + char *thread_name, *group_name, *parent_name; + hrtime_t hrt; + collector_thread_t tid; + thread_name = group_name = parent_name = NULL; + hrt = gethrtime (); + tid = __collector_thr_self (); + TprintfT (DBG_LT1, "jprofile: jvmti_ThreadStart: thread: %lu jni_env=%p jthread=%p\n", + (unsigned long) tid, jni_env, thread); + err = (*jvmti_env)->GetThreadInfo (jvmti_env, thread, &t_info); + if (err == JVMTI_ERROR_NONE) + { + jvmtiThreadGroupInfo g_info; + thread_name = t_info.name; + if (t_info.thread_group) + { + err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, t_info.thread_group, &g_info); + if (err == JVMTI_ERROR_NONE) + { + group_name = g_info.name; + if (g_info.parent) + { + jvmtiThreadGroupInfo p_info; + err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, g_info.parent, &p_info); + if (err == JVMTI_ERROR_NONE) + { + parent_name = p_info.name; + // DeleteLocalRef( p_info.parent ); + } + // DeleteLocalRef( g_info.parent ); + } + } + } + // DeleteLocalRef( t_info.thread_group ); + // DeleteLocalRef( t_info.context_class_loader ); + } + if (thread_name == NULL) + thread_name = ""; + if (group_name == NULL) + group_name = ""; + if (parent_name == NULL) + parent_name = ""; + collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" name=\"%s\" grpname=\"%s\" prntname=\"%s\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n", + SP_JCMD_JTHRSTART, + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), + thread_name, + group_name, + parent_name, + (unsigned long) tid, + thread, + jni_env + ); + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd) + tsd->env = jni_env; +} + +static void +jvmti_ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread) +{ + hrtime_t hrt = gethrtime (); + collector_thread_t tid = __collector_thr_self (); + TprintfT (DBG_LT1, "jprofile: jvmti_ThreadEnd: thread: %lu jni_env=%p jthread=%p\n", + (unsigned long) tid, jni_env, thread); + + collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n", + SP_JCMD_JTHREND, + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), + (unsigned long) tid, + thread, + jni_env + ); + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd) + tsd->env = NULL; +} + +/* The following definitions are borrowed from file jvmticmlr.h, part of jdk7 */ +typedef enum +{ + JVMTI_CMLR_DUMMY = 1, + JVMTI_CMLR_INLINE_INFO = 2 +} jvmtiCMLRKind; + +/* + * Record that represents arbitrary information passed through JVMTI + * CompiledMethodLoadEvent void pointer. + */ +typedef struct _jvmtiCompiledMethodLoadRecordHeader +{ + jvmtiCMLRKind kind; /* id for the kind of info passed in the record */ + jint majorinfoversion; /* major and minor info version values. Init'ed */ + jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */ + struct _jvmtiCompiledMethodLoadRecordHeader* next; +} jvmtiCompiledMethodLoadRecordHeader; + +/* + * Record that gives information about the methods on the compile-time + * stack at a specific pc address of a compiled method. Each element in + * the methods array maps to same element in the bcis array. + */ +typedef struct _PCStackInfo +{ + void* pc; /* the pc address for this compiled method */ + jint numstackframes; /* number of methods on the stack */ + jmethodID* methods; /* array of numstackframes method ids */ + jint* bcis; /* array of numstackframes bytecode indices */ +} PCStackInfo; + +/* + * Record that contains inlining information for each pc address of + * an nmethod. + */ +typedef struct _jvmtiCompiledMethodLoadInlineRecord +{ + jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */ + jint numpcs; /* number of pc descriptors in this nmethod */ + PCStackInfo* pcinfo; /* array of numpcs pc descriptors */ +} jvmtiCompiledMethodLoadInlineRecord; + +static void +jvmti_CompiledMethodLoad (jvmtiEnv *jvmti_env, jmethodID method, + jint code_size, const void *code_addr, jint map_length, + const jvmtiAddrLocationMap *map, + const void *compile_info) +{ + TprintfT (DBG_LT2, "jprofile: jvmti_CompiledMethodLoad: mid=0x%lx addr=%p sz=0x%lu map=%p info=%p\n", + (unsigned long) method, code_addr, (long) code_size, map, compile_info); + char name[32]; + CALL_UTIL (snprintf)(name, sizeof (name), "0x%lx", (unsigned long) method); + + /* Parse compile_info to get pc -> bci mapping. + * Don't interpret compile_info from JVMs other than HotSpot. + */ + int lntsize = 0; + DT_lineno *lntable = NULL; + if (compile_info != NULL && is_hotspot_vm) + { + Tprintf (DBG_LT2, "Mapping from compile_info:\n"); + jvmtiCompiledMethodLoadRecordHeader *currec = + (jvmtiCompiledMethodLoadRecordHeader*) compile_info; + while (currec != NULL) + { + if (currec->kind == JVMTI_CMLR_INLINE_INFO) + { + jvmtiCompiledMethodLoadInlineRecord *inrec = + (jvmtiCompiledMethodLoadInlineRecord*) currec; + if (inrec->numpcs <= 0) + break; + lntsize = inrec->numpcs; + lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno)); + PCStackInfo *pcrec = inrec->pcinfo; + DT_lineno *lnorec = lntable; + for (int i = 0; i < lntsize; ++i) + { + for (int j = pcrec->numstackframes - 1; j >= 0; --j) + if (pcrec->methods[j] == method) + { + lnorec->offset = (char*) pcrec->pc - (char*) code_addr; + lnorec->lineno = pcrec->bcis[j]; + Tprintf (DBG_LT2, " pc: 0x%lx bci: 0x%lx\n", + (long) lnorec->offset, (long) lnorec->lineno); + ++lnorec; + break; + } + ++pcrec; + } + break; + } + currec = currec->next; + } + } + else if (map != NULL) + { + Tprintf (DBG_LT2, "Mapping from jvmtiAddrLocationMap:\n"); + lntsize = map_length; + lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno)); + DT_lineno *lnorec = lntable; + for (int i = 0; i < map_length; ++i) + { + lnorec->offset = (char*) map[i].start_address - (char*) code_addr; + lnorec->lineno = (unsigned int) map[i].location; + Tprintf (DBG_LT2, " pc: 0x%lx bci: 0x%lx\n", + (long) lnorec->offset, (long) lnorec->lineno); + ++lnorec; + } + } + __collector_int_func_load (DFUNC_JAVA, name, NULL, (void*) code_addr, + code_size, lntsize, lntable); +} + +static void +jvmti_CompiledMethodUnload (jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr) +{ + __collector_int_func_unload (DFUNC_API, (void*) code_addr); +} + +static void +jvmti_DynamicCodeGenerated (jvmtiEnv *jvmti_env, const char*name, const void *code_addr, jint code_size) +{ + __collector_int_func_load (DFUNC_API, (char*) name, NULL, (void*) code_addr, + code_size, 0, NULL); +} + +static void +addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len) +{ + char path[MAXPATHLEN + 1]; + mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + mode_t dmode = fmode | S_IXUSR | S_IXGRP | S_IXOTH; + if (name == NULL) + name = ""; + const char *expdir = collector_interface->getExpDir (); + if (CALL_UTIL (strlen)(expdir) + + CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES) + + CALL_UTIL (strlen)(name) + 8 > sizeof (path)) + return; + CALL_UTIL (snprintf)(path, sizeof (path), "%s/%s/%s.class", expdir, SP_DYNAMIC_CLASSES, name); + + /* Create all path components step by step starting with SP_DYNAMIC_CLASSES */ + char *str = path + CALL_UTIL (strlen)(expdir) + 1 + CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES); + while (str) + { + *str = '\0'; + if (CALL_UTIL (mkdir)(path, dmode) != 0) + { + /* Checking for EEXIST is not enough, access() is more reliable */ + if (CALL_UTIL (access)(path, F_OK) != 0) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_MKDIR, errno, path); + return; + } + } + *str++ = '/'; + str = CALL_UTIL (strchr)(str, '/'); + } + + int fd = CALL_UTIL (open)(path, O_WRONLY | O_CREAT | O_TRUNC, fmode); + if (fd < 0) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, path); + return; + } + rwrite (fd, class_data, class_data_len); + CALL_UTIL (close)(fd); +} + +static void +jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined, + jobject loader, const char* name, jobject protection_domain, jint class_data_len, + const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data) +{ + jclass loaderlass; + int err; + jvmtiPhase phase_ptr; + char *cname = NULL; + (*jvmti_env)->GetPhase (jvmti_env, &phase_ptr); + + /* skip non live phases */ + if (phase_ptr != JVMTI_PHASE_LIVE) + return; + + /* skip system class loaders */ + if (!loader) + return; + loaderlass = (*jni_env)->GetObjectClass (jni_env, loader); + err = (*jvmti_env)->GetClassSignature (jvmti_env, loaderlass, &cname, NULL); + if (err != JVMTI_ERROR_NONE || !cname || *cname == (char) 0) + return; + + /* skip classes loaded with AppClassLoader (java.class.path) */ + if (__collector_strcmp (cname, "Lsun/misc/Launcher$AppClassLoader;") == 0) + return; + addToDynamicArchive (name, class_data, (int) class_data_len); +} + +#define NO_CLASS_NAME "<noname>" +#define NO_SOURCE_FILE "<Unknown>" + +static void +record_jclass (uint64_t class_id, hrtime_t hrt, const char *cname, const char *sname) +{ + size_t clen = ARCH_STRLEN (cname); + size_t slen = ARCH_STRLEN (sname); + size_t sz = sizeof (ARCH_jclass) + clen + slen; + ARCH_jclass *jcls = (ARCH_jclass*) alloca (sz); + jcls->comm.tsize = sz; + jcls->comm.type = ARCH_JCLASS; + jcls->class_id = class_id; + jcls->tstamp = hrt; + char *str = (char*) (jcls + 1); + size_t i = CALL_UTIL (strlcpy)(str, cname, clen); + str += i; + while (i++ < clen) + *str++ = (char) 0; /* pad with 0's */ + i = CALL_UTIL (strlcpy)(str, sname, slen); + str += i; + while (i++ < slen) + *str++ = (char) 0; /* pad with 0's */ + collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls); +} + +static void +record_jmethod (uint64_t class_id, uint64_t method_id, + const char *mname, const char *msign) +{ + size_t mnlen = mname ? ARCH_STRLEN (mname) : 0; + size_t mslen = msign ? ARCH_STRLEN (msign) : 0; + size_t sz = sizeof (ARCH_jmethod) + mnlen + mslen; + ARCH_jmethod *jmth = (ARCH_jmethod*) alloca (sz); + if (jmth == NULL) + { + TprintfT (DBG_LT1, "jprofile: record_jmethod ERROR: failed to alloca(%ld)\n", (long) sz); + return; + } + jmth->comm.tsize = sz; + jmth->comm.type = ARCH_JMETHOD; + jmth->class_id = class_id; + jmth->method_id = method_id; + char *str = (char*) (jmth + 1); + if (mname) + { + size_t i = CALL_UTIL (strlcpy)(str, mname, mnlen); + str += i; + while (i++ < mnlen) + *str++ = (char) 0; /* pad with 0's */ + } + if (msign) + { + size_t i = CALL_UTIL (strlcpy)(str, msign, mslen); + str += i; + while (i++ < mslen) + *str++ = (char) 0; /* pad with 0's */ + } + collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jmth); +} + +static void +jvmti_ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env, + jthread thread, jclass klass) +{ + hrtime_t hrt; + jint mnum; + jmethodID *mptr; + char *cname, *sname; + char *str1 = NULL; + int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL); + if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0) + cname = NO_CLASS_NAME; + else + cname = str1; + if (*cname != 'L') + { + DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: GetClassSignature failed. err=%d cname=%s\n", err, cname); + return; + } + char *str2 = NULL; + err = (*jvmti_env)->GetSourceFileName (jvmti_env, klass, &str2); + if (err != JVMTI_ERROR_NONE || str2 == NULL || *str2 == (char) 0) + sname = NO_SOURCE_FILE; + else + sname = str2; + DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: cname=%s sname=%s\n", STR (cname), STR (sname)); + + /* Lock the whole file */ + __collector_mutex_lock (&jclasses_lock); + hrt = gethrtime (); + record_jclass ((unsigned long) klass, hrt, cname, sname); + (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str1); + (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str2); + err = (*jvmti_env)->GetClassMethods (jvmti_env, klass, &mnum, &mptr); + if (err == JVMTI_ERROR_NONE) + { + for (int i = 0; i < mnum; i++) + { + char *mname, *msign; + err = (*jvmti_env)->GetMethodName (jvmti_env, mptr[i], &mname, &msign, NULL); + if (err != JVMTI_ERROR_NONE) + continue; + record_jmethod ((unsigned long) klass, (unsigned long) mptr[i], mname, msign); + // DeleteLocalRef( mptr[i] ); + } + (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) mptr); + } + /* Unlock the file */ + __collector_mutex_unlock (&jclasses_lock); +} + +/* + * The CLASS_LOAD event is enabled to enable AsyncGetCallTrace + */ +static void +jvmti_ClassLoad (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass) +{ + char *cname; + char *str1 = NULL; + int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL); + if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0) + cname = NO_CLASS_NAME; + else + cname = str1; + jstring str = NULL; + const char* resourceName; + jobject classLoader = NULL; + err = (*jvmti)->GetClassLoader (jvmti, klass, &classLoader); + DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jprofile: jvmti_ClassLoad err=%d cname=%s\n", err, STR (cname)); + if (err == 0) + { + if (classLoader == NULL) + { + // bootstrap class loader + resourceName = ""; + } + else + { + char* name = (char *) alloca ((CALL_UTIL (strlen)(str1) + 32) * sizeof (char)); + CALL_UTIL (strlcpy)(name, str1 + 1, CALL_UTIL (strlen)(str1)); + name[CALL_UTIL (strlen)(name) - 1] = '\0'; // remove the last ';' + char* p; + for (p = name; *p != '\0'; p++) + if (*p == '.') + *p = '/'; + CALL_UTIL (strlcat)(name, ".class", CALL_UTIL (strlen)(name) + CALL_UTIL (strlen)(".class") + 1); + if (getResource == NULL || toExternalForm == NULL) + { + resourceName = ""; + DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path with method missing\n", STR (cname)); + } + else + { + jobject url = (*jni_env)->CallObjectMethod (jni_env, classLoader, getResource, (*jni_env)->NewStringUTF (jni_env, name)); + if (url == NULL) + { + resourceName = ""; + DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path\n", STR (cname)); + } + else + { + str = (jstring) (*jni_env)->CallObjectMethod (jni_env, url, toExternalForm); + resourceName = (*jni_env)->GetStringUTFChars (jni_env, str, NULL); + DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: ARCH_JCLASS_LOCATION(Ox%x) class_id=0x%lx className='%s' fileName '%s'\n", + (int) ARCH_JCLASS_LOCATION, (unsigned long) klass, STR (cname), STR (resourceName)); + size_t clen = ARCH_STRLEN (cname); + size_t slen = ARCH_STRLEN (resourceName); + size_t sz = sizeof (ARCH_jclass) + clen + slen; + ARCH_jclass_location *jcls = (ARCH_jclass_location*) alloca (sz); + jcls->comm.tsize = sz; + jcls->comm.type = ARCH_JCLASS_LOCATION; + jcls->class_id = (unsigned long) klass; + char *str = (char*) (jcls + 1); + size_t i = CALL_UTIL (strlcpy)(str, cname, clen); + str += i; + while (i++ < clen) + { + *str++ = (char) 0; /* pad with 0's */ + } + i = CALL_UTIL (strlcpy)(str, resourceName, slen); + str += i; + while (i++ < slen) + { + *str++ = (char) 0; /* pad with 0's */ + } + /* Lock the whole file */ + __collector_mutex_lock (&jclasses_lock); + collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls); + /* Unlock the file */ + __collector_mutex_unlock (&jclasses_lock); + } + } + } + } +} + +static void +jvmti_MonitorEnter (jvmtiEnv *jvmti_env, JNIEnv* jni_env, + jthread thread, jobject object) +{ + if (collector_jsync_begin) + collector_jsync_begin (); + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd == NULL) + return; + tsd->tstamp = gethrtime (); +} + +static void +jvmti_MonitorEntered (jvmtiEnv *jvmti_env, JNIEnv* jni_env, + jthread thread, jobject object) +{ + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd == NULL) + return; + if (collector_jsync_end) + collector_jsync_end (tsd->tstamp, object); +} + +static void +jvmti_GarbageCollectionStart (jvmtiEnv *jvmti_env) +{ + hrtime_t hrt = gethrtime (); + collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n", + SP_JCMD_GCSTART, + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC) + ); + TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionStart.\n"); +} + +static void +jvmti_GarbageCollectionFinish (jvmtiEnv *jvmti_env) +{ + hrtime_t hrt = gethrtime (); + collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n", + SP_JCMD_GCEND, + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC) + ); + TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionFinish.\n"); +} + +#if 0 +static void +jvmti_MonitorWait (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, + jobject object, jlong timed_out) +{ + if (collector_sync_begin) + collector_sync_begin (); + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd == NULL) + return; + tsd->tstamp = gethrtime (); +} + +static void +jvmti_MonitorWaited (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, + jobject object, jboolean timed_out) +{ + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd == NULL) + return; + if (collector_sync_end) + collector_sync_end (tsd->tstamp, object); +} +#endif + +static void +jprof_find_asyncgetcalltrace () +{ + void *jvmhandle; + if (__collector_VM_ReadByteInstruction == NULL) + __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction"); + + /* look for stack unwind function using default path */ + AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*)) + dlsym (RTLD_DEFAULT, "AsyncGetCallTrace"); + if (AsyncGetCallTrace != NULL) + { + __collector_java_asyncgetcalltrace_loaded = 1; + TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace found with RTLD_DEFAULT\n"); + } + else + { + /* not found there, find libjvm.so, and ask again */ + jvmhandle = dlopen ("libjvm.so", RTLD_LAZY | RTLD_NOLOAD); + if (jvmhandle != NULL) + { + AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*)) + dlsym (jvmhandle, "AsyncGetCallTrace"); + } + } + + if (AsyncGetCallTrace == NULL) + { + /* we could not find it -- write collector error */ + TprintfT (0, "jprofile: ERROR -- AsyncGetCallTrace not found in address space\n"); + char *err = dlerror (); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_JVMNOJSTACK, err ? err : ""); + __collector_java_mode = 0; + } + else + { + __collector_java_asyncgetcalltrace_loaded = 1; + TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace initialized in jprof_jvmpi_init_done_event\n"); + } +} + +int +__collector_ext_jstack_unwind (char *ptr, int sz, ucontext_t *uc) +{ + if (AsyncGetCallTrace == NULL) + { + TprintfT (DBG_LT0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace is NULL\n"); + return 0; + } + + TSD_Entry *tsd = collector_interface->getKey (tsd_key); + if (tsd == NULL) + { + TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd is NULL\n"); + return 0; + } + if (__collector_java_attach && tsd->env == NULL && jvmti != NULL && jvm != NULL) + { + TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL under attach\n"); + JNIEnv* jni_env = NULL; + (*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2); + tsd->env = jni_env; + } + if (tsd->env == NULL) + { + TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL\n"); + return 0; + } + + /* skip the Java stack whenever another signal handler is present */ + if (uc->uc_link) + { + TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: uc->uc_link is non-NULL\n"); + return 0; + } + /* we don't expect Java frames in signal handlers, so + * unroll the list of saved contexts to the topmost one + */ + while (uc->uc_link) + uc = uc->uc_link; + Java_info *jinfo = (Java_info*) ptr; + jinfo->kind = JAVA_INFO; + jinfo->hsize = sizeof (Java_info); + ptr += sizeof (Java_info); + sz -= sizeof (Java_info); + + JVMPI_CallTrace jtrace; + jtrace.env_id = tsd->env; + jtrace.frames = (JVMPI_CallFrame*) ptr; + + /* nframes is how many frames we have room for */ + jint nframes = sz / sizeof (JVMPI_CallFrame); + +#if WSIZE(64) + /* bug 6909545: garbage in 64-bit JAVA_INFO */ + CALL_UTIL (memset)(jtrace.frames, 0, nframes * sizeof (JVMPI_CallFrame)); +#endif + +#if ARCH(SPARC) + // 21328946 JDK bug 8129933 causes <no java callstack recorded> on sparc-Linux + // convert from ucontext_t to sigcontext + struct sigcontext sctx; + sctx.sigc_regs.tpc = uc->uc_mcontext.mc_gregs[MC_PC]; + __collector_memcpy (sctx.sigc_regs.u_regs, &uc->uc_mcontext.mc_gregs[3], sizeof (sctx.sigc_regs.u_regs)); + uc = (ucontext_t *) (&sctx); +#endif /* SPARC */ + AsyncGetCallTrace (&jtrace, nframes, uc); + + if (jtrace.num_frames == nframes) + { + JVMPI_CallFrame *last = &jtrace.frames[nframes - 1]; + last->method_id = (jmethodID) SP_TRUNC_STACK_MARKER; + last->lineno = 0; + } + + /* nframes is how many frames we actually got */ + nframes = jtrace.num_frames; + TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace jtrace.numframes = %d\n", nframes); + if (nframes <= 0) + { + /* negative values are error codes */ + TprintfT (0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace returned error: jtrace.numframes = %d\n", nframes); + nframes = 1; + JVMPI_CallFrame *err = (JVMPI_CallFrame*) ptr; + err->lineno = jtrace.num_frames; // bci = error code + err->method_id = 0; // artificial method id + } + jinfo->hsize += nframes * sizeof (JVMPI_CallFrame); + return jinfo->hsize; +} + +/* + * Collector Java API implementation + */ +void +Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv *jEnv, jclass jCls, jstring jName) +{ + JNIEnv *jni; + jint res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2); + if (res < 0) + return; + const char *name = jName ? (*jni)->GetStringUTFChars (jni, jName, NULL) : NULL; + __collector_sample ((char*) name); +} + +void +Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv *jEnv, jclass jCls) +{ + __collector_pause_m ("JAPI"); +} + +void +Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv *jEnv, jclass jCls) +{ + __collector_resume (); +} + +void +Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv *jEnv, jclass jCls) +{ + __collector_terminate_expt (); +} +#endif /* GPROFNG_JAVA_PROFILING */ + +static void init_module () __attribute__ ((constructor)); +static void +init_module () +{ +#if defined(GPROFNG_JAVA_PROFILING) + __collector_dlsym_guard = 1; + RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module"); + __collector_dlsym_guard = 0; + if (reg_module) + { + jprof_hndl = reg_module (&module_interface); + TprintfT (0, "jprofile: init_module.\n"); + } +#endif /* GPROFNG_JAVA_PROFILING */ +} + +int __collector_java_mode = 0; +int __collector_java_asyncgetcalltrace_loaded = 0; diff --git a/gprofng/libcollector/libcol-i386-dis.c b/gprofng/libcollector/libcol-i386-dis.c new file mode 100644 index 0000000..9b3882a --- /dev/null +++ b/gprofng/libcollector/libcol-i386-dis.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#if defined(__i386__) || defined(__x86_64) +#include "opcodes/i386-dis.c" + +#undef _ +#undef M +#include "libiberty/safe-ctype.c" +#endif + diff --git a/gprofng/libcollector/libcol_hwcdrv.c b/gprofng/libcollector/libcol_hwcdrv.c new file mode 100644 index 0000000..f3bd932 --- /dev/null +++ b/gprofng/libcollector/libcol_hwcdrv.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include "collector.h" /* Tprintf*() */ + +#define LIBCOLLECTOR_SRC +#include "hwcdrv.c" diff --git a/gprofng/libcollector/libcol_hwcfuncs.c b/gprofng/libcollector/libcol_hwcfuncs.c new file mode 100644 index 0000000..1f5ad68 --- /dev/null +++ b/gprofng/libcollector/libcol_hwcfuncs.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include "collector.h" /* Tprintf*() */ + +#define LIBCOLLECTOR_SRC +#include "hwcfuncs.c" + + diff --git a/gprofng/libcollector/libcol_util.c b/gprofng/libcollector/libcol_util.c new file mode 100644 index 0000000..c709b3c --- /dev/null +++ b/gprofng/libcollector/libcol_util.c @@ -0,0 +1,1693 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <dlfcn.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#include "gp-defs.h" +#include "collector.h" +#include "libcol_util.h" +#include "gp-experiment.h" +#include "Emsgnum.h" +#include "memmgr.h" // __collector_allocCSize, __collector_freeCSize +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* + * This file is intended for collector's own implementation of + * various routines to avoid interaction with libc and other + * libraries. + */ + +/* ------- libc interface ----------------- */ +CollectorUtilFuncs __collector_util_funcs = {NULL}; +int __collector_dlsym_guard = 0; +int(*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...); + +/* + * We have calls on Solaris to get the thread ID. + * On Linux, there is a gettid() system call. + * From user space, we have to use syscall(__NR_gettid). + * The call is probably fast (with the tid in vdso), but dbx intercepts the syscall. + * 7182047 syscall() has large overhead under dbx on linux + * One option is to use an assembly call to get the tid. + * We know how to do this on x86, but not on SPARC. + * So another option is to do the syscall once and cache the result in thread-local storage. + * This solves the SPARC case. + * On x86 we could use one or both strategies. So there are opportunities here to simplify the code. + */ +static unsigned gettid_key = COLLECTOR_TSD_INVALID_KEY; + +void +__collector_ext_gettid_tsd_create_key () +{ + gettid_key = __collector_tsd_create_key (sizeof (pid_t), NULL, NULL); +} + +pid_t +__collector_gettid () +{ + pid_t *tid_ptr = (pid_t *) __collector_tsd_get_by_key (gettid_key); + // check if we have a thread-specific tid and if it's been initialized + // (it's 0 before initialization and cannot be 0 after since pid 0 is the boot process) + if (tid_ptr && *tid_ptr > 0) + return *tid_ptr; + pid_t r; + +#if ARCH(Intel) +#if WSIZE(32) +#define syscall_instr "int $0x80" +#define syscall_clobber "memory" +#else //WSIZE(64) +#define syscall_instr "syscall" +#define syscall_clobber "rcx", "r11", "memory" +#endif + __asm__ __volatile__(syscall_instr + : "=a" (r) : "0" (__NR_gettid) + : syscall_clobber); +#else + r = syscall (__NR_gettid); +#endif + if (tid_ptr) + *tid_ptr = r; + return r; +} + +static inline int +atomic_swap (volatile int * p, int v) +{ +#if ARCH(Intel) + int r; + __asm__ __volatile__("xchg %1, %2" : "=r" (r) : "m" (*p), "0" (v)); + return r; +#else + /* Since the inline templates perfan/libcollector/src/inline.*.il all + * have implementations for __collector_cas_32(), how about we just + * use that interface for Intel as well and drop the "#if ARCH()" stuff here? + * + * As it is, we're using an atomic swap on Intel and + * compare-and-swap on SPARC. The semantics are different + * (cas requires an expected "compare" value and swaps ONLY + * if we match that value). Nevertheless, the results of the + * two operations + * Intel: atomic_swap(&lock, 1) + * SPARC: cas(&lock,0,1) + * happen to be the same for the two cases we're interested in: + * if lock==0 lock=1 return 0 + * if lock==1 lock=1 return 1 + * You CANNOT always simply substitute cas for swap. + */ + return __collector_cas_32 ((volatile uint32_t *)p, 0, v); +#endif +} + +int +__collector_mutex_lock (collector_mutex_t *lock_var) +{ + volatile unsigned int i; /* xxxx volatile may not be honored on amd64 -x04 */ + + if (!(*lock_var) && !atomic_swap (lock_var, 1)) + return 0; + + do + { + while ((collector_mutex_t) (*lock_var) == 1) + i++; + } + while (atomic_swap (lock_var, 1)); + return 0; +} + +int +__collector_mutex_trylock (collector_mutex_t *lock_var) +{ + if (!(*lock_var) && !atomic_swap (lock_var, 1)) + return 0; + return EBUSY; +} + +int +__collector_mutex_unlock (collector_mutex_t *lock_var) +{ + (*lock_var) = 0; + return 0; +} + +#if ARCH(SPARC) +void +__collector_inc_32 (volatile uint32_t *mem) +{ + uint32_t t1, t2; + __asm__ __volatile__(" ld %2,%0 \n" + "1: add %0,1,%1 \n" + " cas %2,%0,%1 \n" + " cmp %0,%1 \n" + " bne,a 1b \n" + " mov %1,%0 \n" + : "=&r" (t1), "=&r" (t2) + : "m" (*mem) + : "cc" + ); +} + +void +__collector_dec_32 (volatile uint32_t *mem) +{ + uint32_t t1, t2; + __asm__ __volatile__(" ld %2,%0 \n" + "1: sub %0,1,%1 \n" + " cas %2,%0,%1 \n" + " cmp %0,%1 \n" + " bne,a 1b \n" + " mov %1,%0 \n" + : "=&r" (t1), "=&r" (t2) + : "m" (*mem) + : "cc" + ); +} + +uint32_t +__collector_cas_32 (volatile uint32_t *mem, uint32_t old, uint32_t new) +{ + __asm__ __volatile__("cas [%1],%2,%0" + : "+r" (new) + : "r" (mem), "r" (old)); + return new; +} + +uint32_t +__collector_subget_32 (volatile uint32_t *mem, uint32_t val) +{ + uint32_t t1, t2; + __asm__ __volatile__(" ld %2,%0 \n" + "1: sub %0,%3,%1 \n" + " cas %2,%0,%1 \n" + " cmp %0,%1 \n" + " bne,a 1b \n" + " mov %1,%0 \n" + " sub %0,%3,%1 \n" + : "=&r" (t1), "=&r" (t2) + : "m" (*mem), "r" (val) + : "cc" + ); + return t2; +} + +#if WSIZE(32) + +void * +__collector_cas_ptr (volatile void *mem, void *old, void *new) +{ + __asm__ __volatile__("cas [%1],%2,%0" + : "+r" (new) + : "r" (mem), "r" (old)); + return new; +} + +uint64_t +__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new) +{ + uint64_t t; + __asm__ __volatile__(" ldx [%2],%2 \n" + " ldx [%3],%3 \n" + " casx [%1],%2,%3 \n" + " stx %3,%0 \n" + : "=m" (t) + : "r" (mem), "r" (old), "r" (new) + ); + return t; +} + +#elif WSIZE(64) + +void * +__collector_cas_ptr (volatile void *mem, void *old, void *new) +{ + __asm__ __volatile__("casx [%1],%2,%0" + : "+r" (new) + : "r" (mem), "r" (old)); + return new; +} + +uint64_t +__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new) +{ + uint64_t t; + __asm__ __volatile__(" ldx [%2],%2 \n" + " ldx [%3],%3 \n" + " casx [%1],%2,%3 \n" + " mov %3,%0 \n" + : "=&r" (t) + : "r" (mem), "r" (old), "r" (new) + ); + return t; +} + +#endif /* WSIZE() */ +#endif /* ARCH() */ + +void * +__collector_memcpy (void *s1, const void *s2, size_t n) +{ + char *cp1 = (char*) s1; + char *cp2 = (char*) s2; + while (n--) + *cp1++ = *cp2++; + return s1; +} + +static void * +collector_memset (void *s, int c, size_t n) +{ + unsigned char *s1 = s; + while (n--) + *s1++ = (unsigned char) c; + return s; +} + +int +__collector_strcmp (const char *s1, const char *s2) +{ + for (;;) + { + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + s1++; + s2++; + } +} + +int +__collector_strncmp (const char *s1, const char *s2, size_t n) +{ + while (n > 0) + { + if (*s1 != *s2) + return *s1 - *s2; + if (*s1 == 0) + return 0; + s1++; + s2++; + n--; + } + return 0; +} + +char * +__collector_strstr (const char *s1, const char *s2) +{ + if (s2 == NULL || *s2 == 0) + return NULL; + size_t len = __collector_strlen (s2); + for (char c = *s2; *s1; s1++) + if (c == *s1 && __collector_strncmp (s1, s2, len) == 0) + return (char *) s1; + return NULL; +} + +char * +__collector_strchr (const char *str, int chr) +{ + if (chr == '\0') + return (char *) (str + __collector_strlen (str)); + for (; *str; str++) + if (chr == (int) *str) + return (char *) str; + return NULL; +} + +char * +__collector_strrchr (const char *str, int chr) +{ + const char *p = str + __collector_strlen (str); + for (; p - str >= 0; p--) + if (chr == *p) + return (char *) p; + return NULL; +} + +int +__collector_strStartWith (const char *s1, const char *s2) +{ + size_t slen = __collector_strlen (s2); + return __collector_strncmp (s1, s2, slen); +} + +size_t +__collector_strlen (const char *s) +{ + int len = -1; + while (s[++len] != '\0') + ; + return len; +} + +size_t +__collector_strlcpy (char *dst, const char *src, size_t dstsize) +{ + size_t srcsize = 0; + size_t n = dstsize - 1; + char c; + while ((c = *src++) != 0) + if (srcsize++ < n) + *dst++ = c; + if (dstsize > 0) + *dst = '\0'; + return srcsize; +} + +size_t +__collector_strncpy (char *dst, const char *src, size_t dstsize) +{ + size_t i; + for (i = 0; i < dstsize; i++) + { + dst[i] = src[i]; + if (src[i] == '\0') + break; + } + return i; +} + +char * +__collector_strcat (char *dst, const char *src) +{ + size_t sz = __collector_strlen (dst); + for (size_t i = 0;; i++) + { + dst[sz + i] = src[i]; + if (src[i] == '\0') + break; + } + return dst; +} + +size_t +__collector_strlcat (char *dst, const char *src, size_t dstsize) +{ + size_t sz = __collector_strlen (dst); + return sz + __collector_strlcpy (dst + sz, src, dstsize - sz); +} + +void * +__collector_malloc (size_t size) +{ + void * ptr = __collector_allocCSize (__collector_heap, size, 0); + return ptr; +} + +void * +__collector_calloc (size_t nelem, size_t elsize) +{ + size_t n = nelem * elsize; + void * ptr = __collector_malloc (n); + if (NULL == ptr) + return NULL; + collector_memset (ptr, 0, n); + return ptr; +} + +char * +__collector_strdup (const char * str) +{ + if (NULL == str) + return NULL; + size_t size = __collector_strlen (str); + char * dst = (char *) __collector_malloc (size + 1); + if (NULL == dst) + return NULL; + __collector_strncpy (dst, str, size + 1); + return dst; +} + +#define C_FMT 1 +#define C_STR 2 +static char +Printable[256] = {//characters should be escaped by xml: "'<>& + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 3, 3, 1, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* !"#$%&'()*+,-./ */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 1, 3, /* 0123456789:;<=>? */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* PQRSTUVWXYZ[\]^_ */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, /* pqrstuvwxyz{|}~. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* ................ */ +}; +static char hex[17] = "0123456789abcdef"; +static char HEX[17] = "0123456789ABCDEF"; + +int +__collector_xml_snprintf (char *s, size_t n, const char *format, ...) +{ + va_list args; + va_start (args, format); + int res = __collector_xml_vsnprintf (s, n, format, args); + va_end (args); + return res; +} + +int +__collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args) +{ + const char *src = format; + char *dst = s; + int cnt = 0; + unsigned char c; + while ((c = *src) != 0) + { + if (c == '%') + { + char numbuf[32]; + int done = 0; + int jflag = 0; + int lflag = 0; + int zflag = 0; + int width = 0; + src++; + while (!done) + { + c = *src; + switch (c) + { + case '%': + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + src++; + done = 1; + break; + } + case '-': + { + if (jflag != 0) + done = 1; + else + { + jflag = 1; + src++; + } + break; + } + case 'l': + { + if (lflag != 0) + done = 1; + else + { + lflag = 1; + c = *++src; + if (c == 'l') + { + lflag++; + src++; + } + } + break; + } + case 'c': + { + unsigned char c1 = (unsigned char) va_arg (args, int); + if ((Printable[(int) c1] & C_STR) == 0) + { + if (c1 == '"') + {//" + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'q'; + if (cnt++ < n - 1) + *dst++ = 'u'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '\'') + {//' + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 's'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '&') + {//& + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'm'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '<') + {//< + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'l'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '>') + {//> + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'g'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c1 / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c1 % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + } + } + else if (cnt++ < n - 1) + *dst++ = c1; + src++; + done = 1; + break; + } + case 's': + { + /* Strings are always left justified */ + char *str = va_arg (args, char*); + if (!str) + str = "<NULL>"; + unsigned char c1; + while ((c1 = *str++) != 0) + { + if ((Printable[(int) c1] & C_STR) == 0) + { + if (c1 == '"') + {//" + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'q'; + if (cnt++ < n - 1) + *dst++ = 'u'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '\'') + {//' + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = 'o'; + if (cnt++ < n - 1) + *dst++ = 's'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '&') + {//& + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'a'; + if (cnt++ < n - 1) + *dst++ = 'm'; + if (cnt++ < n - 1) + *dst++ = 'p'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '<') + {//< + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'l'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else if (c1 == '>') + {//> + if (cnt++ < n - 1) + *dst++ = '&'; + if (cnt++ < n - 1) + *dst++ = 'g'; + if (cnt++ < n - 1) + *dst++ = 't'; + if (cnt++ < n - 1) + *dst++ = ';'; + } + else + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c1 / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c1 % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + } + } + else if (cnt++ < n - 1) + *dst++ = c1; + width--; + } + while (width > 0) + { + if (cnt++ < n - 1) + *dst++ = ' '; + width--; + } + src++; + done = 1; + break; + } + case 'i': + case 'd': + case 'o': + case 'p': + case 'u': + case 'x': + case 'X': + { + int base = 10; + int uflag = 0; + int sflag = 0; + if (c == 'o') + { + uflag = 1; + base = 8; + } + else if (c == 'u') + uflag = 1; + else if (c == 'p') + { + lflag = 1; + uflag = 1; + base = 16; + } + else if (c == 'x' || c == 'X') + { + uflag = 1; + base = 16; + } + long long argll = 0LL; + if (lflag == 0) + { + if (uflag) + argll = va_arg (args, unsigned int); + else + argll = va_arg (args, int); + } + else if (lflag == 1) + { + if (uflag) + argll = va_arg (args, unsigned long); + else + argll = va_arg (args, long); + } + else if (lflag == 2) + argll = va_arg (args, long long); + unsigned long long argllu = 0ULL; + if (uflag || argll >= 0) + argllu = argll; + else + { + sflag = 1; + argllu = -argll; + } + int idx = sizeof (numbuf); + do + { + numbuf[--idx] = (c == 'X' ? HEX[argllu % base] : hex[argllu % base]); + argllu = argllu / base; + } + while (argllu != 0) + ; + if (sflag) + { + if (jflag || zflag) + { + if (cnt++ < n - 1) + *dst++ = '-'; + } + else + numbuf[--idx] = '-'; + } + + if (jflag) + { + while (idx < sizeof (numbuf) && width > 0) + { + if (cnt++ < n - 1) + *dst++ = numbuf[idx]; + idx++; + width--; + } + zflag = 0; + } + + while (width > sizeof (numbuf) - idx) + { + if (cnt++ < n - 1) + *dst++ = zflag ? '0' : ' '; + width--; + } + while (idx != sizeof (numbuf)) + { + if (cnt++ < n - 1) + *dst++ = numbuf[idx]; + idx++; + } + src++; + done = 1; + break; + } + case '0': + zflag = 1; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + { + while (c >= '0' && c <= '9') + { + width = width * 10 + (c - '0'); + c = *++src; + } + break; + } + default: + done = 1; + break; + } + } + } + else if ((Printable[(int) c] & C_FMT) == 0) + { + if (cnt++ < n - 1) + *dst++ = '%'; + if (cnt++ < n - 1) + *dst++ = hex[c / 16]; + if (cnt++ < n - 1) + *dst++ = hex[c % 16]; + if (cnt++ < n - 1) + *dst++ = '%'; + src++; + } + else + { + if (cnt++ < n - 1) + *dst++ = c; + src++; + } + } + + if (cnt < n - 1) + s[cnt] = '\0'; + else + s[n - 1] = '\0'; + + return cnt; +} + +/* + * Functions to be called directly from libc.so + */ +#if ARCH(Intel) /* intel-Linux */ +/* + * The CPUIDinfo/__collector_cpuid() code is old, + * incorrect, and complicated. It returns the apicid + * rather than the processor number. + * + * Unfortunately, the higher-level sched_getcpu() function, + * which we use on SPARC-Linux, is not available on Oracle + * Linux 5. So we have to test for its existence. + */ + +/* a pointer to sched_getcpu(), in case we find it */ +typedef int (*sched_getcpu_ptr_t)(void); +sched_getcpu_ptr_t sched_getcpu_ptr; +static int need_warning = 0; + +/* the old, low-level code */ +static int useLeafB = 0; + +/* access to the CPUID instruction on Intel/AMD */ +typedef struct +{ + uint32_t eax, ebx, ecx, edx; +} CPUIDinfo; + +/** + * This function returns the result of the "cpuid" instruction + */ +static __attribute__ ((always_inline)) inline void +__collector_cpuid (CPUIDinfo* info) +{ + uint32_t ebx = info->ebx, ecx = info->ecx, edx = info->edx, eax = info->eax; + __asm__ ("cpuid" : "=b" (ebx), "=c" (ecx), "=d" (edx), "=a" (eax) : "a" (eax)); + info->eax = eax; + info->ebx = ebx; + info->ecx = ecx; + info->edx = edx; +} + +static void +getcpuid_init () +{ + CPUIDinfo info; + info.eax = 0; /* max input value for CPUID */ + __collector_cpuid (&info); + + if (info.eax >= 0xb) + { + info.eax = 0xb; + info.ecx = 0; + __collector_cpuid (&info); + useLeafB = info.ebx != 0; + } + + /* indicate that we need a warning */ + /* (need to wait until log mechanism has been initialized) */ + need_warning = 1; +} + +static uint32_t +getcpuid () +{ + /* if we found sched_getcpu(), use it */ + if (sched_getcpu_ptr) + return (*sched_getcpu_ptr)(); + + /* otherwise, check if we need warning */ + if (need_warning) + { + if (useLeafB) + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">x2APIC</event>\n", + SP_JCMD_CWARN, COL_WARN_LINUX_X86_APICID); + else + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">APIC</event>\n", + SP_JCMD_CWARN, COL_WARN_LINUX_X86_APICID); + need_warning = 0; + } + + /* and use the old, low-level code */ + CPUIDinfo info; + if (useLeafB) + { + info.eax = 0xb; + info.ecx = 0; + __collector_cpuid (&info); + return info.edx; /* x2APIC ID */ + } + else + { + info.eax = 0x1; + info.ecx = 0; + __collector_cpuid (&info); + return info.ebx >> 24; /* APIC ID */ + } +} + +#else /* sparc-Linux */ + +/* + * EUGENE + * How should sched_getcpu() be prototyped? Like this? + * #include <sched.h> + * Or like this? + * #define _GNU_SOURCE + * #include <utmpx.h> + * Or just prototype this function explicitly without bothering with include files. + */ +int sched_getcpu (); + +static int +getcpuid () +{ + return sched_getcpu (); +} +#endif + +/* if ever retries time-out, we will stop allowing them */ +static int exhausted_retries = 0; + +int +__collector_open (const char *path, int oflag, ...) +{ + int fd; + mode_t mode = 0; + + hrtime_t t_timeout = __collector_gethrtime () + 5 * ((hrtime_t) NANOSEC); + int nretries = 0; + long long delay = 100; /* start at some small, arbitrary value */ + + /* get optional mode argument if it's expected/required */ + if (oflag | O_CREAT) + { + va_list ap; + va_start (ap, oflag); + mode = (mode_t) va_arg (ap, mode_t); + va_end (ap); + } + + /* retry upon failure */ + while ((fd = CALL_UTIL (open_bare)(path, oflag, mode)) < 0) + { + if (exhausted_retries) + break; + + /* The particular condition we're willing to retry is if + * too many file descriptors were in use. The errno should + * be EMFILE, but apparently and mysteriously it can also be + * and often is ENOENT. + */ + if ((errno != EMFILE) && (errno != ENOENT)) + break; + if (__collector_gethrtime () > t_timeout) + { + exhausted_retries = 1; + break; + } + + /* Oddly, if I replace this spin wait with + * - a usleep() call or + * - a loop on gethrtime() calls + * for roughly the same length of time, retries aren't very effective. */ + int ispin; + double xdummy = 0.5; + for (ispin = 0; ispin < delay; ispin++) + xdummy = 0.5 * (xdummy + 1.); + if (xdummy < 0.1) + /* should never happen, but we check so the loop won't be optimized away */ + break; + delay *= 2; + if (delay > 100000000) + delay = 100000000; /* cap at some large, arbitrary value */ + nretries++; + } + return fd; +} + +int +__collector_util_init () +{ + int oldos = 0; + + /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */ + void *libc = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD); + if (libc == NULL) + libc = dlopen (SYS_LIBC_NAME, RTLD_NOW | RTLD_LOCAL); + if (libc == NULL) + { + /* libcollector will subsequently abort, as all the pointers in the vector are NULL */ +#if 0 + /* SP_COLLECTOR_TRACELEVEL is not yet set, so no Tprintf */ + fprintf (stderr, "__collector_util_init: dlopen(%s) failed: %s\n", SYS_LIBC_NAME, dlerror ()); + return COL_ERROR_UTIL_INIT; +#endif + abort (); + } + + void *ptr = dlsym (libc, "fprintf"); + if (ptr) + __collector_util_funcs.fprintf = (int(*)(FILE *, const char *, ...))ptr; + else + { + // We can't write any error messages without a libc reference +#if 0 + fprintf (stderr, "__collector_util_init: COLERROR_UTIL_INIT fprintf: %s\n", dlerror ()); + return COL_ERROR_UTIL_INIT; +#endif + abort (); + } + int err = 0; + + ptr = dlsym (libc, "mmap"); + if (ptr) + __collector_util_funcs.mmap = (void*(*)(void *, size_t, int, int, int, off_t))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mmap: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + /* mmap64 is only in 32-bits; this call goes to mmap in 64-bits */ + /* internal calls for mapping in libcollector call mmap64 */ + ptr = dlsym (libc, "mmap64"); + if (ptr) + __collector_util_funcs.mmap64 = (void*(*)(void *, size_t, int, int, int, off_t))ptr; + else + __collector_util_funcs.mmap64 = __collector_util_funcs.mmap; + + ptr = dlsym (libc, "munmap"); + if (ptr) + __collector_util_funcs.munmap = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT munmap: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "close"); + if (ptr) + __collector_util_funcs.close = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "open"); + if (ptr) + __collector_util_funcs.open = (int(*)(const char *path, int oflag, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT open: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "open64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0 + if (ptr) + __collector_util_funcs.open_bare = (int(*)(const char *path, int oflag, ...))ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "open64", "GLIBC_2.2"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "open64"); + if (ptr) + __collector_util_funcs.open_bare = (int(*)(const char *path, int oflag, ...))ptr; + else + __collector_util_funcs.open_bare = __collector_util_funcs.open; +#if ARCH(Intel) && WSIZE(32) + } +#endif /* ARCH(Intel) && WSIZE(32) */ + + ptr = dlsym (libc, "close"); + if (ptr) + __collector_util_funcs.close = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT close: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "read"); + if (ptr) + __collector_util_funcs.read = (ssize_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT read: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "write"); + if (ptr) + __collector_util_funcs.write = (ssize_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT write: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "pwrite", "GLIBC_2.2"); // it is in /lib/libpthread.so.0 + if (ptr) + __collector_util_funcs.pwrite = (ssize_t (*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "pwrite", "GLIBC_2.2"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "pwrite"); + if (ptr) + __collector_util_funcs.pwrite = (ssize_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT pwrite: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } +#if ARCH(Intel) && WSIZE(32) + } +#endif + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "pwrite64", "GLIBC_2.2"); // it is in /lib/libpthread.so.0 + if (ptr) + __collector_util_funcs.pwrite64 = (ssize_t (*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "pwrite64", "GLIBC_2.2"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "pwrite64"); + if (ptr) + __collector_util_funcs.pwrite64 = (ssize_t (*)())ptr; + else + __collector_util_funcs.pwrite64 = __collector_util_funcs.pwrite; +#if ARCH(Intel) && WSIZE(32) + } +#endif /* ARCH(Intel) && WSIZE(32) */ + + ptr = dlsym (libc, "lseek"); + if (ptr) + __collector_util_funcs.lseek = (off_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT lseek: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "access"); + if (ptr) + __collector_util_funcs.access = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT access: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "mkdir"); + if (ptr) + __collector_util_funcs.mkdir = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mkdir: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "opendir"); + if (ptr) + __collector_util_funcs.opendir = (DIR * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT opendir: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "closedir"); + if (ptr) + __collector_util_funcs.closedir = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT closedir: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "execv"); + if (ptr) + __collector_util_funcs.execv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT execv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "exit"); + if (ptr) + __collector_util_funcs.exit = (void(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT exit: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "vfork"); + if (ptr) + __collector_util_funcs.vfork = (pid_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT vfork: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "waitpid"); + if (ptr) + __collector_util_funcs.waitpid = (pid_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT waitpid: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + int (*__collector_getcpuid)() = (int(*)()) & getcpuid; +#if ARCH(Intel) + /* if sched_getcpu() not found, init our getcpuid() */ + sched_getcpu_ptr = (sched_getcpu_ptr_t) dlsym (libc, "sched_getcpu"); + if (sched_getcpu_ptr == NULL) + getcpuid_init (); +#endif + __collector_util_funcs.getcpuid = __collector_getcpuid; + __collector_util_funcs.memset = collector_memset; + + ptr = dlsym (libc, "malloc"); + if (ptr) + __collector_util_funcs.malloc = (void *(*)(size_t))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT malloc: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "putenv"); + if (ptr) + __collector_util_funcs.putenv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT putenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "getenv"); + if (ptr) + __collector_util_funcs.getenv = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT getenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "time"); + if (ptr) + __collector_util_funcs.time = (time_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT time: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "mktime"); + if (ptr) + __collector_util_funcs.mktime = (time_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT mktime: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + __collector_util_funcs.strcmp = __collector_strcmp; + __collector_util_funcs.strncmp = __collector_strncmp; + __collector_util_funcs.strncpy = __collector_strncpy; + __collector_util_funcs.strstr = __collector_strstr; + + ptr = dlsym (libc, "gmtime_r"); + if (ptr) + __collector_util_funcs.gmtime_r = (struct tm * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT gmtime_r: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtol"); + if (ptr) + __collector_util_funcs.strtol = (long (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtol: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtoll"); + if (ptr) + __collector_util_funcs.strtoll = (long long (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoll: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + __collector_util_funcs.strchr = __collector_strchr; + __collector_util_funcs.strrchr = __collector_strrchr; + + ptr = dlsym (libc, "setenv"); + if (ptr) + __collector_util_funcs.setenv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT setenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "unsetenv"); + if (ptr) + __collector_util_funcs.unsetenv = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT unsetenv: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "atof"); + if (ptr) + __collector_util_funcs.atof = (double (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT atof: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sysinfo"); + if (ptr) + __collector_util_funcs.sysinfo = (long (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sysinfo: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "clearenv"); + if (ptr) + __collector_util_funcs.clearenv = (int(*)())ptr; + else + { + /* suppress warning on S10 or earlier Solaris */ + if (oldos == 0) + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT clearenv: %s\n", dlerror ()); + /* err = COL_ERROR_UTIL_INIT; */ + /* don't treat this as fatal, so that S10 could work */ + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "fopen", "GLIBC_2.1"); + if (ptr) + __collector_util_funcs.fopen = (FILE * (*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "fopen", "GLIBC_2.1"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "fopen"); + if (ptr) + __collector_util_funcs.fopen = (FILE * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fopen: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } +#if ARCH(Intel) && WSIZE(32) + } +#endif + + ptr = dlsym (libc, "popen"); + if (ptr) + __collector_util_funcs.popen = (FILE * (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT popen: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + +#if ARCH(Intel) && WSIZE(32) + ptr = dlvsym (libc, "fclose", "GLIBC_2.1"); + if (ptr) + __collector_util_funcs.fclose = (int(*)())ptr; + else + { + Tprintf (DBG_LT0, "libcol_util: WARNING: dlvsym for %s@%s failed. Using dlsym() instead.", "fclose", "GLIBC_2.1"); +#endif /* ARCH(Intel) && WSIZE(32) */ + ptr = dlsym (libc, "fclose"); + if (ptr) + __collector_util_funcs.fclose = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fclose: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } +#if ARCH(Intel) && WSIZE(32) + } +#endif + + ptr = dlsym (libc, "pclose"); + if (ptr) + __collector_util_funcs.pclose = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT pclose: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "fgets"); + if (ptr) + __collector_util_funcs.fgets = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fgets: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sscanf"); + if (ptr) + __collector_sscanfp = (int(*)(const char *restrict s, const char *restrict fmt, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sscanf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "snprintf"); + if (ptr) + __collector_util_funcs.snprintf = (int(*)(char *, size_t, const char *, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT snprintf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "vsnprintf"); + if (ptr) + __collector_util_funcs.vsnprintf = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT vsnprintf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "atoi"); + if (ptr) + __collector_util_funcs.atoi = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT atoi: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "calloc"); + if (ptr) + __collector_util_funcs.calloc = (void*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT calloc: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "free"); + if (ptr) + { + __collector_util_funcs.free = (void(*)())ptr; + } + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT free: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strdup"); + if (ptr) + __collector_util_funcs.libc_strdup = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strdup: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + __collector_util_funcs.strlen = __collector_strlen; + __collector_util_funcs.strlcat = __collector_strlcat; + __collector_util_funcs.strlcpy = __collector_strlcpy; + + ptr = dlsym (libc, "strerror"); + if (ptr) + __collector_util_funcs.strerror = (char*(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strerror: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + ptr = dlsym (libc, "strerror_r"); + if (ptr) + __collector_util_funcs.strerror_r = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strerror_r: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + ptr = dlsym (libc, "strspn"); + if (ptr) + __collector_util_funcs.strspn = (size_t (*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strspn: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtoul"); + if (ptr) + __collector_util_funcs.strtoul = (unsigned long int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoul: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "strtoull"); + if (ptr) + __collector_util_funcs.strtoull = (unsigned long long int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT strtoull: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "fcntl"); + if (ptr) + __collector_util_funcs.fcntl = (int(*)(int, int, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT fcntl: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "ioctl"); + if (ptr) + __collector_util_funcs.ioctl = (int(*)(int, int, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT ioctl: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "symlink"); + if (ptr) + __collector_util_funcs.symlink = (int(*)(const char*, const char*))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT symlink: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "syscall"); + if (ptr) + __collector_util_funcs.syscall = (int(*)(int, ...))ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT syscall: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sysconf"); + if (ptr) + __collector_util_funcs.sysconf = (long(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sysconf: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sigfillset"); + if (ptr) + __collector_util_funcs.sigfillset = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sigfillset: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + ptr = dlsym (libc, "sigprocmask"); + if (ptr) + __collector_util_funcs.sigprocmask = (int(*)())ptr; + else + { + CALL_UTIL (fprintf)(stderr, "collector_util_init COL_ERROR_UTIL_INIT sigprocmask: %s\n", dlerror ()); + err = COL_ERROR_UTIL_INIT; + } + + return err; +} diff --git a/gprofng/libcollector/libcol_util.h b/gprofng/libcollector/libcol_util.h new file mode 100644 index 0000000..4384d47 --- /dev/null +++ b/gprofng/libcollector/libcol_util.h @@ -0,0 +1,321 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef _LIBCOL_UTIL_H +#define _LIBCOL_UTIL_H + +#include <stdarg.h> +#include <pthread.h> +#include <signal.h> + +// LIBCOLLECTOR NOT I18N +#define NTXT(x) x +#define STXT(x) x + +extern int __collector_tracelevel; + +/* Initialization function */ +extern int __collector_util_init(); +extern void __collector_libkstat_funcs_init(); +extern void __collector_libscf_funcs_init(); + +/* ------- functions from libcol_util.c ----------------- */ +extern void * __collector_memcpy (void *s1, const void *s2, size_t n); +extern int (*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...); +extern char * __collector_strcat (char *s1, const char *s2); +extern char * __collector_strchr (const char *s1, int chr); +extern size_t __collector_strlcpy (char *dst, const char *src, size_t dstsize); +extern char* __collector_strrchr (const char *str, int chr); +extern size_t __collector_strlen (const char *s); +extern size_t __collector_strlcat (char *dst, const char *src, size_t dstsize); +extern char* __collector_strchr (const char *str, int chr); +extern int __collector_strcmp (const char *s1, const char *s2); +extern int __collector_strncmp (const char *s1, const char *s2, size_t n); +extern char * __collector_strstr (const char *s1, const char *s2); +extern size_t __collector_strncpy (char *dst, const char *src, size_t dstsize); +extern size_t __collector_strncat (char *dst, const char *src, size_t dstsize); +extern void * __collector_malloc (size_t size); +extern void * __collector_calloc (size_t nelem, size_t elsize); +extern char * __collector_strdup (const char * str); +extern int __collector_strStartWith (const char *s1, const char *s2); +extern int __collector_xml_snprintf (char *s, size_t n, const char *format, ...) __attribute__ ((format (printf, 3, 4))); +extern int __collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args); + +/* ------- collector_thread ----------------- */ +pid_t __collector_gettid (); +extern void __collector_ext_gettid_tsd_create_key (); +#define collector_thread_t pthread_t // not using pid_t, since tid is defined as pthread_t in package structures, and other codes assume this type +#define statvfs_t struct statvfs +#define __collector_lwp_self() (collector_thread_t)__collector_gettid() // not using pthread_self() +#define __collector_thr_self() (collector_thread_t)__collector_gettid() // not using pthread_self() + +/* ------- collector_mutex ----------------- */ +/* + * mutex_init is defined in libthread. If we don't want to interact + * with libthread we should use memset to initialize mutexes + */ + +typedef volatile int collector_mutex_t; +#define COLLECTOR_MUTEX_INITIALIZER 0 +extern int __collector_mutex_lock (collector_mutex_t *mp); +extern int __collector_mutex_unlock (collector_mutex_t *mp); +extern int __collector_mutex_trylock (collector_mutex_t *mp); + +#define __collector_mutex_init(xx) \ + do { collector_mutex_t tmp=COLLECTOR_MUTEX_INITIALIZER; *(xx)=tmp; } while(0) + +void __collector_sample (char *name); +void __collector_terminate_expt (); +void __collector_pause (); +void __collector_pause_m (); +void __collector_resume (); + +struct DT_lineno; + +typedef enum +{ + DFUNC_API = 1, /* dynamic function declared with API */ + DFUNC_JAVA, /* dynamically compiled java method */ + DFUNC_KERNEL /* dynamic code mapped by the kernel (Linux) */ +} dfunc_mode_t; + +extern void __collector_int_func_load (dfunc_mode_t mode, char *name, + char *sourcename, void *vaddr, + int size, int lntsize, + struct DT_lineno *lntable); +extern void __collector_int_func_unload (dfunc_mode_t mode, void *vaddr); + +extern int __collector_sigaction (int sig, const struct sigaction *nact, + struct sigaction *oact); +extern void __collector_SIGDFL_handler (int sig); +extern int __collector_ext_itimer_set (int period); + +#if ARCH(Intel) +/* Atomic functions on x86/x64 */ + +/** + * This function enables the inrementing (by one) of the value stored in target + * to occur in an atomic manner. + */ +static __attribute__ ((always_inline)) inline void +__collector_inc_32 (uint32_t *ptr) +{ + __asm__ __volatile__("lock; incl %0" + : // "=m" (*ptr) // output + : "m" (*ptr)); // input +} + +/** + * This function enables the decrementing (by one) of the value stored in target + * to occur in an atomic manner. + */ +static __attribute__ ((always_inline)) inline void +__collector_dec_32 (volatile uint32_t *ptr) +{ + __asm__ __volatile__("lock; decl %0" + : // "=m" (*ptr) // output + : "m" (*ptr)); // input +} +/** + * This function subtrackts the value "off" of the value stored in target + * to occur in an atomic manner, and returns new value stored in target. + */ +static __attribute__ ((always_inline)) inline uint32_t +__collector_subget_32 (uint32_t *ptr, uint32_t off) +{ + uint32_t r; + uint32_t offset = off; + __asm__ __volatile__("movl %2, %0; negl %0; lock; xaddl %0, %1" + : "=r" (r), "=m" (*ptr) /* output */ + : "a" (off), "r" (*ptr) /* input */ + ); + return (r - offset); +} +/** + * This function returns the value of the stack pointer register + */ +static __attribute__ ((always_inline)) inline void * +__collector_getsp () +{ + void *r; +#if WSIZE(64) + __asm__ __volatile__("movq %%rsp, %0" +#else + __asm__ __volatile__("movl %%esp, %0" +#endif + : "=r" (r)); // output + return r; +} +/** + * This function returns the value of the frame pointer register + */ +static __attribute__ ((always_inline)) inline void * +__collector_getfp () +{ + void *r; +#if WSIZE(64) + __asm__ __volatile__("movq %%rbp, %0" +#else + __asm__ __volatile__("movl %%ebp, %0" +#endif + : "=r" (r)); // output + return r; +} +/** + * This function returns the value of the processor counter register + */ +static __attribute__ ((always_inline)) inline void * +__collector_getpc () +{ + void *r; + __asm__ __volatile__( +#if WSIZE(32) + " call 1f \n" + "1: popl %0 \n" +#else + " call 1f \n" + "1: popq %0 \n" +#endif + : "=r" (r)); // output + return r; +} + +/** + * This function enables a compare and swap operation to occur atomically. + * The 32-bit value stored in target is compared with "old". If these values + * are equal, the value stored in target is replaced with "new". The old + * 32-bit value stored in target is returned by the function whether or not + * the replacement occurred. + */ +static __attribute__ ((always_inline)) inline uint32_t +__collector_cas_32 (volatile uint32_t *pdata, uint32_t old, uint32_t new) +{ + uint32_t r; + __asm__ __volatile__("lock; cmpxchgl %2, %1" + : "=a" (r), "=m" (*pdata) : "r" (new), + "a" (old), "m" (*pdata)); + return r; +} +/** + * This function enables a compare and swap operation to occur atomically. + * The 64-bit value stored in target is compared with "old". If these values + * are equal, the value stored in target is replaced with "new". The old + * 64-bit value stored in target is returned by the function whether or not + * the replacement occurred. + */ +static __attribute__ ((always_inline)) inline uint64_t +__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t * new) +{ + uint64_t r; +#if WSIZE(32) + uint32_t old1 = (uint32_t) (*old & 0xFFFFFFFFL); + uint32_t old2 = (uint32_t) ((*old >> 32) & 0xFFFFFFFFL); + uint32_t new1 = (uint32_t) (*new & 0xFFFFFFFFL); + uint32_t new2 = (uint32_t) ((*new >> 32) & 0xFFFFFFFFL); + uint32_t res1 = 0; + uint32_t res2 = 0; + __asm__ __volatile__( + "movl %3, %%esi; lock; cmpxchg8b (%%esi); movl %%edx, %2; movl %%eax, %1" + : "=m" (r), "=m" (res1), "=m" (res2) /* output */ + : "m" (mem), "a" (old1), "d" (old2), "b" (new1), "c" (new2) /* input */ + : "memory", "cc", "esi" //, "edx", "ecx", "ebx", "eax" /* clobbered register */ + ); + r = (((uint64_t) res2) << 32) | ((uint64_t) res1); +#else + __asm__ __volatile__( "lock; cmpxchgq %2, %1" + : "=a" (r), "=m" (*mem) /* output */ + : "r" (*new), "a" (*old), "m" (*mem) /* input */ + : "%rcx", "rdx" /* clobbered register */ + ); +#endif + return r; +} +/** + * This function enables a compare and swap operation to occur atomically. + * The 32-/64-bit value stored in target is compared with "cmp". If these values + * are equal, the value stored in target is replaced with "new". + * The old value stored in target is returned by the function whether or not + * the replacement occurred. + */ +static __attribute__ ((always_inline)) inline void * +__collector_cas_ptr (void *mem, void *cmp, void *new) +{ + void *r; +#if WSIZE(32) + r = (void *) __collector_cas_32 ((volatile uint32_t *)mem, (uint32_t) cmp, (uint32_t)new); +#else + __asm__ __volatile__("lock; cmpxchgq %2, (%1)" + : "=a" (r), "=b" (mem) /* output */ + : "r" (new), "a" (cmp), "b" (mem) /* input */ + ); +#endif + return r; +} + +#elif ARCH(Aarch64) +static __attribute__ ((always_inline)) inline uint32_t +__collector_inc_32 (volatile uint32_t *ptr) +{ + return __sync_add_and_fetch (ptr, 1); +} + +static __attribute__ ((always_inline)) inline uint32_t +__collector_dec_32 (volatile uint32_t *ptr) +{ + return __sync_sub_and_fetch (ptr, 1); +} + +static __attribute__ ((always_inline)) inline uint32_t +__collector_subget_32 (volatile uint32_t *ptr, uint32_t off) +{ + return __sync_sub_and_fetch (ptr, off); +} + +static __attribute__ ((always_inline)) inline uint32_t +__collector_cas_32 (volatile uint32_t *ptr, uint32_t old, uint32_t new) +{ + return __sync_val_compare_and_swap (ptr, old, new); +} + +static __attribute__ ((always_inline)) inline uint64_t +__collector_cas_64p (volatile uint64_t *ptr, uint64_t *old, uint64_t * new) +{ + return __sync_val_compare_and_swap (ptr, *old, *new); +} + +static __attribute__ ((always_inline)) inline void * +__collector_cas_ptr (void *ptr, void *old, void *new) +{ + return (void *) __sync_val_compare_and_swap ((unsigned long *) ptr, (unsigned long) old, (unsigned long) new); +} + +#else +extern void __collector_flushw (); /* defined for SPARC only */ +extern void* __collector_getpc (); +extern void* __collector_getsp (); +extern void* __collector_getfp (); +extern void __collector_inc_32 (volatile uint32_t *); +extern void __collector_dec_32 (volatile uint32_t *); +extern void* __collector_cas_ptr (volatile void *, void *, void *); +extern uint32_t __collector_cas_32 (volatile uint32_t *, uint32_t, uint32_t); +extern uint32_t __collector_subget_32 (volatile uint32_t *, uint32_t); +extern uint64_t __collector_cas_64p (volatile uint64_t *, uint64_t *, uint64_t *); +#endif /* ARCH() */ +#endif /* _LIBCOL_UTIL_H */ diff --git a/gprofng/libcollector/linetrace.c b/gprofng/libcollector/linetrace.c new file mode 100644 index 0000000..970d68c --- /dev/null +++ b/gprofng/libcollector/linetrace.c @@ -0,0 +1,2005 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Lineage events for process fork, exec, etc. + */ + +#include "config.h" +#include <string.h> +#include <elf.h> +#include <regex.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "descendants.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LTT 0 // for interposition on GLIBC functions +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +#define LT_MAXNAMELEN 1024 +#define LT_MAXPATHLEN 1024 + +int __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; +int dbg_current_mode = FOLLOW_NONE; /* for debug only */ +unsigned line_key = COLLECTOR_TSD_INVALID_KEY; +line_mode_t line_mode = LM_DORMANT; +int user_follow_mode = FOLLOW_ON; +int java_mode = 0; + +static char *user_follow_spec; +static char new_lineage[LT_MAXNAMELEN]; +static char curr_lineage[LT_MAXNAMELEN]; +static char linetrace_exp_dir_name[LT_MAXPATHLEN + 1]; // experiment directory + +/* lineage tracking for descendants of this process */ + +static int fork_linenum = 0; +static int line_initted = 0; +static collector_mutex_t fork_lineage_lock = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t clone_lineage_lock = COLLECTOR_MUTEX_INITIALIZER; + +/* interposition */ +#define CALL_REAL(x) (*(int(*)())__real_##x) +#define CALL_REALC(x) (*(char*(*)())__real_##x) +#define CALL_REALF(x) (*(FILE*(*)())__real_##x) +#define NULL_PTR(x) ( __real_##x == NULL ) + +// For a given Linux, which lib functions have more than one GLIBC version? Do this: +// objdump -T `find /lib /lib64 -name "*.so*"` | grep GLIBC | grep text | grep \( +static void *__real_fork = NULL; +static void *__real_vfork = NULL; +static void *__real_execve = NULL; +static void *__real_execvp = NULL; +static void *__real_execv = NULL; +static void *__real_execle = NULL; +static void *__real_execlp = NULL; +static void *__real_execl = NULL; +static void *__real_clone = NULL; +static void *__real_grantpt = NULL; +static void *__real_ptsname = NULL; +static void *__real_popen = NULL; +static int clone_linenum = 0; +#if ARCH(Intel) +#if WSIZE(32) +static void *__real_popen_2_1 = NULL; +static void *__real_popen_2_0 = NULL; +static void *__real_posix_spawn_2_15 = NULL; +static void *__real_posix_spawnp_2_15 = NULL; +static void *__real_posix_spawn_2_2 = NULL; +static void *__real_posix_spawnp_2_2 = NULL; +#elif WSIZE(64) +static void *__real_posix_spawn_2_15 = NULL; +static void *__real_posix_spawnp_2_15 = NULL; +static void *__real_posix_spawn_2_2_5 = NULL; +static void *__real_posix_spawnp_2_2_5 = NULL; +#endif /* WSIZE() */ +#endif /* ARCH(Intel) */ +static void *__real_system = NULL; +static void *__real_posix_spawn = NULL; +static void *__real_posix_spawnp = NULL; +static void *__real_setuid = NULL; +static void *__real_seteuid = NULL; +static void *__real_setreuid = NULL; +static void *__real_setgid = NULL; +static void *__real_setegid = NULL; +static void *__real_setregid = NULL; +static void linetrace_dormant (); +static int check_follow_fork (); +static int check_follow_exec (const char *execfile); +static int check_follow_combo (const char *execfile); +static int path_collectable (const char *execfile); +static char * build_experiment_path (char *instring, size_t instring_sz, const char *lineage_str); +static int init_lineage_intf (); + +/* ------- "Previously dbx-visible" function prototypes ----------------- */ +static int linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *execfile); +static char *lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname); +static void linetrace_ext_fork_prologue (const char *variant, char * new_lineage, int *following_fork); +static void linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * new_lineage, int *following_fork); +static char **linetrace_ext_exec_prologue (const char *variant, + const char* path, char *const argv[], char *const envp[], int *following_exec); +static void linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec); +static void linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo); +static void linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo); + +#ifdef DEBUG +static int +get_combo_flag () +{ + int * guard = NULL; + int combo_flag = ((line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0); + return combo_flag; +} +#endif /* DEBUG */ + +/* must be called for potentially live experiment */ +int +__collector_ext_line_init (int *precord_this_experiment, + const char * progspec, const char * progname) +{ + *precord_this_experiment = 1; + TprintfT (DBG_LT0, "__collector_ext_line_init(%s)\n", progspec); + if (NULL_PTR (fork)) + if (init_lineage_intf ()) + { + TprintfT (DBG_LT0, "__collector_ext_line_init() ERROR: initialization failed.\n"); + return COL_ERROR_LINEINIT; + } + /* check the follow spec */ + user_follow_spec = CALL_UTIL (getenv)(SP_COLLECTOR_FOLLOW_SPEC); + if (user_follow_spec != NULL) + { + TprintfT (DBG_LT0, "collector: %s=%s\n", SP_COLLECTOR_FOLLOW_SPEC, user_follow_spec); + if (!linetrace_follow_experiment (user_follow_spec, curr_lineage, progname)) + { + *precord_this_experiment = 0; + TprintfT (DBG_LT0, "collector: -F =<regex> does not match, will NOT be followed\n"); + } + else + TprintfT (DBG_LT0, "collector: -F =<regex> matches, will be followed\n"); + user_follow_mode = FOLLOW_ALL; + } + __collector_env_save_preloads (); + TprintfT (DBG_LT0, "__collector_ext_line_init(), progname=%s, followspec=%s, followthis=%d\n", + progname, user_follow_spec ? user_follow_spec : "NULL", + *precord_this_experiment); + line_mode = LM_TRACK_LINEAGE; /* even if we don't follow, we report the interposition */ + line_initted = 1; + return COL_ERROR_NONE; +} + +/* + * int __collector_ext_line_install(args) + * Check args to determine which line events to follow. + * Create tsd key for combo flag. + */ +int +__collector_ext_line_install (char *args, const char * expname) +{ + if (!line_initted) + { + TprintfT (DBG_LT0, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args); + return COL_ERROR_EXPOPEN; + } + TprintfT (DBG_LT0, "__collector_ext_line_install(%s, %s)\n", args, expname); + line_key = __collector_tsd_create_key (sizeof (int), NULL, NULL); + + /* determine experiment name */ + __collector_strlcpy (linetrace_exp_dir_name, expname, sizeof (linetrace_exp_dir_name)); + lineage_from_expname (curr_lineage, sizeof (curr_lineage), linetrace_exp_dir_name); + user_follow_mode = CALL_UTIL (atoi)(args); + TprintfT (DBG_LT0, "__collector_ext_line_install() user_follow_mode=0x%X, linetrace_exp_dir_name=%s\n", + user_follow_mode, linetrace_exp_dir_name); + + // determine java mode + char * java_follow_env = CALL_UTIL (getenv)(JAVA_TOOL_OPTIONS); + if (java_follow_env != NULL && CALL_UTIL (strstr)(java_follow_env, COLLECTOR_JVMTI_OPTION)) + java_mode = 1; + + // backup collector specific env + if (sp_env_backup == NULL) + { + sp_env_backup = __collector_env_backup (); + TprintfT (DBG_LT0, "__collector_ext_line_install creating sp_env_backup -- 0x%p\n", sp_env_backup); + } + else + TprintfT (DBG_LT0, "__collector_ext_line_install existing sp_env_backup -- 0x%p\n", sp_env_backup); + if (user_follow_mode == FOLLOW_NONE) + __collector_env_unset (NULL); + + char logmsg[256]; + logmsg[0] = '\0'; + if (user_follow_mode != FOLLOW_NONE) + CALL_UTIL (strlcat)(logmsg, "fork|exec|combo", sizeof (logmsg)); + size_t slen = __collector_strlen (logmsg); + if (slen > 0) + logmsg[slen] = '\0'; + else + CALL_UTIL (strlcat)(logmsg, "none", sizeof (logmsg)); + + /* report which line events are followed */ + (void) __collector_log_write ("<setting %s=\"%s\"/>\n", SP_JCMD_LINETRACE, logmsg); + TprintfT (DBG_LT0, "__collector_ext_line_install(%s): %s \n", expname, logmsg); + return COL_ERROR_NONE; +} + +char * +lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname) +{ + TprintfT (DBG_LT0, "lineage_from_expname(%s, %s)\n", lineage_str, expname); + char *p = NULL; + if (lstr_sz < 1 || !lineage_str || !expname) + { + TprintfT (DBG_LT0, "lineage_from_expname(): ERROR, null string\n"); + return NULL; + } + /* determine lineage from experiment name */ + p = __collector_strrchr (expname, '/'); + if ((p == NULL) || (*++p != '_')) + { + lineage_str[0] = 0; + TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname); + } + else + { + size_t tmp = __collector_strlcpy (lineage_str, p, lstr_sz); + if (tmp >= lstr_sz) + TprintfT (DBG_LT0, "lineage_from_expname(): ERROR: expt=%s lineage=\"%s\" truncated %ld characters\n", + expname, lineage_str, (long) (tmp - lstr_sz)); + lineage_str[lstr_sz - 1] = 0; + p = __collector_strchr (lineage_str, '.'); + if (p != NULL) + *p = '\0'; + TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname, lineage_str); + } + return lineage_str; +} + +/* + * void __collector_line_cleanup (void) + * Disable logging. Clear backup ENV. + */ +void +__collector_line_cleanup (void) +{ + if (line_mode == LM_CLOSED) + { + TprintfT (DBG_LT0, "__collector_line_cleanup(): WARNING, line is already closed\n"); + return; + } + else if (line_mode == LM_DORMANT) + TprintfT (DBG_LT0, "__collector_line_cleanup(): ERROR, line is DORMANT\n"); + else + TprintfT (DBG_LT0, "__collector_line_cleanup()\n"); + line_mode = LM_CLOSED; + user_follow_mode = FOLLOW_NONE; + dbg_current_mode = FOLLOW_NONE; /* for debug only */ + line_key = COLLECTOR_TSD_INVALID_KEY; + java_mode = 0; + if (sp_env_backup != NULL) + { + __collector_env_backup_free (); + sp_env_backup = NULL; + } + return; +} + +/* + * void __collector_ext_line_close (void) + * Disable logging. Cleans ENV vars. Clear backup ENV. + */ +void +__collector_ext_line_close (void) +{ + TprintfT (DBG_LT0, "__collector_ext_line_close()\n"); + __collector_line_cleanup (); + __collector_env_unset (NULL); + return; +} + +/* + * void linetrace_dormant(void) + * Disable logging. Preserve ENV vars. + */ +static void +linetrace_dormant (void) +{ + if (line_mode == LM_DORMANT) + { + TprintfT (DBG_LT0, "linetrace_dormant() -- already dormant\n"); + return; + } + else if (line_mode == LM_CLOSED) + { + TprintfT (DBG_LT0, "linetrace_dormant(): ERROR, line is already CLOSED\n"); + return; + } + else + TprintfT (DBG_LT0, "linetrace_dormant()\n"); + line_mode = LM_DORMANT; + return; +} + +static int +check_follow_fork () +{ + int follow = (user_follow_mode != FOLLOW_NONE); + TprintfT (DBG_LT0, "check_follow_fork()=%d\n", follow); + return follow; +} + +static int +check_follow_exec (const char *execfile) +{ + int follow = (user_follow_mode != FOLLOW_NONE); + if (follow) + { + /* revise based on collectability of execfile */ + follow = path_collectable (execfile); + } + TprintfT (DBG_LT0, "check_follow_exec(%s)=%d\n", execfile, follow); + return follow; +} + +static int +check_follow_combo (const char *execfile) +{ + int follow = (user_follow_mode != FOLLOW_NONE); + TprintfT (DBG_LT0, "check_follow_combo(%s)=%d\n", execfile, follow); + return follow; +} + +static int +check_fd_dynamic (int fd) +{ + TprintfT (DBG_LT0, "check_fd_dynamic(%d)\n", fd); + off_t off = CALL_UTIL (lseek)(fd, (off_t) 0, SEEK_END); + size_t sz = (size_t) 8192; /* one page should suffice */ + if (sz > off) + sz = off; + char *p = CALL_UTIL (mmap64)((char *) 0, sz, PROT_READ, MAP_PRIVATE, fd, (off64_t) 0); + if (p == MAP_FAILED) + { + TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: mmap failed for `%d'\n", fd); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_NOFOLLOW, "mmap-failed"); + return 0; + } + char elfclass = p[EI_CLASS]; + if ((p[EI_MAG0] != ELFMAG0) || + (p[EI_MAG1] != ELFMAG1) || + (p[EI_MAG2] != ELFMAG2) || + (p[EI_MAG3] != ELFMAG3) || + (elfclass != ELFCLASS32 && elfclass != ELFCLASS64) + ) + { + TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd); + CALL_UTIL (munmap)(p, sz); + return 1; + } + Elf32_Ehdr *ehdr32 = (Elf32_Ehdr*) p; + Elf64_Ehdr *ehdr64 = (Elf64_Ehdr*) p; + Elf64_Off e_phoff; + Elf64_Half e_phnum; + Elf64_Half e_phentsize; + if (elfclass == ELFCLASS32) + { + e_phoff = ehdr32->e_phoff; + e_phnum = ehdr32->e_phnum; + e_phentsize = ehdr32->e_phentsize; + } + else + { + e_phoff = ehdr64->e_phoff; + e_phnum = ehdr64->e_phnum; + e_phentsize = ehdr64->e_phentsize; + } + if ((sizeof (Elf32_Ehdr) > sz) || + (sizeof (Elf64_Ehdr) > sz) || + (e_phoff + e_phentsize * (e_phnum - 1) > sz)) + { + TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd); +#if 0 + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_RISKYFOLLOW, "ELF header size"); +#endif + CALL_UTIL (munmap)(p, sz); + return 1; + } + TprintfT (DBG_LT2, "check_fd_dynamic(): elfclass=%d, e_phoff=%lu e_phnum=%lu e_phentsize=%lu\n", + (int) elfclass, (unsigned long) e_phoff, (unsigned long) e_phnum, + (unsigned long) e_phentsize); + int dynamic = 0; + Elf64_Half i; + for (i = 0; i < e_phnum; i++) + { + if (elfclass == ELFCLASS32) + { + if (PT_DYNAMIC == + ((Elf32_Phdr*) (p + e_phoff + e_phentsize * i))->p_type) + { + dynamic = 1; + break; + } + } + else + { + if (PT_DYNAMIC == + ((Elf64_Phdr*) (p + e_phoff + e_phentsize * i))->p_type) + { + dynamic = 1; + break; + } + } + } + if (!dynamic) + { + TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd); +#if 0 + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_NOFOLLOW, "!dynamic"); +#endif + } + else + TprintfT (DBG_LT2, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd); + CALL_UTIL (munmap)(p, sz); + return dynamic; +} + +static int +check_dynamic (const char *execfile) +{ + TprintfT (DBG_LT2, "check_dynamic(%s)\n", execfile); + int fd = CALL_UTIL (open)(execfile, O_RDONLY); + if (fd == -1) + { + TprintfT (DBG_LT0, "check_dynamic(): ERROR/WARNING: Command `%s' could not be opened!\n", execfile); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_RISKYFOLLOW, "open"); + return 1; /* follow, though exec will presumably fail */ + } + int ret = check_fd_dynamic (fd); + CALL_UTIL (close)(fd); + return ret; +} + +static int +path_collectable (const char *execfile) +{ + TprintfT (DBG_LT0, "path_collectable(%s)\n", execfile); + /* Check that execfile exists and is a collectable executable */ + /* logging warning when collection is likely to be unsuccessful */ + /* (if check isn't accurate, generally best not to include it) */ + + if (execfile && !__collector_strchr (execfile, '/')) + { /* got an unqualified name */ + /* XXXX locate execfile on PATH to be able to check it */ + TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't check unqualified executable `%s'\n", execfile); +#if 0 + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_RISKYFOLLOW, "path"); +#endif + return 1; /* follow unqualified execfile unchecked */ + } + struct stat sbuf; + if (stat (execfile, &sbuf)) + { /* can't stat it */ + TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't stat `%s'\n", execfile); +#if 0 + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_RISKYFOLLOW, "stat"); +#endif + return 1; /* follow, though exec will probably fail */ + } + TprintfT (DBG_LT2, "path_collectable(%s) mode=0%o uid=%d gid=%d\n", + execfile, sbuf.st_mode, sbuf.st_uid, sbuf.st_gid); + if (((sbuf.st_mode & S_IXUSR) == 0) || ((sbuf.st_mode & S_IFMT) == S_IFDIR)) + { + TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile); +#if 0 + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_RISKYFOLLOW, "mode"); +#endif + return 1; /* follow, though exec will presumably fail */ + } + /* XXXX setxid(root) is OK iff libcollector is registered as secure */ + /* XXXX setxid(non-root) is OK iff umask is accomodating */ + if (((sbuf.st_mode & S_ISUID) != 0) || ((sbuf.st_mode & S_ISGID) != 0)) + { + TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile); +#if 0 + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_RISKYFOLLOW, "setxid"); +#endif + return 1; /* follow, though collection may be unreliable */ + } + if (!check_dynamic (execfile)) + { + TprintfT (DBG_LT0, "path_collectable(%s) WARNING/ERROR: not dynamic, not collectng!\n", execfile); + return 0; /* don't follow, collection will fail unpredictably */ + } + TprintfT (DBG_LT2, "path_collectable(%s) OK!\n", execfile); + return 1; /* OK to follow */ +} + +static char * +build_experiment_path (char * instring, size_t instring_sz, const char *lineage_str) +{ + TprintfT (DBG_LT0, "build_experiment_path(,%ld, %s)\n", + (long) instring_sz, lineage_str); + const char *p = CALL_UTIL (strstr)(linetrace_exp_dir_name, DESCENDANT_EXPT_KEY); + int basedir_sz; + if (p) + basedir_sz = p - linetrace_exp_dir_name + 4; /* +3 because of DESCENDANT_EXPT_KEY */ + else + basedir_sz = __collector_strlen (linetrace_exp_dir_name) + 1; + int additional_sz = __collector_strlen (lineage_str) + 4; + if (basedir_sz + additional_sz > instring_sz) + { + TprintfT (DBG_LT0, "build_experiment_path(%s,%s): ERROR: path too long: %d > %ld\n", + linetrace_exp_dir_name, lineage_str, + basedir_sz + additional_sz, (long) instring_sz); + *instring = 0; + return NULL; + } + __collector_strlcpy (instring, linetrace_exp_dir_name, basedir_sz); + size_t slen = __collector_strlen (instring); + CALL_UTIL (snprintf)(instring + slen, instring_sz - slen, "/%s.er", lineage_str); + assert (__collector_strlen (instring) + 1 == basedir_sz + additional_sz); + return instring; +} + +static void +check_reuid_change (uid_t ruid, uid_t euid) +{ + uid_t curr_ruid = getuid (); + uid_t curr_euid = geteuid (); + mode_t curr_umask = umask (0); + umask (curr_umask); /* restore original umask */ + int W_oth = !(curr_umask & S_IWOTH); + TprintfT (DBG_LT0, "check_reuid_change(%d,%d): umask=%03o\n", ruid, euid, curr_umask); + TprintfT (DBG_LT0, "check_reuid_change(): umask W usr=%d grp=%d oth=%d\n", + (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth); + if (ruid != -1) + { + TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_ruid, ruid); + if ((curr_euid == 0) && (ruid != 0) && !W_oth) + { + /* changing to non-root ID, with umask blocking writes by other */ + TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after ruid change (%d->%d)\n", + curr_ruid, ruid); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o ruid %d->%d</event>\n", + SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_ruid, ruid); + } + } + if (euid != -1) + { + TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_euid, euid); + if ((curr_euid == 0) && (euid != 0) && !W_oth) + { + /* changing to non-root ID, with umask blocking writes by other */ + TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after euid change (%d->%d)\n", + curr_euid, euid); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o euid %d->%d</event>\n", + SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_euid, euid); + } + } +} + +static void +check_regid_change (gid_t rgid, gid_t egid) +{ + gid_t curr_rgid = getgid (); + gid_t curr_egid = getegid (); + uid_t curr_euid = geteuid (); + mode_t curr_umask = umask (0); + umask (curr_umask); /* restore original umask */ + int W_oth = !(curr_umask & S_IWOTH); + TprintfT (DBG_LT0, "check_regid_change(%d,%d): umask=%03o euid=%d\n", + rgid, egid, curr_umask, curr_euid); + TprintfT (DBG_LT0, "umask W usr=%d grp=%d oth=%d\n", + (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth); + if (rgid != -1) + { + TprintfT (DBG_LT0, "check_regid_change(%d->%d)\n", curr_rgid, rgid); + if ((curr_euid == 0) && (rgid != 0) && !W_oth) + { + /* changing to non-root ID, with umask blocking writes by other */ + TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after rgid change (%d->%d)\n", + curr_rgid, rgid); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o rgid %d->%d</event>\n", + SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_rgid, rgid); + } + } + if (egid != -1) + { + TprintfT (DBG_LT0, "check_regid_change(): check_egid_change(%d->%d)\n", curr_egid, egid); + if ((curr_euid == 0) && (egid != 0) && !W_oth) + { + /* changing to non-root ID, with umask blocking writes by other */ + TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after egid change (%d->%d)\n", + curr_egid, egid); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o egid %d->%d</event>\n", + SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_egid, egid); + } + } +} + +static int +init_lineage_intf () +{ + void *dlflag; + TprintfT (DBG_LT2, "init_lineage_intf()\n"); + + static int nesting_check = 0; + if (nesting_check >= 2) + { + /* segv before stack blows up */ + nesting_check /= (nesting_check - 2); + } + nesting_check++; + + __real_fork = dlsym (RTLD_NEXT, "fork"); + if (__real_fork == NULL) + { + __real_fork = dlsym (RTLD_DEFAULT, "fork"); + if (__real_fork == NULL) + return 1; + dlflag = RTLD_DEFAULT; + } + else + dlflag = RTLD_NEXT; + TprintfT (DBG_LT2, "init_lineage_intf() using RTLD_%s\n", + dlflag == RTLD_DEFAULT ? "DEFAULT" : "NEXT"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_fork\n", __real_fork); + __real_vfork = dlsym (dlflag, "vfork"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_vfork\n", __real_vfork); + __real_execve = dlsym (dlflag, "execve"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execve\n", __real_execve); + __real_execvp = dlsym (dlflag, "execvp"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execvp\n", __real_execvp); + __real_execv = dlsym (dlflag, "execv"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execv\n", __real_execv); + __real_execle = dlsym (dlflag, "execle"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execle\n", __real_execle); + __real_execlp = dlsym (dlflag, "execlp"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execlp\n", __real_execlp); + __real_execl = dlsym (dlflag, "execl"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execl\n", __real_execl); + __real_clone = dlsym (dlflag, "clone"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone); + __real_posix_spawn = dlsym (dlflag, "posix_spawn"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawn\n", + __real_posix_spawn); + __real_posix_spawnp = dlsym (dlflag, "posix_spawnp"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawnp\n", + __real_posix_spawnp); + __real_popen = dlvsym (dlflag, "popen", SYS_POPEN_VERSION); + TprintfT (DBG_LT2, "init_lineage_intf()[%s] @0x%p __real_popen\n", + SYS_POPEN_VERSION, __real_popen); +#if ARCH(Intel) + __real_posix_spawn_2_15 = dlvsym (dlflag, "posix_spawn", SYS_POSIX_SPAWN_VERSION); + __real_posix_spawnp_2_15 = dlvsym (dlflag, "posix_spawnp", SYS_POSIX_SPAWN_VERSION); +#if WSIZE(32) + __real_popen_2_1 = __real_popen; + __real_popen_2_0 = dlvsym (dlflag, "popen", "GLIBC_2.0"); + __real_posix_spawn_2_2 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2"); + __real_posix_spawnp_2_2 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2"); +#elif WSIZE(64) + __real_posix_spawn_2_2_5 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2.5"); + __real_posix_spawnp_2_2_5 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2.5"); +#endif /* WSIZE() */ +#endif /* ARCH(Intel) */ + __real_grantpt = dlsym (dlflag, "grantpt"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_grantpt\n", __real_grantpt); + __real_ptsname = dlsym (dlflag, "ptsname"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_ptsname\n", __real_ptsname); + __real_system = dlsym (dlflag, "system"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_system\n", __real_system); + __real_setuid = dlsym (dlflag, "setuid"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setuid\n", __real_setuid); + __real_seteuid = dlsym (dlflag, "seteuid"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_seteuid\n", __real_seteuid); + __real_setreuid = dlsym (dlflag, "setreuid"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setreuid\n", __real_setreuid); + __real_setgid = dlsym (dlflag, "setgid"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setgid\n", __real_setgid); + __real_setegid = dlsym (dlflag, "setegid"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setegid\n", __real_setegid); + __real_setregid = dlsym (dlflag, "setregid"); + TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setregid\n", __real_setregid); + return 0; +} + +/*------------------------------------------------------------------------ */ +/* Note: The following _prologue and _epilogue functions used to be dbx-visible. + + They are used to appropriately manage lineage-changing events, by + quiescing and re-enabling/re-setting experiment collection before and after, + and logging the lineage-change in the process/experiment undertaking it. + As shown by the interposition functions for fork, exec, etc., which follow, + the _prologue should be called immediately prior (such as a breakpoint + action defined at function entry) and the _epilogue called immediately + after (such as a breakpoint action defined at function return). + */ + +/* + Notes on MT from Solaris 10 man pthread_atfork: + + All multithreaded applications that call fork() in a POSIX + threads program and do more than simply call exec(2) in the + child of the fork need to ensure that the child is protected + from deadlock. + + Since the "fork-one" model results in duplicating only the + thread that called fork(), it is possible that at the time + of the call another thread in the parent owns a lock. This + thread is not duplicated in the child, so no thread will + unlock this lock in the child. Deadlock occurs if the sin- + gle thread in the child needs this lock. + + The problem is more serious with locks in libraries. Since + a library writer does not know if the application using the + library calls fork(), the library must protect itself from + such a deadlock scenario. If the application that links + with this library calls fork() and does not call exec() in + the child, and if it needs a library lock that may be held + by some other thread in the parent that is inside the + library at the time of the fork, the application deadlocks + inside the library. + */ + +static void +linetrace_ext_fork_prologue (const char *variant, char * n_lineage, int *following_fork) +{ + TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n", + variant, n_lineage, *following_fork); + __collector_env_print ("fork_prologue start"); + if (dbg_current_mode != FOLLOW_NONE) + TprintfT (DBG_LT0, "linetrace_ext_fork_prologue(%s) ERROR: dbg_current_mode=%d, changing to FOLLOW_FORK!\n", + variant, dbg_current_mode); + dbg_current_mode = FOLLOW_ON; + if (__collector_strncmp ((char *) variant, "clone", sizeof ("clone") - 1) == 0) + { + __collector_mutex_lock (&clone_lineage_lock); + CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_C%d", curr_lineage, ++clone_linenum); + __collector_mutex_unlock (&clone_lineage_lock); + } + else + { + __collector_mutex_lock (&fork_lineage_lock); + CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_f%d", curr_lineage, ++fork_linenum); + __collector_mutex_unlock (&fork_lineage_lock); + } + *following_fork = check_follow_fork (); + + /* write message before suspending, or it won't be written */ + hrtime_t ts = GETRELTIME (); + TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n", + variant, n_lineage, *following_fork); + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\"/>\n", + SP_JCMD_DESC_START, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + variant, n_lineage, *following_fork); + __collector_ext_dispatcher_thread_timer_suspend (); + __collector_ext_hwc_lwp_suspend (); + __collector_env_print ("fork_prologue end"); +} + +static void +linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * n_lineage, int *following_fork) +{ + if (dbg_current_mode == FOLLOW_NONE) + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) ERROR: dbg_current_mode=%d!\n", + variant, dbg_current_mode); + /* compute descendant experiment name */ + char new_exp_name[LT_MAXPATHLEN]; + /* save exp_name to global var */ + if (!build_experiment_path (new_exp_name, sizeof (new_exp_name), n_lineage)) + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s): ERROR SP_COLLECTOR_EXPNAME not set\n", n_lineage); + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s):%d() returned %d %s; child experiment name = %s\n", + variant, *following_fork, ret, (ret ? "parent" : "child"), new_exp_name); + if (ret == 0) + { + /* *************************************child */ + __collector_env_print ("fork_epilogue child at start"); + /* start a new line */ + fork_linenum = 0; + __collector_mutex_init (&fork_lineage_lock); + clone_linenum = 0; + __collector_mutex_init (&clone_lineage_lock); + __collector_env_update (NULL); + __collector_env_print ("fork_epilogue child after env_update"); + __collector_clean_state (); + __collector_env_print ("fork_epilogue child after clean_slate"); + __collector_line_cleanup (); + __collector_env_print ("fork_epilogue child after line_cleanup"); + if (*following_fork) + { + /* stop recording this experiment, but preserve env vars */ + linetrace_dormant (); + __collector_env_print ("fork_epilogue child after linetrace_dormant"); + + //static char exp_name_env[LT_MAXPATHLEN]; + char * exp_name_env = CALL_UTIL (calloc)(LT_MAXPATHLEN, 1); + CALL_UTIL (snprintf)(exp_name_env, LT_MAXPATHLEN, "%s=%s", SP_COLLECTOR_EXPNAME, new_exp_name); + CALL_UTIL (putenv)(exp_name_env); + + const char *params = CALL_UTIL (getenv)(SP_COLLECTOR_PARAMS); + int ret; + if (new_exp_name == NULL) + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n", + SP_COLLECTOR_EXPNAME); + else if (params == NULL) + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n", + SP_COLLECTOR_PARAMS); + else if ((ret = __collector_open_experiment (new_exp_name, params, SP_ORIGIN_FORK))) + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: '%s' open failed, ret=%d\n", + new_exp_name, ret); + else + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: opened(%s)\n", new_exp_name); + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) returning to *child*\n", variant); + } + else + { + /* disable current and further linetrace experiment resumption */ + TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) child calling line_close\n", variant); + __collector_ext_line_close (); + } + __collector_env_print ("fork_epilogue child at end"); + /* *************************************end child */ + } + else + { + /* *************************************parent */ + __collector_env_print ("fork_epilogue parent at start"); + __collector_ext_dispatcher_thread_timer_resume (); + __collector_ext_hwc_lwp_resume (); + hrtime_t ts = GETRELTIME (); + char msg[256 + LT_MAXPATHLEN]; + if (ret >= 0) + CALL_UTIL (snprintf)(msg, sizeof (msg), "pid=%d", ret); + else + { + /* delete stillborn experiment? */ + char errmsg[256]; + strerror_r (errno, errmsg, sizeof (errmsg)); + CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg); + } + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n", + SP_JCMD_DESC_STARTED, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + variant, n_lineage, *following_fork, msg); + /* environment remains set for collection */ + __collector_env_print ("fork_epilogue parent at end"); + /* *************************************end parent */ + } + dbg_current_mode = FOLLOW_NONE; + *following_fork = 0; +} + +static char** +linetrace_ext_exec_prologue_end (const char *variant, const char* cmd_string, + char *const envp[], int following_exec) +{ + char **coll_env; + TprintfT (DBG_LT0, "linetrace_ext_exec_prologue_end; variant=%s; cmd_string=%s; follow=%d\n", + variant, cmd_string, following_exec); + /* write message before suspending, or it won't be written */ + hrtime_t ts = GETRELTIME (); + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n", + SP_JCMD_EXEC_START, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + variant, new_lineage, following_exec, cmd_string); + if (following_exec) + { + coll_env = __collector_env_allocate (envp, 0); + __collector_env_update (coll_env); + extern char **environ; /* the process' actual environment */ + if (environ == envp) /* user selected process environment */ + environ = coll_env; + } + else + coll_env = (char**) envp; + __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env); + if (!CALL_UTIL (strstr)(variant, "posix_spawn")) + { + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1; + __collector_suspend_experiment ("suspend_for_exec"); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; + } + if (CALL_UTIL (strstr)(variant, "posix_spawn")) + { + __collector_ext_dispatcher_thread_timer_suspend (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1; + __collector_ext_hwc_lwp_suspend (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; + } + return (coll_env); +} + +static char** +linetrace_ext_exec_prologue (const char *variant, + const char* path, char *const argv[], + char *const envp[], int *following_exec) +{ + char cmd_string[_POSIX_ARG_MAX] = {'\0'}; + + if (dbg_current_mode != FOLLOW_NONE) + TprintfT (DBG_LT0, "linetrace_ext_exec_prologue() ERROR: dbg_current_mode=%d, changing to FOLLOW_EXEC!\n", dbg_current_mode); + dbg_current_mode = FOLLOW_ON; + *following_exec = check_follow_exec (path); + if (path != NULL) + { + /* escape any newline, " or \ characters in the exec command */ + TprintfT (DBG_LT3, "linetrace_ext_exec_prologue(): arg0=%s\n", path); + /* leave space in log message for terminator (and header) */ + __collector_strlcpy (cmd_string, path, sizeof (cmd_string)); + size_t len; + unsigned argn = 0; + if (argv[0]) + { + char *p; + while (((p = argv[++argn]) != 0) && + (len = __collector_strlen (cmd_string)) < sizeof (cmd_string) - 2) + { + cmd_string[len++] = ' '; + __collector_strlcpy (cmd_string + len, p, sizeof (cmd_string) - len); + } + } + } + TprintfT (DBG_LT0, "linetrace_ext_exec_prologue(%s), lineage=%s, follow=%d, prog=%s, path=%s \n", + variant, new_lineage, *following_exec, cmd_string, path); + return linetrace_ext_exec_prologue_end (variant, cmd_string, envp, *following_exec); +} + +static void +linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec) +{ + /* For exec, this routine is only entered if the exec failed */ + /* However, posix_spawn() is expected to return */ + if (dbg_current_mode == FOLLOW_NONE) + TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: dbg_current_mode=%d!\n", dbg_current_mode); + TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue(%s):%d returned: %d, errno=%d\n", + variant, *following_exec, ret, errno); + if (!CALL_UTIL (strstr)(variant, "posix_spawn")) + { + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1; + __collector_resume_experiment (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; + } + if (CALL_UTIL (strstr)(variant, "posix_spawn")) + { + __collector_ext_dispatcher_thread_timer_resume (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1; + __collector_ext_hwc_lwp_resume (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; + } + hrtime_t ts = GETRELTIME (); + char msg[256]; + if (ret) + { + char errmsg[256]; + strerror_r (errno, errmsg, sizeof (errmsg)); + CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg); + } + else + CALL_UTIL (snprintf)(msg, sizeof (msg), "rc=%d", ret); + if (!CALL_UTIL (strstr)(variant, "posix_spawn")) + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n", + SP_JCMD_EXEC_ERROR, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + variant, new_lineage, *following_exec, msg); + if (envp == NULL) + TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: envp NULL after %s!\n", variant); + dbg_current_mode = FOLLOW_NONE; + *following_exec = 0; +} + +static void +linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo) +{ + char cmd_string[_POSIX_ARG_MAX] = {'\0'}; + char execfile[_POSIX_ARG_MAX] = {'\0'}; + + if (dbg_current_mode != FOLLOW_NONE) + TprintfT (DBG_LT0, "linetrace_ext_combo_prologue() ERROR: dbg_current_mode=%d! changing to FOLLOW_ON\n", + dbg_current_mode); + dbg_current_mode = FOLLOW_ON; + if (cmd != NULL) + { + /* extract executable name from combo command */ + unsigned len = strcspn (cmd, " "); + __collector_strlcpy (execfile, cmd, len + 1); + + /* escape any newline, " or \ characters in the combo command */ + /* leave space in log message for terminator (and header) */ + __collector_strlcpy (cmd_string, cmd, sizeof (cmd_string)); + } + + *following_combo = check_follow_combo (execfile); + TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(%s) follow=%d, prog=%s\n\n", + variant, *following_combo, cmd_string); + + /* Construct the lineage string for the new image */ + new_lineage[0] = 0; + __collector_strcat (new_lineage, "XXX"); + + /* write message before suspending, or it won't be written */ + hrtime_t ts = GETRELTIME (); + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n", + SP_JCMD_DESC_START, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + variant, new_lineage, *following_combo, cmd_string); + if (*following_combo) + { + __collector_env_update (NULL); + TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant, execfile); + } + __collector_ext_dispatcher_thread_timer_suspend (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1; + __collector_ext_hwc_lwp_suspend (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; +} + +static void +linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo) +{ + if (dbg_current_mode == FOLLOW_NONE) + TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue() ERROR: dbg_current_mode=FOLLOW_NONE\n"); + TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue(%s):%d() returned %d\n", + variant, *following_combo, ret); + __collector_ext_dispatcher_thread_timer_resume (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1; + __collector_ext_hwc_lwp_resume (); + __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0; + hrtime_t ts = GETRELTIME (); + __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" follow=\"%d\" msg=\"rc=%d\"/>\n", + SP_JCMD_DESC_STARTED, + (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC), + variant, *following_combo, ret); + + dbg_current_mode = FOLLOW_NONE; + *following_combo = 0; +} + +/*------------------------------------------------------------- fork */ +pid_t fork () __attribute__ ((weak, alias ("__collector_fork"))); +pid_t _fork () __attribute__ ((weak, alias ("__collector_fork"))); + +pid_t +__collector_fork (void) +{ + pid_t ret; + if (NULL_PTR (fork)) + { + TprintfT (DBG_LT0, "__collector_fork() calling init_lineage_intf()\n"); + init_lineage_intf (); + } + __collector_env_print ("__collector_fork start"); + int * guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + TprintfT (DBG_LT0, "__collector_fork() interposition: line_mode=%d combo=%d\n", + line_mode, combo_flag); + if ((line_mode != LM_TRACK_LINEAGE) || combo_flag) + { + TprintfT (DBG_LT0, "__collector_fork() not following, returning CALL_REAL(fork)()\n"); + return CALL_REAL (fork)(); + } + int following_fork = 0; + linetrace_ext_fork_prologue ("fork", new_lineage, &following_fork); + + /* since libpthread/fork ends up calling fork1, it's a combo */ + PUSH_REENTRANCE (guard); + ret = CALL_REAL (fork)(); + POP_REENTRANCE (guard); + linetrace_ext_fork_epilogue ("fork", ret, new_lineage, &following_fork); + return ret; +} + +/*------------------------------------------------------------- vfork */ +/* vfork interposition in the usual sense is not possible, since vfork(2) + relies on specifics of the stack frames in the parent and child which + only work when the child's exec (or _exit) are in the same stack frame + as the vfork: this isn't the case when there's interposition on exec. + As a workaround, the interposing vfork calls fork1 instead of the real + vfork. Note that fork1 is somewhat less efficient than vfork, and requires + additional memory, which may result in a change of application behaviour + when libcollector is loaded (even when collection is not active), + affecting not only direct use of vfork by the subject application, + but also indirect use through system, popen, and the other combos. + */ +pid_t vfork () __attribute__ ((weak, alias ("__collector_vfork"))); +pid_t _vfork () __attribute__ ((weak, alias ("__collector_vfork"))); + +pid_t +__collector_vfork (void) +{ + if (NULL_PTR (vfork)) + init_lineage_intf (); + + int * guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + + TprintfT (DBG_LT0, "__collector_vfork() interposing: line_mode=%d combo=%d\n", + line_mode, combo_flag); + if ((line_mode != LM_TRACK_LINEAGE) || combo_flag) + return CALL_REAL (fork)(); + + /* this warning is also appropriate for combos which use vfork, + however, let's assume this is achieved elsewhere */ + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN, + COL_WARN_VFORK, "fork"); + + char new_lineage[LT_MAXNAMELEN]; + new_lineage[0] = 0; + int following_fork = 0; + linetrace_ext_fork_prologue ("vfork", new_lineage, &following_fork); + + pid_t ret = CALL_REAL (fork)(); + linetrace_ext_fork_epilogue ("vfork", ret, new_lineage, &following_fork); + return ret; +} + +/*------------------------------------------------------------- execve */ +int execve () __attribute__ ((weak, alias ("__collector_execve"))); + +int +__collector_execve (const char* path, char *const argv[], char *const envp[]) +{ + static char **coll_env = NULL; /* environment for collection */ + if (NULL_PTR (execve)) + init_lineage_intf (); + int * guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + TprintfT (DBG_LT0, + "__collector_execve(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n", + path ? path : "NULL", + argv ? (argv[0] ? argv[0] : "NULL") : "NULL", + envp ? (envp[0] ? envp[0] : "NULL") : "NULL", + line_mode, combo_flag); + if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */ + __collector_env_unset ((char**) envp); + if (line_mode != LM_TRACK_LINEAGE || combo_flag) + return CALL_REAL (execve)(path, argv, envp); + + int following_exec = 0; + coll_env = linetrace_ext_exec_prologue ("execve", path, argv, envp, &following_exec); + TprintfT (DBG_LT2, "__collector_execve(): coll_env=0x%p\n", coll_env); + __collector_env_printall ("__collector_execve", coll_env); + int ret = CALL_REAL (execve)(path, argv, coll_env); + linetrace_ext_exec_epilogue ("execve", envp, ret, &following_exec); + return ret; +} + +int execvp () __attribute__ ((weak, alias ("__collector_execvp"))); + +int +__collector_execvp (const char* file, char *const argv[]) +{ + extern char **environ; /* the process' actual environment */ + char ** envp = environ; + if (NULL_PTR (execvp)) + init_lineage_intf (); + int * guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + TprintfT (DBG_LT0, + "__collector_execvp(file=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n", + file ? file : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", + line_mode, combo_flag); + if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */ + __collector_env_unset ((char**) envp); + if ((line_mode != LM_TRACK_LINEAGE) || combo_flag) + return CALL_REAL (execvp)(file, argv); + + int following_exec = 0; +#ifdef DEBUG + char **coll_env = /* environment for collection */ +#endif /* DEBUG */ + linetrace_ext_exec_prologue ("execvp", file, argv, envp, &following_exec); + TprintfT (DBG_LT0, "__collector_execvp(): coll_env=0x%p\n", coll_env); + + int ret = CALL_REAL (execvp)(file, argv); + linetrace_ext_exec_epilogue ("execvp", envp, ret, &following_exec); + return ret; +} + +int execv () __attribute__ ((weak, alias ("__collector_execv"))); + +int +__collector_execv (const char* path, char *const argv[]) +{ + int ret; + extern char **environ; /* the process' actual environment */ + char ** envp = environ; + TprintfT (DBG_LT0, "__collector_execv(path=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n", + path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", + line_mode, get_combo_flag ()); + + ret = __collector_execve (path, argv, envp); + return ret; +} + +int execle (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execle"))); + +int +__collector_execle (const char* path, const char *arg0, ...) +{ + TprintfT (DBG_LT0, + "__collector_execle(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n", + path ? path : "NULL", arg0 ? arg0 : "NULL", + line_mode, get_combo_flag ()); + + char **argp; + va_list args; + char **argvec; + register char **environmentp; + int nargs = 0; + char *nextarg; + + va_start (args, arg0); + while (va_arg (args, char *) != (char *) 0) + nargs++; + + /* + * save the environment pointer, which is at the end of the + * variable argument list + */ + environmentp = va_arg (args, char **); + va_end (args); + + /* + * load the arguments in the variable argument list + * into the argument vector, and add the terminating null pointer + */ + va_start (args, arg0); + /* workaround for bugid 1242839 */ + argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *))); + argp = argvec; + *argp++ = (char *) arg0; + while ((nextarg = va_arg (args, char *)) != (char *) 0) + *argp++ = nextarg; + va_end (args); + *argp = (char *) 0; + return __collector_execve (path, argvec, environmentp); +} + +int execlp (const char* file, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execlp"))); + +int +__collector_execlp (const char* file, const char *arg0, ...) +{ + TprintfT (DBG_LT0, + "__collector_execlp(file=%s, arg0=%s) interposing: line_mode=%d combo=%d\n", + file ? file : "NULL", arg0 ? arg0 : "NULL", + line_mode, get_combo_flag ()); + char **argp; + va_list args; + char **argvec; + int nargs = 0; + char *nextarg; + + va_start (args, arg0); + while (va_arg (args, char *) != (char *) 0) + nargs++; + va_end (args); + + /* + * load the arguments in the variable argument list + * into the argument vector and add the terminating null pointer + */ + va_start (args, arg0); + + /* workaround for bugid 1242839 */ + argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *))); + argp = argvec; + *argp++ = (char *) arg0; + while ((nextarg = va_arg (args, char *)) != (char *) 0) + *argp++ = nextarg; + va_end (args); + *argp = (char *) 0; + return __collector_execvp (file, argvec); +} + +int execl (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execl"))); + +int +__collector_execl (const char* path, const char *arg0, ...) +{ + TprintfT (DBG_LT0, + "__collector_execl(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n", + path ? path : "NULL", arg0 ? arg0 : "NULL", + line_mode, get_combo_flag ()); + char **argp; + va_list args; + char **argvec; + extern char **environ; + int nargs = 0; + char *nextarg; + va_start (args, arg0); + while (va_arg (args, char *) != (char *) 0) + nargs++; + va_end (args); + + /* + * load the arguments in the variable argument list + * into the argument vector and add the terminating null pointer + */ + va_start (args, arg0); + + /* workaround for bugid 1242839 */ + argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *))); + argp = argvec; + *argp++ = (char *) arg0; + while ((nextarg = va_arg (args, char *)) != (char *) 0) + *argp++ = nextarg; + va_end (args); + *argp = (char *) 0; + return __collector_execve (path, argvec, environ); +} + +#include <spawn.h> + +/*-------------------------------------------------------- posix_spawn */ +#if ARCH(Intel) +// map interposed symbol versions +static int +__collector_posix_spawn_symver (int(real_posix_spawn) (), + pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]); + +int +__collector_posix_spawn_2_15 (pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n", + CALL_REAL (posix_spawn_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL"); + if (NULL_PTR (posix_spawn)) + init_lineage_intf (); + return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_15), pidp, + path, file_actions, attrp, argv, envp); +} + +__asm__(".symver __collector_posix_spawn_2_15,posix_spawn@@GLIBC_2.15"); + +#if WSIZE(32) +int +__collector_posix_spawn_2_2 (pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n", + CALL_REAL (posix_spawn_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL"); + if (NULL_PTR (posix_spawn)) + init_lineage_intf (); + return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2), pidp, + path, file_actions, attrp, argv, envp); +} + +__asm__(".symver __collector_posix_spawn_2_2,posix_spawn@GLIBC_2.2"); + +#else /* ^WSIZE(32) */ +int +__collector_posix_spawn_2_2_5 (pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n", + CALL_REAL (posix_spawn_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL"); + if (NULL_PTR (posix_spawn)) + init_lineage_intf (); + return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2_5), pidp, + path, file_actions, attrp, argv, envp); +} + +__asm__(".symver __collector_posix_spawn_2_2_5,posix_spawn@GLIBC_2.2.5"); +#endif /* ^WSIZE(32) */ + +static int +__collector_posix_spawn_symver (int(real_posix_spawn) (), +#else /* ^ARCH(Intel) */ +int +__collector_posix_spawn ( +#endif /* ARCH() */ + pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + int ret; + static char **coll_env = NULL; /* environment for collection */ + if (NULL_PTR (posix_spawn)) + init_lineage_intf (); + if (NULL_PTR (posix_spawn)) + { + TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s) interposing: ERROR, posix_spawn() not found by dlsym\n", + path ? path : "NULL"); + return -1; /* probably should set errno */ + } + int * guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n", + path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag); + if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */ + __collector_env_unset ((char**) envp); + + if ((line_mode != LM_TRACK_LINEAGE) || combo_flag) + { +#if ARCH(Intel) + return (real_posix_spawn) (pidp, path, file_actions, attrp, argv, envp); +#else + return CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, envp); +#endif + } + int following_exec = 0; + coll_env = linetrace_ext_exec_prologue ("posix_spawn", path, argv, envp, &following_exec); + TprintfT (DBG_LT0, "__collector_posix_spawn(): coll_env=0x%p\n", coll_env); + __collector_env_printall ("__collector_posix_spawn", coll_env); + PUSH_REENTRANCE (guard); +#if ARCH(Intel) + ret = (real_posix_spawn) (pidp, path, file_actions, attrp, argv, coll_env); +#else + ret = CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, coll_env); +#endif + POP_REENTRANCE (guard); + linetrace_ext_exec_epilogue ("posix_spawn", envp, ret, &following_exec); + return ret; +} + +/*-------------------------------------------------------- posix_spawnp */ +#if ARCH(Intel) +// map interposed symbol versions + +static int +__collector_posix_spawnp_symver (int(real_posix_spawnp) (), pid_t *pidp, + const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]); + +int // Common interposition +__collector_posix_spawnp_2_15 (pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n", + CALL_REAL (posix_spawnp_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL"); + if (NULL_PTR (posix_spawnp)) + init_lineage_intf (); + return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_15), pidp, + path, file_actions, attrp, argv, envp); +} + +__asm__(".symver __collector_posix_spawnp_2_15,posix_spawnp@@GLIBC_2.15"); + +#if WSIZE(32) + +int +__collector_posix_spawnp_2_2 (pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n", + CALL_REAL (posix_spawnp_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL"); + if (NULL_PTR (posix_spawnp)) + init_lineage_intf (); + return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2), pidp, + path, file_actions, attrp, argv, envp); +} + +__asm__(".symver __collector_posix_spawnp_2_2,posix_spawnp@GLIBC_2.2"); + +#else /* ^WSIZE(32) */ +int +__collector_posix_spawnp_2_2_5 (pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]) +{ + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n", + CALL_REAL (posix_spawnp_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL"); + if (NULL_PTR (posix_spawnp)) + init_lineage_intf (); + return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2_5), pidp, + path, file_actions, attrp, argv, envp); +} + +__asm__(".symver __collector_posix_spawnp_2_2_5,posix_spawnp@GLIBC_2.2.5"); + +#endif /* ^WSIZE(32) */ + +static int +__collector_posix_spawnp_symver (int(real_posix_spawnp) (), +#else /* ^ARCH(Intel) */ +int +__collector_posix_spawnp ( +#endif /* ARCH() */ + pid_t *pidp, const char *path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, + char *const argv[], char *const envp[]){ + int ret; + static char **coll_env = NULL; /* environment for collection */ + if (NULL_PTR (posix_spawnp)) + init_lineage_intf (); + if (NULL_PTR (posix_spawnp)) + { + TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s) interposing: ERROR, posix_spawnp() not found by dlsym\n", + path ? path : "NULL"); + return -1; /* probably should set errno */ + } + int * guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n", + path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", + envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag); + + if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */ + __collector_env_unset ((char**) envp); + if (line_mode != LM_TRACK_LINEAGE || combo_flag) + { +#if ARCH(Intel) + return (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, envp); +#else + return CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, envp); +#endif + } + int following_exec = 0; + coll_env = linetrace_ext_exec_prologue ("posix_spawnp", path, argv, envp, &following_exec); + TprintfT (DBG_LT0, "__collector_posix_spawnp(): coll_env=0x%p\n", coll_env); + __collector_env_printall ("__collector_posix_spawnp", coll_env); + PUSH_REENTRANCE (guard); +#if ARCH(Intel) + ret = (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, coll_env); +#else + ret = CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, coll_env); +#endif + POP_REENTRANCE (guard); + linetrace_ext_exec_epilogue ("posix_spawnp", envp, ret, &following_exec); + return ret; +} + +/*------------------------------------------------------------- system */ +int system () __attribute__ ((weak, alias ("__collector_system"))); + +int +__collector_system (const char *cmd) +{ + if (NULL_PTR (system)) + init_lineage_intf (); + TprintfT (DBG_LT0, + "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n", + cmd ? cmd : "NULL", line_mode, get_combo_flag ()); + int *guard = NULL; + if (line_mode == LM_TRACK_LINEAGE) + INIT_REENTRANCE (guard); + if (guard == NULL) + return CALL_REAL (system)(cmd); + int following_combo = 0; + linetrace_ext_combo_prologue ("system", cmd, &following_combo); + PUSH_REENTRANCE (guard); + int ret = CALL_REAL (system)(cmd); + POP_REENTRANCE (guard); + linetrace_ext_combo_epilogue ("system", ret, &following_combo); + return ret; +} + +/*------------------------------------------------------------- popen */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) +static FILE * +__collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode); + +FILE * +__collector_popen_2_1 (const char *cmd, const char *mode) +{ + if (NULL_PTR (popen)) + init_lineage_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_1@%p\n", CALL_REAL (popen_2_1)); + return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode); +} + +FILE * +__collector_popen_2_0 (const char *cmd, const char *mode) +{ + if (NULL_PTR (popen)) + init_lineage_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_0@%p\n", CALL_REAL (popen_2_0)); + return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode); +} + +FILE * +__collector__popen_2_1 (const char *cmd, const char *mode) +{ + if (NULL_PTR (popen)) + init_lineage_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector__popen_2_1@%p\n", CALL_REAL (popen_2_1)); + return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode); +} + +FILE * +__collector__popen_2_0 (const char *cmd, const char *mode) +{ + if (NULL_PTR (popen)) + init_lineage_intf (); + return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode); +} + +__asm__(".symver __collector_popen_2_1,popen@@GLIBC_2.1"); +__asm__(".symver __collector_popen_2_0,popen@GLIBC_2.0"); +__asm__(".symver __collector__popen_2_1,_popen@@GLIBC_2.1"); +__asm__(".symver __collector__popen_2_0,_popen@GLIBC_2.0"); +#else // WSIZE(64) +FILE * popen () __attribute__ ((weak, alias ("__collector_popen"))); +#endif + +#if ARCH(Intel) && WSIZE(32) +static FILE * +__collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode) +#else + +FILE * +__collector_popen (const char *cmd, const char *mode) +#endif +{ + FILE *ret; + if (NULL_PTR (popen)) + init_lineage_intf (); + TprintfT (DBG_LT0, + "__collector_popen(cmd=%s) interposing: line_mode=%d combo=%d\n", + cmd ? cmd : "NULL", line_mode, get_combo_flag ()); + int *guard = NULL; + if (line_mode == LM_TRACK_LINEAGE) + INIT_REENTRANCE (guard); + if (guard == NULL) + { +#if ARCH(Intel) && WSIZE(32) + return (real_popen) (cmd, mode); +#else + return CALL_REALF (popen)(cmd, mode); +#endif + } + int following_combo = 0; + linetrace_ext_combo_prologue ("popen", cmd, &following_combo); + PUSH_REENTRANCE (guard); +#if ARCH(Intel) && WSIZE(32) + ret = (real_popen) (cmd, mode); +#else + ret = CALL_REALF (popen)(cmd, mode); +#endif + POP_REENTRANCE (guard); + linetrace_ext_combo_epilogue ("popen", (ret == NULL) ? (-1) : 0, &following_combo); + return ret; +} + +/*------------------------------------------------------------- grantpt */ +int grantpt () __attribute__ ((weak, alias ("__collector_grantpt"))); + +int +__collector_grantpt (const int fildes) +{ + if (NULL_PTR (grantpt)) + init_lineage_intf (); + TprintfT (DBG_LT0, + "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n", + fildes, line_mode, get_combo_flag ()); + int *guard = NULL; + if (line_mode == LM_TRACK_LINEAGE) + INIT_REENTRANCE (guard); + if (guard == NULL) + return CALL_REAL (grantpt)(fildes); + int following_combo = 0; + linetrace_ext_combo_prologue ("grantpt", "/usr/lib/pt_chmod", &following_combo); + PUSH_REENTRANCE (guard); + int ret = CALL_REAL (grantpt)(fildes); + POP_REENTRANCE (guard); + linetrace_ext_combo_epilogue ("grantpt", ret, &following_combo); + return ret; +} + +/*------------------------------------------------------------- ptsname */ +char *ptsname () __attribute__ ((weak, alias ("__collector_ptsname"))); + +char * +__collector_ptsname (const int fildes) +{ + if (NULL_PTR (ptsname)) + init_lineage_intf (); + TprintfT (DBG_LT0, + "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n", + fildes, line_mode, get_combo_flag ()); + int *guard = NULL; + if (line_mode == LM_TRACK_LINEAGE) + INIT_REENTRANCE (guard); + if (guard == NULL) + return CALL_REALC (ptsname)(fildes); + int following_combo = 0; + linetrace_ext_combo_prologue ("ptsname", "/usr/lib/pt_chmod", &following_combo); + PUSH_REENTRANCE (guard); + char *ret = CALL_REALC (ptsname)(fildes); + POP_REENTRANCE (guard); + linetrace_ext_combo_epilogue ("ptsname", (ret == NULL) ? (-1) : 1, &following_combo); + return ret; +} + +/*------------------------------------------------------------- clone */ +/* clone can be fork-like or pthread_create-like, depending on whether + * the flag CLONE_VM is set. If CLONE_VM is not set, then we interpose + * clone in the way similar to interposing fork; if CLONE_VM is set, + * then we interpose clone in the way similar to interposing pthread_create. + * One special case is not handled: when CLONE_VM is set but CLONE_THREAD + * is not, if the parent process exits earlier than the child process, + * experiment will close, losing data from child process. + */ +typedef struct __collector_clone_arg +{ + int (*fn)(void *); + void * arg; + char * new_lineage; + int following_fork; +} __collector_clone_arg_t; + +static int +__collector_clone_fn (void *fn_arg) +{ + int (*fn)(void *) = ((__collector_clone_arg_t*) fn_arg)->fn; + void * arg = ((__collector_clone_arg_t*) fn_arg)->arg; + char * new_lineage = ((__collector_clone_arg_t*) fn_arg)->new_lineage; + int following_fork = ((__collector_clone_arg_t*) fn_arg)->following_fork; + __collector_freeCSize (__collector_heap, fn_arg, sizeof (__collector_clone_arg_t)); + linetrace_ext_fork_epilogue ("clone", 0, new_lineage, &following_fork); + return fn (arg); +} + +int clone (int (*fn)(void *), void *, int, void *, ...) __attribute__ ((weak, alias ("__collector_clone"))); + +int +__collector_clone (int (*fn)(void *), void *child_stack, int flags, void *arg, + ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */) +{ + int ret; + va_list va; + if (flags & CLONE_VM) + { + va_start (va, arg); + ret = __collector_ext_clone_pthread (fn, child_stack, flags, arg, va); + va_end (va); + } + else + { + if (NULL_PTR (clone)) + init_lineage_intf (); + int *guard = NULL; + int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0; + TprintfT (DBG_LT0, "__collector_clone() interposition: line_mode=%d combo=%d\n", + line_mode, combo_flag); + char new_lineage[LT_MAXNAMELEN]; + int following_fork = 0; + __collector_clone_arg_t *funcinfo = __collector_allocCSize (__collector_heap, sizeof (__collector_clone_arg_t), 1); + (*funcinfo).fn = fn; + (*funcinfo).arg = arg; + (*funcinfo).new_lineage = new_lineage; + (*funcinfo).following_fork = 0; + pid_t * ptid = NULL; + struct user_desc * tls = NULL; + pid_t * ctid = NULL; + int num_args = 0; + va_start (va, arg); + if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) + { + ptid = va_arg (va, pid_t *); + tls = va_arg (va, struct user_desc*); + ctid = va_arg (va, pid_t *); + num_args = 3; + } + else if (flags & CLONE_SETTLS) + { + ptid = va_arg (va, pid_t *); + tls = va_arg (va, struct user_desc*); + num_args = 2; + } + else if (flags & CLONE_PARENT_SETTID) + { + ptid = va_arg (va, pid_t *); + num_args = 1; + } + if ((line_mode != LM_TRACK_LINEAGE) || combo_flag || funcinfo == NULL) + { + switch (num_args) + { + case 3: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid); + break; + case 2: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls); + break; + case 1: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid); + break; + default: + ret = CALL_REAL (clone)(fn, child_stack, flags, arg); + break; + } + + va_end (va); + return ret; + } + linetrace_ext_fork_prologue ("clone", new_lineage, &following_fork); + (*funcinfo).following_fork = following_fork; + switch (num_args) + { + case 3: + ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls, ctid); + break; + case 2: + ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls); + break; + case 1: + ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid); + break; + default: + ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo); + break; + } + va_end (va); + if (ret < 0) + __collector_freeCSize (__collector_heap, funcinfo, sizeof (__collector_clone_arg_t)); + TprintfT (DBG_LT0, "__collector_clone() interposing: pid=%d\n", ret); + linetrace_ext_fork_epilogue ("clone", ret, new_lineage, &following_fork); + } + return ret; +} + +/*-------------------------------------------------------------------- setuid */ +int setuid () __attribute__ ((weak, alias ("__collector_setuid"))); +int _setuid () __attribute__ ((weak, alias ("__collector_setuid"))); + +int +__collector_setuid (uid_t ruid) +{ + if (NULL_PTR (setuid)) + init_lineage_intf (); + TprintfT (DBG_LT0, "__collector_setuid(0x%x) interposing\n", ruid); + check_reuid_change (ruid, -1); + int ret = CALL_REAL (setuid)(ruid); + TprintfT (DBG_LT0, "__collector_setuid(0x%x) returning %d\n", ruid, ret); + return ret; +} + +/*------------------------------------------------------------------- seteuid */ +int seteuid () __attribute__ ((weak, alias ("__collector_seteuid"))); +int _seteuid () __attribute__ ((weak, alias ("__collector_seteuid"))); + +int +__collector_seteuid (uid_t euid) +{ + if (NULL_PTR (seteuid)) + init_lineage_intf (); + TprintfT (DBG_LT0, "__collector_seteuid(0x%x) interposing\n", euid); + check_reuid_change (-1, euid); + int ret = CALL_REAL (seteuid)(euid); + TprintfT (DBG_LT0, "__collector_seteuid(0x%x) returning %d\n", euid, ret); + return ret; +} + +/*------------------------------------------------------------------ setreuid */ +int setreuid () __attribute__ ((weak, alias ("__collector_setreuid"))); +int _setreuid () __attribute__ ((weak, alias ("__collector_setreuid"))); + +int +__collector_setreuid (uid_t ruid, uid_t euid) +{ + if (NULL_PTR (setreuid)) + init_lineage_intf (); + TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) interposing\n", ruid, euid); + check_reuid_change (ruid, euid); + int ret = CALL_REAL (setreuid)(ruid, euid); + TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) returning %d\n", ruid, euid, ret); + return ret; +} + +/*-------------------------------------------------------------------- setgid */ +int setgid () __attribute__ ((weak, alias ("__collector_setgid"))); +int _setgid () __attribute__ ((weak, alias ("__collector_setgid"))); + +int +__collector_setgid (gid_t rgid) +{ + if (NULL_PTR (setgid)) + init_lineage_intf (); + TprintfT (DBG_LT0, "__collector_setgid(0x%x) interposing\n", rgid); + check_regid_change (rgid, -1); + int ret = CALL_REAL (setgid)(rgid); + TprintfT (DBG_LT0, "__collector_setgid(0x%x) returning %d\n", rgid, ret); + return ret; +} + +/*------------------------------------------------------------------- setegid */ +int setegid () __attribute__ ((weak, alias ("__collector_setegid"))); +int _setegid () __attribute__ ((weak, alias ("__collector_setegid"))); + +int +__collector_setegid (gid_t egid) +{ + if (NULL_PTR (setegid)) + init_lineage_intf (); + TprintfT (DBG_LT0, "__collector_setegid(0x%x) interposing\n", egid); + check_regid_change (-1, egid); + int ret = CALL_REAL (setegid)(egid); + TprintfT (DBG_LT0, "__collector_setegid(0x%x) returning %d\n", egid, ret); + return ret; +} + +/*------------------------------------------------------------------ setregid */ +int setregid () __attribute__ ((weak, alias ("__collector_setregid"))); +int _setregid () __attribute__ ((weak, alias ("__collector_setregid"))); + +int +__collector_setregid (gid_t rgid, gid_t egid) +{ + if (NULL_PTR (setregid)) + init_lineage_intf (); + TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) interposing\n", rgid, egid); + check_regid_change (rgid, egid); + int ret = CALL_REAL (setregid)(rgid, egid); + TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) returning %d\n", rgid, egid, ret); + return ret; +} + +/*------------------------------------------------------- selective following */ + +static int +linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *progname) +{ + regex_t regex_desc; + if (!follow_spec) + { + TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n"); + return 1; + } + int ercode = regcomp (®ex_desc, follow_spec, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); + if (ercode) + { + // syntax error in parsing string +#ifdef DEBUG + char errbuf[256]; + regerror (ercode, ®ex_desc, errbuf, sizeof (errbuf)); + TprintfT (DBG_LT0, "linetrace_follow_experiment: regerror()=%s\n", errbuf); +#endif + return 1; + } + TprintfT (DBG_LT0, "linetrace_follow_experiment(): compiled spec='%s'\n", follow_spec); + if (lineage_str) + { + if (!regexec (®ex_desc, lineage_str, 0, NULL, 0)) + { + TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES lineage (follow_spec=%s,lineage=%s)\n", + follow_spec, lineage_str); + return 1; + } + } + if (progname) + { + if (!regexec (®ex_desc, progname, 0, NULL, 0)) + { + TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES progname (follow_spec=%s,progname=%s)\n", + follow_spec, progname); + return 1; + } + } + TprintfT (DBG_LT0, "linetrace_follow_experiment(): DOES NOT MATCH (follow_spec=%s,lineage=%s,progname=%s)\n", + follow_spec, lineage_str ? lineage_str : "NULL", + progname ? progname : "NULL"); + return 0; +} diff --git a/gprofng/libcollector/mapfile.aarch64-Linux b/gprofng/libcollector/mapfile.aarch64-Linux new file mode 100644 index 0000000..84d6bbc --- /dev/null +++ b/gprofng/libcollector/mapfile.aarch64-Linux @@ -0,0 +1,40 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +GLIBC_2.17 { + global: + posix_spawn; + posix_spawnp; + pthread_mutex_lock; + pthread_mutex_unlock; + pthread_join; + sem_wait; + pthread_create; + dlopen; + popen; + timer_create; + pthread_cond_wait; + pthread_cond_timedwait; + fopen; + fclose; + fdopen; + fgetpos; + fsetpos; +}; diff --git a/gprofng/libcollector/mapfile.amd64-Linux b/gprofng/libcollector/mapfile.amd64-Linux new file mode 100644 index 0000000..213061f --- /dev/null +++ b/gprofng/libcollector/mapfile.amd64-Linux @@ -0,0 +1,79 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +GLIBC_2.2.5 { + global: + posix_spawn; + posix_spawnp; + pthread_mutex_lock; + pthread_mutex_unlock; + pthread_join; + sem_wait; + pthread_create; + dlopen; + popen; + timer_create; + pthread_cond_wait; + pthread_cond_timedwait; + fopen; + fclose; + fdopen; + fgetpos; + fsetpos; +}; + +GLIBC_2.3.2 { + global: + pthread_cond_wait; + pthread_cond_timedwait; +}; + +GLIBC_2.3.3 { + global: + timer_create; +}; + +GLIBC_2.15 { + global: + posix_spawn; + posix_spawnp; +}; + +GLIBC_2.17 { + global: + posix_spawn; + posix_spawnp; + pthread_mutex_lock; + pthread_mutex_unlock; + pthread_join; + sem_wait; + pthread_create; + dlopen; + popen; + timer_create; + pthread_cond_wait; + pthread_cond_timedwait; + fopen; + fclose; + fdopen; + fgetpos; + fsetpos; +}; + diff --git a/gprofng/libcollector/mapfile.intel-Linux b/gprofng/libcollector/mapfile.intel-Linux new file mode 100644 index 0000000..97482d2 --- /dev/null +++ b/gprofng/libcollector/mapfile.intel-Linux @@ -0,0 +1,81 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +GLIBC_2.0 { + global: + pthread_mutex_lock; + pthread_mutex_unlock; + pthread_join; + pthread_create; + dlopen; + popen; + sem_wait; + pthread_cond_wait; + pthread_cond_timedwait; + fopen; + fclose; + fdopen; + fgetpos; + fsetpos; +}; + +GLIBC_2.1 { + global: + sem_wait; + pthread_create; + dlopen; + open64; + pread; + pwrite; + pwrite64; + popen; + fopen; + fclose; + fdopen; + fgetpos64; + fsetpos64; +}; + +GLIBC_2.2 { + global: + open64; + posix_spawn; + posix_spawnp; + pread; + pwrite; + pwrite64; + timer_create; + fgetpos; + fsetpos; + fgetpos64; + fsetpos64; +}; + +GLIBC_2.3.2 { + global: + pthread_cond_wait; + pthread_cond_timedwait; +}; + +GLIBC_2.15 { + global: + posix_spawn; + posix_spawnp; +}; diff --git a/gprofng/libcollector/mapfile.sparc-Linux b/gprofng/libcollector/mapfile.sparc-Linux new file mode 100644 index 0000000..30d3953 --- /dev/null +++ b/gprofng/libcollector/mapfile.sparc-Linux @@ -0,0 +1,40 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +GLIBC_2.0 { + global: + pthread_mutex_lock; + pthread_mutex_unlock; + pthread_join; +}; + +GLIBC_2.1 { + global: + sem_wait; + pthread_create; + dlopen; + popen; +}; + +GLIBC_2.3.2 { + global: + pthread_cond_wait; + pthread_cond_timedwait; +}; diff --git a/gprofng/libcollector/mapfile.sparcv9-Linux b/gprofng/libcollector/mapfile.sparcv9-Linux new file mode 100644 index 0000000..db79766 --- /dev/null +++ b/gprofng/libcollector/mapfile.sparcv9-Linux @@ -0,0 +1,58 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +GLIBC_2.0 { + global: + dlopen; +}; + +GLIBC_2.1 { + global: + dlopen; +}; + +GLIBC_2.2 { + global: + pthread_create; + popen; + pthread_mutex_lock; + pthread_mutex_unlock; + pthread_join; + sem_wait; + pthread_cond_wait; + pthread_cond_timedwait; + timer_create; + fopen; + fclose; + fdopen; + fgetpos; + fsetpos; +}; + +GLIBC_2.3.2 { + global: + pthread_cond_wait; + pthread_cond_timedwait; +}; + +GLIBC_2.3.3 { + global: + timer_create; +}; diff --git a/gprofng/libcollector/memmgr.c b/gprofng/libcollector/memmgr.c new file mode 100644 index 0000000..5ada421 --- /dev/null +++ b/gprofng/libcollector/memmgr.c @@ -0,0 +1,396 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <sys/mman.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "collector.h" +#include "libcol_util.h" +#include "gp-experiment.h" +#include "memmgr.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 +#define DBG_LT4 4 + +/* + * Memory allocation. + * + * Heap: + * chain[0] - linked list of chunks; + * chain[1] - linked list of free 16-byte objects; + * chain[2] - linked list of free 32-byte objects; + * ... + * + * Chunk: + * + * base lo hi + * V V V + * +------------------+---------+-------------------+--+--+-----+ + * | Var size object | -> <-| Const size objects| | |Chunk| + * +------------------+---------+-------------------+--+--+-----+ + * + * Limitations: + * - one var size object per chunk + * - can't allocate const size objects larger than 2^MAXCHAIN + */ + +#define MAXCHAIN 32 +#define ALIGNMENT 4 /* 2^ALIGNMENT == minimal size and alignment */ +#define ALIGN(x) ((((x) - 1)/(1 << ALIGNMENT) + 1) * (1 << ALIGNMENT)) + +struct Heap +{ + collector_mutex_t lock; /* master lock */ + void *chain[MAXCHAIN]; /* chain[0] - chunks */ + /* chain[i] - structs of size 2^i */ +}; + +typedef struct Chunk +{ + size_t size; + char *base; + char *lo; + char *hi; + struct Chunk *next; +} Chunk; + +static void +not_implemented () +{ + __collector_log_write ("<event kind=\"%s\" id=\"%d\">error memmgr not_implemented()</event>\n", + SP_JCMD_CERROR, COL_ERROR_NOZMEM); + return; +} + +/* + * void __collector_mmgr_init_mutex_locks( Heap *heap ) + * Iinitialize mmgr mutex locks. + */ +void +__collector_mmgr_init_mutex_locks (Heap *heap) +{ + if (heap == NULL) + return; + if (__collector_mutex_trylock (&heap->lock)) + { + /* + * We are in a child process immediately after the fork(). + * Parent process was in the middle of critical section when the fork() happened. + * This is a placeholder for the cleanup. + * See CR 6997020 for details. + */ + __collector_mutex_init (&heap->lock); + } + __collector_mutex_init (&heap->lock); +} + +/* + * alloc_chunk( unsigned sz ) allocates a chunk of at least sz bytes. + * If sz == 0, allocates a chunk of the default size. + */ +static Chunk * +alloc_chunk (unsigned sz, int log) +{ + static long pgsz = 0; + char *ptr; + Chunk *chnk; + size_t chunksz; + if (pgsz == 0) + { + pgsz = CALL_UTIL (sysconf)(_SC_PAGESIZE); + Tprintf (DBG_LT2, "memmgr: pgsz = %ld (0x%lx)\n", pgsz, pgsz); + } + /* Allocate 2^n >= sz bytes */ + unsigned nsz = ALIGN (sizeof (Chunk)) + sz; + for (chunksz = pgsz; chunksz < nsz; chunksz *= 2); + if (log == 1) + Tprintf (DBG_LT2, "alloc_chunk mapping %u, rounded up from %u\n", (unsigned int) chunksz, sz); + /* mmap64 is only in 32-bits; this call goes to mmap in 64-bits */ + ptr = (char*) CALL_UTIL (mmap64)(0, chunksz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, (int) -1, (off64_t) 0); + if (ptr == MAP_FAILED) + { + Tprintf (0, "alloc_chunk mapping failed COL_ERROR_NOZMEMMAP: %s\n", CALL_UTIL (strerror)(errno)); + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_NOZMEMMAP, errno, "0"); + return NULL; + } + /* Put the chunk descriptor at the end of the chunk */ + chnk = (Chunk*) (ptr + chunksz - ALIGN (sizeof (Chunk))); + chnk->size = chunksz; + chnk->base = ptr; + chnk->lo = chnk->base; + chnk->hi = (char*) chnk; + chnk->next = (Chunk*) NULL; + if (log == 1) + Tprintf (DBG_LT2, "memmgr: returning new chunk @%p, chunksx=%ld sz=%ld\n", + ptr, (long) chunksz, (long) sz); + return chnk; +} + +Heap * +__collector_newHeap () +{ + Heap *heap; + Chunk *chnk; + Tprintf (DBG_LT2, "__collector_newHeap calling alloc_chunk(0)\n"); + chnk = alloc_chunk (0, 1); + if (chnk == NULL) + return NULL; + + /* A bit of hackery: allocate heap from its own chunk */ + chnk->hi -= ALIGN (sizeof (Heap)); + heap = (Heap*) chnk->hi; + heap->chain[0] = (void*) chnk; + __collector_mutex_init (&heap->lock); + return heap; +} + +void +__collector_deleteHeap (Heap *heap) +{ + if (heap == NULL) + return; + /* Note: heap itself is in the last chunk */ + for (Chunk *chnk = heap->chain[0]; chnk;) + { + Chunk *next = chnk->next; + CALL_UTIL (munmap)((void*) chnk->base, chnk->size); + chnk = next; + } +} + +void * +__collector_allocCSize (Heap *heap, unsigned sz, int log) +{ + void *res; + Chunk *chnk; + if (heap == NULL) + return NULL; + + /* block all signals and acquire lock */ + sigset_t old_mask, new_mask; + CALL_UTIL (sigfillset)(&new_mask); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask); + __collector_mutex_lock (&heap->lock); + + /* Allocate nsz = 2^idx >= sz bytes */ + unsigned idx = ALIGNMENT; + unsigned nsz = 1 << idx; + while (nsz < sz) + nsz = 1 << ++idx; + + /* Look in the corresponding chain first */ + if (idx < MAXCHAIN) + { + if (heap->chain[idx] != NULL) + { + res = heap->chain[idx]; + heap->chain[idx] = *(void**) res; + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + if (log == 1) + Tprintf (DBG_LT2, "memmgr: allocCSize %p sz %d (0x%x) req = 0x%x, from chain idx = %d\n", res, nsz, nsz, sz, idx); + return res; + } + } + else + { + not_implemented (); + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + return NULL; + } + + /* Chain is empty, allocate from chunks */ + for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next) + if (chnk->lo + nsz < chnk->hi) + break; + if (chnk == NULL) + { + /* Get a new chunk */ + if (log == 1) + Tprintf (DBG_LT2, "__collector_allocCSize (%u) calling alloc_chunk(%u)\n", sz, nsz); + chnk = alloc_chunk (nsz, 1); + if (chnk == NULL) + { + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + return NULL; + } + chnk->next = (Chunk*) heap->chain[0]; + heap->chain[0] = chnk; + } + + /* Allocate from the chunk */ + chnk->hi -= nsz; + res = (void*) chnk->hi; + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + if (log == 1) + Tprintf (DBG_LT2, "memmgr: allocCSize %p sz %d (0x%x) req = 0x%x, new chunk\n", res, nsz, nsz, sz); + return res; +} + +void +__collector_freeCSize (Heap *heap, void *ptr, unsigned sz) +{ + if (heap == NULL || ptr == NULL) + return; + + /* block all signals and acquire lock */ + sigset_t old_mask, new_mask; + CALL_UTIL (sigfillset)(&new_mask); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask); + __collector_mutex_lock (&heap->lock); + + /* Free 2^idx >= sz bytes */ + unsigned idx = ALIGNMENT; + unsigned nsz = 1 << idx; + while (nsz < sz) + nsz = 1 << ++idx; + if (idx < MAXCHAIN) + { + *(void**) ptr = heap->chain[idx]; + heap->chain[idx] = ptr; + } + else + not_implemented (); + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + Tprintf (DBG_LT4, "memmgr: freeC %p sz %ld\n", ptr, (long) sz); +} + +static void * +allocVSize_nolock (Heap *heap, unsigned sz) +{ + void *res; + Chunk *chnk; + if (sz == 0) + return NULL; + + /* Find a good chunk */ + for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next) + if (chnk->lo == chnk->base && chnk->lo + sz < chnk->hi) + break; + if (chnk == NULL) + { + /* Get a new chunk */ + Tprintf (DBG_LT2, "allocVsize_nolock calling alloc_chunk(%u)\n", sz); + chnk = alloc_chunk (sz, 0); + if (chnk == NULL) + return NULL; + chnk->next = (Chunk*) heap->chain[0]; + heap->chain[0] = chnk; + } + chnk->lo = chnk->base + sz; + res = (void*) (chnk->base); + Tprintf (DBG_LT4, "memmgr: allocV %p for %ld\n", res, (long) sz); + return res; +} + +void * +__collector_allocVSize (Heap *heap, unsigned sz) +{ + void *res; + if (heap == NULL) + return NULL; + + /* block all signals and acquire lock */ + sigset_t old_mask, new_mask; + CALL_UTIL (sigfillset)(&new_mask); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask); + __collector_mutex_lock (&heap->lock); + res = allocVSize_nolock (heap, sz); + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + return res; +} + +/* + * reallocVSize( Heap *heap, void *ptr, unsigned newsz ) + * Changes the size of memory pointed by ptr to newsz. + * If ptr == NULL, allocates new memory of size newsz. + * If newsz == 0, frees ptr and returns NULL. + */ +void * +__collector_reallocVSize (Heap *heap, void *ptr, unsigned newsz) +{ + Chunk *chnk; + void *res; + if (heap == NULL) + return NULL; + if (ptr == NULL) + return __collector_allocVSize (heap, newsz); + + /* block all signals and acquire lock */ + sigset_t old_mask, new_mask; + CALL_UTIL (sigfillset)(&new_mask); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask); + __collector_mutex_lock (&heap->lock); + + /* Find its chunk */ + for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next) + if (ptr == chnk->base) + break; + if (chnk == NULL) + { + /* memory corrpution */ + not_implemented (); + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + return NULL; + } + if (chnk->base + newsz < chnk->hi) + { + /* easy case */ + chnk->lo = chnk->base + newsz; + res = newsz ? chnk->base : NULL; + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + Tprintf (DBG_LT4, "memmgr: reallocV %p for %ld\n", ptr, (long) newsz); + return res; + } + res = allocVSize_nolock (heap, newsz); + /* Copy to new location */ + if (res) + { + int size = chnk->lo - chnk->base; + if (newsz < size) + size = newsz; + char *s1 = (char*) res; + char *s2 = chnk->base; + while (size--) + *s1++ = *s2++; + } + /* Free old memory*/ + chnk->lo = chnk->base; + __collector_mutex_unlock (&heap->lock); + CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL); + return res; +} diff --git a/gprofng/libcollector/memmgr.h b/gprofng/libcollector/memmgr.h new file mode 100644 index 0000000..78231c2 --- /dev/null +++ b/gprofng/libcollector/memmgr.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef _MEMMGR_H +#define _MEMMGR_H + +struct Heap; +typedef struct Heap Heap; + +Heap *__collector_newHeap (); +void __collector_deleteHeap (Heap *heap); + +/* + * Initialize memmgr mutex locks. + */ +void __collector_mmgr_init_mutex_locks (Heap *heap); + +/* + * Allocate non-resizable memory. + */ +void *__collector_allocCSize (Heap *heap, unsigned sz, int log); + +/* + * Free non-resizable memory. + */ +void __collector_freeCSize (Heap *heap, void *ptr, unsigned sz); + +/* + * Allocate resizable memory + */ +void *__collector_allocVSize (Heap *heap, unsigned sz); + +/* + * Change size of resizable memory. + * ptr - if not NULL, it must have been previously allocated from + * the same heap, otherwise returns allocVSize(heap, newsz); + * newsz - new size; if 0, memory is freed and no new allocation + * occurs; + */ +void *__collector_reallocVSize (Heap *heap, void *ptr, unsigned newsz); + +#endif diff --git a/gprofng/libcollector/mmaptrace.c b/gprofng/libcollector/mmaptrace.c new file mode 100644 index 0000000..ac5c997 --- /dev/null +++ b/gprofng/libcollector/mmaptrace.c @@ -0,0 +1,1691 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * memory map tracking + * incorporating former "loadobjects" into more general "map" + * (including code and data segments and dynamic functions) + */ + +#include "config.h" +#include <alloca.h> +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <elf.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <stdint.h> + +#include "gp-defs.h" +#include "collector.h" +#include "gp-experiment.h" +#include "memmgr.h" + +/* + * These are obsolete and unreliable. + * They are included here only for historical compatibility. + */ +#define MA_SHARED 0x08 /* changes are shared by mapped object */ +#define MA_ANON 0x40 /* anonymous memory (e.g. /dev/zero) */ +#define MA_ISM 0x80 /* intimate shared mem (shared MMU resources) */ +#define MA_BREAK 0x10 /* grown by brk(2) */ +#define MA_STACK 0x20 /* grown automatically on stack faults */ + +typedef struct prmap_t +{ + unsigned long pr_vaddr; /* virtual address of mapping */ + unsigned long pr_size; /* size of mapping in bytes */ + char *pr_mapname; /* name in /proc/<pid>/object */ + int pr_mflags; /* protection and attribute flags (see below) */ + unsigned long pr_offset; /* offset into mapped object, if any */ + unsigned long pr_dev; + unsigned long pr_ino; + int pr_pagesize; /* pagesize (bytes) for this mapping */ +} prmap_t; + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 +#define DBG_LT4 4 + +#define SYS_MMAP_NAME "mmap" +#define SYS_MMAP64_NAME "mmap64" +#define SYS_MUNMAP_NAME "munmap" +#define SYS_DLOPEN_NAME "dlopen" +#define SYS_DLCLOSE_NAME "dlclose" + +typedef struct MapInfo +{ + struct MapInfo *next; + unsigned long vaddr; + unsigned long size; + char *mapname; /* name in /proc/<pid>/object */ + char *filename; + unsigned long offset; + int mflags; + int pagesize; +} MapInfo; + +typedef struct NameInfo +{ + struct NameInfo *next; + char *mapname; + char filename[1]; /* dynamic length file name */ +} NameInfo; + +static NameInfo *namemaps = NULL; +static MapInfo mmaps; /* current memory maps */ +static struct DataHandle *map_hndl = NULL; +static char dyntext_fname[MAXPATHLEN]; +static void *mapcache = NULL; +static char *maptext = NULL; +static size_t maptext_sz = 4096; /* initial buffer size */ +static int mmap_mode = 0; +static int mmap_initted = 0; +static collector_mutex_t map_lock = COLLECTOR_MUTEX_INITIALIZER; +static collector_mutex_t dyntext_lock = COLLECTOR_MUTEX_INITIALIZER; + +/* a reentrance guard for the interposition functions ensures that updates to + the map cache/file are sequential, with the first doing the final update */ +static int reentrance = 0; +#define CHCK_REENTRANCE (reentrance || mmap_mode <= 0) +#define CURR_REENTRANCE reentrance +#define PUSH_REENTRANCE reentrance++ +#define POP_REENTRANCE reentrance-- + +#define CALL_REAL(x) (__real_##x) +#define NULL_PTR(x) (__real_##x == NULL) + +/* interposition function handles */ +static void *(*__real_mmap)(void* start, size_t length, int prot, int flags, + int fd, off_t offset) = NULL; +static void *(*__real_mmap64)(void* start, size_t length, int prot, int flags, + int fd, off64_t offset) = NULL; +static int (*__real_munmap)(void* start, size_t length) = NULL; +static void *(*__real_dlopen)(const char* pathname, int mode) = NULL; +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) +static void *(*__real_dlopen_2_1)(const char* pathname, int mode) = NULL; +static void *(*__real_dlopen_2_0)(const char* pathname, int mode) = NULL; +#endif +static int (*__real_dlclose)(void* handle) = NULL; +static void (*collector_heap_record)(int, size_t, void*) = NULL; + +/* internal function prototypes */ +static int init_mmap_intf (); +static int init_mmap_files (); +static void append_segment_record (char *format, ...); +static void update_map_segments (hrtime_t hrt, int resolve); +static void resolve_mapname (MapInfo *map, char *name); +static void record_segment_map (hrtime_t timestamp, uint64_t loadaddr, + unsigned long msize, int pagesize, int modeflags, + long long offset, unsigned check, char *name); +static void record_segment_unmap (hrtime_t timestamp, uint64_t loadaddr); + +/* Linux needs handling of the vsyscall page to get its data into the map.xml file */ +static void process_vsyscall_page (); + +#define MAXVSYSFUNCS 10 +static int nvsysfuncs = 0; +static char *sysfuncname[MAXVSYSFUNCS]; +static uint64_t sysfuncvaddr[MAXVSYSFUNCS]; +static unsigned long sysfuncsize[MAXVSYSFUNCS]; + +#define MAXDYN 20 +static int ndyn = 0; +static char *dynname [MAXDYN]; +static void *dynvaddr [MAXDYN]; +static unsigned dynsize [MAXDYN]; +static char *dynfuncname[MAXDYN]; + +/*===================================================================*/ + +/* + * void __collector_mmap_init_mutex_locks() + * Iinitialize mmap mutex locks. + */ +void +__collector_mmap_init_mutex_locks () +{ + __collector_mutex_init (&map_lock); + __collector_mutex_init (&dyntext_lock); +} + +/* __collector_ext_update_map_segments called by the audit agent + * Is is also called by dbx/collector when a (possible) map update + * is intimated, such as after dlopen/dlclose. + * Required when libcollector.so is not preloaded and interpositions inactive. + */ +int +__collector_ext_update_map_segments (void) +{ + if (!mmap_initted) + return 0; + TprintfT (0, "__collector_ext_update_map_segments(%d)\n", CURR_REENTRANCE); + if (CHCK_REENTRANCE) + return 0; + PUSH_REENTRANCE; + update_map_segments (GETRELTIME (), 1); + POP_REENTRANCE; + return 0; +} +/* + * int __collector_ext_mmap_install() + * Install and initialise mmap tracing. + */ +int +__collector_ext_mmap_install (int record) +{ + TprintfT (0, "__collector_ext_mmap_install(mmap_mode=%d)\n", mmap_mode); + if (NULL_PTR (mmap)) + { + if (init_mmap_intf ()) + { + TprintfT (0, "ERROR: collector mmap tracing initialization failed.\n"); + return COL_ERROR_EXPOPEN; + } + } + else + TprintfT (DBG_LT2, "collector mmap tracing: mmap pointer not null\n"); + + /* Initialize side door interface with the heap tracing module */ + collector_heap_record = (void(*)(int, size_t, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record"); + if (record) + { + map_hndl = __collector_create_handle (SP_MAP_FILE); + if (map_hndl == NULL) + return COL_ERROR_MAPOPEN; + if (init_mmap_files ()) + { + TprintfT (0, "ERROR: collector init_mmap_files() failed.\n"); + return COL_ERROR_EXPOPEN; + } + } + mmaps.next = NULL; + mapcache = NULL; + PUSH_REENTRANCE; + update_map_segments (GETRELTIME (), 1); // initial map + POP_REENTRANCE; + mmap_mode = 1; + mmap_initted = 1; + process_vsyscall_page (); + return COL_ERROR_NONE; +} + +/* + * int __collector_ext_mmap_deinstall() + * Optionally update final map and stop tracing mmap events. + */ +int +__collector_ext_mmap_deinstall (int update) +{ + if (!mmap_initted) + return COL_ERROR_NONE; + mmap_mode = 0; + if (update) + { + /* Final map */ + PUSH_REENTRANCE; + update_map_segments (GETRELTIME (), 1); + POP_REENTRANCE; + } + TprintfT (0, "__collector_ext_mmap_deinstall(%d)\n", update); + if (map_hndl != NULL) + { + __collector_delete_handle (map_hndl); + map_hndl = NULL; + } + __collector_mutex_lock (&map_lock); // get lock before resetting + + /* Free all memory maps */ + MapInfo *mp; + for (mp = mmaps.next; mp;) + { + MapInfo *next = mp->next; + __collector_freeCSize (__collector_heap, mp, sizeof (*mp)); + mp = next; + } + mmaps.next = NULL; + + /* Free all name maps */ + NameInfo *np; + for (np = namemaps; np;) + { + NameInfo *next = np->next; + __collector_freeCSize (__collector_heap, np, sizeof (*np) + __collector_strlen (np->filename)); + np = next; + } + namemaps = NULL; + mapcache = __collector_reallocVSize (__collector_heap, mapcache, 0); + mmaps.next = NULL; + mapcache = NULL; + __collector_mutex_unlock (&map_lock); + TprintfT (0, "__collector_ext_mmap_deinstall done\n"); + return 0; +} + +/* + * void __collector_mmap_fork_child_cleanup() + * Perform all necessary cleanup steps in child process after fork(). + */ +void +__collector_mmap_fork_child_cleanup () +{ + /* Initialize all mmap "mutex" locks */ + __collector_mmap_init_mutex_locks (); + if (!mmap_initted) + return; + mmap_mode = 0; + __collector_delete_handle (map_hndl); + __collector_mutex_lock (&map_lock); // get lock before resetting + + /* Free all memory maps */ + MapInfo *mp; + for (mp = mmaps.next; mp;) + { + MapInfo *next = mp->next; + __collector_freeCSize (__collector_heap, mp, sizeof (*mp)); + mp = next; + } + mmaps.next = NULL; + + /* Free all name maps */ + NameInfo *np; + for (np = namemaps; np;) + { + NameInfo *next = np->next; + __collector_freeCSize (__collector_heap, np, sizeof (*np) + __collector_strlen (np->filename)); + np = next; + } + namemaps = NULL; + mapcache = __collector_reallocVSize (__collector_heap, mapcache, 0); + mmap_initted = 0; + reentrance = 0; + __collector_mutex_unlock (&map_lock); +} + +static int +init_mmap_files () +{ + TprintfT (DBG_LT2, "init_mmap_files\n"); + /* also create the headerless dyntext file (if required) */ + CALL_UTIL (snprintf)(dyntext_fname, sizeof (dyntext_fname), "%s/%s", + __collector_exp_dir_name, SP_DYNTEXT_FILE); + if (CALL_UTIL (access)(dyntext_fname, F_OK) != 0) + { + int fd = CALL_UTIL (open)(dyntext_fname, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) + { + char errmsg[256]; + TprintfT (0, "ERROR: init_mmap_files: open(%s) failed\n", + dyntext_fname); + __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: %s</event>\n", + SP_JCMD_CERROR, COL_ERROR_DYNOPEN, errno, + dyntext_fname, errmsg); + return COL_ERROR_DYNOPEN; + } + else + CALL_UTIL (close)(fd); + } + return COL_ERROR_NONE; +} + +static void +append_segment_record (char *format, ...) +{ + char buf[1024]; + char *bufptr = buf; + va_list va; + va_start (va, format); + int sz = __collector_xml_vsnprintf (bufptr, sizeof (buf), format, va); + va_end (va); + + if (__collector_expstate != EXP_OPEN && __collector_expstate != EXP_PAUSED) + { + TprintfT (0, "append_segment_record: expt neither open nor paused (%d); " + "not writing to map.xml\n\t%s", __collector_expstate, buf); + return; + } + if (sz >= sizeof (buf)) + { + /* Allocate a new buffer */ + sz += 1; /* add the terminating null byte */ + bufptr = (char*) alloca (sz); + va_start (va, format); + sz = __collector_xml_vsnprintf (bufptr, sz, format, va); + va_end (va); + } + int rc = __collector_write_string (map_hndl, bufptr, sz); + if (rc != 0) + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\"></event>\n", + SP_JCMD_CERROR, COL_ERROR_MAPWRITE); +} + +static void +record_segment_map (hrtime_t timestamp, uint64_t loadaddr, unsigned long msize, + int pagesize, int modeflags, long long offset, + unsigned check, char *name) +{ + + TprintfT (DBG_LT2, "record_segment_map(%s @ 0x%llx)\n", name, (long long) loadaddr); + append_segment_record ("<event kind=\"map\" object=\"segment\" tstamp=\"%u.%09u\" " + "vaddr=\"0x%016llX\" size=\"%lu\" pagesz=\"%d\" foffset=\"%c0x%08llX\" " + "modes=\"0x%03X\" chksum=\"0x%0X\" name=\"%s\"/>\n", + (unsigned) (timestamp / NANOSEC), + (unsigned) (timestamp % NANOSEC), + loadaddr, msize, pagesize, + offset < 0 ? '-' : '+', offset < 0 ? -offset : offset, + modeflags, check, name); +} + +static void +record_segment_unmap (hrtime_t timestamp, uint64_t loadaddr) +{ + TprintfT (DBG_LT2, "record_segment_unmap(@ 0x%llx)\n", (long long) loadaddr); + append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" vaddr=\"0x%016llX\"/>\n", + (unsigned) (timestamp / NANOSEC), + (unsigned) (timestamp % NANOSEC), loadaddr); +} + +#if WSIZE(64) +#define ELF_EHDR Elf64_Ehdr +#define ELF_PHDR Elf64_Phdr +#define ELF_SHDR Elf64_Shdr +#define ELF_DYN Elf64_Dyn +#define ELF_AUX Elf64_auxv_t +#define ELF_SYM Elf64_Sym +#define ELF_ST_BIND ELF64_ST_BIND +#define ELF_ST_TYPE ELF64_ST_TYPE +#elif WSIZE(32) +#define ELF_EHDR Elf32_Ehdr +#define ELF_PHDR Elf32_Phdr +#define ELF_SHDR Elf32_Shdr +#define ELF_DYN Elf32_Dyn +#define ELF_AUX Elf32_auxv_t +#define ELF_SYM Elf32_Sym +#define ELF_ST_BIND ELF32_ST_BIND +#define ELF_ST_TYPE ELF32_ST_TYPE +#endif + +static unsigned +checksum_mapname (MapInfo* map) +{ + unsigned checksum = 0; + /* only checksum code segments */ + if ((map->mflags & (PROT_EXEC | PROT_READ)) == 0 || + (map->mflags & PROT_WRITE) != 0) + return 0; + checksum = (unsigned) - 1; + TprintfT (DBG_LT2, "checksum_mapname checksum = 0x%0X\n", checksum); + return checksum; +} + + +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) +static void* +dlopen_searchpath_symver (void*(real_dlopen) (), void* caller_addr, const char* basename, int mode) +#else +static void* +dlopen_searchpath (void* caller_addr, const char* basename, int mode) +#endif +{ + TprintfT (DBG_LT2, "dlopen_searchpath(%p, %s, %d)\n", caller_addr, basename, mode); + Dl_info dl_info; + if (dladdr (caller_addr, &dl_info) == 0) + { + TprintfT (0, "ERROR: dladdr(%p): %s\n", caller_addr, dlerror ()); + return 0; + } + TprintfT (DBG_LT2, "dladdr(%p): %p fname=%s\n", + caller_addr, dl_info.dli_fbase, dl_info.dli_fname); + int noload = RTLD_BINDING_MASK | RTLD_NOLOAD; //XXXX why RTLD_BINDING_MASK? +#define WORKAROUND_RTLD_BUG 1 +#ifdef WORKAROUND_RTLD_BUG + // A dynamic linker dlopen bug can result in corruption/closure of open streams + // XXXX workaround should be removed once linker patches are all available +#if WSIZE(64) +#define MAINBASE 0x400000 +#elif WSIZE(32) +#define MAINBASE 0x08048000 +#endif + const char* tmp_path = + (dl_info.dli_fbase == (void*) MAINBASE) ? NULL : dl_info.dli_fname; + void* caller_hndl = NULL; +#if ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)) + caller_hndl = (real_dlopen) (tmp_path, noload); +#else + caller_hndl = CALL_REAL (dlopen)(tmp_path, noload); +#endif + +#else //XXXX workaround should be removed once linker patches are all available + + void* caller_hndl = NULL; +#if (ARCH(Intel) && WSIZE(32) || ARCH(SPARC) + caller_hndl = (real_dlopen) (dl_info.dli_fname, noload); +#else + caller_hndl = CALL_REAL (dlopen)(dl_info.dli_fname, noload); +#endif + +#endif //XXXX workaround should be removed once linker patches are all available + + if (!caller_hndl) + { + TprintfT (0, "ERROR: dlopen(%s,NOLOAD): %s\n", dl_info.dli_fname, dlerror ()); + return 0; + } + Dl_serinfo _info, *info = &_info; + Dl_serpath *path; + + /* determine search path count and required buffer size */ + dlinfo (caller_hndl, RTLD_DI_SERINFOSIZE, (void *) info); + + /* allocate new buffer and initialize */ + /* + CR# 7191331 + There is a bug in Linux that causes the first call + to dlinfo() to return a small value for the dls_size. + + The first call to dlinfo() determines the search path + count and the required buffer size. The second call to + dlinfo() tries to obtain the search path information. + + However, the size of the buffer that is returned by + the first call to the dlinfo() is incorrect (too small). + The second call to dlinfo() uses the incorrect size to + allocate memory on the stack and internally uses the memcpy() + function to copy the search paths to the allocated memory space. + The length of the search path is much larger than the buffer + that is allocated on the stack. The memcpy() overwrites some + of the information that are saved on the stack, specifically, + it overwrites the "basename" parameter. + + collect crashes right after the second call to dlinfo(). + + The search paths are used to locate the shared libraries. + dlinfo() creates the search paths based on the paths + that are assigned to LD_LIBRARY_PATH environment variable + and the standard library paths. The standard library paths + consists of the /lib and the /usr/lib paths. The + standard library paths are always included to the search + paths by dlinfo() even if the LD_LIBRARY_PATH environment + variable is not defined. Therefore, at the very least the + dls_cnt is assigned to 2 (/lib and /usr/lib) and dlinfo() + will never assign dls_cnt to zero. The dls_cnt is the count + of the potential paths for searching the shared libraries. + + So we need to increase the buffer size before the second + call to dlinfo(). There are number of ways to increase + the buffer size. However, none of them can calculate the + buffer size precisely. Some users on the web have suggested + to multiply the MAXPATHLEN by dls_cnt for the buffer size. + The MAXPATHLEN is assigned to 1024 bytes. In my opinion + this is too much. So I have decided to multiply dls_size + by dls_cnt for the buffer size since the dls_size is much + smaller than 1024 bytes. + + I have already confirmed with our user that the workaround + is working with his real application. Additionally, + the dlopen_searchpath() function is called only by the + libcorrector init() function when the experiment is started. + Therefore, allocating some extra bytes on the stack which + is local to this routine is harmless. + */ + + info = alloca (_info.dls_size * _info.dls_cnt); + info->dls_size = _info.dls_size; + info->dls_cnt = _info.dls_cnt; + + /* obtain search path information */ + dlinfo (caller_hndl, RTLD_DI_SERINFO, (void *) info); + path = &info->dls_serpath[0]; + + char pathname[MAXPATHLEN]; + for (unsigned int cnt = 1; cnt <= info->dls_cnt; cnt++, path++) + { + __collector_strlcpy (pathname, path->dls_name, sizeof (pathname)); + __collector_strlcat (pathname, "/", sizeof (pathname)); + __collector_strlcat (pathname, basename, sizeof (pathname)); + void* ret = NULL; +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) + ret = (real_dlopen) (pathname, mode); +#else + ret = CALL_REAL (dlopen)(pathname, mode); +#endif + TprintfT (DBG_LT2, "try %d/%d: %s = %p\n", cnt, info->dls_cnt, pathname, ret); + if (ret) + return ret; // success! + } + return 0; +} + +static void +resolve_mapname (MapInfo *map, char *name) +{ + map->filename = ""; + map->mapname = ""; + if (name == NULL || *name == '\0') + { + if (map->mflags & MA_STACK) + map->filename = "<" SP_MAP_STACK ">"; + else if (map->mflags & MA_BREAK) + map->filename = "<" SP_MAP_HEAP ">"; + else if (map->mflags & MA_ISM) + map->filename = "<" SP_MAP_SHMEM ">"; + return; + } + NameInfo *np; + for (np = namemaps; np; np = np->next) + if (__collector_strcmp (np->mapname, name) == 0) + break; + + if (np == NULL) + { + const char *fname; + fname = name; + /* Create and link a new name map */ + size_t fnamelen = __collector_strlen (fname) + 1; + np = (NameInfo*) __collector_allocCSize (__collector_heap, sizeof (NameInfo) + fnamelen, 1); + if (np == NULL) // We could not get memory + return; + np->mapname = np->filename; + __collector_strlcpy (np->filename, fname, fnamelen); + np->next = namemaps; + namemaps = np; + } + map->mapname = np->mapname; + map->filename = np->filename; + if (map->filename[0] == (char) 0) + map->filename = map->mapname; + TprintfT (DBG_LT2, "resolve_mapname: %s resolved to %s\n", map->mapname, map->filename); +} + +static unsigned long +str2ulong (char **ss) +{ + char *s = *ss; + unsigned long val = 0UL; + const int base = 16; + for (;;) + { + char c = *s++; + if (c >= '0' && c <= '9') + val = val * base + (c - '0'); + else if (c >= 'a' && c <= 'f') + val = val * base + (c - 'a') + 10; + else if (c >= 'A' && c <= 'F') + val = val * base + (c - 'A') + 10; + else + break; + } + *ss = s - 1; + return val; +} + +static void +update_map_segments (hrtime_t hrt, int resolve) +{ + size_t filesz; + if (__collector_mutex_trylock (&map_lock)) + { + TprintfT (0, "WARNING: update_map_segments(resolve=%d) BUSY\n", resolve); + return; + } + TprintfT (DBG_LT2, "\n"); + TprintfT (DBG_LT2, "begin update_map_segments(hrt, %d)\n", resolve); + + // Note: there is similar code to read /proc/$PID/map[s] in + // perfan/er_kernel/src/KSubExp.cc KSubExp::write_subexpt_map() + const char* proc_map = "/proc/self/maps"; + size_t bufsz = maptext_sz; + int done = 0; + filesz = 0; + int map_fd = CALL_UTIL (open)(proc_map, O_RDONLY); + while (!done) + { + bufsz *= 2; + maptext = __collector_reallocVSize (__collector_heap, maptext, bufsz); + TprintfT (DBG_LT2, " update_map_segments: Loop for bufsize=%ld\n", + (long) bufsz); + for (;;) + { + int n = CALL_UTIL (read)(map_fd, maptext + filesz, bufsz - filesz); + TprintfT (DBG_LT2, " update_map_segments: __collector_read(bufp=%p nbyte=%ld)=%d\n", + maptext + filesz, (long) ( bufsz - filesz), n); + if (n < 0) + { + TprintfT (0, "ERROR: update_map_segments: read(maps): errno=%d\n", errno); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_MAPREAD, errno, proc_map); + CALL_UTIL (close)(map_fd); + __collector_mutex_unlock (&map_lock); + return; + } + else if (n == 0) + { + done = 1; + break; + } + filesz += n; + if (filesz >= bufsz) /* Buffer too small */ + break; + } + } + CALL_UTIL (close)(map_fd); + maptext_sz = filesz; + + int mapcache_entries = 0; + char *str, *str1; + for (str = maptext;; str = str1) + { + for (str1 = str; str1 - maptext < filesz; str1++) + { + if (*str1 == '\n') + { + *str1 = (char) 0; + break; + } + } + if (str1 - maptext >= filesz) + break; + str1++; + mapcache_entries++; + mapcache = __collector_reallocVSize (__collector_heap, mapcache, + sizeof (prmap_t) * mapcache_entries); + prmap_t *map = ((prmap_t *) mapcache) + (mapcache_entries - 1); + map->pr_vaddr = str2ulong (&str); + str++; + unsigned long eaddr = str2ulong (&str); + str++; + map->pr_size = eaddr - map->pr_vaddr; + map->pr_mflags = 0; + map->pr_mflags += (*str++ == 'r' ? PROT_READ : 0); + map->pr_mflags += (*str++ == 'w' ? PROT_WRITE : 0); + map->pr_mflags += (*str++ == 'x' ? PROT_EXEC : 0); + map->pr_mflags += (*str++ == 's' ? MA_SHARED : 0); + str++; + map->pr_offset = str2ulong (&str); + str++; + map->pr_dev = str2ulong (&str) * 0x100; + str++; + map->pr_dev += str2ulong (&str); + str++; + map->pr_ino = str2ulong (&str); + if (map->pr_dev == 0) + map->pr_mflags |= MA_ANON; + while (*str == ' ') + str++; + map->pr_mapname = str; + map->pr_pagesize = 4096; + } + + /* Compare two maps and record all differences */ + unsigned nidx = 0; + MapInfo *prev = &mmaps; + MapInfo *oldp = mmaps.next; + for (;;) + { + prmap_t *newp = nidx < mapcache_entries ? + (prmap_t*) mapcache + nidx : NULL; + if (oldp == NULL && newp == NULL) + break; + + /* If two maps are equal proceed to the next pair */ + if (oldp && newp && + oldp->vaddr == newp->pr_vaddr && + oldp->size == newp->pr_size && + __collector_strcmp (oldp->mapname, newp->pr_mapname) == 0) + { + prev = oldp; + oldp = oldp->next; + nidx++; + continue; + } + /* Check if we need to unload the old map first */ + if (newp == NULL || (oldp && oldp->vaddr <= newp->pr_vaddr)) + { + if (oldp != NULL) + { + /* Don't record MA_ANON maps except MA_STACK and MA_BREAK */ + if ((!(oldp->mflags & MA_ANON) || (oldp->mflags & (MA_STACK | MA_BREAK)))) + record_segment_unmap (hrt, oldp->vaddr); + /* Remove and free map */ + prev->next = oldp->next; + MapInfo *tmp = oldp; + oldp = oldp->next; + __collector_freeCSize (__collector_heap, tmp, sizeof (*tmp)); + } + } + else + { + MapInfo *map = (MapInfo*) __collector_allocCSize (__collector_heap, sizeof (MapInfo), 1); + if (map == NULL) + { + __collector_mutex_unlock (&map_lock); + return; + } + map->vaddr = newp->pr_vaddr; + map->size = newp->pr_size; + map->offset = newp->pr_offset; + map->mflags = newp->pr_mflags; + map->pagesize = newp->pr_pagesize; + resolve_mapname (map, newp->pr_mapname); + + /* Insert new map */ + map->next = prev->next; + prev->next = map; + prev = map; + + /* Don't record MA_ANON maps except MA_STACK and MA_BREAK */ + if (!(newp->pr_mflags & MA_ANON) || (newp->pr_mflags & (MA_STACK | MA_BREAK))) + { + unsigned checksum = checksum_mapname (map); + record_segment_map (hrt, map->vaddr, map->size, + map->pagesize, map->mflags, + map->offset, checksum, map->filename); + } + nidx++; + } + } + TprintfT (DBG_LT2, "update_map_segments: done\n\n"); + __collector_mutex_unlock (&map_lock); +} /* update_map_segments */ + +/* + * Map addr to a segment. Cope with split segments. + */ +int +__collector_check_segment_internal (unsigned long addr, unsigned long *base, + unsigned long *end, int maxnretries, int MA_FLAGS) +{ + int number_of_tries = 0; +retry: + ; + + unsigned long curbase = 0; + unsigned long curfoff = 0; + unsigned long cursize = 0; + + MapInfo *mp; + for (mp = mmaps.next; mp; mp = mp->next) + { + + if (curbase + cursize == mp->vaddr && + curfoff + cursize == mp->offset && + ((mp->mflags & MA_FLAGS) == MA_FLAGS + || __collector_strncmp (mp->mapname, "[vdso]", 6) == 0 + || __collector_strncmp (mp->mapname, "[vsyscall]", 10) == 0 + )) + cursize = mp->vaddr + mp->size - curbase; + else if (addr < mp->vaddr) + break; + else if ((mp->mflags & MA_FLAGS) != MA_FLAGS + && __collector_strncmp (mp->mapname, "[vdso]", 6) + && __collector_strncmp (mp->mapname, "[vsyscall]", 10)) + { + curbase = 0; + curfoff = 0; + cursize = 0; + } + else + { + curbase = mp->vaddr; + curfoff = mp->offset; + cursize = mp->size; + } + } + + if (addr >= curbase && addr < curbase + cursize) + { + *base = curbase; + *end = curbase + cursize; + return 1; + } + + /* + * 21275311 Unwind failure in native stack for java application running on jdk8 on x86 + * + * On JDK8, we've observed cases where Java-compiled methods end up + * in virtual address segments that were "dead zones" (mflags&PROT_READ==0) at + * the time of the last update_map_segments() but are now "live". So if we + * fail to find a segment, let's call update_map_segments and then retry + * before giving up. + */ + if (number_of_tries < maxnretries) + { + number_of_tries++; + __collector_ext_update_map_segments (); + goto retry; + } + *base = 0; + *end = 0; + return 0; +} + +/** + * Check if address belongs to a readable and executable segment + * @param addr + * @param base + * @param end + * @param maxnretries + * @return 1 - yes, 0 - no + */ +int +__collector_check_segment (unsigned long addr, unsigned long *base, + unsigned long *end, int maxnretries) +{ + int MA_FLAGS = PROT_READ | PROT_EXEC; + int res = __collector_check_segment_internal (addr, base, end, maxnretries, MA_FLAGS); + return res; +} + +/** + * Check if address belongs to a readable segment + * @param addr + * @param base + * @param end + * @param maxnretries + * @return 1 - yes, 0 - no + */ +int +__collector_check_readable_segment( unsigned long addr, unsigned long *base, unsigned long *end, int maxnretries ) +{ + int MA_FLAGS = PROT_READ; + int res = __collector_check_segment_internal(addr, base, end, maxnretries, MA_FLAGS); + return res; +} + +static ELF_AUX *auxv = NULL; + +static void +process_vsyscall_page () +{ + TprintfT (DBG_LT2, "process_vsyscall_page()\n"); + if (ndyn != 0) + { + /* We've done this one in this process, and cached the results */ + /* use the cached results */ + for (int i = 0; i < ndyn; i++) + { + append_segment_record ("<event kind=\"map\" object=\"dynfunc\" name=\"%s\" " + "vaddr=\"0x%016lX\" size=\"%u\" funcname=\"%s\" />\n", + dynname[i], dynvaddr[i], dynsize[i], dynfuncname[i]); + TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map dynfunc='%s' vaddr=0x%016lX size=%ld funcname='%s' -- from cache\n", + dynname[i], (unsigned long) dynvaddr[i], + (long) dynsize[i], dynfuncname[i]); + } + } + if (nvsysfuncs != 0) + { + /* We've done this one in this process, and cached the results */ + /* use the cached results */ + hrtime_t hrt = GETRELTIME (); + for (int i = 0; i < nvsysfuncs; i++) + { + append_segment_record ("<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" " + "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n", + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), + (unsigned long) sysfuncvaddr[i], (unsigned) sysfuncsize[i], sysfuncname[i]); + TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map function='%s' vaddr=0x%016lX size=%ld -- from cache\n", + sysfuncname[i], (unsigned long) sysfuncvaddr[i], (long) sysfuncsize[i]); + } + } + if (ndyn + nvsysfuncs != 0) + return; + + /* After fork we can't rely on environ as it might have + * been moved by putenv(). Use the pointer saved by the parent. + */ + if (auxv == NULL) + { + char **envp = (char**) environ; + if (envp == NULL) + return; + while (*envp++ != NULL); + auxv = (ELF_AUX*) envp; + } + TprintfT (DBG_LT2, "process_vsyscall_page, auxv = ox%p\n", auxv); + + ELF_AUX *ap; +#ifdef DEBUG + for (ap = auxv; ap->a_type != AT_NULL; ap++) + TprintfT (DBG_LT2, "process_vsyscall_page: ELF_AUX: " + " a_type = 0x%016llx %10lld " + " a_un.a_val = 0x%016llx %10lld\n", + (long long) ap->a_type, (long long) ap->a_type, + (long long) ap->a_un.a_val, (long long) ap->a_un.a_val); +#endif + + // find the first ELF_AUX of type AT_SYSINFO_EHDR + ELF_EHDR *ehdr = NULL; + for (ap = auxv; ap->a_type != AT_NULL; ap++) + { + if (ap->a_type == AT_SYSINFO_EHDR) + { + // newer Linuxes do not have a_ptr field, they just have a_val + ehdr = (ELF_EHDR*) ap->a_un.a_val; + if (ehdr != NULL) + break; + } + } + + // If one is found + if (ehdr != NULL) + { + char *mapName = "SYSINFO_EHDR"; + MapInfo *mp; + for (mp = mmaps.next; mp; mp = mp->next) + { + if ((unsigned long) ehdr == mp->vaddr) + { + mp->mflags |= PROT_EXEC; + if (mp->mapname && mp->mapname[0]) + mapName = mp->mapname; + break; + } + } + + // Find the dynsym section and record all symbols + char *base = (char*) ehdr; + ELF_SHDR *shdr = (ELF_SHDR*) (base + ehdr->e_shoff); + int i; + +#if 0 + TprintfT (DBG_LT2, "process_vsyscall_page: ehdr: EI_CLASS=%lld EI_DATA=%lld EI_OSABI=%lld e_type=%lld e_machine=%lld e_version=%lld\n" + " e_entry =0x%016llx %10lld e_phoff =0x%016llx %10lld\n" + " e_shoff =0x%016llx %10lld e_flags =0x%016llx %10lld\n" + " e_ehsize =0x%016llx %10lld e_phentsize =0x%016llx %10lld\n" + " e_phnum =0x%016llx %10lld e_shentsize =0x%016llx %10lld\n" + " e_shnum =0x%016llx %10lld e_shstrndx =0x%016llx %10lld\n", + (long long) ehdr->e_ident[EI_CLASS], (long long) ehdr->e_ident[EI_DATA], (long long) ehdr->e_ident[EI_OSABI], + (long long) ehdr->e_type, (long long) ehdr->e_machine, (long long) ehdr->e_version, + (long long) ehdr->e_entry, (long long) ehdr->e_entry, + (long long) ehdr->e_phoff, (long long) ehdr->e_phoff, + (long long) ehdr->e_shoff, (long long) ehdr->e_shoff, + (long long) ehdr->e_flags, (long long) ehdr->e_flags, + (long long) ehdr->e_ehsize, (long long) ehdr->e_ehsize, + (long long) ehdr->e_phentsize, (long long) ehdr->e_phentsize, + (long long) ehdr->e_phnum, (long long) ehdr->e_phnum, + (long long) ehdr->e_shentsize, (long long) ehdr->e_shentsize, + (long long) ehdr->e_shnum, (long long) ehdr->e_shnum, + (long long) ehdr->e_shstrndx, (long long) ehdr->e_shstrndx); + for (i = 1; i < ehdr->e_shnum; i++) + { + TprintfT (DBG_LT2, "process_vsyscall_page: SECTION=%d sh_name=%lld '%s'\n" + " sh_type =0x%016llx %10lld\n" + " sh_flags =0x%016llx %10lld\n" + " sh_addr =0x%016llx %10lld\n" + " sh_offset =0x%016llx %10lld\n" + " sh_size =0x%016llx %10lld\n" + " sh_link =0x%016llx %10lld\n" + " sh_info =0x%016llx %10lld\n" + " sh_addralign =0x%016llx %10lld\n" + " sh_entsize =0x%016llx %10lld\n", + i, (long long) shdr[i].sh_name, base + shdr[ehdr->e_shstrndx].sh_offset + shdr[i].sh_name, + (long long) shdr[i].sh_type, (long long) shdr[i].sh_type, + (long long) shdr[i].sh_flags, (long long) shdr[i].sh_flags, + (long long) shdr[i].sh_addr, (long long) shdr[i].sh_addr, + (long long) shdr[i].sh_offset, (long long) shdr[i].sh_offset, + (long long) shdr[i].sh_size, (long long) shdr[i].sh_size, + (long long) shdr[i].sh_link, (long long) shdr[i].sh_link, + (long long) shdr[i].sh_info, (long long) shdr[i].sh_info, + (long long) shdr[i].sh_addralign, (long long) shdr[i].sh_addralign, + (long long) shdr[i].sh_entsize, (long long) shdr[i].sh_entsize); + } +#endif + + int dynSec = -1; + for (i = 1; i < ehdr->e_shnum; i++) + if (shdr[i].sh_type == SHT_DYNSYM) + { + dynSec = i; + break; + } + if (dynSec != -1) + { + char *symbase = base + shdr[shdr[dynSec].sh_link].sh_offset; + ELF_SYM *symbols = (ELF_SYM*) (base + shdr[dynSec].sh_offset); + int nextSec = 0; + int n = shdr[dynSec].sh_size / shdr[dynSec].sh_entsize; + for (i = 0; i < n; i++) + { + ELF_SYM *sym = symbols + i; + TprintfT (DBG_LT2, "process_vsyscall_page: symbol=%d st_name=%lld '%s'\n" + " st_size = 0x%016llx %10lld\n" + " st_value = 0x%016llx %10lld\n" + " st_shndx = 0x%016llx %10lld\n" + " st_info = 0x%016llx %10lld\n", + i, (long long) sym->st_name, symbase + sym->st_name, + (long long) sym->st_size, (long long) sym->st_size, + (long long) sym->st_value, (long long) sym->st_value, + (long long) sym->st_shndx, (long long) sym->st_shndx, + (long long) sym->st_info, (long long) sym->st_info); + if (sym->st_shndx <= 0 || sym->st_size <= 0 || + ELF_ST_BIND (sym->st_info) != STB_GLOBAL || ELF_ST_TYPE (sym->st_info) != STT_FUNC) + continue; + if (nextSec == 0) + nextSec = sym->st_shndx; + else if (nextSec > sym->st_shndx) + nextSec = sym->st_shndx; + } + if (nextSec == 0) + ehdr = NULL; + + while (nextSec != 0) + { + int curSec = nextSec; + char *bgn = base + shdr[curSec].sh_offset; + char *end = bgn + shdr[curSec].sh_size; + for (i = 0; i < n; i++) + { + ELF_SYM *sym = symbols + i; + if (sym->st_shndx <= 0 || sym->st_size <= 0 || + ELF_ST_BIND (sym->st_info) != STB_GLOBAL || ELF_ST_TYPE (sym->st_info) != STT_FUNC) + continue; + if (sym->st_shndx > curSec) + { + if (nextSec == curSec) + nextSec = sym->st_shndx; + else if (nextSec > sym->st_shndx) + nextSec = sym->st_shndx; + nextSec = sym->st_shndx; + continue; + } + if (sym->st_shndx != curSec) + continue; + long long st_delta = (sym->st_value >= shdr[sym->st_shndx].sh_addr) ? + (sym->st_value - shdr[sym->st_shndx].sh_addr) : -1; + char *st_value = bgn + st_delta; + if (st_delta >= 0 && st_value + sym->st_size <= end) + { + append_segment_record ("<event kind=\"map\" object=\"dynfunc\" name=\"%s\" " + "vaddr=\"0x%016lX\" size=\"%u\" funcname=\"%s\" />\n", + mapName, (void*) st_value, sym->st_size, symbase + sym->st_name); + + TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map dynfunc='%s' vaddr=%016lX size=%ld funcname='%s'\n", + mapName, (unsigned long) st_value, + (long) sym->st_size, symbase + sym->st_name); + + /* now cache this for a subsequent experiment */ + if (ndyn >= MAXDYN) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXDYN=%d</event>\n", + SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXDYN); + else + { + dynname [ndyn] = CALL_UTIL (libc_strdup)(mapName); + dynvaddr [ndyn] = (void *) st_value; + dynsize [ndyn] = (unsigned) sym->st_size; + dynfuncname[ndyn] = CALL_UTIL (libc_strdup)(symbase + sym->st_name); + TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d map function='%s' vaddr=0x%016lX size=%ld '%s'\n", + ndyn, dynname[ndyn], (unsigned long) dynvaddr[ndyn], + (long) dynsize[ndyn], dynfuncname[ndyn]); + ndyn++; + } + } + } + __collector_int_func_load (DFUNC_KERNEL, mapName, NULL, + (void*) (base + shdr[curSec].sh_offset), shdr[curSec].sh_size, 0, NULL); + + /* now cache this function for a subsequent experiment */ + if (nvsysfuncs >= MAXVSYSFUNCS) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXVSYSFUNCS=%d</event>\n", + SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXVSYSFUNCS); + else + { + sysfuncname[nvsysfuncs] = CALL_UTIL (libc_strdup)(mapName); + sysfuncvaddr[nvsysfuncs] = (unsigned long) (base + shdr[curSec].sh_offset); + sysfuncsize[nvsysfuncs] = (unsigned long) (shdr[curSec].sh_size); + TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d map function='%s' vaddr=0x%016lX size=%ld\n", + nvsysfuncs, sysfuncname[nvsysfuncs], + (unsigned long) sysfuncvaddr[nvsysfuncs], + (long) sysfuncsize[nvsysfuncs]); + nvsysfuncs++; + } + TprintfT (DBG_LT2, "process_vsyscall_page: collector_int_func_load='%s' vaddr=0x%016lX size=%ld\n", + mapName, (unsigned long) (base + shdr[curSec].sh_offset), + (long) shdr[curSec].sh_size); + if (curSec == nextSec) + break; + } + } + } + +#if WSIZE(32) + unsigned long vsysaddr = (unsigned long) 0xffffe000; +#elif WSIZE(64) + unsigned long vsysaddr = (unsigned long) 0xffffffffff600000; +#endif + // Make sure the vsyscall map has PROT_EXEC + MapInfo *mp; + for (mp = mmaps.next; mp; mp = mp->next) + { + TprintfT (DBG_LT2, "MapInfo: vaddr=0x%016llx [size=%lld] mflags=0x%llx offset=%lld pagesize=%lld\n" + " mapname='%s' filename='%s'\n", + (unsigned long long) mp->vaddr, (long long) mp->size, + (long long) mp->mflags, (long long) mp->offset, (long long) mp->pagesize, + mp->mapname ? mp->mapname : "NULL", + mp->filename ? mp->filename : "NULL"); + if (vsysaddr == mp->vaddr) + mp->mflags |= PROT_EXEC; + if ((unsigned long) ehdr == (unsigned long) mp->vaddr) + continue; + if (__collector_strncmp (mp->mapname, "[vdso]", 6) == 0 + || __collector_strncmp (mp->mapname, "[vsyscall]", 10) == 0) + { + /* + * On rubbia ( 2.6.9-5.ELsmp #1 SMP 32-bit ) access to ehdr causes SEGV. + * There doesn't seem to be a way to reliably determine the actual presence + * of the page: even when /proc reports it's there it can't be accessed. + * We will have to put up with <Unknown> on some Linuxes until this is resolved. + __collector_int_func_load(DFUNC_KERNEL, mp->mapname, NULL, (void*) mp->vaddr, mp->size, 0, NULL); + */ + hrtime_t hrt = GETRELTIME (); + append_segment_record ( + "<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" " + "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n", + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), + (unsigned long) mp->vaddr, (unsigned) mp->size, mp->mapname); + TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map function = %s, vaddr = 0x%016lX, size = %u\n", + mp->mapname, (unsigned long) mp->vaddr, (unsigned) mp->size); + + /* now cache this function for a subsequent experiment */ + if (nvsysfuncs >= MAXVSYSFUNCS) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXVSYSFUNCS=%d</event>\n", + SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXVSYSFUNCS); + else + { + sysfuncname[nvsysfuncs] = CALL_UTIL (libc_strdup)(mp->mapname); + sysfuncvaddr[nvsysfuncs] = mp->vaddr; + sysfuncsize[nvsysfuncs] = (unsigned long) mp->size; + TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d map function='%s' vaddr=0x%016lX size=%ld\n", + nvsysfuncs, sysfuncname[nvsysfuncs], + (unsigned long) sysfuncvaddr[nvsysfuncs], + (long) sysfuncsize[nvsysfuncs]); + nvsysfuncs++; + + } + } + } +} + +/* + * collector API for dynamic functions + */ +void collector_func_load () __attribute__ ((weak, alias ("__collector_func_load"))); +void +__collector_func_load (char *name, char *alias, char *sourcename, + void *vaddr, int size, int lntsize, DT_lineno *lntable) +{ + __collector_int_func_load (DFUNC_API, name, sourcename, + vaddr, size, lntsize, lntable); +} + +void collector_func_unload () __attribute__ ((weak, alias ("__collector_func_unload"))); +void +__collector_func_unload (void *vaddr) +{ + __collector_int_func_unload (DFUNC_API, vaddr); +} + +/* routines for handling dynamic functions */ +static void +rwrite (int fd, void *buf, size_t nbyte) +{ + size_t left = nbyte; + size_t res; + char *ptr = (char*) buf; + while (left > 0) + { + res = CALL_UTIL (write)(fd, ptr, left); + if (res == -1) + { + TprintfT (0, "ERROR: rwrite(%s) failed: errno=%d\n", dyntext_fname, errno); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_DYNWRITE, errno, dyntext_fname); + return; + } + left -= res; + ptr += res; + } +} + +void +__collector_int_func_load (dfunc_mode_t mode, char *name, char *sourcename, + void *vaddr, int size, int lntsize, DT_lineno *lntable) +{ + char name_buf[32]; + int slen; + static char pad[16]; + int padn; + if (!mmap_initted) + return; + hrtime_t hrt = GETRELTIME (); + + if (name == NULL) + { + /* generate a name based on vaddr */ + CALL_UTIL (snprintf)(name_buf, sizeof (name_buf), "0x%lx", (unsigned long) vaddr); + name = name_buf; + } + + switch (mode) + { + case DFUNC_API: + case DFUNC_KERNEL: + append_segment_record ("<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" " + "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n", + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), + (unsigned long) vaddr, (unsigned) size, name); + break; + case DFUNC_JAVA: + append_segment_record ("<event kind=\"map\" object=\"jcm\" tstamp=\"%u.%09u\" " + "vaddr=\"0x%016lX\" size=\"%u\" methodId=\"%s\" />\n", + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), + (unsigned long) vaddr, (unsigned) size, name); + break; + default: + return; + } + + /* 21275311 Unwind failure in native stack for java application running on jdk8 on x86 + * Check: + * - function starts in a known segment (base1 != 0) + * - function ends in the same segment (base1==base2 && end1==end2) + * If not, then call update_map_segments(). + */ + unsigned long base1, end1, base2, end2; + __collector_check_segment ((unsigned long) vaddr, &base1, &end1, 0); + if (base1) + __collector_check_segment (((unsigned long) vaddr)+((unsigned long) size), &base2, &end2, 0); + if (base1 == 0 || base1 != base2 || end1 != end2) + __collector_ext_update_map_segments (); + + /* Write a copy of actual code to the "dyntext" file */ + DT_header dt_hdr; + dt_hdr.type = DT_HEADER; + dt_hdr.size = sizeof (dt_hdr); + dt_hdr.time = hrt; + unsigned long t = (unsigned long) vaddr; /* to suppress a warning from gcc */ + dt_hdr.vaddr = (uint64_t) t; + + DT_code dt_code; + dt_code.type = DT_CODE; + void *code = vaddr; + if (vaddr != NULL && size > 0) + { + dt_code.size = sizeof (dt_code) + ((size + 0xf) & ~0xf); + if (mode == DFUNC_KERNEL) + { + /* Some Linuxes don't accept vaddrs from the vsyscall + * page in write(). Make a copy. + */ + code = alloca (size); + __collector_memcpy (code, vaddr, size); + } + } + else + dt_code.size = 0; + + DT_srcfile dt_src; + dt_src.type = DT_SRCFILE; + if (sourcename) + { + slen = CALL_UTIL (strlen)(sourcename) + 1; + dt_src.size = slen ? sizeof (dt_src) + ((slen + 0xf) & ~0xf) : 0; + } + else + { + slen = 0; + dt_src.size = 0; + } + + DT_ltable dt_ltbl; + dt_ltbl.type = DT_LTABLE; + if (lntable != NULL && lntsize > 0) + dt_ltbl.size = sizeof (dt_ltbl) + lntsize * sizeof (DT_lineno); + else + dt_ltbl.size = 0; + + int fd = CALL_UTIL (open)(dyntext_fname, O_RDWR | O_APPEND); + if (fd == -1) + { + TprintfT (0, "ERROR: __collector_int_func_load: open(%s) failed: errno=%d\n", + dyntext_fname, errno); + (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n", + SP_JCMD_CERROR, COL_ERROR_DYNOPEN, errno, dyntext_fname); + return; + } + + /* Lock the whole file */ + __collector_mutex_lock (&dyntext_lock); + rwrite (fd, &dt_hdr, sizeof (dt_hdr)); + if (dt_code.size) + { + padn = dt_code.size - sizeof (dt_code) - size; + rwrite (fd, &dt_code, sizeof (dt_code)); + rwrite (fd, code, size); + rwrite (fd, &pad, padn); + } + if (dt_src.size) + { + padn = dt_src.size - sizeof (dt_src) - slen; + rwrite (fd, &dt_src, sizeof (dt_src)); + rwrite (fd, sourcename, slen); + rwrite (fd, &pad, padn); + } + if (dt_ltbl.size) + { + rwrite (fd, &dt_ltbl, sizeof (dt_ltbl)); + rwrite (fd, lntable, dt_ltbl.size - sizeof (dt_ltbl)); + } + + /* Unlock the file */ + __collector_mutex_unlock( &dyntext_lock ); + CALL_UTIL(close( fd ) ); +} + +void +__collector_int_func_unload (dfunc_mode_t mode, void *vaddr) +{ + if (!mmap_initted) + return; + hrtime_t hrt = GETRELTIME (); + if (mode == DFUNC_API) + append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" vaddr=\"0x%016lX\"/>\n", + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), (unsigned long) vaddr); + else if (mode == DFUNC_JAVA) + /* note that the "vaddr" is really a method id, not an address */ + append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" methodId=\"0x%016lX\"/>\n", + (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), (unsigned long) vaddr); + else + return; +} + +/* + * int init_mmap_intf() + * Set up interposition (if not already done). + */ +static int +init_mmap_intf () +{ + if (__collector_dlsym_guard) + return 1; + void *dlflag; + __real_mmap = (void*(*)(void* addr, size_t len, int prot, int flags, + int fildes, off_t off))dlsym (RTLD_NEXT, SYS_MMAP_NAME); + if (__real_mmap == NULL) + { + + /* We are probably dlopened after libthread/libc, + * try to search in the previously loaded objects + */ + __real_mmap = (void*(*)(void* addr, size_t len, int prot, int flags, + int fildes, off_t off))dlsym (RTLD_DEFAULT, SYS_MMAP_NAME); + if (__real_mmap == NULL) + { + TprintfT (0, "ERROR: collector real mmap not found\n"); + return 1; + } + TprintfT (DBG_LT2, "collector real mmap found with RTLD_DEFAULT\n"); + dlflag = RTLD_DEFAULT; + } + else + { + TprintfT (DBG_LT2, "collector real mmap found with RTLD_NEXT\n"); + dlflag = RTLD_NEXT; + } + + TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_mmap\n", __real_mmap); + __real_mmap64 = (void*(*)(void *, size_t, int, int, int, off64_t)) + dlsym (dlflag, SYS_MMAP64_NAME); + TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_mmap64\n", __real_mmap64); + __real_munmap = (int(*)(void *, size_t)) dlsym (dlflag, SYS_MUNMAP_NAME); + TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_munmap\n", __real_munmap); + + // dlopen/dlmopen/dlclose are in libdl.so + __real_dlopen = (void*(*)(const char *, int)) + dlvsym (dlflag, SYS_DLOPEN_NAME, SYS_DLOPEN_VERSION); + TprintfT (DBG_LT2, "init_mmap_intf() [%s] @%p __real_dlopen\n", + SYS_DLOPEN_VERSION, __real_dlopen); +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) + __real_dlopen_2_1 = __real_dlopen; + __real_dlopen_2_0 = (void*(*)(const char *, int)) + dlvsym (dlflag, SYS_DLOPEN_NAME, "GLIBC_2.0"); +#endif + + __real_dlclose = (int(*)(void* handle))dlsym (dlflag, SYS_DLCLOSE_NAME); + TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_dlclose\n", __real_dlclose); + TprintfT (DBG_LT2, "init_mmap_intf() done\n"); + + return 0; +} + +/*------------------------------------------------------------- mmap */ +void * +mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + int err = 0; + if (NULL_PTR (mmap)) + err = init_mmap_intf (); + if (err) + return MAP_FAILED; + + /* hrtime_t hrt = GETRELTIME(); */ + void *ret = CALL_REAL (mmap)(start, length, prot, flags, fd, offset); + + if (!CHCK_REENTRANCE && (ret != MAP_FAILED) && collector_heap_record != NULL) + { + PUSH_REENTRANCE; + /* write a separate record for mmap tracing */ + collector_heap_record (MMAP_TRACE, length, ret); + POP_REENTRANCE; + } + TprintfT (DBG_LT2, "libcollector.mmap(%p, %ld, %d, %d, %d, 0x%lld) = %p\n", + start, (long) length, prot, flags, fd, (long long) offset, ret); + return ret; +} + +/*------------------------------------------------------------- mmap64 */ +#if WSIZE(32) /* mmap64 only defined for non-64-bit */ + +void * +mmap64 (void *start, size_t length, int prot, int flags, int fd, off64_t offset) +{ + if (NULL_PTR (mmap64)) + init_mmap_intf (); + + /* hrtime_t hrt = GETRELTIME(); */ + void *ret = CALL_REAL (mmap64)(start, length, prot, flags, fd, offset); + if (!CHCK_REENTRANCE && (ret != MAP_FAILED) && collector_heap_record != NULL) + { + PUSH_REENTRANCE; + /* write a separate record for mmap tracing */ + collector_heap_record (MMAP_TRACE, length, ret); + POP_REENTRANCE; + } + TprintfT (DBG_LT2, "libcollector.mmap64(%p, %ld, %d, %d, %d, 0x%lld) = %p\n", + start, (long) length, prot, flags, fd, (long long) offset, ret); + return ret; +} +#endif /* WSIZE(32) */ + +/*------------------------------------------------------------- munmap */ +int +munmap (void *start, size_t length) +{ + if (NULL_PTR (munmap)) + init_mmap_intf (); + + /* hrtime_t hrt = GETRELTIME(); */ + int rc = CALL_REAL (munmap)(start, length); + if (!CHCK_REENTRANCE && (rc == 0) && collector_heap_record != NULL) + { + PUSH_REENTRANCE; + /* write a separate record for mmap tracing */ + collector_heap_record (MUNMAP_TRACE, length, start); + POP_REENTRANCE; + } + TprintfT (DBG_LT2, "libcollector.munmap(%p, %ld) = %d\n", start, (long) length, rc); + return rc; +} + + +/*------------------------------------------------------------- dlopen */ +// map interposed symbol versions +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) + +static void * +__collector_dlopen_symver (void*(real_dlopen) (), void *caller, const char *pathname, int mode); + +void * +__collector_dlopen_2_1 (const char *pathname, int mode) +{ + if (NULL_PTR (dlopen)) + init_mmap_intf (); + void *caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion + return __collector_dlopen_symver (CALL_REAL (dlopen_2_1), caller, pathname, mode); +} + +void * +__collector_dlopen_2_0 (const char *pathname, int mode) +{ + if (NULL_PTR (dlopen)) + init_mmap_intf (); + void* caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion + return __collector_dlopen_symver (CALL_REAL (dlopen_2_0), caller, pathname, mode); +} + +__asm__(".symver __collector_dlopen_2_1,dlopen@@GLIBC_2.1"); +__asm__(".symver __collector_dlopen_2_0,dlopen@GLIBC_2.0"); + +#endif + +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) +static void * +__collector_dlopen_symver (void*(real_dlopen) (), void *caller, const char *pathname, int mode) +#else +void * +dlopen (const char *pathname, int mode) +#endif +{ + const char * real_pathname = pathname; + char new_pathname[MAXPATHLEN]; + int origin_offset = 0; + TprintfT (DBG_LT2, "dlopen: pathname=%s, mode=%d\n", pathname ? pathname : "NULL", mode); + if (pathname && __collector_strStartWith (pathname, "$ORIGIN/") == 0) + origin_offset = 8; + else if (pathname && __collector_strStartWith (pathname, "${ORIGIN}/") == 0) + origin_offset = 10; + if (origin_offset) + { +#if ! ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)) + // 'caller' is not passed as an argument + void * caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion +#endif + Dl_info dl_info; + if (caller && dladdr (caller, &dl_info) != 0) + { + TprintfT (DBG_LT2, "dladdr(%p): %p fname=%s\n", + caller, dl_info.dli_fbase, dl_info.dli_fname); + new_pathname[0] = '\0'; + const char *p = __collector_strrchr (dl_info.dli_fname, '/'); + if (p) + __collector_strlcpy (new_pathname, dl_info.dli_fname, + (p - dl_info.dli_fname + 2) < MAXPATHLEN ? (p - dl_info.dli_fname + 2) : MAXPATHLEN); + __collector_strlcat (new_pathname, pathname + origin_offset, MAXPATHLEN - CALL_UTIL (strlen)(new_pathname)); + real_pathname = new_pathname; + } + else + TprintfT (0, "ERROR: dladdr(%p): %s\n", caller, dlerror ()); + } + if (NULL_PTR (dlopen)) + init_mmap_intf (); + TprintfT (DBG_LT2, "libcollector.dlopen(%s,%d) interposing\n", + pathname ? pathname : "", mode); + void* ret = NULL; + + // set guard for duration of handling dlopen, since want to ensure + // new mappings are resolved after the actual dlopen has occurred + PUSH_REENTRANCE; + hrtime_t hrt = GETRELTIME (); + + if (real_pathname && !__collector_strchr (real_pathname, '/')) + { // got an unqualified name + // get caller and use its searchpath +#if ! ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)) + void* caller = __builtin_return_address (0); // must be called inside dlopen +#endif + if (caller) + { +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) + ret = dlopen_searchpath_symver (real_dlopen, caller, real_pathname, mode); +#else + ret = dlopen_searchpath (caller, real_pathname, mode); +#endif + } + } + + if (!ret) + { +#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC) + ret = (real_dlopen) (real_pathname, mode); +#else + ret = CALL_REAL (dlopen)(real_pathname, mode); +#endif + } + TprintfT (DBG_LT2, "libcollector -- dlopen(%s) returning %p\n", pathname, ret); + + /* Don't call update if dlopen failed: preserve dlerror() */ + if (ret && (mmap_mode > 0) && !(mode & RTLD_NOLOAD)) + update_map_segments (hrt, 1); + TprintfT (DBG_LT2, "libcollector -- dlopen(%s) returning %p\n", pathname, ret); + POP_REENTRANCE; + return ret; +} + +/*------------------------------------------------------------- dlclose */ +int +dlclose (void *handle) +{ + if (NULL_PTR (dlclose)) + init_mmap_intf (); + TprintfT (DBG_LT2, "__collector_dlclose(%p) entered\n", handle); + hrtime_t hrt = GETRELTIME (); + if (!CHCK_REENTRANCE) + { + PUSH_REENTRANCE; + update_map_segments (hrt, 1); + POP_REENTRANCE; + hrt = GETRELTIME (); + } + int ret = CALL_REAL (dlclose)(handle); + + /* Don't call update if dlclose failed: preserve dlerror() */ + if (!ret && !CHCK_REENTRANCE) + { + PUSH_REENTRANCE; + update_map_segments (hrt, 1); + POP_REENTRANCE; + } + TprintfT (DBG_LT2, "__collector_dlclose(%p) returning %d\n", handle, ret); + return ret; +} diff --git a/gprofng/libcollector/profile.c b/gprofng/libcollector/profile.c new file mode 100644 index 0000000..996d3f0 --- /dev/null +++ b/gprofng/libcollector/profile.c @@ -0,0 +1,287 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Profile handling + * + * Note: SIGPROF signal-handling and interval timer (once exclusive to + * profile handling) are now common services provided by the dispatcher. + */ + +#include "config.h" +#include <dlfcn.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> +#include <unistd.h> + +#include "gp-defs.h" +#include "collector_module.h" +#include "gp-experiment.h" +#include "data_pckts.h" +#include "libcol_util.h" +#include "hwprofile.h" +#include "tsd.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +static int init_interface (CollectorInterface*); +static int open_experiment (const char *); +static int start_data_collection (void); +static int stop_data_collection (void); +static int close_experiment (void); +static int detach_experiment (void); + +static ModuleInterface module_interface ={ + SP_PROFILE_FILE, /* description */ + init_interface, /* initInterface */ + open_experiment, /* openExperiment */ + start_data_collection, /* startDataCollection */ + stop_data_collection, /* stopDataCollection */ + close_experiment, /* closeExperiment */ + detach_experiment /* detachExperiment (fork child) */ +}; + +static CollectorInterface *collector_interface = NULL; +static int prof_mode = 0; +static CollectorModule prof_hndl = COLLECTOR_MODULE_ERR; +static unsigned prof_key = COLLECTOR_TSD_INVALID_KEY; + +typedef struct ClockPacket +{ /* clock profiling packet */ + CM_Packet comm; + pthread_t lwp_id; + pthread_t thr_id; + uint32_t cpu_id; + hrtime_t tstamp __attribute__ ((packed)); + uint64_t frinfo __attribute__ ((packed)); + int mstate; /* kernel microstate */ + int nticks; /* number of ticks in that state */ +} ClockPacket; + +/* XXX should be able to use local types */ +#define CLOCK_TYPE OPROF_PCKT + +#define CHCK_REENTRANCE(x) ( !prof_mode || ((x) = collector_interface->getKey( prof_key )) == NULL || (*(x) != 0) ) +#define PUSH_REENTRANCE(x) ((*(x))++) +#define POP_REENTRANCE(x) ((*(x))--) + +#ifdef DEBUG +#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ ) +#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ ) +#else +#define Tprintf(...) +#define TprintfT(...) +#endif + +static void init_module () __attribute__ ((constructor)); + +static void +init_module () +{ + __collector_dlsym_guard = 1; + RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module"); + __collector_dlsym_guard = 0; + if (reg_module == NULL) + { + TprintfT (0, "clockprof: init_module FAILED -- reg_module = NULL\n"); + return; + } + prof_hndl = reg_module (&module_interface); + if (prof_hndl == COLLECTOR_MODULE_ERR && collector_interface != NULL) + { + Tprintf (0, "clockprof: ERROR: handle not created.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT); + } + TprintfT (0, "clockprof: init_module, prof_hndl = %d\n", prof_hndl); + return; +} + +static int +init_interface (CollectorInterface *_collector_interface) +{ + collector_interface = _collector_interface; + return COL_ERROR_NONE; +} + +static int +open_experiment (const char *exp) +{ + if (collector_interface == NULL) + { + Tprintf (0, "clockprof: ERROR: collector_interface is null.\n"); + return COL_ERROR_PROFINIT; + } + const char *params = collector_interface->getParams (); + while (params) + { + if (__collector_strStartWith (params, "p:") == 0) + { + params += 2; + break; + } + while (*params != 0 && *params != ';') + params++; + if (*params == 0) + params = NULL; + else + params++; + } + if (params == NULL) /* Clock profiling not specified */ + return COL_ERROR_PROFINIT; + TprintfT (0, "clockprof: open_experiment %s -- %s\n", exp, params); + int prof_interval = CALL_UTIL (strtol)(params, NULL, 0); + prof_key = collector_interface->createKey (sizeof ( int), NULL, NULL); + if (prof_key == (unsigned) - 1) + { + Tprintf (0, "clockprof: ERROR: TSD key create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT); + return COL_ERROR_PROFINIT; + } + + /* set dispatcher interval timer period used for all timed activities */ + int prof_interval_actual = __collector_ext_itimer_set (prof_interval); + TprintfT (0, "clockprof: open_experiment(): __collector_ext_itimer_set (actual period=%d, req_period=%d)\n", + prof_interval_actual, prof_interval); + if (prof_interval_actual <= 0) + { + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">itimer could not be set</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT); + return COL_ERROR_PROFINIT; + } + if ((prof_interval_actual >= (prof_interval + prof_interval / 10)) || + (prof_interval_actual <= (prof_interval - prof_interval / 10))) + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", SP_JCMD_CWARN, COL_WARN_PROFRND, prof_interval, prof_interval_actual); + else if (prof_interval_actual != prof_interval) + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", SP_JCMD_COMMENT, COL_WARN_PROFRND, prof_interval, prof_interval_actual); + prof_interval = prof_interval_actual; + collector_interface->writeLog ("<profile name=\"%s\" ptimer=\"%d\" numstates=\"%d\">\n", + SP_JCMD_PROFILE, prof_interval, LMS_MAGIC_ID_LINUX); + collector_interface->writeLog (" <profdata fname=\"%s\"/>\n", + module_interface.description); + + /* Record Profile packet description */ + ClockPacket *cp = NULL; + collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"" STXT ("Clock profiling data") "\">\n", CLOCK_TYPE); + collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n", + &cp->lwp_id, sizeof (cp->lwp_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n", + &cp->thr_id, sizeof (cp->thr_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n", + &cp->cpu_id, sizeof (cp->cpu_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n", + &cp->tstamp, sizeof (cp->tstamp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n", + &cp->frinfo, sizeof (cp->frinfo) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"MSTATE\" uname=\"" STXT ("Thread state") "\" offset=\"%d\" type=\"%s\"/>\n", + &cp->mstate, sizeof (cp->mstate) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"NTICK\" uname=\"" STXT ("Duration") "\" offset=\"%d\" type=\"%s\"/>\n", + &cp->nticks, sizeof (cp->nticks) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" </profpckt>\n"); + collector_interface->writeLog ("</profile>\n"); + return COL_ERROR_NONE; +} + +static int +start_data_collection (void) +{ + TprintfT (0, "clockprof: start_data_collection\n"); + prof_mode = 1; + return 0; +} + +static int +stop_data_collection (void) +{ + prof_mode = 0; + TprintfT (0, "clockprof: stop_data_collection\n"); + return 0; +} + +static int +close_experiment (void) +{ + prof_mode = 0; + prof_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (0, "clockprof: close_experiment\n"); + return 0; +} + +/* fork child. Clean up state but don't write to experiment */ +static int +detach_experiment (void) +{ + prof_mode = 0; + prof_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (0, "clockprof: detach_experiment\n"); + return 0; +} + +/* + * void collector_lost_profile_context + * Placeholder/marker function used when profiling given NULL context. + */ +void +__collector_lost_profile_context (void) { } + +/* + * void __collector_ext_profile_handler( siginfo_t *info, ucontext_t *context ) + * Handle real profile events to collect profile data. + */ +void +__collector_ext_profile_handler (siginfo_t *info, ucontext_t *context) +{ + int *guard; + if (!prof_mode) /* sigprof timer running only because hwprofile.c needs it */ + return; + if (CHCK_REENTRANCE (guard)) + { + TprintfT (0, "__collector_ext_profile_handler: ERROR: prof_mode=%d guard=%d!\n", + prof_mode, guard ? *guard : -2); + return; + } + PUSH_REENTRANCE (guard); + TprintfT (DBG_LT3, "__collector_ext_profile_handler\n"); + ucontext_t uctxmem; + if (context == NULL) + { + /* assume this case is rare, and accept overhead of creating dummy_uc */ + TprintfT (0, "collector_profile_handler: ERROR: got NULL context!\n"); + context = &uctxmem; + getcontext (context); /* initialize dummy context */ + SETFUNCTIONCONTEXT (context, &__collector_lost_profile_context); + } + ClockPacket pckt; + CALL_UTIL (memset)(&pckt, 0, sizeof ( pckt)); + pckt.comm.tsize = sizeof ( pckt); + pckt.comm.type = CLOCK_TYPE; + pckt.lwp_id = __collector_lwp_self (); + pckt.thr_id = __collector_thr_self (); + pckt.cpu_id = CALL_UTIL (getcpuid)(); + pckt.tstamp = collector_interface->getHiResTime (); + pckt.frinfo = collector_interface->getFrameInfo (COLLECTOR_MODULE_ERR, pckt.tstamp, FRINFO_FROM_UC, context); + pckt.mstate = LMS_LINUX_CPU; + pckt.nticks = 1; + collector_interface->writeDataPacket (prof_hndl, (CM_Packet*) & pckt); + POP_REENTRANCE (guard); +} diff --git a/gprofng/libcollector/synctrace.c b/gprofng/libcollector/synctrace.c new file mode 100644 index 0000000..401c8f2 --- /dev/null +++ b/gprofng/libcollector/synctrace.c @@ -0,0 +1,1064 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Synchronization events + */ +#include "config.h" +#include <alloca.h> +#include <dlfcn.h> +#include <unistd.h> +#include <semaphore.h> /* sem_wait() */ +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <pthread.h> + +#include "gp-defs.h" +#include "collector_module.h" +#include "gp-experiment.h" +#include "data_pckts.h" +#include "i18n.h" +#include "tsd.h" +#include "cc_libcollector.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LTT 0 // for interposition on GLIBC functions +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* define the packet that will be written out */ +typedef struct Sync_packet +{ /* Synchronization delay tracing packet */ + Common_packet comm; + hrtime_t requested; /* time of synchronization request */ + Vaddr_type objp; /* vaddr of synchronization object */ +} Sync_packet; + +static int open_experiment (const char *); +static int start_data_collection (void); +static int stop_data_collection (void); +static int close_experiment (void); +static int detach_experiment (void); +static int init_thread_intf (); +static int sync_calibrate (); + +static ModuleInterface module_interface ={ + SP_SYNCTRACE_FILE, /* description */ + NULL, /* initInterface */ + open_experiment, /* openExperiment */ + start_data_collection, /* startDataCollection */ + stop_data_collection, /* stopDataCollection */ + close_experiment, /* closeExperiment */ + detach_experiment /* detachExperiment (fork child) */ +}; + +static CollectorInterface *collector_interface = NULL; +static int sync_mode = 0; +static long sync_scope = 0; +static int sync_native = 0; +static int sync_java = 0; +static CollectorModule sync_hndl = COLLECTOR_MODULE_ERR; +static unsigned sync_key = COLLECTOR_TSD_INVALID_KEY; +static long sync_threshold = -1; /* calibrate the value */ +static int init_thread_intf_started = 0; +static int init_thread_intf_finished = 0; + +#define CHCK_NREENTRANCE(x) (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0)) +#define RECHCK_NREENTRANCE(x) (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0)) +#define CHCK_JREENTRANCE(x) (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0)) +#define RECHCK_JREENTRANCE(x) (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0)) +#define PUSH_REENTRANCE(x) ((*(x))++) +#define POP_REENTRANCE(x) ((*(x))--) + +#define CALL_REAL(x) (*(int(*)())__real_##x) +#define NULL_PTR(x) ( __real_##x == NULL ) +#define gethrtime collector_interface->getHiResTime + +#ifdef DEBUG +#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ ) +#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ ) +#else +#define Tprintf(...) +#define TprintfT(...) +#endif + +/* + * In most cases, the functions which require interposition are implemented as + * weak symbols corresponding to an associated internal function named with a + * leading underscore: e.g., mutex_lock() is simply an alias for _mutex_lock(). + * For the wait functions, however, the published version (used by applications) + * is distinct from the internal version (used by system libraries), i.e., + * cond_wait() is an alias for _cond_wait_cancel() rather than _cond_wait(). + */ +static void *__real_strtol = NULL; +static void *__real_fprintf = NULL; +static void *__real___collector_jprofile_enable_synctrace = NULL; +static void *__real_pthread_mutex_lock = NULL; +static void *__real_pthread_mutex_unlock = NULL; /* not interposed, used in calibrate */ +static void *__real_pthread_cond_wait = NULL; +static void *__real_pthread_cond_timedwait = NULL; +static void *__real_pthread_join = NULL; +static void *__real_sem_wait = NULL; +static void *__real_pthread_cond_wait_2_3_2 = NULL; +static void *__real_pthread_cond_timedwait_2_3_2 = NULL; + +#if WSIZE(32) +static void *__real_sem_wait_2_1 = NULL; +static void *__real_sem_wait_2_0 = NULL; +static void *__real_pthread_cond_wait_2_0 = NULL; +static void *__real_pthread_cond_timedwait_2_0 = NULL; +#elif WSIZE(64) +#if ARCH(Intel) +static void *__real_pthread_cond_wait_2_2_5 = NULL; +static void *__real_pthread_cond_timedwait_2_2_5 = NULL; +#elif ARCH(SPARC) +static void *__real_pthread_cond_wait_2_2 = NULL; +static void *__real_pthread_cond_timedwait_2_2 = NULL; +#endif /* ARCH() */ +#endif /* WSIZE() */ + +static void +collector_memset (void *s, int c, size_t n) +{ + unsigned char *s1 = s; + while (n--) + *s1++ = (unsigned char) c; +} + +void +__collector_module_init (CollectorInterface *_collector_interface) +{ + if (_collector_interface == NULL) + return; + collector_interface = _collector_interface; + TprintfT (0, "synctrace: __collector_module_init\n"); + sync_hndl = collector_interface->registerModule (&module_interface); + + /* Initialize next module */ + ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init"); + if (next_init != NULL) + next_init (_collector_interface); +} + +static int +open_experiment (const char *exp) +{ + long thresh = 0; + if (init_thread_intf_finished == 0) + init_thread_intf (); + if (collector_interface == NULL) + { + Tprintf (0, "synctrace: collector_interface is null.\n"); + return COL_ERROR_SYNCINIT; + } + if (sync_hndl == COLLECTOR_MODULE_ERR) + { + Tprintf (0, "synctrace: handle create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_SYNCINIT); + return COL_ERROR_SYNCINIT; + } + TprintfT (0, "synctrace: open_experiment %s\n", exp); + + char *params = (char *) collector_interface->getParams (); + while (params) + { + if ((params[0] == 's') && (params[1] == ':')) + { + char *ptr = params + 2; + Tprintf (DBG_LT1, "synctrace: open_experiment s: parameter = %s\n", ptr); + while (*ptr != ',' && *ptr != ';') + ptr++; + sync_scope = 0; + if (*ptr == ',') + { + sync_scope = CALL_REAL (strtol) (ptr + 1, NULL, 0); + switch (sync_scope) + { + case 1: + sync_java = 0; + sync_native = 1; + break; + case 2: + sync_java = 1; + sync_native = 0; + break; + default: + case 3: + sync_native = 1; + sync_java = 1; + break; + } + Tprintf (0, "\tsynctrace: sync_scope found as %ld\n", sync_scope); + } + else + { + /* the old-style descriptor, without scope */ + /* if there was no comma, use the old default */ + sync_scope = 3; + sync_java = 1; + sync_native = 1; + Tprintf (0, "\tsynctrace: sync_scope not found set to %ld\n", sync_scope); + } + if (__real___collector_jprofile_enable_synctrace == NULL) + sync_java = 0; + thresh = CALL_REAL (strtol)(params + 2, NULL, 0); + break; /* from the loop to find the "s:thresh,scope" entry */ + } + else + params++; + } + if (params == NULL) /* Sync data collection not specified */ + return COL_ERROR_SYNCINIT; + if (thresh < 0) /* calibrate the threshold, keep it as a negative number */ + thresh = -sync_calibrate (); + + sync_key = collector_interface->createKey (sizeof ( int), NULL, NULL); + if (sync_key == (unsigned) - 1) + { + Tprintf (0, "synctrace: TSD key create failed.\n"); + collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", + SP_JCMD_CERROR, COL_ERROR_SYNCINIT); + return COL_ERROR_SYNCINIT; + } + /* if Java synctrace was requested, tell the jprofile module */ + if (sync_java) + { + TprintfT (0, "synctrace: enabling Java synctrace\n"); + CALL_REAL (__collector_jprofile_enable_synctrace)(); + } + collector_interface->writeLog ("<profile name=\"%s\" threshold=\"%ld\" scope=\"%ld\">\n", + SP_JCMD_SYNCTRACE, thresh, sync_scope); + collector_interface->writeLog (" <profdata fname=\"%s\"/>\n", + module_interface.description); + /* Record Sync_packet description */ + Sync_packet *pp = NULL; + collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Synchronization tracing data\">\n", SYNC_PCKT); + collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n", + &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"SRQST\" uname=\"Synchronization start time\" offset=\"%d\" type=\"%s\"/>\n", + &pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" <field name=\"SOBJ\" uname=\"Synchronization object address\" offset=\"%d\" type=\"%s\"/>\n", + &pp->objp, sizeof (pp->objp) == 4 ? "INT32" : "INT64"); + collector_interface->writeLog (" </profpckt>\n"); + collector_interface->writeLog ("</profile>\n"); + + /* Convert threshold from microsec to nanosec */ + sync_threshold = (thresh > 0 ? thresh : -thresh) * 1000; + TprintfT (0, "synctrace: open_experiment complete %ld\n", sync_threshold); + return COL_ERROR_NONE; +} + +static int +start_data_collection (void) +{ + sync_mode = 1; + TprintfT (0, "synctrace: start_data_collection\n"); + return 0; +} + +static int +stop_data_collection (void) +{ + sync_mode = 0; + TprintfT (0, "synctrace: stop_data_collection\n"); + return 0; +} + +static int +close_experiment (void) +{ + sync_mode = 0; + sync_threshold = -1; + sync_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (0, "synctrace: close_experiment\n"); + return 0; +} + +/* fork child. Clean up state but don't write to experiment */ +static int +detach_experiment (void) +{ + sync_mode = 0; + sync_threshold = -1; + sync_key = COLLECTOR_TSD_INVALID_KEY; + TprintfT (0, "synctrace: detach_experiment\n"); + return 0; +} + +#define NUM_ITER 100 /* number of iterations in calibration */ +#define NUM_WARMUP 3 /* number of warm up iterations */ + +static int +sync_calibrate () +{ + pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; + hrtime_t bt, at, delta; + hrtime_t avg, max, min; + int i; + int ret; + avg = (hrtime_t) 0; + min = max = (hrtime_t) 0; + for (i = 0; i < NUM_ITER + NUM_WARMUP; i++) + { + /* Here we simulate a real call */ + bt = gethrtime (); + ret = CALL_REAL (pthread_mutex_lock)(&mt); + at = gethrtime (); + CALL_REAL (pthread_mutex_unlock)(&mt); + if (i < NUM_WARMUP) /* skip these iterations */ + continue; + /* add the time of this one */ + delta = at - bt; + avg += delta; + if (min == 0) + min = delta; + if (delta < min) + min = delta; + if (delta > max) + max = delta; + } + /* compute average time */ + avg = avg / NUM_ITER; + + /* pretty simple, let's see how it works */ + if (max < 6 * avg) + max = 6 * avg; + /* round up to the nearest microsecond */ + ret = (int) ((max + 999) / 1000); + return ret; +} + +static int +init_thread_intf () +{ + void *dlflag = RTLD_NEXT; + int err = 0; + /* if we detect recursion/reentrance, SEGV so we can get a stack */ + init_thread_intf_started++; + if (!init_thread_intf_finished && init_thread_intf_started >= 3) + { + /* pull the plug if recursion occurs... */ + abort (); + } + /* lookup fprint to print fatal error message */ + void *ptr = dlsym (RTLD_DEFAULT, "fprintf"); + if (ptr) + { + __real_fprintf = (void *) ptr; + } + else + { + abort (); + } + + /* find the __collector_jprofile_enable_synctrace routine in jprofile module */ + ptr = dlsym (RTLD_DEFAULT, "__collector_jprofile_enable_synctrace"); + if (ptr) + __real___collector_jprofile_enable_synctrace = (void *) ptr; + else + { +#if defined(GPROFNG_JAVA_PROFILING) + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __collector_jprofile_enable_synctrace\n"); + err = COL_ERROR_SYNCINIT; +#endif + sync_java = 0; + } + +#if WSIZE(32) + /* ########################################## begin WSIZE(32) */ + /* IMPORTANT!! The GLIBC_* versions below must match those in the er_sync.*.mapfile ! */ + dlflag = RTLD_NEXT; + ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0"); + if (ptr == NULL) + { + /* We are probably dlopened after libthread/libc, + * try to search in the previously loaded objects + */ + dlflag = RTLD_DEFAULT; + ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0"); + if (ptr != NULL) + { + __real_pthread_mutex_lock = ptr; + Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for OS sync routines\n"); + } + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n"); + err = COL_ERROR_SYNCINIT; + } + } + else + __real_pthread_mutex_lock = ptr; + + ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.0"); + if (ptr) + __real_pthread_mutex_unlock = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2"); + if (ptr) + __real_pthread_cond_wait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2"); + if (ptr) + __real_pthread_cond_timedwait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.0"); + if (ptr) + __real_pthread_join = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.1"); + if (ptr) + __real_sem_wait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n"); + err = COL_ERROR_SYNCINIT; + } + +#if ARCH(Intel) + /* ############## Intel specific additional pointers for 32-bits */ + ptr = __real_sem_wait_2_1 = __real_sem_wait; + ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.0"); + if (ptr) + __real_sem_wait_2_0 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait_2_0\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.0"); + if (ptr) + __real_pthread_cond_wait_2_0 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_0\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.0"); + if (ptr) + __real_pthread_cond_timedwait_2_0 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __real_pthread_cond_timedwait_2_0\n"); + err = COL_ERROR_SYNCINIT; + } +#endif /* ARCH(Intel) */ + +#else /* WSIZE(64) */ + /* # most versions are different between platforms */ + /* # the few that are common are set after the ARCH ifdef */ +#if ARCH(Aarch64) + dlflag = RTLD_NEXT; +#define GLIBC_N "GLIBC_2.17" + __real_pthread_mutex_lock = dlvsym(dlflag, "pthread_mutex_lock", GLIBC_N); + __real_pthread_mutex_unlock = dlvsym(dlflag, "pthread_mutex_unlock", GLIBC_N); + __real_pthread_cond_wait = dlvsym(dlflag, "pthread_cond_wait", GLIBC_N); + __real_pthread_cond_timedwait = dlvsym(dlflag, "pthread_cond_timedwait", GLIBC_N); + __real_pthread_join = dlvsym(dlflag, "pthread_join", GLIBC_N); + __real_sem_wait = dlvsym(dlflag, "sem_wait", GLIBC_N); + +#elif ARCH(Intel) + dlflag = RTLD_NEXT; + ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5"); + if (ptr == NULL) + { + /* We are probably dlopened after libthread/libc, + * try to search in the previously loaded objects + */ + dlflag = RTLD_DEFAULT; + ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5"); + if (ptr != NULL) + { + __real_pthread_mutex_lock = ptr; + Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n"); + } + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n"); + err = COL_ERROR_SYNCINIT; + } + } + else + __real_pthread_mutex_lock = ptr; + ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2.5"); + if (ptr) + __real_pthread_mutex_unlock = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2"); + if (ptr) + __real_pthread_cond_wait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2"); + if (ptr) + __real_pthread_cond_timedwait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2.5"); + if (ptr) + __real_pthread_join = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2.5"); + if (ptr) + __real_sem_wait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2.5"); + if (ptr) + __real_pthread_cond_wait_2_2_5 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2.5"); + if (ptr) + __real_pthread_cond_timedwait_2_2_5 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2_5\n"); + err = COL_ERROR_SYNCINIT; + } + +#elif ARCH(SPARC) + dlflag = RTLD_NEXT; + ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2"); + if (ptr == NULL) + { + /* We are probably dlopened after libthread/libc, + * try to search in the previously loaded objects + */ + dlflag = RTLD_DEFAULT; + ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2"); + if (ptr != NULL) + { + __real_pthread_mutex_lock = ptr; + Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n"); + } + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT mutex_lock\n"); + err = COL_ERROR_SYNCINIT; + } + } + else + __real_pthread_mutex_lock = ptr; + ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2"); + if (ptr) + __real_pthread_mutex_unlock = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2"); + if (ptr) + __real_pthread_cond_wait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2"); + if (ptr) + __real_pthread_cond_timedwait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2"); + if (ptr) + __real_pthread_join = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2"); + if (ptr) + __real_sem_wait = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2"); + if (ptr) + __real_pthread_cond_wait_2_2 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n"); + err = COL_ERROR_SYNCINIT; + } + ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2"); + if (ptr) + __real_pthread_cond_timedwait_2_2 = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2\n"); + err = COL_ERROR_SYNCINIT; + } +#endif /* ARCH() */ +#endif /* WSIZE(64) */ + /* the pointers that are common to 32- and 64-bits, and to SPARC and Intel */ + + __real_pthread_cond_wait_2_3_2 = __real_pthread_cond_wait; + __real_pthread_cond_timedwait_2_3_2 = __real_pthread_cond_timedwait; + ptr = dlsym (dlflag, "strtol"); + if (ptr) + __real_strtol = (void *) ptr; + else + { + CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT strtol\n"); + err = COL_ERROR_SYNCINIT; + } + init_thread_intf_finished++; + TprintfT (0, "synctrace init_thread_intf complete\n"); + return err; +} + +/* These next two routines are used from jprofile to record Java synctrace data */ +void +__collector_jsync_begin () +{ + int *guard; + if (CHCK_JREENTRANCE (guard)) + { + Tprintf (DBG_LT1, "__collector_jsync_begin: skipped\n"); + return; + } + Tprintf (DBG_LT1, "__collector_jsync_begin: start event\n"); + PUSH_REENTRANCE (guard); +} + +void +__collector_jsync_end (hrtime_t reqt, void *object) +{ + int *guard; + if (RECHCK_JREENTRANCE (guard)) + { + Tprintf (DBG_LT1, "__collector_jsync_end: skipped\n"); + return; + } + hrtime_t grnt = gethrtime (); + if (grnt - reqt >= sync_threshold) + { + Sync_packet spacket; + collector_memset (&spacket, 0, sizeof ( Sync_packet)); + spacket.comm.tsize = sizeof ( Sync_packet); + spacket.comm.tstamp = grnt; + spacket.requested = reqt; + spacket.objp = (Vaddr_type) object; + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket); + collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket); + } + Tprintf (DBG_LT1, "__collector_jsync_begin: end event\n"); + POP_REENTRANCE (guard); +} + +/*-------------------------------------------------------- pthread_mutex_lock */ +int +pthread_mutex_lock (pthread_mutex_t *mp) +{ + int *guard; + if (NULL_PTR (pthread_mutex_lock)) + init_thread_intf (); + if (CHCK_NREENTRANCE (guard)) + return CALL_REAL (pthread_mutex_lock)(mp); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + int ret = CALL_REAL (pthread_mutex_lock)(mp); + if (RECHCK_NREENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + if (grnt - reqt >= sync_threshold) + { + Sync_packet spacket; + collector_memset (&spacket, 0, sizeof ( Sync_packet)); + spacket.comm.tsize = sizeof ( Sync_packet); + spacket.comm.tstamp = grnt; + spacket.requested = reqt; + spacket.objp = (Vaddr_type) mp; + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket); + collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket); + } + POP_REENTRANCE (guard); + return ret; +} + + +/*------------------------------------------------------------- pthread_cond_wait */ +// map interposed symbol versions +static int +__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex); + +int +__collector_pthread_cond_wait_2_3_2 (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if (NULL_PTR (pthread_cond_wait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_3_2@%p\n", CALL_REAL (pthread_cond_wait_2_3_2)); + return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_3_2), cond, mutex); +} + +#if ARCH(Intel) || ARCH(SPARC) +__asm__(".symver __collector_pthread_cond_wait_2_3_2,pthread_cond_wait@@GLIBC_2.3.2"); +#endif + +#if WSIZE(32) + +int +__collector_pthread_cond_wait_2_0 (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if (NULL_PTR (pthread_cond_wait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_0@%p\n", CALL_REAL (pthread_cond_wait_2_0)); + return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_0), cond, mutex); +} + +__asm__(".symver __collector_pthread_cond_wait_2_0,pthread_cond_wait@GLIBC_2.0"); + +#else // WSIZE(64) +#if ARCH(Intel) +int +__collector_pthread_cond_wait_2_2_5 (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if (NULL_PTR (pthread_cond_wait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2_5@%p\n", CALL_REAL (pthread_cond_wait_2_2_5)); + return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2_5), cond, mutex); +} + +__asm__(".symver __collector_pthread_cond_wait_2_2_5,pthread_cond_wait@GLIBC_2.2.5"); +#elif ARCH(SPARC) + +int +__collector_pthread_cond_wait_2_2 (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if (NULL_PTR (pthread_cond_wait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2@%p\n", CALL_REAL (pthread_cond_wait_2_2)); + return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2), cond, mutex); +} + +__asm__(".symver __collector_pthread_cond_wait_2_2,pthread_cond_wait@GLIBC_2.2"); +#endif // ARCH() +#endif // WSIZE() + +static int +__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + int *guard; + if (NULL_PTR (pthread_cond_wait)) + init_thread_intf (); + if (CHCK_NREENTRANCE (guard)) + return (real_pthread_cond_wait) (cond, mutex); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + int ret = -1; + ret = (real_pthread_cond_wait) (cond, mutex); + if (RECHCK_NREENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + if (grnt - reqt >= sync_threshold) + { + Sync_packet spacket; + collector_memset (&spacket, 0, sizeof ( Sync_packet)); + spacket.comm.tsize = sizeof ( Sync_packet); + spacket.comm.tstamp = grnt; + spacket.requested = reqt; + spacket.objp = (Vaddr_type) mutex; + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket); + collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket); + } + POP_REENTRANCE (guard); + return ret; +} + +/*---------------------------------------------------- pthread_cond_timedwait */ +// map interposed symbol versions +static int +__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (), + pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); + +int +__collector_pthread_cond_timedwait_2_3_2 (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + if (NULL_PTR (pthread_cond_timedwait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_3_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_3_2)); + return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_3_2), cond, mutex, abstime); +} + +#if ARCH(Intel) || ARCH(SPARC) +__asm__(".symver __collector_pthread_cond_timedwait_2_3_2,pthread_cond_timedwait@@GLIBC_2.3.2"); +#endif // ARCH() + +#if WSIZE(32) +int +__collector_pthread_cond_timedwait_2_0 (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + if (NULL_PTR (pthread_cond_timedwait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_0@%p\n", CALL_REAL (pthread_cond_timedwait_2_0)); + return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_0), cond, mutex, abstime); +} + +__asm__(".symver __collector_pthread_cond_timedwait_2_0,pthread_cond_timedwait@GLIBC_2.0"); + +#else // WSIZE(64) +#if ARCH(Intel) +int +__collector_pthread_cond_timedwait_2_2_5 (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + if (NULL_PTR (pthread_cond_timedwait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2_5@%p\n", CALL_REAL (pthread_cond_timedwait_2_2_5)); + return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2_5), cond, mutex, abstime); +} + +__asm__(".symver __collector_pthread_cond_timedwait_2_2_5,pthread_cond_timedwait@GLIBC_2.2.5"); +#elif ARCH(SPARC) + +int +__collector_pthread_cond_timedwait_2_2 (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + if (NULL_PTR (pthread_cond_timedwait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_2)); + return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2), cond, mutex, abstime); +} + +__asm__(".symver __collector_pthread_cond_timedwait_2_2,pthread_cond_timedwait@GLIBC_2.2"); +#endif // ARCH() +#endif // WSIZE() + +static int +__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (), + pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + int *guard; + if (NULL_PTR (pthread_cond_timedwait)) + init_thread_intf (); + if (CHCK_NREENTRANCE (guard)) + return (real_pthread_cond_timedwait) (cond, mutex, abstime); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + int ret = -1; + ret = (real_pthread_cond_timedwait) (cond, mutex, abstime); + if (RECHCK_NREENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + if (grnt - reqt >= sync_threshold) + { + Sync_packet spacket; + collector_memset (&spacket, 0, sizeof ( Sync_packet)); + spacket.comm.tsize = sizeof ( Sync_packet); + spacket.comm.tstamp = grnt; + spacket.requested = reqt; + spacket.objp = (Vaddr_type) mutex; + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket); + collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket); + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- pthread_join */ +int +pthread_join (pthread_t target_thread, void **status) +{ + int *guard; + if (NULL_PTR (pthread_join)) + init_thread_intf (); + if (CHCK_NREENTRANCE (guard)) + return CALL_REAL (pthread_join)(target_thread, status); + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + int ret = CALL_REAL (pthread_join)(target_thread, status); + if (RECHCK_NREENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + if (grnt - reqt >= sync_threshold) + { + Sync_packet spacket; + collector_memset (&spacket, 0, sizeof ( Sync_packet)); + spacket.comm.tsize = sizeof ( Sync_packet); + spacket.comm.tstamp = grnt; + spacket.requested = reqt; + spacket.objp = (Vaddr_type) target_thread; + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket); + collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket); + } + POP_REENTRANCE (guard); + return ret; +} + +/*------------------------------------------------------------- sem_wait */ +// map interposed symbol versions +#if ARCH(Intel) && WSIZE(32) +static int +__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp); + +int +__collector_sem_wait_2_1 (sem_t *sp) +{ + if (NULL_PTR (sem_wait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_1@%p\n", CALL_REAL (sem_wait_2_1)); + return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_1), sp); +} + +int +__collector_sem_wait_2_0 (sem_t *sp) +{ + if (NULL_PTR (sem_wait)) + init_thread_intf (); + TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_0@%p\n", CALL_REAL (sem_wait_2_0)); + return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_0), sp); +} + +__asm__(".symver __collector_sem_wait_2_1,sem_wait@@GLIBC_2.1"); +__asm__(".symver __collector_sem_wait_2_0,sem_wait@GLIBC_2.0"); +#endif + +#if ARCH(Intel) && WSIZE(32) +static int +__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp) +{ +#else +int +sem_wait (sem_t *sp) +{ +#endif + int *guard; + if (NULL_PTR (sem_wait)) + init_thread_intf (); + if (CHCK_NREENTRANCE (guard)) + { +#if ARCH(Intel) && WSIZE(32) + return (real_sem_wait) (sp); +#else + return CALL_REAL (sem_wait)(sp); +#endif + } + PUSH_REENTRANCE (guard); + hrtime_t reqt = gethrtime (); + int ret = -1; +#if ARCH(Intel) && WSIZE(32) + ret = (real_sem_wait) (sp); +#else + ret = CALL_REAL (sem_wait)(sp); +#endif + if (RECHCK_NREENTRANCE (guard)) + { + POP_REENTRANCE (guard); + return ret; + } + hrtime_t grnt = gethrtime (); + if (grnt - reqt >= sync_threshold) + { + Sync_packet spacket; + collector_memset (&spacket, 0, sizeof ( Sync_packet)); + spacket.comm.tsize = sizeof ( Sync_packet); + spacket.comm.tstamp = grnt; + spacket.requested = reqt; + spacket.objp = (Vaddr_type) sp; + +#if ARCH(Intel) && WSIZE(32) + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket); +#else + spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket); +#endif + collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket); + } + POP_REENTRANCE (guard); + return ret; +} diff --git a/gprofng/libcollector/tsd.c b/gprofng/libcollector/tsd.c new file mode 100644 index 0000000..416c3e7 --- /dev/null +++ b/gprofng/libcollector/tsd.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <pthread.h> + +#include "collector.h" +#include "libcol_util.h" +#include "tsd.h" +#include "memmgr.h" + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 + +/* + * Build our thread-specific-data support on pthread interfaces. + */ +#define MAXNKEYS 64 /* hard-wired? really? well, it depends only on us and we have a sense for how many keys we will use */ +static pthread_key_t tsd_pkeys[MAXNKEYS]; +static size_t tsd_sizes[MAXNKEYS]; +static unsigned tsd_nkeys = 0; + +int +__collector_tsd_init () +{ + return 0; +} + +void +__collector_tsd_fini () +{ + Tprintf (DBG_LT1, "tsd_fini()\n"); + while (tsd_nkeys) + { + tsd_nkeys--; + pthread_key_delete (tsd_pkeys[tsd_nkeys]); + tsd_sizes[tsd_nkeys] = 0; // should be unneeded + } +} + +int +__collector_tsd_allocate () +{ + return 0; +} + +void +__collector_tsd_release () { } + +static void +tsd_destructor (void *p) +{ + if (p) + __collector_freeCSize (__collector_heap, p, *((size_t *) p)); +} + +unsigned +__collector_tsd_create_key (size_t sz, void (*init)(void*), void (*fini)(void*)) +{ + /* + * We no longer support init and fini arguments (and weren't using them anyhow). + * Our hard-wired MAXNKEYS presumably is considerably higher than the number of keys we use. + */ + if (init || fini || (tsd_nkeys >= MAXNKEYS)) + return COLLECTOR_TSD_INVALID_KEY; + + /* + * A pthread key has a value that is (void *). + * We don't know where it is stored, and can access its value only through {get|set}specific. + * But libcollector expects a pointer to memory that it can modify. + * So we have to allocate that memory and store the pointer. + * + * For now, we just have to register a destructor that will free the memory + * when the thread finishes. + */ + if (pthread_key_create (&tsd_pkeys[tsd_nkeys], &tsd_destructor)) + return COLLECTOR_TSD_INVALID_KEY; + tsd_sizes[tsd_nkeys] = sz; + tsd_nkeys++; + return (tsd_nkeys - 1); +} + +void * +__collector_tsd_get_by_key (unsigned key_index) +{ + if (key_index == COLLECTOR_TSD_INVALID_KEY) + return NULL; + if (key_index < 0 || key_index >= tsd_nkeys) + return NULL; + pthread_key_t key = tsd_pkeys[key_index]; + size_t sz = tsd_sizes[key_index]; + + /* + * When we use __collector_freeCSize(), we need to know the + * size that had been allocated. So, stick a header to the + * front of the allocation to hold the size. The header could + * just be sizeof(size_t), but pad it to preserve alignment for + * the usable area. + */ + size_t header = 8; + void *value = pthread_getspecific (key); + + // check whether we have allocated the memory + if (value == NULL) + { + // add room to record the size + value = __collector_allocCSize (__collector_heap, sz + header, 0); + if (value == NULL) + { + // do we need to guard against trying to alloc each time? + return NULL; + } + // write the size of the allocation + *((size_t *) value) = sz + header; + CALL_UTIL (memset)(((char *) value) + header, 0, sz); + + // record the allocation for future retrieval + if (pthread_setspecific (key, value)) + return NULL; + } + // return the pointer, skipping the header + return ((char *) value) +header; +} + +void +__collector_tsd_fork_child_cleanup () +{ + __collector_tsd_fini (); +} diff --git a/gprofng/libcollector/tsd.h b/gprofng/libcollector/tsd.h new file mode 100644 index 0000000..38b3d53 --- /dev/null +++ b/gprofng/libcollector/tsd.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* Thread-specific data */ + +#ifndef _TSD_H +#define _TSD_H + +#include <sys/types.h> + +int __collector_tsd_init (); +/* Function: Init tsd module. Call once before using other functions. + MT-Level: Unsafe + Return: 0 if successful + */ + +void __collector_tsd_fini (); +/* Function: Shutdown tsd module. + MT-Level: Unsafe + Return: None + */ + +void __collector_tsd_fork_child_cleanup (); +/* Function: Reset tsd module. Call immediately after fork() in child process. + MT-Level: Unsafe + Return: None + */ + +int __collector_tsd_allocate (); +/* Function: Allocate thread info. + Call from threads before using tsd_get_by_key(). + Call from main thread should be made before calls from other threads. + MT-Level: First call is unsafe. Safe afterwards. + Return: 0 if successful + */ + +void __collector_tsd_release (); +/* Function: Free thread info. + Call from threads just before thread termination. + MT-Level: Safe + Return: None + */ + +#define COLLECTOR_TSD_INVALID_KEY ((unsigned)-1) +unsigned __collector_tsd_create_key (size_t memsize, void (*init)(void*), void (*fini)(void*)); +/* Function: Reserve TDS memory. + MT-Level: Unsafe + Inputs: <memsize>: number of bytes to reserve + <init>: key memory initialization. Must be callable even if + the associated thread has not yet been created. + <fini>: key memory finalization. Must be callable even if + the associated thread has been terminated. + Return: key or COLLECTOR_TSD_INVALID_KEY if not successful. + */ + +void *__collector_tsd_get_by_key (unsigned key); +/* Function: Get TSD memory. + Call from threads after calling tsd_allocate(). + MT-Level: Safe + Inputs: <key>: return value from tsd_create_key() + Return: memory if successful, NULL otherwise + */ +#endif /* _TSD_H */ diff --git a/gprofng/libcollector/unwind.c b/gprofng/libcollector/unwind.c new file mode 100644 index 0000000..ffb06f9 --- /dev/null +++ b/gprofng/libcollector/unwind.c @@ -0,0 +1,4630 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <alloca.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <pthread.h> + +#include "gp-defs.h" +#include "collector.h" +#include "gp-experiment.h" +#include "memmgr.h" +#include "tsd.h" + +/* Get dynamic module interface*/ +#include "collector_module.h" + +/* Get definitions for SP_LEAF_CHECK_MARKER, SP_TRUNC_STACK_MARKER */ +#include "data_pckts.h" + +#if ARCH(SPARC) +struct frame +{ + long fr_local[8]; /* saved locals */ + long fr_arg[6]; /* saved arguments [0 - 5] */ + struct frame *fr_savfp; /* saved frame pointer */ + long fr_savpc; /* saved program counter */ +#if WSIZE(32) + char *fr_stret; /* struct return addr */ +#endif + long fr_argd[6]; /* arg dump area */ + long fr_argx[1]; /* array of args past the sixth */ +}; + +#elif ARCH(Intel) +struct frame +{ + unsigned long fr_savfp; + unsigned long fr_savpc; +}; +#endif + +/* Set the debug trace level */ +#define DBG_LT0 0 +#define DBG_LT1 1 +#define DBG_LT2 2 +#define DBG_LT3 3 + +int (*__collector_VM_ReadByteInstruction)(unsigned char *) = NULL; +#define VM_NO_ACCESS (-1) +#define VM_NOT_VM_MEMORY (-2) +#define VM_NOT_X_SEGMENT (-3) + +#define isInside(p, bgn, end) ((p) >= (bgn) && (p) < (end)) + +/* + * Weed through all the arch dependent stuff to get the right definition + * for 'pc' in the ucontext structure. The system header files are mess + * dealing with all the arch (just look for PC, R_PC, REG_PC). + * + */ + +#if ARCH(SPARC) + +#define IN_BARRIER(x) \ + ( barrier_hdl && \ + (unsigned long)x >= barrier_hdl && \ + (unsigned long)x < barrier_hdlx ) +static unsigned long barrier_hdl = 0; +static unsigned long barrier_hdlx = 0; + +#if WSIZE(64) +#define STACK_BIAS 2047 +#define IN_TRAP_HANDLER(x) \ + ( misalign_hdl && \ + (unsigned long)x >= misalign_hdl && \ + (unsigned long)x < misalign_hdlx ) +static unsigned long misalign_hdl = 0; +static unsigned long misalign_hdlx = 0; +#elif WSIZE(32) +#define STACK_BIAS 0 +#endif + +#if WSIZE(64) +#define GET_GREG(ctx,reg) (((ucontext_t*)ctx)->uc_mcontext.mc_gregs[(reg)]) +#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.mc_gregs[MC_O6]) +#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.mc_gregs[MC_PC]) +#else +#define GET_GREG(ctx,reg) (((ucontext_t*)ctx)->uc_mcontext.gregs[(reg)]) +#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_O6]) +#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_PC]) +#endif + +#elif ARCH(Intel) +#include "opcodes/disassemble.h" + +static int +fprintf_func (void *arg ATTRIBUTE_UNUSED, const char *fmt ATTRIBUTE_UNUSED, ...) +{ + return 0; +} + +/* Get LENGTH bytes from info's buffer, at target address memaddr. + Transfer them to myaddr. */ +static int +read_memory_func (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + disassemble_info *info) +{ + unsigned int opb = info->octets_per_byte; + size_t end_addr_offset = length / opb; + size_t max_addr_offset = info->buffer_length / opb; + size_t octets = (memaddr - info->buffer_vma) * opb; + if (memaddr < info->buffer_vma + || memaddr - info->buffer_vma > max_addr_offset + || memaddr - info->buffer_vma + end_addr_offset > max_addr_offset + || (info->stop_vma && (memaddr >= info->stop_vma + || memaddr + end_addr_offset > info->stop_vma))) + return -1; + memcpy (myaddr, info->buffer + octets, length); + return 0; +} + +static void +print_address_func (bfd_vma addr ATTRIBUTE_UNUSED, + disassemble_info *info ATTRIBUTE_UNUSED) { } + +static asymbol * +symbol_at_address_func (bfd_vma addr ATTRIBUTE_UNUSED, + disassemble_info *info ATTRIBUTE_UNUSED) +{ + return NULL; +} + +static bfd_boolean +symbol_is_valid (asymbol *sym ATTRIBUTE_UNUSED, + disassemble_info *info ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +static void +memory_error_func (int status ATTRIBUTE_UNUSED, bfd_vma addr ATTRIBUTE_UNUSED, + disassemble_info *info ATTRIBUTE_UNUSED) { } + + +#if WSIZE(32) +#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_EIP]) +#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_ESP]) +#define GET_FP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_EBP]) + +#elif WSIZE(64) +#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RIP]) +#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RSP]) +#define GET_FP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RBP]) +#endif /* WSIZE() */ + +#elif ARCH(Aarch64) +#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.regs[15]) +#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.regs[13]) +#define GET_FP(ctx) (((ucontext_t*)ctx)->uc_mcontext.regs[14]) +#endif /* ARCH() */ + +/* + * FILL_CONTEXT() for all platforms + * Could use getcontext() except: + * - it's not guaranteed to be async signal safe + * - it's a system call and not that lightweight + * - it's not portable as of POSIX.1-2008 + * So we just use low-level mechanisms to fill in the few fields we need. + */ +#if ARCH(SPARC) +#if WSIZE(32) +#define FILL_CONTEXT(context) \ + { \ + greg_t fp; \ + __asm__ __volatile__( "mov %%i6, %0" : "=r" (fp) ); \ + __asm__ __volatile__( "ta 3" ); \ + GET_SP(context) = fp; \ + GET_PC(context) = (greg_t)0; \ + } + +#elif WSIZE(64) +#define FILL_CONTEXT(context) \ + { \ + greg_t fp; \ + __asm__ __volatile__( "mov %%i6, %0" : "=r" (fp) ); \ + __asm__ __volatile__( "flushw" ); \ + GET_SP(context) = fp; \ + GET_PC(context) = (greg_t)0; \ + } +#endif /* WSIZE() */ + +#elif ARCH(Intel) +#define FILL_CONTEXT(context) \ + { \ + context->uc_link = NULL; \ + void *sp = __collector_getsp(); \ + GET_SP(context) = (greg_t)sp; \ + GET_FP(context) = (greg_t)__collector_getfp(); \ + GET_PC(context) = (greg_t)__collector_getpc(); \ + context->uc_stack.ss_sp = sp; \ + context->uc_stack.ss_size = 0x100000; \ + } + +#elif ARCH(Aarch64) +#define FILL_CONTEXT(context) \ + { getcontext(context); \ + context->uc_mcontext.sp = (__u64) __builtin_frame_address(0); \ + } + +#endif /* ARCH() */ + +static int +getByteInstruction (unsigned char *p) +{ + if (__collector_VM_ReadByteInstruction) + { + int v = __collector_VM_ReadByteInstruction (p); + if (v != VM_NOT_VM_MEMORY) + return v; + } + return *p; +} + +struct DataHandle *dhndl = NULL; + +static unsigned unwind_key = COLLECTOR_TSD_INVALID_KEY; + +/* To support two OpenMP API's we use a pointer + * to the actual function. + */ +int (*__collector_omp_stack_trace)(char*, int, hrtime_t, void*) = NULL; +int (*__collector_mpi_stack_trace)(char*, int, hrtime_t) = NULL; + +#define DEFAULT_MAX_NFRAMES 256 +static int max_native_nframes = DEFAULT_MAX_NFRAMES; +static int max_java_nframes = DEFAULT_MAX_NFRAMES; + +#define NATIVE_FRAME_BYTES(nframes) ( ((nframes)+1) * sizeof(long) ) +#define JAVA_FRAME_BYTES(nframes) ( ((nframes)+1) * sizeof(long) * 2 + 16 ) +#define OVERHEAD_BYTES ( 2 * sizeof(long) + 2 * sizeof(Stack_info) ) + +#define ROOT_UID 801425552975190205ULL +#define ROOT_UID_INV 92251691606677ULL +#define ROOT_IDX 13907816567264074199ULL +#define ROOT_IDX_INV 2075111ULL +#define UIDTableSize 1048576 +static volatile uint64_t *UIDTable = NULL; +static volatile int seen_omp = 0; + +static int stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode); +static FrameInfo compute_uid (Frame_packet *frp); +static int omp_no_walk = 0; + +#if ARCH(Intel) +#define ValTableSize 1048576 +#define OmpValTableSize 65536 +static unsigned long *AddrTable_RA_FROMFP = NULL; // Cache for RA_FROMFP pcs +static unsigned long *AddrTable_RA_EOSTCK = NULL; // Cache for RA_EOSTCK pcs +static struct WalkContext *OmpCurCtxs = NULL; +static struct WalkContext *OmpCtxs = NULL; +static uint32_t *OmpVals = NULL; +static unsigned long *OmpRAs = NULL; +static unsigned long adjust_ret_addr (unsigned long ra, unsigned long segoff, unsigned long tend); +static int parse_x86_AVX_instruction (unsigned char *pc); + +struct WalkContext +{ + unsigned long pc; + unsigned long sp; + unsigned long fp; + unsigned long ln; + unsigned long sbase; /* stack boundary */ + unsigned long tbgn; /* current memory segment start */ + unsigned long tend; /* current memory segment end */ +}; +#endif + +#if defined(DEBUG) && ARCH(Intel) +#include <execinfo.h> + +static void +dump_stack (int nline) +{ + if ((__collector_tracelevel & SP_DUMP_STACK) == 0) + return; + + enum Constexpr { MAX_SIZE = 1024 }; + void *array[MAX_SIZE]; + size_t sz = backtrace (array, MAX_SIZE); + char **strings = backtrace_symbols (array, sz); + DprintfT (SP_DUMP_STACK, "\ndump_stack: %d size=%d\n", nline, (int) sz); + for (int i = 0; i < sz; i++) + DprintfT (SP_DUMP_STACK, " %3d: %p %s\n", i, array[i], + strings[i] ? strings[i] : "???"); +} + +#define dump_targets(nline, ntrg, targets) \ + if ((__collector_tracelevel & SP_DUMP_UNWIND) != 0) \ + for(int i = 0; i < ntrg; i++) \ + DprintfT (SP_DUMP_UNWIND, " %2d: 0x%lx\n", i, (long) targets[i]) +#else +#define dump_stack(x) +#define dump_targets(nline, ntrg, targets) +#endif + +void +__collector_ext_unwind_key_init (int isPthread, void * stack) +{ + void * ptr = __collector_tsd_get_by_key (unwind_key); + if (ptr == NULL) + { + TprintfT (DBG_LT2, "__collector_ext_unwind_key_init: cannot get tsd\n"); + return; + } + if (isPthread) + { + size_t stack_size = 0; + void *stack_addr = 0; + pthread_t pthread = pthread_self (); + pthread_attr_t attr; + int err = pthread_getattr_np (pthread, &attr); + TprintfT (DBG_LT1, "__collector_ext_unwind_key_init: pthread: 0x%lx err: %d\n", pthread, err); + if (err == 0) + { + err = pthread_attr_getstack (&attr, &stack_addr, &stack_size); + if (err == 0) + stack_addr = (char*) stack_addr + stack_size; + TprintfT (DBG_LT1, "__collector_ext_unwind_key_init: stack_size=0x%lx eos=%p err=%d\n", + (long) stack_size, stack_addr, err); + err = pthread_attr_destroy (&attr); + TprintfT (DBG_LT1, "__collector_ext_unwind_key_init: destroy: %d\n", err); + } + *(void**) ptr = stack_addr; + } + else + *(void**) ptr = stack; // cloned thread +} + +void +__collector_ext_unwind_init (int record) +{ + int sz = UIDTableSize * sizeof (*UIDTable); + UIDTable = (uint64_t*) __collector_allocCSize (__collector_heap, sz, 1); + if (UIDTable == NULL) + { + __collector_terminate_expt (); + return; + } + CALL_UTIL (memset)((void*) UIDTable, 0, sz); + + char *str = CALL_UTIL (getenv)("GPROFNG_JAVA_MAX_CALL_STACK_DEPTH"); + if (str != NULL && *str != 0) + { + char *endptr; + int n = CALL_UTIL (strtol)(str, &endptr, 0); + if (endptr != str && n >= 0) + { + if (n < 5) + n = 5; + if (n > MAX_STACKDEPTH) + n = MAX_STACKDEPTH; + max_java_nframes = n; + } + } + + str = CALL_UTIL (getenv)("GPROFNG_MAX_CALL_STACK_DEPTH"); + if (str != NULL && *str != 0) + { + char *endptr = str; + int n = CALL_UTIL (strtol)(str, &endptr, 0); + if (endptr != str && n >= 0) + { + if (n < 5) + n = 5; + if (n > MAX_STACKDEPTH) + n = MAX_STACKDEPTH; + max_native_nframes = n; + } + } + + TprintfT (DBG_LT0, "GPROFNG_MAX_CALL_STACK_DEPTH=%d GPROFNG_JAVA_MAX_CALL_STACK_DEPTH=%d\n", + max_native_nframes, max_java_nframes); + omp_no_walk = 1; + + if (__collector_VM_ReadByteInstruction == NULL) + __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction"); + +#if ARCH(SPARC) +#if WSIZE(64) + misalign_hdl = (unsigned long) dlsym (RTLD_DEFAULT, "__misalign_trap_handler"); + misalign_hdlx = (unsigned long) dlsym (RTLD_DEFAULT, "__misalign_trap_handler_end"); + if (misalign_hdlx == 0) + misalign_hdlx = misalign_hdl + 292; + barrier_hdl = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_"); + barrier_hdlx = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_Dummy_"); + if (barrier_hdlx == 0) + barrier_hdl = 0; +#else + barrier_hdl = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_"); + barrier_hdlx = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_Dummy_"); + if (barrier_hdlx == 0) + barrier_hdl = 0; +#endif /* WSIZE() */ + +#elif ARCH(Intel) + sz = ValTableSize * sizeof (*AddrTable_RA_FROMFP); + AddrTable_RA_FROMFP = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1); + sz = ValTableSize * sizeof (*AddrTable_RA_EOSTCK); + AddrTable_RA_EOSTCK = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1); + if (omp_no_walk && (__collector_omp_stack_trace != NULL || __collector_mpi_stack_trace != NULL)) + { + sz = OmpValTableSize * sizeof (*OmpCurCtxs); + OmpCurCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1); + sz = OmpValTableSize * sizeof (*OmpCtxs); + OmpCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1); + sz = OmpValTableSize * sizeof (*OmpVals); + OmpVals = (uint32_t*) __collector_allocCSize (__collector_heap, sz, 1); + sz = OmpValTableSize * sizeof (*OmpRAs); + OmpRAs = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1); + if (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL) + { + TprintfT (0, "unwind_init() ERROR: failed; terminating experiment\n"); + __collector_terminate_expt (); + return; + } + } +#endif /* ARCH() */ + + if (record) + { + dhndl = __collector_create_handle (SP_FRINFO_FILE); + __collector_log_write ("<%s name=\"%s\" format=\"binary\"/>\n", SP_TAG_DATAPTR, SP_FRINFO_FILE); + } + + unwind_key = __collector_tsd_create_key (sizeof (void*), NULL, NULL); + if (unwind_key == COLLECTOR_TSD_INVALID_KEY) + { + TprintfT (0, "unwind_init: ERROR: TSD key create failed.\n"); + __collector_log_write ("<%s kind=\"%s\" id=\"%d\">TSD key not created</%s>\n", + SP_TAG_EVENT, SP_JCMD_CERROR, COL_ERROR_GENERAL, SP_TAG_EVENT); + return; + } + TprintfT (0, "unwind_init() completed normally\n"); + return; +} + +void +__collector_ext_unwind_close () +{ + __collector_delete_handle (dhndl); + dhndl = NULL; +} + +void* +__collector_ext_return_address (unsigned level) +{ + if (NULL == UIDTable) //unwind not initialized yet + return NULL; + unsigned size = (level + 4) * sizeof (long); // need to strip __collector_get_return_address and its caller + ucontext_t context; + FILL_CONTEXT ((&context)); + char* buf = (char*) alloca (size); + if (buf == NULL) + { + TprintfT (DBG_LT0, "__collector_get_return_address: ERROR: alloca(%d) fails\n", size); + return NULL; + } + int sz = stack_unwind (buf, size, NULL, NULL, &context, 0); + if (sz < (level + 3) * sizeof (long)) + { + TprintfT (DBG_LT0, "__collector_get_return_address: size=%d, but stack_unwind returns %d\n", size, sz); + return NULL; + } + long *lbuf = (long*) buf; + TprintfT (DBG_LT2, "__collector_get_return_address: return %lx\n", lbuf[level + 2]); + return (void *) (lbuf[level + 2]); +} +/* + * Collector interface method getFrameInfo + */ +FrameInfo +__collector_get_frame_info (hrtime_t ts, int mode, void *arg) +{ + ucontext_t *context = NULL; + void *bptr = NULL; + CM_Array *array = NULL; + + int unwind_mode = 0; + int do_walk = 1; + + if (mode & FRINFO_NO_WALK) + do_walk = 0; + int bmode = mode & 0xffff; + int pseudo_context = 0; + if (bmode == FRINFO_FROM_STACK_ARG || bmode == FRINFO_FROM_STACK) + { + bptr = arg; + context = (ucontext_t*) alloca (sizeof (ucontext_t)); + FILL_CONTEXT (context); + unwind_mode |= bmode; + } + else if (bmode == FRINFO_FROM_UC) + { + context = (ucontext_t*) arg; + if (context == NULL) + return (FrameInfo) 0; + if (GET_SP (context) == 0) + pseudo_context = 1; + } + else if (bmode == FRINFO_FROM_ARRAY) + { + array = (CM_Array*) arg; + if (array == NULL || array->length <= 0) + return (FrameInfo) 0; + } + else + return (FrameInfo) 0; + + int max_frame_size = OVERHEAD_BYTES + NATIVE_FRAME_BYTES (max_native_nframes); + if (__collector_java_mode && __collector_java_asyncgetcalltrace_loaded && context && !pseudo_context) + max_frame_size += JAVA_FRAME_BYTES (max_java_nframes); + + Frame_packet *frpckt = alloca (sizeof (Frame_packet) + max_frame_size); + frpckt->type = FRAME_PCKT; + frpckt->hsize = sizeof (Frame_packet); + + char *d = (char*) (frpckt + 1); + int size = max_frame_size; + +#define MIN(a,b) ((a)<(b)?(a):(b)) + /* get Java info */ + if (__collector_java_mode && __collector_java_asyncgetcalltrace_loaded && context && !pseudo_context) + { + /* use only 2/3 of the buffer and leave the rest for the native stack */ + int tmpsz = MIN (size, JAVA_FRAME_BYTES (max_java_nframes)); + if (tmpsz > 0) + { + int sz = __collector_ext_jstack_unwind (d, tmpsz, context); + d += sz; + size -= sz; + } + } + + /* get native stack */ + if (context) + { + Stack_info *sinfo = (Stack_info*) d; + int sz = sizeof (Stack_info); + d += sz; + size -= sz; +#if ARCH(Intel) + if (omp_no_walk == 0) + do_walk = 1; +#endif + if (do_walk == 0) + unwind_mode |= FRINFO_NO_WALK; + + int tmpsz = MIN (size, NATIVE_FRAME_BYTES (max_native_nframes)); + if (tmpsz > 0) + { + sz = stack_unwind (d, tmpsz, bptr, NULL, context, unwind_mode); + d += sz; + size -= sz; + } + sinfo->kind = STACK_INFO; + sinfo->hsize = (d - (char*) sinfo); + } + + /* create a stack image from user data */ + if (array && array->length > 0) + { + Stack_info *sinfo = (Stack_info*) d; + int sz = sizeof (Stack_info); + d += sz; + size -= sz; + sz = array->length; + if (sz > size) + sz = size; // YXXX should we mark this with truncation frame? + __collector_memcpy (d, array->bytes, sz); + d += sz; + size -= sz; + sinfo->kind = STACK_INFO; + sinfo->hsize = (d - (char*) sinfo); + } + + /* Compute the total size */ + frpckt->tsize = d - (char*) frpckt; + FrameInfo uid = compute_uid (frpckt); + return uid; +} + +FrameInfo +compute_uid (Frame_packet *frp) +{ + uint64_t idxs[LAST_INFO]; + uint64_t uid = ROOT_UID; + uint64_t idx = ROOT_IDX; + + Common_info *cinfo = (Common_info*) ((char*) frp + frp->hsize); + char *end = (char*) frp + frp->tsize; + for (;;) + { + if ((char*) cinfo >= end || cinfo->hsize == 0 || + (char*) cinfo + cinfo->hsize > end) + break; + + /* Start with a different value to avoid matching with uid */ + uint64_t uidt = 1; + uint64_t idxt = 1; + long *ptr = (long*) ((char*) cinfo + cinfo->hsize); + long *bnd = (long*) ((char*) cinfo + sizeof (Common_info)); + TprintfT (DBG_LT2, "compute_uid: Cnt=%ld: ", (long) cinfo->hsize); + while (ptr > bnd) + { + long val = *(--ptr); + tprintf (DBG_LT2, "0x%8.8llx ", (unsigned long long) val); + uidt = (uidt + val) * ROOT_UID; + idxt = (idxt + val) * ROOT_IDX; + uid = (uid + val) * ROOT_UID; + idx = (idx + val) * ROOT_IDX; + } + if (cinfo->kind == STACK_INFO || cinfo->kind == JAVA_INFO) + { + cinfo->uid = uidt; + idxs[cinfo->kind] = idxt; + } + cinfo = (Common_info*) ((char*) cinfo + cinfo->hsize); + } + tprintf (DBG_LT2, "\n"); + + /* Check if we have already recorded that uid. + * The following fragment contains benign data races. + * It's important, though, that all reads from UIDTable + * happen before writes. + */ + int found1 = 0; + int idx1 = (int) ((idx >> 44) % UIDTableSize); + if (UIDTable[idx1] == uid) + found1 = 1; + int found2 = 0; + int idx2 = (int) ((idx >> 24) % UIDTableSize); + if (UIDTable[idx2] == uid) + found2 = 1; + int found3 = 0; + int idx3 = (int) ((idx >> 4) % UIDTableSize); + if (UIDTable[idx3] == uid) + found3 = 1; + if (!found1) + UIDTable[idx1] = uid; + if (!found2) + UIDTable[idx2] = uid; + if (!found3) + UIDTable[idx3] = uid; + + if (found1 || found2 || found3) + return (FrameInfo) uid; + frp->uid = uid; + + /* Compress info's */ + cinfo = (Common_info*) ((char*) frp + frp->hsize); + for (;;) + { + if ((char*) cinfo >= end || cinfo->hsize == 0 || + (char*) cinfo + cinfo->hsize > end) + break; + if (cinfo->kind == STACK_INFO || cinfo->kind == JAVA_INFO) + { + long *ptr = (long*) ((char*) cinfo + sizeof (Common_info)); + long *bnd = (long*) ((char*) cinfo + cinfo->hsize); + uint64_t uidt = cinfo->uid; + uint64_t idxt = idxs[cinfo->kind]; + int found = 0; + int first = 1; + while (ptr < bnd - 1) + { + int idx1 = (int) ((idxt >> 44) % UIDTableSize); + if (UIDTable[idx1] == uidt) + { + found = 1; + break; + } + else if (first) + { + first = 0; + UIDTable[idx1] = uidt; + } + long val = *ptr++; + uidt = uidt * ROOT_UID_INV - val; + idxt = idxt * ROOT_IDX_INV - val; + } + if (found) + { + char *d = (char*) ptr; + char *s = (char*) bnd; + if (!first) + { + int i; + for (i = 0; i<sizeof (uidt); i++) + { + *d++ = (char) uidt; + uidt = uidt >> 8; + } + } + int delta = s - d; + while (s < end) + *d++ = *s++; + cinfo->kind |= COMPRESSED_INFO; + cinfo->hsize -= delta; + frp->tsize -= delta; + end -= delta; + } + } + cinfo = (Common_info*) ((char*) cinfo + cinfo->hsize); + } + __collector_write_packet (dhndl, (CM_Packet*) frp); + return (FrameInfo) uid; +} + +FrameInfo +__collector_getUID (CM_Array *arg, FrameInfo suid) +{ + if (arg->length % sizeof (long) != 0 || + (long) arg->bytes % sizeof (long) != 0) + return (FrameInfo) - 1; + if (arg->length == 0) + return suid; + + uint64_t uid = suid ? suid : 1; + uint64_t idx = suid ? suid : 1; + long *ptr = (long*) ((char*) arg->bytes + arg->length); + long *bnd = (long*) (arg->bytes); + while (ptr > bnd) + { + long val = *(--ptr); + uid = (uid + val) * ROOT_UID; + idx = (idx + val) * ROOT_IDX; + } + + /* Check if we have already recorded that uid. + * The following fragment contains benign data races. + * It's important, though, that all reads from UIDTable + * happen before writes. + */ + int found1 = 0; + int idx1 = (int) ((idx >> 44) % UIDTableSize); + if (UIDTable[idx1] == uid) + found1 = 1; + int found2 = 0; + int idx2 = (int) ((idx >> 24) % UIDTableSize); + if (UIDTable[idx2] == uid) + found2 = 1; + int found3 = 0; + int idx3 = (int) ((idx >> 4) % UIDTableSize); + if (UIDTable[idx3] == uid) + found3 = 1; + + if (!found1) + UIDTable[idx1] = uid; + if (!found2) + UIDTable[idx2] = uid; + if (!found3) + UIDTable[idx3] = uid; + if (found1 || found2 || found3) + return (FrameInfo) uid; + + int sz = sizeof (Uid_packet) + arg->length; + if (suid) + sz += sizeof (suid); + Uid_packet *uidp = alloca (sz); + uidp->tsize = sz; + uidp->type = UID_PCKT; + uidp->flags = 0; + uidp->uid = uid; + + /* Compress */ + ptr = (long*) (arg->bytes); + bnd = (long*) ((char*) arg->bytes + arg->length); + long *dst = (long*) (uidp + 1); + uint64_t uidt = uid; + uint64_t idxt = idx; + uint64_t luid = suid; /* link uid */ + + while (ptr < bnd) + { + + long val = *ptr++; + *dst++ = val; + + if ((bnd - ptr) > sizeof (uidt)) + { + uidt = uidt * ROOT_UID_INV - val; + idxt = idxt * ROOT_IDX_INV - val; + int idx1 = (int) ((idxt >> 44) % UIDTableSize); + if (UIDTable[idx1] == uidt) + { + luid = uidt; + break; + } + } + } + if (luid) + { + char *d = (char*) dst; + for (int i = 0; i<sizeof (luid); i++) + { + *d++ = (char) luid; + luid = luid >> 8; + } + uidp->flags |= COMPRESSED_INFO; + uidp->tsize = d - (char*) uidp; + } + __collector_write_packet (dhndl, (CM_Packet*) uidp); + + return (FrameInfo) uid; +} + +int +__collector_getStackTrace (void *buf, int size, void *bptr, void *eptr, void *arg) +{ + if (arg == (void*) __collector_omp_stack_trace) + seen_omp = 1; + int do_walk = 1; + if (arg == NULL || arg == (void*) __collector_omp_stack_trace) + { + do_walk = (arg == (void*) __collector_omp_stack_trace && omp_no_walk) ? 0 : 1; + ucontext_t *context = (ucontext_t*) alloca (sizeof (ucontext_t)); + FILL_CONTEXT (context); + arg = context; + } + int unwind_mode = 0; + if (do_walk == 0) + unwind_mode |= FRINFO_NO_WALK; + return stack_unwind (buf, size, bptr, eptr, arg, unwind_mode); +} + +#if ARCH(SPARC) +/* + * These are important data structures taken from the header files reg.h and + * ucontext.h. They are used for the stack trace algorithm explained below. + * + * typedef struct ucontext { + * u_long uc_flags; + * struct ucontext *uc_link; + * usigset_t uc_sigmask; + * stack_t uc_stack; + * mcontext_t uc_mcontext; + * long uc_filler[23]; + * } ucontext_t; + * + * #define SPARC_MAXREGWINDOW 31 + * + * struct rwindow { + * greg_t rw_local[8]; + * greg_t rw_in[8]; + * }; + * + * #define rw_fp rw_in[6] + * #define rw_rtn rw_in[7] + * + * struct gwindows { + * int wbcnt; + * int *spbuf[SPARC_MAXREGWINDOW]; + * struct rwindow wbuf[SPARC_MAXREGWINDOW]; + * }; + * + * typedef struct gwindows gwindows_t; + * + * typedef struct { + * gregset_t gregs; + * gwindows_t *gwins; + * fpregset_t fpregs; + * long filler[21]; + * } mcontext_t; + * + * The stack would look like this when SIGPROF occurrs. + * + * ------------------------- <- high memory + * | | + * | | + * ------------------------- + * | | + * ------------------------- <- fp' <-| + * | | | + * : : | + * | | | + * ------------------------- | + * | fp |----------| + * | | + * ------------------------- <- sp' + * | | | | + * | gwins | <- saved stack pointers & | | + * | | register windows | |- mcontext + * ------------------------- | | + * | gregs | <- saved registers | | + * ------------------------- | + * | | |- ucontext + * ------------------------- <- ucp (ucontext pointer) | + * | | | + * | | |- siginfo + * ------------------------- <- sip (siginfo pointer) | + * | | + * ------------------------- <- sp + * + * Then the signal handler is called with: + * handler( signo, sip, uip ); + * When gwins is null, all the stack frames are saved in the user stack. + * In that case we can find sp' from gregs and walk the stack for a backtrace. + * However, if gwins is not null we will have a more complicated case. + * Wbcnt(in gwins) tells you how many saved register windows are valid. + * This is important because the kernel does not allocate the entire array. + * And the top most frame is saved in the lowest index element. The next + * paragraph explains the possible causes. + * + * There are two routines in the kernel to flush out user register windows. + * flush_user_windows and flush_user_windows_to_stack + * The first routine will not cause a page fault. Therefore if the user + * stack is not in memory, the register windows will be saved to the pcb. + * This can happen when the kernel is trying to deliver a signal and + * the user stack got swap out. The kernel will then build a new context for + * the signal handler and the saved register windows will + * be copied to the ucontext as show above. On the other hand, + * flush_user_windows_to_stack can cause a page fault, and if it failed + * then there is something wrong (stack overflow, misalign). + * The first saved register window does not necessary correspond to the + * first stack frame. So the current stack pointer must be compare with + * the stack pointers in spbuf to find a match. + * + * We will also follow the uc_link field in ucontext to trace also nested + * signal stack frames. + * + */ + +/* Dealing with trap handlers. + * When a user defined trap handler is invoked the return address + * (or actually the address of an instruction that raised the trap) + * is passed to the trap handler in %l6, whereas saved %o7 contains + * garbage. First, we need to find out if a particular pc belongs + * to the trap handler, and if so, take the %l6 value from the stack rather + * than %o7 from either the stack or the register. + * There are three possible situations represented + * by the following stacks: + * + * MARKER MARKER MARKER + * trap handler pc __func pc before 'save' __func pc after 'save' + * %l6 %o7 from reg %o7 (garbage) + * ... %l6 trap handler pc + * ... %l6 + * ... + * where __func is a function called from the trap handler. + * + * Currently this is implemented to only deal with __misalign_trap_handler + * set for v9 FORTRAN applications. Implementation of IN_TRAP_HANDLER + * macro shows it. A general solution is postponed. + */ + +/* Special handling of unwind through the parallel loop barrier code: + * + * The library defines two symbols, __mt_EndOfTask_Barrier_ and + * __mt_EndOfTask_Barrier_Dummy_ representing the first word of + * the barrier sychronization code, and the first word following + * it. Whenever the leaf PC is between these two symbols, + * the unwind code is special-cased as follows: + * The __mt_EndOfTask_Barrier_ function is guaranteed to be a leaf + * function, so its return address is in a register, not saved on + * the stack. + * + * MARKER + * __mt_EndOfTask_Barrier_ PC -- the leaf PC + * loop body function address for the task -- implied caller of __mt_EndOfTask_Barrier_ + * this address is taken from the %O0 register + * {mt_master or mt_slave} -- real caller of __mt_EndOfTask_Barrier_ + * ... + * + * With this trick, the analyzer will show the time in the barrier + * attributed to the loop at the end of which the barrier synchronization + * is taking place. That loop body routine, will be shown as called + * from the function from which it was extracted, which will be shown + * as called from the real caller, either the slave or master library routine. + */ + +/* + * These no-fault-load (0x82) assembly functions are courtesy of Rob Gardner. + * + * Note that 0x82 is ASI_PNF. See + * http://lxr.free-electrons.com/source/arch/sparc/include/uapi/asm/asi.h#L134 + * ASI address space identifier; PNF primary no fault + */ + +/* load an int from an address */ + +/* if the address is illegal, return a 0 */ +static int +SPARC_no_fault_load_int (void *addr) +{ + int val; + __asm__ __volatile__( + "lda [%1] 0x82, %0\n\t" + : "=r" (val) + : "r" (addr) + ); + + return val; +} + +/* check if an address is invalid + * + * A no-fault load of an illegal address still faults, but it does so silently to the calling process. + * It returns a 0, but so could a load of a legal address. + * So, we time the load. A "fast" load must be a successful load. + * A "slow" load is probably a fault. + * Since it could also be a cache/TLB miss or other abnormality, + * it's safest to retry a slow load. + * The cost of trying a valid address should be some nanosecs. + * The cost of trying an invalid address up to 10 times could be some microsecs. + */ +#if 0 +static +int invalid_SPARC_addr(void *addr) +{ + long t1, t2; + int i; + + for (i=0; i<10; i++) { + __asm__ __volatile__( + "rd %%tick, %0\n\t" + "lduba [%2] 0x82, %%g0\n\t" + "rd %%tick, %1\n\t" + : "=r" (t1), "=r" (t2) + : "r" (addr) ); + if ( (t2 - t1) < 100 ) + return 0; + } + return 1; +} +#endif + +/* + * The standard SPARC procedure-calling convention is that the + * calling PC (for determining the return address when the procedure + * is finished) is placed in register %o7. A called procedure + * typically executes a "save" instruction that shifts the register + * window, and %o7 becomes %i7. + * + * Optimized leaf procedures do not shift the register window. + * They assume the return address will remain %o7. So when + * we process a leaf PC, we walk instructions to see if there + * is a call, restore, or other instruction that would indicate + * we can IGNORE %o7 because this is NOT a leaf procedure. + * + * If a limited instruction walk uncovers no such hint, we save + * not only the PC but the %o7 value as well... just to be safe. + * Later, in DBE post-processing of the call stacks, we decide + * whether any recorded %o7 value should be used as a caller + * frame or should be discarded. + */ + +#define IS_ILLTRAP(x) (((x) & 0xc1c00000) == 0) +#define IS_SAVE(x) (((x) & 0xc1f80000) == 0x81e00000) +#define IS_MOVO7R(x) (((x) & 0xc1f8201f) == 0x8160000f) +#define IS_MOVRO7(x) (((x) & 0xfff82000) == 0x9f600000) +#define IS_ORRG0O7(x) (((x) & 0xff78201f) == 0x9e100000) +#define IS_ORG0RO7(x) (((x) & 0xff7fe000) == 0x9e100000) +#define IS_ORG0O7R(x) (((x) & 0xc17fe01f) == 0x8010000f) +#define IS_ORO7G0R(x) (((x) & 0xc17fe01f) == 0x8013c000) +#define IS_RESTORE(x) (((x) & 0xc1f80000) == 0x81e80000) +#define IS_RET(x) ((x) == 0x81c7e008) +#define IS_RETL(x) ((x) == 0x81c3e008) +#define IS_RETURN(x) (((x) & 0xc1f80000) == 0x81c80000) +#define IS_BRANCH(x) ((((x) & 0xc0000000) == 0) && (((x) & 0x01c00000) != 0x01000000)) +#define IS_CALL(x) (((x) & 0xc0000000) == 0x40000000) +#define IS_LDO7(x) (((x) & 0xfff80000) == 0xde000000) + +static long pagesize = 0; + +static int +process_leaf (long *lbuf, int ind, int lsize, void *context) +{ + greg_t pc = GET_PC (context); + greg_t o7 = GET_GREG (context, REG_O7); + + /* omazur: TBR START -- not used */ + if (IN_BARRIER (pc)) + { + if (ind < lsize) + lbuf[ind++] = pc; + if (ind < lsize) + lbuf[ind++] = GET_GREG (context, REG_O0); + return ind; + } + /* omazur: TBR END */ +#if WSIZE(64) + if (IN_TRAP_HANDLER (pc)) + { + if (ind < lsize) + lbuf[ind++] = pc; + return ind; + } +#endif + unsigned *instrp = (unsigned *) pc; + unsigned *end_addr = instrp + 20; + while (instrp < end_addr) + { + unsigned instr = *instrp++; + if (IS_ILLTRAP (instr)) + break; + else if (IS_SAVE (instr)) + { + if (ind < lsize) + lbuf[ind++] = pc; + if (o7 && ind < lsize) + lbuf[ind++] = o7; + return ind; + } + else if (IS_MOVO7R (instr) || IS_ORG0O7R (instr) || IS_ORO7G0R (instr)) + break; + else if (IS_MOVRO7 (instr) || IS_ORG0RO7 (instr)) + { + int rs2 = (instr & 0x1f) + REG_G1 - 1; + o7 = (rs2 <= REG_O7) ? GET_GREG (context, rs2) : 0; + break; + } + else if (IS_ORRG0O7 (instr)) + { + int rs2 = ((instr & 0x7c000) >> 14) + REG_G1 - 1; + o7 = (rs2 <= REG_O7) ? GET_GREG (context, rs2) : 0; + break; + } + else if (IS_RESTORE (instr)) + { + o7 = 0; + break; + } + else if (IS_RETURN (instr)) + { + o7 = 0; + break; + } + else if (IS_RET (instr)) + { + o7 = 0; + break; + } + else if (IS_RETL (instr)) + { + /* process delay slot */ + instr = *instrp++; + if (IS_RESTORE (instr)) + o7 = 0; + break; + } + else if (IS_BRANCH (instr)) + { + unsigned *backbegin = ((unsigned *) pc - 1); + unsigned *backend = backbegin - 12 + (instrp - (unsigned *) pc); + while (backbegin > backend) + { + // 21920143 stack unwind: SPARC process_leaf backtracks too far + /* + * We've already dereferenced backbegin+1. + * So if backbegin is on the same page, we're fine. + * If we've gone to a different page, possibly things are not fine. + * We don't really know how to test that. + * Let's just assume the worst: that dereferencing backbegin would segv. + * We won't know if we're in a leaf function or not. + */ + if (pagesize == 0) + pagesize = CALL_UTIL (sysconf)(_SC_PAGESIZE); + if ((((long) (backbegin + 1)) & (pagesize - 1)) < sizeof (unsigned*)) + break; + unsigned backinstr = *backbegin--; + if (IS_LDO7 (backinstr)) + { + o7 = 0; + break; + } + else if (IS_ILLTRAP (backinstr)) + break; + else if (IS_RETURN (backinstr)) + break; + else if (IS_RET (backinstr)) + break; + else if (IS_RETL (backinstr)) + break; + else if (IS_CALL (backinstr)) + break; + else if (IS_SAVE (backinstr)) + { + o7 = 0; + break; + } + } + break; + } + else if (IS_CALL (instr)) + o7 = 0; + } + +#if WSIZE(64) + if (o7 != 0 && ((long) o7) < 32 && ((long) o7) > -32) + { + /* 20924821 SEGV in unwind code on SPARC/Linux + * We've seen this condition in some SPARC-Linux runs. + * o7 is non-zero but not a valid address. + * Values like 4 or -7 have been seen. + * Let's check if o7 is unreasonably small. + * If so, set to 0 so that it won't be recorded. + * Otherwise, there is risk of it being dereferenced in process_sigreturn(). + */ + // __collector_log_write("<event kind=\"%s\" id=\"%d\">time %lld, internal debug unwind at leaf; o7 = %ld, pc = %x</event>\n", + // SP_JCMD_COMMENT, COL_COMMENT_NONE, __collector_gethrtime() - __collector_start_time, (long) o7, pc ); + o7 = 0; + } +#endif + + if (o7) + { + if (ind < lsize) + lbuf[ind++] = SP_LEAF_CHECK_MARKER; + if (ind < lsize) + lbuf[ind++] = pc; + if (ind < lsize) + lbuf[ind++] = o7; + } + else if (ind < lsize) + lbuf[ind++] = pc; + return ind; +} + +#if WSIZE(64) +// detect signal handler +static int +process_sigreturn (long *lbuf, int ind, int lsize, unsigned char * tpc, + struct frame **pfp, void * bptr, int extra_frame) +{ + // cheap checks whether tpc is obviously not an instruction address + if ((4096 > (unsigned long) tpc) // the first page is off limits + || (3 & (unsigned long) tpc)) + return ind; // the address is not aligned + + // get the instruction at tpc, skipping over as many as 7 nop's (0x01000000) + int insn, i; + for (i = 0; i < 7; i++) + { + insn = SPARC_no_fault_load_int ((void *) tpc); + if (insn != 0x01000000) + break; + tpc += 4; + } + + // we're not expecting 0 (and it could mean an illegal address) + if (insn == 0) + return ind; + + // We are looking for __rt_sigreturn_stub with the instruction + // 0x82102065 : mov 0x65 /* __NR_rt_sigreturn */, %g1 + if (insn == 0x82102065) + { + /* + * according to linux kernel source code, + * syscall(_NR_rt_sigreturn) uses the following data in stack: + * struct rt_signal_frame { + * struct sparc_stackf ss; + * siginfo_t info; + * struct pt_regs regs; + * ....}; + * sizeof(struct sparc_stackf) is 192; + * sizeof(siginfo_t) is 128; + * we need to get the register values from regs, which is defined as: + * struct pt_regs { + * unsigned long u_regs[16]; + * unsigned long tstate; + * unsigned long tpc; + * unsigned long tnpc; + * ....}; + * pc and fp register has offset of 120 and 112; + * the pc of kill() is stored in tnpc, whose offest is 136. + */ + greg_t pc = *((unsigned long*) ((char*) ((*pfp)) + 192 + 128 + 136)); + greg_t pc1 = *((unsigned long*) ((char*) ((*pfp)) + 192 + 128 + 120)); + (*pfp) = *((struct frame**) ((char*) ((*pfp)) + 192 + 128 + 112)); + if (pc && pc1) + { + if (bptr != NULL && extra_frame && ((char*) (*pfp) + STACK_BIAS) < (char*) bptr && ind < 2) + { + lbuf[0] = pc1; + if (ind == 0) + ind++; + } + if (bptr == NULL || ((char*) (*pfp) + STACK_BIAS) >= (char*) bptr) + { + if (ind < lsize) + lbuf[ind++] = (unsigned long) tpc; + if (ind < lsize) + lbuf[ind++] = pc; + if (ind < lsize) + lbuf[ind++] = pc1; + } + } + DprintfT (SP_DUMP_UNWIND, "unwind.c: resolved sigreturn pc=0x%lx, pc1=0x%lx, fp=0x%lx\n", pc, pc1, *(pfp)); + } + return ind; +} +#endif + +/* + * int stack_unwind( char *buf, int size, ucontext_t *context ) + * This routine looks into the mcontext and + * trace stack frames to record return addresses. + */ +int +stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode) +{ + /* + * trace the stack frames from user stack. + * We are assuming that the frame pointer and return address + * are null when we are at the top level. + */ + long *lbuf = (long*) buf; + int lsize = size / sizeof (long); + struct frame *fp = (struct frame *) GET_SP (context); /* frame pointer */ + greg_t pc; /* program counter */ + int extra_frame = 0; + if ((mode & 0xffff) == FRINFO_FROM_STACK) + extra_frame = 1; + + int ind = 0; + if (bptr == NULL) + ind = process_leaf (lbuf, ind, lsize, context); + + int extra_frame = 0; + if ((mode & 0xffff) == FRINFO_FROM_STACK) + extra_frame = 1; + int ind = 0; + if (bptr == NULL) + ind = process_leaf (lbuf, ind, lsize, context); + + while (fp) + { + if (ind >= lsize) + break; + fp = (struct frame *) ((char *) fp + STACK_BIAS); + if (eptr && fp >= (struct frame *) eptr) + { + ind = ind >= 2 ? ind - 2 : 0; + break; + } +#if WSIZE(64) // detect signal handler + unsigned char * tpc = ((unsigned char*) (fp->fr_savpc)); + struct frame * tfp = (struct frame*) ((char*) (fp->fr_savfp) + STACK_BIAS); + int old_ind = ind; + ind = process_sigreturn (lbuf, old_ind, lsize, tpc, &tfp, bptr, extra_frame); + if (ind != old_ind) + { + pc = (greg_t) tpc; + fp = tfp; + } + else +#endif + { +#if WSIZE(64) + if (IN_TRAP_HANDLER (lbuf[ind - 1])) + pc = fp->fr_local[6]; + else + pc = fp->fr_savpc; +#else + pc = fp->fr_savpc; +#endif + fp = fp->fr_savfp; + if (pc) + { + if (bptr != NULL && extra_frame && ((char*) fp + STACK_BIAS) < (char*) bptr && ind < 2) + { + lbuf[0] = pc; + if (ind == 0) + ind++; + } + if (bptr == NULL || ((char*) fp + STACK_BIAS) >= (char*) bptr) + lbuf[ind++] = pc; + } + } + + /* 4616238: _door_return may have a frame that has non-zero + * saved stack pointer and zero pc + */ + if (pc == (greg_t) NULL) + break; + } + + if (ind >= lsize) + { /* truncated stack handling */ + ind = lsize - 1; + lbuf[ind++] = SP_TRUNC_STACK_MARKER; + } + return ind * sizeof (long); +} + +#elif ARCH(Intel) + +/* get __NR_<syscall_name> constants */ +#include <syscall.h> + +/* + * From uts/intel/ia32/os/sendsig.c: + * + * An amd64 signal frame looks like this on the stack: + * + * old %rsp: + * <128 bytes of untouched stack space> + * <a siginfo_t [optional]> + * <a ucontext_t> + * <siginfo_t *> + * <signal number> + * new %rsp: <return address (deliberately invalid)> + * + * The signal number and siginfo_t pointer are only pushed onto the stack in + * order to allow stack backtraces. The actual signal handling code expects the + * arguments in registers. + * + * An i386 SVR4/ABI signal frame looks like this on the stack: + * + * old %esp: + * <a siginfo32_t [optional]> + * <a ucontext32_t> + * <pointer to that ucontext32_t> + * <pointer to that siginfo32_t> + * <signo> + * new %esp: <return address (deliberately invalid)> + */ + +#if WSIZE(32) +#define OPC_REG(x) ((x)&0x7) +#define MRM_REGD(x) (((x)>>3)&0x7) +#define MRM_REGS(x) ((x)&0x7) +#define RED_ZONE 0 +#elif WSIZE(64) +#define OPC_REG(x) (B|((x)&0x7)) +#define MRM_REGD(x) (R|(((x)>>3)&0x7)) +#define MRM_REGS(x) (B|((x)&0x7)) +#define RED_ZONE 16 +#endif +#define MRM_EXT(x) (((x)>>3)&0x7) +#define MRM_MOD(x) ((x)&0xc0) + +#define RAX 0 +#define RDX 2 +#define RSP 4 +#define RBP 5 + +struct AdvWalkContext +{ + unsigned char *pc; + unsigned long *sp; + unsigned long *sp_safe; + unsigned long *fp; + unsigned long *fp_sav; + unsigned long *fp_loc; + unsigned long rax; + unsigned long rdx; + unsigned long ra_sav; + unsigned long *ra_loc; + unsigned long regs[16]; + int tidx; /* targets table index */ + uint32_t cval; /* cache value */ +}; + +static unsigned long +getRegVal (struct AdvWalkContext *cur, int r, int *undefRez) +{ + if (cur->regs[r] == 0) + { + if (r == RBP) + { + tprintf (DBG_LT3, "getRegVal: returns cur->regs[RBP]=0x%lx cur->pc=0x%lx\n", + (unsigned long) cur->fp, (unsigned long) cur->pc); + return (unsigned long) cur->fp; + } + *undefRez = 1; + } + tprintf (DBG_LT3, "getRegVal: cur->regs[%d]=0x%lx cur->pc=0x%lx\n", + r, (unsigned long) cur->regs[r], (unsigned long) cur->pc); + return cur->regs[r]; +} + +static unsigned char * +check_modrm (unsigned char *pc) +{ + unsigned char modrm = *pc++; + unsigned char mod = MRM_MOD (modrm); + if (mod == 0xc0) + return pc; + unsigned char regs = modrm & 0x07; + if (regs == RSP) + { + if (mod == 0x40) + return pc + 2; // SIB + disp8 + if (mod == 0x80) + return pc + 5; // SIB + disp32 + return pc + 1; // SIB + } + if (mod == 0x0) + { + if (regs == RBP) + pc += 4; // disp32 + } + else if (mod == 0x40) + pc += 1; /* byte */ + else if (mod == 0x80) + pc += 4; /* word */ + return pc; +} + +static int +read_int (unsigned char *pc, int w) +{ + if (w == 1) + return *((char *) pc); + if (w == 2) + return *(short*) pc; + return *(int*) pc; +} + +/* Return codes */ +enum +{ + RA_FAILURE = 0, + RA_SUCCESS, + RA_END_OF_STACK, + RA_SIGRETURN, + RA_RT_SIGRETURN +}; + +/* Cache value encodings */ +static const uint32_t RA_FROMFP = (uint32_t) - 1; /* get the RA from the frame pointer */ +static const uint32_t RA_EOSTCK = (uint32_t) - 2; /* end-of-stack */ + + +#define MAXCTX 16 +#define MAXTRGTS 64 +#define MAXJMPREG 2 +#define MAXJMPREGCTX 3 + +#define DELETE_CURCTX() __collector_memcpy (cur, buf + (--nctx), sizeof (*cur)) + +/** + * Look for pc in AddrTable_RA_FROMFP and in AddrTable_RA_EOSTCK + * @param wctx + * @return + */ +static int +cache_get (struct WalkContext *wctx) +{ + unsigned long addr; + if (AddrTable_RA_FROMFP != NULL) + { + uint64_t idx = wctx->pc % ValTableSize; + addr = AddrTable_RA_FROMFP[ idx ]; + if (addr == wctx->pc) + { // Found in AddrTable_RA_FROMFP + unsigned long *sp = NULL; + unsigned long fp = wctx->fp; + /* validate fp before use */ + if (fp < wctx->sp || fp >= wctx->sbase - sizeof (*sp)) + return RA_FAILURE; + sp = (unsigned long *) fp; + fp = *sp++; + unsigned long ra = *sp++; + unsigned long tbgn = wctx->tbgn; + unsigned long tend = wctx->tend; + if (ra < tbgn || ra >= tend) + if (!__collector_check_segment (ra, &tbgn, &tend, 0)) + return RA_FAILURE; + unsigned long npc = adjust_ret_addr (ra, ra - tbgn, tend); + if (npc == 0) + return RA_FAILURE; + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d cached pc=0x%lX\n", __LINE__, npc); + wctx->pc = npc; + wctx->sp = (unsigned long) sp; + wctx->fp = fp; + wctx->tbgn = tbgn; + wctx->tend = tend; + return RA_SUCCESS; + } + } + if (NULL == AddrTable_RA_EOSTCK) + return RA_FAILURE; + uint64_t idx = wctx->pc % ValTableSize; + addr = AddrTable_RA_EOSTCK[ idx ]; + if (addr != wctx->pc) + return RA_FAILURE; + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d cached RA_END_OF_STACK\n", __LINE__); + return RA_END_OF_STACK; +} +/** + * Save pc in RA_FROMFP or RA_EOSTCK cache depending on val + * @param wctx + */ +static void +cache_put (struct WalkContext *wctx, const uint32_t val) +{ + if (RA_FROMFP == val) + { + // save pc in RA_FROMFP cache + if (NULL != AddrTable_RA_FROMFP) + { + uint64_t idx = wctx->pc % ValTableSize; + AddrTable_RA_FROMFP[ idx ] = wctx->pc; + if (NULL != AddrTable_RA_EOSTCK) + if (AddrTable_RA_EOSTCK[ idx ] == wctx->pc) + // invalidate pc in RA_EOSTCK cache + AddrTable_RA_EOSTCK[ idx ] = 0; + } + return; + } + if (RA_EOSTCK == val) + { + // save pc in RA_EOSTCK cache + if (NULL != AddrTable_RA_EOSTCK) + { + uint64_t idx = wctx->pc % ValTableSize; + AddrTable_RA_EOSTCK[ idx ] = wctx->pc; + if (NULL != AddrTable_RA_FROMFP) + { + if (AddrTable_RA_FROMFP[ idx ] == wctx->pc) + // invalidate pc in RA_FROMFP cache + AddrTable_RA_FROMFP[ idx ] = 0; + } + } + return; + } +} + +static int +process_return_real (struct WalkContext *wctx, struct AdvWalkContext *cur, int cache_on) +{ + if ((unsigned long) cur->sp >= wctx->sbase || + (unsigned long) cur->sp < wctx->sp) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: not in stack: %p [0x%lX-0x%lX]\n", + cur->sp, wctx->sp, wctx->sbase); + return RA_FAILURE; + } + + unsigned long ra; + if (cur->sp == cur->ra_loc) + { + ra = cur->ra_sav; + cur->sp++; + } + else if (cur->sp >= cur->sp_safe && (unsigned long) cur->sp < wctx->sbase) + ra = *cur->sp++; + else + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: not safe: %p >= %p\n", cur->sp, cur->sp_safe); + return RA_FAILURE; + } + if (ra == 0) + { + if (cache_on) + cache_put (wctx, RA_EOSTCK); + wctx->pc = ra; + wctx->sp = (unsigned long) cur->sp; + wctx->fp = (unsigned long) cur->fp; + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d RA_END_OF_STACK\n", __LINE__); + return RA_END_OF_STACK; + } + + unsigned long tbgn = wctx->tbgn; + unsigned long tend = wctx->tend; + if (ra < tbgn || ra >= tend) + { + if (!__collector_check_segment (ra, &tbgn, &tend, 0)) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: not in segment: 0x%lX [0x%lX-0x%lX]\n", + ra, wctx->tbgn, wctx->tend); + return RA_FAILURE; + } + } + + if (cur->cval == RA_FROMFP) + { + if (wctx->fp == (unsigned long) (cur->sp - 2)) + { + if (cache_on) + cache_put (wctx, RA_FROMFP); + } + else + cur->cval = 0; + } + + unsigned long npc = adjust_ret_addr (ra, ra - tbgn, tend); + if (npc == 0) + { + if (cur->cval == RA_FROMFP) + { + /* We have another evidence that we can trust this RA */ + DprintfT (SP_DUMP_UNWIND, "unwind.c: trusted fp, pc = 0x%lX\n", wctx->pc); + wctx->pc = ra; + } + else + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: 0 after adjustment\n"); + return RA_FAILURE; + } + } + else + wctx->pc = npc; + wctx->sp = (unsigned long) cur->sp; + wctx->fp = (unsigned long) cur->fp; + wctx->tbgn = tbgn; + wctx->tend = tend; + return RA_SUCCESS; +} + +static int +process_return (struct WalkContext *wctx, struct AdvWalkContext *cur) +{ + return process_return_real (wctx, cur, 1); +} + +static void +omp_cache_put (unsigned long *cur_sp_safe, struct WalkContext * wctx_pc_save, + struct WalkContext *wctx, uint32_t val) +{ + if (omp_no_walk && (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL)) + { + size_t sz = OmpValTableSize * sizeof (*OmpCurCtxs); + OmpCurCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1); + sz = OmpValTableSize * sizeof (*OmpCtxs); + OmpCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1); + sz = OmpValTableSize * sizeof (*OmpVals); + OmpVals = (uint32_t*) __collector_allocCSize (__collector_heap, sz, 1); + sz = OmpValTableSize * sizeof (*OmpRAs); + OmpRAs = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1); + } + if (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL) + return; + +#define USE_18434988_OMP_CACHE_WORKAROUND +#ifndef USE_18434988_OMP_CACHE_WORKAROUND + uint64_t idx = wctx_pc_save->pc * ROOT_IDX; + OmpVals[ idx % OmpValTableSize ] = val; + idx = (idx + val) * ROOT_IDX; + __collector_memcpy (&(OmpCurCtxs[ idx % OmpValTableSize ]), wctx_pc_save, sizeof (struct WalkContext)); + idx = (idx + val) * ROOT_IDX; + __collector_memcpy (&(OmpCtxs[ idx % OmpValTableSize ]), wctx, sizeof (struct WalkContext)); +#endif + unsigned long *sp = NULL; + unsigned long fp = wctx_pc_save->fp; + int from_fp = 0; + if (val == RA_END_OF_STACK) + { + sp = (unsigned long *) (wctx->sp); + sp--; + TprintfT (DBG_LT1, "omp_cache_put: get sp from EOS, sp=%p\n", sp); + } + else + { + if (fp < wctx_pc_save->sp || fp >= wctx_pc_save->sbase - sizeof (*sp)) + { + sp = (unsigned long *) (wctx->sp); + sp--; + TprintfT (DBG_LT1, "omp_cache_put: get sp from sp, sp=%p\n", sp); + } + else + { + TprintfT (DBG_LT1, "omp_cache_put: get sp from fp=0x%lx\n", fp); + sp = (unsigned long *) fp; + from_fp = 1; + } + } + + if (sp < cur_sp_safe || ((unsigned long) sp >= wctx->sbase)) + return; + + unsigned long ra = *sp++; + if (from_fp) + { + unsigned long tbgn = wctx_pc_save->tbgn; + unsigned long tend = wctx_pc_save->tend; + if (ra < tbgn || ra >= tend) + { + sp = (unsigned long *) (wctx->sp); + sp--; + ra = *sp++; + } + } +#ifdef USE_18434988_OMP_CACHE_WORKAROUND + uint64_t idx1 = wctx_pc_save->pc * ROOT_IDX; + uint64_t idx2 = (idx1 + val) * ROOT_IDX; + uint64_t idx3 = (idx2 + val) * ROOT_IDX; + uint64_t idx4 = (idx3 + val) * ROOT_IDX; + OmpRAs [ idx4 % OmpValTableSize ] = 0; // lock + OmpVals[ idx1 % OmpValTableSize ] = val; + __collector_memcpy (&(OmpCurCtxs[ idx2 % OmpValTableSize ]), wctx_pc_save, sizeof (struct WalkContext)); + __collector_memcpy (&(OmpCtxs [ idx3 % OmpValTableSize ]), wctx, sizeof (struct WalkContext)); + OmpRAs [ idx4 % OmpValTableSize ] = ra; +#else + idx = (idx + val) * ROOT_IDX; + OmpRAs[ idx % OmpValTableSize ] = ra; +#endif + TprintfT (DBG_LT1, "omp_cache_put: pc=0x%lx\n", wctx_pc_save->pc); +} + +/* + * See bug 17166877 - malloc_internal unwind failure. + * Sometimes there are several calls right after ret, like: + * leave + * ret + * call xxx + * call xxxx + * call xxxxx + * If they are also jump targets, we should better not + * create new jump context for those, since they may + * end up into some other function. + */ +static int +is_after_ret (unsigned char * npc) +{ + if (*npc != 0xe8) + return 0; + unsigned char * onpc = npc; + int ncall = 1; + int maxsteps = 10; + int mincalls = 3; + int steps = 0; + while (*(npc - 5) == 0xe8 && steps < maxsteps) + { + npc -= 5; + ncall++; + steps++; + } + if (*(npc - 1) != 0xc3 || *(npc - 2) != 0xc9) + return 0; + steps = 0; + while (*(onpc + 5) == 0xe8 && steps < maxsteps) + { + onpc += 5; + ncall++; + steps++; + } + if (ncall < mincalls) + return 0; + return 1; +} + +static int +find_i386_ret_addr (struct WalkContext *wctx, int do_walk) +{ + if (wctx->sp == 0) + // Some artificial contexts may have %sp set to 0. See SETFUNCTIONCONTEXT() + return RA_FAILURE; + + /* Check cached values */ + int retc = cache_get (wctx); + if (retc != RA_FAILURE) + return retc; + + /* An attempt to perform code analysis for call stack tracing */ + unsigned char opcode; + unsigned char extop; + unsigned char extop2; + unsigned char modrm; + int imm8; /* immediate operand, byte */ + int immv; /* immediate operand, word(2) or doubleword(4) */ + int reg; /* register code */ + + /* Buffer for branch targets (analysis stoppers) */ + unsigned char *targets[MAXTRGTS]; + int ntrg = 0; /* number of entries in the table */ + targets[ntrg++] = (unsigned char*) wctx->pc; + targets[ntrg++] = (unsigned char*) - 1; + + struct AdvWalkContext buf[MAXCTX]; + struct AdvWalkContext *cur = buf; + CALL_UTIL (memset)((void*) cur, 0, sizeof (*cur)); + + cur->pc = (unsigned char*) wctx->pc; + cur->sp = (unsigned long*) wctx->sp; + cur->sp_safe = cur->sp - RED_ZONE; /* allow for the 128-byte red zone on amd64 */ + cur->fp = (unsigned long*) wctx->fp; + cur->tidx = 1; + DprintfT (SP_DUMP_UNWIND, "\nstack_unwind (x86 walk):%d %p start\n", __LINE__, cur->pc); + + int nctx = 1; /* number of contexts being processed */ + int cnt = 8192; /* number of instructions to analyse */ + + /* + * The basic idea of our x86 stack unwind is that we don't know + * if we can trust the frame-pointer register. So we walk + * instructions to find a return instruction, at which point + * we know the return address is on the top of the stack, etc. + * + * A severe challenge to walking x86 instructions is when we + * encounter "jmp *(reg)" instructions, where we are expected + * to jump to the (unknown-to-us) contents of a register. + * + * The "jmp_reg" code here attempts to keep track of the + * context for such a jump, deferring any handling of such + * a difficult case. We continue with other contexts, hoping + * that some other walk will take us to a return instruction. + * + * If no other walk helps, we return to "jmp_reg" contexts. + * While we don't know the jump target, it is possible that the + * bytes immediately following the jmp_reg instruction represent + * one possible target, as might be the case when a "switch" + * statement is compiled. + * + * Unfortunately, the bytes following a "jmp_reg" instruction might + * instead be a jump target from somewhere else -- execution might + * never "fall through" from the preceding "jmp_reg". Those bytes + * might not even be instructions at all. There are many uses of + * jmp_reg instructions beyond just compiling switch statements. + * + * So walking the bytes after a "jmp_reg" instruction can lead + * to bugs and undefined behavior, including SEGV and core dump. + * + * We currently do not really understand the "jmp_reg" code below. + */ + int jmp_reg_switch_mode = 0; + int num_jmp_reg = 0; // number of jmp *reg met when switch mode is off or when in current switch case + int total_num_jmp_reg = 0; // number of total jmp *reg met + struct AdvWalkContext * jmp_reg_ctx[MAXJMPREG]; // context of jmp *reg met when switch mode is off or when in current switch case + struct AdvWalkContext * jmp_reg_switch_ctx[MAXJMPREG]; // context of jmp *reg used in switch cases + struct AdvWalkContext * jmp_reg_switch_backup_ctx = NULL; // context of the first jmp *reg used in switch cases + + int cur_jmp_reg_switch = 0; // current switch table + int num_jmp_reg_switch = 0; // number of switch table + int jmp_reg_switch_case = 0; // case number in current switch table + unsigned char * jmp_reg_switch_pc = NULL; // the start pc of current switch case + unsigned char * jmp_reg_switch_pc_old = NULL; // backup for deleteing context of jump target + unsigned char * jmp_reg_switch_base = NULL; // start pc for checking offsets + int max_jmp_reg_switch_case = 2; +#if WSIZE(32) + int max_switch_pc_offset = 512; +#else // WSIZE(64) + int max_switch_pc_offset = 1024; +#endif + int expected_num_jmp_reg = 1; // should be smaller than MAXJMPREG + int max_num_jmp_reg_seen = 4; // try to resolve return if there are so many such instructions + + + int save_ctx = 0; // flag to save walk context in the cache to speed up unwind + struct WalkContext wctx_pc_save; + if (do_walk == 0) + // do_walk is the flag indicating not walking through the instructions, resolving the RA from the stack fp first + __collector_memcpy (&wctx_pc_save, wctx, sizeof (struct WalkContext)); + +startWalk: + if (do_walk == 0) + { // try to resolve RA from stack frame pointer + if (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL) + { + do_walk = 1; + goto startWalk; + } + // before goto checkFP, try the RA from cache (key: WalkContext -> value: caller's WalkContext)) + uint64_t idx = wctx->pc * ROOT_IDX; + uint32_t val = OmpVals[idx % OmpValTableSize]; + idx = (idx + val) * ROOT_IDX; +#ifdef USE_18434988_OMP_CACHE_WORKAROUND + // Check ra: if it is 0 - then cache is invalid + uint64_t idx4; + idx4 = (idx + val) * ROOT_IDX; + idx4 = (idx4 + val) * ROOT_IDX; + if (0 == OmpRAs[ idx4 % OmpValTableSize ]) // Invalid cache + goto checkFP; +#endif + struct WalkContext saved_ctx; + __collector_memcpy (&saved_ctx, &OmpCurCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext)); + if (wctx->pc == saved_ctx.pc + && wctx->sp == saved_ctx.sp + && wctx->fp == saved_ctx.fp + && wctx->tbgn == saved_ctx.tbgn + && wctx->tend == saved_ctx.tend) + { // key match, RA may be valid + idx = (idx + val) * ROOT_IDX; + unsigned long *sp = NULL; + unsigned long fp = wctx->fp; + int from_fp = 0; + if (val == RA_END_OF_STACK) + { + DprintfT (SP_DUMP_UNWIND, "find_i386_ret_addr:%d -- RA_END_OF_STACK: pc=0x%lx\n", __LINE__, wctx->pc); + __collector_memcpy (wctx, &OmpCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext)); + return val; + } + else + { + if (fp < wctx->sp || fp >= wctx->sbase - sizeof (*sp)) + { + TprintfT (DBG_LT1, "omp_cache_get -- wrong fp: pc=0x%lx\n", wctx->pc); + sp = (unsigned long *) (OmpCtxs[ idx % OmpValTableSize ].sp); + sp--; + if (sp < cur->sp_safe || (unsigned long) sp >= wctx->sbase) + { + goto checkFP; + } + unsigned long ra = *sp; + uint64_t idx2 = (idx + val) * ROOT_IDX; + if (OmpRAs[ idx2 % OmpValTableSize ] == ra) + { + __collector_memcpy (wctx, &OmpCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext)); + TprintfT (DBG_LT1, "omp_cache_get -- ra match with target sp: pc=0x%lx, ra=0x%lx, val=%d\n", wctx->pc, ra, val); + return val; + } + TprintfT (DBG_LT1, "omp_cache_get -- ra mismatch: ra=0x%lx, expected ra=0x%lx, val=%d\n", ra, OmpRAs[ idx2 % OmpValTableSize ], val); + goto checkFP; + } + sp = (unsigned long *) fp; + from_fp = 1; + } + + uint64_t idx2 = (idx + val) * ROOT_IDX; + unsigned long ra = *sp++; + if (from_fp) + { + unsigned long tbgn = wctx->tbgn; + unsigned long tend = wctx->tend; + if (ra < tbgn || ra >= tend) + { + sp = (unsigned long *) (OmpCtxs[ idx % OmpValTableSize ].sp); + sp--; + //if (sp < cur->sp_safe - 16 || (unsigned long)sp >= wctx->sbase - sizeof(*sp)) { + // The check above was replaced with the check below, + // because we do not know why "- 16" and "- sizeof(*sp)" was used. + if (sp < cur->sp_safe || (unsigned long) sp >= wctx->sbase) + goto checkFP; + else + ra = *sp; + } + } + if (OmpRAs[ idx2 % OmpValTableSize ] == ra) + { + TprintfT (DBG_LT1, "omp_cache_get -- ra match: pc=0x%lx\n", wctx->pc); + __collector_memcpy (wctx, &OmpCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext)); + return val; + } + } + goto checkFP; + } + else + { + CALL_UTIL (memset)(jmp_reg_ctx, 0, MAXJMPREG * sizeof (struct AdvWalkContext *)); + CALL_UTIL (memset)(jmp_reg_switch_ctx, 0, MAXJMPREG * sizeof (struct AdvWalkContext *)); + } + while (cnt--) + { + if (nctx == 0 && (num_jmp_reg == expected_num_jmp_reg || jmp_reg_switch_mode == 1)) + { // no context available, try jmp switch mode + int i = 0; + if (num_jmp_reg == expected_num_jmp_reg) + jmp_reg_switch_mode = 0; // first jmp reg expected, restart switch mode + DprintfT (SP_DUMP_UNWIND, "unwind.c: begin switch mode, num_jmp_reg = %d, jmp_reg_switch_backup_ctx=%p, jmp_reg_switch_case=%d, jmp_reg_switch_mode=%d.\n", + num_jmp_reg, jmp_reg_switch_backup_ctx, jmp_reg_switch_case, jmp_reg_switch_mode); + // the ideal asm of switch is + // jmp reg + // ...//case 1 + // ret + // ...//case 2 + // ret + // ...//etc + if (jmp_reg_switch_mode == 0) + { + num_jmp_reg_switch = num_jmp_reg; // backup num_jmp_reg + jmp_reg_switch_mode = 1; // begin switch mode + for (i = 0; i < num_jmp_reg_switch; i++) + { + if (jmp_reg_switch_ctx[i] == NULL) + jmp_reg_switch_ctx[i] = (struct AdvWalkContext*) alloca (sizeof (*jmp_reg_switch_ctx[i])); + if (jmp_reg_switch_ctx[i] != NULL) + { // backup jmp_reg_ctx + __collector_memcpy (jmp_reg_switch_ctx[i], jmp_reg_ctx[i], sizeof (*jmp_reg_switch_ctx[i])); + cur_jmp_reg_switch = 0; // reset the current switch table + jmp_reg_switch_case = 0; // reset the case number in current switch table + } + } + if (jmp_reg_switch_backup_ctx == NULL) + { // only backup when the first jmp *reg is met for restoring later, if switch mode fails to resolve RA + jmp_reg_switch_backup_ctx = (struct AdvWalkContext*) alloca (sizeof (*jmp_reg_switch_backup_ctx)); + if (jmp_reg_switch_backup_ctx != NULL) + __collector_memcpy (jmp_reg_switch_backup_ctx, cur, sizeof (*cur)); + DprintfT (SP_DUMP_UNWIND, "unwind.c: back up context for switch mode.\n"); + } + } + if (jmp_reg_switch_mode == 1) + { // in the process of trying switch cases + if (cur_jmp_reg_switch == num_jmp_reg_switch) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: have tried all switch with max_jmp_reg_switch_case for each\n"); + if (jmp_reg_switch_backup_ctx != NULL) + __collector_memcpy (cur, jmp_reg_switch_backup_ctx, sizeof (*cur)); + int rc = process_return_real (wctx, cur, 0); + if (rc == RA_SUCCESS) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + break; // have tried all switch with max_jmp_reg_switch_case for each, goto checkFP + } + unsigned char *npc = jmp_reg_switch_ctx[cur_jmp_reg_switch]->pc; + if (jmp_reg_switch_case == 0) + // first switch case + npc = check_modrm (npc); // pc next to "jmp reg" instruction + else if (jmp_reg_switch_pc != NULL) + npc = jmp_reg_switch_pc; // // pc next to "ret" instruction of previous case + else + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: unexpected jum switch mode situation, jmp_reg_switch_case=%d, jmp_reg_switch_pc=%p\n", + jmp_reg_switch_case, jmp_reg_switch_pc); + break; //goto checkFP + } + jmp_reg_switch_base = npc; + struct AdvWalkContext *new = buf + nctx; + nctx += 1; + __collector_memcpy (new, jmp_reg_switch_ctx[cur_jmp_reg_switch], sizeof (*new)); + new->pc = npc; + cur = new; /* advance the new context first */ + jmp_reg_switch_pc = NULL; + jmp_reg_switch_case++; + if (jmp_reg_switch_case == max_jmp_reg_switch_case) + { // done many cases, change to another switch table + cur_jmp_reg_switch++; + jmp_reg_switch_case = 0; + } + } + num_jmp_reg = 0; + } + if (jmp_reg_switch_mode == 1) + { // when processing switch cases, check pc each time + unsigned long tbgn = wctx->tbgn; + unsigned long tend = wctx->tend; + if ((unsigned long) (cur->pc) < tbgn || (unsigned long) (cur->pc) >= tend) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: pc out of range, pc=0x%lx\n", (unsigned long) (cur->pc)); + break; + } + if (jmp_reg_switch_base != NULL && cur->pc > jmp_reg_switch_base + max_switch_pc_offset) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: limit the walk offset after jmp reg instruction\n"); + if (jmp_reg_switch_backup_ctx != NULL) + __collector_memcpy (cur, jmp_reg_switch_backup_ctx, sizeof (*cur)); + int rc = process_return_real (wctx, cur, 0); + if (rc == RA_SUCCESS) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + break; // limit the walk offset after jmp reg instruction, got checkFP + } + } + + if (nctx == 0) + break; +// dump_targets (__LINE__, ntrg, targets); + while (cur->pc > targets[cur->tidx]) + cur->tidx += 1; + if (cur->pc == targets[cur->tidx]) + { + /* Stop analysis. Delete context. */ + if (jmp_reg_switch_mode == 0 || cur->pc != jmp_reg_switch_pc_old) + { + if (jmp_reg_switch_mode == 1 && nctx == 1 && jmp_reg_switch_pc == NULL) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d old target, cur->pc=%p, jmp_reg_switch_pc=%p, nctx=%d\n", + __LINE__, cur->pc, jmp_reg_switch_pc, nctx); + jmp_reg_switch_pc = cur->pc; // save cp before delete context, may be used as a start of switch case + jmp_reg_switch_pc_old = jmp_reg_switch_pc; + } + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, old target.\n", __LINE__); + DELETE_CURCTX (); + if (cur >= buf + nctx) + cur = buf; + continue; + } + if (jmp_reg_switch_mode == 1 && cur->pc == jmp_reg_switch_pc_old) + jmp_reg_switch_pc_old = NULL; // reset jmp_reg_switch_pc_old to delete the context later when cur->pc != jmp_reg_switch_pc_old + } + + /* let's walk the next x86 instruction */ + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d cur:%ld pc=0x%lx %02x %02x %02x %02x %02x %02x %02x sp=0x%lx\n", + __LINE__, (long) (cur - buf), (unsigned long) cur->pc, + (int) cur->pc[0], (int) cur->pc[1], (int) cur->pc[2], + (int) cur->pc[3], (int) cur->pc[4], (int) cur->pc[5], + (int) cur->pc[6], (unsigned long) cur->sp); + int v = 4; /* Operand size */ + int a = 4; /* Address size */ + /* int W = 0; REX.W bit */ +#if WSIZE(64) + int R = 0; /* REX.R bit */ +#endif + int X = 0; /* REX.X bit */ + int B = 0; /* REX.B bit */ + /* Check prefixes */ + int done = 0; + while (!done) + { + opcode = *cur->pc++; + switch (opcode) + { + case 0x66: /* opd size override */ + v = 2; + break; + case 0x67: /*addr size override */ + a = 2; + break; +#if WSIZE(64) + case 0x40: /* REX */ + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + B = (opcode & 0x1) ? 8 : 0; + X = (opcode & 0x2) ? 8 : 0; + R = (opcode & 0x4) ? 8 : 0; + if (opcode & 0x8) /* 64 bit operand size */ + v = 8; + opcode = *cur->pc++; + done = 1; + break; +#endif + default: + done = 1; + break; + } + } + int z = (v == 8) ? 4 : v; + switch (opcode) + { + case 0x0: /* add Eb,Gb */ + case 0x01: /* add Ev,Gv */ + case 0x02: /* add Gb,Eb */ + case 0x03: /* add Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x04: /* add %al,Ib */ + cur->pc += 1; + break; + case 0x05: /* add %eax,Iz */ + cur->pc += z; + break; + case 0x06: /* push es */ + cur->sp -= 1; + break; + case 0x07: /* pop es */ + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0x08: /* or Eb,Gb */ + case 0x09: /* or Ev,Gv */ + case 0x0a: /* or Gb,Eb */ + case 0x0b: /* or Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x0c: /* or %al,Ib */ + cur->pc += 1; + break; + case 0x0d: /* or %eax,Iz */ + cur->pc += z; + break; + case 0x0e: /* push cs */ + cur->sp -= 1; + break; + case 0x0f: /* two-byte opcodes */ + extop = *cur->pc++; + switch (extop) + { /* RTM or HLE */ + case 0x01: + extop2 = *cur->pc; + switch (extop2) + { + case 0xd5: /* xend */ + case 0xd6: /* xtest */ + cur->pc++; + break; + default: + break; + } + break; + case 0x03: + cur->pc = check_modrm (cur->pc); + break; + case 0x0b: + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, undefined instruction. opcode=0x%02x\n", + __LINE__, (int) opcode); + DELETE_CURCTX (); + break; + case 0x05: /* syscall */ + case 0x34: /* sysenter */ + if (cur->rax == __NR_exit) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode=0x%02x\n", + __LINE__, (int) opcode); + DELETE_CURCTX (); + break; + } + else if (cur->rax == __NR_rt_sigreturn) + { + if (jmp_reg_switch_mode == 1) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address under jmp switch mode, opcode=0x%02x\n", + __LINE__, (int) opcode); + goto checkFP; + } + wctx->sp = (unsigned long) cur->sp; + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_RT_SIGRETURN); + return RA_RT_SIGRETURN; + } +#if WSIZE(32) + else if (cur->rax == __NR_sigreturn) + { + if (jmp_reg_switch_mode == 1) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: give up return address under jmp switch mode, opcode = 0x34\n"); + goto checkFP; + } + wctx->sp = (unsigned long) cur->sp; + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_SIGRETURN); + return RA_SIGRETURN; + } +#endif + /* Check for Linus' trick in the vsyscall page */ + while (*cur->pc == 0x90) /* nop */ + cur->pc++; + if (*cur->pc == 0xeb) /* jmp imm8 */ + cur->pc += 2; + break; + case 0x0d: /* nop Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x10: /* xmm Vq,Wq */ + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + cur->pc = check_modrm (cur->pc); + break; + case 0x18: /* prefetch */ + cur->pc = check_modrm (cur->pc); + break; + case 0x1E: /* endbr64/endbr32 (f3 0f 1e .. ) is parsing as repz nop edx */ + cur->pc += 2; + break; + case 0x1f: /* nop Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x28: /* xmm Vq,Wq */ + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + cur->pc = check_modrm (cur->pc); + break; + case 0x30: /* wrmsr */ + case 0x31: /* rdtsc */ + case 0x32: /* rdmsr */ + case 0x33: /* rdpmc */ + break; + /* case 0x34: sysenter (see above) */ + case 0x38: case 0x3a: + extop2 = *cur->pc++; + cur->pc = check_modrm (cur->pc); + // 21275311 Unwind failure in native stack for java application running on jdk8 + // Three-byte opcodes "66 0f 3a ??" should consume an additional "immediate" byte. + if (extop == 0x3a) + cur->pc++; + break; + case 0x40: case 0x41: case 0x42: case 0x43: /* CMOVcc Gv,Ev */ + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + cur->pc = check_modrm (cur->pc); + break; + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + cur->pc = check_modrm (cur->pc); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + cur->pc = check_modrm (cur->pc) + 1; + break; + case 0x74: case 0x75: case 0x76: + cur->pc = check_modrm (cur->pc); + break; + case 0x77: + break; + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + cur->pc = check_modrm (cur->pc); + break; + case 0x80: case 0x81: case 0x82: case 0x83: /* Jcc Jz */ + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + immv = read_int (cur->pc, z); + cur->pc += z; + if (nctx < (jmp_reg_switch_mode ? MAXJMPREGCTX : MAXCTX)) + { + int tidx = 0; + unsigned char *npc = cur->pc + immv; + if ((unsigned long) npc < wctx->tbgn || (unsigned long) npc >= wctx->tend) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode=0x%02x\n", + __LINE__, (int) opcode); + DELETE_CURCTX (); + break; + } + if (is_after_ret (npc)) + break; + while (npc > targets[tidx]) + tidx += 1; + if (npc != targets[tidx]) + { + if (ntrg < MAXTRGTS) + { + for (int i = 0; i < nctx; i++) + if (buf[i].tidx >= tidx) + buf[i].tidx++; + + /* insert a new target */ + for (int i = ntrg; i > tidx; i--) + targets[i] = targets[i - 1]; + ntrg += 1; + targets[tidx++] = npc; + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d ntrg=max(%d)\n", + __LINE__, ntrg); + struct AdvWalkContext *new = buf + nctx; + nctx += 1; + __collector_memcpy (new, cur, sizeof (*new)); + new->pc = npc; + new->tidx = tidx; + cur = new; /* advance the new context first */ + continue; + } + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d nctx=max(%d)\n", + __LINE__, ntrg); + break; + case 0x90: case 0x91: case 0x92: case 0x93: /* setcc Eb */ + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + cur->pc = check_modrm (cur->pc); + break; + case 0xa0: /* push fs */ + cur->sp -= 1; + break; + case 0xa1: /* pop fs */ + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0xa2: /* cpuid */ + break; + case 0xa3: /* bt Ev,Gv */ + cur->pc = check_modrm (cur->pc); + break; + case 0xa4: /* shld Ev,Gv,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0xa5: /* shld Ev,Gv,%cl */ + cur->pc = check_modrm (cur->pc); + break; + case 0xa8: /* push gs */ + cur->sp -= 1; + break; + case 0xa9: /* pop gs */ + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0xaa: /* rsm */ + break; + case 0xab: /* bts Ev,Gv */ + cur->pc = check_modrm (cur->pc); + break; + case 0xac: /* shrd Ev,Gv,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0xad: /* shrd Ev,Gv,%cl */ + cur->pc = check_modrm (cur->pc); + break; + case 0xae: /* group15 */ + cur->pc = check_modrm (cur->pc); + break; + case 0xaf: /* imul Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0xb1: /* cmpxchg Ev,Gv */ + cur->pc = check_modrm (cur->pc); + break; + case 0xb3: + case 0xb6: /* movzx Gv,Eb */ + case 0xb7: /* movzx Gv,Ew */ + cur->pc = check_modrm (cur->pc); + break; + case 0xba: /* group8 Ev,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0xbb: /* btc Ev,Gv */ + case 0xbc: /* bsf Gv,Ev */ + case 0xbd: /* bsr Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0xbe: /* movsx Gv,Eb */ + case 0xbf: /* movsx Gv,Ew */ + cur->pc = check_modrm (cur->pc); + break; + case 0xc0: /* xadd Eb,Gb */ + case 0xc1: /* xadd Ev,Gv */ + cur->pc = check_modrm (cur->pc); + break; + case 0xc2: /* cmpps V,W,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0xc3: /* movnti M,G */ + cur->pc = check_modrm (cur->pc); + break; + case 0xc6: /* shufps V,W,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0xc7: /* RDRAND */ + cur->pc = check_modrm (cur->pc); + break; + case 0xc8: case 0xc9: case 0xca: case 0xcb: /* bswap */ + case 0xcc: case 0xcd: case 0xce: case 0xcf: + break; + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + cur->pc = check_modrm (cur->pc); + break; + default: + if (jmp_reg_switch_mode == 1 && extop == 0x0b) + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d invalid opcode ub2: 0x0f %x jmp_reg_switch_mode=%d\n", + __LINE__, (int) extop, jmp_reg_switch_mode); + else + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0x0f %x jmp_reg_switch_mode=%d\n", + __LINE__, (int) extop, jmp_reg_switch_mode); + DELETE_CURCTX (); + } + break; + } + break; + case 0x10: /* adc Eb,Gb */ + case 0x11: /* adc Ev,Gv */ + case 0x12: /* adc Gb,Eb */ + case 0x13: /* adc Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x14: /* adc %al,Ib */ + cur->pc += 1; + break; + case 0x15: /* adc %eax,Iz */ + cur->pc += z; + break; + case 0x16: /* push ss */ + cur->sp -= 1; + break; + case 0x17: /* pop ss */ + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0x18: /* sbb Eb,Gb */ + case 0x19: /* sbb Ev,Gv */ + case 0x1a: /* sbb Gb,Eb */ + case 0x1b: /* sbb Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x1c: /* sbb %al,Ib */ + cur->pc += 1; + break; + case 0x1d: /* sbb %eax,Iz */ + cur->pc += z; + break; + case 0x1e: /* push ds */ + cur->sp -= 1; + break; + case 0x1f: /* pop ds */ + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0x20: /* and Eb,Gb */ + case 0x21: /* and Ev,Gv */ + case 0x22: /* and Gb,Eb */ + case 0x23: /* and Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x24: /* and %al,Ib */ + cur->pc += 1; + break; + case 0x25: /* and %eax,Iz */ + cur->pc += z; + break; + case 0x26: /* seg=es prefix */ + break; + case 0x27: /* daa */ + break; + case 0x28: /* sub Eb,Gb */ + case 0x29: /* sub Ev,Gv */ + case 0x2a: /* sub Gb,Eb */ + case 0x2b: /* sub Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x2c: /* sub %al,Ib */ + cur->pc += 1; + break; + case 0x2d: /* sub %eax,Iz */ + cur->pc += z; + break; + case 0x2e: /* seg=cs prefix */ + break; + case 0x2f: /* das */ + break; + case 0x30: /* xor Eb,Gb */ + case 0x31: /* xor Ev,Gv */ + case 0x32: /* xor Gb,Eb */ + case 0x33: /* xor Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x34: /* xor %al,Ib */ + cur->pc += 1; + break; + case 0x35: /* xor %eax,Iz */ + cur->pc += z; + break; + case 0x36: /* seg=ss prefix */ + break; + case 0x37: /* aaa */ + break; + case 0x38: /* cmp Eb,Gb */ + case 0x39: /* cmp Ev,Gv */ + case 0x3a: /* cmp Gb,Eb */ + case 0x3b: /* cmp Gv,Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x3c: /* cmp %al,Ib */ + cur->pc += 1; + break; + case 0x3d: /* cmp %eax,Iz */ + cur->pc += z; + break; + case 0x3e: /* seg=ds prefix */ + break; + case 0x3f: /* aas */ + break; +#if WSIZE(32) + case 0x40: /* inc %eax */ + case 0x41: /* inc %ecx */ + case 0x42: /* inc %edx */ + case 0x43: /* inc %ebx */ + break; + case 0x44: /* inc %esp */ + /* Can't be a valid stack pointer - delete context */ + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0x44.\n", __LINE__); + DELETE_CURCTX (); + break; + case 0x45: /* inc %ebp */ + case 0x46: /* inc %esi */ + case 0x47: /* inc %edi */ + case 0x48: /* dec %eax */ + case 0x49: /* dec %ecx */ + case 0x4a: /* dec %edx */ + case 0x4b: /* dec %ebx */ + break; + case 0x4c: /* dec %esp */ + /* Can't be a valid stack pointer - delete context */ + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0x4c.\n", __LINE__); + DELETE_CURCTX (); + break; + case 0x4d: /* dec %ebp */ + case 0x4e: /* dec %esi */ + case 0x4f: /* dec %edi */ + break; +#endif + case 0x50: /* push %eax */ + case 0x51: /* push %ecx */ + case 0x52: /* push %edx */ + case 0x53: /* push %ebx */ + case 0x54: /* push %esp */ + case 0x55: /* push %ebp */ + case 0x56: /* push %esi */ + case 0x57: /* push %edi */ + cur->sp -= 1; + reg = OPC_REG (opcode); + if (reg == RBP) + { +#if 0 + /* Don't do this check yet. Affects tail calls. */ + /* avoid other function's prologue */ + if ((cur->pc[0] == 0x89 && cur->pc[1] == 0xe5) || + (cur->pc[0] == 0x8b && cur->pc[1] == 0xec)) + { + /* mov %esp,%ebp */ + DELETE_CURCTX (); + break; + } +#endif + if (cur->fp_loc == NULL) + { + cur->fp_loc = cur->sp; + cur->fp_sav = cur->fp; + } + } + break; + case 0x58: /* pop %eax */ + case 0x59: /* pop %ecx */ + case 0x5a: /* pop %edx */ + case 0x5b: /* pop %ebx */ + case 0x5c: /* pop %esp */ + case 0x5d: /* pop %ebp */ + case 0x5e: /* pop %esi */ + case 0x5f: /* pop %edi */ + reg = OPC_REG (opcode); + cur->regs[reg] = 0; + if (isInside ((unsigned long) cur->sp, (unsigned long) cur->sp_safe, wctx->sbase)) + cur->regs[reg] = *cur->sp; + DprintfT (SP_DUMP_UNWIND, "stack_unwind:%d cur->regs[%d]=0x%lx\n", + __LINE__, reg, (unsigned long) cur->regs[reg]); + if (reg == RDX) + { + if (cur->sp >= cur->sp_safe && + (unsigned long) cur->sp < wctx->sbase) + cur->rdx = *cur->sp; + } + else if (reg == RBP) + { + if (cur->fp_loc == cur->sp) + { + cur->fp = cur->fp_sav; + cur->fp_loc = NULL; + } + else if (cur->sp >= cur->sp_safe && + (unsigned long) cur->sp < wctx->sbase) + cur->fp = (unsigned long*) (*cur->sp); + } + else if (reg == RSP) + { + /* f.e. JVM I2CAdapter */ + if (cur->sp >= cur->sp_safe && (unsigned long) cur->sp < wctx->sbase) + { + unsigned long *nsp = (unsigned long*) (*cur->sp); + if (nsp >= cur->sp && nsp <= cur->fp) + { + cur->sp = nsp; + } + else + { + DprintfT (SP_DUMP_UNWIND, "stack_unwind%d give up return address, opcode=0x%02x\n", + __LINE__, opcode); + goto checkFP; + } + } + else + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address, opcode=0x%02x\n", + __LINE__, opcode); + goto checkFP; + } + break; + } + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + { + cur->sp_safe = cur->sp - RED_ZONE; + } + break; + case 0x60: /* pusha(d) */ + cur->sp -= 8; + break; + case 0x61: /* popa(d) */ + cur->sp += 8; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0x62: /* group AVX, 4-bytes EVEX prefix */ + { + unsigned char *pc = cur->pc - 1; // points to the beginning of the instruction + int len = parse_x86_AVX_instruction (pc); + if (len < 4) + { + DELETE_CURCTX (); + } + else + { + pc += len; + cur->pc = pc; + } + } + break; + case 0x63: /* arpl Ew,Gw (32) movsxd Gv,Ev (64)*/ + cur->pc = check_modrm (cur->pc); + break; + case 0x64: /* seg=fs prefix */ + case 0x65: /* seg=gs prefix */ + break; + case 0x66: /* opd size override */ + case 0x67: /* addr size override */ + break; + case 0x68: /* push Iz */ + cur->sp = (unsigned long*) ((long) cur->sp - z); + cur->pc += z; + break; + case 0x69: /* imul Gv,Ev,Iz */ + cur->pc = check_modrm (cur->pc); + cur->pc += z; + break; + case 0x6a: /* push Ib */ + cur->sp = (unsigned long*) ((long) cur->sp - v); + cur->pc += 1; + break; + case 0x6b: /* imul Gv,Ev,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + cur->pc = check_modrm (cur->pc); + break; + case 0x70: /* jo Jb */ + case 0x71: /* jno Jb */ + case 0x72: /* jb Jb */ + case 0x73: /* jnb Jb */ + case 0x74: /* jz Jb */ + case 0x75: /* jnz Jb */ + case 0x76: /* jna Jb */ + case 0x77: /* ja Jb */ + case 0x78: /* js Jb */ + case 0x79: /* jns Jb */ + case 0x7a: /* jp Jb */ + case 0x7b: /* jnp Jb */ + case 0x7c: /* jl Jb */ + case 0x7d: /* jge Jb */ + case 0x7e: /* jle Jb */ + case 0x7f: /* jg Jb */ + imm8 = *(char*) cur->pc++; + if (nctx < (jmp_reg_switch_mode ? MAXJMPREGCTX : MAXCTX)) + { + int tidx = 0; + unsigned char *npc = cur->pc + imm8; + if (is_after_ret (npc)) + break; + while (npc > targets[tidx]) + tidx += 1; + if (npc != targets[tidx]) + { + if (ntrg < MAXTRGTS) + { + for (int i = 0; i < nctx; i++) + if (buf[i].tidx >= tidx) + buf[i].tidx++; + + /* insert a new target */ + for (int i = ntrg; i > tidx; i--) + targets[i] = targets[i - 1]; + ntrg += 1; + targets[tidx++] = npc; + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d ntrg(%d)=max\n", __LINE__, ntrg); + struct AdvWalkContext *new = buf + nctx; + nctx += 1; + __collector_memcpy (new, cur, sizeof (*new)); + new->pc = npc; + new->tidx = tidx; + cur = new; /* advance the new context first */ + continue; + } + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d nctx(%d)=max\n", __LINE__, nctx); + break; + case 0x80: /* group1 Eb,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0x81: /* group1 Ev,Iz */ + modrm = *cur->pc; + if (MRM_MOD (modrm) == 0xc0 && MRM_REGS (modrm) == RSP) + { + int immz = read_int (cur->pc + 1, z); + extop = MRM_EXT (modrm); + if (extop == 0) /* add imm32,%esp */ + cur->sp = (unsigned long*) ((long) cur->sp + immz); + else if (extop == 4) /* and imm32,%esp */ + cur->sp = (unsigned long*) ((long) cur->sp & immz); + else if (extop == 5) /* sub imm32,%esp */ + cur->sp = (unsigned long*) ((long) cur->sp - immz); + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + } + cur->pc = check_modrm (cur->pc); + cur->pc += z; + break; + case 0x82: /* group1 Eb,Ib */ + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0x83: /* group1 Ev,Ib */ + modrm = *cur->pc; + if (MRM_MOD (modrm) == 0xc0 && MRM_REGS (modrm) == RSP) + { + imm8 = (char) cur->pc[1]; /* sign extension */ + extop = MRM_EXT (modrm); + if (extop == 0) /* add imm8,%esp */ + cur->sp = (unsigned long*) ((long) cur->sp + imm8); + else if (extop == 4) /* and imm8,%esp */ + cur->sp = (unsigned long*) ((long) cur->sp & imm8); + else if (extop == 5) /* sub imm8,%esp */ + cur->sp = (unsigned long*) ((long) cur->sp - imm8); + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + } + cur->pc = check_modrm (cur->pc); + cur->pc += 1; + break; + case 0x84: /* test Eb,Gb */ + case 0x85: /* test Ev,Gv */ + case 0x86: /* xchg Eb,Gb */ + case 0x87: /* xchg Ev,Gv */ + cur->pc = check_modrm (cur->pc); + break; + case 0x88: /* mov Eb,Gb */ + cur->pc = check_modrm (cur->pc); + break; + case 0x89: /* mov Ev,Gv */ + modrm = *cur->pc; + if (MRM_MOD (modrm) == 0xc0) + { + if (MRM_REGS (modrm) == RBP && MRM_REGD (modrm) == RSP) + /* movl %esp,%ebp */ + cur->fp = cur->sp; + else if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { /* mov %ebp,%esp */ + cur->sp = cur->fp; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + if (wctx->fp == (unsigned long) cur->sp) + cur->cval = RA_FROMFP; + } + } + else if (MRM_MOD (modrm) == 0x80) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { + if (cur->pc[1] == 0x24) + { /* mov %ebp,disp32(%esp) - JVM */ + immv = read_int (cur->pc + 2, 4); + cur->fp_loc = (unsigned long*) ((char*) cur->sp + immv); + cur->fp_sav = cur->fp; + } + } + } + else if (MRM_MOD (modrm) == 0x40) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RDX) + { + if (cur->pc[1] == 0x24 && cur->pc[2] == 0x0) + { /* movl %edx,0(%esp) */ + cur->ra_loc = cur->sp; + cur->ra_sav = cur->rdx; + } + } + else if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { + if (cur->pc[1] == 0x24) + { /* mov %ebp,disp8(%esp) - JVM */ + imm8 = ((char*) (cur->pc))[2]; + cur->fp_loc = (unsigned long*) ((char*) cur->sp + imm8); + cur->fp_sav = cur->fp; + } + } + } + else if (MRM_MOD (modrm) == 0x0) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { + if (cur->pc[1] == 0x24) + { /* mov %ebp,(%esp) */ + cur->fp_loc = cur->sp; + cur->fp_sav = cur->fp; + } + } + else if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RDX) + { + if (cur->pc[1] == 0x24) + { /* movl %edx,(%esp) */ + cur->ra_loc = cur->sp; + cur->ra_sav = cur->rdx; + } + } + } + cur->pc = check_modrm (cur->pc); + break; + case 0x8a: /* mov Gb,Eb */ + cur->pc = check_modrm (cur->pc); + break; + case 0x8b: /* mov Gv,Ev */ + modrm = *cur->pc; + if (MRM_MOD (modrm) == 0xc0) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + /* mov %esp,%ebp */ + cur->fp = cur->sp; + else if (MRM_REGS (modrm) == RBP && MRM_REGD (modrm) == RSP) + { /* mov %ebp,%esp */ + cur->sp = cur->fp; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + if (wctx->fp == (unsigned long) cur->sp) + cur->cval = RA_FROMFP; + } + } + else if (MRM_MOD (modrm) == 0x80) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { + if (cur->pc[1] == 0x24) + { /* mov disp32(%esp),%ebp */ + immv = read_int (cur->pc + 2, 4); + unsigned long *ptr = (unsigned long*) ((char*) cur->sp + immv); + if (cur->fp_loc == ptr) + { + cur->fp = cur->fp_sav; + cur->fp_loc = NULL; + } + else if (ptr >= cur->sp_safe && (unsigned long) ptr < wctx->sbase) + cur->fp = (unsigned long*) (*ptr); + } + } + } + else if (MRM_MOD (modrm) == 0x40) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { + if (cur->pc[1] == 0x24) + { /* mov disp8(%esp),%ebp - JVM */ + imm8 = ((char*) (cur->pc))[2]; + unsigned long *ptr = (unsigned long*) ((char*) cur->sp + imm8); + if (cur->fp_loc == ptr) + { + cur->fp = cur->fp_sav; + cur->fp_loc = NULL; + } + else if (ptr >= cur->sp_safe && (unsigned long) ptr < wctx->sbase) + cur->fp = (unsigned long*) (*ptr); + } + } + } + else if (MRM_MOD (modrm) == 0x0) + { + if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP) + { + if (cur->pc[1] == 0x24) + { /* mov (%esp),%ebp */ + if (cur->fp_loc == cur->sp) + { + cur->fp = cur->fp_sav; + cur->fp_loc = NULL; + } + else if (cur->sp >= cur->sp_safe && + (unsigned long) cur->sp < wctx->sbase) + cur->fp = (unsigned long*) *cur->sp; + } + } + } + cur->pc = check_modrm (cur->pc); + break; + case 0x8c: /* mov Mw,Sw */ + cur->pc = check_modrm (cur->pc); + break; + case 0x8d: /* lea Gv,M */ + modrm = *cur->pc; + if (MRM_REGD (modrm) == RSP) + { + unsigned char *pc = cur->pc; + // Mez: need to use always regs[RSP/RBP] instead cur->sp(or fp): + cur->regs[RSP] = (unsigned long) cur->sp; + cur->regs[RBP] = (unsigned long) cur->fp; + cur->pc++; + int mod = (modrm >> 6) & 3; + int r_m = modrm & 7; + long val = 0; + int undefRez = 0; + if (mod == 0x3) + val = getRegVal (cur, MRM_REGS (modrm), &undefRez); + else if (r_m == 4) + { // SP or R12. Decode SIB-byte. + int sib = *cur->pc++; + int scale = 1 << (sib >> 6); + int index = X | ((sib >> 3) & 7); + int base = B | (sib & 7); + if (mod == 0) + { + if ((base & 7) == 5) + { // BP or R13 + if (index != 4) // SP + val += getRegVal (cur, index, &undefRez) * scale; + val += read_int (cur->pc, 4); + cur->pc += 4; + } + else + { + val += getRegVal (cur, base, &undefRez); + if (index != 4) // SP + val += getRegVal (cur, index, &undefRez) * scale; + } + } + else + { + val += getRegVal (cur, base, &undefRez); + if (index != 4) // SP + val += getRegVal (cur, index, &undefRez) * scale; + if (mod == 1) + { + val += read_int (cur->pc, 1); + cur->pc++; + } + else + { // mod == 2 + val += read_int (cur->pc, 4); + cur->pc += 4; + } + } + } + else if (mod == 0) + { + if (r_m == 5) + { // BP or R13 + val += read_int (cur->pc, 4); + cur->pc += 4; + } + else + val += getRegVal (cur, MRM_REGS (modrm), &undefRez); + } + else + { // mod == 1 || mod == 2 + val += getRegVal (cur, MRM_REGS (modrm), &undefRez); + if (mod == 1) + { + val += read_int (cur->pc, 1); + cur->pc++; + } + else + { // mod == 2 + val += read_int (cur->pc, 4); + cur->pc += 4; + } + } + if (undefRez) + { + DprintfT (SP_DUMP_UNWIND, "stack_unwind%d cannot calculate RSP. cur->pc=0x%lx val=0x%lx\n", + __LINE__, (unsigned long) cur->pc, (unsigned long) val); + goto checkFP; + } + cur->regs[MRM_REGD (modrm)] = val; + DprintfT (SP_DUMP_UNWIND, "stack_unwind%d cur->pc=0x%lx val=0x%lx wctx->sp=0x%lx wctx->sbase=0x%lx\n", + __LINE__, (unsigned long) cur->pc, (unsigned long) val, + (unsigned long) wctx->sp, (unsigned long) wctx->sbase); + if (cur->pc != check_modrm (pc)) + DprintfT (SP_DUMP_UNWIND, "stack_unwind%d ERROR: cur->pc=0x%lx != check_modrm(0x%lx)=0x%lx\n", + __LINE__, (unsigned long) cur->pc, (unsigned long) pc, + (unsigned long) check_modrm (pc)); + if (MRM_REGD (modrm) == RSP) + { + if (!isInside ((unsigned long) val, wctx->sp, wctx->sbase)) + { + DprintfT (SP_DUMP_UNWIND, "stack_unwind%d cannot calculate RSP. cur->pc=0x%lx opcode=0x%02x val=0x%lx wctx->sp=0x%lx wctx->sbase=0x%lx\n", + __LINE__, (unsigned long) cur->pc, opcode, (unsigned long) val, + (unsigned long) wctx->sp, (unsigned long) wctx->sbase); + goto checkFP; + } + cur->sp = (unsigned long *) val; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + } + } + else + cur->pc = check_modrm (cur->pc); + break; + case 0x8e: /* mov Sw,Ew */ + cur->pc = check_modrm (cur->pc); + break; + case 0x8f: /* pop Ev */ + cur->pc = check_modrm (cur->pc); + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0x90: /* nop */ + break; + case 0x91: /* xchg %eax,%ecx */ + case 0x92: /* xchg %eax,%edx */ + case 0x93: /* xchg %eax,%ebx */ + case 0x94: /* xchg %eax,%esp XXXX */ + case 0x95: /* xchg %eax,%ebp XXXX */ + case 0x96: /* xchg %eax,%esi */ + case 0x97: /* xchg %eax,%edi */ + break; + case 0x98: /* cbw/cwde */ + case 0x99: /* cwd/cwq */ + break; + case 0x9a: /* callf Ap */ + if (jmp_reg_switch_mode == 1) + { + struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur)); + __collector_memcpy (tmpctx, cur, sizeof (*cur)); + int rc = process_return (wctx, tmpctx); + if (rc != RA_FAILURE) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + cur->pc += 2 + a; + break; + case 0x9b: /* fwait */ + case 0x9c: /* pushf Fv */ + case 0x9d: /* popf Fv */ + case 0x9e: /* sahf */ + case 0x9f: /* lahf */ + break; + case 0xa0: /* mov al,Ob */ + case 0xa1: /* mov eax,Ov */ + case 0xa2: /* mov Ob,al */ + case 0xa3: /* mov Ov,eax */ + cur->pc += a; + break; + case 0xa4: /* movsb Yb,Xb */ + case 0xa5: /* movsd Yv,Xv */ + case 0xa6: /* cmpsb Yb,Xb */ + case 0xa7: /* cmpsd Xv,Yv */ + break; + case 0xa8: /* test al,Ib */ + cur->pc += 1; + break; + case 0xa9: /* test eax,Iz */ + cur->pc += z; + break; + case 0xaa: /* stosb Yb,%al */ + case 0xab: /* stosd Yv,%eax */ + case 0xac: /* lodsb %al,Xb */ + case 0xad: /* lodsd %eax,Xv */ + case 0xae: /* scasb %al,Yb */ + case 0xaf: /* scasd %eax,Yv */ + break; + case 0xb0: /* mov %al,Ib */ + case 0xb1: /* mov %cl,Ib */ + case 0xb2: /* mov %dl,Ib */ + case 0xb3: /* mov %bl,Ib */ + case 0xb4: /* mov %ah,Ib */ + case 0xb5: /* mov %ch,Ib */ + case 0xb6: /* mov %dh,Ib */ + case 0xb7: /* mov %bh,Ib */ + cur->pc += 1; + break; + case 0xb8: /* mov Iv,%eax */ + case 0xb9: /* mov Iv,%ecx */ + case 0xba: /* mov Iv,%edx */ + case 0xbb: /* mov Iv,%ebx */ + case 0xbc: /* mov Iv,%esp */ + case 0xbd: /* mov Iv,%rbp */ + case 0xbe: /* mov Iv,%esi */ + case 0xbf: /* mov Iv,%edi */ + reg = OPC_REG (opcode); + if (reg == RAX) + cur->rax = read_int (cur->pc, v); + cur->pc += v; + break; + case 0xc0: /* group2 Eb,Ib */ + case 0xc1: /* group2 Ev,Ib */ + cur->pc = check_modrm (cur->pc) + 1; + break; + case 0xc2: /* ret Iw */ + /* In the dynamic linker we may see that + * the actual return address is at sp+immv, + * while sp points to the resolved address. + */ + { + immv = read_int (cur->pc, 2); + int rc = process_return (wctx, cur); + if (rc != RA_FAILURE) + { + if (jmp_reg_switch_mode == 1) + { + DprintfT (SP_DUMP_UNWIND, "stack_unwind%d give up return address under jmp switch mode, opcode = 0xc2\n", __LINE__); + goto checkFP; + } + wctx->sp += immv; + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xc2.\n", __LINE__); + DELETE_CURCTX (); + } + break; + case 0xc3: /* ret */ + { + int rc = process_return (wctx, cur); + if (rc != RA_FAILURE) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + if (jmp_reg_switch_mode == 1) + jmp_reg_switch_pc = cur->pc; + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xc3.\n", __LINE__); + DELETE_CURCTX (); + } + break; + case 0xc4: /* group AVX, 3-bytes VEX prefix */ + { + unsigned char *pc = cur->pc - 1; // points to the beginning of the instruction + int len = parse_x86_AVX_instruction (pc); + if (len < 3) + DELETE_CURCTX (); + else + { + pc += len; + cur->pc = pc; + } + } + break; + case 0xc5: /* group AVX, 2-bytes VEX prefix */ + { + unsigned char *pc = cur->pc - 1; // points to the beginning of the instruction + int len = parse_x86_AVX_instruction (pc); + if (len < 2) + DELETE_CURCTX (); + else + { + pc += len; + cur->pc = pc; + } + } + break; + case 0xc6: + modrm = *cur->pc; + if (modrm == 0xf8) /* xabort */ + cur->pc += 2; + else /* mov Eb,Ib */ + cur->pc = check_modrm (cur->pc) + 1; + break; + case 0xc7: + modrm = *cur->pc; + if (modrm == 0xf8) /* xbegin */ + cur->pc += v + 1; + else + { /* mov Ev,Iz */ + extop = MRM_EXT (modrm); + if (extop != 0) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address, opcode = 0xc7\n", __LINE__); + goto checkFP; + } + if (MRM_MOD (modrm) == 0xc0 && MRM_REGS (modrm) == RAX) + cur->rax = read_int (cur->pc + 1, z); + cur->pc = check_modrm (cur->pc) + z; + } + break; + case 0xc8: /* enter Iw,Ib */ + cur->pc += 3; + break; + case 0xc9: /* leave */ + /* mov %ebp,%esp */ + cur->sp = cur->fp; + /* pop %ebp */ + if (cur->fp_loc == cur->sp) + { + cur->fp = cur->fp_sav; + cur->fp_loc = NULL; + } + else if (cur->sp >= cur->sp_safe && + (unsigned long) cur->sp < wctx->sbase) + { + cur->fp = (unsigned long*) (*cur->sp); + if (wctx->fp == (unsigned long) cur->sp) + cur->cval = RA_FROMFP; + } + cur->sp += 1; + if (cur->sp - RED_ZONE > cur->sp_safe) + cur->sp_safe = cur->sp - RED_ZONE; + break; + case 0xca: /* retf Iw */ + cur->pc += 2; /* XXXX process return */ + break; + case 0xcb: /* retf */ + break; /* XXXX process return */ + case 0xcc: /* int 3 */ + break; + case 0xcd: /* int Ib */ + if (*cur->pc == 0x80) + { + if (cur->rax == __NR_exit) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xcd.\n", __LINE__); + DELETE_CURCTX (); + break; + } + else if (cur->rax == __NR_rt_sigreturn) + { + if (jmp_reg_switch_mode == 1) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address under jmp switch mode, opcode=0xcd\n", + __LINE__); + goto checkFP; + } + wctx->sp = (unsigned long) cur->sp; + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_RT_SIGRETURN); + return RA_RT_SIGRETURN; + } +#if WSIZE(32) + else if (cur->rax == __NR_sigreturn) + { + if (jmp_reg_switch_mode == 1) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address under jmp switch mode, opcode = 0xc2\n", + __LINE__); + goto checkFP; + } + wctx->sp = (unsigned long) cur->sp; + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_SIGRETURN); + return RA_SIGRETURN; + } +#endif + } + cur->pc += 1; + break; + case 0xce: /* into */ + case 0xcf: /* iret */ + break; + case 0xd0: /* shift group2 Eb,1 */ + case 0xd1: /* shift group2 Ev,1 */ + case 0xd2: /* shift group2 Eb,%cl */ + case 0xd3: /* shift group2 Ev,%cl */ + cur->pc = check_modrm (cur->pc); + break; + case 0xd4: /* aam Ib */ + cur->pc += 1; + break; + case 0xd5: /* aad Ib */ + cur->pc += 1; + break; + case 0xd6: /* falc? */ + break; + case 0xd7: + cur->pc = check_modrm (cur->pc); + cur->pc++; + break; + case 0xd8: /* esc instructions */ + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + cur->pc = check_modrm (cur->pc); + break; + case 0xe0: /* loopne Jb */ + case 0xe1: /* loope Jb */ + case 0xe2: /* loop Jb */ + case 0xe3: /* jcxz Jb */ + imm8 = *(char*) cur->pc++; + if (nctx < (jmp_reg_switch_mode ? MAXJMPREGCTX : MAXCTX)) + { + int tidx = 0; + unsigned char *npc = cur->pc + imm8; + if (is_after_ret (npc)) + break; + while (npc > targets[tidx]) + tidx += 1; + if (npc != targets[tidx]) + { + if (ntrg < MAXTRGTS) + { + for (int i = 0; i < nctx; i++) + if (buf[i].tidx >= tidx) + buf[i].tidx++; + /* insert a new target */ + for (int i = ntrg; i > tidx; i--) + targets[i] = targets[i - 1]; + ntrg += 1; + targets[tidx++] = npc; + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c: ntrg = max\n"); + struct AdvWalkContext *new = buf + nctx; + nctx += 1; + __collector_memcpy (new, cur, sizeof (*new)); + new->pc = npc; + new->tidx = tidx; + cur = new; /* advance the new context first */ + continue; + } + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c: nctx = max\n"); + break; + case 0xe4: case 0xe5: + cur->pc = check_modrm (cur->pc); + cur->pc++; + break; + case 0xe6: case 0xe7: + cur->pc++; + cur->pc = check_modrm (cur->pc); + break; + case 0xec: case 0xed: case 0xee: case 0xef: + cur->pc = check_modrm (cur->pc); + break; + case 0xe8: /* call Jz (f64) */ + { + if (jmp_reg_switch_mode == 1) + { + struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur)); + __collector_memcpy (tmpctx, cur, sizeof (*cur)); + int rc = process_return (wctx, tmpctx); + if (rc != RA_FAILURE) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + int immz = read_int (cur->pc, z); + if (immz == 0) + /* special case in PIC code */ + cur->sp -= 1; + cur->pc += z; + } + break; + case 0xe9: /* jump Jz */ + { + int immz = read_int (cur->pc, z); + unsigned char *npc = cur->pc + z + immz; + if ((unsigned long) npc < wctx->tbgn || (unsigned long) npc >= wctx->tend) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xe9.\n", __LINE__); + DELETE_CURCTX (); + break; + } + int tidx = 0; + while (npc > targets[tidx]) + tidx += 1; + if (npc != targets[tidx]) + { + if (ntrg < MAXTRGTS) + { + for (int i = 0; i < nctx; i++) + if (buf[i].tidx >= tidx) + buf[i].tidx++; + /* insert a new target */ + for (int i = ntrg; i > tidx; i--) + targets[i] = targets[i - 1]; + ntrg += 1; + targets[tidx++] = npc; + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c: ntrg = max\n"); + cur->pc = npc; + cur->tidx = tidx; + continue; /* advance this context first */ + } + else + { + /* Delete context */ + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xe9.\n", __LINE__); + DELETE_CURCTX (); + } + } + break; + case 0xeb: /* jump imm8 */ + { + imm8 = *(char*) cur->pc++; + int tidx = 0; + unsigned char *npc = cur->pc + imm8; + while (npc > targets[tidx]) + tidx += 1; + if (npc != targets[tidx]) + { + if (ntrg < MAXTRGTS) + { + for (int i = 0; i < nctx; i++) + if (buf[i].tidx >= tidx) + buf[i].tidx++; + /* insert a new target */ + for (int i = ntrg; i > tidx; i--) + targets[i] = targets[i - 1]; + ntrg += 1; + targets[tidx++] = npc; + } + else + DprintfT (SP_DUMP_UNWIND, "unwind.c: ntrg = max\n"); + cur->pc = npc; + cur->tidx = tidx; + continue; /* advance this context first */ + } + else + { + /* Delete context */ + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xeb.\n", __LINE__); + DELETE_CURCTX (); + } + } + break; + case 0xf0: /* lock prefix */ + case 0xf2: /* repne prefix */ + case 0xf3: /* repz prefix */ + break; + case 0xf4: /* hlt */ + extop2 = *(cur->pc - 3); + if (extop2 == 0x90) + { + // 17851712 occasional SEGV in find_i386_ret_addr in unwind.c during attach + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_END_OF_STACK); + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d returns RA_END_OF_STACK\n", __LINE__); + return RA_END_OF_STACK; + } + /* We see 'hlt' in _start. Stop analysis, revert to FP */ + /* A workaround for the Linux main stack */ + if (nctx > 1) + { + DELETE_CURCTX (); + break; + } + if (cur->fp == 0) + { + if (jmp_reg_switch_mode == 1) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: give up return address under jmp switch mode, opcode = 0xf4\n"); + goto checkFP; + } + cache_put (wctx, RA_EOSTCK); + wctx->pc = 0; + wctx->sp = 0; + wctx->fp = 0; + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_END_OF_STACK); + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d returns RA_END_OF_STACK\n", __LINE__); + return RA_END_OF_STACK; + } + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address, opcode = 0xf4\n", __LINE__); + goto checkFP; + case 0xf5: /* cmc */ + break; + case 0xf6: /* group3 Eb */ + modrm = *cur->pc; + extop = MRM_EXT (modrm); + cur->pc = check_modrm (cur->pc); + if (extop == 0x0) /* test Ib */ + cur->pc += 1; + break; + case 0xf7: /* group3 Ev */ + modrm = *cur->pc; + extop = MRM_EXT (modrm); + cur->pc = check_modrm (cur->pc); + if (extop == 0x0) /* test Iz */ + cur->pc += z; + break; + case 0xf8: /* clc */ + case 0xf9: /* stc */ + case 0xfa: /* cli */ + case 0xfb: /* sti */ + case 0xfc: /* cld */ + case 0xfd: /* std */ + break; + case 0xfe: /* group4 */ + modrm = *cur->pc; + extop = MRM_EXT (modrm); + switch (extop) + { + case 0x0: /* inc Eb */ + case 0x1: /* dec Eb */ + cur->pc = check_modrm (cur->pc); + break; + case 0x7: + cur->pc = check_modrm (cur->pc); + break; + default: + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0xfe %x\n", + __LINE__, extop); + DELETE_CURCTX (); + break; + } + break; + case 0xff: /* group5 */ + modrm = *cur->pc; + extop = MRM_EXT (modrm); + switch (extop) + { + case 0x0: /* inc Ev */ + case 0x1: /* dec Ev */ + cur->pc = check_modrm (cur->pc); + break; + case 0x2: /* calln Ev */ + if (jmp_reg_switch_mode == 1) + { + struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur)); + __collector_memcpy (tmpctx, cur, sizeof (*cur)); + int rc = process_return (wctx, tmpctx); + if (rc != RA_FAILURE) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + cur->pc = check_modrm (cur->pc); + break; + case 0x3: /* callf Ep */ + if (jmp_reg_switch_mode == 1) + { + struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur)); + __collector_memcpy (tmpctx, cur, sizeof (*cur)); + int rc = process_return (wctx, tmpctx); + if (rc != RA_FAILURE) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + cur->pc = check_modrm (cur->pc); /* XXXX */ + break; + case 0x4: /* jumpn Ev */ + /* This instruction appears in PLT or + * in tail call optimization. + * In both cases treat it as return. + * Save jump *(reg) - switch, etc, for later use when no ctx left + */ + if (modrm == 0x25 || /* jumpn *disp32 */ + MRM_MOD (modrm) == 0x40 || /* jumpn byte(reg) */ + MRM_MOD (modrm) == 0x80) /* jumpn word(reg) */ + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: PLT or tail call: %p\n", cur->pc - 1); + int rc = process_return (wctx, cur); + if (rc != RA_FAILURE) + { + if (jmp_reg_switch_mode == 1 && total_num_jmp_reg < max_num_jmp_reg_seen) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: give up return address under jmp switch mode, opcode = 0xff\n"); + goto checkFP; + } + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + else if (modrm != 0x24 /*ignore SIB*/) /* jumpn *(reg) or jumpn reg */ + { + // 22846120 stack unwind does not find caller of __memcpy_ssse3_back with B64 intel-Linux + /* + * For now, let's deal rather narrowly with this scenario. If: + * - we are in the middle of an "ff e2" instruction, and + * - the next instruction is undefined ( 0f 0b == ud2 ) + * then test return. (Might eventually have to broaden the scope + * of this fix to other registers/etc.) + */ + if (cur->pc[0] == 0xe2 && cur->pc[1] == 0x0f && cur->pc[2] == 0x0b) + { + int rc = process_return_real (wctx, cur, 0); + if (rc == RA_SUCCESS) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + + // 22691241 shjsynprog, jsynprog core dump from find_i386_ret_addr + /* + * Here is another oddity. Java 9 seems to emit dynamically generated + * code where a code block ends with a "jmp *reg" and then padding to a + * multiple-of-16 boundary and then a bunch of 0s. In this case, let's + * not continue to walk bytes since we would be walking off the end of + * the instructions into ... something. Treating them as instructions + * can lead to unexpected results, including SEGV. + */ + /* + * While the general problem deserves a better solution, let's look + * here only for one particular case: + * 0xff 0xe7 jmp *reg + * nop to bring us to a multiple-of-16 boundary + * 0x0000000000000a00 something that does not look like an instruction + * + * A different nop might be used depending on how much padding is needed + * to reach that multiple-of-16 boundary. We've seen two: + * 0x90 one byte + * 0x0f 0x1f 0x40 0x00 four bytes + */ + // confirm the instruction is 0xff 0xe7 + if (cur->pc[0] == 0xe7) + { + // check for correct-length nop and find next 16-byte boundary + int found_nop = 0; + unsigned long long *boundary = 0; + switch ((((unsigned long) (cur->pc)) & 0xf)) + { + case 0xb: // look for 4-byte nop + if (*((unsigned *) (cur->pc + 1)) == 0x00401f0f) + found_nop = 1; + boundary = (unsigned long long *) (cur->pc + 5); + break; + case 0xe: // look for 1-byte nop + if (cur->pc[1] == 0x90) + found_nop = 1; + boundary = (unsigned long long *) (cur->pc + 2); + break; + default: + break; + } + + // if nop is found, check what's at the boundary + if (found_nop && *boundary == 0x000000000a00) + { + DELETE_CURCTX (); + break; + } + } + + DprintfT (SP_DUMP_UNWIND, "unwind.c: probably PLT or tail call or switch table: %p\n", + cur->pc - 1); + if (num_jmp_reg < expected_num_jmp_reg) + { + if (jmp_reg_ctx[num_jmp_reg] == NULL) + jmp_reg_ctx[num_jmp_reg] = (struct AdvWalkContext *) alloca (sizeof (*cur)); + if (jmp_reg_ctx[num_jmp_reg] != NULL) + __collector_memcpy (jmp_reg_ctx[num_jmp_reg], cur, sizeof (*cur)); + } + if (num_jmp_reg < expected_num_jmp_reg || + (num_jmp_reg >= expected_num_jmp_reg && + jmp_reg_ctx[expected_num_jmp_reg - 1] != NULL && + cur->pc != jmp_reg_ctx[expected_num_jmp_reg - 1]->pc)) + { + num_jmp_reg++; + total_num_jmp_reg++; + } + if (jmp_reg_switch_mode == 1 && total_num_jmp_reg >= max_num_jmp_reg_seen) + { + int rc = process_return_real (wctx, cur, 0); + if (rc == RA_SUCCESS) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + } + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xff.\n", __LINE__); + DELETE_CURCTX (); + break; + case 0x5: /* jmpf Ep */ + cur->pc = check_modrm (cur->pc); /* XXXX */ + break; + case 0x6: /* push Ev */ + cur->pc = check_modrm (cur->pc); + cur->sp -= 1; + break; + case 0x7: + cur->pc = check_modrm (cur->pc); /* XXXX */ + if (jmp_reg_switch_mode == 1) + { + int rc = process_return_real (wctx, cur, 0); + if (rc == RA_SUCCESS) + { + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc); + return rc; + } + } + break; + default: + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0xff %x\n", + __LINE__, (int) extop); + DELETE_CURCTX (); + break; + } + break; + default: + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0x%x\n", + __LINE__, (int) opcode); + DELETE_CURCTX (); + break; + } + + /* switch to next context */ + if (++cur >= buf + nctx) + cur = buf; + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d switch context: cur=0x%lx(%ld) nctx=%d cnt=%d\n", + __LINE__, (unsigned long) cur, (long) (cur - buf), (int) nctx, (int) cnt); + } + +checkFP: + Tprintf (DBG_LT3, "find_i386_ret_addr:%d checkFP: wctx=0x%lx fp=0x%lx ln=0x%lx pc=0x%lx sbase=0x%lx sp=0x%lx tbgn=0x%lx tend=0x%lx\n", + __LINE__, (unsigned long) wctx, (unsigned long) wctx->fp, + (unsigned long) wctx->ln, (unsigned long) wctx->pc, (unsigned long) wctx->sbase, + (unsigned long) wctx->sp, (unsigned long) wctx->tbgn, (unsigned long) wctx->tend); + + if (jmp_reg_switch_mode == 1) + { // not deal with switch cases not ending with ret + if (jmp_reg_switch_backup_ctx != NULL) + __collector_memcpy (cur, jmp_reg_switch_backup_ctx, sizeof (*cur)); + DprintfT (SP_DUMP_UNWIND, "stack_unwind jmp reg mode on: pc = 0x%lx cnt = %d, nctx = %d\n", wctx->pc, cnt, nctx); + } + + unsigned long *cur_fp = cur->fp; + unsigned long *cur_sp = cur->sp; + if (do_walk == 0) + __collector_memcpy (&wctx_pc_save, wctx, sizeof (struct WalkContext)); + + /* Resort to the frame pointer */ + if (cur->fp_loc) + cur->fp = cur->fp_sav; + cur->sp = cur->fp; + if ((unsigned long) cur->sp >= wctx->sbase || + (unsigned long) cur->sp < wctx->sp) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d do_walk=%d cur->sp=0x%p out of range. wctx->sbase=0x%lx wctx->sp=0x%lx wctx->pc=0x%lx\n", + __LINE__, (int) do_walk, cur->sp, (unsigned long) wctx->sbase, + (unsigned long) wctx->sp, (unsigned long) wctx->pc); + if (do_walk == 0) + { + cur->sp = cur_sp; + cur->fp = cur_fp; + do_walk = 1; + save_ctx = 1; + goto startWalk; + } + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE); + return RA_FAILURE; + } + + unsigned long fp = *cur->sp++; + if (fp <= (unsigned long) cur->sp || fp >= wctx->sbase) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d fp=0x%016llx out of range. cur->sp=%p wctx->sbase=0x%lx wctx->pc=0x%lx\n", + __LINE__, (unsigned long long) fp, cur->sp, + (unsigned long) wctx->sbase, (unsigned long) wctx->pc); + if (do_walk == 0) + { + cur->sp = cur_sp; + cur->fp = cur_fp; + do_walk = 1; + save_ctx = 1; + goto startWalk; + } + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE); + return RA_FAILURE; + } + + unsigned long ra = *cur->sp++; + if (ra == 0) + { + cache_put (wctx, RA_EOSTCK); + DprintfT (SP_DUMP_UNWIND, "unwind.c:%d returns RA_END_OF_STACK wctx->pc = 0x%lx\n", __LINE__, wctx->pc); + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_END_OF_STACK); + return RA_END_OF_STACK; + } + + unsigned long tbgn = wctx->tbgn; + unsigned long tend = wctx->tend; + if (ra < tbgn || ra >= tend) + { + // We do not know yet if update_map_segments is really needed + if (!__collector_check_segment (ra, &tbgn, &tend, 0)) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: __collector_check_segment fail. wctx->pc = 0x%lx\n", wctx->pc); + if (do_walk == 0) + { + cur->sp = cur_sp; + cur->fp = cur_fp; + do_walk = 1; + save_ctx = 1; + goto startWalk; + } + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE); + return RA_FAILURE; + } + } + + unsigned long npc = adjust_ret_addr (ra, ra - tbgn, tend); + if (npc == 0) + { + DprintfT (SP_DUMP_UNWIND, "unwind.c: adjust_ret_addr fail. wctx->pc = 0x%lx\n", wctx->pc); + if (do_walk == 0) + { + cur->sp = cur_sp; + cur->fp = cur_fp; + do_walk = 1; + save_ctx = 1; + goto startWalk; + } + if (save_ctx) + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE); + return RA_FAILURE; + } + wctx->pc = npc; + wctx->sp = (unsigned long) cur->sp; + wctx->fp = fp; + wctx->tbgn = tbgn; + wctx->tend = tend; + + if (save_ctx) + { + omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_SUCCESS); + DprintfT (SP_DUMP_UNWIND, "unwind.c: cache walk context. wctx_pc_save->pc = 0x%lx\n", wctx_pc_save.pc); + } + return RA_SUCCESS; +} + +/* + * We have the return address, but we would like to report to the user + * the calling PC, which is the instruction immediately preceding the + * return address. Unfortunately, x86 instructions can have variable + * length. So we back up 8 bytes and try to figure out where the + * calling PC starts. (FWIW, call instructions are often 5-bytes long.) + */ +unsigned long +adjust_ret_addr (unsigned long ra, unsigned long segoff, unsigned long tend) +{ + unsigned long npc = 0; + int i = segoff < 8 ? segoff : 8; + for (; i > 1; i--) + { + unsigned char *ptr = (unsigned char*) ra - i; + int z = 4; + int a = 4; + int done = 0; + int bVal; + while (!done) + { + bVal = getByteInstruction (ptr); + if (bVal < 0) + return 0; + switch (bVal) + { + case 0x26: + case 0x36: +#if WSIZE(64) + ptr += 1; + break; +#endif + case 0x64: + case 0x65: + bVal = getByteInstruction (ptr + 1); + if (bVal < 0) + return 0; + if (bVal == 0xe8) + // a workaround for bug 16193041, assuming "call Jz" has no segment override prefix + done = 1; + else + ptr += 1; + break; + case 0x66: + z = 2; + ptr += 1; + break; + case 0x67: + a = 2; + ptr += 1; + break; + default: + done = 1; + break; + } + } +#if WSIZE(64) + bVal = getByteInstruction (ptr); + if (bVal < 0) + return 0; + if (bVal >= 0x40 && bVal <= 0x4f) + { /* XXXX not all REX codes applicable */ + if (bVal & 0x8) + z = 4; + ptr += 1; + } +#endif + int opcode = getByteInstruction (ptr); + if (opcode < 0) + return 0; + ptr++; + switch (opcode) + { + case 0xe8: /* call Jz (f64) */ + ptr += z; + break; + case 0x9a: /* callf Ap */ + ptr += 2 + a; + break; + case 0xff: /* calln Ev , callf Ep */ + { + int extop = MRM_EXT (*ptr); + if (extop == 2 || extop == 3) + ptr = check_modrm (ptr); + } + break; + default: + continue; + } + if ((unsigned long) ptr == ra) + { + npc = ra - i; + break; + } + } + if (npc == 0) + { + unsigned char * ptr = (unsigned char *) ra; +#if WSIZE(32) + // test __kernel_sigreturn or __kernel_rt_sigreturn + if ((ra + 7 < tend && getByteInstruction (ptr) == 0x58 + && getByteInstruction (ptr + 1) == 0xb8 + && getByteInstruction (ptr + 6) == 0xcd + && getByteInstruction (ptr + 7) == 0x80) /* pop %eax; mov $NNNN, %eax; int */ + || (ra + 7 < tend && getByteInstruction (ptr) == 0x58 + && getByteInstruction (ptr + 1) == 0xb8 + && getByteInstruction (ptr + 6) == 0x0f + && getByteInstruction (ptr + 7) == 0x05) /* pop %eax; mov $NNNN, %eax; syscall */ + || (ra + 6 < tend && getByteInstruction (ptr) == 0xb8 + && getByteInstruction (ptr + 5) == 0xcd + && getByteInstruction (ptr + 6) == 0x80) /* mov $NNNN, %eax; int */ + || (ra + 6 < tend && getByteInstruction (ptr) == 0xb8 + && getByteInstruction (ptr + 5) == 0x0f + && getByteInstruction (ptr + 6) == 0x05)) /* mov $NNNN, %eax; syscall */ +#else //WSIZE(64) + // test __restore_rt + if (ra + 8 < tend && getByteInstruction (ptr) == 0x48 + && getByteInstruction (ptr + 7) == 0x0f + && getByteInstruction (ptr + 8) == 0x05) /* mov $NNNNNNNN, %rax; syscall */ +#endif + { + npc = ra; + } + } + if (npc == 0 && __collector_java_mode + && __collector_java_asyncgetcalltrace_loaded) + { // detect jvm interpreter code for java user threads + unsigned char * ptr = (unsigned char *) ra; +#if WSIZE(32) + // up to J170 + /* + * ff 24 9d e0 64 02 f5 jmp *-0xafd9b20(,%ebx,4) + * 8b 4e 01 movl 1(%esi),%ecx + * f7 d1 notl %ecx + * 8b 5d ec movl -0x14(%ebp),%ebx + * c1 e1 02 shll $2,%ecx + * eb d8 jmp .-0x26 [ 0x92a ] + * 83 ec 08 subl $8,%esp || 8b 65 f8 movl -8(%ebp),%esp + * */ + if (ra - 20 >= (ra - segoff) && ((*ptr == 0x83 && *(ptr + 1) == 0xec) || (*ptr == 0x8b && *(ptr + 1) == 0x65)) + && *(ptr - 2) == 0xeb + && *(ptr - 5) == 0xc1 && *(ptr - 4) == 0xe1 + && *(ptr - 8) == 0x8b && *(ptr - 7) == 0x5d + && *(ptr - 10) == 0xf7 && *(ptr - 9) == 0xd1 + && *(ptr - 13) == 0x8b && *(ptr - 12) == 0x4e + && *(ptr - 20) == 0xff && *(ptr - 19) == 0x24 && *(ptr - 18) == 0x9d) + { + npc = ra - 20; + } + // J180 J190 + // ff 24 9d ** ** ** ** jmp *-0x*******(,%ebx,4) + if (npc == 0 + && ra - 7 >= (ra - segoff) + && *(ptr - 7) == 0xff + && *(ptr - 6) == 0x24 + && *(ptr - 5) == 0x9d) + { + npc = ra - 7; + } +#else //WSIZE(64) + // up to J170 + /* + * 41 ff 24 da jmp *(%r10,%rbx,8) + * 41 8b 4d 01 movl 1(%r13),%ecx + * f7 d1 notl %ecx + * 48 8b 5d d8 movq -0x28(%rbp),%rbx + * c1 e1 02 shll $2,%ecx + * eb cc jmp .-0x32 [ 0xd23 ] + * 48 8b 65 f0 movq -0x10(%rbp),%rsp + */ + if (ra - 19 >= (ra - segoff) && *ptr == 0x48 && ((*(ptr + 1) == 0x8b && *(ptr + 2) == 0x65) || (*(ptr + 1) == 0x83 && *(ptr + 2) == 0xec)) + && *(ptr - 2) == 0xeb + && *(ptr - 5) == 0xc1 && *(ptr - 4) == 0xe1 + && *(ptr - 9) == 0x48 && *(ptr - 8) == 0x8b && *(ptr - 7) == 0x5d + && *(ptr - 11) == 0xf7 && *(ptr - 10) == 0xd1 + && *(ptr - 15) == 0x41 && *(ptr - 14) == 0x8b && *(ptr - 13) == 0x4d + && *(ptr - 19) == 0x41 && *(ptr - 18) == 0xff) + npc = ra - 19; + // J180 J190 + // 41 ff 24 da jmp *(%r10,%rbx,8) + if (npc == 0 + && ra - 4 >= (ra - segoff) + && *(ptr - 4) == 0x41 + && *(ptr - 3) == 0xff + && *(ptr - 2) == 0x24 + && *(ptr - 1) == 0xda) + npc = ra - 4; +#endif + } + + return npc; +} + +/* + * Parses AVX instruction and returns its length. + * Returns 0 if parsing failed. + * https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + */ +static int +parse_x86_AVX_instruction (unsigned char *pc) +{ + /* + * VEX prefix has a two-byte form (0xc5) and a three byte form (0xc4). + * If an instruction syntax can be encoded using the two-byte form, + * it can also be encoded using the three byte form of VEX. + * The latter increases the length of the instruction by one byte. + * This may be helpful in some situations for code alignment. + * + Byte 0 Byte 1 Byte 2 Byte 3 + (Bit Position) 7 0 7 6 5 4 0 7 6 3 2 10 + 3-byte VEX [ 11000100 ] [ R X B | m-mmmm ] [ W | vvvv | L | pp ] + 7 0 7 6 3 2 10 + 2-byte VEX [ 11000101 ] [ R | vvvv | L | pp ] + 7 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 + 4-byte EVEX [ 01100010 ] [ R X B R1 0 0 m m ] [ W v v v v 1 p p ] [ z L1 L B1 V1 a a a ] + + R: REX.R in 1's complement (inverted) form + 0: Same as REX.R=1 (64-bit mode only) + 1: Same as REX.R=0 (must be 1 in 32-bit mode) + + X: REX.X in 1's complement (inverted) form + 0: Same as REX.X=1 (64-bit mode only) + 1: Same as REX.X=0 (must be 1 in 32-bit mode) + + B: REX.B in 1's complement (inverted) form + 0: Same as REX.B=1 (64-bit mode only) + 1: Same as REX.B=0 (Ignored in 32-bit mode). + + W: opcode specific (use like REX.W, or used for opcode + extension, or ignored, depending on the opcode byte) + + m-mmmm: + 00000: Reserved for future use (will #UD) + 00001: implied 0F leading opcode byte + 00010: implied 0F 38 leading opcode bytes + 00011: implied 0F 3A leading opcode bytes + 00100-11111: Reserved for future use (will #UD) + + vvvv: a register specifier (in 1's complement form) or 1111 if unused. + + L: Vector Length + 0: scalar or 128-bit vector + 1: 256-bit vector + + pp: opcode extension providing equivalent functionality of a SIMD prefix + 00: None + 01: 66 + 10: F3 + 11: F2 + * + * Example: 0xc5f877L vzeroupper + * VEX prefix: 0xc5 0x77 + * Opcode: 0xf8 + * + */ + int len = 0; + disassemble_info dis_info; + dis_info.arch = bfd_arch_i386; + dis_info.mach = bfd_mach_x86_64; + dis_info.flavour = bfd_target_unknown_flavour; + dis_info.endian = BFD_ENDIAN_UNKNOWN; + dis_info.endian_code = dis_info.endian; + dis_info.octets_per_byte = 1; + dis_info.disassembler_needs_relocs = FALSE; + dis_info.fprintf_func = fprintf_func; + dis_info.stream = NULL; + dis_info.disassembler_options = NULL; + dis_info.read_memory_func = read_memory_func; + dis_info.memory_error_func = memory_error_func; + dis_info.print_address_func = print_address_func; + dis_info.symbol_at_address_func = symbol_at_address_func; + dis_info.symbol_is_valid = symbol_is_valid; + dis_info.display_endian = BFD_ENDIAN_UNKNOWN; + dis_info.symtab = NULL; + dis_info.symtab_size = 0; + dis_info.buffer_vma = 0; + dis_info.buffer = pc; + dis_info.buffer_length = 8; + + disassembler_ftype disassemble = print_insn_i386; + if (disassemble == NULL) + { + DprintfT (SP_DUMP_UNWIND, "parse_x86_AVX_instruction ERROR: unsupported disassemble\n"); + return 0; + } + len = disassemble (0, &dis_info); + DprintfT (SP_DUMP_UNWIND, "parse_x86_AVX_instruction: returned %d pc: %p\n", len, pc); + return len; +} + +/* + * In the Intel world, a stack frame looks like this: + * + * %fp0->| | + * |-------------------------------| + * | Args to next subroutine | + * |-------------------------------|-\ + * %sp0->| One word struct-ret address | | + * |-------------------------------| > minimum stack frame (8 bytes) + * | Previous frame pointer (%fp0)| | + * %fp1->|-------------------------------|-/ + * | Local variables | + * %sp1->|-------------------------------| + * + */ + +int +stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode) +{ + long *lbuf = (long*) buf; + int lsize = size / sizeof (long); + int ind = 0; + int do_walk = 1; + int extra_frame = 0; + if (mode & FRINFO_NO_WALK) + do_walk = 0; + if ((mode & 0xffff) == FRINFO_FROM_STACK) + extra_frame = 1; + + /* + * trace the stack frames from user stack. + * We are assuming that the frame pointer and return address + * are null when we are at the top level. + */ + struct WalkContext wctx; + wctx.pc = GET_PC (context); + wctx.sp = GET_SP (context); + wctx.fp = GET_FP (context); + wctx.ln = (unsigned long) context->uc_link; + unsigned long *sbase = (unsigned long*) __collector_tsd_get_by_key (unwind_key); + if (sbase && *sbase > wctx.sp) + wctx.sbase = *sbase; + else + { + wctx.sbase = wctx.sp + 0x100000; + if (wctx.sbase < wctx.sp) /* overflow */ + wctx.sbase = (unsigned long) - 1; + } + // We do not know yet if update_map_segments is really needed + __collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0); + + for (;;) + { + if (ind >= lsize || wctx.pc == 0) + break; + if (bptr != NULL && extra_frame && wctx.sp <= (unsigned long) bptr && ind < 2) + { + lbuf[0] = wctx.pc; + if (ind == 0) + { + ind++; + if (ind >= lsize) + break; + } + } + if (bptr == NULL || wctx.sp > (unsigned long) bptr) + { + lbuf[ind++] = wctx.pc; + if (ind >= lsize) + break; + } + + for (;;) + { + if (eptr != NULL && wctx.sp >= (unsigned long) eptr) + { + ind = ind >= 2 ? ind - 2 : 0; + goto exit; + } + int ret = find_i386_ret_addr (&wctx, do_walk); + DprintfT (SP_DUMP_UNWIND, "stack_unwind (x86 walk):%d find_i386_ret_addr returns %d\n", __LINE__, ret); + if (ret == RA_FAILURE) + { + /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */ + goto exit; + } + + if (ret == RA_END_OF_STACK) + goto exit; +#if WSIZE(32) + if (ret == RA_RT_SIGRETURN) + { + struct SigFrame + { + unsigned long arg0; + unsigned long arg1; + unsigned long arg2; + } *sframe = (struct SigFrame*) wctx.sp; + ucontext_t *ncontext = (ucontext_t*) sframe->arg2; + wctx.pc = GET_PC (ncontext); + if (!__collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0)) + { + /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */ + goto exit; + } + unsigned long nsp = GET_SP (ncontext); + /* Check the new stack pointer */ + if (nsp <= sframe->arg2 || nsp > sframe->arg2 + sizeof (ucontext_t) + 1024) + { + /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */ + goto exit; + } + wctx.sp = nsp; + wctx.fp = GET_FP (ncontext); + break; + } + else if (ret == RA_SIGRETURN) + { + struct sigcontext *sctx = (struct sigcontext*) wctx.sp; + wctx.pc = sctx->eip; + if (!__collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0)) + { + /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */ + goto exit; + } + wctx.sp = sctx->esp; + wctx.fp = sctx->ebp; + break; + } +#elif WSIZE(64) + if (ret == RA_RT_SIGRETURN) + { + ucontext_t *ncontext = (ucontext_t*) wctx.sp; + wctx.pc = GET_PC (ncontext); + if (!__collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0)) + { + /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */ + goto exit; + } + unsigned long nsp = GET_SP (ncontext); + /* Check the new stack pointer */ + if (nsp <= wctx.sp || nsp > wctx.sp + sizeof (ucontext_t) + 1024) + { + /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */ + goto exit; + } + wctx.sp = nsp; + wctx.fp = GET_FP (ncontext); + break; + } +#endif /* WSIZE() */ + if (bptr != NULL && extra_frame && wctx.sp <= (unsigned long) bptr && ind < 2) + { + lbuf[0] = wctx.pc; + if (ind == 0) + { + ind++; + if (ind >= lsize) + break; + } + } + if (bptr == NULL || wctx.sp > (unsigned long) bptr) + { + lbuf[ind++] = wctx.pc; + if (ind >= lsize) + goto exit; + } + } + } + +exit: +#if defined(DEBUG) + if ((SP_DUMP_UNWIND & __collector_tracelevel) != 0) + { + DprintfT (SP_DUMP_UNWIND, "stack_unwind (x86 walk):%d found %d frames\n\n", __LINE__, ind); + for (int i = 0; i < ind; i++) + DprintfT (SP_DUMP_UNWIND, " %3d: 0x%lx\n", i, (unsigned long) lbuf[i]); + } +#endif + dump_stack (__LINE__); + if (ind >= lsize) + { + ind = lsize - 1; + lbuf[ind++] = (unsigned long) SP_TRUNC_STACK_MARKER; + } + return ind * sizeof (long); +} + +#elif ARCH(Aarch64) + +static int +stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode) +{ + if (buf && bptr && eptr && context && size + mode > 0) + getByteInstruction ((unsigned char *) eptr); + int ind = 0; + __u64 *lbuf = (void *) buf; + int lsize = size / sizeof (__u64); + __u64 pc = context->uc_mcontext.pc; + __u64 sp = context->uc_mcontext.sp; + __u64 stack_base; + unsigned long tbgn = 0; + unsigned long tend = 0; + + unsigned long *sbase = (unsigned long*) __collector_tsd_get_by_key (unwind_key); + if (sbase && *sbase > sp) + stack_base = *sbase; + else + { + stack_base = sp + 0x100000; + if (stack_base < sp) // overflow + stack_base = (__u64) -1; + } + DprintfT (SP_DUMP_UNWIND, + "unwind.c:%d stack_unwind %2d pc=0x%llx sp=0x%llx stack_base=0x%llx\n", + __LINE__, ind, (unsigned long long) pc, (unsigned long long) sp, + (unsigned long long) stack_base); + + while (sp && pc) + { + DprintfT (SP_DUMP_UNWIND, + "unwind.c:%d stack_unwind %2d pc=0x%llx sp=0x%llx\n", + __LINE__, ind, (unsigned long long) pc, (unsigned long long) sp); +// Dl_info dlinfo; +// if (!dladdr ((void *) pc, &dlinfo)) +// break; +// DprintfT (SP_DUMP_UNWIND, "%2d: %llx <%s+%llu> (%s)\n", +// ind, (unsigned long long) pc, +// dlinfo.dli_sname ? dlinfo.dli_sname : "(?)", +// (unsigned long long) pc - (unsigned long long) dlinfo.dli_saddr, +// dlinfo.dli_fname); + lbuf[ind++] = pc; + if (ind >= lsize || sp >= stack_base || (sp & 15) != 0) + break; + if (pc < tbgn || pc >= tend) + if (!__collector_check_segment ((unsigned long) pc, &tbgn, &tend, 0)) + { + DprintfT (SP_DUMP_UNWIND, + "unwind.c:%d __collector_check_segment failed. sp=0x%lx\n", + __LINE__, (unsigned long) sp); + break; + } + pc = ((__u64 *) sp)[1]; + __u64 old_sp = sp; + sp = ((__u64 *) sp)[0]; + if (sp < old_sp) + break; + } + if (ind >= lsize) + { + ind = lsize - 1; + lbuf[ind++] = (__u64) SP_TRUNC_STACK_MARKER; + } + return ind * sizeof (__u64); +} +#endif /* ARCH() */ |